# 11 — Route & Sales Visit Management **Status**: Not Started **Depends On**: 00 — Existing Gap Fixes --- ## Goal Route CRUD already exists (`Features/Route`). This step covers the sales-visit half of [mainPlan.md §3](./mainPlan.md#3-route-management) — the part that is about a SalesRep's daily visit schedule, not the ride/dispatch route from [03_ride_lifecycle.md](./03_ride_lifecycle.md)'s `planDeliveryRoute`. --- ## Background / Context Today a `Store` has a single `FK_RouteId` (bulk-assign not yet supported via API — see gap #2 in [00_existing_gaps.md](./00_existing_gaps.md)), and route access is only granted via `UserRouteScope` (a many-to-many grant), not single ownership. There is no visit check-in/out data anywhere. --- ## Data Model Changes ### Route Ownership `RouteId`, `OwnerUserId` — single-owner assignment, distinct from the broader `UserRouteScope` access grant which may cover multiple users (e.g. a Supervisor overseeing several reps' routes). ### Route Visit Log `RouteId`, `StoreId`, `UserId`, `CheckInAt`, `CheckInGps`, `CheckOutAt` — one row per planned visit. --- ## API Endpoints | Function reference | Endpoint intent | |---|---| | `assignOutletsToRoute(routeId, outletIds[])` | `POST /api/routes/{id}/stores` — bulk version of the existing single `Store.RouteId` field | | `assignRouteToSalesRep(routeId, salesRepId)` | `PUT /api/routes/{id}/owner` | | `optimizeRouteSequence(routeId)` | `POST /api/routes/{id}/optimize` | | `recordRouteCheckIn(routeId, outletId, gpsCoords, timestamp)` | `POST /api/routes/{id}/visits/check-in` | | `recordRouteCheckOut(routeId, outletId, timestamp)` | `POST /api/routes/{id}/visits/check-out` | | `getRouteAdherence(routeId, date)` | `GET /api/routes/{id}/adherence?date=...` | | `reassignRoute(routeId, newSalesRepId)` | `PUT /api/routes/{id}/owner` (same as assign, different actor) | | `getRoutePerformance(routeId, period)` | `GET /api/routes/{id}/performance?period=...` | --- ## Business Rules - Check-in `gpsCoords` feeds `sendRouteDeviationAlert` in [09_fraud_controls.md](./09_fraud_controls.md) — a check-in materially outside the store's registered location should flag, not silently accept. - `getStoreVisitHistory` (§4) reads directly from `Route Visit Log` — no separate storage. --- ## Open Questions - Is route sequence optimization (`optimizeRouteSequence`) a manual reorder endpoint, or does it need actual distance/priority-based computation (external mapping API)? --- ## Implementation Notes > Fill this section in during planning discussion before writing any code.