This page is the authoritative list of permission keys. Module specs, API docs and tests reference these keys; a new key is added here first. Roles and scopes come from CONVENTIONS §4; the authorisation flow is in §6.2 of the architecture.
1. Role model
1.1 Concepts
| Concept | Definition |
|---|
| Permission | <module>.<resource>.<action>, for example lve.request.approve |
| Grant | A permission plus a maximum scope: lve.request.approve@TEAM |
| Role | A named set of grants. Seeded roles are templates; tenants clone them into custom roles |
| Role assignment | User + role + optional narrowing filter (a location, department or legal entity). The effective scope is the grant's scope intersected with the filter |
| Scope | SELF (S) → TEAM (T, direct and indirect reports from reports_to) → DEPARTMENT (D) → LOCATION (L) → ORG (O) |
| Check | Every request is evaluated as the pair (permission, scope) against the target record's employee, department and location, at the record's effective date |
1.2 Seeded role templates
Roles are additive. Every user holds employee; the other columns in the matrix show only what a role adds. A dash in a non-employee column never removes the user's own SELF grant from employee.
| Column | Role key | Default assignment scope |
|---|
| OWN | org_owner | ORG |
| HRA | hr_admin | ORG |
| HRM | hr_manager | ORG; assign with a location filter for site HR (effective L) |
| FA | finance_admin | ORG |
| PM | payroll_manager | ORG; assign with a location or legal-entity filter if payroll is run per site |
| LM | line_manager | TEAM. Derived automatically for anyone with at least one report; never assigned by hand |
| SA | sales_admin | ORG |
| SM | sales_manager | TEAM; LOCATION by filter |
| EMP | employee | SELF. Held by every user |
| FE | field_executive | SELF (adds tracking and CRM) |
| KIO | kiosk_operator | LOCATION, punch-only |
| INS | instructor | Own courses (shown as S) |
| AUD | auditor | ORG, read-only |
1.3 Custom roles
- Created by cloning a template (
iam.role.manage). A custom role can only contain grants at or below the creator's own grants (no privilege escalation through role editing).
- A role can be assigned only by someone who holds every grant in it at an equal or wider scope (
iam.role.assign).
- Nobody can edit a role they currently hold or assign a role to themselves; the second person rule applies.
- Common custom roles: Department Head (a
line_manager clone with approvals at D), Site Admin (an hr_manager clone with an L filter and no emp.profile.create), Payroll Viewer (read-only payroll for an external CA firm, with an expiry date on the assignment).
- Role changes notify
org_owner and are audited; quarterly access review lists every assignment with its last use.
- Templates are versioned. When a release adds a new permission to a seeded template, tenants on the template get it; tenants with a cloned custom role see a "new permission available" prompt instead.
1.4 Field-level protection
Sensitive fields are filtered after row-level authorisation, in the serializer, so every API, export and report path applies the same rule.
| Field group | Fields | Required permission | Without it |
|---|
| Identity numbers | Aadhaar, PAN, passport, voter ID | emp.sensitive.read | Last 4 characters only |
| Bank | Account number, IFSC, account holder | emp.sensitive.read | Last 4 of the account; IFSC shown |
| Health and family | Medical leave reasons, disability, blood group, nominee details | emp.sensitive.read | Hidden |
| Compensation | CTC, components, revisions, loans, tax declarations | pay.compensation.read | Hidden; reports drop the columns |
| Payslips | Payslip documents and figures | pay.payslip.read | Not accessible |
| Location trails | GPS points, routes, battery | ffm.tracking.read | Only visit check-ins (ffm.visit.read) |
| Biometric | Face template, enrolment status details | Never readable by any role (system use only) | Status "Enrolled / Not enrolled" only |
Each unmasked read of a C4 field is written to the audit log (security). Exports of sensitive fields require step-up MFA.
1.5 Segregation of duties
Enabled by default when a tenant has at least two users holding payroll permissions. Tenants with one payroll person get a persistent warning, and the compensating control is that org_owner is notified of every run approval and bank file.
| Rule | Enforcement |
|---|
The preparer of a payroll run (pay.run.create) cannot approve the same run (pay.run.approve) | Hard block |
| A user who changed compensation for an employee in the run period cannot approve the run that includes that change | Hard block, listed in the approval screen |
| A user who changed an employee's bank details in the last 24 hours cannot generate a bank file containing that employee | Hard block; the line is excluded or another user generates the file |
| Nobody approves their own leave, regularisation, claim, timesheet, travel or F&F | Hard block; routed to the next approver |
The person who computes F&F (ext.settlement.compute) cannot approve it | Hard block |
| A user cannot grant themselves a role or edit a role they hold | Hard block |
| Claims verified by finance must not be approved and verified by the same user | Hard block |
| Support sessions cannot approve, run payroll, generate files, change roles or export | Hard block (guard), regardless of consent |
2. Tenant permission matrix
Legend: S = SELF, T = TEAM, D = DEPARTMENT, L = LOCATION, O = ORG, — = not granted by this role. Columns are listed in section 1.2. Master-data reads that contain no personal data (company, holidays, org chart, directory) are O for everyone. Total: 141 permission keys.
| Permission | What it allows | OWN | HRA | HRM | FA | PM | LM | SA | SM | EMP | FE | KIO | INS | AUD |
|---|
plt.subscription.read | View plan, usage, invoices | O | O | — | O | — | — | — | — | — | — | — | — | O |
plt.subscription.manage | Change plan, add-ons, payment method | O | — | — | — | — | — | — | — | — | — | — | — | — |
plt.support_access.approve | Approve or deny Spyrl support access; revoke sessions | O | O | — | — | — | — | — | — | — | — | — | — | — |
plt.data_export.request | Request a full tenant export | O | — | — | — | — | — | — | — | — | — | — | — | — |
plt.tenant.close_request | Request account closure and deletion | O | — | — | — | — | — | — | — | — | — | — | — | — |
ORG: Organisation Setup & Masters
| Permission | What it allows | OWN | HRA | HRM | FA | PM | LM | SA | SM | EMP | FE | KIO | INS | AUD |
|---|
org.company.read | View company profile, locations, departments | — | — | — | — | — | — | — | — | O | — | — | — | — |
org.company.manage | Edit legal entity, statutory registrations | O | O | — | — | — | — | — | — | — | — | — | — | — |
org.location.manage | Create and edit locations and geo-fenced sites | O | O | — | — | — | — | — | — | — | — | — | — | — |
org.department.manage | Departments and cost centres | O | O | — | — | — | — | — | — | — | — | — | — | — |
org.designation.manage | Designations and grades | O | O | — | — | — | — | — | — | — | — | — | — | — |
org.holiday.read | View holiday calendars | — | — | — | — | — | — | — | — | O | — | — | — | — |
org.holiday.manage | Edit holiday calendars | O | O | O | — | — | — | — | — | — | — | — | — | — |
org.custom_field.manage | Define custom fields | O | O | — | — | — | — | — | — | — | — | — | — | — |
org.branding.manage | Logo, colours, sender name | O | O | — | — | — | — | — | — | — | — | — | — | — |
org.chart.read | View the org chart | — | — | — | — | — | — | — | — | O | — | — | — | — |
IAM: Identity, Access & Security
| Permission | What it allows | OWN | HRA | HRM | FA | PM | LM | SA | SM | EMP | FE | KIO | INS | AUD |
|---|
iam.user.read | View user accounts and status | O | O | O | — | — | T | — | — | — | — | — | — | O |
iam.user.invite | Send or resend activation invites | O | O | O | — | — | — | — | — | — | — | — | — | — |
iam.user.deactivate | Deactivate or reactivate users | O | O | O | — | — | — | — | — | — | — | — | — | — |
iam.role.read | View roles and assignments | O | O | — | — | — | — | — | — | — | — | — | — | O |
iam.role.manage | Create, clone and edit custom roles | O | O | — | — | — | — | — | — | — | — | — | — | — |
iam.role.assign | Assign roles (only roles whose grants you hold) | O | O | — | — | — | — | — | — | — | — | — | — | — |
iam.policy.manage | Password, session, MFA and device policies | O | O | — | — | — | — | — | — | — | — | — | — | — |
iam.sso.manage | Configure OIDC and SAML connections | O | O | — | — | — | — | — | — | — | — | — | — | — |
iam.device.approve | Approve a new mobile device | O | O | O | — | — | T | — | T | — | — | — | — | — |
iam.session.revoke | List and revoke sessions | O | O | O | — | — | — | — | — | S | — | — | — | — |
iam.audit.read | Search the audit log | O | O | — | — | — | — | — | — | — | — | — | — | O |
iam.audit.export | Export the audit log | O | — | — | — | — | — | — | — | — | — | — | — | O |
iam.api_client.manage | Create API clients and webhook subscriptions | O | O | — | — | — | — | — | — | — | — | — | — | — |
EMP: Core HR & Onboarding
| Permission | What it allows | OWN | HRA | HRM | FA | PM | LM | SA | SM | EMP | FE | KIO | INS | AUD |
|---|
emp.directory.read | Directory: name, photo, designation, work contact | — | — | — | — | — | — | — | — | O | — | — | — | — |
emp.profile.read | Full profile (non-sensitive fields) | O | O | O | O | O | T | — | T | S | — | — | — | O |
emp.profile.create | Add employees (new hire) | O | O | O | — | — | — | — | — | — | — | — | — | — |
emp.profile.update | Edit employee records directly | O | O | O | — | — | — | — | — | — | — | — | — | — |
emp.change_request.create | Request a change to own profile | — | — | — | — | — | — | — | — | S | — | — | — | — |
emp.change_request.approve | Approve profile change requests | O | O | O | — | — | — | — | — | — | — | — | — | — |
emp.sensitive.read | Unmask Aadhaar, PAN, bank, health fields | O | O | — | O | O | — | — | — | S | — | — | — | — |
emp.sensitive.update | Edit Aadhaar, PAN, bank fields directly | O | O | — | — | — | — | — | — | — | — | — | — | — |
emp.document.read | View employee documents | O | O | O | — | — | — | — | — | S | — | — | — | O |
emp.document.upload | Upload documents | O | O | O | — | — | — | — | — | S | — | — | — | — |
emp.document.verify | Mark documents verified | O | O | O | — | — | — | — | — | — | — | — | — | — |
emp.job.change | Transfers, promotions, manager changes (effective-dated) | O | O | O | — | — | — | — | — | — | — | — | — | — |
emp.probation.confirm | Confirm or extend probation | O | O | O | — | — | T | — | — | — | — | — | — | — |
emp.onboarding.manage | Onboarding checklists and induction | O | O | O | — | — | T | — | — | — | — | — | — | — |
emp.import.run | Bulk imports (dry-run and commit) | O | O | O | — | — | — | — | — | — | — | — | — | — |
emp.letter.generate | Generate letters from templates | O | O | O | — | — | — | — | — | — | — | — | — | — |
ATT: Attendance, Shifts & Time
| Permission | What it allows | OWN | HRA | HRM | FA | PM | LM | SA | SM | EMP | FE | KIO | INS | AUD |
|---|
att.punch.create | Punch in/out for self (web, mobile) | — | — | — | — | — | — | — | — | S | — | — | — | — |
att.punch.create_on_behalf | Punch for others at a front desk or kiosk | — | — | — | — | — | — | — | — | — | — | L | — | — |
att.punch.ingest | Device and sync-agent ingest (machine tokens only, no human role) | — | — | — | — | — | — | — | — | — | — | — | — | — |
att.record.read | View attendance records and day status | O | O | O | O | O | T | — | T | S | — | — | — | O |
att.record.edit | Correct attendance directly (reason required) | O | O | O | — | — | — | — | — | — | — | — | — | — |
att.day.recompute | Recompute employee-days for a date range (job; refused for locked periods) | O | O | O | — | O | — | — | — | — | — | — | — | — |
att.work_request.request | Request a work type for a day: WFH, on-duty, remote location | — | — | — | — | — | — | — | — | S | — | — | — | — |
att.work_request.approve | Approve work-type requests (on-behalf entries are auto-approved) | O | — | O | — | — | T | — | — | — | — | — | — | — |
att.regularization.request | Request regularisation | — | — | — | — | — | — | — | — | S | — | — | — | — |
att.regularization.approve | Approve regularisation | O | — | O | — | — | T | — | — | — | — | — | — | — |
att.permission.request | Request short permission (hours) | — | — | — | — | — | — | — | — | S | — | — | — | — |
att.permission.approve | Approve permission | O | — | O | — | — | T | — | — | — | — | — | — | — |
att.overtime.approve | Approve overtime | O | — | O | — | — | T | — | — | — | — | — | — | — |
att.shift.manage | Shift masters | O | O | O | — | — | — | — | — | — | — | — | — | — |
att.roster.manage | Rosters and rotations | O | O | O | — | — | T | — | — | — | — | — | — | — |
att.shift_change.request | Request a shift change or swap | — | — | — | — | — | — | — | — | S | — | — | — | — |
att.shift_change.approve | Approve shift changes | O | — | O | — | — | T | — | — | — | — | — | — | — |
att.policy.manage | Attendance policies and assignment | O | O | — | — | — | — | — | — | — | — | — | — | — |
att.geofence.manage | Geo-fences and allowed networks | O | O | O | — | — | — | — | — | — | — | — | — | — |
att.device.manage | Register biometric devices, kiosks, mappings | O | O | O | — | — | — | — | — | — | — | — | — | — |
att.face.enroll | Enrol or reset a face profile (consent required) | — | O | O | — | — | T | — | — | S | — | L | — | — |
att.period.lock | Lock or unlock an attendance period | O | — | O | — | O | — | — | — | — | — | — | — | — |
att.import.run | Import attendance (CSV, device logs) | O | O | O | — | — | — | — | — | — | — | — | — | — |
LVE: Leave & Holidays
| Permission | What it allows | OWN | HRA | HRM | FA | PM | LM | SA | SM | EMP | FE | KIO | INS | AUD |
|---|
lve.balance.read | View leave balances and ledger | O | O | O | — | O | T | — | — | S | — | — | — | O |
lve.request.create | Apply for leave | — | — | — | — | — | — | — | — | S | — | — | — | — |
lve.request.cancel | Cancel a leave request | O | — | O | — | — | — | — | — | S | — | — | — | — |
lve.request.approve | Approve or reject leave | O | — | O | — | — | T | — | — | — | — | — | — | — |
lve.request.create_on_behalf | Apply leave for someone else | O | — | O | — | — | T | — | — | — | — | — | — | — |
lve.type.manage | Leave types | O | O | — | — | — | — | — | — | — | — | — | — | — |
lve.policy.manage | Leave policies (accrual, carry-forward, sandwich) | O | O | — | — | — | — | — | — | — | — | — | — | — |
lve.balance.adjust | Manual balance adjustment (ledger entry with reason) | O | O | O | — | — | — | — | — | — | — | — | — | — |
lve.compoff.approve | Approve comp-off credits | O | — | O | — | — | T | — | — | — | — | — | — | — |
lve.encashment.approve | Approve leave encashment | O | — | O | O | — | — | — | — | — | — | — | — | — |
PAY: Payroll & Statutory Compliance
| Permission | What it allows | OWN | HRA | HRM | FA | PM | LM | SA | SM | EMP | FE | KIO | INS | AUD |
|---|
pay.payslip.read | View payslips | O | — | — | O | O | — | — | — | S | — | — | — | O |
pay.compensation.read | View CTC, salary structure, components | O | — | — | O | O | — | — | — | S | — | — | — | O |
pay.compensation.update | Change compensation (effective-dated) | O | — | — | O | O | — | — | — | — | — | — | — | — |
pay.structure.manage | Salary structure templates | O | — | — | O | — | — | — | — | — | — | — | — | — |
pay.component.manage | Pay components and formulas | O | — | — | O | — | — | — | — | — | — | — | — | — |
pay.policy.manage | Pay groups, payroll calendar, statutory settings | O | — | — | O | — | — | — | — | — | — | — | — | — |
pay.input.manage | Variable inputs, arrears, one-time deductions | O | — | — | — | O | — | — | — | — | — | — | — | — |
pay.run.create | Create and calculate a payroll run | O | — | — | — | O | — | — | — | — | — | — | — | — |
pay.run.review | View run results, variance and validation reports | O | — | — | O | O | — | — | — | — | — | — | — | O |
pay.run.approve | Approve a calculated run | O | — | — | O | — | — | — | — | — | — | — | — | — |
pay.run.lock | Lock an approved run and publish payslips | O | — | — | O | O | — | — | — | — | — | — | — | — |
pay.run.reverse | Reverse a locked run (creates a reversal run) | O | — | — | O | — | — | — | — | — | — | — | — | — |
pay.loan.manage | Loans and advances | O | — | — | — | O | — | — | — | — | — | — | — | — |
pay.advance.request | Request a salary advance (eligibility and recovery months shown) | — | — | — | — | — | — | — | — | S | — | — | — | — |
pay.tax_declaration.submit | Submit IT declarations and proofs | — | — | — | — | — | — | — | — | S | — | — | — | — |
pay.tax_declaration.verify | Verify declarations and proofs | O | — | — | — | O | — | — | — | — | — | — | — | — |
pay.statutory_file.generate | Generate ECR, ESIC, PT, LWF, 24Q files | O | — | — | O | O | — | — | — | — | — | — | — | — |
pay.bank_file.generate | Generate bank payout files | O | — | — | O | O | — | — | — | — | — | — | — | — |
pay.journal.export | Export payroll journal (Tally, Zoho, CSV) | O | — | — | O | O | — | — | — | — | — | — | — | — |
pay.statutory_pack.accept | Accept a new statutory pack version | O | — | — | O | — | — | — | — | — | — | — | — | — |
pay.form16.publish | Publish Form 16 to employees | O | — | — | O | O | — | — | — | — | — | — | — | — |
NTF: Notifications & Workflow
| Permission | What it allows | OWN | HRA | HRM | FA | PM | LM | SA | SM | EMP | FE | KIO | INS | AUD |
|---|
ntf.inbox.read | Own notifications and pending approvals | — | — | — | — | — | — | — | — | S | — | — | — | — |
ntf.delegation.manage | Delegate approvals (own; others for admins) | — | O | — | — | — | — | — | — | S | — | — | — | — |
ntf.workflow.manage | Approval chains, SLAs, escalation | O | O | — | — | — | — | — | — | — | — | — | — | — |
ntf.template.manage | Notification and letter text templates | O | O | — | — | — | — | — | — | — | — | — | — | — |
ntf.channel.manage | Channels, sender identity, reminder schedules | O | O | — | — | — | — | — | — | — | — | — | — | — |
RPT: Reporting, Dashboards & Exports
| Permission | What it allows | OWN | HRA | HRM | FA | PM | LM | SA | SM | EMP | FE | KIO | INS | AUD |
|---|
rpt.dashboard.read | Dashboards (scope-filtered) | O | O | O | O | O | T | O | T | S | — | — | — | O |
rpt.report.read | Standard reports (scope-filtered, sensitive fields masked) | O | O | O | O | O | T | O | T | S | — | — | S | O |
rpt.report.export | Export reports to Excel/CSV/PDF | O | O | O | O | O | T | O | T | — | — | — | — | O |
rpt.report.schedule | Schedule reports by email | O | O | O | O | O | T | O | T | — | — | — | — | — |
rpt.payroll_report.read | Salary-bearing reports (registers, statutory) | O | — | — | O | O | — | — | — | — | — | — | — | O |
rpt.custom_report.build | Build custom reports (R4) | O | O | — | O | — | — | O | — | — | — | — | — | — |
MOB: Mobile & Kiosk
| Permission | What it allows | OWN | HRA | HRM | FA | PM | LM | SA | SM | EMP | FE | KIO | INS | AUD |
|---|
mob.kiosk.enroll | Enrol a kiosk tablet for a location | O | O | O | — | — | — | — | — | — | — | — | — | — |
mob.kiosk.operate | Operate kiosk mode (punch-only) | — | — | — | — | — | — | — | — | — | — | L | — | — |
CLM: Claims & Expenses
| Permission | What it allows | OWN | HRA | HRM | FA | PM | LM | SA | SM | EMP | FE | KIO | INS | AUD |
|---|
clm.claim.create | Submit claims and advances | — | — | — | — | — | — | — | — | S | — | — | — | — |
clm.claim.approve | Approve claims (manager step) | O | — | — | — | — | T | — | T | — | — | — | — | — |
clm.claim.verify | Finance verification of receipts and limits | — | — | — | O | O | — | — | — | — | — | — | — | — |
clm.claim.pay | Mark for payout (payroll or bank file) | O | — | — | O | O | — | — | — | — | — | — | — | — |
clm.policy.manage | Expense categories, limits, per-diem, mileage | O | O | — | O | — | — | — | — | — | — | — | — | — |
EXT: Exit & Full-and-Final
| Permission | What it allows | OWN | HRA | HRM | FA | PM | LM | SA | SM | EMP | FE | KIO | INS | AUD |
|---|
ext.resignation.submit | Submit resignation | — | — | — | — | — | — | — | — | S | — | — | — | — |
ext.resignation.approve | Accept resignation, set last working day | O | — | O | — | — | T | — | — | — | — | — | — | — |
ext.termination.initiate | Initiate termination | O | O | O | — | — | — | — | — | — | — | — | — | — |
ext.master.manage | Separation reasons, termination categories, clearance templates | O | O | — | — | — | — | — | — | — | — | — | — | — |
ext.clearance.update | Update clearance items | O | O | O | O | O | T | — | — | — | — | — | — | — |
ext.settlement.compute | Compute full-and-final settlement | O | — | — | — | O | — | — | — | — | — | — | — | — |
ext.settlement.approve | Approve full-and-final settlement | O | — | — | O | — | — | — | — | — | — | — | — | — |
ENG: Engagement
| Permission | What it allows | OWN | HRA | HRM | FA | PM | LM | SA | SM | EMP | FE | KIO | INS | AUD |
|---|
eng.announcement.read | Read announcements targeted to me | — | — | — | — | — | — | — | — | S | — | — | — | — |
eng.announcement.publish | Publish announcements | O | O | O | — | — | T | — | — | — | — | — | — | — |
eng.recognition.give | Give recognition to colleagues | — | — | — | — | — | — | — | — | O | — | — | — | — |
eng.program.manage | Recognition programmes and badges | O | O | — | — | — | — | — | — | — | — | — | — | — |
FFM: Field Force & Sales CRM
| Permission | What it allows | OWN | HRA | HRM | FA | PM | LM | SA | SM | EMP | FE | KIO | INS | AUD |
|---|
ffm.tracking.read | View live and past location trails | O | — | — | — | — | — | — | T | — | — | — | — | — |
ffm.visit.create | Check in at client visits | — | — | — | — | — | — | — | — | — | S | — | — | — |
ffm.visit.read | View visit history | O | — | — | — | — | — | O | T | — | S | — | — | O |
ffm.account.read | View accounts, contacts, leads | O | — | — | — | — | — | O | T | — | S | — | — | — |
ffm.account.manage | Create and edit accounts and leads | O | — | — | — | — | — | O | T | — | S | — | — | — |
ffm.lead.assign | Assign or reassign leads and accounts | O | — | — | — | — | — | O | T | — | — | — | — | — |
ffm.pipeline.manage | Pipeline stages and templates | O | — | — | — | — | — | O | — | — | — | — | — | — |
ffm.beat.manage | Beat and route plans | O | — | — | — | — | — | O | T | — | — | — | — | — |
ffm.target.manage | Sales targets | O | — | — | — | — | — | O | T | — | — | — | — | — |
ffm.travel.submit | Submit travel (kms) for a day | — | — | — | — | — | — | — | — | — | S | — | — | — |
ffm.travel.approve | Approve or revise travel kms (reason required) | O | — | — | — | — | — | — | T | — | — | — | — | — |
ffm.payment.collect | Record a payment collected in the field | — | — | — | — | — | — | — | — | — | S | — | — | — |
TSM: Timesheets & Projects
| Permission | What it allows | OWN | HRA | HRM | FA | PM | LM | SA | SM | EMP | FE | KIO | INS | AUD |
|---|
tsm.timesheet.submit | Submit timesheets | — | — | — | — | — | — | — | — | S | — | — | — | — |
tsm.timesheet.approve | Approve timesheets | O | — | — | — | — | T | — | — | — | — | — | — | — |
tsm.project.manage | Projects, tasks, allocations | O | O | — | — | — | — | — | — | — | — | — | — | — |
LMS: Learning Management
| Permission | What it allows | OWN | HRA | HRM | FA | PM | LM | SA | SM | EMP | FE | KIO | INS | AUD |
|---|
lms.course.read | Take assigned and open courses | — | — | — | — | — | — | — | — | S | — | — | — | — |
lms.course.manage | Create and edit courses | O | O | — | — | — | — | — | — | — | — | — | S | — |
lms.course.assign | Assign courses to learners | O | O | O | — | — | T | — | — | — | — | — | S | — |
lms.assessment.grade | Grade assessments | — | O | — | — | — | — | — | — | — | — | — | S | — |
Notes on the matrix
line_manager approvals are the first step of most workflows; HR roles hold O-scope approvals so they can act as later steps or as a fallback. Which steps exist is configured in NTF workflows, not in roles.
auditor is read-only and time-limited by assignment expiry. It sees compensation and payroll reports (statutory audits need them) but never unmasked identity or bank numbers.
org_owner holds almost everything so a small company can run with one admin, but segregation-of-duties rules still apply per action.
hr_admin configures and manages people data but does not see compensation by default; tenants that want HR to see salaries add pay.compensation.read to a custom role.
sales_admin configures the CRM but cannot see live location trails; only sales_manager (TEAM) and org_owner can, to limit surveillance (privacy).
- Machine principals (API clients, device tokens, kiosk tokens) receive OAuth scopes named after the same permission keys, with ORG or LOCATION scope only, and never
*.sensitive.* unless explicitly granted.
Platform roles live in the control plane and its own identity provider, separate from tenant roles (administration). No platform role carries any tenant permission; tenant data is reachable only through a consented support session.
| Permission | What it allows | platform_admin | support_engineer | billing_admin | release_manager |
|---|
plt.tenant.read | View tenant registry, usage, health | ✓ | ✓ | ✓ | ✓ |
plt.tenant.manage | Trial, suspend, reactivate, export, delete, move cells (deletion and moves need a second approver) | ✓ | — | — | — |
plt.plan.manage | Plans, entitlements, overrides | ✓ | — | ✓ | — |
plt.invoice.manage | Invoices, credits, dunning | ✓ | — | ✓ | — |
plt.flag.manage | Release flags and targeting | ✓ | — | — | ✓ |
plt.flag.kill_switch | Toggle documented kill switches during an incident | ✓ | ✓ | — | ✓ |
plt.cell.manage | Create and resize cells, maintenance windows | ✓ | — | — | ✓ |
plt.release.rollout | Start, pause, resume, abort, roll back waves; minimum mobile version | ✓ | — | — | ✓ |
plt.support.request | Request a support session | ✓ | ✓ | — | — |
plt.support.emergency_approve | Approve an emergency session without tenant consent (second person) | ✓ | — | — | — |
plt.statutory_pack.publish | Publish statutory pack versions | ✓ | — | — | — |
plt.announcement.publish | Banners and announcements | ✓ | ✓ | — | ✓ |
plt.audit.read | Platform audit log | ✓ | — | — | — |
plt.platform_user.manage | Manage platform staff accounts | ✓ | — | — | — |
4. Keeping the matrix true
- The matrix is generated from
packages/policy/permissions.ts (the seeded templates). A CI check fails if this page and the code disagree.
- Authorisation tests are generated from the same source: for each key and role, a test asserts allow inside scope and deny outside scope (testing strategy).
- New permissions need a security review entry: the data class touched, the default roles, and any SoD rule.