Skip to main content

Deployment Architecture

Shared multi-tenant model: one deployment serves all tenants. Isolation is logical (a tenantId column plus a tenant-scoped data layer), not one stack per client — see Multi-Tenancy.

Isolation Boundaries

ResourceScope
Application containerShared across all tenants
PostgreSQL databaseShared — isolated per tenant by tenantId and the tenant-scoped Prisma client
Blob storageShared account; blob keys carry tenant context and downloads re-check the requester's tenant
Domain + TLS certificateOne platform domain; tenants addressed at /t/{slug}
Azure app registration (SSO)One platform app; per-tenant entraDirectoryId enables verified SSO auto-approval
Azure app registration (email-to-ticket)Shared — the platform SSO app, used against each tenant's entraDirectoryId. Needs Mail.ReadWrite + Mail.Send application permissions

:::caution Isolation is enforced in code There is no database-per-tenant or Postgres row-level security. The boundary is the tenant-scoped Prisma client plus the CI guard (scripts/check-tenant-scoping.ts). Any new tenant model must be added to TENANT_MODELS, and any raw-client use must be justified and whitelisted. :::

Requirements

  • Public HTTPS domain (Graph webhooks and Teams both require it)
  • Outbound access to Microsoft Graph, Entra ID, Azure Blob, and the SMTP host
  • A container host and a PostgreSQL instance sized to the combined tenant volume
  • Scheduled-job execution (SLA checks, reminder firing, Graph subscription renewal)

See Deployment Runbook, Docker, and Tenant Provisioning.