feat(permissions): per-desk till guards, jobs in the role composer, permission-scoped live feed; role reassignment applies without re-login
Permissions matrix rethink (wiki/decisions/venue-modules.md §"Permissions matrix", open-questions #16) — the grid stays the enforcement layer: - Move 1: each desk's money is guarded by that desk's own permissions. Manifest tillGuards {read, shift, cash}: booth = shift:read / shift:create / drawer:create (unchanged), carwash = carwash:read / carwash:cash (new). Shift + drawer routes resolve the guard FROM THE TILL (requireTill); a wash role holds no shift:* and cannot touch the booth by construction. Replaces the session:read borrowing (tillPermission). /api/shift/tills lists the role's readable tills with canWork; history/movements without a till filter return the union of readable tills. - Move 2: jobs — manifest permission bundles (booth-operator, booth-supervisor, merchant, wash-operator) as one-click chips in Setup → Roles, with "mixes desks" and "partial job" lints (warnings, never blocks). - Move 3: the live WebSocket admits any watch permission (event/session/device read or a module's feedPermission) and filters every push per role; report:read is the reports screen only. Auth: the token's roleId is only a hint — refreshRole() after every jwtVerify resolves the user's CURRENT role (cached, bumped on role/user writes), so reassigning a user's role applies on the next request and a deleted user's session ends with 401. Tests: till guards + look-only role, feed rules, every job's permissions exist, role reassignment without re-login. 353/353. Claude-Session: https://claude.ai/code/session_01FWncR69HgGPuei1dLrW3cU
This commit is contained in:
@@ -138,3 +138,11 @@ procurement. (See [[parking-system-architecture]] §10.)
|
||||
payment lands on the wash operator's own till, never the booth's). Open: vision category
|
||||
flag, bay camera, the Bar's scope. Full design and the remaining questions on
|
||||
[[venue-modules]].
|
||||
|
||||
16. **Permissions matrix after venue modules.** _(Raised by the user, 2026-09-05.)_ The flat
|
||||
`resource:action` grid was composed for one desk; a second desk (Car Wash) exposed borrowed
|
||||
meanings (`session:read` as "works the booth till", `report:read` as "may open the socket")
|
||||
and a composer at the wrong altitude. Decision + three moves (per-desk till guards, jobs on
|
||||
top of the grid, a permission-scoped live feed) on [[venue-modules]] §"Permissions matrix";
|
||||
moves built 2026-09-05. Open: default supervisor bundle, re-applying jobs after a module
|
||||
update, signing role edits.
|
||||
|
||||
Reference in New Issue
Block a user