Jump to content

RefractTrack Permissions and Roles

From Pixel Refraction Studio
Revision as of 23:28, 27 August 2026 by Nerdofepic (talk | contribs) (Created page with "== Permissions and Roles == RefractTrack uses a full role-based access control (RBAC) system. There is no longer a fixed "Member vs. Reporter" split baked into the code — that distinction now exists only as a seeded, ordinary, fully-editable '''Reporter''' role preset, like any other role. === Permission keys === <code><nowiki>includes/permissions.php</nowiki></code>'s <code><nowiki>PERMISSION_DEFS</nowiki></code> is the single source of truth for every permission k...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Permissions and Roles

RefractTrack uses a full role-based access control (RBAC) system. There is no longer a fixed "Member vs. Reporter" split baked into the code — that distinction now exists only as a seeded, ordinary, fully-editable Reporter role preset, like any other role.

Permission keys

includes/permissions.php's PERMISSION_DEFS is the single source of truth for every permission key that can exist. Adding a new permission is a code change, never a database migration.

Category Key Meaning
tasks tasks:view View tasks on the board or list
tasks tasks:report Report tickets through the simplified reporter form
tasks tasks:create Create new tasks with full features
tasks tasks:bulkcreate Use the bulk task creation tool
tasks tasks:edit:content Edit a task's content (title, description, type, priority, groups)
tasks tasks:edit:stage Move tasks between stages (also allows setting the assignee and due date)
tasks tasks:review Approve, reject, or reset a task's review status
tasks tasks:delete Permanently delete tasks
tasks tasks:archive Archive or unarchive tasks
tasks tasks:clone Clone existing tasks
comments comments:view View comments on tasks
comments comments:create Post comments on tasks
comments comments:edit Edit your own comments after posting (admins can edit anyone's)
attachments attachments:view View attachments on tasks
attachments attachments:create Upload new attachments to tasks
attachments attachments:delete Remove attachments from tasks
projects projects:view View existing projects
projects projects:create Create new projects
projects projects:edit Edit existing projects
projects projects:activate Activate or deactivate projects
stages stages:view View existing stages
stages stages:create Create new stages
stages stages:edit Edit existing stages
stages stages:reorder Reorder stages
stages stages:delete Delete stages
groups groups:view View existing groups
groups groups:create Create new groups
groups groups:edit Edit existing groups
groups groups:delete Delete existing groups
lists lists:view View bulk-create saved lists
lists lists:create Create bulk-create saved lists
lists lists:edit Edit bulk-create saved lists
backups backups:export Export a project as JSON or CSV
backups backups:import Import a project from JSON or CSV
themes themes:change Change the application's color theme
themes themes:brand Change the application's name/branding
users users:view View existing users
users users:create Create new users (including their permissions and projects)
users users:edit:contents Edit a user's display name and password (usernames can't be changed after creation)
users users:edit:permissions Edit the permissions granted to a user
users users:edit:projects Edit which projects a user has access to
users users:activate Activate or deactivate users
roles roles:view View existing role presets
roles roles:create Create new role presets
roles roles:edit Edit existing role presets
roles roles:delete Delete role presets

Implied permissions

Holding a more capable permission implies holding the corresponding :view permission, so granting tasks:create also grants tasks:view without a separate step, and so on for essentially every noun/verb pair above. Two deliberate exceptions:

  • tasks:report implies nothing — it's the stripped-down reporter flow, not real task visibility.
  • tasks:bulkcreate additionally implies lists:view (it needs to read saved lists, not manage them), on top of the usual tasks:view.

This is an explicit map, not something derived by pattern-matching the permission name, precisely to allow exceptions like these.

Role presets

  • roles / role_permissions — named presets (e.g. "Reporter"), managed from Manage → Roles.
  • roles.is_system = 1 is reserved for the built-in Admin role.
  • Applying a role preset to a user (apply_role_to_user()) is a one-time copy into that user's own permission grants — not a live link. Editing a role afterward does not retroactively change users the preset was previously applied to.

Per-user permissions

user_permissions is the actual, live source of truth for every non-admin user's grants — independent of whatever role preset (if any) was used to seed them.

Admin bypass

users.is_admin is a bypass flag, not a materialized permission list. The core authorization check (user_can()) short-circuits to true for admins on every check, so a newly-added permission automatically applies to every admin user with no data migration needed.

Project-scoped permissions

Most permissions are additionally checked against user_project_access — a user can hold a permission globally but still be denied for a specific project they lack access to:

Checked per-project (default-allow — granted globally unless a project access row restricts it): tasks:view, tasks:create, tasks:bulkcreate, tasks:edit:content, tasks:edit:stage, tasks:review, tasks:delete, tasks:archive, tasks:clone, comments:view, comments:create, comments:edit, attachments:view, attachments:create, attachments:delete, backups:export, backups:import.

backups:export/backups:import are included here even though they're not "task" permissions by category, because both operate on a project's full task data wholesale — leaving them unscoped would let a restricted user route around the rest of the restriction by simply exporting (or importing into) a project they otherwise can't see.

Checked per-project (default-deny — empty access means zero projects, not "everything"): tasks:report — preserving the historical reporter-form behavior where a reporter with no explicit project grants can't submit anywhere.

Deliberately NOT project-scoped: stages:*, groups:*, and lists:*, even though the underlying data they manage (stages, groups, saved lists) is itself project-owned. The ability to manage stages/groups/lists at all remains a global grant; only which project's stages/groups/lists a user is looking at changes per page. This is intentional product precedent, not an oversight — see Stages and Groups.