The permission matrix and seeded system roles
Roles & Permissions
Access in Surflink is governed by a custom permission matrix, not fixed roles. Each org has roles, and each role is a set of permission keys.
Permission scopes
Permissions come in two scopes, and a role belongs to exactly one of them:
- Org-scope (
org_members.org_role_id) -- organization-wide capabilities. Keys includeorg.manage,org.billing.read,org.billing.manage,org.members.invite,org.members.manage,org.roles.manage,athletes.create,athletes.delete,athletes.assign_coaches. - Student-scope (
athlete_coaches.athlete_role_id) -- what a coach may do for the athletes they're assigned to. Keys includesessions.read/write/delete,training_sessions.read/write/delete,drills.read/write/assign,goals.read/write,game_plans.read/write,competitions.read/write,season_reports.read/write/share,messages.read/write,notifications.send,video.upload,video.annotate,fitness.read/write,qualifications.read/write,journal.read/write.
Seeded system roles per org type
| Workspace type | System roles |
|---|---|
| instructor | Owner (workspace), Coach (workspace), Head Coach (student), Assistant Coach (student), Viewer (student) |
| pro_coach | Owner (workspace), Coach (workspace), Head Coach (student), Specialist (student), Viewer (student) |
- Owner has every permission and cannot be edited.
- Coach is a plain org membership with no org-admin powers -- a coach's access to athletes comes from their per-athlete student role, not this org role.
- Admin has everything except
org.billing.manage. - Head Coach has all student permissions plus
athletes.create. - Assistant Coach / Specialist are coaching roles with session, video, drills, and messaging access.
- Viewer is read-only.
- Front Desk can create students and handle training sessions/messages.
Create and edit roles
In Workspace -> Roles (requires org.roles.manage), roles are grouped into Workspace roles and Coaching roles:
- Click New in the section for the scope you want (org / coaching).
- Rename it and tick the permissions you want -- they're grouped into Organization and Student.
- Save. Custom (non-system) roles also have Delete role.
The Owner role is locked (all permissions, uneditable). System roles can't be deleted.
How effective permissions are computed
For a given athlete and coach, the effective student-scope permission for a key is:
permissions_override[key] ?? assignedRole.permissions[key] ?? false
with these overrides:
- Super admins bypass all checks.
- A student can read their own data (keys ending in
.read). - An org admin with
athletes.assign_coachespasses student-scope checks for any athlete in the org.
Coach data isolation
Access is enforced at the database level (Postgres row-level security), not just in the UI. A coach who is not an org admin can only see and act on the athletes they are assigned to (via the athlete's Coaches tab). This covers an athlete's profile, sessions, training sessions, equipment, journal, goals, assessments, competitions, and game plans - another coach's athletes are simply invisible to them.
- Owners / admins (anyone with
athletes.assign_coaches) still see the whole roster. - The coach who creates an athlete is automatically assigned to them, so they keep access immediately.
- Shared coaching libraries (Drills and Spots) remain visible org-wide so the whole team can reuse them.
See Members & Multi-Coach for how roles get assigned to people.