Skip to main content

Organizations & isolation

The organization tree

An organization is a tenant. Organizations form a tree: a parent org can have child orgs (departments, franchisees, downstream customers), each with their own users, roles, and applications.

  • A role's scope decides how far it reaches: SELF (this org only) or SUBTREE (this org and everything below it).
  • A parent-org admin can administer its children; a child cannot see up or sideways.

Every organization carries a materialized path (e.g. /1000001/57/903/) so ancestry is a single indexed lookup, not a tree walk.

Tenant isolation

Isolation is enforced at the database with PostgreSQL row-level security (RLS), keyed on tenant_id — not by application-layer WHERE clauses that a bug could forget. Every request runs under the caller's tenant context; the database itself refuses to return another tenant's rows.

The runtime connects as a non-superuser role so RLS actually applies (a superuser would bypass it). Trusted, user-less system operations — login before a tenant is known, cross-tenant automation — run under an explicit, audited bypass, never implicitly.

:::info Why this matters For a regulated tenant, "we filter by tenant in the query" is not a control an auditor accepts. RLS makes cross-tenant leakage a database-level impossibility, not a code-review promise. :::

Reaching organizations via the API

  • GET /api/organizations — the orgs within your reach (yours and below), keyset-paginated.
  • GET /api/organizations/search?q=… — search by name/slug.
  • POST /api/organizations — create a child (parentId).
  • POST /api/organizations/{id}/suspend · …/activate — lock a tenant out or restore it.

Suspending an org (or any org above it) stops its users from obtaining tokens — this is what makes a subscription lapse or an offboarding actually bite.