Compare commits

..
Author SHA1 Message Date
Johan LEROY 5e06b08546 docs(livrables): charte EnerVision sur les rapports EC02 et EC04, chaîne md2pdf versionnée
Les deux PDF sont régénérés avec la chaîne Markdown vers HTML vers CSS de pagination
vers PDF, désormais versionnée dans docs/livrables/outils (script, CSS, logo). Le CSS
reprend les tokens du frontend (vert primaire, neutres, Lato en substitut de Segoe UI,
tableaux sans filet vertical, badges d'état pour les marqueurs Prouvé, Constaté, Absent).

Le rapport collectif EC02 perd sa section « Écarts entre conception (EC01) et
réalisation » : les dossiers EC01 sont individuels et différents d'un membre à l'autre,
il n'existe pas une conception collective à comparer. Les sections suivantes sont
renumérotées ; le rapport passe de 12 à 10 pages.
2026-09-24 16:50:46 +02:00
Johan LEROYandGitHub 931ec9e527 Merge pull request #169 from ineszang/dev
Dev
2026-09-24 16:25:07 +02:00
Johan LEROYandGitHub c8eddbc02b Merge pull request #168 from ineszang/docs/livrables-gel
Rapport collectif EC02 présenté à l'échelle de l'équipe
2026-09-24 16:18:26 +02:00
Johan LEROYandGitHub 0a7dd2e692 Merge pull request #167 from ineszang/dev
Remontée dev vers main : livrables du gel
2026-09-24 16:08:45 +02:00
6 changed files with 108 additions and 39 deletions
@@ -258,43 +258,7 @@ imparti, et **RPA avancé**, au-delà de l'orchestration Airflow.
---
## 6. Écarts entre conception (EC01) et réalisation
Le guide d'évaluation le dit : **les écarts entre conception et réalisation font partie du
compte rendu d'activité**. Chaque écart ci-dessous porte sa trace.
| # | Choix du dossier EC01 (14/09) | Réalisé au gel | Verdict |
|---|---|---|---|
| 1 | FastAPI / Python pour l'API | FastAPI, contrat OpenAPI versionné et testé | ✅ Tenu |
| 2 | PostgreSQL 17 + TimescaleDB | Identique, relevés en hypertable (ADR 0001) | ✅ Tenu |
| 3 | JWT + Argon2id, RBAC à 3 rôles | Identique, plus rotation du jeton de rafraîchissement (ADR 0002, 0003) | ✅ Tenu |
| 4 | Une valeur nulle n'est jamais effacée | Qualité de donnée et imputation tracées, gravées par une contrainte `CHECK` | ✅ Tenu |
| 5 | Contrats d'interface figés | Contrat OpenAPI testé, table `prediction` comme frontière ML | ✅ Tenu |
| 6 | Docker Compose plutôt que Kubernetes | Compose, un projet par environnement (ADR 0009, 0017) | ✅ Tenu |
| 7 | On-premise plutôt que cloud public | Machine de l'école, aucune ressource cloud | ✅ Tenu |
| 8 | Traefik en terminaison TLS | Nginx par stack (ADR 0007) et frontal SNI (ADR 0018) | 🔁 Substitué |
| 9 | Prophet + IsolationForest | LightGBM, un modèle global (ADR 0005), alertes internes par règles, dérive surveillée (ADR 0013) | 🔁 Substitué |
| 10 | APScheduler pour l'ETL | Airflow, 7 DAGs : imports, entraînement, scoring, alertes, dérive, rétention | 🔁 Substitué |
| 11 | MinIO, couche bronze | Garage par environnement (ADR 0019) | 🔁 Substitué |
| 12 | Ansible, durcissement et déploiement | Terraform et script rejouable (ADR 0010) ; durcissement non automatisé | ⚠️ Partiel |
| 13 | SOPS + age pour les secrets | Secrets générés sur la machine, hors de Git | ❌ Non fait |
| 14 | Trivy, Bandit, gitleaks en CI | Bandit (#121) et un DAST ZAP non prévu (#140) ; Trivy et gitleaks hors CI | ⚠️ Partiel |
| 15 | Prometheus, Grafana, Loki | Prometheus, Alertmanager, Grafana actifs en production (ADR 0016) ; pas de Loki | ⚠️ Partiel |
| 16 | Runner auto-hébergé, déploiement automatique | `deploy.yml` sur runner auto-hébergé, sept déploiements de production | ✅ Tenu |
| 17 | Deux réseaux Docker, données jamais exposées | Un seul composant exposé, le frontal ; tout le reste sur la boucle locale | 🔁 Intention tenue, autre moyen |
**Décompte sur les 17 choix du dossier : 8 tenus, 5 substitués, 3 partiels, 1 non fait.** Au
23/09, il était de 8 tenus, 4 substitués, 3 partiels et 2 non faits : MinIO est passé de « non
fait » à « substitué » par Garage.
**Hors de cette liste**, le dashboard était prévu en React / Vite ; il est en **Angular 22**
depuis son initialisation le 14/09 (commit `49f4697`, PR #52). Sans effet sur le reste de
l'architecture, puisque le frontend ne connaît que le contrat d'API. Motif : choix de Valentin, développeur
full stack de l'équipe, qui maîtrisait Angular ; aucune objection dans le cadre du projet.
---
## 7. Usage de l'intelligence artificielle
## 6. Usage de l'intelligence artificielle
Déclaration exigée par le formateur : outils utilisés, tâches réalisées, valeur ajoutée,
limites constatées, vérifications humaines.
@@ -316,7 +280,7 @@ tâches, valeur ajoutée, limites, vérifications.
---
## 8. Licences logicielles
## 7. Licences logicielles
**Licence du dépôt** : aucun fichier `LICENSE` au gel. Faute de licence explicite, le code reste
sous le régime par défaut : tous droits réservés à ses auteurs, aucune réutilisation accordée.
@@ -348,7 +312,7 @@ notamment sa licence AGPL, que Garage partage ; les autres raisons de l'ADR rest
---
## 9. Anonymisation et conformité RGPD
## 8. Anonymisation et conformité RGPD
- **Les données du projet sont synthétiques.** Les séries de consommation proviennent des CSV
fournis par l'organisme de formation et de l'API Mock simulée. Aucune donnée de consommation
Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

+70
View File
@@ -0,0 +1,70 @@
@page {
size: A4;
margin: 17mm 16mm 19mm 16mm;
@bottom-left {
content: string(doctitle);
font: 8pt Lato, "Liberation Sans", Arial, sans-serif;
color: #6b7280;
}
@bottom-right {
content: counter(page) " / " counter(pages);
font: 8pt Lato, "Liberation Sans", Arial, sans-serif;
color: #6b7280;
}
}
:root {
--ink: #1f2937;
--muted: #6b7280;
--label: #374151;
--accent: #16a34a;
--accent-dark: #15803d;
--accent-light: #dcfce7;
--rule: #e5e7eb;
--border: #d1d5db;
--soft: #f3f4f6;
}
html { font: 10pt/1.48 Lato, "Liberation Sans", Arial, sans-serif; color: var(--ink); background: #fff; }
body { margin: 0; }
.brand { display: flex; align-items: center; justify-content: space-between; padding-bottom: 3mm; margin-bottom: 5mm; border-bottom: 0.3mm solid var(--rule); }
.brand .lockup { display: flex; align-items: center; gap: 3mm; }
.brand img { height: 9mm; width: 9mm; }
.brand .name { font-size: 14pt; font-weight: 700; color: var(--ink); }
.brand .meta { font-size: 8pt; font-weight: 700; letter-spacing: 0.12em; color: var(--accent-dark); text-transform: uppercase; }
h1 { string-set: doctitle content(); font-size: 20pt; line-height: 1.2; color: var(--ink); margin: 0 0 5mm; }
h1::after { content: ""; display: block; width: 14mm; height: 1mm; background: var(--accent); margin-top: 3mm; }
h2 { font-size: 13.5pt; color: var(--ink); margin: 7mm 0 3mm; padding-bottom: 1.2mm; border-bottom: 0.3mm solid var(--rule); break-after: avoid; }
h3 { font-size: 11pt; color: var(--label); margin: 5mm 0 2mm; break-after: avoid; }
h4 { font-size: 10.2pt; margin: 4mm 0 1.5mm; break-after: avoid; }
p, li { orphans: 3; widows: 3; }
a { color: var(--accent-dark); text-decoration: none; }
strong { font-weight: 700; }
code { font: 8.4pt "Noto Sans Mono", "DejaVu Sans Mono", monospace; background: var(--soft); padding: 0 1mm; border-radius: 1mm; }
pre { background: var(--soft); padding: 3mm; border-radius: 0 2mm 2mm 0; border-left: 1mm solid var(--accent); overflow-wrap: anywhere; white-space: pre-wrap; break-inside: avoid; }
pre code { background: none; padding: 0; }
table { border-collapse: collapse; width: 100%; margin: 3mm 0 4mm; font-size: 8.6pt; break-inside: auto; }
thead { display: table-header-group; }
tr { break-inside: avoid; }
th, td { padding: 1.5mm 2.2mm; text-align: left; vertical-align: top; border-bottom: 0.25mm solid var(--rule); }
th { font-size: 7.4pt; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); border-bottom: 0.4mm solid var(--border); }
thead:has(th:empty + th:empty) { display: none; }
table:has(thead th:empty + th:empty) { border-collapse: separate; border-spacing: 0 0.6mm; margin-top: 0; }
table:has(thead th:empty + th:empty) td { background: var(--soft); border: none; padding: 1.8mm 2.5mm; }
table:has(thead th:empty + th:empty) td:first-child { border-radius: 2mm 0 0 2mm; width: 24mm; font-size: 7.4pt; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); padding-top: 2.2mm; }
table:has(thead th:empty + th:empty) td:first-child strong { color: var(--muted); }
table:has(thead th:empty + th:empty) td:last-child { border-radius: 0 2mm 2mm 0; }
blockquote { margin: 3mm 0; padding: 2mm 4mm; border-left: 1mm solid var(--accent); background: var(--soft); border-radius: 0 2mm 2mm 0; }
hr { border: none; border-top: 0.3mm solid var(--rule); margin: 6mm 0; }
img { max-width: 100%; }
.badge { display: inline-block; font-size: 6.8pt; font-weight: 700; letter-spacing: 0.03em; text-transform: uppercase; border-radius: 99mm; padding: 0.3mm 1.8mm; line-height: 1.5; vertical-align: 0.3mm; white-space: nowrap; }
.badge.ok { background: var(--accent); color: #fff; }
.badge.warn { background: #fef9e7; color: #92400e; border: 0.25mm solid #f9a825; }
.badge.no { background: #fef2f2; color: #b91c1c; border: 0.25mm solid #dc2626; }
+35
View File
@@ -0,0 +1,35 @@
#!/usr/bin/env bash
# Réf : consigne formateur, version figée d'un livrable = Markdown -> HTML -> CSS de pagination -> PDF.
# Usage : md2pdf.sh "fichier.md" [sortie.pdf]. Sans sortie, le PDF est écrit à côté du .md.
set -euo pipefail
src="$1"
out="${2:-${src%.md}.pdf}"
here="$(cd "$(dirname "$0")" && pwd)"
work="$(mktemp -d)"
trap 'rm -rf "$work"' EXIT
title="$(grep -m1 '^# ' "$src" | sed 's/^# //; s/&/\&amp;/g; s/</\&lt;/g')"
css_title="$(grep -m1 '^# ' "$src" | sed 's/^# //; s/\\/\\\\/g; s/"/\\"/g')"
logo="$(base64 -w0 "$here/logo-icon.png")"
npx --yes marked@18 --gfm -i "$src" -o "$work/body.html"
sed -i 's/ \([:;?!»]\)/\xc2\xa0\1/g; s/« /«\xc2\xa0/g' "$work/body.html"
# Les marqueurs de preuve du rapport EC04 deviennent des pastilles, comme les badges d'état de l'application.
sed -i -E 's#\[Prouvé\]#<span class="badge ok">Prouvé</span>#g; s#\[Constaté\]#<span class="badge warn">Constaté</span>#g; s#\[Absent\]#<span class="badge no">Absent</span>#g; s#<strong>((<span class="badge[^"]*">[^<]*</span> ?)+)</strong>#\1#g' "$work/body.html"
{
printf '<!doctype html>\n<html lang="fr"><head><meta charset="utf-8"><title>%s</title><style>\n' "$title"
cat "$here/md2pdf.css"
# Piège : Chromium ignore `string-set`, le titre du pied de page est donc écrit en dur ici.
printf '\n@page { @bottom-left { content: "%s"; } }\n' "$css_title"
printf '\n</style></head><body>\n'
printf '<div class="brand"><div class="lockup"><img src="data:image/png;base64,%s" alt=""><span class="name">EnerVision</span></div><div class="meta">EADL 2026 · Groupe 3</div></div>\n' "$logo"
cat "$work/body.html"
printf '\n</body></html>\n'
} > "$work/doc.html"
chromium --headless --disable-gpu --no-pdf-header-footer \
--print-to-pdf="$out" "file://$work/doc.html" 2>/dev/null
echo "PDF écrit : $out"