Skip to main content

Admin Roles

Create and manage admin roles, assign permissions to them, and control which admin users hold each role.

Overview​

Admin roles let administrators delegate specific sections of the admin panel to team members without granting full system access. Each role carries a set of granular permissions and can be assigned to any number of admin users.

Accessing the Page​

Navigate to Admin > Admin Roles (/admin-roles). Both the sidebar entry and the page itself require admin-roles:read, on top of the admin:access dashboard gate.

The list is a table with Name, Permissions (count), Members (count), Type (System / Custom badge), and Actions.

Permissions​

PermissionDescription
admin-roles:readView the admin roles list
admin-roles:createCreate new admin roles
admin-roles:editEdit existing roles (name, description, permissions, members)
admin-roles:deleteDelete non-system roles

Creating a Role​

  1. Click Create Role (requires admin-roles:create).
  2. Enter a name (required, max 100 characters) and an optional description.
  3. Use the permission picker to select which admin permissions the role grants. Permissions come from the backend registry via /api/admin-permissions, grouped by the category derived from the part of the permission string before the :, each with a tri-state "select all in category" checkbox.
  4. Click Create Role to save.

Editing a Role​

Click any row in the table, or the pencil in the Actions column, to open the edit dialog (requires admin-roles:edit).

All fields - name, description, and permissions - are editable for all roles, including system roles. Save Changes stays disabled until something actually changed and sends only the changed fields.

admin:access Permission​

Every role automatically includes the admin:access permission. The picker skips it - it cannot be selected or deselected. It is required for any admin user to access the admin panel at all.

Two-factor authentication required​

Admin access requires two-factor authentication. A user whose admin roles grant any admin permission, but who has no 2FA factor (an authenticator app or a passkey), cannot use any of it:

  • Admin panel - opening it sends the user to the web app at /dashboard?admin_mfa=required. The dashboard opens the Admin access needs two-factor dialog with a note that the user came from the admin app. A sign-in on the way drops the query; the dialog then still opens, only without that note. The admin login page keeps its message for /login?error=mfa_required (old links and bookmarks), with a link to the same dashboard address.
  • Web app - while adminMfaRequired is true, every dashboard page load opens the same dialog: why admin access needs a second factor, and Set up two-factor, which opens Settings › Security › Sign-in & 2FA at the two-factor section and starts the choice between a passkey and an authenticator app. Later closes it for the rest of the browser session (sessionStorage); the redirect from the admin panel opens it again. When the settings window closes after the setup started, the dashboard reads me again: with a factor the dialog is gone, without one it returns. It never appears in popouts or overlays.
  • API - every admin resolver and admin REST route refuses the session with ADMIN_MFA_REQUIRED (REST: 403, GraphQL: extensions.code). GraphQL and REST use the same check and the same message.
  • Everything else keeps working - the same session keeps its channels, account permissions and user-level permissions in the web app.

The check runs in the API's auth middleware on every request of a session that holds admin grants. It is fail-closed: if the factor state cannot be read, the request is answered 503 authorization_unavailable instead of being served with admin rights. It takes effect at once in both directions: turning on 2FA unlocks the admin panel on the next request, and removing the last factor locks it on the next request. me { adminMfaRequired } / GET /v1/users/me admin_mfa_required report the state; a refusal is an authorization decision and writes no audit event. System keys are not affected - they carry no user and are provisioned in the config.

devtools:read Permission​

Grants the Dev & Admin menu in the web app (lumio.vision, production included): a wrench icon left of Logout in the dashboard sidebar and the shortcut Ctrl + Alt + Shift + D. Its first tool previews a seasonal look in the admin's own browser only (see Preferences → Seasonal Look). The web app shows the menu only to users whose admin roles give them both admin:access and devtools:read; it is seeded to system_admin and can be added to further admin roles here. Nothing the menu does is sent to the server, so it writes no audit event.

System Roles​

Roles with is_system: true (shown with a "System" badge) are protected:

  • They are editable - you can change their name, description, and permissions.
  • They are not deletable - the Delete Role button in the dialog's Danger Zone is disabled, with "System roles cannot be deleted." shown as both a tooltip and a note underneath. The server refuses the delete as well.

The built-in system_admin role is an example of a system role.

Member Management​

The edit dialog includes a Members section:

  • Lists all admin users currently holding the role with their name, email, and avatar.
  • Use the search box to find users by name or email and add them to the role. The search is debounced and excludes users who already hold the role.
  • Click the remove button next to any member to unassign them.

API​

ActionGraphQLREST
List rolesadminRolesGET /v1/admin/admin-roles
Get a roleadminRoleGET /v1/admin/admin-roles/\{id\}
Create a roleadminCreateRolePOST /v1/admin/admin-roles
Update a roleadminUpdateRolePATCH /v1/admin/admin-roles/\{id\}
Delete a roleadminDeleteRoleDELETE /v1/admin/admin-roles/\{id\}
List role membersadminRoleMembersGET /v1/admin/admin-roles/\{id\}/members
Assign a memberadminAssignUserRolePUT /v1/admin/admin-roles/\{id\}/members/\{userId\}
Unassign a memberadminUnassignUserRoleDELETE /v1/admin/admin-roles/\{id\}/members/\{userId\}
Permission registry for the pickerallAdminPermissionsGET /v1/admin/admin-permissions

Assigning and unassigning members is gated on admin-roles:edit, not on a dedicated permission.

A role's permission list is validated against the backend registry on create and update, so a wildcard such as accounts:* can never be persisted into an admin role.