permits: admin CRUD (route + UI)
A permit is an aggregate (row + credentials + bound plates); create/update treat it as one unit (child sets replaced on update). GET /api/permits (any signed-in role, for lookup); POST/PUT/DELETE + POST /:id/revoke (admin only). Validation: maxConcurrent positive-int-or-null (unbound); a permit must have at least one credential OR one bound plate. Revoke is the soft common case (keeps history, barred at the barrier); DELETE hard-removes — past ledger events that reference it are untouched (append-only audit trail, independent of this row). Web PermitManager in the admin shell: list + add/edit (holder, car-bound toggle, validity, credentials, plates), revoke, delete. Makes permits usable without hand-seeding (companion to the tariff composer). Verified via inject: validation (empty / maxConcurrent=0 -> 400), create -> 201, operator can LIST but not write (403), update replaces child rows, revoke -> revoked, delete -> 204 then 404 with children cleaned.
This commit is contained in:
+13
@@ -564,3 +564,16 @@ guarantee. Recorded in [[dingtian-relay]] (new Hardening section).
|
||||
F1 exits → F3 enters); plate-bound permit opens; revoked → reject; unknown credential falls through
|
||||
to exit-flow reject (not mis-read as permit); verifyChain ok. Full build 5/5.
|
||||
- Updated [[permit]] (as-built), [[parking-session]] (read dispatch).
|
||||
|
||||
## [2026-06-15] build | Permit admin CRUD (route + UI)
|
||||
- `apps/server/src/routes/permits.ts`: a permit is an aggregate (row + credentials + bound plates);
|
||||
create/update replace the child sets as one unit. GET (any role, for lookup), POST/PUT/DELETE +
|
||||
POST /:id/revoke (admin only). Validation: maxConcurrent positive-int-or-null; must have ≥1
|
||||
credential OR ≥1 plate. Revoke = soft (keeps history); DELETE = hard (past ledger events untouched).
|
||||
- `apps/web/src/PermitManager.tsx` in the admin shell: list + add/edit (holder, car-bound toggle →
|
||||
maxConcurrent or unbound, validity window, credentials add/remove, plates as a list), revoke, delete.
|
||||
- Makes permits usable without hand-seeding (companion to the tariff composer).
|
||||
- VERIFIED via inject: empty + maxConcurrent=0 → 400 w/ messages; valid → 201; operator LIST 200 but
|
||||
create 403; update unbinds + REPLACES child rows (old cred gone); revoke→revoked; delete→204 then
|
||||
404, children cleaned. Full build 5/5.
|
||||
- Updated [[permit]] (CRUD as-built).
|
||||
|
||||
Reference in New Issue
Block a user