SRV-06 — RBAC & data scopes
Role and permission catalogue (module × action), permission guard on every procedure, delegate zone scope and reseller ownership scope as reusable query filters.
| Field | Details |
|---|---|
| Task code | SRV-06 |
| Phase | P0 — Foundations (cadrage, UX/UI, architecture & contract) |
| Product scope | V1 |
| Status | Done (Mon 19 Oct 2026) |
| Start | Mon 19 Oct 2026 |
| Due | Mon 19 Oct 2026 |
| Responsible | Anis — Full-stack developer |
| Co-responsible | — |
| Effort | 1 person-day(s) planned · 4 from scratch · size S |
| Area · app | Server · server |
| Depends on | SRV-05 |
| Unblocks | SRV-10, DSH-01 |
| Milestones | — |
Summary
Role and permission catalogue (module × action), permission guard on every procedure, delegate zone scope and reseller ownership scope as reusable query filters.
Description
The cahier (§3, §3.1) asks for eight roles, permissions per module and action, and strict data scopes; ACL-05 requires every API operation to enforce them server-side. This task implements the permission catalogue (<module>.<action> over the 18 modules and 7 actions), the default matrix for the 8 roles, an oRPC middleware that checks the permission declared on each procedure, and two reusable scope filters: self (a reseller's own data) and delegate (the delegate's zones and assigned resellers) applied as Prisma where builders, returning 404 NOT_FOUND/403 OUT_OF_SCOPE outside scope. Financial fields (purchase price, margins, credit) are stripped from responses unless the caller holds the right permission (ACL-04). It also implements admin.roles.list, admin.roles.updatePermissions and admin.permissions.list with PERMISSION_CHANGE audit. Out of scope: the matrix UI (DSH-12).
Subtasks
| # | Subtask | Owner |
|---|---|---|
| 1 | Permission catalogue generated from the module × action list and synced to the Permission table at boot | Anis |
| 2 | Default role matrix for SUPER_ADMIN, COMMERCIAL_ADMIN, STOCK_MANAGER, FINANCE_MANAGER, DELIVERY_MANAGER, DIRECTION, DELEGATE, RESELLER (seeded, SUPER_ADMIN locked) | Anis |
| 3 | requirePermission middleware reading procedure meta; 403 PERMISSION_DENIED with the missing key in details | Anis |
| 4 | Effective-permission cache per user in Redis with invalidation on role or matrix change | Anis |
| 5 | Scope builders scopeSelf(ctx) and scopeDelegate(ctx) (zones via DelegateZone/ZoneArea, assigned resellers via ResellerAssignment) and OUT_OF_SCOPE handling | Anis |
| 6 | Response shaping for restricted fields: purchasePrice and margins need pricing.administer, credit data needs finance.view (ACL-04) | Anis |
| 7 | admin.roles.list, admin.roles.updatePermissions, admin.permissions.list with PERMISSION_CHANGE audit entries | Anis |
| 8 | CI guard: every procedure in the router declares either a permission, a scope or auth: public/optional | Anis |
Deliverables
- apps/server/src/modules/access/{catalogue.ts,matrix.seed.ts,guard.ts,scopes.ts,roles.router.ts}
- packages/contracts/src/admin/system.roles.ts
- Permissions matrix page /docs/srs/permissions-matrix aligned with the seed
Acceptance criteria
- A STOCK_MANAGER calling admin.orders.validate gets 403 PERMISSION_DENIED (ACL-02, ACL-05)
- A delegate requesting a reseller outside their zones and assignments gets 403 OUT_OF_SCOPE; a reseller requesting another reseller's order gets 404 NOT_FOUND (ACL-03)
- purchasePrice is absent from admin.products.get for a user without pricing.administer (ACL-04)
- Changing a role's permissions takes effect on the next request of its users and writes a PERMISSION_CHANGE audit entry
- The CI guard fails when a procedure has no permission or scope declaration
Requirements covered
| Requirement | Title | Release |
|---|---|---|
| ACL-01 | Eight roles: super admin, commercial admin, stock, finance, delivery, direction, delegate, reseller | V1 |
| ACL-02 | Permissions per module and action (view, create, update, delete, validate, export, administer), editable matrix | V1 |
| ACL-03 | Data scope: delegates see only their zones, tours, assigned resellers and own performance; resellers only their own data | V1 |
| ACL-04 | Least privilege by default; financial data (purchase prices, margins, credit) strictly limited | V1 |
| ACL-05 | Every API operation enforces permission and scope server-side; UI hides what the user cannot do | V1 |
API surface
| Endpoint group | Operations |
|---|---|
| Administration, settings & audit | 22 |
Test measures
- Table-driven permission test: for each role × sample procedure, expected allow/deny
- DB tests for scope filters with delegates on overlapping zones
- Unit test of response shaping for restricted fields
Risks
- Scope checks forgotten on list endpoints — scopes are applied in the repository layer by default and must be explicitly bypassed for staff
KPI
- Delivered by Mon 19 Oct 2026 within 1 person-day(s).
- Every acceptance criterion above demonstrated before hand-off; linked requirements' acceptance criteria pass.
- Zero open critical defects, permission gaps or data-integrity regressions at sign-off.
Generated from content/plan/tasks.json by scripts/generate-team-tasks.mjs. Dates are computed by the scheduler (Sunday–Thursday weeks, holidays excluded) — change the plan, not this page.
SRV-05 — Authentication & sessions (Better Auth)
Phone/email + password sign-in, OTP, reseller sign-up with declared customer type and account claim, guest (anonymous) access rules, password reset/change, bearer sessions for mobile and cookies for web, lockout, status gating, device registration.
SRV-07 — Platform services — audit, numbering, settings, files, PDF
Audit journal writer, sequential business numbers, typed settings service, S3 pre-signed uploads with thumbnails, PDF rendering base for invoices and delivery notes.