ddaf3c6cee
- Add JWT token auth to OPC WebSocket (unauthenticated → 403, per-user tracking) - Externalize Transmission RPC credentials to TRANSMISSION_USER/PASS env vars - Remove hardcoded SECRET_KEY fallback from dev compose - Rate-limit passkey register options endpoint at 5/minute - Add PDD (docs/improvement-plan.md) and sprint specs (specs/) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
97 lines
4.2 KiB
Markdown
97 lines
4.2 KiB
Markdown
# Sprint 05 — Operations & Resilience
|
|
|
|
**Depends on:** S04 (CI must be reliable before automating ops)
|
|
**Duration:** ~12h
|
|
**Goal:** Add health checks, resource limits, log rotation, fix Immich uploads, back up dashboard data, add monitoring endpoint.
|
|
|
|
---
|
|
|
|
## S05.1 — Add HEALTHCHECK to claude-dev image
|
|
|
|
- **Files:** `claude-dev/Dockerfile`, `claude-dev/docker-compose.yml`
|
|
- **Estimate:** 1h
|
|
- **Done means:** Dockerfile has `HEALTHCHECK --interval=30s --timeout=5s --retries=3 CMD claude --version || exit 1`. `docker ps` shows healthy.
|
|
- **Verify by:**
|
|
1. Deploy claude-dev → `docker ps` shows "(healthy)"
|
|
2. Break `claude` binary → container shows "(unhealthy)" after 3 failures
|
|
- **Risk:** `claude --version` may require network access. Test on NAS first. Alternative: `pgrep -f claude` or simple `curl localhost:<port>`.
|
|
|
|
- [ ] S05.1 — Add HEALTHCHECK to claude-dev image
|
|
|
|
## S05.2 — Add resource limits to production containers
|
|
|
|
- **Files:** `claude-dev/docker-compose.yml`, `dashboard/docker-compose.yml`
|
|
- **Estimate:** 1.5h
|
|
- **Done means:** Production compose files have `mem_limit`, `cpus`, and `restart_policy`. Limits are generous: 2GB dashboard, 1GB claude-dev, 0.5GB sidecars.
|
|
- **Verify by:**
|
|
1. `docker stats` shows containers respecting limits
|
|
2. Normal operation unaffected
|
|
3. `docker compose up -d` applies limits without restarting
|
|
- **Risk:** Limits too tight → OOM kills. Start generous, adjust after a week of monitoring.
|
|
|
|
- [ ] S05.2 — Add resource limits to production containers
|
|
|
|
## S05.3 — Implement audit log rotation
|
|
|
|
- **Files:** `dashboard/backend/main.py:161,171-188`
|
|
- **Estimate:** 2h
|
|
- **Done means:** Audit logging uses `RotatingFileHandler` with max 10MB and 5 backups.
|
|
- **Verify by:**
|
|
1. Write 11MB of audit entries → file rotates, `audit.log.1` created
|
|
2. Original `audit.log` starts fresh
|
|
3. Old backups capped at 5 files
|
|
- **Risk:** Log format change may affect parsing in `system.py:82-116`. Test the log reader with rotated files.
|
|
|
|
- [ ] S05.3 — Implement audit log rotation
|
|
|
|
## S05.4 — Fix Immich ML model downloads
|
|
|
|
- **Files:** `immich/docker-compose.yml`, `immich/.env`
|
|
- **Estimate:** 3h (investigation + fix)
|
|
- **Done means:** Immich mobile upload works. ML models download successfully or ML is gracefully disabled.
|
|
- **Verify by:**
|
|
1. Upload photo from phone → succeeds (no timeout)
|
|
2. `ssh nas "docker logs immich_machine_learning"` → no "Failed to load detection model" errors
|
|
3. If ML disabled: photo upload works, smart search unavailable (acceptable)
|
|
- **Risk:** Most complex item. May require pre-downloading models, configuring mirror, increasing timeouts, or disabling ML temporarily. Environment-specific (China network to modelscope.cn).
|
|
|
|
- [ ] S05.4 — Fix Immich ML model downloads
|
|
|
|
## S05.5 — Add dashboard data to backup script
|
|
|
|
- **Files:** `backup.sh`
|
|
- **Estimate:** 1.5h
|
|
- **Done means:** `backup.sh` copies `opc.db`, `auth.json`, `rbac.json`, and audit log to backup tarball. Restore procedure documented.
|
|
- **Verify by:**
|
|
1. Run `backup.sh` → tarball contains dashboard data files
|
|
2. Extract tarball → files are valid (SQLite DB opens, JSON parses)
|
|
- **Risk:** `auth.json` contains passkey data — ensure backup stored securely.
|
|
|
|
- [ ] S05.5 — Add dashboard data to backup script
|
|
|
|
## S05.6 — Add minimal health check endpoint
|
|
|
|
- **Files:** `dashboard/backend/main.py` or `routers/health.py`
|
|
- **Estimate:** 1h
|
|
- **Done means:** `GET /api/health` returns `{"status":"ok","db":true,"docker":true,"disk":{"free_gb":123}}`. Non-200 triggers optional Telegram notification.
|
|
- **Verify by:**
|
|
1. All services healthy → `/api/health` returns 200
|
|
2. Docker socket unreachable → returns 503 with `docker: false`
|
|
3. Cron job calls `/api/health` every 5 minutes
|
|
- **Risk:** Health endpoint must be lightweight. Cache results for 30 seconds.
|
|
|
|
- [ ] S05.6 — Add minimal health check endpoint
|
|
|
|
---
|
|
|
|
## Exit criteria
|
|
|
|
- [ ] `docker ps` shows claude-dev as "(healthy)"
|
|
- [ ] Production containers have CPU/memory limits in compose
|
|
- [ ] Audit log rotates at 10MB with 5 backups
|
|
- [ ] Photo upload from phone succeeds
|
|
- [ ] `backup.sh` includes dashboard data files
|
|
- [ ] `GET /api/health` returns component statuses
|
|
- [ ] All backend tests pass
|
|
- [ ] All frontend tests pass
|