Skip to main content
Back to Projects
ProductDjangoMySQLCeleryPaddleGmail APIPillow

RealtyDesk: A Hyperlocal Market-Letter Product for Real Estate Agents

Founder & Full-Stack Engineer
9 min read
realtydesk.ai (opens in new tab)

RealtyDesk turns public housing data into a monthly marketing asset for a single real estate agent. Each agent claims a ZIP code, and every month that ZIP's letter goes out branded to them: an email, a print one-pager, and a set of social cards, each carrying the agent's name, brokerage, license number, and photo. One agent per ZIP, so the product is exclusive by design. I built the whole thing solo, from an empty repository to a product that can take real payments, with a data layer, a deterministic content engine, account-level billing, and a compliant outreach pipeline.

28k+Programmatic Pages
710kMarket Data Rows
1 per ZIPExclusivity Model
SoloEngineer

Context

Agents market to a "farm," a neighborhood they want to own. The classic tool is a monthly market letter: what did prices do, how many homes are for sale, how fast are they selling. Most agents either write it by hand every month or pay for national tools that produce something generic and priced for a brokerage rather than one person.

The product hypothesis was narrow and testable: take the free Realtor.com research dataset, generate a genuinely local letter for every ZIP, and sell each ZIP to exactly one agent. The scarcity is real, not a marketing line, because the data model enforces it.

The hard part is not the idea. It is that the artifact carries the agent's license number, so it has to be correct without a human checking each of tens of thousands of pages every month. Most of the engineering below exists to make "correct by construction" true.


My Role

Founder and Full-Stack Engineer

I owned every decision end to end:

  • Data ingestion and the market-data model
  • The deterministic content engine and its quality rules
  • Programmatic page generation and the SEO indexing strategy
  • Account, claim, and exclusivity logic with row-level locking
  • Paddle billing, including the subscription lifecycle both directions
  • The cold-outreach engine, deliverability, and compliance
  • Frontend, design system, and the letter artifact itself
  • Infrastructure and deployment on Railway

Architecture

RealtyDesk is a Django application backed by MySQL, deployed on Railway, with scheduled jobs driven by GitHub Actions hitting secured internal endpoints. The public market pages, the authenticated agent dashboard, the letter renderer, and the outreach engine all live in one codebase because they share the same core objects: the ZIP, its monthly data, and the letter built from it.


Engineering Decisions

1. Claims Are Assembled, Not Generated

The single most important rule in the product: nothing that must be true is written by a language model. A page carrying an agent's license number cannot say prices "should" do anything, cannot quote a number that is not in the data, and cannot predict the market.

The letter copy is assembled deterministically from the data. Where a short interpretive line is generated, it passes through quality rules enforced in code, not merely requested in a prompt: no digits, no stock openers, no advice, no prediction, no cliches, and a hard length cap. A line that fails is regenerated once with an explanation of exactly what it broke; if it fails again, it is left out and the block does not render. A letter missing one line beats a letter carrying one the agent would never have signed.

This came from measurement. An early audit of live copy found that a large majority of interpretive lines broke at least one quality rule, most commonly by handing out pricing advice under the agent's name. A second, more instructive trap: after the first fix, the audit reported zero violations while a random sample immediately turned up advice the rule had failed to catch. A check that returns a clean number and a false result is worse than no check. The lesson stuck: always read a random sample, never trust the audit alone.

2. Programmatic SEO With a Deliberate Throttle

Every ZIP gets a public market page, which is tens of thousands of near-identical templated pages on a young domain. That is exactly the doorway-content pattern that gets a domain penalized. The naive version of this product would expose all of them to search at once and quietly poison its own domain.

Indexability is controlled by a single dial. Only the richest markets plus any ZIP an agent has actually claimed are indexable and in the sitemap; everything else carries noindex until the domain earns wider exposure. The sitemap and the page-level directive read from the same set, so they can never disagree, which is a common and invisible way to leak the whole graph to a crawler regardless of the sitemap. The dial is raised deliberately, in steps, only once indexed pages start to rank.

Depth matters as much as restraint. The pages were thin, so I backfilled a two-year history from the Realtor.com history file, streaming 710,000 rows into the data model, and each page now renders a real per-ZIP trend with an honest y-axis label so a two-percent drift cannot masquerade as a crash. A trend is the one thing on the page that is genuinely unique per ZIP and impossible to template, and it is the question a homeowner actually asks.

3. A Backfill That Refuses to Delete

The letter for each ZIP-month is a one-to-one record attached to the market-data row with a cascading delete. The monthly ingest deletes and re-inserts the current month, which is fine. The history backfill could not use the same pattern: deleting and re-inserting would have silently destroyed hand-repaired letters. The backfill streams and upserts with conflict-ignore semantics and never issues a delete, so re-running it is free and no letter is ever cascaded away. The safety property is verified after every run.

4. Billing That Actually Stops

Billing is per account, not per ZIP. An early version charged per claimed ZIP, which meant three ZIPs on a plan advertised as one price produced triple the invoice. Rebuilt around an account-level subscription, it enforces a claim allowance instead.

The most important correctness work was the cancellation path. Releasing a ZIP has to stop the billing, not just free the ZIP locally. An earlier version set the claim canceled in the database and stopped there, so an agent who released their last ZIP would have kept being charged every month forever. The product is positioned against exactly that trap, so the first sign of the bug would have been a chargeback from someone who trusted the promise. It now cancels immediately at the payment provider, frees the ZIP even if the provider is unreachable, and raises an alarm to reconcile by hand rather than trapping anyone over a failed API call. None of this was visible in a green deploy; it surfaced only by rehearsing the full money path end to end against live payments.

5. Outreach With Deliverability and Compliance Built In

Cold outreach runs from a separate domain, never the product domain, to protect the product's sending reputation. The engine ramps sending slowly behind a date-gated cap, warms the domain with genuine two-way mail, honors opt-outs and hard bounces through a suppression table that survives re-importing the source list, and includes a postal address and honest subject lines to stay CAN-SPAM compliant. Reply handling reads the mailbox and classifies each message, biased toward suppressing, because never re-mailing a stranger is cheap and mailing someone who asked you to stop is not.


Infrastructure

The application runs on Railway against MySQL. Scheduled work (monthly data ingest, hourly outreach, reply scanning, reservation expiry, warm-up) is driven by GitHub Actions calling secured internal endpoints, each guarded by a shared key and exempt from CSRF because the caller is a script, not a browser. Social cards and print one-pagers are rendered server-side with Pillow. The design system lives in a single tokens file shared by the app and the marketing theme, so a visual change happens once.


Reflections

Correct by construction beats correct by review. When an artifact carries someone's license number across tens of thousands of pages every month, you cannot inspect your way to trust. The rules have to be in the code, and the failure mode has to be omission, not a plausible falsehood.

Rehearse the money path. The worst bug in the build, billing that never stopped, passed every test and every deploy. It only appeared when I walked the product as a paying user would. Some correctness lives in the seams between systems, where unit tests do not look.

Restraint is a feature on a young domain. The instinct with programmatic SEO is to publish everything. The discipline is a single dial you turn deliberately, and a sitemap that can never disagree with the page.

Distribution is the constraint, not the product. The engineering here is complete and proven. What a product like this needs next is not more features, it is evidence from real users, and I built the outreach and measurement to go get it.


RealtyDesk is live at realtydesk.ai (opens in new tab). Every ZIP's market page, like the two-year trend and the monthly letter, is public and built from the same data the paid product brands for agents.