The route-surface-breakdown change is fully implemented (18/18 tasks, all artifacts done). Archive it via `openspec archive` (CLI 1.6.0): - Moves the change to openspec/changes/archive/2026-07-13-route-surface-breakdown/ - Promotes its 5 delta requirements into a new capability spec at openspec/specs/route-surface-breakdown/spec.md (surface/waytype breakdown from BRouter waytags, async Overpass backfill, live SSE update, proportion bars, localized labels) Purpose paragraph filled in (the CLI leaves a TBD placeholder). Both the spec and archived change pass `openspec validate --strict`. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2.8 KiB
2.8 KiB
Why
"How much of this is gravel?" is a top-three question for choosing a route, and
Komoot's surface/waytype bars are one of its most-used features.
@trails-cool/map-core already ships the surface/highway colour palettes, and
the Planner already computes accurate per-segment surface/highway from BRouter
(route-merge → EnrichedRoute.surfaces[]) — then discards it on save.
This change captures that data, shows it as proportion bars, and backfills
everything else (imports, uploads, older rows) asynchronously so the bars
aren't limited to Planner routes.
What Changes
- On route and activity detail, show surface and waytype proportion bars
(e.g. "62% asphalt · 28% gravel · 10% path"), coloured with the
map-coreSURFACE_COLORS/HIGHWAY_COLORSpalettes, with per-category km/percent. - Path 1 — synchronous (Planner routes): compute a distance-weighted surface + waytype distribution from the BRouter waytags at save time, send it in the planner→journal handoff, store it. Accurate, free, no external call.
- Path 2 — async backfill (everything else): for a route/activity that has geometry but no breakdown (imports, manual uploads, pre-existing rows), a background job map-matches the geometry to OSM ways via Overpass, computes the breakdown, stores it, and pushes an SSE event so an open detail page fills the bars in live.
- Degrade gracefully: no geometry / not-yet-backfilled → no bars (or a "computing…" state while a backfill is in flight).
Capabilities
New Capabilities
route-surface-breakdown: the surface/waytype proportion bars on route & activity detail — derived synchronously from BRouter waytags (Planner) or asynchronously via an Overpass backfill job with an SSE live-update.
Modified Capabilities
Impact
- Schema: nullable
surface_breakdownjsonb onjournal.routesandjournal.activities(additive —pnpm db:push). - Planner:
api.save-to-journalcomputes + sends the breakdown. - Journal:
- route callback stores the synchronous breakdown;
- a typed
surface-backfillpg-boss job (Overpass map-match → breakdown → store → SSE), enqueued after imports/uploads and available as a sweep; - a journal-side Overpass way/surface client (reusing the existing
/api/overpassproxy pattern); - an SSE
surface_breakdownevent + a detail-page subscription; - a
SurfaceBreakdowncomponent (reusesmap-corepalettes +stats.ts).
- i18n:
journal.surface.*(en + de). - Privacy: the backfill sends route geometry to Overpass — see design for the proxy/self-host + visibility considerations.