Permissions matrix
The single source of truth is packages/contracts/src/rbac.ts. This page is generated from that file: if you find a mismatch, the contract wins.
Full permission list
Section titled “Full permission list”TwistCue has ~30 permissions in the form resource:action. * is a wildcard reserved for superadmin.
Full role × permission matrix
Section titled “Full role × permission matrix”Legend: ✅ granted · – not granted · Wildcard * grants everything.
| Permission | superadmin | content_manager | moderator | support | analyst | finance |
|---|---|---|---|---|---|---|
| catalog:read | ✅ | ✅ | ✅ | ✅ | ✅ | – |
| catalog:write | ✅ | ✅ | – | – | – | – |
| catalog:delete | ✅ | ✅ | – | – | – | – |
| publishing:read | ✅ | ✅ | – | – | – | – |
| publishing:write | ✅ | ✅ | – | – | – | – |
| curation:read | ✅ | ✅ | ✅ | – | ✅ | – |
| curation:write | ✅ | ✅ | – | – | – | – |
| users:read | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| users:ban | ✅ | – | ✅ | ✅ | – | – |
| users:anonymize | ✅ | – | – | – | – | – |
| wallet:read | ✅ | – | – | ✅ | – | ✅ |
| wallet:adjust | ✅ | – | – | ✅¹ | – | ✅ |
| payments:read | ✅ | – | – | ✅ | ✅ | ✅ |
| payments:refund | ✅ | – | – | – | – | ✅ |
| payments:refund_request | ✅ | – | – | ✅ | – | ✅ |
| pricing:read | ✅ | – | – | – | – | ✅ |
| pricing:write | ✅ | – | – | – | – | ✅ |
| moderation:read | ✅ | – | ✅ | – | – | – |
| moderation:write | ✅ | – | ✅ | – | – | – |
| push:read | ✅ | ✅ | – | – | – | – |
| push:write | ✅ | ✅ | – | – | – | – |
| analytics:read | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| admins:read | ✅ | – | – | – | – | – |
| admins:write | ✅ | – | – | – | – | – |
| roles:read | ✅ | – | – | – | – | – |
| roles:manage | ✅ | – | – | – | – | – |
| approvals:read | ✅ | – | – | – | – | – |
| approvals:decide | ✅ | – | – | – | – | – |
| audit:read | ✅ | – | – | – | ✅ | ✅ |
| system:read | ✅ | – | – | – | – | – |
| system:write | ✅ | – | – | – | – | – |
¹ support’s wallet:adjust is subject to the 500-coin-per-user-per-day cap: enforced in admin-users.service, not by the guard.
Grouped by resource
Section titled “Grouped by resource”Catalog
Section titled “Catalog”catalog:read: view series, episodes, taxonomy, cast, media metadatacatalog:write: create / edit series & episodes / taxonomy / castcatalog:delete: delete series (two-person action) / episodes / taxonomy / cast
Publishing
Section titled “Publishing”publishing:read: view schedule / statuspublishing:write: schedule / publish / unpublish / archive
Curation
Section titled “Curation”curation:read: view hero / rails / collections / free-todaycuration:write: edit hero / rails / collections / free-today
users:read: search / view users, notesusers:ban: ban / suspend / reactivate; comp subscriptionusers:anonymize: GDPR delete (two-person action)
Wallet & coins
Section titled “Wallet & coins”wallet:read: view ledgerwallet:adjust: grant / deduct coins. Support-capped at 500/user/day.
Payments
Section titled “Payments”payments:read: view transactions / refunds / reconciliationpayments:refund_request: request refunds (routed to executor)payments:refund: execute refunds (>$50 also requires approval)
Pricing / promos / packages
Section titled “Pricing / promos / packages”pricing:read,pricing:write: pricing overrides, coin packages, promos, subscriptions
Moderation
Section titled “Moderation”moderation:read,moderation:write: comments, reports, strikes
push:read,push:write: segments, campaigns, sending
Analytics
Section titled “Analytics”analytics:read: every analytics dashboard
System
Section titled “System”admins:read,admins:write: admin user CRUDroles:read,roles:manage: role CRUDapprovals:read,approvals:decide: two-person queueaudit:read: audit logsystem:read,system:write: feature flags, market settings
Permission enforcement
Section titled “Permission enforcement”- Server-side:
PermissionsGuardon every route with@RequirePermission('resource:action'). OR semantics across multiple listed perms. - Client-side: sidebar hides routes you can’t reach; buttons hide actions you can’t perform.
- Superadmin
*short-circuits to true inhasPermission().
Custom permissions
Section titled “Custom permissions”Not supported. Only the 30+ predefined resource:action combinations from rbac.ts are recognized. Adding a new permission requires:
- Adding it to
PERMISSIONSinpackages/contracts/src/rbac.ts. - Adding it to a
PERMISSION_GROUPSentry so the role editor shows it. - Applying
@RequirePermission('new:perm')on the target endpoint. - Rebuilding contracts, api, admin.
Related
Section titled “Related”- The six roles: the role-focused explanation.
- Approvals queue: what actions require two-person.