Update official docs: API guide v2.0, architecture with new components
This commit is contained in:
+98
-40
@@ -1,60 +1,118 @@
|
||||
# Architecture Technique - Imago Hub
|
||||
# Architecture Technique — Imago Hub v2.0.0
|
||||
|
||||
Ce document détaille l'architecture logicielle, les flux de données et les choix technologiques d'Imago Hub. Il s'adresse aux développeurs, architectes et contributeurs du projet.
|
||||
Ce document détaille l'architecture logicielle, les flux de données et les choix technologiques.
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ 1. Vue d'Ensemble des Composants
|
||||
## 1. Vue d'Ensemble
|
||||
|
||||
Imago s'articule autour de plusieurs services distincts orchestrés via Docker, communiquant par des interfaces asynchrones et résilientes.
|
||||
|
||||
### La Stack Technique
|
||||
- **Backend API Layer :** `FastAPI` (Python 3.10+) pour des performances maximales, des endpoints asynchrones (`async/await`) et une validation native (Pydantic). L'API répond vite, elle ne bloque jamais sur l'IO réseau.
|
||||
- **Frontend Admin :** `React` (JavaScript/TypeScript) propulsé par Vite et servi via Nginx. Interface Single-Page minimaliste, rapide.
|
||||
- **Worker Queue :** `ARQ` (Async Redis Queue). Une alternative moderne s'appuyant sur l'Event Loop natif d'asyncio Python au lieu de frameworks lourds.
|
||||
- **Broker & Cache :** `Redis` stocke les jobs temporaires, limite les taux (Rate Limiting) et gère le pub/sub des requêtes websocket.
|
||||
- **Base de données :** `PostgreSQL` interrogé via `SQLAlchemy` (orm asynchrone : `asyncpg`).
|
||||
- **Objets & Médias :** `MinIO` implémentant le standard S3 (ou un volume filesystem classique) pour isoler les données binaires massives.
|
||||
| Composant | Technologie | Rôle |
|
||||
|---|---|---|
|
||||
| API Backend | FastAPI (Python 3.12+) + Uvicorn | Endpoints REST async, validation Pydantic |
|
||||
| Frontend Admin | React + TypeScript + Vite + Nginx | Interface d'administration |
|
||||
| Worker Queue | ARQ (Async Redis Queue) | Traitement asynchrone du pipeline AI |
|
||||
| Broker/Cache | Redis 7 | Jobs ARQ, Pub/Sub WebSocket, Rate Limiting, DLQ |
|
||||
| Base de données | PostgreSQL 16 + SQLAlchemy async | Données relationnelles, multi-tenant |
|
||||
| Stockage objets | MinIO (S3-compatible) ou stockage local | Fichiers binaires (images, thumbnails) |
|
||||
| Observabilité | structlog + Prometheus + Grafana | Logs structurés, métriques, dashboards |
|
||||
|
||||
---
|
||||
|
||||
## 🔄 2. Flux de Traitement Asynchrone (Le Pipeline)
|
||||
## 2. Flux de Traitement (Pipeline AI)
|
||||
|
||||
Toute la valeur d'Imago réside dans sa capacité à dépiler un flux lourd d'images de façon déconnectée des appels HTTP des utilisateurs finaux.
|
||||
```
|
||||
Client → POST /api/v1/images/upload
|
||||
→ Validation MIME + quota
|
||||
→ Sauvegarde fichier (S3 ou local) + thumbnail
|
||||
→ Insert BDD (status: PENDING)
|
||||
→ Enqueue job ARQ: process_image_task(image_id, client_id)
|
||||
→ Réponse 201 au client
|
||||
|
||||
### Chronologie d'un événement `Upload`
|
||||
1. Le client effectue un `POST /upload`. L'API FastAPI, en streaming mémoire, pousse l'image vers le backend de stockage (S3).
|
||||
2. L'API enregistre dans PostgreSQL l'image avec un statut `PENDING`.
|
||||
3. L'API publie un message **enqueue** vers ARQ/Redis : `analyse_image(db_id=124)`.
|
||||
4. L'API répond immédiatement au client HTTP avec `202 Accepted` et l'UUID généré.
|
||||
Worker ARQ (processus séparé):
|
||||
→ status: PROCESSING
|
||||
→ Étape 1: EXIF (piexif) → métadonnées appareil, GPS
|
||||
→ Étape 2: OCR (Tesseract) → texte + fallback AI OCR
|
||||
→ Étape 3: Vision AI (Gemini/OpenRouter) → description, tags
|
||||
→ status: DONE (ou ERROR si échec après N tentatives)
|
||||
→ Publication Redis Pub/Sub → WebSocket clients
|
||||
```
|
||||
|
||||
### Boucle du Worker ARQ (processus séparé)
|
||||
Une fois le message attrapé par le démon `worker.py` :
|
||||
1. **Verrouillage** : Le statut passe à `PROCESSING`.
|
||||
2. **Étape EXIF** : (via `exifread` / modules Python) analyse purement metadata, parse le GPS et écrit dans les tables reliées.
|
||||
3. **Étape OCR** : Tesseract est encapsulé. Il scanne l'image et met à jour l'entité PostgreSQL.
|
||||
4. **Étape IA Vision** : Un client HTTP asynchrone (`httpx`) effectue un appel API vers Google (Gemini) ou OpenRouter. Une demande de structuration en prompt pur JSON assure des typages clairs.
|
||||
5. **Clôture** : Le statut passe à `COMPLETED`.
|
||||
|
||||
*(En cas d'échec sur une étape isolée comme le réseau IA, le worker utilise la retry-policy asynchrone native d'ARQ).*
|
||||
**Résilience :**
|
||||
- Chaque étape est indépendante — un échec partiel n'arrête pas le pipeline
|
||||
- Circuit breaker AI : timeout configurable + retry exponentiel
|
||||
- Dead Letter Queue : jobs échoués après `PIPELINE_MAX_RETRIES` → Redis DLQ inspectable
|
||||
|
||||
---
|
||||
|
||||
## 🗄️ 3. Modèle de Données & Multi-tenancy
|
||||
## 3. Modèle de Données
|
||||
|
||||
La BDD relationnelle s'articule pour cloisonner (isolation de locataire) les données de façon logicielle :
|
||||
### Table `api_clients`
|
||||
- `id` (UUID), `name`, `api_key_hash` (SHA-256 + pepper)
|
||||
- `scopes` (JSON), `plan` (free/standard/premium)
|
||||
- `storage_used_bytes`, `quota_storage_mb`, `quota_images`
|
||||
- `is_active` (soft delete)
|
||||
|
||||
- **Table Clients** : Représente le "Tenant". Un Client possède plusieurs clés API hashées (Bcrypt) et un "plan" définissant ses quotas.
|
||||
- **Table Image** : Clé principale. Chaque Image possède une `client_id` liant la ressource directement au Tenant. C'est l'essence du filtrage (Aucune requête RDBM vers Images ne démarre sans `WHERE client_id = X`).
|
||||
- **Tables Satellites (Exif, OCR, AITasks)** : Héritent des dépendances (Cascade Deletes) liant l'information technique à l'uuid Image.
|
||||
|
||||
### Le Rate Limiting Distribué
|
||||
Le limiter applicatif s'appuie sur `slowapi` et le backend Redis. L'ID du tenant (Client Object) sert de clé dans Redis pour évaluer le bucket algorithmique :
|
||||
- Permet de bloquer avant l'appel FastAPI les clients abusifs en respectant strictement l'architecture distribuée.
|
||||
### Table `images`
|
||||
- `id`, `uuid`, `client_id` → isolation multi-tenant
|
||||
- `original_name`, `file_path`, `thumbnail_path`, `mime_type`, `file_size`
|
||||
- `processing_status` (pending/processing/done/error)
|
||||
- **EXIF** : `exif_make`, `exif_model`, `exif_gps_lat/lon`, `exif_taken_at`, etc.
|
||||
- **OCR** : `ocr_text`, `ocr_language`, `ocr_confidence`
|
||||
- **AI** : `ai_description`, `ai_tags` (JSON), `ai_model_used`, `ai_prompt_tokens`, `ai_output_tokens`
|
||||
- Indexes composites : `(client_id, uploaded_at)`, `(client_id, processing_status)`
|
||||
|
||||
---
|
||||
|
||||
## 🔌 4. Observabilité et Temps Réel
|
||||
## 4. Sécurité
|
||||
|
||||
- **FastAPI Websockets Pub/Sub :** L'API monte des sessions WebSockets bidirectionnelles. Lors d'un changement dans PostgreSQL (Via un event déclenché par ARQ en fin de boucle), un hook publie un patch JSON aux websockets écoutants. L'UI (Shaarli / Admin) est ré-invalider sans actualisation HTTP.
|
||||
- **Prometheus Metrics :** Le endpoint `/metrics` expose via un middleware des données quantitatives brutes de latence et volumétries. Facilement gratté (scraped) par des tableaux Grafana ou Datadog.
|
||||
| Couche | Mécanisme |
|
||||
|---|---|
|
||||
| Authentification | API Key via `Authorization: Bearer <key>` ou `X-API-Key` |
|
||||
| Hashage | SHA-256 + pepper (SECRET_KEY) — comparaison timing-safe |
|
||||
| Master Key | `ADMIN_API_KEY` configurable, bypass BDD avec tous les droits |
|
||||
| Autorisation | Scopes obligatoires par endpoint (`require_scope("images:write")`) |
|
||||
| Validation | Scopes rejetés si invalides (`VALID_SCOPES`) |
|
||||
| Rate Limiting | slowapi par client_id + plan, stockage Redis optionnel |
|
||||
| CORS | Configurable, rejette `["*"]` si `allow_credentials=True` |
|
||||
| URLs signées | HMAC via itsdangerous (local) ou S3 presigned URLs |
|
||||
|
||||
---
|
||||
|
||||
## 5. Observabilité
|
||||
|
||||
- **structlog** : JSON en production, console colorée en dev. Trace ID (`X-Request-ID`) injecté.
|
||||
- **Prometheus** : `/metrics` — counters (uploads, tokens, erreurs), histograms (durée pipeline), gauges (stockage, WebSocket)
|
||||
- **Health checks** : `/health` (simple), `/health/detailed` (BDD, Redis, ARQ, MinIO, OCR, AI, worker)
|
||||
- **Grafana** : dashboard 10 panneaux fourni (`docs/grafana-dashboard.json`)
|
||||
|
||||
---
|
||||
|
||||
## 6. WebSocket — Temps Réel
|
||||
|
||||
- `/ws/pipeline/{image_id}?token=API_KEY` — événements live du pipeline
|
||||
- `/ws/admin/monitor?token=ADMIN_KEY` — monitoring global admin
|
||||
- Buffer Redis 60s (10 derniers événements) pour reconnexion
|
||||
- Pub/Sub Redis : `pipeline:{image_id}` et `pipeline:admin`
|
||||
|
||||
---
|
||||
|
||||
## 7. Infrastructure & Déploiement
|
||||
|
||||
### Développement local
|
||||
```bash
|
||||
docker compose up -d # PostgreSQL + Redis + MinIO + API + Worker
|
||||
```
|
||||
|
||||
### Production (serveur lab)
|
||||
L'image est poussée vers le registry local :
|
||||
```
|
||||
docker-registry.dev.home:5000/imago-backend:latest
|
||||
```
|
||||
Déploiement : `docker-compose.production.yml` + `.env.production`
|
||||
|
||||
### Build & Push
|
||||
```powershell
|
||||
cd docker
|
||||
.\build-img.ps1 # Build via WSL Debian
|
||||
.\deploy-img.ps1 # Push vers registry (semver auto)
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user