feat(GRO-2225): seed deterministic route-opt cohort + UAT receptionist credential
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:
+6
-1
@@ -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 |
|
||||
|---|----------|-------|----------|
|
||||
|
||||
Reference in New Issue
Block a user