feat(tours): the paddle checklist through the offline core on the client

PAD-06 and PAD-09 on the client's data side. A tour's cached row keeps its
checklist beside its provenance, written through one cache helper by the
repository and the queue replay, which also keeps provenance an answer
lacks. The checklist is read for the bench the list shows and served from
the cache while its revision matches. Decisions made offline, or behind a
queued write of the same tour, change the cached checklist and bench at
once under a local revision and replay with their idempotency key; a route
written offline marks the checklist stale until the server judged it.

The obstacle store learns a camera focus: a click in the rail moves the
camera onto an obstacle and the other parts of its lock, the newest of such
a focus and a picked search result wins, and a selected lock lights up
whole on both maps. The checklist hook and its model hold the logic the
cards will show.
This commit is contained in:
Maurice
2026-10-17 00:29:26 +00:00
parent fa8272c522
commit 7fffd4300f
23 changed files with 1389 additions and 57 deletions
+2 -1
View File
@@ -6,6 +6,7 @@
* online trigger → flush() → replay REST with X-Idempotency-Key header → update Dexie
*/
import { offlineDb, MUTATION_SCHEMA_VERSION } from '../db/offlineDb'
import { cacheTourAnswer } from '../db/cacheTour'
import { apiClient } from '../api/client'
import { isAuthed } from './authGate'
import { isEffectivelyOffline } from './networkMode'
@@ -428,7 +429,7 @@ async function reconcileTour(mutation: QueuedMutation, saved: TourCreateResponse
await offlineDb.tours.delete(mutation.tempId)
if (temp && !(await offlineDb.places.get(realId))) await offlineDb.places.put({ ...temp, id: realId })
}
await offlineDb.tours.put({ ...saved.tour, trip_id: mutation.tripId, waypoints: saved.waypoints })
await cacheTourAnswer(mutation.tripId, saved)
})
await remapTempId(mutation, realId, idMap)
}