Platform Design
Identity & Tenancy
How customers, users, and data are modeled from day one: a global control-plane registry of organizations, one isolated data plane per customer, and delegated enterprise SSO that customers configure themselves through Auth0.
Status: proposed design
Two data planes
The platform keeps two very different kinds of data apart. A small, highly available control plane is our customer registry and the thing our IaC reads and writes — it never holds PHI. Each customer then gets its own data plane: a Postgres deployed where their cluster lives, holding users, sessions, their forked lesson library, and PHI.
organizations · infra/provisioning state · Auth0 mappings · billing — no PHI
Mercy Health
Azure · us-east
Charité Berlin
GCP · europe-west3
Shared pool
Azure · us-east
One control-plane registry routes every org to its own data plane. Residency follows the tenant DB; no tenant holds another tenant's data.
The organizations registry
organizations is the top-level entity and the system of record for every customer — the central control point where placement, infrastructure, identity, and compliance all hang off one row. It is the seam between our IaC and the running platform.
Identity
- name
- slug
- status (trial · active · suspended)
Placement
- tier (dedicated · shared)
- cloud (azure · gcp)
- region
- version_pin
Infra binding
- pulumi_stack
- cluster_endpoint
- tenant_db_ref (secret)
BYO-cloud
- cloud_credentials_ref (secret store, never raw)
Auth0 binding
- auth0_org_id
- connection_ids
- verified_domains
Compliance
- data_residency
- baa_signed
- isolation notes
Onboarding is a pipeline keyed off the org row
Adding a customer — today by us, later via a sign-up or trial button — is an ordered, auditable pipeline. The org row is the durable orchestration record: each step records status and is idempotent on retry.
1 · Create org row
Tier, cloud, region, version chosen in the control-plane registry.
2 · Trigger Pulumi stack
Parameterized stack provisions the cluster + tenant Postgres.
3 · Fork starter content
Lumeto template scenarios are copied into the tenant DB.
4 · Auth0 Org + SSO ticket
Mint the Auth0 Organization and a self-service access ticket.
5 · Write outputs back
Endpoints, DB ref, auth0_org_id, domains saved onto the org row.
Self-serve enterprise SSO
Customers are hospitals and medical schools that authenticate against their own directories and want to wire up SSO themselves. We use Auth0 Self-Service Enterprise Configuration so the setup is documentation-driven and hands-off on our side.
Profile — a reusable whitelist
A profile is a template (max 20 per tenant) listing which IdPs the assistant offers and which attributes to capture. It is not per customer — it's the cookie-cutter that many customers are stamped from.
Ticket — one per customer
Onboarding mints a one-time access ticket from a profile, bound to the customer's Auth0 Organization. We send the URL plus our docs; it grants their admin scoped access to set up exactly one connection.
Connection + Org — the result
The finished Enterprise connection lands in our tenant under the customer's Auth0 Organization (1:1 with the org row) — the membership and org-aware login anchor.
Start with one permissive profile
Entra ID (OIDC), Generic SAML, and Google Workspace — most customers are Microsoft Entra and can pick OIDC or configure Entra as SAML themselves. We only add a second profile when we need to restrict rather than enable — e.g. a regulated profile that forces SAML and requires SCIM + domain verification. The per-customer variation lives in the ticket and connection, never in new profiles.What the customer admin does in the setup assistant
- 1Select identity provider (Entra ID, Okta, Google, ADFS, Ping, OIDC/SAML)
- 2Create the application in their IdP (guided instructions)
- 3Configure the connection (domain, client id/secret)
- 4Map claims to our User Attribute Profile
- 5Assign user/group access
- 6Test SSO — then enable
Routing and provisioning users
Email-based routing
Organization Domain Discovery syncs verified domains to both the Auth0 Org and the connection's matching_domains. A user types their work email and is routed straight to their company's IdP — no tenant picker.
SCIM lifecycle
SCIM (offered in the assistant) is the primary path for create/update/deactivate, so disabling a user in the customer's IdP deprovisions them here. JIT-on-login is the fallback where SCIM isn't configured.
User Attribute Profile
A defined UAP fixes the claims we depend on — email, name, and a role/group signal for instructor vs learner — so the tenant users table is populated reliably.
Identity boundaries
auth0_org_id, connection ids, and verified domains. Actual user records, sessions, and PHI live exclusively in the tenant data plane, keyed by the Auth0 user id (sub). Enterprise customers are SSO-only; database connections are reserved for Lumeto staff and self-serve trials.Lumeto is its own organization
We model Lumeto exactly like a customer: its own Auth0 Organization backed by a Google Workspace enterprise connection (our daily-driver directory and single source of truth for staff identity). Eating our own dogfood keeps one consistent model and gives every Lumeto employee SSO with proper deprovisioning.
Google Workspace connection
One directory of record for Lumeto staff — not split across Google and Azure, so a departing employee is removed in one place. Our own Entra directory stays available only as an internal test IdP.
Staff are control-plane operators
Lumeto staff identities live in the control plane with elevated roles (provisioning, support, cross-tenant access) — they are not users inside any customer's tenant DB.
Authn vs authz
Google Workspace answers who a staff member is; control-plane roles answer what they may do to a given customer's org and infrastructure.