Document Phase 8/10 real-hardware validation in PLAN.md and refresh READMEs
- PLAN.md: mark Phase 8 (dashcam retrieval) verified on real hardware, add Phase 10 documenting the OOM/multipart and Cloudflare body-size fixes plus the chunked/resumable upload redesign, both verified end-to-end against real dashcam footage. Update architecture decision #3 (Mongo -> Postgres supersession), add unraid/Pi deploy notes and memory-budget gotcha. - readme.md: refresh feature list (remote upload, chunked dashcam uploads, toggle) and project status (all 10 phases done, only cellular fallback untested). - server/README.md: document the new chunked upload endpoints and the Cloudflare body-size-limit rationale behind them.
This commit is contained in:
+31
-6
@@ -9,13 +9,24 @@ docker-compose stack on an unraid server (or any Docker host).
|
||||
|
||||
- `GET /health` — unauthenticated liveness check.
|
||||
- `POST /api/v1/tracking/batch` — bulk-insert a batch of GPS/trip points.
|
||||
- `POST /api/v1/dashcam/upload` — upload one dashcam video file (multipart,
|
||||
content-addressed by sha256 so retries/duplicates are safe).
|
||||
- `POST /api/v1/dashcam/upload` — upload one dashcam video file in a single
|
||||
request (multipart, content-addressed by sha256). Kept for reference/
|
||||
compatibility, but the Pi no longer calls this directly for real dashcam
|
||||
footage — see chunked upload below.
|
||||
- `GET /api/v1/dashcam/upload/status` — check upload progress for a
|
||||
`(relative_path, sha256)` pair: `not_started`, `in_progress` (with the list
|
||||
of already-received chunk indices, for resuming), or `already_uploaded`.
|
||||
- `POST /api/v1/dashcam/upload/chunk` — upload one chunk of a dashcam video
|
||||
(keyed by `relative_path`/`sha256`/`chunk_index`/`total_chunks`). Chunks are
|
||||
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
|
||||
actually uses for real dashcam files — see "Why chunked uploads" below.
|
||||
|
||||
Both upload endpoints require two headers: `X-Device-Name` and `X-Api-Key`
|
||||
(see [Registering a device](#registering-a-device-and-getting-an-api-key)
|
||||
below). Postgres is **not** published to the LAN — only the `api` container
|
||||
talks to it, over the internal compose network.
|
||||
Both `/api/v1/tracking/batch` and the dashcam upload endpoints require two
|
||||
headers: `X-Device-Name` and `X-Api-Key` (see
|
||||
[Registering a device](#registering-a-device-and-getting-an-api-key) below).
|
||||
Postgres is **not** published to the LAN — only the `api` container talks to
|
||||
it, over the internal compose network.
|
||||
|
||||
## Deploying on unraid
|
||||
|
||||
@@ -79,6 +90,20 @@ override/rewrite (e.g. in AdGuard Home, same trick used for `yaris.local` on
|
||||
the Pi) so the hostname resolves directly to the unraid LAN IP while on the
|
||||
home network, bypassing the tunnel entirely for big transfers.
|
||||
|
||||
## Why chunked uploads
|
||||
|
||||
Cloudflare Tunnel's free tier enforces a hard ~100MB request-body cap,
|
||||
returning a bare `413 Payload Too Large` before the request even reaches this
|
||||
API — confirmed against real dashcam footage (avg ~320MB/file), which the
|
||||
single-shot `/api/v1/dashcam/upload` endpoint could never pass through the
|
||||
tunnel. The Pi's upload client instead splits each file into 40MB chunks and
|
||||
POSTs them one at a time to `/api/v1/dashcam/upload/chunk`, checking
|
||||
`/api/v1/dashcam/upload/status` first so an interrupted upload (Pi
|
||||
reboot/crash, network drop) resumes from the last received chunk instead of
|
||||
restarting the whole file. Verified end-to-end on real hardware: a full
|
||||
28GB/87-file dashcam backlog uploaded successfully this way, each file
|
||||
byte-for-byte sha256-verified against the source on the Pi.
|
||||
|
||||
## Toggling dashcam uploads off
|
||||
|
||||
The Pi's web UI has a setting to pause dashcam file uploads while keeping
|
||||
|
||||
Reference in New Issue
Block a user