Sharing reports without sending the wrong one
Alongside the work on the report itself, there was a separate problem to solve: how Aire Spaces shared reports with their clients. Every month, twenty documents had to be assembled, addressed, and sent out by hand — and the overhead of doing that was only part of it. With a manual mail-merge, the chance of slipping a report into the wrong inbox was real, and the cost of getting it wrong — sharing one client’s financials with another — is not the kind of mistake anyone wants to find out about.
There was a quieter cost too. Past reports lived in the email history of whoever had sent them, so anything older than the most recent month meant a request, a search, and a re-send.
The state of things
- • Twenty documents to assemble and mail-merge by hand each month
- • A real risk of sending a client's report to the wrong recipient
- • Past reports lived in email — every retrieval was a request
A login per client, on familiar ground
We reached for Supabase. We have reached for it on a number of projects, and the pieces we needed here — migrations, auth, row-level security — were not the first time we had wired any of them up. Row-level security in particular mapped cleanly to what the situation called for, with a rule that a client only ever sees the reports tied to their own properties, enforced at the database layer rather than reimplemented in application code. There is no path through the portal that returns the wrong report to the wrong person.
Around that, we built what was specific to Aire Spaces: a light admin surface for adding clients and assigning properties, the way reports surface inside the portal (current month at the front, history a click away), and the rules for how access propagates when a client gains or loses a property. The redesigned report still exports as a PDF for anyone who wants a print asset, but reading now happens in the portal more often than not — and the monthly mail-merge is gone with it.
Supabase — fast to wire up, RLS for access control, and a clean persistence layer for historical data. A strong, malleable component. A recurring part of how we build.