Overview
Roles & Permissions
The seven user roles in SalonOS and what each can access.
Role Model
SalonOS has seven roles arranged in a hierarchy. Every user has exactly one role within a given context (location or brand). Permissions are enforced by Row-Level Security at the database layer — the application UI reflects what the database allows.
| Role | Scope | Description |
|---|---|---|
| super_admin | Platform | Platform operators. Access to all tenants for support. Not visible to salons. |
| org_owner | Org | The business owner. Full access across all brands and locations they own. |
| brand_manager | Brand | Manages one brand: configures services, pricing, staff, and policies across all of the brand's locations. |
| location_manager | Location | Runs day-to-day operations at one location. Full operational access, limited configuration access. |
| front_desk | Location | Books appointments, manages walk-ins, processes checkout, manages clients. |
| stylist | Location | Views own calendar and client history. May add notes. Limited booking self-service (configurable). |
| client | Brand | Accesses client-facing surfaces: booking, portal, check-in, feedback. Never accesses the operator dashboard. |
Permission Matrix
Scheduling
| Capability | org_owner | brand_manager | location_manager | front_desk | stylist |
|---|---|---|---|---|---|
| View all staff calendars | Yes | Yes (brand) | Yes | Yes | Own day only |
| Create/edit appointments | Yes | Yes | Yes | Yes | Own, if enabled |
| Cancel / no-show | Yes | Yes | Yes | Yes | Own, if enabled |
| Manage walk-in queue | Yes | Yes | Yes | Yes | View/claim |
| Create non-bookable blocks | Yes | Yes | Yes | Limited | No |
| Override conflict/shift | Yes | Yes | Yes | If granted | No |
| Configure scheduling settings | Yes | Brand level | Location subset | No | No |
Client CRM
| Capability | org_owner | brand_manager | location_manager | front_desk | stylist |
|---|---|---|---|---|---|
| Create and edit clients | Yes | Yes | Yes | Yes | Notes only |
| View full client history | Yes | Yes | Yes | Yes | Yes (service-relevant) |
| Capture / withdraw consent | Yes | Yes | Yes | Yes | No |
| Add shared notes | Yes | Yes | Yes | Yes | Yes |
| Add private notes | Yes | Yes | Yes | If configured | Author only |
| Manage tags and segment rules | Yes | Yes (brand) | Tags only | Tags only | No |
| Merge duplicates | Yes | Yes | Yes | Flag only | No |
| Handle data-subject requests | Yes | Yes | Limited | No | No |
Checkout & Finance
| Capability | org_owner | brand_manager | location_manager | front_desk | stylist |
|---|---|---|---|---|---|
| Process checkout | Yes | Yes | Yes | Yes | No |
| Apply discounts / override price | Yes | Yes | Yes | If granted | No |
| Issue refunds | Yes | Yes | Yes | If granted | No |
| View invoices | Yes | Yes | Yes | Yes | Own services |
| Cash drawer open/close | Yes | Yes | Yes | Yes | No |
| View financial reports | Yes | Yes | Yes | No | No |
| Manage expenses and vendors | Yes | Yes | Yes | No | No |
| Configure commission rules | Yes | Yes (brand) | View only | No | No |
Staff Management
| Capability | org_owner | brand_manager | location_manager | front_desk | stylist |
|---|---|---|---|---|---|
| Create / edit staff profiles | Yes | Yes | Yes | No | Own profile |
| Manage shifts and schedules | Yes | Yes | Yes | No | No |
| Approve / deny leave requests | Yes | Yes | Yes | No | No |
| View attendance records | Yes | Yes | Yes | No | Own |
| Set performance targets | Yes | Yes | Yes | No | No |
| Assign tasks | Yes | Yes | Yes | Yes | Own tasks |
Marketing & Retention
| Capability | org_owner | brand_manager | location_manager | front_desk | stylist |
|---|---|---|---|---|---|
| Create and send campaigns | Yes | Yes | If granted | No | No |
| Manage loyalty and memberships | Yes | Yes | Yes | View/redeem | No |
| Issue gift cards | Yes | Yes | Yes | Yes | No |
| Manage segments and journeys | Yes | Yes | No | No | No |
| Configure review requests | Yes | Yes | Yes | No | No |
Settings & Configuration
| Capability | org_owner | brand_manager | location_manager | front_desk | stylist |
|---|---|---|---|---|---|
| Edit brand name, logo, colors | Yes | Yes | No | No | No |
| Manage service catalog | Yes | Yes | Location overrides | No | No |
| Configure integrations | Yes | Yes | No | No | No |
| Manage roles and invitations | Yes | Yes | Location staff | No | No |
| Configure SaaS billing | Yes | No | No | No | No |
Role Assignment
Roles are assigned when inviting a staff member:
- An org owner or brand manager creates an invitation with a specified role and location/brand scope.
- The invitee receives a link to set up their account.
- The role is stored in a
role_assignmentrecord linking the user, role, and scope (org / brand / location).
A user can hold different roles at different locations (e.g., location_manager at Location A and front_desk at Location B) but this requires separate role assignments.
Client Accounts
Clients are a separate user type. They authenticate through client-facing surfaces (booking page, portal) and never see the operator dashboard. Their permissions are limited to:
- Viewing and editing their own contact details and preferences
- Capturing or withdrawing their own consent
- Viewing their own booking history
- Submitting intake forms, consent waivers, and feedback
Super Admin
The super_admin role belongs to SalonOS platform operators, not salon staff. It allows:
- Viewing the Platform Overview dashboard (
/dashboard/super-admin) — all-tenant KPIs, tenant list - Viewing and impersonating any tenant for support
- Managing subscription plans and billing
- Running data exports and migrations
- Handling platform-level incidents
Super-admin access is logged in the audit trail and never exposed to tenant users.
Server-Side Role Enforcement (RBAC Middleware)
Role-gating is centralised in lib/auth/require-role.ts. Any server component or
server action can call one of three helpers:
await requireRole(["super_admin"]) // exact role list
await requireAnyAdmin() // location_manager and above
await requireManagerOrAbove() // brand_manager and above
The helpers read memberships.role from the database — they never trust
client-supplied values. An unauthenticated request redirects to /sign-in;
an insufficient role redirects to /dashboard.
Role group constants live in lib/auth/types.ts:
| Constant | Roles |
|---|---|
ALL_ROLES |
super_admin → stylist |
OPS_ROLES |
super_admin → front_desk |
ADMIN_ROLES |
super_admin → location_manager |
MANAGER_ROLES |
super_admin → brand_manager |
OWNER_ROLES |
super_admin, org_owner |
SUPER_ADMIN_ONLY |
super_admin |