Software that survives production: the ledger and the 158 RLS policies behind Niiko
EngineeringProductNiikoPostgreSQL

The impressive part of a product is the outer layer. Underneath Niiko there is a ledger the database itself keeps honest, a row-level wall between every client, and a rule that nothing is ever edited or deleted.
Niiko is the operating system we built for our own studio — clients, billing, work, one record — and then for other businesses that run on WhatsApp and spreadsheets and the memory of whoever answered the chat. When money and other people's data go through your software, the question is not whether it is fast. It is whether it is still right a year later, after a bad deploy, a restored backup and a thousand corrections.
A ledger the database enforces
Every amount in Niiko is a double-entry ledger, and the balance is not something the application promises — it is a constraint the database refuses to break. Nothing in the ledger is edited or deleted. A mistake is corrected by a new entry, with the original left where it was, so the history you audit is the history that happened.
We learned the hard way that «append-only» has to be designed, not declared. The first version blocked its own correction path; the fix was to make the correction another entry, not an update. That lesson is now a public repository with the failing test in it, because a rule without its test is prose.
One wall per client, inside the database
Isolation between clients is not a WHERE clause somebody remembers to add. It is row-level security in Postgres: 158 policies, live in production, that decide what a connection can see before any application code runs. The subtle failure — a pooled connection carrying the previous request's identity — has its own probe, because it compiles, the unit tests pass, and the data is crossed.
A right to be forgotten that a backup cannot undo
Personal data in Niiko is encrypted per person. Forgetting someone means destroying their key — and then the restored backup from last month cannot bring them back either, because their rows are noise without it. You cannot delete what you never encrypted per subject; we encrypted per subject.
Billing is idempotent and two-phase: a retry cannot charge twice, and a half-finished operation cannot leave money in a state no human agreed to. None of this is visible in a demo. All of it is why the demo is still true in production.
- Modular micro-kernel: modules with hard boundaries, wired by declarative grants and an event catalog that continuous integration verifies.
- Every public action is one typed method in the SDKs (TypeScript and Python), one command in the CLI, one operation in the n8n node — all generated from the same manifest.
- The lessons are public: ledger invariants, RLS per request, crypto-shredding erasure, idempotency of the effect — each a repository with the test that catches the mistake.
// Experience itOpen niiko.org