Solo build, in production
A live property management app in daily production, designed and shipped solo. A double-entry ledger tracks balances, with tenant KYC verification and row-level-security private storage.
Small property owners run their buildings over WhatsApp threads and spreadsheets: who owes what, whose KYC is on file, who moved out last month. None of that scales past a handful of units, and none of it gives a tenant a real way to see their own balance or pay rent without asking. I designed and built Rynto solo to replace that with a real app: owners manage properties, houses, and tenants; tenants see their balance and pay rent; every bill, payment, and KYC document has an actual record behind it instead of a chat history.

I treat every KYC upload as a new row instead of overwriting the last one, then resolve which one is currently valid at read time. A tenant re-uploading a document while an earlier one is still under review doesn't hide the already-approved version behind a pending one.
The first cross-table RLS policy I wrote checked houses from a properties policy and properties from a houses policy, and Postgres re-evaluated both recursively until access to both tables broke entirely. I fixed it by wrapping the check in a security-definer function, then made that the standing pattern for every cross-table RLS check since, instead of solving it once and moving on.
A bill or house mutation writes its notification row synchronously, then invokes the push-delivery function without waiting on it. A slow or failing push provider never blocks the action the user is actually waiting on.
Transactions are only ever inserted, never updated or deleted, and a house's balance is a running total recomputed from that log by a Postgres function whenever a bill or payment changes. That gives me an auditable history and a balance I can always rebuild from source, without maintaining matched debit and credit entries for a level of bookkeeping formality this app doesn't need yet.
I'd planned to work through tables in a set order during a security audit, but recon showed the KYC document bucket was open to anyone with no ownership check. I patched that first as an emergency fix, out of the planned order, then continued the rest of the pass on schedule.
A pre-release security audit found that core tables (profiles, properties, houses, bills, transactions, roles) had Row-Level Security disabled, with Supabase's default anon grant still active. The anon key ships in every app build, so this wasn't a logged-in user having too much access, it was open read and write on the tables that mattered most. I enabled RLS across every sensitive table and locked storage down to ownership-scoped policies.
The KYC bucket had storage policies granting anyone access with no ownership check, and the bucket itself was set public, which bypasses storage RLS for reads entirely. That was the single most severe finding in the audit and the first thing I fixed.
The original invite acceptance ran as a public, unauthenticated function that assigned a tenant to a house on a bare request, trusting whatever phone number was encoded in the token rather than checking who was actually making the request. It also had no guard against two people accepting the same invite at once. I rebuilt it around a tracked invites table, a deep link into a native in-app screen, and a security-definer function that requires the caller to be authenticated and phone-matched before the assignment happens, with an atomic guard closing the race.
Independent of what any individual migration granted, Supabase's schema-level default lets the anon role execute every function unless a migration explicitly revokes it. I fixed this function by function as I found them. A broader platform-level default fix is still on my list, not done yet.
Tenants still see add-bill and delete-bill buttons that RLS now correctly rejects server-side. It's not a security hole anymore, just an interface that hasn't caught up to the access model yet.
Rynto is live in production, in daily use by real property owners and tenants, at version 1.0.0 across both stores. It's been through a real security audit and a full invite-flow rework since it first shipped, and I'm still actively maintaining it, not treating it as done.