Re-exported at 46a0726, which adds README.md plus docs/ARCHITECTURE, DEVELOPMENT, TESTING, v1 history including the original brief, and a v3 backlog. 112 files, and the bundle now carries 19 commits. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
132 lines
6.4 KiB
Markdown
132 lines
6.4 KiB
Markdown
# v3 backlog
|
|
|
|
Everything known-outstanding as of v2.0.1, with enough context to pick up cold.
|
|
Nothing here is committed to — it is a menu, roughly ordered by value.
|
|
|
|
**Before planning anything: run the real-ride checklist in
|
|
[../TESTING.md](../TESTING.md).** Several items below may turn out to be non-issues, and
|
|
others may appear that nobody has thought of.
|
|
|
|
---
|
|
|
|
## 1. Carried over from v2 — the honest debt
|
|
|
|
### Elevation gain accuracy · *needs real data first*
|
|
|
|
~30 m of phantom gain per ten stationary minutes against synthetic ±8 m uniform noise. Real
|
|
GPS altitude error is *correlated* rather than uniform, so the true behaviour is unknown.
|
|
|
|
The current implementation is a 15-sample moving average plus reversal hysteresis (see
|
|
[../ARCHITECTURE.md](../ARCHITECTURE.md)). A naive version reported 1498 m over a parked
|
|
bike, so the guard rails matter.
|
|
|
|
**Do not tune this blind.** Record a flat ride, check whether the reported gain is
|
|
plausible, and only then adjust. If it needs work, options are a longer smoothing window, a
|
|
larger threshold, or using barometric pressure where available (much more accurate than GPS
|
|
altitude, and most phones have the sensor).
|
|
|
|
### Compose UI tests · *the largest coverage gap*
|
|
|
|
Zero UI tests across six screens. Everything was verified by manual screenshot. Worth
|
|
covering: navigation record→trips→detail→back, rotation/state retention, empty states,
|
|
`NotFound`, chart degradation below two points, selection mode enabling Merge only at two.
|
|
|
|
### Unmeasured, and probably should be
|
|
|
|
- **Battery drain** over a multi-hour ride — never measured, and it is the thing most likely
|
|
to make the app unusable in practice
|
|
- **Map memory across repeated navigation** — the osmdroid lifecycle is a known hazard and
|
|
the wiring was never leak-tested
|
|
- **GPX import into Strava/Garmin** — validated against an XML parser, but schema validity
|
|
does not guarantee a consumer accepts it
|
|
|
|
---
|
|
|
|
## 2. The original v3 candidate — live group ride view
|
|
|
|
Deferred from v2 as "needs real server work". This was in the **v1** brief's goal
|
|
statement, so it has been the intended destination all along.
|
|
|
|
Already in place:
|
|
- `TelemetryUploader` — batched POST, retry, offline-safe, cannot stall recording
|
|
- `synced` column and backlog semantics
|
|
- `trip_id` / `segment_id` per point, so a server can reconstruct rides and pauses
|
|
- `Config.deviceId` — stable per-install id to distinguish riders
|
|
|
|
Missing:
|
|
- **A server.** Nothing exists. This is the actual work.
|
|
- **UI for the endpoint** — currently only reachable via `Config.setUploadEndpoint()`
|
|
- Other riders' positions on a map, and a live map at all (see below)
|
|
- Auth, rider identity, group membership
|
|
|
|
**Worth deciding early:** this is the point where Rippr stops being a local-only app. That
|
|
brings hosting, privacy, and location-sharing consent into scope.
|
|
|
|
---
|
|
|
|
## 3. Live map — explicitly deferred, revisit deliberately
|
|
|
|
v2 has **no live map by design**, on Dylan's reasoning:
|
|
|
|
> "we hit start, put the phone in our pocket and then stop it after the ride. So having a
|
|
> live map doesn't make sense at all honestly, we just wanna see the path render after."
|
|
|
|
`TrackingService` holds no reference to any map type, and the map exists only inside the
|
|
detail screen's Compose lifecycle. That boundary is deliberate and worth preserving unless
|
|
there is a real reason to cross it.
|
|
|
|
**Group riding is the one plausible reason** — seeing where the others are while stopped at
|
|
a junction. If it happens, keep it screen-on-only and never let the service touch it.
|
|
|
|
---
|
|
|
|
## 4. Smaller items
|
|
|
|
| Item | Notes |
|
|
|---|---|
|
|
| **Trip splitting** | Merge exists; split does not. The natural counterpart. |
|
|
| **SAF export** | Dropped in T16 as unnecessary — share sheet covers it. Add if a real need appears. |
|
|
| **Auto-pause** | Detect a stop and pause automatically. Rejected in v2 as unreliable in traffic; revisit only with real ride data showing it would help. |
|
|
| **Distance units** | Metric only, hardcoded. Trivial to add a preference. |
|
|
| **Settings screen** | None exists. `Config` has endpoint, deviceId, mapEnabled — the map toggle currently lives on trip detail because one switch did not justify a screen. |
|
|
| **Offline tile pre-download** | osmdroid caches what it renders; a mountain ride with no signal shows blank tiles. Respect OSM's usage policy — no bulk prefetch of their public servers. |
|
|
| **Notification live stats** | Show distance/duration in the ongoing notification, readable without unlocking. |
|
|
| **Crash reporting** | None. A recorder that dies mid-ride currently leaves no trace beyond logcat. |
|
|
|
|
---
|
|
|
|
## 5. Things that must not regress
|
|
|
|
Hard-won and easy to undo by accident. Each has a comment in the code explaining why.
|
|
|
|
1. **The unbounded `Channel` + single batched writer.** Do not write to the database from
|
|
the location callback.
|
|
2. **Points stamped with `tripId`/`segmentId` at creation.** Refactoring this into a
|
|
write-time lookup breaks the pause guarantee silently.
|
|
3. **Recording state derived from the database.** Never reintroduce an in-memory flag.
|
|
4. **`fallbackToDestructiveMigration()` stays removed.** Any schema change ships a
|
|
`Migration` against `app/schemas/com.rippr.data.AppDatabase/2.json`.
|
|
5. **Decimation is render-only.** It must never reach storage or export.
|
|
6. **`RipprTheme`'s `Surface`.** It sets `LocalContentColor`; without it, text without an
|
|
explicit colour renders black-on-black and disappears.
|
|
7. **The map zoom clamp.** `zoomToBoundingBox` ignores `maxZoomLevel`; a short ride will
|
|
render an empty grid without it.
|
|
8. **Instrumented tests use in-memory databases.** One previously wiped the real device
|
|
database in `setUp`.
|
|
|
|
---
|
|
|
|
## 6. Reading order for picking this up cold
|
|
|
|
1. [../../README.md](../../README.md) — what the app is and its current state
|
|
2. [../ARCHITECTURE.md](../ARCHITECTURE.md) — why it is built this way
|
|
3. [../v2/PROGRESS.md](../v2/PROGRESS.md) — every bug found during v2 and how
|
|
4. [../TESTING.md](../TESTING.md) — **especially "What the emulator cannot verify"**
|
|
5. [../DEVELOPMENT.md](../DEVELOPMENT.md) — when you actually need to build something
|
|
|
|
The v2 planning approach worked well and is worth repeating: one document per task with
|
|
goal, context, design, acceptance criteria and risks, written *before* implementing, plus a
|
|
running progress log recording what actually went wrong. Several bugs were caught precisely
|
|
because the risk had been written down first — and one (the osmdroid lifecycle) was written
|
|
down and then walked into anyway, which is its own lesson.
|