[AZ-172] Update documentation for distributed architecture, add Update Docs step to workflow

- Update module docs: main, inference, ai_config, loader_http_client
- Add new module doc: media_hash
- Update component docs: inference_pipeline, api
- Update system-flows (F2, F3) and data_parameters
- Add Task Mode to document skill for incremental doc updates
- Insert Step 11 (Update Docs) in existing-code flow, renumber 11-13 to 12-14

Made-with: Cursor
This commit is contained in:
Oleksandr Bezdieniezhnykh
2026-03-31 17:25:58 +03:00
parent e29606c313
commit 1fe9425aa8
12 changed files with 447 additions and 245 deletions
@@ -2,18 +2,18 @@
## Overview
**Purpose**: HTTP API layer exposing object detection capabilities via FastAPI — handles request/response serialization, async task management, SSE streaming, and authentication token forwarding.
**Purpose**: HTTP API layer exposing object detection capabilities via FastAPI — handles request/response serialization, async task management, SSE streaming, media lifecycle management, DB-driven configuration, and authentication token forwarding.
**Pattern**: Controller layer — thin API surface that delegates all business logic to the Inference Pipeline.
**Pattern**: Controller layer — thin API surface that delegates inference to the Inference Pipeline and manages media records via the Annotations service.
**Upstream**: Inference Pipeline (Inference class), Domain (constants_inf for labels).
**Upstream**: Inference Pipeline (Inference class), Domain (constants_inf for labels), Annotations service (AI settings, media records).
**Downstream**: None (top-level, client-facing).
## Modules
| Module | Role |
|--------|------|
| `main` | FastAPI app definition, endpoints, DTOs, TokenManager, SSE streaming |
| `main` | FastAPI app definition, endpoints, DTOs, TokenManager, SSE streaming, media lifecycle, DB-driven config resolution |
## External API Specification
@@ -24,6 +24,7 @@
{
"status": "healthy",
"aiAvailability": "Enabled",
"engineType": "onnx",
"errorMessage": null
}
```
@@ -31,7 +32,7 @@
### POST /detect
**Input**: Multipart form — `file` (image bytes), optional `config` (JSON string).
**Input**: Multipart form — `file` (image or video bytes), optional `config` (JSON string), optional auth headers.
**Response**: `list[DetectionDto]`
```json
[
@@ -46,14 +47,15 @@
}
]
```
**Errors**: 400 (empty image / invalid data), 422 (runtime error), 503 (engine unavailable).
**Behavior** (AZ-173, AZ-175): Accepts both images and videos. Detects upload kind by extension, falls back to content probing. If authenticated: computes content hash, persists to storage, creates media record, tracks status lifecycle (New → AI Processing → AI Processed / Error).
**Errors**: 400 (empty/invalid image data), 422 (runtime error), 503 (engine unavailable).
### POST /detect/{media_id}
**Input**: Path param `media_id`, optional JSON body `AIConfigDto`, headers `Authorization: Bearer {token}`, `x-refresh-token: {token}`.
**Response**: `{"status": "started", "mediaId": "..."}` (202-style).
**Errors**: 409 (duplicate detection for same media_id).
**Side effects**: Starts async detection task; results delivered via SSE stream and/or posted to Annotations service.
**Behavior** (AZ-174): Resolves media path and AI settings from Annotations service. Merges DB settings with client overrides. Reads file bytes from resolved path, dispatches `run_detect_image` or `run_detect_video`.
**Errors**: 409 (duplicate detection), 503 (media path not resolved).
### GET /detect/stream
@@ -66,9 +68,10 @@ data: {"annotations": [...], "mediaId": "...", "mediaStatus": "AIProcessing", "m
## Data Access Patterns
- In-memory state:
- `_active_detections: dict[str, bool]` — guards against duplicate media processing
- `_active_detections: dict[str, asyncio.Task]` — guards against duplicate media processing
- `_event_queues: list[asyncio.Queue]` — SSE client queues (maxsize=100)
- No database access
- Persistent media storage to `VIDEOS_DIR` / `IMAGES_DIR` (AZ-175)
- No direct database access — media records managed via Annotations service HTTP API
## Implementation Details
@@ -76,8 +79,10 @@ data: {"annotations": [...], "mediaId": "...", "mediaStatus": "AIProcessing", "m
- `ThreadPoolExecutor(max_workers=2)` runs inference off the async event loop
- SSE: one `asyncio.Queue` per connected client; events broadcast to all queues; full queues silently drop events
- `TokenManager` decodes JWT exp from base64 payload (no signature verification), auto-refreshes 60s before expiry
- `detection_to_dto` maps Detection fields to DetectionDto, looks up label from `constants_inf.annotations_dict`
- Annotations posted to external service with base64-encoded frame image
- `TokenManager.decode_user_id` extracts user identity from multiple JWT claim formats (sub, userId, nameid, SAML)
- DB-driven config via `_resolve_media_for_detect`: fetches AI settings from Annotations, merges nested sections and casing variants
- Media lifecycle: `_post_media_record` + `_put_media_status` manage status transitions via Annotations API
- Content hashing via `compute_media_content_hash` (XxHash64 with sampling) for media deduplication
## Caveats
@@ -88,6 +93,7 @@ data: {"annotations": [...], "mediaId": "...", "mediaStatus": "AIProcessing", "m
- SSE queue overflow silently drops events (QueueFull caught and ignored)
- JWT token handling has no signature verification — relies entirely on the Annotations service for auth
- No graceful shutdown handling for in-progress detections
- Media record creation failures are silently caught (detection proceeds regardless)
## Dependency Graph
@@ -96,6 +102,7 @@ graph TD
main --> inference
main --> constants_inf
main --> loader_http_client
main --> media_hash
```
## Logging Strategy