POST-MORTEM #041
Next.js, Node.js, Python, PostgreSQL
The Next.js app, the Node.js webhook worker, and a Python reconciliation job all used a service-role credential. Twelve billing tables were readable without a tenant check, and the dashboard ran about 40 queries per page.
Next.js App Router for the product, Node.js for Stripe webhooks, Python for reconciliation, PostgreSQL as the ledger store.
Keep the existing UI and billing flow. Put tenant checks in the database, not in a client-supplied organization id. Make the Node.js webhook and the Python job idempotent against the ledger.
Row policies now key off membership. The dashboard reads one Postgres function instead of a query waterfall. Stripe events and the reconciliation job both post once. Pooling stopped serverless invocations from exhausting connections.
Two-tenant SQL tests on every exposed table. A replayed webhook and a rerun of the Python job left the ledger unchanged. Query plans compared before and after on the main dashboard route.