Refresh docs and reorder roadmap

Co-authored-by: Copilot <[email protected]>
This commit is contained in:
Mathieu Moran
2026-08-10 18:48:59 -04:00
co-authored by Copilot
parent 457e3dcc08
commit d216aac97e
3 changed files with 425 additions and 386 deletions
+89 -84
View File
@@ -1398,89 +1398,9 @@ including two UX polish passes and multiple bug-fix rounds.
- **Dispatcher hook fix (`deploy/90-yaris-uplink`)** — previously ignored wlan1 events; now listens for both `wlan0` and `wlan1` so uplink transition recording remains accurate on current hardware. - **Dispatcher hook fix (`deploy/90-yaris-uplink`)** — previously ignored wlan1 events; now listens for both `wlan0` and `wlan1` so uplink transition recording remains accurate on current hardware.
- **README hardware photo** — added a current hardware build image (`pics/yaris-obd-hardware.jpg`) at the bottom of `readme.md`; saved without EXIF metadata and resized for lighter page load. - **README hardware photo** — added a current hardware build image (`pics/yaris-obd-hardware.jpg`) at the bottom of `readme.md`; saved without EXIF metadata and resized for lighter page load.
### Phase 25: Pre-install Yaris 2013 compatibility test — 🚧 PLANNED (core-system gate) **Roadmap ordering note (2026-08-10):** the late phases are intentionally sequenced as
**Added 2026-08-09; intentionally immediately before the Android app.** Bench tests, synthetic Phase 25.5a–25.5d (configuration/sync/status work) -> Phase 25 (real-car acceptance gate) ->
routes, attached-hardware tests, and stationary Pi runs cannot prove the complete system works Phase 26 (Android, always last).
when temporarily connected to and powered by the actual 2013 Toyota Yaris. This phase is the
pre-installation acceptance gate for the complete core Pi/web/server system after Phase 24. It is
verification and targeted correction—not permanent installation or another redesign—and the
system is not considered ready to install until the results are recorded here. Permanent mounting,
cable routing, trim work, and final installation are explicitly outside the roadmap and will be
handled by the owner after this phase passes.
Prepare a temporary, removable test setup before driving:
- Connect the Pi, SIM868 HAT/antennas, USB OBD adapter, dashcam, and representative intended power
source without permanently mounting or routing anything. Secure every temporary component and
cable so it cannot interfere with pedals, steering, airbags, visibility, occupants, or loose-item
safety during the controlled drive; remove the setup after testing.
- Resolve the Phase 19/20 undervoltage/throttling warning before the test; confirm
`vcgencmd get_throttled` shows no current power fault at idle and under load with the temporary
representative power setup. This validates electrical compatibility, not final cable routing.
- Back up the Pi SQLite database and record baseline row/trip/video/upload counts on the Pi and
remote server. Use a uniquely timestamped test window so generated records can be reconciled
without deleting unrelated history.
- Verify the service, watchdog, storage mounts, hotspot, `http://yaris.local/`, alert engine, GPS
antenna view, dashcam recording mode, free space, and remote server health before moving.
- Use a second person for UI/log observations while the vehicle is moving, or record diagnostics
for review afterward. The driver must not operate or troubleshoot the UI while driving.
Run a controlled route containing ignition-off/on, stationary idle, low-speed streets, normal road
speed, several complete stops, turns, a short GPS-obstructed segment if safely available, and a
clean trip end:
- **OBD/ECU:** confirm the ELM327 reaches `CAR_CONNECTED`, record negotiated Toyota protocol and
adapter firmware, and verify real speed/RPM/coolant/fuel/throttle/MIL/DTC values. Compare wheel
speed against the instrument cluster at several safe speeds. Record unsupported PIDs (especially
odometer PID A6) as capabilities, not failures, and verify reconnect after ignition cycling and a
deliberate USB disconnect/reconnect.
- **GPS and motion logging:** confirm fixes while stationary and moving, route coordinates on the
offline map, OBD-speed-first motion detection, GPS displacement fallback when OBD is deliberately
unavailable, one-minute idle heartbeat behavior, and no false trip from stationary GPS drift.
- **Trip boundary/replay:** after the inactivity timeout, verify exactly one trip (or the expected
number for deliberate ignition gaps), correct start/end time and coordinates, plausible
distance/average/max speed, km/mi and km/h/mph values, route polyline, start/end markers, timeline
scrubber, play/pause marker position, and stopped portions of the route.
- **Local web UI:** test the final Phase 23 interface on the actual phone over the Pi/phone network at
`http://yaris.local/`; verify the explicit **In-car / Local Pi** identity, dashboard telemetry,
DTC page, trip history, dashcam library, settings, alerts, responsive layout, reconnect behavior,
and no new browser console/API errors.
- **Dashcam workflow:** create a known short real clip, switch the camera safely into USB storage
mode, detect/list it without confusing the OBD adapter, import only that selected file, verify
thumbnail/playback/Range seeking, preserve the source until checks finish, and confirm the camera
returns to recording afterward. Test deletion only with the disposable clip.
- **Alerts:** safely exercise conditions that can be simulated without damaging hardware (upload
backlog, temporary GPS loss while OBD reports motion, and disposable threshold overrides).
Confirm local bell transition/recovery/cooldown behavior and offline alert-state reconciliation
with the Phase 24 server after connectivity returns. Do not intentionally overheat, undervolt,
fill storage, or trigger a real MIL. With a real SIM, explicitly determine whether the SIM868
transport can reliably deliver ntfy notifications while WiFi/Ethernet is unavailable, including
authentication, timeout, retry, and recovery. If that cannot be made reliable on the actual
modem/network, remove the ntfy feature and its settings rather than retain a transport that fails
in the only situation where it is useful.
- **Power/reliability:** perform multiple normal ignition/power cycles, confirm automatic boot,
service/watchdog startup, SIM868 power-on, OBD/GPS recovery, no SQLite corruption, and no current
undervoltage/throttling. The deferred Phase 14 clean-shutdown limitation must be explicitly
accepted or resolved with representative delayed-power/ignition-sense hardware before declaring
the design ready for permanent installation.
Verify the complete remote path after connectivity returns:
- Confirm every test-window tracking row uploads exactly once and the selected dashcam clip resumes
or completes without corruption; compare counts, timestamps, hashes, and byte sizes locally and
remotely.
- On the Phase 24 portal, verify the explicit **Remote server** identity, authenticated
vehicle-scoped trip summary/replay, route and timeline agreement with the local Pi, archived clip
thumbnail/playback/Range seeking/download, synchronized alert history/current state without
duplicate transitions after an offline interval, and absence of local-only OBD/cellular/Pi
controls.
- The Android companion is intentionally outside this core acceptance gate and remains the final,
low-priority Phase 26. Its own hotspot/cellular binding, trip display, and disposable clip relay
require separate real-phone/in-car acceptance when that phase is implemented.
Acceptance requires a written result for every item, captured negotiated protocol/PID support,
measured trip/count/hash comparisons, relevant logs/screenshots, no unexplained tracebacks or data
loss, and cleanup of every disposable record/file while preserving the real drive. Any defect found
must be fixed, redeployed uncommitted, and the affected in-car test repeated before the final commit
and **ready-to-install** sign-off. Afterward, the owner handles permanent installation outside the
phase roadmap.
### Phase 25.5a: Device configuration sync backend — ✅ COMPLETE (connection-driven server sync) ### Phase 25.5a: Device configuration sync backend — ✅ COMPLETE (connection-driven server sync)
**Server API and Pi sync thread implemented.** Server stores device config; Pi fetches when internet available and applies changes without restart. **Server API and Pi sync thread implemented.** Server stores device config; Pi fetches when internet available and applies changes without restart.
@@ -1744,7 +1664,7 @@ updates its display-facing values without a manual restart once sync lands.
history view still shows one configured car/device at a time until a later history view still shows one configured car/device at a time until a later
portal-wide device selector/filter is implemented. portal-wide device selector/filter is implemented.
### Phase 25.5d: GPS dashboard visibility / live-status debugging — 🚧 IN PROGRESS ### Phase 25.5d: GPS dashboard visibility / live-status debugging — ✅ COMPLETE
- Add an explicit Pi dashboard GPS status indicator (thread alive / live fix / stale fix / no fix) - Add an explicit Pi dashboard GPS status indicator (thread alive / live fix / stale fix / no fix)
- Expose a local `/api/gps/status` endpoint so GPS health can be checked without relying on - Expose a local `/api/gps/status` endpoint so GPS health can be checked without relying on
socket events alone socket events alone
@@ -1793,6 +1713,91 @@ updates its display-facing values without a manual restart once sync lands.
card now appears before the Live GPS map. Deployed to the real Pi and confirmed the rendered card now appears before the Live GPS map. Deployed to the real Pi and confirmed the rendered
`/` HTML places `Overview` before `Live GPS`. `/` HTML places `Overview` before `Live GPS`.
---
### Phase 25: Pre-install Yaris 2013 compatibility test — 🚧 PLANNED (core-system gate)
**Added 2026-08-09; intentionally immediately before the Android app.** Bench tests, synthetic
routes, attached-hardware tests, and stationary Pi runs cannot prove the complete system works
when temporarily connected to and powered by the actual 2013 Toyota Yaris. This phase is the
pre-installation acceptance gate for the complete core Pi/web/server system after Phase 24. It is
verification and targeted correction—not permanent installation or another redesign—and the
system is not considered ready to install until the results are recorded here. Permanent mounting,
cable routing, trim work, and final installation are explicitly outside the roadmap and will be
handled by the owner after this phase passes.
Prepare a temporary, removable test setup before driving:
- Connect the Pi, SIM868 HAT/antennas, USB OBD adapter, dashcam, and representative intended power
source without permanently mounting or routing anything. Secure every temporary component and
cable so it cannot interfere with pedals, steering, airbags, visibility, occupants, or loose-item
safety during the controlled drive; remove the setup after testing.
- Resolve the Phase 19/20 undervoltage/throttling warning before the test; confirm
`vcgencmd get_throttled` shows no current power fault at idle and under load with the temporary
representative power setup. This validates electrical compatibility, not final cable routing.
- Back up the Pi SQLite database and record baseline row/trip/video/upload counts on the Pi and
remote server. Use a uniquely timestamped test window so generated records can be reconciled
without deleting unrelated history.
- Verify the service, watchdog, storage mounts, hotspot, `http://yaris.local/`, alert engine, GPS
antenna view, dashcam recording mode, free space, and remote server health before moving.
- Use a second person for UI/log observations while the vehicle is moving, or record diagnostics
for review afterward. The driver must not operate or troubleshoot the UI while driving.
Run a controlled route containing ignition-off/on, stationary idle, low-speed streets, normal road
speed, several complete stops, turns, a short GPS-obstructed segment if safely available, and a
clean trip end:
- **OBD/ECU:** confirm the ELM327 reaches `CAR_CONNECTED`, record negotiated Toyota protocol and
adapter firmware, and verify real speed/RPM/coolant/fuel/throttle/MIL/DTC values. Compare wheel
speed against the instrument cluster at several safe speeds. Record unsupported PIDs (especially
odometer PID A6) as capabilities, not failures, and verify reconnect after ignition cycling and a
deliberate USB disconnect/reconnect.
- **GPS and motion logging:** confirm fixes while stationary and moving, route coordinates on the
offline map, OBD-speed-first motion detection, GPS displacement fallback when OBD is deliberately
unavailable, one-minute idle heartbeat behavior, and no false trip from stationary GPS drift.
- **Trip boundary/replay:** after the inactivity timeout, verify exactly one trip (or the expected
number for deliberate ignition gaps), correct start/end time and coordinates, plausible
distance/average/max speed, km/mi and km/h/mph values, route polyline, start/end markers, timeline
scrubber, play/pause marker position, and stopped portions of the route.
- **Local web UI:** test the final Phase 23 interface on the actual phone over the Pi/phone network at
`http://yaris.local/`; verify the explicit **In-car / Local Pi** identity, dashboard telemetry,
DTC page, trip history, dashcam library, settings, alerts, responsive layout, reconnect behavior,
and no new browser console/API errors.
- **Dashcam workflow:** create a known short real clip, switch the camera safely into USB storage
mode, detect/list it without confusing the OBD adapter, import only that selected file, verify
thumbnail/playback/Range seeking, preserve the source until checks finish, and confirm the camera
returns to recording afterward. Test deletion only with the disposable clip.
- **Alerts:** safely exercise conditions that can be simulated without damaging hardware (upload
backlog, temporary GPS loss while OBD reports motion, and disposable threshold overrides).
Confirm local bell transition/recovery/cooldown behavior and offline alert-state reconciliation
with the Phase 24 server after connectivity returns. Do not intentionally overheat, undervolt,
fill storage, or trigger a real MIL. With a real SIM, explicitly determine whether the SIM868
transport can reliably deliver ntfy notifications while WiFi/Ethernet is unavailable, including
authentication, timeout, retry, and recovery. If that cannot be made reliable on the actual
modem/network, remove the ntfy feature and its settings rather than retain a transport that fails
in the only situation where it is useful.
- **Power/reliability:** perform multiple normal ignition/power cycles, confirm automatic boot,
service/watchdog startup, SIM868 power-on, OBD/GPS recovery, no SQLite corruption, and no current
undervoltage/throttling. The deferred Phase 14 clean-shutdown limitation must be explicitly
accepted or resolved with representative delayed-power/ignition-sense hardware before declaring
the design ready for permanent installation.
Verify the complete remote path after connectivity returns:
- Confirm every test-window tracking row uploads exactly once and the selected dashcam clip resumes
or completes without corruption; compare counts, timestamps, hashes, and byte sizes locally and
remotely.
- On the Phase 24 portal, verify the explicit **Remote server** identity, authenticated
vehicle-scoped trip summary/replay, route and timeline agreement with the local Pi, archived clip
thumbnail/playback/Range seeking/download, synchronized alert history/current state without
duplicate transitions after an offline interval, and absence of local-only OBD/cellular/Pi
controls.
- The Android companion is intentionally outside this core acceptance gate and remains the final,
low-priority Phase 26. Its own hotspot/cellular binding, trip display, and disposable clip relay
require separate real-phone/in-car acceptance when that phase is implemented.
Acceptance requires a written result for every item, captured negotiated protocol/PID support,
measured trip/count/hash comparisons, relevant logs/screenshots, no unexplained tracebacks or data
loss, and cleanup of every disposable record/file while preserving the real drive. Any defect found
must be fixed, redeployed uncommitted, and the affected in-car test repeated before the final commit
and **ready-to-install** sign-off. Afterward, the owner handles permanent installation outside the
phase roadmap.
--- ---
### Phase 26: Native Android companion app — 🚧 PLANNED (low priority, always last) ### Phase 26: Native Android companion app — 🚧 PLANNED (low priority, always last)
+34 -15
View File
@@ -59,8 +59,8 @@ Dashboard — mobile (390 px) and desktop (1280 px):
trip history with OSM/CARTO live map and route replay, dashcam archive browsing with inline trip history with OSM/CARTO live map and route replay, dashcam archive browsing with inline
video player and Range-request seeking, overview stats dashboard, delete buttons for trips and video player and Range-request seeking, overview stats dashboard, delete buttons for trips and
clips, and a device-settings page for editing the synced owner/car/avatar values that the Pi clips, and a device-settings page for editing the synced owner/car/avatar values that the Pi
pulls from the server. The portal can register multiple devices, reveal a one-time API key at pulls from the server. The portal can register/delete multiple devices, reveal a one-time API
creation/rotation time, and request a sync for a selected device. When the Pi has key at creation/rotation time, and request a sync for a selected device. When the Pi has
**Sync with server** enabled, those identity changes hot-reload into the running local UI on the **Sync with server** enabled, those identity changes hot-reload into the running local UI on the
next successful sync instead of waiting for a manual restart. Shared `history.js` code runs on next successful sync instead of waiting for a manual restart. Shared `history.js` code runs on
both the Pi and the server — tile source and zoom limits are configured per-deployment via HTML both the Pi and the server — tile source and zoom limits are configured per-deployment via HTML
@@ -71,8 +71,9 @@ Dashboard — mobile (390 px) and desktop (1280 px):
diagnostics, plus quick actions for server test, sync-now, uplink reconnect, and app restart diagnostics, plus quick actions for server test, sync-now, uplink reconnect, and app restart
- 🗄️ **Motion-aware local-first SQLite logging** — five-second motion checks without five-second - 🗄️ **Motion-aware local-first SQLite logging** — five-second motion checks without five-second
parked writes, plus retry-safe remote sync and automatic backoff parked writes, plus retry-safe remote sync and automatic backoff
- 🌡️ **Pi health monitoring** — dashboard temperature, RAM, disk space, uptime, and explicit - 🌡️ **Pi health + diagnostics** — a dedicated local Status page shows temperature, RAM, disk,
undervoltage/throttling warnings from the Raspberry Pi firmware uptime, undervoltage/throttling warnings, service state, uplink/server reachability, GPS state,
OBD presence, and safe quick actions
- 🔔 **Offline-first alerts** — a notification bell on every page reports check-engine state, - 🔔 **Offline-first alerts** — a notification bell on every page reports check-engine state,
storage pressure, upload backlog, temperature/power faults, and GPS loss while moving. Optional storage pressure, upload backlog, temperature/power faults, and GPS loss while moving. Optional
ntfy delivery is available but remains disabled until configured ntfy delivery is available but remains disabled until configured
@@ -122,7 +123,14 @@ For the remote server (receives trip logs + dashcam uploads), see [server/README
## Customizing device identity ## Customizing device identity
The Pi displays a username, car model, and avatar image. All customizable values are stored in `config/device.json` (no code edits needed). The Pi displays an owner name, car model, device name, and avatar. You can manage those values in
two ways:
- **Locally on the Pi** through the Settings page
- **From the server portal** when **Sync with server** is enabled on the Pi
The local fallback/default source remains [config/device.json](./config/device.json), so the car
still boots with sensible identity values even when fully offline.
### Edit device configuration ### Edit device configuration
@@ -141,10 +149,10 @@ Edit [config/device.json](./config/device.json):
|-------|----------|---------| |-------|----------|---------|
| `owner_name` | Top-right of app topbar | Your name/username | | `owner_name` | Top-right of app topbar | Your name/username |
| `car_model` | Left sidebar (next to car icon) | Vehicle model/year | | `car_model` | Left sidebar (next to car icon) | Vehicle model/year |
| `device_name` | (Reserved) | Future server-side use in Phase 25.5 | | `device_name` | Local settings / remote portal | Device identity used by server sync/provisioning |
| `avatar_path` | Top-right avatar circle | Profile picture (relative to `static/`) | | `avatar_path` | Top-right avatar circle | Profile picture (relative to `static/`) |
After editing, restart the app: If you edit the JSON file directly, restart the app:
```bash ```bash
# If running as a systemd service: # If running as a systemd service:
@@ -187,15 +195,26 @@ rm db/sql/quoije_Yaris2013.db
## Project status ## Project status
Phases 1–24.7 are complete. The system is fully built and audited, ready for the Phase 25 real-vehicle test: The build is now at the endgame stage: the Pi app, remote server, and device-management/sync work
are implemented and verified on the real Pi/unraid setup. The remaining roadmap phases are the
temporary real-vehicle acceptance test and the low-priority Android companion.
- **Phases 1–23.5**: core Pi system — GPS, OBD, dashcam, trip history, web UI redesign, WiFi upgrade, cellular fallback, alerts, settings, upload - **Phases 1–23.5**: core Pi system — GPS, OBD, dashcam, trip history, web UI redesign, WiFi upgrade, cellular fallback, alerts, settings, upload
- **Phase 24**: remote web portal at `https://yaris.ceaf.dev/` — login-protected, trip history with CARTO live map, dashcam archive, delete, overview stats - **Phase 24**: remote web portal at `https://yaris.ceaf.dev/` — login-protected, trip history with CARTO live map, dashcam archive, delete, overview stats
- **Phase 24.5**: full code audit — 6 bugs fixed across Pi modules and server, 63 tests passing - **Phase 24.5**: full code audit — 6 bugs fixed across Pi modules and server, 63 tests passing
- **Phase 24.6**: Yaris 2013 OBD compatibility hardening — `_decode_odometer` no longer kills the OBD session on unsupported PIDs, sensor globals reset on reconnect, `OBD_SKIP_VOLTAGE_CHECK` escape hatch for clone ELM327 adapters - **Phase 24.6**: Yaris 2013 OBD compatibility hardening — `_decode_odometer` no longer kills the OBD session on unsupported PIDs, sensor globals reset on reconnect, `OBD_SKIP_VOLTAGE_CHECK` escape hatch for clone ELM327 adapters
- **Phase 24.7**: diagnostic script (`scripts/diagnose.sh`), map tile switch to CARTO, zoom limit fix - **Phase 24.7**: diagnostic script (`scripts/diagnose.sh`), map tile switch to CARTO, zoom limit fix
- **Phase 24.8**: deployment/readme cleanup and uplink interface consistency
- **Phases 25.5a–25.5d**: offline-first device identity sync, remote portal device settings,
Pi-side hot-reload, multi-device provisioning, one-time API key rotation/registration, local
Settings UI for remote credentials, Sync now / Test connection, GPS live-status verification,
dedicated local Status page, and status-page quick actions
- **Current known limitation**: the remote portal's device-management page is multi-device, but the
main remote overview/history/dashcam browsing views still follow one configured `DEVICE_NAME`
until a later portal-wide device selector/filter is added
**Next**: Phase 25 — temporary real-vehicle test in the 2013 Yaris (see PLAN.md for the full acceptance checklist). Phase 26 (Android companion app) follows after that. **Next**: Phase 25 — temporary real-vehicle test in the 2013 Yaris (see [PLAN.md](./PLAN.md) for
the full acceptance checklist). Phase 26 (Android companion app) follows after that.
Phase 14 is partially complete: the Pi's hardware watchdog is deployed and reboot-verified. Phase 14 is partially complete: the Pi's hardware watchdog is deployed and reboot-verified.
Read-only-root storage hardening is deferred until persistent storage is moved off the SD root Read-only-root storage hardening is deferred until persistent storage is moved off the SD root
@@ -205,12 +224,12 @@ The browser-based phone relay was removed after real-world testing confirmed tha
cannot reliably use the Pi's WiFi and cellular data simultaneously. A native Android companion is cannot reliably use the Pi's WiFi and cellular data simultaneously. A native Android companion is
planned later instead (Phase 26). planned later instead (Phase 26).
The local Web UI includes a Settings page for safe runtime configuration: dashcam uploads, The local web UI includes a Settings page for safe runtime configuration: dashcam uploads,
uploaded-video retention, cellular APN fallback, optional ntfy delivery, and alert thresholds. uploaded-video retention, cellular APN fallback, optional ntfy delivery, alert thresholds, local
Notification secrets are write-only in the browser API, and network credentials that could lock device identity, and remote server credentials/API key. Notification secrets remain write-only in
the Pi out remain SSH/file-managed. When cellular is configured, small ntfy notifications use the the browser API. When cellular is configured, small ntfy notifications use the SIM868 first and
SIM868 first and WiFi/Ethernet only as fallback; that modem path is implemented and mock-tested but WiFi/Ethernet only as fallback; that modem path is implemented and mock-tested but still needs
still needs real-SIM/carrier verification. real-SIM/carrier verification.
The Pi can also join a configured phone hotspot for outbound internet when no SIM is available, The Pi can also join a configured phone hotspot for outbound internet when no SIM is available,
including trip synchronization and WiFi dashcam uploads, with automatic recovery to home WiFi or including trip synchronization and WiFi dashcam uploads, with automatic recovery to home WiFi or
+33 -18
View File
@@ -21,6 +21,13 @@ docker-compose stack on an unraid server (or any Docker host).
staged on disk and reassembled + sha256-verified once all have arrived, then staged on disk and reassembled + sha256-verified once all have arrived, then
recorded the same way as the single-shot endpoint. This is what the Pi recorded the same way as the single-shot endpoint. This is what the Pi
actually uses for real dashcam files — see "Why chunked uploads" below. actually uses for real dashcam files — see "Why chunked uploads" below.
- `GET /api/device-config` — device-authenticated config fetch used by the Pi's
identity-sync thread and local **Sync now** action.
- `POST /api/v1/device-config/ack` — device-authenticated config-sync
acknowledgement so the server can record the last applied version/time.
- `/settings/device` + `/api/v1/portal/devices*` — login-protected multi-device
management UI/APIs for create, delete, rotate key, edit config, and request
sync.
Both `/api/v1/tracking/batch` and the dashcam upload endpoints require two Both `/api/v1/tracking/batch` and the dashcam upload endpoints require two
headers: `X-Device-Name` and `X-Api-Key` (see headers: `X-Device-Name` and `X-Api-Key` (see
@@ -28,13 +35,11 @@ headers: `X-Device-Name` and `X-Api-Key` (see
Postgres is **not** published to the LAN — only the `api` container talks to Postgres is **not** published to the LAN — only the `api` container talks to
it, over the internal compose network. it, over the internal compose network.
**CORS is enabled on every response** (`Access-Control-Allow-Origin: *`) so a **CORS is enabled on every response** (`Access-Control-Allow-Origin: *`) for the
device's registered API key can be used directly from browser JS running on a device-authenticated API surface. This keeps header-authenticated device calls
*different* origin — specifically, the Pi's phone-relay feature (see usable from browser-based tooling and same-user cross-origin utilities without
[PLAN.md](../PLAN.md) Phase 11), where a phone's browser calls this API introducing cookie/session theft risk, because device auth is explicit
straight from a page served by the Pi itself. This is safe here because (`X-Device-Name`/`X-Api-Key`) rather than ambient session auth.
auth is header-based (`X-Device-Name`/`X-Api-Key`), not cookie/session-based,
so a permissive origin can't be used to steal a logged-in session.
## Deploying on unraid ## Deploying on unraid
@@ -65,12 +70,11 @@ so a permissive origin can't be used to steal a logged-in session.
docker compose ps docker compose ps
curl http://localhost:8098/health curl http://localhost:8098/health
``` ```
5. Sign in to the remote portal and open `/settings/device` to edit the synced 5. Sign in to the remote portal and open `/settings/device` to manage devices:
owner/car/device/avatar values for the configured `DEVICE_NAME`. If the Pi create/delete devices, reveal a one-time API key, rotate keys, edit synced
has local **Sync with server** enabled, those values hot-reload into the owner/car/device/avatar values, and request a sync. If the Pi has local
running Pi UI after the next successful sync. Phase 25.5c also adds a **Sync with server** enabled, those values hot-reload into the running Pi UI
multi-device list, one-time API-key reveal, key rotation, and a request-sync after the next successful sync.
action on that page.
### Upgrading an existing unraid deployment ### Upgrading an existing unraid deployment
@@ -87,10 +91,12 @@ docker compose up -d --build
Phase 25.5a adds the device identity sync columns (`owner_name`, `car_model`, Phase 25.5a adds the device identity sync columns (`owner_name`, `car_model`,
`device_name`, `avatar_path`, `config_version`, `config_updated_at`) used by the `device_name`, `avatar_path`, `config_version`, `config_updated_at`) used by the
Pi/server config sync flow. The browser portal page at `/settings/device` edits Pi/server config sync flow. Phase 25.5c adds multi-device provisioning/status
those values; the Pi applies them on its next successful sync when local columns (`last_config_sync_at`, `last_config_sync_version`,
**Sync with server** is enabled, and Phase 25.5b now hot-reloads the in-process `force_sync_requested_at`, `api_key_rotated_at`). The browser portal page at
UI fields instead of requiring an app restart. `/settings/device` edits those values; the Pi applies them on its next
successful sync when local **Sync with server** is enabled, and Phase 25.5b
hot-reloads the in-process UI fields instead of requiring an app restart.
## Registering a device and getting an API key ## Registering a device and getting an API key
@@ -104,14 +110,23 @@ This prints a one-time API key — copy the `YARIS_DEVICE_NAME` /
`YARIS_API_KEY` values into the Pi's upload-client config. Only the `YARIS_API_KEY` values into the Pi's upload-client config. Only the
key's sha256 hash is stored server-side; the raw key is never shown again. key's sha256 hash is stored server-side; the raw key is never shown again.
On the Pi, those credentials can now be entered through the local Settings page
instead of editing `db/upload_creds.env` over SSH. The same page also exposes
**Test connection** and **Sync now** actions.
The browser portal at `/settings/device` can now do the same workflow without The browser portal at `/settings/device` can now do the same workflow without
shell access: shell access:
- create a new device - create a new device
- delete a non-default device
- reveal a one-time API key - reveal a one-time API key
- rotate the API key later - rotate the API key later
- request a sync for the selected device - request a sync for the selected device
Current limitation: device management is multi-device, but the main remote
overview/history/dashcam browsing pages still scope themselves to one
configured `DEVICE_NAME` until a portal-wide device selector/filter is added.
## Exposing it outside the LAN ## Exposing it outside the LAN
Two options, either works with this API unchanged: Two options, either works with this API unchanged:
@@ -149,7 +164,7 @@ byte-for-byte sha256-verified against the source on the Pi.
The Pi's web UI has a setting to pause dashcam file uploads while keeping The Pi's web UI has a setting to pause dashcam file uploads while keeping
GPS/trip log uploads running — no server-side change needed, the Pi simply GPS/trip log uploads running — no server-side change needed, the Pi simply
stops calling `/api/v1/dashcam/upload` while the toggle is off. stops calling the dashcam upload status/chunk endpoints while the toggle is off.
## Local development / testing without unraid ## Local development / testing without unraid