frontend: global km/mi distance-unit toggle across dashboard, activities, routes, records
Build and push images / validate (push) Successful in 3s
Build and push images / build-backend (push) Successful in 5s
Build and push images / build-worker (push) Successful in 5s
Build and push images / build-frontend (push) Successful in 9s

This commit is contained in:
2026-06-18 13:01:25 +01:00
parent e61c77842f
commit a50d13179c
13 changed files with 186 additions and 57 deletions
+22
View File
@@ -125,6 +125,28 @@ docker compose -f docker-compose.deploy.yml up -d
The Vite dev server proxies `/api` to `http://backend:8000` (for use inside the Docker Compose network). The production build bakes `VITE_API_URL` at build time.
### Request routing & browser caching
There are **two** nginx configs and they serve different roles — don't confuse them:
- `nginx.conf` (repo root) is the **dev/CI** reverse proxy (`docker-compose.yml`): one nginx that proxies `/api/``backend:8000` and `/``frontend:80`.
- `frontend/nginx-spa.conf` runs *inside the `frontend` image* and only serves the built SPA (the `milevault_frontend` container). It has no `/api` proxy.
**In production (`docker-compose.deploy.yml` / `~/milevault_docker`) there is no nginx reverse-proxy service — Traefik does the routing via container labels:** `Host(...) && PathPrefix(/api)` → backend, `Host(...)` → frontend SPA. The empty `~/milevault_docker/nginx.conf` is an unused leftover. So if a request reaches the SPA nginx with an `/api` path it falls through to `index.html` (returns HTML, not JSON) — a sign Traefik routing, not nginx, is the thing to debug.
**Caching policy (set deliberately; a wrong change here strands users on stale builds):**
- Hashed assets (`*.js`/`*.css`) → `Cache-Control: public, immutable` (1y) in `nginx-spa.conf`.
- `index.html``no-cache` (must revalidate) in `nginx-spa.conf`, so new deploys are picked up without a manual cache clear.
- All `/api/*` responses → `no-store`, added by an HTTP middleware in `backend/app/main.py`, so browsers can't cache authenticated state (e.g. a stale "Garmin not connected").
### Deploy verification
After `./deploy.sh`, the Gitea Actions build (`validate``build-backend`/`build-worker`/`build-frontend`) must finish before `docker compose pull && up -d` picks up new `:latest` images. Poll completion via the API rather than guessing:
```bash
curl -s https://gitea.jarrett.eu/api/v1/repos/owain/MileVault/actions/tasks
```
The runner builds images on-host, so local image digests won't match the registry — verify a deploy landed by `docker exec`-ing into the running container and grepping the changed source, not by comparing digests.
## Environment variables
Required in `.env` (or passed to Docker Compose):