docs: réaligne la documentation sur l'état livré au gel

Trois environnements et un frontal SNI au lieu de deux, certificats Let's
Encrypt par DNS-01, sept DAGs, index des ADR complété jusqu'à 0020. Les
exemples de l'ETL passent en bash et n'utilisent plus l'option --limit,
retirée. L'adresse de la machine est masquée dans l'arbre, les ADR 0009 et
0014 portent une note datée sur l'approbation de la production.
This commit is contained in:
Johan LEROY
2026-09-24 15:55:08 +02:00
parent 9f343e9f42
commit 9ee0de9d55
25 changed files with 315 additions and 212 deletions
+66 -53
View File
@@ -1,4 +1,4 @@
# Pipeline ETL — EnerVision
# Pipeline ETL · EnerVision
## Objectif
@@ -236,11 +236,11 @@ apps/backend/
exécuter :
```powershell
uv run python -m app.etl.historical_import `
--csv ..\..\data\raw\all_sites_combined.csv `
--metadata ..\..\data\raw\dataset_metadata.json `
--source-timezone UTC `
```bash
uv run python -m app.etl.historical_import \
--csv ../../data/raw/all_sites_combined.csv \
--metadata ../../data/raw/dataset_metadata.json \
--source-timezone UTC \
--dry-run
```
@@ -250,10 +250,10 @@ Aucune donnée n'est écrite dans la base pendant cette exécution.
Depuis `apps/backend/` :
```powershell
uv run python -m app.etl.historical_import `
--csv ..\..\data\raw\all_sites_combined.csv `
--metadata ..\..\data\raw\dataset_metadata.json `
```bash
uv run python -m app.etl.historical_import \
--csv ../../data/raw/all_sites_combined.csv \
--metadata ../../data/raw/dataset_metadata.json \
--source-timezone UTC
```
@@ -303,7 +303,7 @@ Une nouvelle exécution du même import ne crée donc pas de mesures supplément
Depuis la racine du projet, vérifier le nombre d'enregistrements avec :
```powershell
```bash
docker compose exec db psql -U enervision -d enervision -c "SELECT COUNT(*) AS datasets FROM dataset; SELECT COUNT(*) AS sites FROM site; SELECT COUNT(*) AS readings FROM reading;"
```
@@ -317,7 +317,7 @@ readings = 122647
Vérifier la source des mesures avec :
```powershell
```bash
docker compose exec db psql -U enervision -d enervision -c "SELECT source, COUNT(*) FROM reading GROUP BY source ORDER BY source;"
```
@@ -384,7 +384,9 @@ end_time
limit
```
Le paramètre `limit` doit être compris entre 1 et 1000.
Le paramètre `limit` doit être compris entre 1 et 1000. Il n'est plus fourni par l'appelant :
`limit_for_window()` le dérive de la fenêtre demandée, pour obtenir une lecture par heure,
alignée sur l'heure pile.
### Configuration de l'API Mock
@@ -485,8 +487,13 @@ data_quality = "degraded"
L'import ne s'interrompt pas pour autant : le mock émet des anomalies par construction, et
`raw_data` conserve la réponse d'origine.
La taille des réponses est plafonnée : au plus `MAX_SITES` sites, et au plus `--limit` mesures
par site. Au-delà, l'import échoue au lieu de charger.
La taille des réponses est plafonnée : au plus `MAX_SITES` sites, et au plus `limit` mesures par
site, une par heure de la fenêtre (`limit_for_window()`). Au-delà, l'import échoue au lieu de
charger.
L'import refuse aussi une fenêtre qui recouvre le dataset historique
(`refuse_if_overlaps_historical_dataset()`) : le CSV couvre 2023 et 2024, une fenêtre de l'API Mock
doit donc commencer après le 31/12/2024, et démarrer pile sur une heure.
Enfin, seuls les champs attendus sont recopiés vers la base. Une clé supplémentaire renvoyée par
l'API n'atteint jamais une colonne.
@@ -495,30 +502,36 @@ l'API n'atteint jamais une colonne.
Le mode `--dry-run` permet de tester la connexion, la récupération des sites et la récupération des mesures sans écrire dans PostgreSQL.
Depuis `apps/backend/` :
Depuis `apps/backend/`, sur une fenêtre de deux heures postérieure au dataset historique (une
lecture par heure et par site) :
```powershell
uv run python -m app.etl.mock_api_import `
--start-time "2024-06-15T12:00:00" `
--end-time "2024-06-15T13:00:00" `
--limit 60 `
```bash
uv run python -m app.etl.mock_api_import \
--start-time "2026-09-24T08:00:00" \
--end-time "2026-09-24T10:00:00" \
--dry-run
```
Les heures sans fuseau sont lues en UTC. Seuls `--start-time`, `--end-time` et `--dry-run`
existent.
### Chargement réel depuis l'API Mock
Depuis `apps/backend/` :
```powershell
uv run python -m app.etl.mock_api_import `
--start-time "2024-06-15T12:00:00" `
--end-time "2024-06-15T13:00:00" `
--limit 60
```bash
uv run python -m app.etl.mock_api_import \
--start-time "2026-09-24T08:00:00" \
--end-time "2026-09-24T10:00:00"
```
### Résultat validé pour l'API Mock
En fonctionnement normal, cet import n'est pas lancé à la main : le DAG `mock_api_import` le
joue chaque heure (voir la fin de ce document).
Le scénario de validation utilisé couvre la période :
### Validation initiale du 18/09, antérieure à la réconciliation
Le premier scénario de validation, joué le 18/09 avant la clôture de la réconciliation (#15),
couvrait la période :
```text
15/06/2024 12:00 UTC
@@ -526,9 +539,11 @@ Le scénario de validation utilisé couvre la période :
15/06/2024 13:00 UTC
```
avec une limite de 60 lectures par site.
avec une limite de 60 lectures par site. Il ne se rejoue plus tel quel : depuis le 23/09, cette
fenêtre est refusée parce qu'elle recouvre le dataset historique, et l'option `--limit` a disparu
au profit d'une lecture par heure.
Résultat obtenu :
Résultat obtenu à l'époque :
```text
sites récupérés : 7
@@ -581,7 +596,8 @@ Les tests de l'import API Mock couvrent notamment :
- la récupération des sites ;
- l'appel à `/api/v1/readings` ;
- les paramètres `site_id`, `start_time`, `end_time` et `limit` ;
- les paramètres `site_id`, `start_time`, `end_time` et `limit`, dérivé de la fenêtre ;
- le refus d'une fenêtre qui recouvre le dataset historique ;
- la gestion des erreurs HTTP ;
- la validation du format de la réponse ;
- la transformation des mesures ;
@@ -594,48 +610,43 @@ Les tests de l'import API Mock couvrent notamment :
Exécuter les tests ETL :
```powershell
uv run pytest tests\etl -v
```bash
uv run pytest tests/etl -v
```
Exécuter les tests unitaires de l'import API Mock :
```powershell
uv run pytest tests\etl\test_mock_api_import.py -v
```bash
uv run pytest tests/etl/test_mock_api_import.py -v
```
Exécuter le test d'intégration de l'import API Mock :
```powershell
uv run pytest tests\etl\test_mock_api_import.py -m integration -v
```bash
uv run pytest tests/etl/test_mock_api_import.py -m integration -v
```
Contrôler la qualité du code :
```powershell
uv run ruff check app\etl tests\etl
```bash
uv run ruff check app/etl tests/etl
```
Contrôler le typage :
```powershell
```bash
uv run mypy app
```
Exécuter la suite complète avec le seuil de couverture :
```powershell
```bash
uv run pytest --cov-fail-under=85
```
Lors de la validation de l'import API Mock :
```text
8 tests unitaires passés
1 test d'intégration passé
```
La suite backend complète a également été validée avec une couverture supérieure au seuil de 85 %.
Lors de la première validation, le 18/09, le fichier comptait 8 tests unitaires et 1 test
d'intégration. Il en compte aujourd'hui 42, dont 2 d'intégration (`pytest --collect-only`), après
l'ajout des bornes physiques, de la réconciliation et de l'alignement horaire.
## Suite du pipeline Data
@@ -663,10 +674,12 @@ mock_api_import.py
La logique d'extraction, de transformation et de chargement est donc disponible pour les deux sources de données du MVP.
Airflow tourne désormais réellement (`etl/airflow/`, `make airflow-up`) et orchestre cinq DAGs :
Airflow tourne désormais réellement (`etl/airflow/`, `make airflow-up`) et orchestre sept DAGs :
le pipeline ML (`ml_train` et `ml_score`, issue #115), la détection d'alertes et la génération
des recommandations (`alertes`, issue #116), l'import historique (`historical_import`,
issue #119) et l'import périodique de l'API Mock (`mock_api_import`, issue #15).
issue #119), l'import périodique de l'API Mock (`mock_api_import`, issue #15), la surveillance
de dérive du modèle (`derive`, ADR 0013) et la rétention des relevés, exportés vers Garage puis
supprimés (`retention`, issue #36, ADR 0019).
Le DAG `mock_api_import` s'exécute chaque heure, à la minute `:45`, sur une fenêtre qui part de
l'heure pile précédant son déclenchement jusqu'à l'instant du déclenchement lui-même (pas
@@ -681,7 +694,7 @@ Les deux pipelines normalisent leurs données vers les tables communes `site` et
conservant leur source (`csv` ou `api_history`). La réconciliation entre les deux sources
(issue #15) est close : voir `docs/architecture/40-data.md`.
Airflow permet de planifier les traitements, gérer leur ordre d'exécution, suivre leur état et remonter les erreurs. Il ne remplace pas la logique ETL Python existante : les scripts actuels restent responsables de l'extraction, de la validation, de la transformation et du chargement. `etl/airflow/dags/ml_train.py`, `ml_score.py`, `alertes.py`, `historical_import.py` et
`mock_api_import.py` montrent le patron retenu (des `BashOperator` qui invoquent le script tel quel, dans l'environnement `uv` que l'image embarque pour lui).
Airflow permet de planifier les traitements, gérer leur ordre d'exécution, suivre leur état et remonter les erreurs. Il ne remplace pas la logique ETL Python existante : les scripts actuels restent responsables de l'extraction, de la validation, de la transformation et du chargement. `etl/airflow/dags/ml_train.py`, `ml_score.py`, `alertes.py`, `historical_import.py`,
`mock_api_import.py`, `derive.py` et `retention.py` montrent le patron retenu (des `BashOperator` qui invoquent le script tel quel, dans l'environnement `uv` que l'image embarque pour lui).
Le pipeline Data servira ensuite à préparer les données nécessaires au modèle de Machine Learning.