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.8 KiB
2.8 KiB
1. Schema migration
- 1.1 Add
last_pushed_version(integer, nullable) tosync_pushesin the Drizzle schema. - 1.2 Write a Drizzle migration that backfills
last_pushed_versionfromroute_versionfor every existing row. - 1.3 Extend the migration to collapse rows: per
(user_id, route_id, provider)group, keep the row with the highestroute_versionand delete the rest. If the highest-versioned row failed, keep it (it's still the canonical one under the new key). - 1.4 Drop the unique constraint that includes
route_version; add a unique index on(user_id, route_id, provider). - 1.5 Drop the
route_versioncolumn. - 1.6 Run the migration locally against a copy of prod data (or a synthesized dataset that has multiple versions) and verify counts.
2. Provider plumbing
- 2.1 Extend
wahooProvider.pushRoute(or add a siblingupdateRoute) so the wahoo provider exposes a way to PUT against an existing remote id; share the body construction with the POST path. - 2.2 Treat a 404 response from PUT as a signal to fall back to POST and return the new
remote_idto the caller. - 2.3 Update the wahoo provider's unit tests: a successful PUT, a 404 PUT that falls back to a successful POST, and the existing POST/error matrix.
3. Push pipeline
- 3.1 In
pushes.server.ts, look upsync_pushesby(user_id, route_id, provider)instead of(…, route_version, …). - 3.2 If the row has a non-null
remote_id, call the provider's update path; otherwise call the create path. - 3.3 On success, upsert the row with
last_pushed_versionset to the just-pushed local version,pushed_at = now(),error = null. - 3.4 Change
external_idconstruction toroute:<route_id>(drop the:v<version>suffix). - 3.5 Update existing pushes.server tests to assert PUT is used on the second push and that exactly one row exists afterwards.
4. UI
- 4.1 Update the route detail page status block to compare
last_pushed_versionwith the local route's current version and render the three states (matches, local newer, failed). - 4.2 i18n: add "On Wahoo (v{{n}}) — local version is newer" and "Send updated version" strings (en + de).
- [~] 4.3 E2E test: connect Wahoo (mocked), push v1, edit the route to v2, push again, assert the request was a PUT to the same remote id and the UI returns to "Sent to Wahoo on ". _(Skipped — contract is fully covered by
wahoo.test.ts(PUT to/v1/routes/:id, same remote id, 204 fallback) andpushes.server.test.ts(PUT on advance, PUT→POST 404 fallback). The remaining E2E gap is purely UI re-render, not worth a fake Wahoo HTTP server + OAuth dance.)
5. Spec & docs
- 5.1 Verify
openspec validate wahoo-route-updatepasses. - 5.2 After merge, run
/opsx:archiveto fold the delta intoopenspec/specs/wahoo-route-push/spec.md.