feat(GRO-2225): seed deterministic route-opt cohort + UAT receptionist credential
CI / Test (pull_request) Successful in 25s
CI / Lint & Typecheck (pull_request) Successful in 29s
CI / Build & Push Docker Images (pull_request) Successful in 1m1s

UAT seed reproducibility fix for route optimization (§4.16). No live geocoder
(UAT has no Google Maps key; provider is nearest_neighbor) — coordinates are
hand-picked Seattle-metro fixtures.

- seedUatRouteCohort(): 12 fixed-id clients/pets/appointments for uat-groomer on
  fixed date 2026-09-15. 10 pre-geocoded (multi-stop optimized route) + 2
  intentionally un-geocoded (skip-and-surface path, TC-API-16.4). Idempotent:
  clients/pets/appointments upserted by deterministic UUID; skips cleanly when
  uat-groomer is absent (prod/demo).
- UAT receptionist: standing `uat-receptionist@groombook.dev` staff record
  (role=receptionist) + Better-Auth credential from SEED_UAT_RECEPTIONIST_PASSWORD,
  so the route 403 path (TC-API-16.9) is reproducible without a hand-built session.
- UAT_PLAYBOOK §4.16: replace manual-PATCH/geocoding pre-condition with the
  seeded cohort + receptionist.

The SEED_UAT_RECEPTIONIST_PASSWORD secret/env wiring in groombook/infra is a
separate change; the seed degrades gracefully (warn + skip) without it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Flea Flicker
2026-06-08 23:13:27 +00:00
parent aabedc8152
commit 7f3c048cbf
2 changed files with 216 additions and 1 deletions
+6 -1
View File
@@ -363,7 +363,12 @@ This means:
### 4.16 Route Optimization — Route CRUD + Optimize (GRO-2155, Phase 2.1)
A groomer's daily route is one row per `(staffId, routeDate)` in `groomer_routes`, with ordered `route_stops`. `POST /api/routes/optimize` pulls the day's non-cancelled appointments whose client is geocoded (GRO-2154), orders them (Google Directions `optimizeWaypoints` when a key is configured in `businessSettings.googleMapsApiKey`, else an offline nearest-neighbor heuristic), and persists `stopOrder`, `travelMinsFromPrev`, `travelDistanceKmFromPrev` plus route `totalTravelMins`/`totalDistanceKm`/`optimizedAt`. **Auth: manager (any groomer's route) or groomer (own route only); receptionists have no access.** Pre-condition: at least one geocoded client with appointments on the target date for the staff member (use §4.2 geocoding + a seed groomer).
A groomer's daily route is one row per `(staffId, routeDate)` in `groomer_routes`, with ordered `route_stops`. `POST /api/routes/optimize` pulls the day's non-cancelled appointments whose client is geocoded (GRO-2154), orders them (Google Directions `optimizeWaypoints` when a key is configured in `businessSettings.googleMapsApiKey`, else an offline nearest-neighbor heuristic), and persists `stopOrder`, `travelMinsFromPrev`, `travelDistanceKmFromPrev` plus route `totalTravelMins`/`totalDistanceKm`/`optimizedAt`. **Auth: manager (any groomer's route) or groomer (own route only); receptionists have no access.**
**Pre-condition (GRO-2225 — zero-touch; no manual PATCH/geocoding needed).** A fresh UAT reset+seed now provisions a deterministic route cohort, so §4.16 runs directly against seed data:
- **Groomer:** `uat-groomer@groombook.dev` (staffId `00000000-0000-0000-0000-000000000004`). Resolve its id via `GET /api/staff` or sign in as the groomer and omit `staffId`.
- **Date:** `2026-09-15` (fixed). On this date the groomer has **12** confirmed appointments: **10 pre-geocoded** clients clustered in the Seattle metro (multi-stop route) + **2 intentionally un-geocoded** clients (exercise the skip-and-surface path, TC-API-16.4). Cohort clients are named `Route Demo — …` (emails `route-client-NN@uat.groombook.dev`).
- **Receptionist (TC-API-16.9 403):** sign in as `uat-receptionist@groombook.dev` (password from the `seed-uat-passwords` secret, key `SEED_UAT_RECEPTIONIST_PASSWORD`) — a standing receptionist login; no hand-built session required.
| # | Scenario | Steps | Expected |
|---|----------|-------|----------|