--- status: complete phase: 06-performance-production-hardening source: 06-01-SUMMARY.md, 06-02-SUMMARY.md, 06-03-SUMMARY.md, 06-04-SUMMARY.md, 06-05-SUMMARY.md started: 2026-06-04T00:00:00Z updated: 2026-06-04T19:05:00Z --- ## Current Test [testing complete] ## Tests ### 1. Cold Start Smoke Test expected: Stop any running services. Run `docker compose up -d --build`. All services (backend, celery-worker, celery-beat, postgres, minio, redis, loki, promtail, grafana) start without errors. `curl -sf http://localhost:8000/health` returns a 200 response. result: pass ### 2. X-Correlation-ID response header expected: Make any authenticated API request (e.g. `curl -si http://localhost:8000/health`). The response headers include `x-correlation-id: `. Make a second request — the header value is different (new UUID per request). result: pass ### 3. JSON structured logging expected: Set LOG_JSON=true in the backend service (or `.env`), restart backend. Then call an endpoint and check `docker compose logs backend`. Log lines should be valid JSON objects containing an "event" key (e.g. `{"event": "...", "level": "info", "correlation_id": "...", ...}`). result: pass ### 4. Grafana accessible expected: After `docker compose up`, navigate to http://localhost:3000 in a browser (or run `curl -sf http://localhost:3000/api/health`). Grafana loads and the health endpoint returns JSON with `"database": "ok"`. result: pass ### 5. Loki ready expected: Run `curl -sf http://localhost:3100/ready`. Response body is `ready` and the command exits 0. result: pass ### 6. Container runs as non-root (appuser) expected: Run `docker compose exec backend id`. Output shows `uid=1000(appuser)` — NOT uid=0 (root). The multi-stage hardened Dockerfile creates appuser with uid=1000. result: pass ### 7. Read-only rootfs + writable /tmp expected: Run `docker compose exec backend sh -c 'touch /readonly_probe 2>&1 || echo "rootfs is read-only"'`. Output contains "read-only". Then run `docker compose exec backend sh -c 'touch /tmp/ok && echo "tmp writable"'`. Output contains "tmp writable" (the tmpfs mount works). result: pass ### 8. Per-account rate limiting (429 after 100 req/min) expected: Log in as a regular user. Send 101+ rapid requests to `GET /api/documents/` (e.g. with a loop or ab/curl). The 101st request (or shortly after) returns HTTP 429 with a rate-limit error. A different user account is NOT affected by the first user hitting the limit. result: pass ## Summary total: 8 passed: 8 issues: 0 pending: 0 skipped: 0 blocked: 0 ## Gaps [none yet]