# 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.