ADR-0002. RBAC via Casbin + PolicyDefinition edge table
| Field | Value |
|---|---|
| Status | Accepted |
| Date | 2026-02-04 |
| Deciders | identity-team |
| Supersedes | — |
Context
- We need a flexible RBAC model that supports:
- System fixed roles (SUPER_ADMIN, ADMIN, OPERATOR, OWNER, CASHIER, EMPLOYEE, CUSTOMER, GUEST)
- Custom merchant roles
- Permission grants (Role → Permission)
- Scoping (User can be SCOPED_OWNER for organizer X but EMPLOYEE for organizer Y)
- Two natural approaches:
- Triple tables: User_Role, Role_Permission, plus separate scoping
- Single edge table with
subject+targetpolymorphism
Decision
Use a single PolicyDefinition table with two variants:
| Variant | Subject | Target | Use |
|---|---|---|---|
GROUP | User | Role / Organizer / Merchant | "User X has role Y" or "User X belongs to merchant Z" |
PERMISSION | Role | Permission | "Role Y has permission Z" |
Plus a scope field (SYSTEM / ORGANIZER / MERCHANT) to constrain edges to a context.
Casbin's RBAC model is configured to evaluate this table at request time. Per-edge changes propagate immediately (no role-recompile step).
Consequences
| Pros | Cons |
|---|---|
| Single table for all RBAC edges; uniform query | Polymorphic — no DB-level FK to subject/target |
| Scope field lets one user be different roles per organizer | Casbin's evaluation cost grows with edge count |
| Custom merchant roles are first-class (not hard-coded) | Permission-check latency requires Redis caching at sister side |
Add new variants (e.g. RESOURCE for ABAC) without schema migration | Audit/diff of "who can do X" requires graph traversal |
Alternatives Considered
| Option | Pros | Cons | Why rejected |
|---|---|---|---|
| Triple tables (UserRole, RolePermission) | Clear semantics | Two more migrations + parallel write paths | Worse maintenance |
| Single jsonb permission set per User | Fast read | No history; no group inheritance; impossible to query "who has X" | Wrong primitive |
| Spicedb / external authz | Industry standard | Operational overhead; vendor latency | Premature for our scale |
References
core/src/models/schemas/identity/policy-definition/schema.tsservices/policy-definition/— 4 specialized writerscasbinmodel file (Casbin RBAC with domains)