Upgrade configuration and Docker stack to v2.0.0

This commit is contained in:
2026-06-22 14:49:56 -04:00
parent 2f2a5e9b4a
commit 0d2ecbd218
19 changed files with 779 additions and 495 deletions
+39 -1
View File
@@ -4,7 +4,45 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [Unreleased]
## [2.0.0] - 2026-06-22
### Security
- API Key hashing now uses SHA-256 + pepper (SECRET_KEY) with timing-safe comparison via `secrets.compare_digest()`
- CORS validation rejects `["*"]` when `allow_credentials=True` (Pydantic model_validator)
- Scope validation: `ClientCreate.scopes` rejects invalid values via `field_validator`
- Master key comparison uses constant-time compare
### Added
- **Dead Letter Queue (DLQ)**: Failed ARQ jobs pushed to Redis DLQ after `PIPELINE_MAX_RETRIES` attempts. Admin endpoints to list/retry/clear dead jobs (`GET/POST/DELETE /admin/api/queue/dead`)
- **Circuit Breaker AI**: All AI calls wrapped with `asyncio.wait_for()` + exponential backoff retry (configurable via `AI_REQUEST_TIMEOUT`, `AI_MAX_RETRIES`)
- **Request ID Middleware**: `X-Request-ID` header injected in all responses + bound to structlog context
- **Rate Limiting per Plan**: Dynamic rate limits based on client plan (free/standard/premium) via ContextVar
- **Redis Rate Limit Storage**: Optional persistence via `RATE_LIMIT_STORAGE_URL`
- **Worker script**: `worker.py` for standalone ARQ worker launch
- **Docker Compose stack**: PostgreSQL 16 + Redis 7 + MinIO + API + Worker
- **`.env.example`**: All configuration variables documented
- **Grafana Dashboard**: `docs/grafana-dashboard.json` with 10 panels (images, tokens, pipeline, storage, WebSocket, errors)
- **Database indexes**: Composite indexes `(client_id, uploaded_at)` and `(client_id, processing_status)` on images table
### Changed
- `APP_VERSION` aligned to `2.0.0` in config (was `1.0.0`)
- `delete_files()` now fully async — uses `await backend.delete()` instead of fire-and-forget `ensure_future()`
- Upload flow: files deleted on DB commit failure (no orphaned S3 files)
- Gemini client: cached with TTL — recreated if `GEMINI_API_KEY` changes
- `parse_redis_url()` extracted to `app/workers/redis_client.py` (DRY — was duplicated in main.py and image_worker.py)
- Rate limit key function encodes plan for per-plan bucket isolation
- `_FallbackArqPool` moved to `app/workers/arq_fallback.py` (avoids circular imports)
- ARQ worker: configurable `PIPELINE_TIMEOUT` and `PIPELINE_MAX_RETRIES`, `on_shutdown` handler
- Pipeline: `push_dead_job()` on final retry failure marks image as `ERROR` with DLQ metadata
- Admin panel: VITE_API_BASE_URL changed from internal Docker hostname to `http://localhost:8000`
### Fixed
- ARQ fallback now returns explicit warning in `UploadResponse.message` instead of silently ignoring
- Removed obsolete comment in `ai_vision.py` about `StorageBackend.read`
- Removed signal handler instability in test fixtures
- Fixed Docker Compose admin connectivity (browser couldn't resolve internal `backend` hostname)
## [1.0.0] - Previous
### Added (Phase 3: DX)
- **WebSockets / Real-Time**: