Fold the wahoo-route-update delta into openspec/specs/wahoo-route-push/spec.md (POST→PUT logic with 404 fallback, stable external_id, push-status UI) and move the change directory to openspec/changes/archive/. Task 4.3 (Playwright E2E) skipped — contract is fully covered by unit/integration tests in wahoo.test.ts and pushes.server.test.ts. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2.3 KiB
2.3 KiB
Why
When a user pushes a route to Wahoo, edits the route, and pushes again, today we POST a brand-new route to /v1/routes. Wahoo treats it as unrelated to the first push (it does not de-duplicate by external_id), so the user's Wahoo route library accumulates one entry per version. The user expects "edit and re-send" to update the route they already saved on Wahoo, not pile new copies on top.
What Changes
- When the Journal pushes a route version and a previous version of the same route was already successfully pushed to Wahoo, the Journal SHALL
PUT /v1/routes/:idagainst the previously storedremote_idinstead of posting a new route. - Change the
external_idsent to Wahoo from per-version (route:<routeId>:v<version>) to per-route (route:<routeId>). The version is still tracked locally for idempotency and "what's currently on Wahoo" display, butexternal_idshould identify the logical route. - Restructure
sync_pushessemantics so a single logical Wahoo route maps to one row per(user_id, route_id, provider)whoselast_pushed_versionandpushed_atreflect the latest successful push, instead of one row per(user_id, route_id, route_version, provider). - The "Already on Wahoo" UI now shows the version Wahoo currently has, with a "Send updated version" CTA when the local route is newer.
Capabilities
New Capabilities
Modified Capabilities
wahoo-route-push: push pipeline switches from POST-per-version to POST-then-PUT, idempotency key narrows from version-scoped to route-scoped, and theexternal_idformat changes.
Impact
- Code:
apps/journal/app/lib/sync/providers/wahoo.ts(add update path);apps/journal/app/lib/sync/pushes.server.ts(decide POST vs PUT based on existingsync_pushesrow);apps/journal/app/routes/api.sync.push.$provider.$routeId.ts(no change in surface, internals only);sync_pushestable schema (droproute_versionfrom the unique key, addlast_pushed_versioncolumn). - Data migration: existing
sync_pushesrows are per-version; we collapse them so the highest-versioned row per(user, route, provider)becomes the canonical row and lower-versioned rows are deleted. - No changes to authentication, scope set, or the Wahoo data URI / FIT capabilities work shipped in the cutover prep.