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) orSUBTREE(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.