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>
This commit is contained in:
50
docs/v3/V3-03-units.md
Normal file
50
docs/v3/V3-03-units.md
Normal file
@@ -0,0 +1,50 @@
|
||||
# V3-03 — Distance and speed units
|
||||
|
||||
**Phase** Foundations · **Depends on** V3-02 · **Size** S · **Status** Not started
|
||||
|
||||
## Goal
|
||||
Imperial as well as metric, chosen once and applied everywhere.
|
||||
|
||||
## Context
|
||||
Everything is hardcoded metric: `formatDistance` switches m/km at 1000, `formatSpeed`
|
||||
prints km/h, elevation prints metres. Fine in Canada, useless to anyone in the US or UK.
|
||||
|
||||
Cheap, and the kind of thing that makes an app feel unfinished when missing.
|
||||
|
||||
## Design
|
||||
A `UnitSystem` enum (`metric`, `imperial`) in `Config`, defaulting from the device locale
|
||||
on first launch.
|
||||
|
||||
**Conversion belongs in formatting only.** Storage stays SI — metres, km/h, metres of
|
||||
altitude — forever. Converting at the storage layer would corrupt every existing ride and
|
||||
break the parity harness.
|
||||
|
||||
| Value | Metric | Imperial |
|
||||
|---|---|---|
|
||||
| Distance | m / km | ft / mi |
|
||||
| Speed | km/h | mph |
|
||||
| Elevation | m | ft |
|
||||
|
||||
## Implementation
|
||||
1. `UnitSystem` in `Config`; default from `Platform.localeName`
|
||||
2. Extend `ui/format.dart` — every formatter takes the unit system
|
||||
3. Thread it through: record screen, trips list, trip detail, charts, map legend
|
||||
4. Exports stay SI regardless. GPX is metres by specification; changing that breaks
|
||||
consumers.
|
||||
|
||||
## Acceptance criteria
|
||||
- [ ] Switching units updates every screen immediately
|
||||
- [ ] Stored values are unchanged — verified by exporting before and after
|
||||
- [ ] GPX/GeoJSON output is byte-identical across the two settings
|
||||
- [ ] First launch picks a sensible default from the locale
|
||||
|
||||
## Tests
|
||||
- Formatter tests for both systems, including the m→km and ft→mi boundaries
|
||||
- **A test asserting export output does not change with the unit setting**
|
||||
- Widget test toggling units and checking a rendered label
|
||||
|
||||
## Risks
|
||||
The obvious trap is converting too deep in the stack. Guard it with the export test.
|
||||
|
||||
## Out of scope
|
||||
Temperature, pace (min/km) — pace is arguably right for running, revisit after V3-01.
|
||||
Reference in New Issue
Block a user