Adds the core route engine for Mobile Groomer Route Optimization:
- src/services/routeOptimization.ts — order a day's geocoded stops via
Google Directions (optimizeWaypoints:true) when a Maps API key is
configured, else an offline nearest-neighbor TSP heuristic over
great-circle distance. Handles the >25-stop edge case by chunking into
sub-routes (Directions waypoint cap) with a user warning, degrades to
the heuristic if Google errors mid-run, and resolves the API key from
businessSettings.googleMapsApiKey (decrypted) / GOOGLE_MAPS_API_KEY.
- src/routes/routes.ts — GET /api/routes/daily (fetch/create draft route
+ enriched stops) and POST /api/routes/optimize (generate/re-optimize,
persist stopOrder + travelMinsFromPrev + travelDistanceKmFromPrev and
route totals/optimizedAt in one transaction). Auth: manager (any) or
groomer (own route only); receptionists denied. Un-geocoded
appointments are skipped and surfaced.
- src/index.ts — mount /api/routes under requireRole("manager","groomer").
- Unit tests for haversine, leg estimation, nearest-neighbor ordering,
the Google path (mocked fetch), chunking, and fallback.
- UAT_PLAYBOOK.md §4.16 — new Route Optimization test cases.
Co-Authored-By: Paperclip <noreply@paperclip.ing>