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:
Mathieu Moran
2026-08-08 19:50:52 -04:00
co-authored by Copilot
parent 261ef3f4db
commit 9bdf5bad2c
12 changed files with 582 additions and 1 deletions
+44
View File
@@ -0,0 +1,44 @@
services:
db:
image: postgres:17
container_name: yaris-obd-db
restart: unless-stopped
environment:
POSTGRES_DB: ${POSTGRES_DB:-yarisobd}
POSTGRES_USER: ${POSTGRES_USER:-yarisobd}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set a POSTGRES_PASSWORD in .env}
volumes:
- ${DATA_DIR:-./data}/postgres:/var/lib/postgresql/data
- ./sql/init.sql:/docker-entrypoint-initdb.d/init.sql:ro
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-yarisobd}"]
interval: 10s
timeout: 5s
retries: 5
# Not published to the host/LAN on purpose - only reachable from the
# `api` container over the internal compose network.
api:
build: .
container_name: yaris-obd-api
restart: unless-stopped
depends_on:
db:
condition: service_healthy
environment:
POSTGRES_HOST: db
POSTGRES_PORT: 5432
POSTGRES_DB: ${POSTGRES_DB:-yarisobd}
POSTGRES_USER: ${POSTGRES_USER:-yarisobd}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set a POSTGRES_PASSWORD in .env}
DASHCAM_STORAGE_DIR: /data/dashcam
MAX_DASHCAM_UPLOAD_MB: ${MAX_DASHCAM_UPLOAD_MB:-2048}
volumes:
- ${DATA_DIR:-./data}/dashcam:/data/dashcam
ports:
- "${API_PORT:-8098}:8098"
healthcheck:
test: ["CMD", "python3", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8098/health', timeout=3)"]
interval: 30s
timeout: 5s
retries: 3