Identity and tenancy
Overview
Tenant boundary, users, memberships, platform roles, tenant roles, permissions, settings, subscriptions, legal entities, tax registrations, and document sequences.
Responsibilities
- Authenticate users and issue access and refresh tokens. Controllers for that live in
src/common/auth. - Bind a user to tenants through
Membership. - Resolve permission strings for
PermissionsGuard. - Keep tenant settings and subscription flags that the sync scheduler reads.
Architecture
JWT carries tenantId. JwtAccessGuard rejects the token if that tenant no longer exists. Prisma then applies the tenancy extension. See Tenancy and Authentication.
Code map
| Piece | Path |
|---|---|
| Features | src/modules/identity (tenant, user, user-setting, tenant-setting, tenant-role, role-permission) |
| Auth | src/common/auth |
| Schema | 10-tenant.prisma, 11-identity.prisma |
Data model
Tenant, TenantSetting, TenantSubscription, LegalEntity, TaxRegistration, DocumentSequence, User, Membership, TenantRole, TenantRolePermission, MembershipRole, Permission, PlatformRolePermission, UserSetting, Device.
Permission and PlatformRolePermission are global. They are not filtered by tenant.
Business rules
- Non-public routes require an access JWT, except
@PublicRouteand the metrics bypass. - Sync scheduling requires
tenant.isActiveandsubscription.isActive. - Unknown: whether an inactive subscription blocks HTTP, and what
SubscriptionTiermeans commercially.
API surface
Tenant, user, role, and auth routes. OpenAPI is the field list. Invite email uses email_queue job tenant-invite-email.
Events and queues
No outbox types were found for identity. Email jobs are Bull.
Failure scenarios
Stale tenant on the JWT returns auth.error.staleSession. Forgot-password does not reveal whether the email exists.
Development
New tenant-owned tables must be classified in the tenancy extension. New routes that should not be world-to-authenticated need @RequirePermissions.