# 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 `` per second with: - lat/lon/elevation from GPS - `` — heart rate - `` — power (watts) - `` — 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 (half day) - [ ] **Android runtime permissions** — `BLUETOOTH_SCAN` + `BLUETOOTH_CONNECT` require explicit permission requests on Android 12+; add a `requestBlePermissions()` call in `SensorPairingScreen` before scanning - [ ] **Cadence CSC parsing** — `subscribeCadence()` in `ble.ts` is stubbed; implement stateful CSC Measurement parsing (track previous crank revolution count + timestamp, compute RPM from delta) - [ ] **BLE persistence** — save paired device IDs + types to AsyncStorage on connect; on app start, attempt to reconnect to previously paired devices automatically ### 3 — Km notifications (half day) - [ ] **Permission request** — call `Notifications.requestPermissionsAsync()` on first launch - [ ] **Milestone tracker** — track last notified km in the GPS background task (or store); fire a notification each time `distanceMeters` crosses a new km boundary, gated on the `kmNotifications` setting from AsyncStorage ### 4 — Android battery optimization prompt (1–2 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 `` + a tile source (e.g. OpenFreeMap); call `MapLibreGL.setAccessToken(null)` for raster-free usage - [ ] **Camera follow** — add `` that follows `trackPoints[last]` during recording - [ ] **Line layer** — replace SVG polyline with `` + ``