Maintenance permissions matrix (locked)
This document defines who may perform which actions and how permissions flags behave. Frontend must not infer policy; it renders from permissions, relatedUsers[].canViewProfile, and route guards.
Role names match the backend enum: e.g. administrator, super_admin, department_head, employee, technician.
Actions by role (summary)
| Action | employee | technician | department_head | administrator | super_admin |
|---|---|---|---|---|---|
| Create request | ✓ (own) | — | — | — | — |
| Approve (dept) | — | — | ✓ (same dept) | ✓* | ✓* |
| Assign | — | — | ✗ | ✓ | ✓ |
| Decline | — | — | ✓ (same dept) | ✓ | ✓ |
| Cancel | ✓† | — | ✓‡ | ✓ | ✓ |
| Complete | — | ✓ (if assigned) | — | — | — |
| Archive | ✓§ | — | ✓¶ | ✓ | ✓ |
| Purge (hard delete) | ✗ | ✗ | ✗ | ✓ | ✓ |
* Scope rules must match product (e.g. admin may approve any dept — confirm in implementation).
† Employee cancel: typically own request, before or after dept rules per product; must match status-transitions.md.
‡ Department head: same department as request.
§ Submitter: own request only.
¶ Department head: same department only.
Assign: assignedBy is always the administrator / super_admin who performed the assignment (audit).
permissions object (intent)
The API returns a permissions object on detail (and as needed on list). At minimum:
| Flag | Meaning |
|---|---|
canArchive | User may archive this row (see archive rules below). |
canPurge | User may hard-delete this row (see purge rules below). |
Other flags (e.g. canUpdate, canCancel, canApprove) remain as today’s product requires; do not add canDelete (ambiguous).
When archived
| Flag | Rule |
|---|---|
canArchive | false (already archived; unarchive not supported). |
canPurge | Still true for administrator / super_admin if status is cancelled or declined (purge allowed even when archived). |
Archive rules
Archive sets archivedAt / archivedBy (soft hide from default lists).
Eligible status (terminal only)
Archive is allowed only when:
status ∈ { completed, cancelled, declined }
Not allowed for pending or in_progress.
Who may archive
| Role | Scope |
|---|---|
Submitter (employee on own request) | Own request |
department_head | Same department as request |
administrator, super_admin | Per product (typically any) |
Technician cannot archive (locked).
Visibility (archived rows)
Archive does not revoke read access for users who could already see the request. Archived tasks:
- Are hidden from default lists
- Appear when
includeArchived(or equivalent) is true
Accessible by (read): submitter, department head (same department), assigned technician, administrator, super_admin — per locked product spec.
Purge rules (hard delete)
Registry: Only administrator and super_admin may hold purge permission; remove purge from employee, department_head, etc. (breaking change vs legacy if applicable).
Eligible status
cancelledordeclinedonly.completed— must not be purgeable (canPurgefalse even for admin).
Archived
- Purge is allowed for
cancelled/declinedeven ifarchivedAtis set.
Completed + archive
- Completed tasks:
canArchivemay be true;canPurgeis false (retention / audit; compliance tooling out of scope for v1).
relatedUsers[].canViewProfile
- Computed only on the server from viewer role + target user role + policy.
- Frontend: show link to
/users/:idonly whencanViewProfile === true. - No email in
relatedUsers(locked).
Decline (API validation)
declinedNotes: required on the decline request (body).- DB column nullable until decline.
Cancel (API validation)
cancellationNotes: required on the cancel request (body).- DB column nullable until cancel.
Same user, multiple roles in relatedUsers
- A user may appear more than once with different
typevalues. - Frontend must not deduplicate by user id when rendering role lines.
Related documentation
- status-transitions.md — when transitions are valid.
- snapshot-behavior.md — closed-task display and
takenAt.