Roles and permissions
The permission model in detail, and how to design roles for your shop.
Every staff account carries one role, and a role is a set of permissions.
Nine are checked server-side today, and a request without one is refused with a 403 naming the permission:
pos.refund · pos.discount · inventory.adjust · inventory.stocktake · inventory.transfer · invoicing.send · invoicing.payments · marketing.send · settings.access_levels
The rest of the matrix currently shapes what the interface offers rather than being enforced at the API. Treat those as an organising tool, not as a security boundary — the real boundaries are company tenancy, store assignment on store-scoped requests, and the PIN gate.
The roles
| Role | What it is |
|---|---|
| staff | Counter staff. Sell and look things up. |
| supervisor | Runs a shift. Refunds, discounts, the register, stock. |
| admin | Runs the business. Everything, always. |
| superadmin | Platform role. Not a tenant role. |
What each role can do by default
A new company starts with this matrix. staff gets:
- Point of Sale — process sales, hold sales, view products
- View-only access to Inventory, Invoicing, CRM, Repairs and the Dashboard
supervisor adds:
- Point of Sale — refunds, discounts, price overrides, voids, opening and closing the register, and POS reports
- Inventory — adjustments, transfers and stocktakes
- Invoicing — create, send and take payments
- CRM — edit customers
- Repairs — create and update tickets
- Marketing — view
- Settings — products, targets and receipts
admin holds every permission. That is not a default you can edit away — see below.
POS-003is "Process refunds" — which is the quickest way to be precise about one in a support conversation. The admin column is switched on and disabled: admin always holds every permission, because the matrix is edited by admins and a save that could strip their own rights would lock them out of this very screen. Toggles shown are the shipped defaults. Source: SettingsModule.tsx, PERMISSION_CODES / PERMISSION_LABELS / DEFAULT_ROLE_PERMISSIONS in pos/types.ts.Editing the matrix
Only the staff and supervisor columns are editable. The admin column is fixed at full access on purpose: the matrix is edited by admins, so a save that could strip admin rights would lock every admin out of the screen needed to undo it.
A company can deliberately grant staff and supervisors nothing at all. Because admin's full row set is always written alongside, that choice is stored and honoured rather than being mistaken for "this company has never customised its permissions" and silently reset to the defaults.
Permission names and codes
Every permission has a short code as well as a name — POS-003 is "Process refunds", INV-002 is stock adjustments. The code is shown beside the permission on the Access Levels screen and is the least ambiguous way to refer to one.
Permissions are grouped by area — pos.*, inventory.*, invoicing.*, crm.*, repairs.*, marketing.*, dashboard.* and settings.*. The ones that come up most often at the counter:
| Permission | Allows | staff | supervisor |
|---|---|---|---|
pos.sell | Process sales | Yes | Yes |
pos.hold | Hold / park sales | Yes | Yes |
pos.view_products | See the product list | Yes | Yes |
pos.refund | Process refunds | No | Yes |
pos.discount | Apply discounts | No | Yes |
pos.price_override | Override a price | No | Yes |
pos.void | Void a sale | No | Yes |
pos.open_close_register | Open / close the till | No | Yes |
pos.view_reports | POS reporting | No | Yes |
Roles are not the only gate
Two further checks sit alongside permissions. Staff are restricted to the store locations they are assigned to, on reads as well as on changes; owners and admins reach every shop. And a number of actions additionally require a staff PIN at the moment they are performed.