ADR-0002 — Comment le backend consomme actuariat_lib¶
| Statut | ✅ Accepté — 2026-06-09 |
| Portée | backend/ (FastAPI), packaging d'image Docker, déploiement Dokploy |
| Décision | Installer la lib depuis les sources ; contexte de build Docker = racine du repo |
| Contexte méthode | Temps 3 « construire » de la méthode à 4 temps — brancher le moteur en service |
🎯 À retenir
Le backend installe actuariat_lib depuis les sources du monorepo, avec le contexte de build Docker placé à la racine du dépôt (context: ., dockerfile: backend/Dockerfile). Source unique, sync automatique lib ↔ backend, aucune infra de registre. Bascule vers un index privé seulement quand un 2ᵉ module consommera la lib.
Contexte¶
Le moteur DBO (dbo_population_puc) vit dans actuariat_lib (src/actuariat_lib/, couche
pure, validée par les oracles K1/K1-bis). Le backend FastAPI (backend/app/) expose la
route POST /api/dbo qui traduit un payload JSON en HypothesesActuarielles, charge la
table réglementaire (ADR-0001) et appelle le moteur — il ne recalcule rien.
Pour que la route fonctionne, l'image Docker du backend doit contenir actuariat_lib. Or le
service backend se construisait avec build: ./backend : le contexte Docker est ./backend,
alors que la lib vit dans ./src — hors contexte. Un simple import ne suffit pas ; il faut
décider comment l'image récupère la lib.
Deux contraintes transverses pèsent :
- Monorepo — lib et backend vivent dans le même dépôt, versionnent, se testent et se
déploient ensemble (Dokploy rebuild
devà chaque push). - Pureté de la lib —
actuariat_libne doit acquérir aucune dépendance vers le backend. Le branchement doit rester unidirectionnel (backend → lib).
Options considérées¶
- A — Install depuis les sources : contexte de build = racine, le Dockerfile fait
COPY pyproject.toml srcpuispip install .. Une seule source de vérité : la source du repo. - B — Wheel vendoré : builder
actuariat_lib-1.1.0-py3-none-any.whl, le déposer dansbackend/vendor/, le pointer depuisrequirements.txt. Contexte de build inchangé (./backend). - C — Index privé : publier la lib sur un index (PyPI privé / registre), l'épingler par
version dans
requirements.txt.
Comparatif pour / contre¶
| Critère | A — Install depuis source | B — Wheel vendoré | C — Index privé |
|---|---|---|---|
| Source unique de vérité | ✅ la source du monorepo | ❌ wheel = copie à régénérer | ✅ une version publiée |
| Sync lib ↔ backend | ✅ automatique | ❌ manuelle (rebuild+revendor à chaque évol.) | ⚠️ via bump de version |
| Artefact binaire en git | ✅ aucun | ❌ .whl committé |
✅ aucun |
| Cohérence avec le repo | ✅ le service docs est déjà en context: . |
❌ romprait l'idiome | ⚠️ neutre |
| Pureté de la lib (unidirectionnel) | ✅ backend → lib | ✅ backend → lib | ✅ backend → lib |
| Couplage des cadences | ❌ lib et backend bumpent ensemble | ✅ découplés | ✅ découplés |
| Infra nécessaire aujourd'hui | ✅ nulle | ✅ nulle | ❌ registre + publication + auth |
| Réutilisation multi-modules | ⚠️ couplée à ce repo | ⚠️ chacun re-vendore | ✅✅ conçue pour ça |
| Risque de dérive silencieuse | ✅ nul (toujours la source) | ❌ wheel périmé non détecté | ✅ version explicite |
| Build offline / reproductible | ✅ (sources locales) | ✅ (wheel local) | ❌ dépend du registre |
Décision¶
Option A — installer la lib depuis les sources, en passant le contexte de build du service
backend à la racine du dépôt (build: { context: ., dockerfile: backend/Dockerfile }).
Justification. C'est un monorepo : lib et backend versionnent, se déploient et évoluent
ensemble. La source unique est le modèle honnête — pas de wheel à re-synchroniser à la main
(B, source de dérive silencieuse), pas d'infra de registre à monter (C, cérémonie
prématurée). A s'aligne en plus sur l'idiome déjà présent dans le repo : le service docs
se construit lui aussi avec context: .. B et C sont les bonnes réponses le jour où la
lib devient un artefact indépendant consommé par un autre module — c'est exactement le
déclencheur A→C déjà pré-enregistré dans l'ADR-0001.
Conséquences¶
- Dockerfile backend (
backend/Dockerfile) : chemins relatifs à la racine désormais.COPY pyproject.toml src+pip install .(couche dédiée, mise en cache tant que la lib ne bouge pas ; embarque aussi les tables CIMA via lepackage-datad'ADR-0001), puisCOPY backend/requirements.txt+pip install -r, puisCOPY backend/app. - Compose :
docker-compose.ymletdocker-compose.dev.ymlpassent le servicebackendàbuild: { context: ., dockerfile: backend/Dockerfile }. .dockerignoreracine (nouveau, partagé par les buildsbackendetdocs) : exclut.venv, caches,frontend/node_modules,frontend/.next,references/,data/,refs/,.git,*.db.
⚠️ Piège
Le .dockerignore racine est partagé par les builds backend et docs. Ne pas exclure docs/, mkdocs.yml, requirements-docs.txt (le build docs en a besoin) ni pyproject.toml / src/ / backend/ (le build backend en a besoin) : une exclusion de trop casse silencieusement l'un des deux images.
- Dév local : la lib est installée éditable dans le venv du backend
(
uv pip install --python backend/.venv/bin/python -e .) →import actuariat_libimmédiat pour lancer/serveur et tests. - Validation : image construite en Docker réel ; à l'intérieur,
actuariat_libs'importe, la table CIMA charge, les 4 fichiers package-data sont présents, et la route reproduit l'oracle K1 = 2 751 205,018849 FCFA via HTTP (backend/tests/test_dbo.py).
Déclencheur de réexamen (pré-enregistré)¶
Dès qu'un 2ᵉ module Quantis consomme actuariat_lib, migrer A → C : publier la lib sur
un index privé et l'épingler par version (le même déclencheur que l'ADR-0001 sur les données).
Tant qu'actuariat_lib n'a qu'un consommateur (le backend ActuaryLab), A reste cohérent.