feat(roles): roles remember the jobs they follow (re-appliable), every role edit is signed
Closes the permissions-matrix loose ends (venue-modules.md §Permissions matrix): - `role_jobs` (migration 0029): a role stores the manifest jobs it was composed from (chips on at save + any bundle fully present). `jobById` / `jobsBehind` in @parking/shared surface a followed job whose bundle grew past the role in a later release; the roles list shows a "behind <job>" badge with a one-click "Update to job" (the union, nothing removed) and the editor lints it. Never a runtime union: the grid stays the explicit enforcement layer and an update never widens a role without a click. - Every role create/update/delete appends a `config_change` (`role.<id>`, prev/value = name + sorted permissions + jobs, operator); a no-op resave signs nothing. roleRoutes now takes the ledger. - booth-supervisor already carries subscription:*; the stale open note is closed. Tests: routes/roles.test.ts. Wiki: venue-modules status, local-jwt-auth, log. Claude-Session: https://claude.ai/code/session_01FWncR69HgGPuei1dLrW3cU
This commit is contained in:
@@ -37,6 +37,11 @@ Authentication and authorization, kept **fully local** — a direct consequence
|
||||
`bumpPermsCache()`, which user update/delete now call), so REASSIGNING a user's role — or deleting
|
||||
the user (→ 401 on their next request) — applies immediately too. Found when a user moved to a new
|
||||
wash role kept the old role's rights until logout.
|
||||
**Role edits are signed (2026-09-06):** every create/update/delete of a role appends a
|
||||
`config_change` (`role.<id>`, before/after shape, operator) to the ledger, and a role remembers
|
||||
the manifest JOBS it was composed from (`role_jobs`) so a job that grows in a later release can
|
||||
be re-applied with one click rather than expanding silently — [[venue-modules]] §Permissions
|
||||
matrix.
|
||||
- **Protected built-in `admin` role** (`id='admin'`, `builtin=1`): non-editable, non-deletable, and
|
||||
always resolves to the FULL permission set in code. The app refuses to delete or downgrade the
|
||||
**last user holding admin** — administration can never be locked out of the appliance.
|
||||
|
||||
Reference in New Issue
Block a user