feat(equipment): My reservations on /me + docs
/me gains a "My equipment reservations" section (the member's own reservations with status and window). ARCHITECTURE documents the equipment module; HANDOFF pass-23 records Classes deployed and the code-complete-but-local equipment module.
This commit is contained in:
+22
-1
@@ -420,7 +420,8 @@ Migrations 012-030 are tracked authoritatively in `docs/DATABASE_SCHEMA.md`
|
||||
customizable permissions + Ops ACLs, self-change hardening, `026`-`029` custom
|
||||
forms + waivers + onboarding form step + per-space form slug + invite roles,
|
||||
`030` certifications + Instructor capability, `031` secrets SELECT honors
|
||||
`ops.secrets.read`, `032` classes + sessions + signups).
|
||||
`ops.secrets.read`, `032` classes + sessions + signups, `033` equipment +
|
||||
reservations).
|
||||
|
||||
### Forms & waivers (migrations 026-029; complete Phases 1-5)
|
||||
|
||||
@@ -489,6 +490,26 @@ path, so it still requires the acting instructor to hold
|
||||
reports the certificates were skipped (no service-role bypass of the
|
||||
guarded certifications surface). No anonymous path.
|
||||
|
||||
### Equipment (migration 033)
|
||||
|
||||
`equipment` (registry; status available/maintenance/retired; optional
|
||||
`required_certification_id`; `is_active` archive) and
|
||||
`equipment_reservations` (member time-window reservation) back a tool
|
||||
reservation system. Pure logic in `lib/equipment-logic.ts`
|
||||
(`intervalsOverlap`, `hasConflict`, `reservationEligibility`), unit-tested.
|
||||
Server actions in `lib/actions/equipment.ts`. One additive permission,
|
||||
`equipment.manage` (registry CRUD + adjust/cancel any reservation, gates
|
||||
`/equipment/manage` via `lib/equipment-guard.ts`). Members reserve with
|
||||
only membership. `/equipment` is the member catalog (reserve), `/me` lists
|
||||
the member's own reservations. RLS is additive and default-deny: equipment
|
||||
readable by managers (all) or members (active only), reservations by
|
||||
managers (all) or the member (own) with manager-only UPDATE and **no
|
||||
INSERT/DELETE policy** so reserve/cancel funnels through one validated
|
||||
service-client action that enforces the equipment status, the no-overlap
|
||||
rule, and the required-certification gate (checked against the normal
|
||||
`member_certifications` data; an `equipment.manage` holder gets the
|
||||
override and may book on a member's behalf). No anonymous path.
|
||||
|
||||
---
|
||||
|
||||
## 13. Known Limitations
|
||||
|
||||
@@ -4,6 +4,28 @@ Append-only. Newest entries on top. Keep each entry to one screen.
|
||||
|
||||
---
|
||||
|
||||
## 2026-05-17 (pass 23) — Classes DEPLOYED; Equipment module (3) code-complete LOCAL
|
||||
|
||||
Branch `main`. Classes module (pass-22) was deployed this pass (push `2096228`, Actions run 25979364584 success 1m? ; migration `032` applied; `/classes`, `/classes/manage`, `/me` smoke 307→login, not browser-verified). User then chose to continue the locked order → Equipment (module 3).
|
||||
|
||||
### Equipment registry + reservations (locked module 3) — CODE-COMPLETE, LOCAL, 6 commits, NOT deployed
|
||||
Phase-by-phase, each gated (vitest + `pnpm build` read in-run) + own commit:
|
||||
- A: migration `033_equipment.sql` (`equipment`, `equipment_reservations`) mirrored in `schema.sql` (in-place seed fn + appended Section 20); `equipment.manage` perm (group Equipment) seeded+backfilled; types; DATABASE_SCHEMA/DB_SCHEMA_MAP. Additive default-deny RLS; reservations have SELECT (manage or own) + manager UPDATE, NO INSERT/DELETE (reserve/cancel via validated service-client action). No DB overlap constraint (no btree_gist dep) — overlap enforced in the action via pure logic.
|
||||
- B: pure `lib/equipment-logic.ts` (intervalsOverlap, hasConflict, reservationEligibility) + 9 tests (suite 391) + Zod.
|
||||
- C: `lib/actions/equipment.ts` (registry CRUD; listEquipmentForMembers w/ member_certified flag via service client; reserve/cancel validated service-client w/ status+overlap+required-cert, equipment.manage override + book-for-member; listEquipmentReservations; getMyReservations) + `lib/equipment-guard.ts` + barrel + API_REFERENCE.
|
||||
- D: `/equipment/manage` admin pages + sidebar Admin "Manage equipment".
|
||||
- E: `/equipment` member browse + reserve (cert gate shown up front) + sidebar member "Equipment".
|
||||
- F: "My equipment reservations" on `/me` + ARCHITECTURE + this entry.
|
||||
|
||||
Cert-gate (user-approved): reserving cert-gated equipment requires an active `member_certifications` for the member; an `equipment.manage` holder overrides and may book on a member's behalf. Cert check reads `member_certifications` via the service client (boolean only) since a non-cert-permissioned equipment manager can't read it under RLS — no write/PII bypass of the guarded surface.
|
||||
|
||||
### Open / not done
|
||||
- Equipment is LOCAL (6 commits). Awaiting deploy approval. After push: confirm `033` applied, board has `equipment.manage`, exercise add equipment (+ required cert) → member reserve (cert gate / overlap) → manager override → `/me`. NOT browser-verified.
|
||||
- Pure logic unit-tested; action orchestration (overlap/cert/override/RLS) NOT (same systemic no-mock-harness gap).
|
||||
- Roadmap remaining: module 4 Door epic (member_cards + configurable door integration + native HeatSync adapter + the universal API-call UI builder; largest/riskiest, design-first, do last). Cert/feature nav links for non-admin permission-holders still admin-block-only (known minor gap).
|
||||
|
||||
---
|
||||
|
||||
## 2026-05-17 (pass 22) — Classes module (2) code-complete LOCAL; roadmap reaffirmed
|
||||
|
||||
Branch `main`. Incident-INSERT RLS bug confirmed RESOLVED by the user (closed; see pass-21 note). User asked to continue the locked roadmap; chose Classes (module 2) next; reaffirmed the locked order (Certs done → Classes → Equipment → Door epic, which is where the "custom API-call UI builder" lives, module 4, design-first/last).
|
||||
|
||||
Reference in New Issue
Block a user