The 19 permission keys and the seeded system roles
Roles & Permissions
Access is governed by a permission matrix, not fixed roles. Each workspace has roles; each role is a set of permission keys in one of two scopes. Every key in the matrix is checked by something that ships — a route, a page or a database row-security policy — so a ticked box always does something. There are 19 keys.
Organization scope
Held through the member's org role (org_members.org_role_id):
| Key | What it allows |
|---|---|
org.manage | Edit the workspace (name, type) |
org.billing.read | See the plan and open the billing portal |
org.billing.manage | Start or change the subscription and seats |
org.members.invite | Invite members |
org.members.manage | Change members' roles, reset passwords, remove members |
org.roles.manage | Create, edit and delete roles |
athletes.create | Add athletes — and send athlete invites |
athletes.update | Edit athletes |
athletes.delete | Delete athletes and merge duplicates |
athletes.assign_coaches | Assign coaches to athletes; see the whole roster |
coaches.view_all | See every coach's sessions and schedule |
Athlete scope
Held per athlete through the coaching assignment (athlete_coaches.athlete_role_id):
| Key | What it allows |
|---|---|
sessions.read | View the athlete's video sessions |
sessions.write | Annotate and review their sessions |
training_sessions.write | Schedule and edit their training sessions |
drills.assign | Assign drills |
competitions.write | Add or import competition results |
messages.write | Message the athlete |
video.upload | Upload footage for the athlete |
qualifications.write | Edit qualification pathways |
Seeded system roles
| Workspace type | System roles |
|---|---|
| instructor | Owner (org), Coach (org), Head Coach (athlete), Assistant Coach (athlete), Viewer (athlete) |
| pro_coach | Owner (org), Coach (org), Head Coach (athlete), Specialist (athlete), Viewer (athlete) |
- Owner has every key and cannot be edited.
- Coach is a plain membership with no org-scope keys — a coach's access to athletes comes entirely from their per-athlete coaching role.
- Head Coach has every athlete-scope key plus
athletes.createandathletes.update. - Assistant Coach (instructor):
sessions.read,sessions.write,training_sessions.write,drills.assign,messages.write,video.upload. - Specialist (pro_coach):
sessions.read,sessions.write,video.upload,drills.assign,messages.write. - Viewer:
sessions.readonly — every other read a Viewer makes flows through row security on the assignment itself.
Create and edit roles
Workspace → Roles (requires org.roles.manage) groups roles into Workspace roles and Coaching roles. New in the section for the scope you want, name it, tick keys (grouped Organization and Athlete), Save. Custom roles can be deleted; system roles cannot; the Owner role is locked.
How effective permissions are computed
For a given athlete and coach, an athlete-scope key resolves as the assignment's per-key override if one is set, otherwise the assigned role's value, otherwise false — with these exceptions: super admins bypass every check; an athlete can read their own data; an org admin holding athletes.assign_coaches passes athlete-scope checks for any athlete in the workspace.
Coach data isolation
Isolation is enforced by Postgres row-level security, not just the UI. A coach who is not an admin can only see and act on athletes they are assigned to — profile, sessions, training sessions, drills, results. The coach who creates an athlete is assigned automatically. Owners and admins (anyone with athletes.assign_coaches) see everything. Drills are shared workspace-wide.
See Members & Multi-Coach for how roles reach people.