Files
samplez/rippr-src/docs/v1
uhryniuk 247b9cdb3f Refresh Rippr snapshot and bundle with full project documentation
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>
2026-08-11 08:44:48 -05:00
..

v1 — the original recorder

v1 was specified as MotoTrack, a "bare-bones, highly resilient" recorder to capture GPS telemetry during motorcycle group rides. Renamed to Rippr partway through.

The original brief is preserved verbatim in original-spec.md.

Design priority, quoted from the brief: "Unbreakable execution over UI beauty." That framing drove every architectural choice and still holds.

What shipped

A single-screen app with an un-killable foreground service writing GPS fixes to Room, plus a REST uploader. Validated on a real ride — including max speed, which the emulator cannot produce.

Deviations from the spec, and why

The spec was written as complete, paste-ready code. Most of it was sound; these parts were not, and were changed deliberately.

Spec said What shipped Why
super.onCreate() in MainActivity super.onCreate(savedInstanceState) Would not compile
kapt for Room KSP kapt is 2–3× slower and unreliable on modern Kotlin/JDK
Hardcoded material3:1.2.1 beside a Compose BOM Version catalog + BOM Version conflict
insertPoint() per fix from the callback Unbounded Channel + batched writer A coroutine per fix gives no back-pressure guarantee; disk latency could block GPS
Activity-local isRecording Process-wide state (later, in v2, the database) Lied after process death
1 Hz polling of two suspend DAO queries Room Flow Push, not poll
No stop action on the notification Stop action + tap-to-open
Nothing countering Doze / OEM killers Battery-optimisation exemption prompt A multi-hour ride must survive
No Theme.MotoTrack, no launcher icon Generated both Referenced by the manifest but never defined
"Streams over HTTP/REST" in the goal, no task for it Full uploader: synced column, batched POST, retry, offline-safe Stated as a goal, so it was built

Verification

The emulator harness built here was reused throughout v2:

  • Merged manifest checked inside the APK — foregroundServiceType=0x8 (location) confirmed
  • 25 synthetic GPS fixes fed; final stored coordinate matched the fed value exactly
  • Foreground service confirmed via dumpsys (isForeground=true, ongoing notification)
  • Stop path verified: service gone, notification removed, final flush landed, 81 contiguous point ids

Speed was never verified in v1's automated testing — the emulator reports zero velocity. It was confirmed only on Dylan's first real ride.

What v1 lacked

Feedback after that ride, which became the v2 brief:

"app is simple and clean. I like that but it's missing stuff. There is no reset or pause button, there is no concept of a trip, it captures speed data but not path data."

Three of those four were the same missing concept — no Trip boundary. The fourth was a misconception worth recording: path data was already being captured. Every point stored latitude, longitude, altitude and bearing at 1–2 Hz from day one. What was missing was a map to draw it on.

Icon work

The launcher icon was designed in this phase. Five motorcycle-themed concepts were generated locally as SVG, using Google Material Symbols (Apache-2.0) as reference geometry; Dylan picked Route — a switchback trace inside a ring.

Lesson from that round: the first attempt hand-authored bezier paths without ever rendering them, and they were poor. Building a rasterise-and-look loop (rsvg-convert) changed the output quality completely. Generators live in design/.