Skip to content
← All work

Work

Replatforming the resident experience across brand, money, and realtime

A zero-downtime cutover of every resident-facing surface to a new brand and domain—with a rewards pipeline aligned to the real Stripe payout lifecycle, and chat moved from best-effort to recoverable.

Role
Staff Software Engineer
Year
2026
Themes
Migration · Stripe · Realtime · Payments · Platform

A brand cutover is easy to describe and hard to do honestly: move every resident-facing surface—chat, rewards, identity, links, emails—onto a new name and a new domain, while the old one keeps working for everyone who never heard the announcement.

The framing

Three surfaces carried most of the risk. Rewards, because it is money-adjacent and money screens erode trust the moment they say something the bank has not done. Chat, because realtime is the one place a product’s promise is checked in seconds—one person sends, the other person should see. And the domain itself, because years of emails, generated links, and legacy routes were pointing at the old name and none of them were allowed to break.

What changed—the money screens

  • Reward statuses now map to the real Stripe payout lifecycle: Rewarded → Bank processing → Paid, with Forfeited as the exception path. “Paid” means the bank transfer completed—not that funds touched a wallet.
  • The backend owns the summary. Lifetime earned, three-month earnings, and waiting payout are computed where the data lives, instead of being reconstructed on the client from a partial page.
  • Cashout state is written synchronously at payout creation, so a refresh can never show money as available after it has already left.
  • The transaction feed paginates in the database—one ordered query across rewards and bank transfers—so pages are never short, never empty, and never disagree with the totals.

The point of all of it is the same: the screen tells the truth. Recurring payout and eligibility bugs stopped recurring—three months and counting without one.

What changed—realtime

The product expectation fits in a sentence: when one user sends a message, the other sees it without refreshing. The system behind that sentence was rebuilt—one subscription per channel identity, clean teardown, and reconnection treated as a first-class event that recovers whatever was missed while offline. Local development now reproduces the production websocket path exactly, Redis and proxy included, so “works locally” finally means something.

What changed—the cutover

  • Slug-first routing on the new domain, with resolver-backed compatibility routes: a legacy link asks the server where it belongs instead of trusting whatever the browser claims.
  • Staged redirects—temporary until proven, permanent after—preserved every email, generated link, and legacy route through the transition.
  • A shared integration branch, dedicated test environments, and a QA path that exercised the release as a whole before production traffic depended on it. The branch and environment strategy was the control plane for the work: it is what let a cross-cutting migration ship as one decision instead of a series of partial merges.

Outcome

The resident experience runs on its new brand, and nobody outside the team can point to the day it moved. That was the goal.