Skip to main content

Custom roles

The built-in system roles cover the most common access patterns, but every workspace can define its own roles that combine permissions in whatever way suits the organisation. Custom roles live inside a single workspace — Operentra is multi-tenant, so every role is scoped to the workspace (company) that created it. Roles you create are never visible to, or shared with, any other tenant. Only the platform operator, working from the separate /operator console, sits outside this workspace scope.

Managing roles requires the roles.manage permission (managing user accounts and their role assignments requires users.manage). Both are held by the Super Admin role and can be granted to any custom role.

Where roles are managed

Roles are managed from the admin console:

PageRoutePurpose
Roles/admin/access/rolesList, create, duplicate, and delete roles
Role editor/admin/access/roles/:id/permissionsToggle a role's permissions
Permissions/admin/access/permissionsBrowse the full permission catalogue
Users/admin/access/usersAssign roles to user accounts

Everything is also available over the Access Control API — see API endpoints below.

Creating a custom role

From Roles (/admin/access/roles), click Create Role. A short dialog collects:

FieldRequiredNotes
Display NameYesHuman-friendly label, e.g. Payroll Manager
SlugYesLowercase identifier used in code and APIs; auto-derived from the display name and must be unique within the workspace
DescriptionNoShort summary of what the role can do

Choosing Create & Configure creates the (initially empty) role and drops you straight into the role editor to pick its permissions.

Duplicating an existing role

Instead of starting from scratch, click Duplicate on any role card. This pre-fills the dialog with the source role's name and description and, on save, copies all of the source role's permissions into the new role. Duplicating a system role is the supported way to create an editable variant of it. After the copy is created you can open the new role and adjust its permissions.

The permission editor

The role editor (/admin/access/roles/:id/permissions) is a two-pane, module-scoped editor:

  • Left rail — a searchable list of every permission module (Company, Employees, Attendance, Leave, Payroll, Salary Slips, Tax, Loans, Reports, Roles, Users, and so on). Each module shows a live selected/total badge and a status dot: a filled check when every permission in the module is on, an amber ring when some are on, an empty circle when none are.
  • Right pane — the individual permissions for the currently selected module, each with a checkbox, its display name, its machine name (e.g. payroll.view), and a description where one exists.

The search box filters both the module rail and the permission list, so typing part of a permission name jumps you to the relevant modules quickly.

Toggling permissions

  • Per permission — tick or untick any checkbox in the right pane.
  • Per module — use Select all in module / Deselect all in module in the module header to flip an entire feature area at once.
  • Everything — the sidebar footer has Select all and Clear all buttons that act across every module.

The editor lets you rename the role (display name) and edit its description inline. The slug shown under the title is fixed once the role is created. A running summary at the bottom of the page reports how many permissions are selected across how many modules.

Changes are held locally until you press Save changes. An Unsaved badge and a browser "leave page?" prompt guard against losing edits; Reset discards them.

System roles are read-only

A role marked System cannot be modified or deleted. The editor opens it in view-only mode. To base a custom role on a system role, duplicate it first.

Assigning roles to users

Roles are assigned from Users (/admin/access/users). Open a user, edit their role assignments, and save. A user can hold multiple roles at once — their effective permissions are the union of every assigned role (see below).

The Access Control API deliberately uses a single management permission per area rather than separate view/create/update/delete permissions: users.manage covers all user operations and roles.manage covers all role operations.

How multiple roles combine

When a user holds several roles, their effective permission set is the union of all of them:

effectivePermissions = Role_A.permissions ∪ Role_B.permissions ∪ … ∪ Role_N.permissions

There is no "deny" permission. If any assigned role grants a capability, the user has it. This keeps authorisation simple and predictable.

UserRolesEffective result
A finance leadAccountant + Department HeadAll Accountant capabilities plus team attendance and leave approvals
A payroll specialistHR Officer + a custom "Payroll Manager"HR read access plus full payroll processing
A regular staff memberEmployeeSelf-service access only

The permission check runs on the server for every request: the guard resolves the user's live permissions from the database each time, so a change to a role takes effect on the user's next request — there is no stale token to wait out. The web app caches the signed-in user's permissions (from GET /api/auth/me) to decide which menus and buttons to show, so the UI for an already-signed-in user only reflects a permission change after their session data is refreshed (a re-login or token refresh). Newly seeded permissions in particular require affected users to sign in again before the frontend surfaces them.

Editing and deleting roles

Editing — open any custom role from the Roles page (Edit) and adjust its display name, description, or permissions in the editor. System roles open as View only.

Deleting — the Delete action appears on a role card only when both conditions hold:

  • the role is not a system role, and
  • no users are currently assigned to it (its user count is zero).

Reassign any remaining users to another role first, then delete. The API enforces the same two rules and rejects a delete otherwise.

Worked examples

These examples describe the shape of a focused role. For the exact permission names available in each module, browse the in-app Permissions page or the Permission matrix.

A "Payroll Manager" typically needs read access to employees, the full Payroll and Salary Slips modules, the Tax module, selected Loans capabilities (approve/disburse), Reports, and the relevant Print permissions — but none of the HR administration or access-control permissions. Building this as one custom role is cleaner than assigning two broad system roles.

A "Recruiter" typically needs to create and update employee records, upload documents, create contracts, and read announcements and holidays — a narrow, low-risk footprint.

Start each role from the smallest set of permissions that does the job and add more only when a real need appears.

API endpoints

Roles and users are managed through the Access Control API under /api/access/*. Every route is company-scoped by the tenant guard and gated by the permission shown.

MethodPathDescriptionPermission
GET/api/access/rolesList roles in the workspace (with permission and user counts)roles.manage
GET/api/access/roles/:idRole detail with its permissionsroles.manage
POST/api/access/rolesCreate a custom roleroles.manage
PUT/api/access/roles/:idUpdate name, description, or permissionsroles.manage
DELETE/api/access/roles/:idDelete a custom roleroles.manage
GET/api/access/permissionsFull permission catalogue, grouped by moduleroles.manage
GET/api/access/usersList user accountsusers.manage
POST/api/access/usersCreate a userusers.manage
PUT/api/access/users/:idUpdate a user and its role assignmentsusers.manage
DELETE/api/access/users/:idDelete a userusers.manage
note

The API prefix defaults to api and is configurable via the API_PREFIX environment variable; paths above assume the default.

Both POST /api/access/roles and PUT /api/access/roles/:id accept an optional permissionIds array. On update, supplying permissionIds replaces the role's entire permission set with the list you send.

Best practices

  1. Least privilege — start narrow and add permissions as real needs surface, rather than starting broad and trimming.
  2. Name by function — "Payroll Manager", "Recruiter", not "Custom Role 1".
  3. Prefer duplicate-and-trim — clone the closest system role, then remove what you don't need.
  4. Review periodically — audit role assignments so users keep only the access they still require.
  5. Avoid role sprawl — if two roles differ by only a permission or two, consider consolidating.