SECTION 0 — MULTI-TENANCY IS A BOUNDARY SYSTEM
Multi-tenancy failures are usually boundary failures:
-
data leaks across tenants
-
inconsistent authorization
-
billing and quota mismatch
Senior fullstack means you design tenant isolation so it’s hard to violate.
SECTION 1 — REQUIREMENTS
-
Users belong to one or more organizations (tenants).
-
Roles: owner/admin/member.
-
Tenant-scoped resources (projects, tickets, documents).
-
Billing plans, quotas, usage tracking.
Non-functional:
-
Security: no cross-tenant data exposure.
-
Correctness: consistent authZ across UI/API.
-
Operability: tenant-level debugging and support.
SECTION 2 — INVARIANTS
-
Every tenant-scoped row has a
tenant_id. -
Every request executes with an explicit
active_tenant_id. -
Authorization checks are centralized, not duplicated.
-
Billing is evaluated at the same boundary as authorization.
SECTION 3 — DATA ISOLATION STRATEGIES
Options:
-
shared DB, shared schema (tenant_id column)
-
shared DB, separate schemas
-
separate DB per tenant
Senior default for most SaaS:
- shared DB + tenant_id + Row Level Security (RLS) where supported.
RLS benefits:
-
makes data leaks harder
-
forces every query to be tenant-aware
SECTION 4 — AUTHZ MODEL (RBAC + RESOURCE CHECKS)
-
membership table:
(user_id, tenant_id, role) -
policy checks:
-
role-based rules
-
resource ownership rules
-
Senior rule:
AuthZ should be testable as a pure function: can(user, action, resource).
SECTION 5 — FRONTEND–BACKEND CONTRACT (TENANT CONTEXT)
-
UI must always know the active tenant.
-
API must require tenant context:
-
header:
X-Tenant-Id -
or tenant in path:
/tenants/{tenantId}/projects
-
Prefer path-scoped for clarity and caching.
UI state machine:
-
tenant not selected
-
tenant selected
-
membership revoked (force reselect)
SECTION 6 — BILLING BOUNDARIES (PLAN + QUOTA)
Decide where you enforce quotas:
-
at write endpoints (recommended)
-
async enforcement (dangerous for abuse)
Mechanism:
-
usage counters per tenant
-
plan limits
-
enforce on critical writes
Senior rule:
Billing must fail closed for abuse-prone operations.
SECTION 7 — FAILURE MODES
-
missing tenant_id filter in a query → prevented by RLS / query builders
-
cached data leaks → ensure cache keys include tenant_id
-
user removed from tenant but UI still shows data → backend must enforce and return 403; UI reacts
SECTION 8 — OBSERVABILITY
-
tenant-scoped logs (tenantId in every log)
-
per-tenant request rates
-
authZ deny rates
-
quota enforcement events
SECTION 9 — EXERCISES
-
Define your tenant isolation strategy and why.
-
Design your authZ function signatures and test cases.
-
Decide path vs header tenant context and document tradeoffs.
-
Define quota enforcement points and failure responses.