---
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: <UUID4>`. 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]
