0011. One PostgreSQL database per tenant¶
- Status: Superseded by 0012
- Date: 2026-10-01
Context¶
BizOS isolates each customer company. ADR-0003 chose PostgreSQL and left the tenancy model open: one database per tenant, one schema per tenant, or a shared schema with a tenant column. The control plane still has to store the tenant registry, operator data, and platform records apart from tenant business data. The same tenant schema must be migrated on every tenant database.
Options considered¶
- One database per tenant, plus one control-plane database. Strong isolation and independent backup, at the cost of many databases and a migration fan-out.
- One schema per tenant in a shared database. Fewer databases to operate, but weaker isolation and a noisy neighbor on connections, locks, and backups.
- One shared schema with a tenant column on every row. Simple operations, but a missing filter leaks data across customers.
Decision¶
Use one control-plane database and one PostgreSQL database per tenant. Drizzle applies the migrations in db/migrations/tenant/ to each tenant database. Connection strings are derived from the tenant's database name and an admin URL; they are not stored in the registry.
Consequences¶
- Tenant data is isolated at the database boundary. Control-plane modules do not join tenant tables.
- Provisioning creates a database, then runs the shared tenant migrations. The runner must be idempotent so a retry is safe.
- The API keeps one pool per active tenant and closes idle pools.
- Operators suspend, reactivate, and place a tenant in maintenance by changing registry state. The platform rejects non-active tenant requests.
- This closes the tenancy-model question left open by ADR-0003. ADR-0003 itself is unchanged.