🏗️ Architecture
Multi-Tenant Data Flow
How requests are scoped to tenants throughout the stack.
Request Flow
Diagram source
sequenceDiagram
Client->>API: Request + JWT
API->>JWT: Decode tenantId
JWT->>RequestContext: Set tenantId
RequestContext->>Guard: TenantPermissionGuard
Guard->>Service: tenantId filter active
Service->>Repository: WHERE tenantId = :id
Repository->>Database: Scoped query
Database-->>Client: Tenant-specific dataLayer-by-Layer
1. JWT Token
Every JWT contains the tenantId:
{
"id": "user-uuid",
"tenantId": "tenant-uuid",
"role": "ADMIN",
"exp": 1735689600
}2. RequestContext
RequestContext stores the current tenant in async local storage:
RequestContext.currentTenantId(); // returns tenant UUID3. Guard Layer
TenantPermissionGuard validates:
- Token contains valid
tenantId - Tenant exists and is active
4. Service Layer
All services extend TenantAwareCrudService which auto-filters by tenant:
// Automatically adds WHERE tenantId = :currentTenant
const tasks = await this.taskService.findAll();5. Repository Layer
Query builders append tenant filter:
SELECT * FROM task
WHERE "tenantId" = 'tenant-uuid'
AND "organizationId" = 'org-uuid'Cross-Tenant Access
Only SUPER_ADMIN role can access data across tenants.
Related Pages
- Tenant Isolation — security deep dive
- Multi-Tenancy — architecture overview
- Request Lifecycle — full request flow