Skip to content

PRD: Fixed & custom roles

ModulePermissions (CORE-02)PRD IDPRD-ROLE-001
StatusShippedOwnerPermissions squad
Date2026-05-27Versionv1.0
Packages@nx/identity · @nx/core · apps/client · apps/boURDROLE · CROLE

TL;DR

Gives every KICKO tenant a working role layer on top of the Casbin RBAC engine: eight fixed system roles ship pre-seeded with a numeric priority hierarchy, and administrators and owners can define their own custom roles scoped to an organization or merchant. The result: access levels are predictable out of the box, the top roles bypass data filtering while Owner/Cashier/Employee stay scoped, and no one can ever create or manage a role at or above their own priority.

1. Context & Problem

KICKO controls feature and data access through a Casbin priority-based RBAC model with per-merchant domains, but the engine alone has no opinion about which roles exist or who may create them. Without a role layer, every tenant would start empty - no default access levels, no guard against an admin minting a role more powerful than themselves, and no way to limit a role to one organization or merchant.

A merchant needs sensible defaults the moment it is created, a fixed set of system roles that cannot be tampered with, and the freedom for administrators and owners to define narrower roles for their own staff. Roles must also be wired to the per-merchant domain model so that a role's domain travels in the sign-in token and role listings filter by merchantId/organizer. This is the foundation the rest of the Permissions module (grants, effective permissions, hierarchy) builds on.

2. Goals & Non-Goals

Goals

  • Seed eight fixed system roles at startup with a numeric priority hierarchy - Super Admin / Admin / Operator bypass data filtering, while Owner / Cashier / Employee are scoped to the org or merchants they belong to; seed a default GUEST role for sign-up.
  • Protect SYSTEM roles: block modify, delete, and priority change; exclude them from role-merchant mapping counts.
  • Let administrators and owners create custom roles with an i18n name, a priority strictly below their own, and an optional organization/merchant scope; auto-generate the role identifier from priority + name.
  • Support role update (name, description, priority) and safe deletion (blocked while users remain assigned; cascade-removes grants and scope links).
  • Scope role CRUD by organizer/merchant; make merchantId an optional query param; HQ owners skip the merchant/identifier filter.
  • Return a role's domain in the JWT token, so authorization resolves within the active merchant domain.
  • Provide a role-management UI: role list with filters, a create/edit form with priority input and merchant sync, and a collapsible permission tree.

Non-Goals

  • Wildcard / glob permissions and permission categories - see Non-Goals in the URD.
  • The resource/action/domain hierarchy and coarse manage/write grants - owned by the Resource, Action & Domain Hierarchy increment.
  • Permission catalog and grant/revoke - owned by Policy-Definition Grants.
  • Time- or shift-based permissions, permission audit logging, per-merchant active-role switching.

3. Success Metrics

MetricTarget / signal
Out-of-box readiness100% of new merchants have the eight fixed roles available at first sign-in
System-role integrityZero successful modify/delete/priority-change on a SYSTEM role; system roles never counted in role-merchant mapping
Privilege-escalation guardZero custom roles created at or above the creator's own priority
Scope correctnessRole list/count always filtered to the requesting user's reach; foreign IDs never returned
AdoptionCustom roles created per organizer trends up as merchants tailor staff access

4. Personas & Use Cases

PersonaGoal in this feature
Super Admin / Admin / OperatorManage roles across the platform with full data reach
OwnerCreate and manage roles scoped to their own organization and merchants
Administrator (BO)Maintain roles and their permission trees from the back office
Employee / CashierReceive a fixed, scoped role limiting them to assigned merchants

Core scenarios: a merchant is created with eight fixed roles already seeded → an admin or owner creates a custom role with a priority below their own and an optional org/merchant scope → they edit the role's name, priority, and permission tree → and delete it safely once no users remain assigned, with system roles always protected.

5. User Stories

  • As an owner, I want a fixed set of roles available the moment my merchant exists, so I can assign staff without configuring access levels from scratch.
  • As an administrator, I want to create a custom role with a priority strictly below my own, so I can delegate without granting more power than I hold.
  • As an administrator, I want to scope a custom role to one organization or merchant, so it only applies where it should.
  • As an administrator, I want to update a role's name, description, and priority, so role definitions stay accurate over time.
  • As an administrator, I want deletion blocked while users are still assigned, so I never strand a user without a role.
  • As an owner, I want system roles to be untouchable, so the platform's baseline access model can't be broken.
  • As an administrator, I want a role-management screen with a collapsible permission tree, so I can see and shape what a role can do at a glance.

6. Functional Requirements

