feat(backend): moteur de règles de recommandations et route de génération

`recommendation` n'avait aucun écrivain : les quatre couches de lecture étaient
livrées, mais rien ne produisait de ligne. Le moteur comble ce trou.

Le catalogue `REGLES` vit dans `app/services/`, pas dans `ml/` : il lit `alert.type`,
`alert.severity`, `alert.value` et `alert.threshold`, sans modèle ni feature, et
s'appuie sur deux repositories existants. L'arbitrage avec l'ADR 0005, qui annonçait
#38 du côté ML, est tranché par l'ADR 0006.

Sept règles, cinq par type d'alerte et deux transverses (sévérité critique,
dépassement d'au moins 20 % du seuil), donc une à trois recommandations par alerte.
L'idempotence est portée par la base : `create_missing()` insère en
`ON CONFLICT DO NOTHING` sur `uq_recommendation_alert_rule`, ce qui supprime la
fenêtre entre un contrôle préalable et l'insertion. `rule_reference` devient de ce
fait une clé fonctionnelle, d'où le suffixe de version sur chaque référence.

Deux déclencheurs : `POST /api/v1/recommendations/generate` réservé `admin`, et
`python -m app.cli generate-recommendations` (cible `make recommendations`).

Limite connue : aucune source n'alimente `alert` aujourd'hui, ni détection interne
(#104) ni ingestion de l'API Mock. La route répond, le rapport reste à zéro, et la
chaîne s'allume sans retoucher le moteur le jour où les alertes existent.

Tests : 80 unitaires et API verts, plus 6 d'intégration dont l'idempotence jouée
contre PostgreSQL.

Closes #38
This commit is contained in:
Johan LEROY
2026-09-18 15:49:54 +02:00
parent 619024f547
commit aeb07e14db
21 changed files with 854 additions and 23 deletions
+5
View File
@@ -165,3 +165,8 @@ Elles vivent dans `../adr/`, pas ici.
| ADR | Objet |
|---|---|
| [0001](../adr/0001-postgresql-timescaledb.md) | PostgreSQL 17 avec l'extension TimescaleDB, et la frontière `db/` vs `alembic/` |
| [0002](../adr/0002-authentification-jwt-et-refresh-opaque.md) | Authentification par JWT d'accès et jeton de rafraîchissement opaque |
| [0003](../adr/0003-autorisation-rbac-a-trois-roles.md) | Autorisation RBAC à trois rôles, avec relecture du compte à chaque requête |
| [0004](../adr/0004-journal-d-audit-en-ajout-seul.md) | Journal d'audit en ajout seul, garanti par PostgreSQL |
| [0005](../adr/0005-modele-prediction-lightgbm.md) | Modèle de prédiction de consommation : LightGBM |
| [0006](../adr/0006-moteur-de-regles-dans-le-backend.md) | Le moteur de règles de recommandation vit dans le backend, pas dans `ml/` |