6.4 KiB
6.4 KiB
Plan : Architecture Simplification — 2 services (Vue + FastAPI/SQLite)
Objectif
Supprimer le backend Spring Boot (passe-plat) et PostgreSQL. Le document-parser Python absorbe toute la logique backend. On passe de 4 services à 2 services : Vue frontend + FastAPI Python.
Architecture Python — Clean Architecture légère
document-parser/
├── main.py # FastAPI app, CORS, lifespan, routers mount
├── bbox.py # (existant) coord conversion
├── test_bbox.py # (existant) bbox tests
├── requirements.txt # + aiosqlite, aiofiles
├── Dockerfile # (adapté)
├── .dockerignore # (existant)
│
├── domain/ # 🧠 Modèles métier purs (pas de dépendance framework)
│ ├── __init__.py
│ ├── models.py # Document, AnalysisJob, Status (dataclasses/Pydantic)
│ └── parsing.py # Logique d'extraction Docling (déplacée depuis main.py)
│
├── api/ # 🌐 Couche HTTP (FastAPI routers)
│ ├── __init__.py
│ ├── schemas.py # Pydantic request/response schemas (DTOs)
│ ├── documents.py # Router /api/documents (CRUD + upload + preview)
│ └── analyses.py # Router /api/analyses (CRUD + async processing)
│
├── persistence/ # 💾 Couche données (SQLite via aiosqlite)
│ ├── __init__.py
│ ├── database.py # SQLite connection, init schema, get_db()
│ ├── document_repo.py # CRUD documents
│ └── analysis_repo.py # CRUD analysis jobs
│
└── services/ # ⚙️ Orchestration (use cases)
├── __init__.py
├── document_service.py # Upload, delete, preview (file I/O + persistence)
└── analysis_service.py # Create job, background parse, update status
Pourquoi cette structure plutôt qu'hexagonale ?
- domain/ : modèles purs, testables, zéro import framework → l'esprit de l'hexagonale
- api/ : adaptateur HTTP (port entrant)
- persistence/ : adaptateur stockage (port sortant)
- services/ : orchestration des use cases
- Pas de ports/adapters formels (interfaces abstraites) → overkill pour le scope
- Un mec de Docling voit ça, il comprend en 5 secondes. Clean, pas over-engineered.
Endpoints conservés (contrat API identique)
Le frontend ne change quasiment pas — mêmes URLs, mêmes payloads :
| Method | Path | Description |
|---|---|---|
| POST | /api/documents/upload |
Upload PDF (multipart) |
| GET | /api/documents |
List documents |
| GET | /api/documents/{id} |
Get document |
| DELETE | /api/documents/{id} |
Delete document + file |
| GET | /api/documents/{id}/preview?page=&dpi= |
Page preview PNG |
| POST | /api/analyses |
Create analysis (body: {documentId}) |
| GET | /api/analyses |
List analyses |
| GET | /api/analyses/{id} |
Get analysis (polling) |
| DELETE | /api/analyses/{id} |
Delete analysis |
| GET | /health |
Health check |
Détails d'implémentation
1. SQLite (persistence/database.py)
aiosqlitepour async natif avec FastAPI- Schema identique au Liquibase actuel (2 tables: documents, analysis_jobs)
- DB file dans volume Docker :
/app/data/docling_studio.db - Init schema au startup (CREATE TABLE IF NOT EXISTS)
- Pas besoin d'Alembic pour un projet de cette taille
2. File storage
- Même logique :
./uploads/{uuid}_{filename} - Volume Docker monté sur
/app/uploads
3. Async analysis (services/analysis_service.py)
asyncio.create_task()pour le background processing (pas besoin de Celery)- Status polling identique : PENDING → RUNNING → COMPLETED | FAILED
- Le parse Docling tourne dans un thread via
asyncio.to_thread()(car bloquant + lock)
4. CORS
fastapi.middleware.cors.CORSMiddlewaredans main.py- Origins configurables via env var
5. domain/parsing.py
- Déplace depuis main.py :
_build_converter(),_get_element_type(),extract_pages_detail(),_process_content_item() - Le converter et le lock restent globaux (singleton pattern)
Changements Frontend
Minimes — seulement la configuration :
- vite.config.js : proxy target change
8081→8000 - frontend/Dockerfile (nginx) : proxy_pass change
backend:8081→document-parser:8000 - api.js : AUCUN changement (mêmes paths
/api/...) - stores : AUCUN changement
docker-compose.yml simplifié
services:
document-parser:
build: ./document-parser
ports:
- "8000:8000"
volumes:
- uploads_data:/app/uploads
- db_data:/app/data
deploy:
resources:
limits:
memory: 4g
frontend:
build: ./frontend
ports:
- "3000:80"
depends_on:
- document-parser
volumes:
uploads_data:
db_data:
→ Plus de postgres, plus de backend Java. 2 services, clean.
Étapes d'exécution
- Créer la structure Python (domain/, api/, persistence/, services/)
- persistence/database.py — SQLite async init + schema
- persistence/document_repo.py — CRUD documents
- persistence/analysis_repo.py — CRUD analyses
- domain/models.py — Dataclasses Document, AnalysisJob, Status
- domain/parsing.py — Extraire la logique Docling depuis main.py
- api/schemas.py — Pydantic DTOs (DocumentResponse, AnalysisResponse, etc.)
- services/document_service.py — Upload, delete, preview, list, get
- services/analysis_service.py — Create, run background, status tracking
- api/documents.py — Router documents (5 endpoints)
- api/analyses.py — Router analyses (4 endpoints)
- main.py — Réécrire : CORS, lifespan (DB init), mount routers
- requirements.txt — Ajouter aiosqlite, aiofiles
- docker-compose.yml — Simplifier (2 services)
- frontend/vite.config.js — Changer proxy target
- frontend/Dockerfile — Changer nginx proxy_pass
- Supprimer le dossier backend/ entier
- Mettre à jour README.md — Nouvelle architecture
Ce qu'on ne touche PAS
- bbox.py, test_bbox.py (inchangés)
- Toute la logique Vue (stores, components, pages)
- Logique Docling (parsing, extraction) — juste déplacée
- Dockerfile du parser (juste adapter le CMD si nécessaire)