# ADR-001: Framework-level shared-schema tenancy with fail-closed scoping

- Status: Accepted
- Date: 2026-07-04
- Traces: SR-FND-001..006, NFR-SEC-01, RK-03, DBD §2.6

## Context
Shared database / shared schema with `company_id` on all business tables
(CON-T-09). The existential risk is cross-tenant leakage (RK-03).

## Decision
1. A request-scoped `TenantContext` set exactly once by middleware
   (session) or token resolution (API); immutable thereafter.
2. `CompanyScope` global scope applied via the mandatory
   `BelongsToCompany` trait on every tenant model; scope throws
   (fail-closed) when context is missing.
3. Write-side guards: auto-stamping, forged-company rejection,
   company_id immutability.
4. Single sanctioned bypass `withoutCompanyScope()`, restricted by
   architectural test to operator-realm namespaces and always audited.
5. Adversarial isolation test suite is a CI merge blocker and grows
   with every endpoint (SR-FND-005).
6. Connection resolution abstracted so DB-per-tenant (Enterprise
   Edition option) requires no module changes (SR-FND-004).

## Consequences
+ Isolation is structural, testable, and reviewer-visible.
+ DB-per-tenant path preserved.
- Every developer must know the trait rule — enforced by arch tests
  and PR checklist, not memory.

## Alternatives considered
stancl/tenancy (DB-per-tenant default conflicts with SaaS cost model at
10k tenants); manual where-clauses (unenforceable); MySQL views per
tenant (operationally impossible at scale, breaks cPanel parity).
