Skip to content

Roles & Permissions ​

Shelf has five organization roles. Every member of a workspace holds at least one; the few who hold several are judged by the most privileged (see Precedence below).

RoleIn plain language
OwnerCreated (or was handed) the workspace. Everything an Administrator can do, plus billing, add-ons, SSO/SCIM settings and transferring ownership. Exactly one per workspace.
AdministratorRuns the workspace: catalogue, settings, team, every booking and every custody assignment. Only the Owner can grant, change or revoke it.
ManagerRuns bookings, custody and audits for everyone: creates, changes, checks out and in, cancels and deletes any booking; assigns or releases custody to anyone; and creates, runs, edits, archives and deletes any audit. Reads the catalogue, locations and team, and adds non-registered members, notes and reminders. Cannot change assets, kits, categories, locations, settings, the team or billing. Owners and Administrators can grant it.
Self serviceBooks equipment and takes custody for themselves. Sees and changes their own bookings; sees others' bookings or custody only when the workspace allows it.
BaseRequests bookings for themselves. Cannot take custody. Sees others' bookings or custody only when the workspace allows it.

How a decision is made ​

Two questions, two resolvers, both in @shelf/permissions:

QuestionAnswered by
May this role do action on entity?the permission matrix: userHasPermission (client), requirePermission / requireMobilePermission (server). A member holding several roles gets the union of their grants; Owner and Administrator are allowed everything.
How far does this role reach? Whose bookings, whose custody, which audits, which limits, who hears about what?the role policy table ROLE_POLICIES, read through resolveRoleAccess to a RoleAccess object. It reads the member's single highest-rank role and folds in the workspace's visibility toggles.

Where to get it:

  • Web loaders and actions: const { access } = await requirePermission(…).
  • Mobile API: const { access } = await getMobileUserContext(userId, organizationId).
  • Web components: useRoleAccess() for reach, useOrganizationRoles() + userHasPermission for the matrix.
  • Companion: useRoleAccess() (apps/companion/hooks/use-role-access.ts) from the roles and toggles /api/mobile/me returns.
  • Owner-only actions: isWorkspaceOwner(roles) / access.ownsWorkspace.
  • Prisma audiences: roles: { hasSome: rolesWhere((p) => p.notifications.orgBookingBroadcasts) }.

Never compare role names in app code. The lint rule local-rules/no-direct-role-checks refuses it in the webapp and the companion: a comparison decides for the roles it names and guesses for the rest.

Workspace visibility toggles ​

Settings → Bookings has four switches: Self service can see bookings, Base can see bookings, Self service can see custody, Base can see custody. Each widens what one role may see. None widens what it may change.

Effective access ​

Rendered from the characterization fixture (apps/webapp/app/utils/permissions/__snapshots__/effective-access.json). Do not edit by hand: run pnpm --filter @shelf/webapp docs:roles.

Precedence (a member holding several roles is judged by the highest): Owner > Administrator > Manager > Self service > Base.

Reach ​

OwnerAdministratorManagerSelf serviceBase
Sees every booking (toggles off / on)yes / yesyes / yesyes / yesno / yesno / yes
Sees every custodian (toggles off / on)yes / yesyes / yesyes / yesno / yesno / yes
Removes booking items inDRAFT, RESERVED, ONGOING, OVERDUEDRAFT, RESERVED, ONGOING, OVERDUEDRAFT, RESERVED, ONGOING, OVERDUEDRAFT, RESERVEDDRAFT
Asset list showsEvery assetEvery assetEvery assetAssets available for bookings, plus the ones they holdAssets available for bookings, plus the ones they hold
Default asset indexADVANCEDADVANCEDADVANCEDSIMPLESIMPLE

Permission matrix ​

EntityOwnerAdministratorManagerSelf serviceBase
assetcreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-rolecreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-roleread, custodyread, custodyread
assetIndexSettingscreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-rolecreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-roleread, updatereadread
assetModelcreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-rolecreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-rolereadNoneread
assetReminderscreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-rolecreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-rolecreate, read, update, deleteNoneNone
auditcreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-rolecreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-rolecreate, read, update, delete, archiveread, updateread, update
auditNotecreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-rolecreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-rolecreate, read, update, deletecreate, readcreate, read
bookingcreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-rolecreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-rolecreate, read, update, delete, checkout, checkin, export, archive, cancel, extend, manage-assets, manage-kitscreate, read, update, delete, checkout, checkin, export, archive, cancel, extend, manage-assets, manage-kitscreate, read, update, delete, export, manage-assets, manage-kits
bookingNotecreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-rolecreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-rolecreate, read, update, deletecreate, readcreate, read
categorycreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-rolecreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-roleNoneNoneNone
command-palette-searchcreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-rolecreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-rolereadreadread
custodycreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-rolecreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-rolereadNoneNone
customFieldcreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-rolecreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-roleNoneNoneNone
dashboardcreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-rolecreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-roleNoneNoneNone
emailSettingscreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-rolecreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-roleNoneNoneNone
generalSettingscreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-rolecreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-roleNoneNoneNone
kitcreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-rolecreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-roleread, custodyread, custodyread
locationcreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-rolecreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-rolereadNoneNone
locationNotecreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-rolecreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-roleNoneNoneNone
nonRegisteredMembercreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-rolecreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-rolecreate, read, updateNoneNone
notecreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-rolecreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-rolecreate, read, deleteNoneNone
qrcreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-rolecreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-rolereadreadread
reportscreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-rolecreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-roleNoneNoneNone
scancreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-rolecreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-rolereadNoneNone
subscriptioncreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-rolecreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-roleNoneNoneNone
tagcreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-rolecreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-roleNoneNoneNone
teamMembercreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-rolecreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-rolereadNoneNone
teamMemberNotecreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-rolecreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-roleNoneNoneNone
teamMemberProfilecreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-rolecreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-rolereadNoneNone
updatecreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-rolecreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-rolereadreadread
user-datacreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-rolecreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-roleread, updateread, updateread, update
workingHourscreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-rolecreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-rolereadreadread
workspacecreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-rolecreate, read, update, delete, checkout, checkin, export, import, archive, cancel, extend, manage-assets, custody, manage-kits, change-roleNoneNoneNone

Adding a role ​

  1. Add the value to the OrganizationRoles enum in packages/database/prisma/schema.prisma and write the migration (ALTER TYPE … ADD VALUE, alone in its file).
  2. Add it to ORGANIZATION_ROLES in packages/permissions/src/roles.ts; the parity check forces both sides to match.
  3. Add its row to Role2PermissionMap (matrix.ts), ROLE_POLICIES (policies.ts) and ROLE_LABELS (roles.ts). All three are total records: the build fails until each has an entry.
  4. If an SSO group can confer it, add an SsoDetails column and its entry in SSO_GROUP_ROLE (apps/webapp/app/utils/sso-group-roles.ts).
  5. Regenerate the fixture and this page, and review every changed row.

Released under the AGPL-3.0 License.