Objective
- Fix dispatch map pins and drive-time forecasts so they reflect the actual inspection location when the address text shown in dispatch is already correct.
- Give schedulers and dispatch staff trustworthy travel context between inspections—wrong GPS coordinates lead to incorrect Mapbox routes, inflated or deflated drive times, and poor scheduling decisions.
- Prevent split-brain location data on inspections where the work order property looks correct but calendar/dispatch routing uses stale coordinates.
Background
- Reported example: Work order 1008598200 — the inspection address displays correctly in dispatch, but the map pin sits at incorrect GPS coordinates, producing a wrong drive-time forecast to/from neighboring jobs on that inspector's day.
- Dispatch loads calendar events and builds Mapbox driving routes from each stop's lat/lng (
attik-frontend/src/app/tools/dispatch/dispatchContext.tsx→cleanSearchCoords→callDirectionsServer). Drive time is computed from coordinates, not from the address string. - The calendar API mixes two fields on the same inspection document (
attik-backend/src/routes/calendar.ts): - Address label →
inspection.property.address(fallbackinspection.address) - Map pin / routing coords → top-level
inspection.lat/inspection.lng - Inspections store coordinates in two places (
attik-backend/src/models/inspectionSchema.ts): - Top-level
lat/lng— used by dispatch, calendar, reschedule preview - Nested
property.lat/property.lng— used by work order map, scheduler, pricing - On create, both are set together (
attik-backend/src/util/functions/inspection/createInspection.ts). On property edit from the work order, onlypropertyis PATCHed (attik-frontend/src/app/tools/inspections/[id]/components/PropertySectionWrapper.tsxsends{ property: propertyData }). Backend updatesproperty.lat/property.lngbut does not mirror to top-level unlesslat/lngare sent separately (attik-backend/src/routes/inspection.ts). - Diagnostic split: If the work order static map (uses
property.lat) looks correct but the dispatch pin is wrong → likely stale top-level coordinates after a property/address correction. If both are wrong → bad geocoding at creation or bad coords from import (ISN/Spectora).
Root cause hypothesis (code trace)
Primary: duplicate coordinate fields drift after property/address updates.
- User corrects address on work order →
property.lat/property.lngupdate with new geocode. - Top-level
inspection.lat/inspection.lngremain at original scheduling/import values. - Calendar aggregation projects
$inspection.lat/$inspection.lnginto dispatch events while address text comes fromproperty.address. - Mapbox route legs in
cleanSearchCoordsuse the stale top-level coords → wrong pin + wrong drive time despite correct address tooltip.
Secondary causes to rule out on example job:
- Bad geocoding at initial scheduler entry (Mapbox wrong match).
- ISN historical import using incorrect
latitude/longitudefrom source order (attik-backend/src/util/functions/isn/importIsnHistoricalOrder.tssets both levels the same at import—less likely unless address edited post-import). - Missing/zero coords (
lat/lng= 0) skipped in routing—usually omits pin rather than wrong location.
Scope
Backend (attik-backend)
src/routes/calendar.ts— calendar event projection uses top-levellat/lngonly; consider$ifNullfallback toproperty.lat/property.lngfor legacy/drifted records.src/routes/inspection.ts— whenproperty.lat/property.lng(or full property address) update, mirror coords (and optionallyaddress) to top-levelinspection.lat/inspection.lng/inspection.address.src/models/inspectionSchema.ts— document single source of truth or pre-save sync if appropriate.src/routes/schedule.ts— optimal-slots path also references$inspection.lat; verify parity after fix.- Optional one-time backfill for inspections where
property.lat/lng≠ top-levellat/lng(or property has coords and top-level is 0).
Frontend (attik-frontend)
src/app/tools/inspections/[id]/components/PropertySectionWrapper.tsx— property save sends onlyproperty; may also send top-levellat/lngas belt-and-suspenders until backend sync exists.src/app/tools/dispatch/dispatchContext.tsxandsrc/components/scheduling/dispatchScheduling/cleanSearchCoords.ts— verify routing uses corrected calendar payload (no client-side workaround needed if backend is fixed).src/components/scheduling/DispatchSection.tsx— scheduler dispatch section uses same calendar + directions pattern; confirm fix applies there too.src/app/tools/inspections/[id]/components/RescheduleJobModal.tsx— uses top-levelinspection.lat/lng; should benefit from backend sync.
Verification on example job
- For inspection 1008598200, compare top-level vs
propertylat/lng in DB/API before and after fix. - Confirm dispatch pin, Mapbox route, and drive-time blocks align with work order map for that job's scheduled day.
Out of scope (v1)
- Persisting/caching Mapbox directions legs globally (see ATT-819).
- Dispatch optimization / Mapbox cost layer (ATT-1821).
- Re-geocoding every inspection in bulk without drift detection.
Done when
- [ ] Dev confirms on 1008598200 (or repro case) whether top-level vs
propertycoords diverge. - [ ] Property/address updates keep top-level and property coordinates in sync going forward.
- [ ] Calendar/dispatch events use correct coords (fallback or synced source) so map pin matches address.
- [ ] Drive-time legs between inspections on the same day reflect actual travel distance for corrected jobs.
- [ ] Scheduler dispatch section and tools/dispatch page behave consistently.
- [ ] Optional backfill script or migration documented/run for existing drifted inspections.
- [ ] Test coverage for property PATCH updating both coordinate locations.
References
- Example work order: https://www.attik.ai/inspections/1008598200
- Related: ATT-819 (persist drive times), ATT-1048 (reschedule dispatch context)
attik-backend/src/routes/calendar.tsattik-backend/src/routes/inspection.tsattik-frontend/src/app/tools/dispatch/dispatchContext.tsxattik-frontend/src/components/scheduling/dispatchScheduling/cleanSearchCoords.ts