diff --git a/docs/BACKLOG.md b/docs/BACKLOG.md index 50993e7..19d1f1b 100644 --- a/docs/BACKLOG.md +++ b/docs/BACKLOG.md @@ -252,6 +252,14 @@ Split out from v3 deliberately. These three are **one programme, not three items needs a server, an identity system, and a privacy stance, and none of them is worth building alone. Nothing in v3 depends on any of them. +**A fourth item that doesn't fit that programme but shares its precondition:** +self-hosted road-snapped routing (v3's V3-08/V3-09, gated on +[V3-17](v3/V3-17-osrm-hosting.md)). It needs a server the same way this section's three +items do, but nothing about identity, privacy, or the group-ride use case — it's routing +infrastructure, not a rider-facing programme. Filed under `docs/v3/` for now since that's +where the tickets it unblocks already live; flagged here because "v3 is everything +buildable with no server" stops being strictly true the moment V3-17 is picked up. + ## Live group rides Invite someone to a ride and see both of you on the map, live. diff --git a/docs/v3/README.md b/docs/v3/README.md index 767a280..6590165 100644 --- a/docs/v3/README.md +++ b/docs/v3/README.md @@ -24,8 +24,8 @@ backup are v4 — see [../BACKLOG.md](../BACKLOG.md). | [V3-05](V3-05-mounted-mode.md) | Mounted (handlebar) mode | M | V3-04 | Done | | [V3-06](V3-06-notification-stats.md) | Live stats in the notification | S | — | Done | | [V3-07](V3-07-route-drawing.md) | Route drawing (pins, straight lines) | M | — | Done | -| [V3-08](V3-08-road-routing.md) | Road-snapped routing and ETA | L | V3-07, V3-01 | Not started | -| [V3-09](V3-09-route-following.md) | Follow a planned route | M | V3-04, V3-08 | Not started | +| [V3-08](V3-08-road-routing.md) | Road-snapped routing and ETA | L | V3-07, V3-01, **V3-17** | Deferred (needs V3-17) | +| [V3-09](V3-09-route-following.md) | Follow a planned route | M | V3-04, V3-08 | Deferred (needs V3-08) | | [V3-10](V3-10-trip-splitting.md) | Trip splitting | S | — | Done | | [V3-11](V3-11-offline-tiles.md) | Offline tile pre-download | M | V3-04 | Partially done (pipeline shipped; needs aeroplane-mode device verification) | | [V3-12](V3-12-crash-reporting.md) | Crash reporting | S | — | Partially done (code only; needs a real Sentry DSN + release build) | @@ -33,6 +33,7 @@ backup are v4 — see [../BACKLOG.md](../BACKLOG.md). | [V3-14](V3-14-gpx-interop.md) | GPX interoperability | S | V3-01 | Partially done (code only; needs real-device verification) | | [V3-15](V3-15-auto-pause.md) | Auto-pause | M | V3-13 *(gated)* | Not started | | [V3-16](V3-16-visual-identity.md) | Visual identity | M | V3-04, V3-05 | Partially done (token-level identity shipped; needs outdoor device verification) | +| [V3-17](V3-17-osrm-hosting.md) | Self-hosted OSRM: investigate and stand one up | M | — *(needs a server — see the ticket's own note on the v3/v4 boundary)* | Not started | ## Dependencies @@ -40,15 +41,20 @@ backup are v4 — see [../BACKLOG.md](../BACKLOG.md). V3-01 ──┬────────────► V3-08 ──► V3-09 └──► V3-14 ▲ V3-07 ──────► V3-08 │ +V3-17 ──────► V3-08 │ V3-02 ──► V3-03 │ V3-04 ──┬──► V3-05 ──┬───────┘ ├──► V3-11 └──► V3-16 └──► V3-09 V3-13 ──► V3-15 (gate: may close unbuilt) -no dependencies: V3-01 · V3-02 · V3-04 · V3-06 · V3-07 · V3-10 · V3-12 +no dependencies: V3-01 · V3-02 · V3-04 · V3-06 · V3-07 · V3-10 · V3-12 · V3-17 ``` +**V3-08/V3-09 are deferred, on request**, pending V3-17 (self-hosted OSRM). See V3-17's +own note on why that also puts them in tension with this document's v3/v4 boundary — +unresolved by design, not an oversight. + ## Three that carry more weight than their size suggests **V3-01** ships the port's **first real migration**. The destructive fallback is gone, so @@ -56,7 +62,9 @@ getting `addColumn` plus a v1-database test right matters more than the feature V3-07 and V3-09 both add migrations behind it. **V3-08** forces a routing-engine decision with ongoing cost and vendor implications. -Behind a `RoutingService` interface, mirroring what `LocationSource` did for GPS. +Behind a `RoutingService` interface, mirroring what `LocationSource` did for GPS. The +direction is decided (self-hosted OSRM); V3-17 does the actual standing-up, and V3-08 is +deferred until it exists. **V3-13** is not code. It answers the three questions that have been open since v2, and **V3-15 may close unbuilt** as a result — a legitimate and probably likely outcome. diff --git a/docs/v3/V3-08-road-routing.md b/docs/v3/V3-08-road-routing.md index 13e04ef..29685bb 100644 --- a/docs/v3/V3-08-road-routing.md +++ b/docs/v3/V3-08-road-routing.md @@ -1,6 +1,7 @@ # V3-08 — Road-snapped routing and ETA -**Phase** Route planning · **Depends on** V3-07, benefits from V3-01 · **Size** L · **Status** Not started +**Phase** Route planning · **Depends on** V3-07, benefits from V3-01, **blocked on V3-17** +· **Size** L · **Status** Deferred ## Goal Resolve the actual shortest path along roads between pins, and estimate how long the ride @@ -11,6 +12,12 @@ This is what Dylan asked for. It is also the ticket with a **decision that canno deferred**: road-snapped routing needs a routing engine over OpenStreetMap data, and the choice has ongoing consequences. +**Decided, not deferred:** self-hosted OSRM (see the table below). What's actually +deferred is standing one up — that's [V3-17](V3-17-osrm-hosting.md), split out on +request because provisioning a server is a different kind of work from building the app +code that calls it, and this ticket cannot start until V3-17 has something to point +`RoutingService` at. + ## Design ### Choosing an engine — decide before writing code diff --git a/docs/v3/V3-09-route-following.md b/docs/v3/V3-09-route-following.md index cc50459..f7f6d63 100644 --- a/docs/v3/V3-09-route-following.md +++ b/docs/v3/V3-09-route-following.md @@ -1,6 +1,6 @@ # V3-09 — Follow a planned route while riding -**Phase** Route planning · **Depends on** V3-04, V3-08 · **Size** M · **Status** Not started +**Phase** Route planning · **Depends on** V3-04, V3-08 (itself blocked on V3-17) · **Size** M · **Status** Deferred ## Goal Pick a saved route before starting, see it on the live map underneath your actual track, diff --git a/docs/v3/V3-17-osrm-hosting.md b/docs/v3/V3-17-osrm-hosting.md new file mode 100644 index 0000000..1eb7f8a --- /dev/null +++ b/docs/v3/V3-17-osrm-hosting.md @@ -0,0 +1,88 @@ +# V3-17 — Self-hosted OSRM: investigate and stand one up + +**Phase** Infrastructure · **Depends on** nothing · **Size** M · **Blocks** V3-08, V3-09 · +**Status** Not started + +## Goal +Get a self-hosted OSRM instance running somewhere, so V3-08 (road-snapped routing and +ETA) has a real backend to build against instead of a deferred decision. + +## Context +V3-08 named the choice of routing engine as "a decision that cannot be deferred," and +[the conversation that spawned this ticket](../v3/README.md) picked a direction without +picking a provider: **self-hosted OSRM**, over a hosted API (GraphHopper, Mapbox +Directions) or the public OSRM demo (explicitly not for production use). + +**This ticket exists because that decision itself has a wrinkle worth naming up front:** +this whole v3 backlog's organizing principle, stated in `docs/BACKLOG.md`, is *"v3 is +everything that can be built with no server. v4 is everything that cannot."* A +self-hosted OSRM instance is a server. Strictly, that makes V3-08 and V3-09 — anything +that depends on this ticket — v4 work by the project's own definition, not v3, even +though they're filed under `docs/v3/` today and the routing itself has nothing to do +with the group-rides/accounts/backup programme that currently defines v4. Whether to +formally renumber them is a documentation decision for whoever picks this up next; this +ticket does not resolve it, only flags it so it isn't silently glossed over. + +## Design +Two separable questions: + +1. **Where does it run?** A small VPS (the same shape of box that would eventually host + the v4 group-ride server, so this could double as an early step toward that) versus + something serverless/managed. OSRM's own Docker image is the standard path either way. +2. **What data does it need?** A regional OSM extract, not the planet — start with + whatever region actually gets ridden (per `docs/LAUNCH.md`, this is presently a + friends-and-family app, so the region is small and known). [Geofabrik](https://download.geofabrik.de/) + publishes regional `.osm.pbf` extracts sized for exactly this. + +Profiles matter for this app specifically (see V3-08's Design section): a motorcycle +route and a bicycle route between the same two pins should genuinely differ. OSRM ships +car/bike/foot profiles out of the box; a motorcycle profile is closer to car (mostly +avoids the walk-only restrictions bike profiles impose) but might want the twisty-road +preference a stock car profile doesn't have reason to express. Confirming that is part of +this ticket's investigation, not something to guess at now. + +## Implementation +1. Pick and provision a host (see Design's first question) +2. Download and preprocess a regional extract with OSRM's own toolchain + (`osrm-extract` → `osrm-partition` → `osrm-customize`, or the older + `osrm-contract` pipeline depending on the OSRM version chosen) +3. Run `osrm-routed` behind whatever the host offers for TLS termination — the app will + be calling this over the public internet from riders' phones, so plain HTTP is not + an option +4. Confirm at least a car-equivalent and a bike profile both return sane routes for a + handful of real local pin pairs, by hand, before writing any app code against it +5. Write the resulting base URL and auth (if any) down for V3-08 to consume — as + configuration, never a hardcoded value, matching V3-08's own "no API key committed to + the repository" acceptance criterion, which applies here too even though there's no + third-party vendor to protect a key from — an open, unauthenticated routing endpoint + is still worth not publishing in a public repo +6. A basic uptime check of some kind — this becomes a real dependency the app relies on, + not a fire-and-forget script + +## Acceptance criteria +- [ ] An OSRM instance is reachable over HTTPS from outside the host network +- [ ] Returns a road-following route for a real pin pair in the region actually ridden +- [ ] At least two distinct profiles (car-equivalent, bike) both work +- [ ] The endpoint and any credentials live in configuration, not source +- [ ] Documented: what's running, where, how to update the extract when it goes stale, + and what it costs (if anything) to keep running + +## Tests +Infrastructure, not app code — no `flutter test` coverage belongs to this ticket +directly. V3-08's own `FakeRoutingService`-driven tests are what verify the app's +behavior; this ticket's job is only to make the real thing exist for that fake to stand +in for. + +## Risks +- **Ongoing hosting cost and maintenance**, however small — this is the first piece of + always-on infrastructure this project has taken on. Worth being honest that "no + server" stopped being true the moment this ticket is picked up, regardless of which + numbering bucket it ends up filed under. +- **OSM extracts go stale.** A road that didn't exist at extract time won't route. + Needs a refresh cadence, not a one-time setup. +- Regional extracts are cheap; do not reach for a planet-wide extract preemptively. + +## Out of scope +Actually building V3-08/V3-09 against this once it exists — that's their ticket, not +this one. Turn-by-turn navigation, traffic-aware routing, anything beyond what stock OSRM +gives you.