The problem
SSM pays up front for every lockbox, supply run, landscaping job and repair across about 250 properties, then has to win each dollar back from the right owner. That's 500+ charges a month and $450K+ a year. Before the app it was all tracked by hand, and $18K+ a year never got billed at all.
Partner cards made it worse. Partners sometimes fronted costs on personal cards, so one charge created two debts: the owner owed SSM, and SSM owed the partner. That's $45K+ a year riding on personal cards with nothing tying it back.
Whatever I built also had to tie out to the books in QuickBooks Online and Buildium. And the monthly owner report was still a spreadsheet a partner put together by hand.
Who it's for, and the first test
The partners are the daily users, so I designed for them first. They log charges on their phones in the field, and I set the bar at about 10 seconds a charge.
For owners, one rule kept the portal shippable from day one: optional data never blocks a feature. When I designed it in August, none of the 43 active properties in the app had fee terms entered. So a missing value just hides its block, and an owner never sees $0.00.
My own real-use test, the day after V1 went live, caught the core loop failing to close. The pay button sat behind the bottom nav, and Generate Statement was a stub. That test drove the rebuild you'll see below.
I also cracked a silent failure that had swallowed one partner's charges for weeks. He'd tap Add charge and nothing saved. A diagnostics beacon I added found two causes on two partners' phones: a sign-in problem specific to one device, and a corporate web proxy that blocked every save on the other. He logged his first charge on July 9, and the app now shows an error the moment a save fails.

Key decisions
Four decisions shaped the product. Most of them came straight out of something breaking in real use.
Balances are computed
A July audit found the ledger math and rounding correct, and the design is why. Money is stored in integer cents. Every balance and status is calculated from the ledger, because a stored balance can drift, and database rules stop a payment from covering more than a charge owes. Five separate safety nets sit underneath: offline-first capture, append-only records with soft delete, an activity log on every action, database constraints with point-in-time recovery, and a nightly off-platform backup.
Rebuild around the loop
One loop carries the whole app: add a charge, open it, mark it paid with one tap, see it on the owner. I rebuilt everything around it after that first test. Charges got proper detail pages, and statements became actual PDFs. Later, one shared component drew the money split on the four main screens, with To bill and Awaiting in the bar and Paid in history. My first split bar had used two browns so close you couldn't see the divider.
Owners get their own app
Owners never see a cent of SSM's internal costs, and the architecture makes that hard to break by accident. They use the same login and get a different UI. Access is deny-by-default at the router, so a forgotten route returns a 403 to an owner. With filters, one forgotten filter would expose the whole book of business. Before I built it, my research sweep found dozens of places a non-staff login could see or change data. Owners see only the final billed amount, and their approval card uses a data type with no cost field, so a future change can't leak it.
Switch off the blank work
I switched off a feature that was producing empty paperwork. Nightly auto-issue made 48 September statements, and 43 were blank. I redesigned the job as one report per owner, modeled on the partner's hand-made one. In my October spec, the report reads the Buildium, bank and Airbnb exports with fixed, tested rules, and it won't close a month while anything is still unresolved.

How I built it
699 commits, 49 database tables, about 274 API routes and 3,015 automated tests with zero failures. Every commit is under my name. I wrote the specs, made the product calls and reviewed every change before it shipped.
Each feature started as a design spec (25 between June 15 and October 7), then a phase plan, test-first code and a verification checklist. Standing rules and 50+ written lessons, like "never touch production data," kept mistakes from repeating. After mid-June, all testing ran on a demo twin with its own database, and production was treated as read-only.
One push updates the web app and the iPhone app together, because the iPhone app is a Capacitor shell around the live web app. When I restyled it, every screen got a written element inventory and nothing could move, because real-world testing had put each button where it was.
I audited my own product hard and fixed 94% of what the audits reproduced. A full audit in August reproduced 72 findings. We fixed 68 and left 4 open on purpose. One audit found 8 real defects hiding under 2,600+ passing tests, including routes nothing ever called. After that, every flow got driven on the iPhone simulator and every route got checked for a real caller.

What changed
The app has run SSM's money since launch day, and it hands the partners back 1,500+ hours a year, worth $110K+ in partner time. It launched on Cloudflare's free tier on June 15, 2026. QuickBooks invoicing reached production on July 6 after a four-lens audit with 859 passing tests, and the first real invoices went out August 5, with a blank invoice-number bug fixed the same night. The owner portal and partner statement flow shipped August 21, and the iPhone app reached TestFlight build 7 with push notifications.
My September cross-check caught errors in 35% of the hand-made owner reports. I had the report checked against 188 Buildium payments, and 22 of 34 houses matched to the dollar. The other 12 turned up bounced payments and rents swapped between units, plus two rents that showed up only in the bank statement. Those cases are now the acceptance test for the new report.
Every charge now gets logged once, against one property, and billed through the books instead of copied by hand. That closes the gap where $18K+ a year used to slip away. It also ended the who-paid-what mix-ups over partner cards, and owners have fewer reasons to be unhappy. The owner report was the last hand-made piece when I stepped back.
I designed the growth side too: ssmproperty.com plus a second brand site, ATLStay, with about 931 indexed URLs, including 100 city pages and 80 neighborhood pages. An owner intake form estimates a property's rental income, and a lead desk stores and alerts on every lead.

What's next
I'd ship the owner report against every September case, then run 250 owner reports a month on autopilot so month-end never waits on a spreadsheet again. Then I'd open the portal to every owner, starting with one I watch use it live. After that, I'd package the ledger, QuickBooks sync and owner portal for other property managers, since the hardest parts are already built and tested.


