RefractTrack Permissions and Roles
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:reportimplies nothing — it's the stripped-down reporter flow, not real task visibility.tasks:bulkcreateadditionally implieslists:view(it needs to read saved lists, not manage them), on top of the usualtasks: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 = 1is 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.