Permissions matrix
Better Comply uses five roles. Every permission check runs at the database level (Row Level Security) - the table below reflects the authoritative allowedRoles in the application routes and the sidebar navigation.
All users - use this page to understand what each role can see and do, and to decide which role to assign to a new user.
The five roles
| Role | Internal name | Purpose |
|---|---|---|
| Employee | employee | Complete assigned trainings and view personal history |
| Team Lead | team_lead | Supervise a team and receive weekly digest reports |
| Quality Admin | admin_quality | Author content, manage the QMS lifecycle, run audits |
| HR Admin | admin_hr | Manage users and monitor training compliance |
| Corporate Admin | corporate_admin | All Quality Admin and HR Admin capabilities plus system-level tools |
Every user has exactly one role. Roles are assigned by administrators and are enforced at the database level on every request - role information is never trusted from the browser.
Roles are stored in a separate user_roles table, not in the user profile. An administrator assigns roles through the Users page.
Feature access by role
The columns are the five roles. "Admin" in the table header means Quality Admin, HR Admin, and Corporate Admin (all three ADMIN_ROLES).
| Feature / Area | Employee | Team Lead | Quality Admin | HR Admin | Corporate Admin |
|---|---|---|---|---|---|
| My Trainings (own assignments) | yes | - | - | - | - |
| Complete a training | yes | yes* | yes* | yes* | yes* |
| Sign evidence | yes | yes* | yes* | yes* | yes* |
| Download a certificate | yes | yes* | yes* | yes* | yes* |
| Training history (own) | yes | yes | - | - | - |
| Profile page | yes | yes | yes | yes | yes |
| My Team (team dashboard) | - | yes | - | - | - |
| Send reminders to team | - | yes | yes | yes | yes |
| Reports (read-only) | - | yes | yes | yes | yes |
| Weekly digest email | - | yes | yes | yes | yes |
| Dashboard (org-wide stats) | - | - | yes | yes | yes |
| Campaigns (create/manage) | - | - | yes | yes | yes |
| Training Materials (authoring) | - | - | yes | yes | yes |
| Controlled Documents (manage) | - | - | yes | yes | yes |
| Quality Review Queue | - | - | yes | - | yes |
| Onboarding rules | - | - | yes | yes | yes |
| Users (invite/manage) | - | - | yes | yes | yes |
| Organization (departments/locations) | - | - | yes | yes | yes |
| Audit log | - | - | yes | yes | yes |
| Email settings | - | - | yes | yes | yes |
| Dev Tools | - | - | - | - | yes |
* Admins and Team Leads can complete trainings assigned to them via their own assignments. The "My Trainings" page itself (/my-trainings) is an employee-only route; admins reach their own assignments from within the training viewer if directly linked. The History page (/history) is available to employees and team leads.
The Quality Review Queue (/quality/review-queue) is restricted to Quality Admin and Corporate Admin only. HR Admin does not have access. This is enforced by the route guard and confirmed in the sidebar. This is intentional: the queue is the segregation-of-duties control point for content approval.
Navigation by role
The sidebar shows different items depending on the signed-in user's role. The table below lists every navigation item and the roles that see it.
| Sidebar item | Route | Roles with access |
|---|---|---|
| Dashboard | /dashboard | Quality Admin, HR Admin, Corporate Admin |
| My Trainings | /my-trainings | Employee |
| My Team | /team | Team Lead |
| Campaigns | /campaigns | Quality Admin, HR Admin, Corporate Admin |
| Training Materials | /training-materials | Quality Admin, HR Admin, Corporate Admin |
| Controlled Documents | /controlled-documents | Quality Admin, HR Admin, Corporate Admin |
| Quality Review Queue | /quality/review-queue | Quality Admin, Corporate Admin |
| Onboarding | /onboarding | Quality Admin, HR Admin, Corporate Admin |
| Users | /users | Quality Admin, HR Admin, Corporate Admin |
| Organization | /organization | Quality Admin, HR Admin, Corporate Admin |
| Reports | /reports | Quality Admin, HR Admin, Corporate Admin, Team Lead |
| Audit | /audit | Quality Admin, HR Admin, Corporate Admin |
| History | /history | Employee, Team Lead |
| Profile | /profile | All roles |
| Dev Tools | /dev-tools | Corporate Admin |
Supervisor relationships
A worker can have two independent supervisor relationships at the same time:
- Foreman - the worker's direct line manager, stored as
manager_id. Set on the user's profile by an administrator. - Line lead - the supervisor responsible for the worker's production line, stored as
line_lead_id. Set on the user's profile by an administrator.
Both relationships make the worker appear in that supervisor's My Team view and weekly digest email. Either supervisor must hold the Team Lead role (or an Admin role) to be assignable as a supervisor.
Security model
- Role checks run at the database level via Row Level Security (RLS) policies and SECURITY DEFINER functions. The route guard in the browser is a user-experience layer, not the security boundary.
- The database
is_admin()function returns true foradmin_quality,admin_hr, andcorporate_admin. - Audit logs are write-protected: direct inserts from browser clients are denied. All writes go through the server-side
log_audit_event()function. - Report views (
report_assignment_status,report_person_status) useSECURITY INVOKER, meaning base-table RLS still applies: a Team Lead sees only their direct reports even though the view is granted to all authenticated users.
Corrections to earlier documentation
The internal roles-overview.md and permissions.md documents contained several inaccuracies relative to the actual application code. The table above reflects the code. Key corrections:
- Corporate Admin is a distinct role, not a variant of Quality or HR Admin. It appears as a separate entry in
ADMIN_ROLESand has exclusive access to Dev Tools and the Quality Review Queue (shared with Quality Admin). - Admins do not have a "My Trainings" page. The route
/my-trainingsis restricted to theemployeerole. The internal docs listed it as visible to administrators - this was incorrect. - The Quality Review Queue is not available to HR Admin. The route
/quality/review-queueallowsadmin_qualityandcorporate_adminonly. - History is not shown to admins in the sidebar. The
/historyroute allowsemployeeandteam_lead. - My Team (
/team) is Team Lead only. Admins can see all-team data through Reports, not through the Team dashboard route. - The internationalization documentation listed only 4 product locales. The actual
SUPPORTED_LANGUAGESconstant in@betterknow/shareddefines 11 locales. See Supported languages.