ADR-0007 — Shared-DB multi-tenancy with tenant_id + Row-Level Security

V1 Freeze (2026-06-12): Accepted. Blocker-4 follow-up: the unsafe phrase “session GUC” is replaced by a transaction-local SET LOCAL context; the connection-pooling interaction is now decided in its own ADR-0038.

Context

BitVault is multi-tenant SaaS and self-hostable. Multi-tenancy is a security boundary: a cross-tenant data leak is catastrophic and is one forgotten WHERE tenant_id = ? away if isolation lives only in application code (R4). Options trade isolation strength against cost/operability: shared schema (cheap, weakest isolation), schema-per-tenant, database-per-tenant (strongest, costliest).

Decision

Consequences

Positive

Negative / costs

Alternatives considered

Verification

Two CI tests (see ADR-0038) guard the I3 invariant (08): (1) a forged tenant_id in the application layer → RLS still blocks cross-tenant reads/writes; (2) a pooled-connection bleed test across a transaction-mode pool → tenant B never observes tenant A’s rows, and a query without the context wrapper returns zero rows.