Roles
Admin → Roles (/admin/roles) lists the five built-in roles and — on
Command+ plans — lets a superadmin define custom roles with fine-grained
permissions. The list of built-in roles is fixed; you cannot delete or rename
them, only view what they can do.
Only superadmin can open this page. Everyone else gets redirected to the
dashboard by the route guard.
The five built-in roles
From OrgRole in org.ts, in descending privilege:
| Role | Level | Badge | Typical use |
|---|---|---|---|
superadmin | L1 | red | Platform owner. Sees every org, can change plan, manage roles. |
admin | L2 | amber | Org administrator. Invites, billing, DJI, webhooks, workflows. |
manager | L3 | cyan | Team/shift lead. Runs missions, invites operators, no billing. |
operator | L4 | green | Pilot / field user. Joins missions, pilots drones, uses PTT. |
observer | L5 | grey | View-only. Watches live feeds, cannot publish. |
ADMIN_ROLES in code is ['superadmin', 'admin'] — those are the two roles
the Firestore rules check for any write to an org-scoped document outside the
user’s own profile.
Capability matrix
| Capability | superadmin | admin | manager | operator | observer |
|---|---|---|---|---|---|
| Create / deactivate orgs, change plan | ✓ | — | — | — | — |
| Invite members, change roles | ✓ | ✓ (≤ own) | ✓ (op/obs) | — | — |
| Pair DJI docks, create venues/assets | ✓ | ✓ | — | — | — |
| Configure webhooks / workflows | ✓ | ✓ | — | — | — |
| Create missions, pilot (DRC), publish TACLINK | ✓ | ✓ | ✓ | ✓ | — |
| Subscribe to TACLINK (listen/watch) | ✓ | ✓ | ✓ | ✓ | ✓ |
| Create custom roles | ✓ | — | — | — | — |
| Export mission reports | ✓ | ✓ | ✓ | ✓ | — |
The helper roleAtLeast(role, minimum) gates features throughout the
code — e.g. roleAtLeast(me.role, 'manager') is the check for “can start
a mission”.
Editing a built-in role
Click any built-in role on the left to open its detail pane. You can view the permission list but Edit is disabled — built-ins are the contract the Firestore rules trust. If you need a tweak, clone it into a custom role.
Custom roles (Command+ plans)
Custom roles ship on the Command and Sovereign plans; Guardian and
Tactical see a padlock banner reading “Custom roles require Command plan or
higher”. The feature flag is PlanFeatures.customRoles and the Firestore
rules enforce it at write-time too.
Creating a custom role
Click Create role in the header. The form asks for:
- Role name — free text, e.g.
SAR Team Lead. - Description — one-liner shown in the member picker.
- Hierarchy level — integer 5–99. Lower numbers have more privilege. Built-ins occupy levels 1–5 so custom roles always sit below.
- Colour — picked from the 12-swatch palette. Drives the badge tint.
- Permissions — multi-select checkbox grid grouped by module
(Missions, Teams, DJI, Webhooks, Reports, …). Each permission is an
{action}.{resource}string such asread.mission,write.flight_task,approve.workflow_step.
Save writes the role to
/organizations/{orgId}/customRoles/{roleId} and it becomes selectable in the
Users page role picker alongside the built-ins.
Assigning a custom role
On Users, the role dropdown shows built-ins then a
divider then your custom roles. Assigning one sets
OrgMember.customRoleId and leaves OrgMember.role at the built-in base
(for Firestore-rules back-compat). The rules check custom roles first and
fall back to the base role if the custom role doc is missing.
Deleting a custom role
Popover-confirmed. Any member currently holding the role is automatically
downgraded to the base role field. Deletion is logged as
admin.role.deleted in the audit stream.