Phase 9: scaffold remote server (Flask + Postgres, docker-compose for unraid)
- server/sql/init.sql: devices/tracking_points/dashcam_files schema - server/modules/db.py: psycopg3 pool + query helpers - server/modules/auth.py: X-Device-Name/X-Api-Key header auth - server/app.py: /health, /api/v1/tracking/batch, /api/v1/dashcam/upload - server/Dockerfile + docker-compose.yml: api (gunicorn) + postgres services - server/scripts/create_device.py: one-time device/API-key registration - server/README.md: unraid deployment + Cloudflare Tunnel exposure docs - PLAN.md: Phase 9 marked in progress with full build notes Co-authored-by: Copilot <[email protected]>
This commit is contained in:
@@ -297,11 +297,50 @@ dashcam" on `/dash`, confirm it's detected and its real videos import correctly
|
||||
`dash/videos/` on the Pi. No code changes should be needed for that - only the transport (loop
|
||||
device vs. real USB) differs, and the detection/copy logic is transport-agnostic by design.
|
||||
|
||||
### Phase 9: Remote server for itinerary/dashcam upload — ⏳ TODO
|
||||
### Phase 9: Remote server for itinerary/dashcam upload — 🚧 IN PROGRESS
|
||||
Per architecture decisions #4 and #5: build a self-hosted server/API to receive itinerary
|
||||
(from the SQLite/Mongo pipeline) and dashcam file uploads, with the Pi using its home WiFi when
|
||||
available and falling back to the SIM868's GSM/GPRS cellular connection otherwise.
|
||||
|
||||
Decided: Flask API + dedicated Postgres, deployed as a docker-compose stack on the user's
|
||||
unraid server (separate from any existing containers/DBs there), living in `server/` in this
|
||||
same repo (not a separate repo). Auth: simple `X-Device-Name`/`X-Api-Key` header pair per
|
||||
device, key hash stored server-side, real key never committed (raw key printed once by
|
||||
`server/scripts/create_device.py`, saved locally on the Pi only). External access: Cloudflare
|
||||
Tunnel already running on the unraid box (add a public-hostname rule pointing at the API's
|
||||
published port) — router port-forward + the user's Unifi firewall is a documented fallback if
|
||||
ever needed instead. Large dashcam uploads should prefer a local-network path (e.g. an AdGuard
|
||||
DNS override to bypass the tunnel while on home WiFi) since tunnels typically cap per-request
|
||||
upload size.
|
||||
|
||||
Built so far (`server/` folder):
|
||||
- `server/sql/init.sql` — Postgres schema: `devices` (name + sha256 api-key-hash), `tracking_points`
|
||||
(device_id FK, GPS/speed/odometer + `recorded_at`, unique per device+timestamp so retried
|
||||
batches can't duplicate rows), `dashcam_files` (device_id FK, relative_path + sha256, unique per
|
||||
device+path+hash so re-uploads are no-ops).
|
||||
- `server/modules/db.py` — psycopg3 connection pool + query helpers (bulk tracking insert with
|
||||
`ON CONFLICT DO NOTHING`, dashcam dedupe-check-before-write).
|
||||
- `server/modules/auth.py` — `require_device_auth` decorator checking the two headers against
|
||||
the stored key hash.
|
||||
- `server/app.py` — Flask app: `GET /health` (unauthenticated), `POST /api/v1/tracking/batch`
|
||||
(bulk JSON insert), `POST /api/v1/dashcam/upload` (multipart, streamed to disk with sha256
|
||||
verification + path-traversal guard on `relative_path`).
|
||||
- `server/Dockerfile` + `server/docker-compose.yml` — `api` (gunicorn, published on host port
|
||||
8098 by default) + `db` (Postgres 17, internal-only, not published to the LAN) services, data
|
||||
volume defaults to `server/data/` but recommended to point `DATA_DIR` at
|
||||
`/mnt/user/appdata/yaris-obd-server` on unraid.
|
||||
- `server/.env.example` — template for `POSTGRES_PASSWORD`/`API_PORT`/`DATA_DIR`/upload size cap.
|
||||
- `server/scripts/create_device.py` — run once per device inside the `api` container to register
|
||||
it and print its one-time API key.
|
||||
- `server/README.md` — full unraid deployment + Cloudflare Tunnel exposure + device-registration
|
||||
instructions.
|
||||
|
||||
Still TODO: deploy the stack on the actual unraid box and verify end-to-end (containers healthy,
|
||||
`/health` reachable from the LAN), register the Pi as a device and get its real API key, then
|
||||
build the Pi-side upload client (`modules/app_upload.py`) that drains the local SQLite queue and
|
||||
dashcam files to this API with retry/backoff — including a web UI toggle to pause dashcam
|
||||
uploads specifically while always continuing to upload GPS/trip logs.
|
||||
|
||||
## Working Notes / Environment Gotchas
|
||||
|
||||
- **Pi credentials/SSH**: `ssh yaris@<pi-ip>`. Confirm current IP before connecting (varies by
|
||||
|
||||
Reference in New Issue
Block a user