At a Glance
Owner: Seed-managed (release-time) · Table:tb_permission· Used by: access-control/application-role (only consumer) · Atomic(resource, action)pairs — the smallest unit of authorisation.
A permission is the smallest unit of authorisation: a (resource, action) pair such as (purchase_request, approve) or (inventory, view). Permissions are catalogued centrally and never assigned directly to users — they are aggregated into access-control/application-role rows via tb_application_role_tb_permission, and users get them transitively by being granted a role.
The runtime check "can user X perform action Y on resource Z in BU B" is a single join across tb_user_tb_application_role, tb_application_role, and tb_application_role_tb_permission.
Maintained by release migrations (seed). Read by the role-edit UI for bundling and by every API request for permission checks.
Per-document comment threads and approval actions are gated by their own permission atoms (App IDs). Comment permissions follow a uniform verb set per document type:
| Document type | Comment App ID prefix | Actions |
|---|---|---|
| Purchase Request | purchaseRequestComment |
findAll, create, update, delete, addAttachment, removeAttachment, createWithFiles |
| Purchase Order | purchaseOrderComment |
findAll, create, update, delete, addAttachment, removeAttachment, createWithFiles |
| Store Requisition | storeRequisitionComment |
findAll, create, update, delete, addAttachment, removeAttachment, createWithFiles |
createWithFiles is the single-call create that posts a comment with attachments in one multipart request (vs. create then addAttachment).
Approval-workflow atoms:
| App ID | Purpose |
|---|---|
storeRequisition.approve |
Approve a store-requisition approval step |
storeRequisition.reject |
Reject a store-requisition at an approval step |
storeRequisition.review |
Mark a store-requisition reviewed (intermediate workflow action) |
storeRequisition.save |
Save / submit store-requisition workflow changes |
my-approve.findAll |
List every document awaiting the current user's approval, across document types — backs the cross-module approval inbox (dashboard/my-approval) |
These are seed-managed atoms like all others on this page; they are bundled into roles via access-control/application-role.
| Task | Where | Notes |
|---|---|---|
| View the permission catalogue | Sysadmin → Platform → Permissions (read-only) | List grouped by resource |
| Bundle permissions into a role | access-control/application-role edit screen | Checkbox grid; this is the normal path |
| Add a new permission atom | Release migration / seed | tb_permission is seed-managed, not UI-editable |
| Rename / retire a permission | Soft-delete + re-create | Constraint includes deleted_at so (resource, action) can be re-used |
| Find which roles include a permission | Query tb_application_role_tb_permission by permission_id |
Useful before retirement |
| Symptom | Cause | Action |
|---|---|---|
| "Permission not found" at runtime | Code references a permission that was deleted or never seeded | Re-seed or restore via migration |
Duplicate (resource, action) insert |
Existing non-deleted row | Use the existing row instead |
| Feature silently disabled for everyone | Permission deleted while code still references it | Operational guard — restore via migration |
| Confusing tooltip in role editor | Missing or terse description |
Update seed; descriptions should explain what the permission unlocks |
tb_user_tb_permission join — all paths go through application roles.deleted_at so a renamed permission can be soft-deleted and (resource, action) re-created.description is for the role-edit tooltip — must explain what the permission unlocks, not just restate the pair.Source: platform schema.
tb_permission| Field | Prisma Type | Nullable | Description |
|---|---|---|---|
id |
String @db.Uuid |
No | Primary key. |
resource |
String @db.VarChar |
No | Logical resource (e.g. purchase_request, inventory, vendor). |
action |
String @db.VarChar |
No | Verb (e.g. view, create, update, delete, approve, post). |
description |
String? |
Yes | Human-readable label and rationale. |
| Audit columns | — | Yes | created_*, updated_*, deleted_*. |
Constraints: @@unique([resource, action, deleted_at]). Back-relation to tb_application_role_tb_permission. Audit FKs onDelete: NoAction.
(resource, action) is unique among non-deleted permissions; constraint includes deleted_at to allow rename via soft-delete + re-create.tb_application_role. Single source of truth keeps audit trails simple.(resource, action).../carmen-turborepo-backend-v2/packages/prisma-shared-schema-platform/prisma/schema.prisma — tb_permission (lines ~323-341).../carmen-turborepo-frontend/apps/web/app/(app)/configuration/user-role/. No standalone CRUD.