# ADR 0020: Organization Is The SaaS Tenant Root ## Status Accepted. ## Context The Hub is moving from a single-organization deployment assumption toward a SaaS shape. The existing permission model already supports team principals via `PermissionGrant(PROJECT, TEAM, role)`, but without a tenant root the data model cannot safely answer: - which customer owns a project; - which organization a team belongs to; - whether a team grant crosses customer boundaries; - which external directory sync produced a Feishu department/user-group membership; - where future org admin, billing, audit, and platform break-glass controls attach. Retrofitting this after projects, teams, runs, and audit records grow would force tenant assumptions into every caller. ## Decision Introduce `Organization` as the SaaS tenant root. Customer-side collaboration data is organization-scoped: ```text Organization OrganizationMembership Team TeamMembership Project ExternalDirectoryConnection PermissionGrant ``` `User` remains global. A user can belong to multiple organizations through `OrganizationMembership`. Project-level authorization still uses `PermissionGrant` and `PermissionAuthorizer`; the authorizer derives the organization from the requested resource, then resolves teams and external principals in that organization scope. `Team` belongs to exactly one organization. `Project` belongs to exactly one organization. A `PermissionGrant` that grants a `TEAM` principal on a `PROJECT` resource is valid only when the team and project are in the same organization. This invariant is pinned in `Spec.System.Organization`. External directory membership is scoped through `ExternalDirectoryConnection`: ```text ExternalDirectoryConnection( organizationId, provider, providerTenantId, source ) ``` `ExternalPrincipalMembership` points at a connection rather than carrying a free-floating `source` string. `source` names a sync pipeline; it is not the tenant identity. The SaaS platform control plane is separate from customer project permissions. `READ/EDIT/MANAGE` remains the customer-side project permission lattice. Platform staff access, tenant suspension, billing, and break-glass access are a separate control plane and must not be modeled as project `MANAGE`. ## Consequences - Existing single-org data is backfilled into a default organization during migration. - `Team.slug` becomes organization-scoped instead of globally unique. - Actor resolution is organization-aware: direct teams and synchronized external principals only expand inside the resource's organization. - Direct `USER` grants remain possible because a global user can collaborate across organizations when explicitly granted. - Future org admin UI can be built on this model without changing the authorization core. ## Open Questions / Deferred - Full platform admin UI, billing, and tenant suspension workflows are deferred. Production safety limits and workload brakes are no longer deferred; ADR-0022 defines them without treating a workload brake as tenant suspension. - Whether direct `USER` project grants should require active `OrganizationMembership` is deferred; explicit direct grants remain allowed for now. - Provider-specific directory semantics beyond Feishu are deferred, but the connection model leaves room for them.