LCL Rapports¶
Portail des rapports de contrôle qualité de LCL Environnement.
Les techniciens saisissent leurs relevés sur le terrain dans ODK Central (formulaires F1 à F7). Ce portail transforme ces soumissions en PDF, les classe par chantier, les rend consultables dans un site web, et alerte par courriel dès qu'un rapport révèle une non-conformité. Il reçoit aussi les rapports de laboratoire produits par LabTracker, une application distincte, et les range aux côtés des rapports de terrain.
flowchart TB
Terrain["Terrain<br/>(formulaires)"] --> ODK["ODK Central"]
ODK -->|"soumissions + entités (lecture)"| Generateur["Générateur PDF<br/>odk_reports/ (un module par rapport)"]
Generateur -->|"écrit rapports/<no projet>/*.pdf"| API["API Flask"]
LabTracker["Laboratoire (LabTracker)"] -->|POST| API
API -->|"courriel d'alerte (non-conformités)"| Alertes["Alertes"]
API -->|"/api/..."| Site["Site React<br/>consultation, téléchargement, réglages"]
Ce qu'il faut comprendre en premier¶
Il n'y a pas de base de données. Un « projet » est un dossier nommé
d'après son numéro ODK (rapports/CMC-1274-9623/), et un rapport est un
fichier PDF dedans. Tout l'état vit dans des fichiers JSON cachés à la racine
du dossier des rapports :
| Fichier | Rôle |
|---|---|
.generated.json |
Suivi incrémental : quelles soumissions sont déjà générées |
.projects.json |
Numéros de projets connus d'ODK, publiés par le générateur |
.received.json |
Index des rapports déposés par LabTracker |
.alertes.json |
Destinataires des alertes, modifiables depuis le site |
.alertes-envoyees.json |
Non-conformités déjà signalées, pour ne pas les répéter |
Rien ne tourne en arrière-plan. Aucun cron, aucun minuteur. Une génération part quand quelqu'un clique sur « Générer » dans le site (ou lance la commande sur le serveur). Les alertes sont donc aussi réactives que les générations, sauf celles des dépôts LabTracker, qui partent immédiatement.
ODK est la source de vérité. Les PDF générés sont reconstructibles à volonté. Les rapports reçus de LabTracker, eux, ne le sont pas : effacer le dossier des rapports les perdrait définitivement.
Organisation du dépôt¶
backend/
api_server.py API Flask : consultation, génération, réglages, proxy ODK
inbound_reports.py Réception des rapports LabTracker (POST /api/rapports)
odk_report_generator.py Point d'entrée du générateur (enveloppe mince)
odk_reports/ Le générateur — voir son propre README
Dockerfile Image de production
docker-compose.yml Déploiement (utilisé par Coolify)
frontend/
src/App.js L'application React (fichier unique)
tests/
golden/ 113 PDF de référence, un par cas couvert
compare_pdfs.py Compare les PDF régénérés aux références, au pixel
docs/ Décisions et contrats d'interface
Le générateur a sa propre documentation, plus détaillée : backend/odk_reports/README.md,
à lire avant d'ajouter ou de modifier un rapport.
Démarrer en local¶
Prérequis : Python 3.12, Node 20+, et un accès ODK si tu veux générer de vrais rapports.
Backend
cd backend && python -m venv venv && ./venv/Scripts/pip install -r requirements.txt
cd backend && RAPPORTS_DIR=../test-output ./venv/Scripts/python api_server.py
L'API écoute sur le port 5050. Sous Linux ou macOS, remplacer
./venv/Scripts/ par ./venv/bin/.
Frontend
cd frontend && npm install && npm start
Le site démarre sur le port 3000 et relaie /api vers le port 5050
(proxy dans package.json). L'écran de connexion demande des identifiants
ODK ; sans eux, tu peux quand même exercer l'API directement.
Générer des rapports
python backend/odk_report_generator.py --url https://odk.lclchantiers.com --email TON_EMAIL --password 'TON_MOT_DE_PASSE' --project 1 --output ./test-output
--form limite à un formulaire, --no-projet à un chantier, --force
ignore le suivi incrémental et régénère tout.
Tester¶
La suite compare les PDF régénérés aux 113 références de tests/golden/,
en les rendant à l'image et en mesurant l'écart au pixel :
python backend/odk_report_generator.py --url ... --output ./test-output --force
backend/venv/Scripts/python tests/compare_pdfs.py
Une différence signalée est soit une régression, soit un changement voulu. Dans le second cas, mettre à jour les références dans un commit séparé du changement de code, pour que l'historique reste lisible.
⚠️ Cette suite exige aujourd'hui un accès ODK : elle ne peut pas tourner en intégration continue. Remplacer l'appel à ODK par des données enregistrées est le prochain chantier, et il débloquerait une CI.
Configuration¶
Tout passe par des variables d'environnement ; aucun secret n'est versionné.
| Variable | Rôle |
|---|---|
RAPPORTS_DIR |
Où vivent les PDF (défaut /opt/odk-rapports/rapports) |
ODK_UPSTREAM |
Où l'API joint ODK Central |
ODK_HOST_HEADER |
En-tête Host envoyé à ODK derrière un proxy |
ODK_GENERATOR_URL |
URL d'ODK utilisée par le générateur |
PORTAL_PUBLIC_URL |
URL publique du portail, mise dans les liens sortants |
LABTRACKER_TOKEN |
Jeton de service attendu des dépôts LabTracker |
SMTP_HOST, SMTP_PORT, SMTP_SECURITY, SMTP_USER, SMTP_PASSWORD, SMTP_FROM |
Envoi des alertes |
Sans SMTP_HOST, aucune alerte n'est tentée. Sans LABTRACKER_TOKEN, tout
dépôt est refusé. C'est délibéré : un portail mal configuré doit fermer, pas
ouvrir.
Déployer¶
La production tourne sur un Droplet DigitalOcean, derrière Caddy géré par
Coolify (voir docs/migration-2026-05-07.md).
Le backend est conteneurisé : backend/docker-compose.yml, avec le dossier
des rapports monté depuis l'hôte pour survivre au conteneur.
Le frontend est encore servi en fichiers statiques par un mini-nginx et
demande un npm run build séparé. backend/install.sh est l'ancien
script d'installation (venv + systemd + nginx), conservé pour mémoire mais
plus utilisé : ne pas s'en servir.
Conventions¶
- Code et commentaires en anglais, chaînes visibles par l'utilisateur en français (étiquettes des PDF, messages de l'interface, journaux). Les noms de formulaires et de domaine (« planche de référence ») restent en français même dans un commentaire anglais.
- Un commentaire explique pourquoi, pas quoi : le code dit déjà quoi.
- Commits atomiques, mise à jour des PDF de référence séparée du code.
À savoir avant de modifier quoi que ce soit¶
Aucune authentification
L'API n'a aucune authentification hormis le jeton des dépôts LabTracker. Consultation, génération et réglages sont ouverts à qui atteint le portail.
- Le mot de passe ODK transite en argument de ligne de commande vers le
sous-processus du générateur, donc visible dans
ps. - Les PDF sont traités comme binaires (
.gitattributes) : sans ça, git réécrit les fins de ligne à l'intérieur et corrompt les références. - Un rapport ne doit jamais lire l'horloge. Son rendu doit dépendre de ses seules données, sinon il change tous les jours et devient intestable.