Platform Roles
Access is controlled by a 5-tier role hierarchy. Roles are stored in user_roles with gym_id IS NULL — that null gym is what makes a role a platform role rather than a gym role. There is no platform_roles table, and roles are never stored on the profile.
Role Hierarchy (highest → lowest)
| Role | Rank | Access Level |
|---|---|---|
| Super Admin | 1 | Everything, plus the actions reserved to it alone: changing a gym's status, suspending a gym, marking a gym as demo, VAT settings, AI prompt configuration, error logs, email intercept, Zoom. |
| Admin | 2 | All configuration and money pages: billing, pricing, plans, discounts, disputes, Stripe health, feature flags, all template libraries, communications, settings, roadmap, tasks, planning, ideas. |
| Manager | 3 | Gyms and gym detail, gym leads, demo bookings, analytics, support tickets, knowledge base, platform help KB, media library, chat access log. |
| Editor | 4 | The internal help centre only (/platform/help and its category/article pages). |
| Ideas | 5 | Lowest rank. Ranked below Editor, so it reaches nothing that sets a minimum role. |
Ranks come from get_platform_role_rank(). Routes are wrapped in <ProtectedRoute platformOnly minPlatformRole="…">; a role passes if its rank is at least as high as the one named.
Manager Variants
manager_sales and manager_support have identical data access and RLS to manager. The only difference is which dashboard sections render: a Sales Manager sees New Leads and Subscription Changes but not Support Tickets; a Support Manager sees the reverse. Never treat a variant as a security control.
UI guard versus real enforcement
minPlatformRole only decides whether a page renders. The real enforcement is RLS on each table, which is why a lower-ranked user may occasionally reach a page and see an empty or partial result set rather than an error.
Role Assignment
- Go to Settings → Platform Users.
- Select the user and choose the new role.
- The change is applied through the
change_platform_rolefunction rather than a direct table write, so it is validated and recorded. It takes effect on the user's next page load.
Grant the lowest role that does the job, and escalate temporarily rather than permanently.
What no platform role grants
- Membership of a gym — you must enter a gym to act inside it.
- Member chat message bodies without a logged, reasoned, 60-minute reveal.
- The service role key or database password. Neither is retrievable from the app.