Files
bincio-rec/CLAUDE.md
T
Davide Scaini 5f12b2857d feat: section 3 — km milestone notifications
- Foreground notification handler in App.tsx (iOS shows banners while active)
- requestNotificationPermissions() called on app mount
- GPS task tracks running distance per recording session (module-level state)
- Fires immediate notification at each km crossed, gated on kmNotifications setting
2026-06-03 09:03:55 +02:00

132 lines
6.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# bincio-rec
GPS activity recorder for the bincio ecosystem.
Companion to **bincio-autarchive** (archive/sync app): rec makes the data, autarchive stores and syncs it.
---
## Concept
A focused, minimal recording app for cycling, running, hiking, and walking.
Records GPS track + BLE sensor data, saves to GPX, optionally uploads directly to a bincio-activity server.
Future: live navigation / turn-by-turn instructions.
The app does one thing well: **record**. No browsing, no analysis — that's autarchive's job.
---
## Ecosystem
```
bincio-rec → writes GPX files to shared storage
bincio-autarchive → imports GPX, stores locally, syncs to server
bincio-activity → server: parses GPX, stores activities, serves API
bincio-auth → auth service: issues JWTs for all bincio apps
```
bincio-rec can also upload directly to bincio-activity via `/api/upload/raw` (same endpoint autarchive uses), with instance URL + API token configured in settings.
---
## Tech Stack
**Expo Prebuild** (not managed Expo, not bare RN).
- Managed Expo ruled out: BLE requires native modules
- Bare RN ruled out: Expo library ecosystem is valuable (location, notifications, file system)
- Prebuild gives full native access while keeping Expo tooling and EAS Build
Key libraries:
- `expo-location` + `expo-task-manager` — background GPS recording
- `react-native-ble-plx` — BLE sensors (HR, power, cadence)
- `@maplibre/maplibre-react-native` — live track map, future navigation
- `expo-notifications` — km milestone alerts, future navigation cues
- `expo-keep-awake` — keep screen on during recording (user-toggleable)
- `expo-file-system` — write GPX/JSON to shared storage
- `expo-sqlite` — local DB for past recordings list
Target: **Android first**, iOS second.
---
## v1 Screens
1. **Sensor pairing** — scan BLE, pair HR monitor / power meter / cadence sensor; persisted
2. **Recording** — start / pause / resume / stop
- Live stats: elapsed time, distance, current+avg speed, HR, power, cadence, elevation gain
- Map with track drawn in real time
- Keep-awake toggle
3. **Post-recording summary** — stats overview, title field, save / discard
4. **Saved recordings** — list of past sessions; tap to export GPX or upload to server
5. **Settings** — bincio instance URL + API token; km notification toggle; upload format
---
## Output Format
**GPX with Garmin trackpoint extensions** — one `<trkpt>` per second with:
- lat/lon/elevation from GPS
- `<gpxtpx:hr>` — heart rate
- `<gpxtpx:power>` — power (watts)
- `<gpxtpx:cad>` — cadence (rpm)
bincio-activity already parses this format via `bincio.extract.parsers`.
Files saved to a user-accessible location (iOS Files app / Android shared storage) so bincio-autarchive can import them manually.
---
## Known Platform Concerns
- **Android battery optimization**: aggressive OEMs (Xiaomi, Samsung, Huawei) kill background tasks. Prompt user to whitelist bincio-rec in battery settings on first launch. Every recording app has this problem — no framework-level fix.
- **iOS background location**: requires `location` background mode in `Info.plist` and "Always" location permission. Fine for sideloading/TestFlight; App Store submission requires clear justification.
- **iOS foreground notifications**: notification sounds are suppressed when app is in foreground — use `expo-av` audio cue instead for km alerts while screen is on.
---
## Out of Scope (v1)
- Navigation / turn-by-turn routing
- Auto-pause (stop lights, etc.)
- Structured workouts / intervals
- Offline maps
- Live tracking / sharing
---
## v1 Completion Plan
Scaffold is done (all screens, navigation, store, services, GPX, DB, upload).
Items below are what remains before v1 is shippable.
### 1 — Quick fixes ✅
- [x] **Keep-awake toggle** — wired to `keepAwake` store state via `activateKeepAwakeAsync` / `deactivateKeepAwake`; toggle button visible in controls bar
- [x] **Sensor button on Recording screen** — "⚡ Sensors" button overlaid on map area navigates to SensorPairing modal
- [x] **GPS pause/resume**`handlePause` calls `stopGpsRecording()`, `handleResume` calls `startGpsRecording()`
- [x] **Track view**`TrackView` component renders recorded lat/lon points as a scaled SVG polyline on a dark background (no tile server needed); replaces the grey placeholder
### 2 — BLE ✅
- [x] **Android runtime permissions**`requestBlePermissions()` requests `BLUETOOTH_SCAN` + `BLUETOOTH_CONNECT` on Android 12+ (API 31+) before scanning
- [x] **Cadence CSC parsing** — stateful parsing in `parseCscMeasurement()`: tracks previous crank revolution count + event time (uint16, 1/1024 s), computes RPM from delta with uint16 rollover handling
- [x] **BLE persistence**`savePairedDevice` / `loadPairedDevices` / `removePairedDevice` in `ble.ts` via AsyncStorage; SensorPairingScreen shows saved sensors at top, auto-attempts reconnect on mount, Forget button removes a device
### 3 — Km notifications ✅
- [x] **Permission request**`requestNotificationPermissions()` called in `App.tsx` on mount; foreground notification handler set at module level so iOS shows banners while app is active
- [x] **Milestone tracker** — module-level `runningDistanceMeters` / `lastNotifiedKm` / `prevPoint` in `gps.ts`, reset on each `startGpsRecording()`; each incoming location adds haversine distance and fires a notification when a new km is crossed, gated on the `kmNotifications` AsyncStorage setting
### 4 — Android battery optimization prompt (12 hours)
- [ ] On first launch, detect if the app is affected by battery optimization (`expo-intent-launcher`) and show a one-time prompt directing the user to whitelist bincio-rec; persist dismissal in AsyncStorage so it only shows once
### 5 — Map (optional upgrade)
The track view from section 1 already shows the GPX polyline scaled to fit the screen.
MapLibre can be added later for a real basemap (streets/terrain), but is not required for v1.
- [ ] **MapLibre basemap** — replace `TrackView` SVG with `<MapLibreGL.MapView>` + a tile source (e.g. OpenFreeMap); call `MapLibreGL.setAccessToken(null)` for raster-free usage
- [ ] **Camera follow** — add `<MapLibreGL.Camera>` that follows `trackPoints[last]` during recording
- [ ] **Line layer** — replace SVG polyline with `<MapLibreGL.ShapeSource>` + `<MapLibreGL.LineLayer>`