#RequirementURD ref
FR-1Seed eight fixed system roles at startup (Super Admin, Admin, Operator, Owner, Cashier, Employee, Customer, Guest); seed a default GUEST for sign-upURD-ROLE-001
FR-2Each role carries a numeric priority that sets its place in the hierarchyURD-ROLE-003
FR-3Super Admin / Admin / Operator bypass all data filtering and hold every permissionURD-ROLE-004
FR-4Owner sees only their own organization and its merchants; Employee/Cashier see only assigned merchantsURD-ROLE-005..006
FR-5Every list and count operation is filtered by the requesting user's scope and cannot be overriddenURD-ROLE-007..008
FR-6An HQ owner reaches every sibling merchant of the organizer; HQ skips the merchant/identifier filterURD-ROLE-009
FR-7SYSTEM roles cannot be modified, deleted, or have their priority changed; excluded from role-merchant mapping countsURD-ROLE-002
FR-8Authorized users create custom roles with an i18n name, priority, and optional org/merchant scopeURD-CROLE-001 · URD-CROLE-004
FR-9Role identifier is auto-generated from priority + name and is unique within its scopeURD-CROLE-002
FR-10A new role's priority must be strictly lower than the creator's own highest priorityURD-CROLE-003
FR-11Custom roles can be updated (name, description, priority)URD-CROLE-005
FR-12A role cannot be deleted while users remain assigned; deletion cascade-removes grants and scope linksURD-CROLE-006..007
FR-13An Owner can create roles scoped only to their own organization or merchantsURD-CROLE-008
FR-14A role's domain is returned in the sign-in JWT tokenURD-ROLE-004

Full requirement text and acceptance criteria live in the Permissions URD. This PRD references them rather than restating them.

7. Non-Functional Requirements

AreaRequirement
Data integrityAll records are soft-deleted, never physically removed; deleting a role cascades to its grants and scope links atomically
Tenancy & authzAll role CRUD scoped per merchant (x-merchant-id) and organizer; gated by permissions; privilege-escalation guard on every create/manage
StatelessnessThe session token is stateless - role changes take effect on next sign-in; a role's domain is carried in the JWT
Performance / scaleRole list/count filtering by scope avoids loading roles outside the user's reach
i18nRole name and description are bilingual ({ en, vi })
ConsistencyIdentifier auto-generation and scope-link creation happen in one operation; partial failures don't leave orphaned roles

8. UX & Flows

Key screens: in apps/client, a role-management screen with a collapsible permission tree, a create/edit form with priority input, multi-language description, and merchant sync; in apps/bo, role screens with filters and an admin update form.

9. Data & Domain

EntityRole
RoleNamed access level - i18n name, numeric priority, SYSTEM or CUSTOM type, auto-generated identifier
Role-merchant / role-organizer scope linkMembership binding a custom role to a specific organization or merchant
User-role membershipLinks a user to a role; deletion is blocked while any remain
Permission grantPolicy record removed in cascade when a role is deleted
Sign-in token (JWT)Carries the user's roles and the active merchant domain

Conceptual only - full schema and the policy data model live in the identity RBAC docs.

10. Dependencies & Assumptions

Depends on

  • User Management (CORE-01) - users are the subjects that receive roles.
  • Commerce (orgs & merchants) - organizations and merchants are the scopes roles attach to.
  • Casbin RBAC engine (@nx/core) - the priority-based model with per-merchant domains the role layer sits on.

Assumptions

  • Each merchant is created with access to the eight seeded fixed roles.
  • The active merchant is chosen per request via the active-merchant header; the role's domain resolves within it.
  • An organizer/merchant the custom role is scoped to already exists.

11. Risks & Open Questions

Risk / questionMitigation / status
An admin mints a role more powerful than themselvesPrivilege-escalation guard - new priority must be strictly below the creator's own
System roles tampered with or miscountedSYSTEM roles immutable and excluded from role-merchant mapping counts
Deleting a role strands assigned usersDeletion blocked while users remain; must unassign first
Stateless token means stale permissionsAccepted - role/permission changes take effect on next sign-in
HQ-owner reach across sibling merchantsHQ owners skip the merchant/identifier filter; behaviour documented as expansion

12. Release Plan & Launch Criteria

AspectPlan
PhaseROLE is P1, CROLE is P2 - see URD feature catalog
RolloutAll merchants; no feature flag
MigrationEight fixed roles + default GUEST seeded at startup; no data migration
Launch criteriaEight roles seeded and protected; custom create/update/delete verified with priority guard and cascade; role list/count scoped correctly; role domain present in JWT
MonitoringCustom-role creation volume, privilege-escalation rejections, role-scope filter consistency

13. FAQ

Can a system role be edited or deleted? No - the eight SYSTEM roles are immutable: modify, delete, and priority change are all rejected, and they are excluded from role-merchant mapping counts.

Why can't I create a role with the same priority as mine? The privilege-escalation guard requires a new role's priority to be strictly below your own highest priority, so you can never delegate more power than you hold.

What scope does a custom role apply to? It can be scoped to a specific organization or merchant; an Owner can only scope to their own organization or merchants.

Why can't I delete a role? Deletion is blocked while users are still assigned - unassign them first. Once empty, deletion cascade-removes the role's grants and scope links.

When do role changes take effect? On next sign-in - the session token is stateless and carries the user's roles and domain.

References

Proprietary and Confidential. Unauthorized copying, distribution, or use of this software is strictly prohibited.