Multi-Tenancy
Multi-Tenancy
Section titled “Multi-Tenancy”flowgeist.tool is a B2B SaaS: every business entity belongs to exactly one tenant (customer organization). Strict data isolation between tenants is a hard requirement — it is part of the product’s security model.
Tenant model
Section titled “Tenant model”- Tenant entities carry a
tenant_idforeign key. - The
TenantResolverGuardresolves the tenant context early in the guard pipeline — before authentication and authorization. - Queries must always be scoped to the resolved tenant. A resource from a different tenant must behave as if it does not exist (404, never 403-with-leak).
Isolation rules
Section titled “Isolation rules”- Every query is tenant-scoped. When writing Prisma queries, always include the tenant filter — never rely on “the ID is unguessable”.
- Cross-tenant access returns 404. Do not distinguish “not found” from “belongs to another tenant” — that would leak existence.
- Tenant context comes from the server side (JWT claim / resolved tenant), never from a client-supplied parameter alone.
- Super-Admin is the only role that can act across tenants (provisioning, tenant lifecycle: ACTIVE → SUSPENDED → TERMINATED).
Tenant lifecycle
Section titled “Tenant lifecycle”| Status | Effect |
|---|---|
ACTIVE |
Normal operation |
SUSPENDED |
Users set INACTIVE, login refused |
TERMINATED |
Soft-deleted (no purge — audit trail) |
Tenants are provisioned through a dedicated M2M API
(/api/v1/provisioning/*) authenticated by a shared secret with
timing-safe comparison — it fails closed (503) when the secret is not
configured.
Testing requirement
Section titled “Testing requirement”Every service test must verify tenant isolation:
- Reading/updating a resource owned by another tenant →
404/NOT_FOUND. - List endpoints must not leak other tenants’ rows.
- Use synthetic fixtures only — no PII in test data
(
example.comdomains, synthetic UUIDs).