Files
rippr/docs/v3/V3-07-route-drawing.md
Dylan 342a8f8382 Break v3 into 16 tickets
One file per feature, in the v2 shape that worked: goal, context, design,
implementation, acceptance criteria, tests, risks, out of scope -- written before
implementing so the risks are on paper rather than walked into.

Three carry more weight than their size suggests. V3-01 ships the port's first
real migration, and since the destructive fallback is gone, getting addColumn and
a v1-database test right matters more than the feature. V3-08 forces a
routing-engine decision with ongoing cost, so it sits behind a RoutingService
interface mirroring what LocationSource did for GPS. V3-13 is not code at all --
it answers the three questions open since v2, and V3-15 may close unbuilt as a
result, which is a legitimate outcome.

Several tickets record constraints that are easy to lose: no activity picker in
front of Start, because the founding premise is press-and-go with gloves; the
Route-to-Trip foreign key must not cascade, or deleting an old plan deletes the
ride; V3-14 will deliberately break the parity harness by adding GPX <type>, and
that expectation should be updated rather than the check dropped; and V3-16 must
not regress the explicit text colours that exist because of the black-on-black bug.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-17 10:41:35 -05:00

2.4 KiB

V3-07 — Route drawing (pins and straight lines)

Phase Route planning · Depends on nothing · Size M · Status Not started

Goal

Drop pins on a map to sketch a route, see the straight-line distance, and save it. The foundation for V3-08, deliberately shipped without a routing engine.

Context

Pre-ride planning is a genuinely new mode, not an extension of recording. It needs no ride in progress, no server, and nothing else in v3 — the most independent thing in the backlog.

Split from road-snapped routing (V3-08) on purpose: pins, storage, editing and the map interaction are all needed either way, and none of them require choosing a routing vendor. That decision should not block a usable feature.

Design

New entities, separate from Trip. A plan is not a recording, and conflating them would put unridden kilometres into ride totals.

Route(id, name, createdAt, activity?, distanceM, estimatedMillis?, geometry?)
Waypoint(id, routeId, ordinal, latitude, longitude, name?)

geometry is null in this ticket; V3-08 fills it with the road-snapped polyline. ordinal rather than relying on insertion id, so waypoints can be reordered.

Straight-line distance reuses haversineMeters — already ported and parity-proven.

Implementation

  1. Drift tables + migration (the second one; V3-01 proves the path)
  2. RouteRepository mirroring TripRepository's shape
  3. RoutePlannerScreen — tap to add a pin, drag to move, tap a pin to delete, reorder
  4. Straight-line polyline between pins, visibly distinct from a recorded path
  5. Routes list, reachable from the record screen alongside Rides
  6. Name, rename, delete

Acceptance criteria

  • Pins can be added, moved, reordered and deleted
  • Distance updates live as pins change
  • A saved route survives an app restart
  • Routes never appear in the rides list, and never contribute to ride totals
  • Deleting a route cascades to its waypoints

Tests

  • Repository: create, reorder, delete, cascade — in-memory, like the trip tests
  • Distance matches pathLengthMeters over the same points
  • Widget: tapping the map adds a pin; the distance label updates
  • A test asserting routes are absent from watchCompletedTrips

Risks

The main one is scope drift into V3-08. Ship straight lines first; they are genuinely useful for a rough plan.

Out of scope

Road snapping, ETA, following a route while riding. Import of existing GPX routes.