Skip to content

Tenancy

Tenancy

Tenant isolation is a first-class runtime concern. Many views depend on request.tenant, X-Tenant-ID, and tenant membership checks to determine what the caller can see or mutate.

Core building blocks

  • api.tenancy.middleware.TenantMiddleware resolves the current tenant for the request.
  • api.tenancy.middleware.TenantRequiredMiddleware enforces tenant presence for paths that need it.
  • api.tenancy.models.Tenant and TenantMembership own the workspace and membership records.
  • api.permissions.IsTenantMember and IsTenantManager enforce role-based access.
  • api/views/tenant_views/* expose the tenant CRUD and membership API.

Membership semantics

The repository uses tenant membership in several ways:

  • Microsoft auth auto-creates membership when a user signs in with a Microsoft tenant.
  • Billing and org invite endpoints require membership to the current tenant.
  • Activity logs allow staff users or tenant managers/admins.
  • Document processing and schema management are tenant scoped even when the route itself is global.

TenantMembership is the primary authorization record. The current tenant is usually pulled from middleware, not from ad hoc route parameters.

Tenant viewset family

The tenant route family is split by responsibility:

  • TenantViewSet — tenant CRUD and list/detail operations.
  • TenantMembershipViewSet — membership list/create/update/delete and nested member routes.
  • tenant mixins — branding and tenant switching helpers.

This separation matters because membership operations use different authorization rules from tenant CRUD.

Request flow

flowchart TD
A[HTTP request] --> B[TenantMiddleware]
B --> C{X-Tenant-ID or session tenant?}
C -->|resolved| D[request.tenant set]
C -->|missing| E[TenantRequiredMiddleware may reject]
D --> F[View checks membership/role]
F --> G[Tenant-scoped queryset or mutation]

Invariants

  • Tenant-scoped endpoints should not assume the current tenant comes from the URL.
  • Membership checks happen in permissions and sometimes again inside the view when the business rule is stricter than the permission class.
  • Background workers do not have the request context that middleware provides, so worker code often has to use all_objects or explicit tenant keys.

Validation

  • tests/unit/auth/test_auth_and_tenancy_contracts.py — cross-checks auth and tenant isolation contracts.
  • tests/unit/auth/test_ms_tenant_org.py — Microsoft-driven tenant creation and binding.
  • tests/integration/test_viewsets.py — nested route behavior for tenant endpoints.

Scope boundary

This page documents the tenant isolation layer. For org invitations, read Organization settings. For billing usage, read Billing. For tenant-aware processing documents, read Document processing.