Revix is multi-tenant from the first migration: every seller's reviews, sessions, billing and settings live in one PostgreSQL database with 31 tables. In a system that posts to a merchant's public storefront, a tenant leak is not a bug — it is one merchant's reply landing on another merchant's store.
What I built
Recurring billing keys with three tiers, trials, consent capture before authorization, dunning and refund-driven cancellation, with quota decisions as pure functions. Merge-under-lock persistence, corrupt-file repair, a collection coverage ledger, and Alembic migrations. A versioned consent ledger, account deletion with a grace period and scheduled destruction of personal data.
Three failures and how they were actually found
Row-level security that had never once run. The policies existed, were switched on, and looked healthy. But the application connected as the table owner — and owners bypass RLS automatically. Every tenant boundary still rested on application code remembering to filter. I built a dedicated non-bypassing role with minimal grants and session-variable tenant policies, and classified all 31 tables into four isolation categories, documenting why the users table deliberately cannot be tenant-keyed (login happens before a tenant is known).
A silent lost update deleting freshly collected reviews. Atomic replacement protected against corrupt writes, not stale ones. Two threads each wrote a whole in-memory snapshot back to disk, erasing rows the collector had appended seconds earlier. Four collector paths held the advisory lock; nineteen application writers did not. I replaced all of them with one merge-under-lock write path — acquire, re-read, merge, replace atomically, never let an empty value overwrite a filled one — plus a test that fails the build if a lock-free whole-file write reappears.
Webhooks that corrupted a subscription on redelivery. Idempotency was derived from a unique constraint on payment rows, so every webhook branch that creates no payment row — cancellations, billing-key deletions — re-ran its side effects on every redelivery. I added an event-level ledger keyed on the provider's webhook id, claimed before processing and released if processing crashes. Signature verification moved to the Standard Webhooks spec and is fail-closed in production.
Principles I now build by
Prefer the database to the application: a uniqueness constraint beats a boot-time lock, a non-bypassing role beats remembering to filter. Every fix leaves a guard behind — a failing test, a constraint, a raising constructor. Fail closed on anything shared.
Scale
79,517 lines of Python (42,418 product, 37,099 tests). 2,245 test functions, 4,970 assertions. 1,852 commits, one author. GitHub Actions runs the full suite on every push.
Before/after: the application connected as the table owner, so no RLS policy had ever been evaluated.
The single write path that replaced 19 lock-free writers.
Event-level idempotency: claimed before processing, released on crash, signatures fail-closed.
Like this project
Posted Aug 25, 2026
RLS that had never run, a lost-update bug fixed with merge-under-lock, and webhooks made idempotent with an event ledger. 31 tables, 2,245 tests, one author.