Files
samplez/rippr-src/docs/v1/original-spec.md
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

92 lines
4.0 KiB
Markdown

# Original v1 brief (verbatim)
Preserved as written, before any of it was implemented or corrected. See
[README.md](README.md) for which parts were changed and why — several would not have
compiled or would have dropped GPS fixes under load.
The project was called **MotoTrack** at this point, with package `com.example.mototrack`.
Both were renamed to Rippr / `com.rippr` during development.
---
## Project Specification: MotoTrack Single-Session Android Recorder
**Goal:** Build a bare-bones, highly resilient Native Android app (Kotlin) to record GPS
telemetry during motorcycle group rides today.
**Design Priority:** Unbreakable execution over UI beauty. Must run as an un-killable
**Foreground Service** that records telemetry to a local SQLite database and streams
updates over HTTP/REST when online.
### 1. Setup & Installation
Prerequisites: Android Studio (Koala/Ladybug+), a physical Android phone on 8.0+ (API 26+)
with USB debugging on, and a cable.
Project setup: New Project → Empty Activity (Jetpack Compose); Name `MotoTrack`; package
`com.example.mototrack`; Minimum SDK API 26; Kotlin.
Dependencies specified:
```kotlin
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
id("kotlin-kapt")
}
dependencies {
implementation("com.google.android.gms:play-services-location:21.2.0")
val roomVersion = "2.6.1"
implementation("androidx.room:room-runtime:$roomVersion")
implementation("androidx.room:room-ktx:$roomVersion")
kapt("androidx.room:room-compiler:$roomVersion")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.0")
implementation("androidx.compose.material3:material3:1.2.1")
}
```
### 2. Task breakdown
**Task 1 — Manifest & permissions.** `ACCESS_FINE_LOCATION`, `ACCESS_COARSE_LOCATION`,
`FOREGROUND_SERVICE`, `FOREGROUND_SERVICE_LOCATION`, `POST_NOTIFICATIONS`, `INTERNET`;
`MainActivity` exported with a LAUNCHER intent filter; `TrackingService` declared with
`android:foregroundServiceType="location"`.
**Task 2 — Local storage (Room).** `TrackPoint` entity with `id`, `timestamp`, `latitude`,
`longitude`, `speedKmh`, `altitudeM`. `TrackPointDao` with `insertPoint`, `getAllPoints`,
`getMaxSpeed`, `getPointCount`. `AppDatabase` at version 1 with a `@Volatile` singleton.
**Task 3 — Un-killable foreground service.** `TrackingService` holding a
`FusedLocationProviderClient`, a `CoroutineScope(Dispatchers.IO + SupervisorJob())`, and a
`LocationCallback` that converts `loc.speed * 3.6f` to km/h and launches a coroutine per
fix to `insertPoint`. `startForeground` with `FOREGROUND_SERVICE_TYPE_LOCATION` on Q+,
`START_STICKY`, a `LocationRequest` at `PRIORITY_HIGH_ACCURACY` / 1000 ms with a 500 ms
minimum interval, and an `IMPORTANCE_LOW` notification channel.
**Task 4 — Simple UI & controller.** `MainActivity` with `mutableStateOf` fields for
`isRecording`, `maxSpeed` and `pointCount`; a `RequestMultiplePermissions` launcher; a
`LaunchedEffect` polling `getMaxSpeed()` and `getPointCount()` every second; and a single
button toggling between START and STOP RECORDING.
### 3. Verification & deployment
1. Attach device, click Run 'app' in Android Studio
2. Grant location and notification permissions
3. Tap START RECORDING; confirm the persistent notification appears
4. Lock the screen and take a 1-minute test walk/drive
5. Unlock: verify Max Speed and Points Captured are updating
---
## Notable in hindsight
- **"Streams updates over HTTP/REST"** appears in the goal but no task defines it. The
uploader was built anyway, since it was clearly intended.
- **The 1 Hz polling loop** in Task 4 was replaced by a Room `Flow`.
- **A coroutine launched per GPS fix** (Task 3) offers no back-pressure guarantee; this
became the unbounded `Channel` and single batched writer that still underpins recording.
- **`super.onCreate()`** in Task 4 is missing its argument and would not compile.
- The verification steps assume Android Studio. Everything ended up driven from the CLI
instead — see [../DEVELOPMENT.md](../DEVELOPMENT.md).