Permissions
Purpose
Section titled “Purpose”Describe how access is governed beyond authentication: roles, per-user capabilities, and tenant-level limits and features.
Overview
Section titled “Overview”Access control has several layers:
- Roles —
agent<supervisor<admin<platform_admin. The JWT carries the role; handlers checkIsTenantAdmin()/IsPlatformAdmin(). Platform admins must be in the Platform tenant to wield cross-tenant power. - Capabilities — a per-user JSONB map (
users.capabilities) of resource →none/read/write, seeded from a role preset and individually overridable by a platform admin. Used for finer gating than the role alone. - Tenant limits —
tenants.limitsJSONB, platform-admin-only resource ceilings enforced in control-plane handlers (CheckTenantQuota); nothing on the call path. - Tenant features —
tenants.featuresJSONB, boolean entitlements, deny-by-default (e.g.self_service_carriers).
Configuration
Section titled “Configuration”Roles, capabilities, limits and features are managed through the admin/tenant
UIs and their endpoints (/users/{id}/capabilities, /tenants/{id}/limits,
/tenants/{id}/features) — not environment variables. Assign the narrowest role
that lets a user do their job.
Examples
Section titled “Examples”| Role | Can | Cannot |
|---|---|---|
| Agent | Handle calls, set dispositions, read own CDRs | Manage campaigns or users |
| Supervisor | Monitor live, run reports, QA scorecards | Provision tenants |
| Admin | Manage campaigns, users, routing, carriers | Touch other tenants |
| Platform admin | Provision tenants + edges, set limits/features | — |
- Enforce least privilege; capability overrides let you grant a single extra resource without changing the role.
- Permission checks are server-side (in handlers) — never rely on UI hiding.
- Most role enforcement lives inside handlers, so a route’s required role isn’t always visible from the route table alone.