Files
hackerspace.sh/content/docs/reference/roles-and-permissions.md
T
Moheeb Zara 16229ae523 feat(docs): add a Diátaxis documentation section to the public site
A new public /docs area covering the whole platform, organized by Diátaxis:
tutorials (learning), how-to guides (tasks), reference (facts), and explanation
(the why). 29 pages, each grounded in the actual routes, actions, schema, and
UI — verified against the code and corrected for accuracy (e.g. admin-only vs
admin+board gating, where the permissions matrix actually lives, how Stripe
reconciliation matches).

Implementation:
- lib/docs/nav.ts is the single source of truth (categories + pages), driving
  the sidebar, static params, and prev/next.
- Content authored as content/docs/<category>/<slug>.md, read at build time
  (the routes are statically generated), rendered by <DocsMarkdown> — reuses the
  existing react-markdown/GFM stack, no new dependencies.
- (docs) route group with its own theme (docs.css) matching the public site's
  dark / monospace / lime aesthetic; sidebar with active-state, breadcrumb,
  prev/next, and a Diátaxis home. Public — signed-in users can read it too.
- "Docs" link added to the landing nav.

typecheck 0 · lint 0 errors · build ok (all /docs pages prerendered)
2026-08-05 00:42:42 -07:00

5.8 KiB

Every space controls who can do what through two layers: a fixed set of five built-in roles that drive database-level access, and an additive per-space permission matrix that grants named capabilities to roles. This page catalogs both, plus the status gate that decides when a role or permission actually takes effect.

Built-in roles

There are exactly five roles, defined by the member_role enum and listed here in privilege order. Every member holds exactly one built-in role. Roles cannot be added or removed, but a space can rename any of them and change its color in Customize (see Customize your space); the rename is display-only and does not change access.

Role Default label Notes
admin Admin Implicitly holds every permission and can never be locked out
board Board Broad operational access; default holder of most permissions
treasurer Treasurer Finance-focused
member Member Standard member
associate Associate Limited access

Two role groups are used throughout the app: ADMIN_ROLES (admin, board) gate most administrative writes, and TREASURER_ROLES (admin, board, treasurer) gate financial sign-off.

Status and privilege eligibility

Holding a role is not enough to use it. A member's member_status must be privilege-eligible before any role or permission resolves. This is enforced at both the app layer and the RLS layer (user_has_role_in_space and user_has_permission both require it).

Status Can act in app Privilege-eligible
current Yes Yes
late Yes Yes
unverified Yes (own /me and onboarding only) No
inactive No No

unverified is deliberately excluded: in a space that requires approval, a new member stays unverified until an admin approves them and must hold no privileged capability in that window, even if they redeemed a role-bearing invite code. A dues lapse moves a member current → late; that is a grace state, not an authorization downgrade, so late keeps its role.

Permission catalog

Permissions are app-owned capability codes (the set is fixed by the product). Which roles hold which permissions is stored per space in space_role_permissions. The table below lists every code with its group and the built-in roles that hold it in a newly seeded space. admin holds all of them implicitly and is never stored.

Code Group Capability Default holders
ops.kb.read Ops Read knowledge base board, treasurer, member, associate
ops.kb.write Ops Write knowledge base board
ops.process.read Ops Read processes board, treasurer, member
ops.process.write Ops Write processes board
ops.secrets.read Ops Reveal secrets board
ops.secrets.write Ops Manage secrets board
ops.arealeads.manage Ops Manage area leads board
members.manage People Manage members board
payments.manage Finance Manage payments board, treasurer
governance.manage Governance Manage proposals, incidents, policies board
forum.moderate Community Moderate forum and comments board
forms.manage Community Manage forms and waivers board
certifications.manage Certifications Manage certification types board
certifications.grant Certifications Award and revoke certifications board
classes.manage Classes Manage classes and schedule sessions board
classes.instruct Classes Run classes: attendance, completion, attendees board
equipment.manage Equipment Manage equipment and reservations board
door.manage Access Configure door integrations, buttons, and member cards board
door.operate Access Operate doors: open/lock, push/revoke cards board
apicall.invoke Access Use API-call buttons (non-door automations) board
customize.manage Admin Customize roles, tiers, areas, invites, onboarding board
settings.manage Admin Space settings, integrations, webhooks board

Custom roles

A space can also create custom roles (in the Roles section of Customize). A custom role has a slug, name, description, and color. On its own it is display-only: creating one adds a label for committees, mentors, or area leads and grants nothing. However, a custom role's slug appears as a subject in the Permissions matrix, so an admin can grant it any capability from the catalog. Custom roles are created and edited by admin/board; only admin can delete one.

How permissions resolve

user_effective_roles(uid, sid) returns a member's built-in role, the slugs of any custom roles assigned to them, and an area_lead:<id> marker for each area they lead. user_has_permission(uid, sid, perm) then answers true when the member is privilege-eligible and either holds the admin role (implicit-all shortcut) or one of their effective roles has the permission granted in space_role_permissions.

This layer is strictly additive. A grant can only widen what a role can do through the surfaces that consult permissions; it never overrides the row-level security that isolates one space's data from another. The Permissions matrix is editable by admin and board — both the setRolePermissions server action and the space_role_permissions RLS policies authorize the two roles. The Customize UI, however, currently exposes the matrix as view-only to board and enables editing for admin only; a board member can still change permissions through the server action directly.

See also: Modules reference and Customize your space.