Concept

Multi-tenancy & security

One tenant must never see another's data. Coro treats this as a database-level guarantee, not a UI convention.

Every table has a tenant_id

There are no exceptions. Every row in every financial, operational, and reference table carries a tenant_id, and every query is scoped by it through Postgres Row-Level Security — not just a WHERE tenant_id = ? clause an application developer could forget to add.

What RLS actually buys you

  • A bug in application code can't leak cross-tenant data — the database itself refuses the row
  • Direct API calls are checked the same way the UI is, so editing the DOM never grants access the role doesn't have
  • Financial mutations run through Postgres functions with their own tenant and permission checks — a defense-in-depth layer beyond RLS

Roles, enforced twice

Role-based access control exists in the UI for a good experience, and again in RLS policies for the actual guarantee. An Auditor role sees every screen a Manager does, but every write attempt — from the UI or directly against the API — is rejected at the database.