Commit Graph
79 Commits
Author SHA1 Message Date
Johan LEROY 7e504bee72 docs(frontend): documente la vue recommandations
Route, paramètres ?site= et ?alert=, jointure côté client et sa raison (pas de
site_id sur une recommandation, aucun filtre sur GET /recommendations,
/alerts non paginé), génération réservée aux admins, points d'entrée.
2026-09-21 14:41:56 +02:00
Johan LEROY 83caa9006e chore(frontend): active strict, ajoute .form-select et documente le spec ciblé
Frontend / Audit des dépendances (push) Successful in 5s
SonarQube / build-back (push) Successful in 1m6s
Frontend / build (push) Successful in 9m47s
SonarQube / test-ml (push) Failing after 2m2s
SonarQube / build-front (push) Successful in 10m5s
SonarQube / test-back (push) Failing after 49s
Frontend / test (push) Failing after 5m5s
SonarQube / test-front (push) Failing after 5m3s
SonarQube / SonarQube (push) Skipped
- tsconfig.json : "strict": true, vérifié sans erreur sur app et specs
- _forms.scss : .form-select, select natif habillé comme .form-input avec un
  chevron, documenté dans le design système
- TESTING.md : commande pour jouer un seul fichier ou dossier de specs
2026-09-21 14:25:30 +02:00
Dorian 3c378c177f ci(ml,etl): analyse ml/ et etl/airflow dans SonarCloud avec un rapport de couverture ML 2026-09-21 14:12:38 +02:00
Johan LEROYandClaude Opus 5 62d81e901d fix(ci,docs): lève les points de revue du SAST et de la vue CI/CD
Backend / Tests exigeant une base (push) Failing after 34s
Backend / Lint, typage et tests (push) Successful in 1m43s
Backend / Analyse statique de sécurité (push) Successful in 7s
Backend / Audit des dépendances (push) Successful in 57s
ML / Analyse statique de sécurité (push) Successful in 7s
ML / Lint, typage et tests (push) Successful in 3m0s
ML-START.md affirmait que l'orchestration Airflow n'existait pas : `ml_score`
tourne en `@hourly` depuis l'issue #115, seuls le mode `--csv` et un lancement
local restent manuels.

50-cicd.md : Dependabot compte six entrées sur cinq écosystèmes et non cinq
entrées, le filtre d'`airflow.yml` couvre aussi `apps/backend/` depuis le DAG
`alertes`, et les issues #21 (job de déploiement) et #22 (secrets) sont
distinguées au lieu d'être citées l'une pour l'autre. Le `continue-on-error` du
second passage Bandit est nommé pour ce qu'il est : le job reste vert même avec
un constat LOW.

Bandit est épinglé à 1.9.4 dans les deux jobs `sast` : sans épingle, une
nouvelle version passe la CI au rouge sans qu'une ligne du dépôt ait changé, et
le rejeu à l'identique documenté n'existe pas. Le `cache-dependency-glob` part :
`uvx` n'installe pas le projet, le verrou n'alimentait aucune clé de cache.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-21 13:41:17 +02:00
Johan LEROY 31886944ab Merge remote-tracking branch 'origin/dev' into docs/livrables-ec03-ec06
# Conflicts:
#	docs/architecture/00-vue-ensemble.md
#	docs/architecture/README.md
2026-09-21 13:40:44 +02:00
Johan LEROY f8d08c8686 fix(etl): borne le DAG alertes sur son pire cas et couvre sa seconde commande en CI
Airflow / Lint et intégrité des DAGs (push) Successful in 56s
Airflow / Construction de l'image (push) Successful in 3m20s
`execution_timeout` plafonne une tentative, pas la tâche. Avec deux reprises, quinze
minutes par tentative autorisaient quarante-neuf minutes par tâche et quatre-vingt-dix-huit
pour l'enchaînement, quand le commentaire annonçait une somme tenant sous le pas horaire.
Le plafond passe à cinq minutes, ce qui borne le pire cas à trente-huit minutes, et le test
d'intégrité calcule désormais ce pire cas plutôt que la somme des plafonds : reprises et
délais d'attente compris, c'est la durée qu'un `max_active_runs=1` fait payer à l'exécution
suivante.

La CI vérifie aussi `app.cli generate-recommendations --help` sans réseau. C'est la seconde
commande du DAG, et son import tire FastAPI, les repositories et les services, donc une part
de l'environnement `/opt/backend` que la détection seule ne touche pas.

`10-infra.md` nomme enfin ce que le décalage de quinze minutes ne garantit pas : le plafond
de `ml_score` valant trente minutes, un scoring qui déborde prive la règle `anomaly` de la
prédiction de l'heure, qu'elle ne retrouvera au passage suivant que si sa fenêtre la couvre
encore.
2026-09-21 13:28:23 +02:00
Johan LEROY be44b97d7a Merge remote-tracking branch 'origin/dev' into docs/livrables-ec03-ec06
Conflit sur docs/architecture/00-vue-ensemble.md, résolu au profit de l'état réel
de dev après la #117 et la #115.

La ligne ML reprend l'orchestration Airflow de dev, que la branche avait retirée
alors que la ligne ETL de la même table la décrit ; seul le renvoi vers
ML-START.md garde la correction de chemin apportée ici.

Trois manques listés comme assumés ne le sont plus : la terminaison TLS pose HSTS
et CSP, le proxy limite le débit, et environment.ts de production est passé en URL
relative. La section plus haut les décrit déjà comme livrés.
2026-09-21 12:23:06 +02:00
Johan LEROY 306c5a52e5 Merge remote-tracking branch 'origin/dev' into feat/dag-alertes
# Conflicts:
#	.env.example
#	Makefile
#	docs/README.md
2026-09-21 12:16:58 +02:00
Johan LEROY 2686880185 docs: acte l'ordonnancement des alertes par l'ADR 0008 et met à jour les vues
L'ADR 0008 décide qu'Airflow exécute le code du backend en sous-processus plutôt
que d'appeler l'API, et assume ce que cela coûte : une image plus lourde, la CI
Airflow déclenchée par les changements du backend, une clé applicative de plus.

Les vues suivent. Trois DAGs dans 10-infra.md et dans la vue d'ensemble, avec le
motif du décalage horaire. La détection n'est plus « lancée à la main » dans
20-backend.md. La génération des recommandations gagne son troisième déclencheur
dans 40-data.md. La dette de cantonnement ETL et ML porte l'aggravation comme
l'atténuation. L'affirmation selon laquelle `etl/airflow/` ne contient que des
`.gitkeep`, fausse depuis l'issue #115, disparaît.

L'index des décisions omettait les ADR 0005 et 0006, il les récupère au passage.
2026-09-21 12:14:06 +02:00
Johan LEROY bc75528616 fix(infra): lève les points de revue du reverse proxy
Compose interpole tout le fichier avant n'importe quelle sous-commande : la garde
`${PUBLIC_HOST:?}` de l'overlay cassait `stack-down` et `stack-logs` autant que le
démarrage. La valeur retombe sur `enervision.local`, et `stack-up` vérifie à la place
que le certificat présent couvre l'hôte demandé, ce qui est la condition réelle à tenir.

La CSP `script-src 'self'` bloquait le gestionnaire `onload` que l'inlining du CSS
critique d'Angular pose sur la feuille de styles : l'application se serait affichée sans
style derrière le proxy. `inlineCritical` passe à faux, le build de production ne produit
plus aucun script en ligne.

La zone de limitation resserrée ne couvre plus que les routes qui vérifient un secret.
Derrière le NAT de l'école, où une seule adresse porte toute la promotion, `/auth/me` et
`/auth/refresh` y auraient produit des 429 en usage normal.

Enfin `certbot/certbot` est épinglé en v5.8.0 pour que Dependabot puisse le suivre, le
proxy attend une API saine plutôt que démarrée, et la redirection vers `$host` est actée
comme risque accepté : figer un nom canonique couperait l'accès par adresse IP, seule
voie ouverte sur la machine cible.
2026-09-21 12:11:32 +02:00
Johan LEROY d7457e9fd9 Merge remote-tracking branch 'origin/dev' into docs/livrables-ec03-ec06
# Conflicts:
#	docs/architecture/00-vue-ensemble.md
2026-09-21 11:56:08 +02:00
Johan LEROY c528ed239b Merge remote-tracking branch 'origin/dev' into feat/reverse-proxy-nginx-tls
Rapatrie la #118 (DAGs Airflow). Quatre conflits, tous additifs sauf un :

- `.env.example` et `.gitignore` : les blocs Airflow et proxy cohabitent.
- `Makefile` : `AIRFLOW` rejoint les variables de dossier, les cibles Airflow
  et TLS cohabitent dans `.PHONY`.
- `00-vue-ensemble.md` : la ligne ML de `dev` est retenue, la ligne Infra de
  cette branche aussi, chacune portant sa propre mise à jour.

L'interface Airflow rejoint la base et Mailpit sur `127.0.0.1` dans l'overlay :
elle n'a pas d'authentification à publier derrière le proxy.
2026-09-21 11:24:42 +02:00
Johan LEROY a88e51c92a Merge remote-tracking branch 'origin/dev' into feat/reverse-proxy-nginx-tls
Trois conflits, tous documentaires ou de liste :

- `.env.example` : les variables de l'API Mock et celles du proxy cohabitent.
- `Makefile` : la cible `recommendations` rejoint les cibles TLS dans `.PHONY`.
- `owasp-traceabilite.md` : la ligne API10 de `dev` est retenue, la ligne API8
  « ouvert » de `dev` est abandonnée puisque cette branche la déplace vers les
  points couverts.

Au passage, l'ADR 0006 arrivé par la #114 manquait aux deux index de décisions,
et l'ADR 0007 manquait à celui de la vue d'ensemble.
2026-09-21 11:21:45 +02:00
Dorian 901ceffd72 fix(etl): fiabilise airflow-init, borne les DAGs ML et ajoute la CI Airflow
Airflow / Lint et intégrité des DAGs (push) Successful in 1m10s
Airflow / Construction de l'image (push) Successful in 1m47s
2026-09-21 11:18:02 +02:00
Johan LEROY 5545c166fd docs(architecture): ajoute la vue CI/CD et corrige trois affirmations fausses
La documentation du pipeline est explicitement notée par EC03 (C20) et n'existait
pas. L'index des vues justifiait son absence par un manque de matière : quatre
workflows et quatorze jobs en sont assez.

Trois affirmations de 00-vue-ensemble.md étaient devenues fausses, ce qui coûte
plus cher qu'une absence puisqu'on les lit et qu'on construit dessus :

- la CI/CD y était déclarée `Cible` / `Rien` alors que quatre workflows tournent ;
- le flux bout en bout y était `Cible` avec "aucun maillon n'existe, à l'exception
  de la base", alors que tout le chemin de lecture et deux ingestions existent ;
- l'analyse de dépendances y était listée comme absente alors que pip-audit,
  npm audit et Dependabot sont en place. Seule celle des images manque.

Ferme C20 de la grille d'auto-évaluation.
2026-09-21 10:50:25 +02:00
Johan LEROY 3c01ab3ecc docs(ml): écrit ML-START.md et répare les renvois cassés
Le document était référencé 11 fois, dont 4 depuis le code (config.py, data.py,
train.py, score.py, features.py), et n'avait jamais été écrit. Deux chemins
contradictoires coexistaient : `../ML-START.md` depuis ml/README.md et
docs/architecture/, `docs/ML-START.md` depuis le code. Le chemin retenu est celui
du code, majoritaire et le seul qu'un lecteur du module rencontre.

Il couvre les trois sections que les renvois annoncent : mécanisme d'accès aux
données et pourquoi ce n'est pas l'API, étapes d'un run de scoring, frontière
entre FastAPI et LightGBM.

Ferme C34 de la grille d'auto-évaluation.
2026-09-21 10:50:12 +02:00
Dorian 6f6f451eb4 Merge remote-tracking branch 'origin/dev' into feat/dag-ml-train-score 2026-09-21 10:39:07 +02:00
Johan LEROY 0a2ed5ad8f docs: distingue l'ingestion des mesures de celle des alertes
La #114 arrive sur dev avec un ADR 0006 qui note que l'ingestion de
l'API Mock /alerts reste à faire. « Les deux sources sont implémentées »
se lisait comme couvrant aussi les alertes.
2026-09-21 10:25:48 +02:00
Johan LEROY 459ddf1792 Merge remote-tracking branch 'origin/dev' into feat/mock-api-import 2026-09-21 10:24:48 +02:00
Johan LEROY de697b080d docs: rétablit la hiérarchie des titres et les motifs du document Data
40-data.md était passé à quatre titres de niveau 1 et etl/README.md à cinq,
alors que les huit autres documents d'architecture n'en ont qu'un. Les
sections ajoutées redescendent d'un niveau.

La réécriture de la section « Tables d'authentification » avait aussi vidé
quatre choix de modélisation de leur raison, dont le renvoi à l'ADR 0004 sur
audit_log.actor_id. Ces motifs sont rétablis, et les deux tables de
réinitialisation reçoivent le leur.

Documente enfin la frontière de confiance avec l'API Mock : les quatre
garde-fous, les plages de PHYSICAL_BOUNDS, et ce qu'il reste à faire.
2026-09-21 10:21:18 +02:00
Johan LEROY f238940867 fix(etl): borne la réponse de l'API Mock avant écriture en base
L'API Mock est le seul item OWASP API10 du projet, et ce script en est le
premier consommateur. Des quatre garde-fous exigés par la traçabilité OWASP,
seul le timeout était en place.

- plafonne la taille des réponses : MAX_SITES sites, au plus --limit mesures ;
- borne chaque grandeur physique par PHYSICAL_BOUNDS, une valeur hors plage,
  d'un type inattendu, NaN ou infinie devenant NULL avec sa raison dans
  null_reasons et data_quality à degraded ;
- ne recopie vers la base que les champs attendus, via build_site_row() et
  build_reading_row(), au lieu de passer les dictionnaires de l'API en
  paramètres SQL ;
- écarte une data_quality que ck_reading_quality refuserait, plutôt que de
  faire échouer le lot entier ;
- nomme la cible du ON CONFLICT, qui avalait jusqu'ici toute violation
  d'unicité, y compris celle de la clé primaire.

raw_data conserve la réponse d'origine intacte : rien n'est perdu, seule son
exploitation est bornée.
2026-09-21 10:21:10 +02:00
Dorian b941880c22 feat(etl,ml): orchestre l'entrainement et le scoring LightGBM via deux DAGs Airflow 2026-09-21 10:03:23 +02:00
Johan LEROY 0c487fa7be docs: acte la terminaison TLS par l'ADR 0007 et met à jour les vues
L'ADR 0007 tranche le reverse proxy en Compose plutôt que l'ingress k3s, qui
supposait un registre et des manifestes inexistants, et referme la première
question ouverte de 10-infra.md.

Les vues suivent : troisième topologie et ports 80/443 dans 10-infra.md, TLS,
HSTS et CSP passent d'« Absent, et assumé » à « En place » dans la vue
d'ensemble, la ligne API8 transport rejoint les points couverts de la
traçabilité OWASP.

Trois affirmations périmées disparaissent au passage : le compose a bien un
service frontend, environment.ts ne pointe plus sur localhost:8000, et le
Dockerfile du front n'est plus mono-étage sur une branche.
2026-09-21 09:51:19 +02:00
Johan LEROY 19c38fe571 fix(backend): decoupe l'insertion des recommandations en lots et remet les docs a jour
Backend / Tests exigeant une base (push) Failing after 34s
Backend / Lint, typage et tests (push) Successful in 1m24s
Backend / Audit des dépendances (push) Successful in 57s
SonarQube / build-back (push) Successful in 1m5s
SonarQube / build-front (push) Successful in 9m39s
SonarQube / test-back (push) Failing after 51s
SonarQube / test-front (push) Failing after 5m6s
SonarQube / SonarQube (push) Skipped
`create_missing()` construisait un seul `INSERT ... VALUES` pour la totalite des
propositions. Avec quatre colonnes par ligne et le plafond asyncpg de 32 767
parametres, la route echouait au-dela de 8 191 recommandations par appel, cas
devenu realiste maintenant que la detection interne (#104) alimente `alert` en
continu. L'insertion passe par des lots de `TAILLE_DE_LOT` lignes, sur le patron
de `app/etl/historical_import.py`.

L'ADR 0006, `20-backend.md` et la description de la PR annoncaient qu'aucune
source n'alimentait `alert` et que #104 n'etait pas commencee. #104 est livree
sur `dev` depuis la #113 : les phrases sont corrigees plutot que laissees a
vieillir dans un ADR.
2026-09-21 09:45:25 +02:00
Johan LEROY 9a1af94d88 Merge remote-tracking branch 'origin/dev' into feat/moteur-regles-recommandations 2026-09-21 09:40:46 +02:00
Meryemel-gham 96dd1f834c docs: documente l'ingestion depuis l'API Mock 2026-09-21 09:11:44 +02:00
Dorian c059f838bb fix(backend): fiabilise le tri des lectures/predictions et la detection de redemarrage a zero
Backend / Tests exigeant une base (push) Failing after 38s
Backend / Lint, typage et tests (push) Successful in 1m29s
Backend / Audit des dépendances (push) Successful in 1m3s
SonarQube / build-back (push) Successful in 1m8s
SonarQube / build-front (push) Successful in 9m36s
SonarQube / test-back (push) Failing after 1m5s
SonarQube / test-front (push) Failing after 5m15s
SonarQube / SonarQube (push) Skipped
2026-09-18 16:58:03 +02:00
Dorian a9e124a97d feat(backend): detecte les alertes internes a partir des lectures et previsions 2026-09-18 16:10:06 +02:00
Johan LEROY aeb07e14db 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
2026-09-18 15:49:54 +02:00
Dorian 460d6c1b3e Merge remote-tracking branch 'origin/dev' into feat/service-de-scoring 2026-09-18 15:06:41 +02:00
Dorian eb4291b10a fix(ml,backend,frontend): borne la peremption des predictions et isole les erreurs par flux 2026-09-18 14:58:39 +02:00
Johan LEROY feee6c3ffc docs(backend): documente la classification des routes et la CI d'intégration
La checklist « ajouter une route métier » demandait de maintenir deux listes à la main en
prévenant qu'une route oubliée n'y serait pas détectée. Elle pointe désormais vers
`tests/api/acces.py`, où l'oubli échoue.

Corrige au passage « quatre routes seulement sont publiques » : il y en a sept dans le
contrat, les deux sondes, `/auth/login`, `/auth/logout`, `/auth/forgot-password` et les deux
routes de réinitialisation, qui portent leur autorisation dans le jeton à usage unique plutôt
que dans un `Principal`.

`TESTING.md` précise que les tests `integration` ne sont plus facultatifs : ils cassent la CI
comme les autres.
2026-09-18 12:09:12 +02:00
Dorian db81290026 Merge remote-tracking branch 'origin/dev' into feat/service-de-scoring 2026-09-18 12:05:38 +02:00
Dorian d9229e5a93 feat(frontend): affiche les prévisions de consommation sur le dashboard 2026-09-18 11:51:02 +02:00
Dorian e9376a98bf feat(ml,backend): implemente le service de scoring et GET /predictions (#37) 2026-09-18 11:06:04 +02:00
Johan LEROYandGitHub 297d85a0ca Merge pull request #84 from ineszang/feat/endpoint-sites-current
feat(backend): expose GET /api/v1/sites/{site_id}/current
2026-09-18 10:33:53 +02:00
PhyriosandGitHub 3cf9194d4c Add progress update for project on 2026-09-18
Document progress update for the project as of September 18, 2026, detailing closed issues, merged PRs, and individual contributions.
2026-09-18 09:24:26 +02:00
PhyriosandGitHub 8def1e23af Add progress report for 15/09/2026 review meeting 2026-09-18 09:23:41 +02:00
Johan LEROY e22feac2c4 fix(frontend): navigation cohérente entre les pages authentifiées
Logo cliquable vers le tableau de bord (ev-brand-link) et fil d'Ariane
(ev-breadcrumb) sur les sous-pages, pour éviter les impasses de
navigation entre dashboard, liste des sites et détail de site.
2026-09-17 15:58:50 +02:00
Johan LEROY 85cb7c9eeb fix(frontend,backend): traite la revue de phyri0s sur la PR #93
Backend / Lint, typage et tests (push) Successful in 1m23s
Frontend / build (push) Successful in 9m38s
Frontend / test (push) Failing after 5m4s
Frontend / SonarQube (push) Skipped
Corrige les 10 points de la revue du systeme de design : garde-fou de
route explicite pour /docs, /redoc et /static, ton distinct pour les
alertes critical vs high, flex-shrink sur le bon element du badge,
mutualisation du bloc ev-card dans _auth-page.scss, bouton de
deconnexion migre vers ev-button (nouvel input fullWidth), tokens
manquants (--color-danger-hover, --color-warning-text,
--color-text-inverse, --color-critical), test de synchronisation des
deux copies du logo, openapi_avec_logo qui enveloppe application.openapi
au lieu de le reimplementer, doc du frontend et index mis a jour, et
suppression du CSS mort .form-error.
2026-09-17 15:53:55 +02:00
Johan LEROY 39b1d28ead Merge remote-tracking branch 'origin/dev' into feat/design-system
# Conflicts:
#	apps/frontend/src/app/features/auth/change-password/change-password.html
#	apps/frontend/src/app/features/auth/change-password/change-password.ts
#	apps/frontend/src/app/features/auth/login/login.html
#	apps/frontend/src/app/features/auth/login/login.ts
2026-09-17 15:44:10 +02:00
Johan LEROYandGitHub 5394257855 Merge pull request #90 from ineszang/feat/password-policy-forgot-password
feat(auth): politique de complexité du mot de passe et flux de réinitialisation
2026-09-17 15:34:26 +02:00
Dorian 4f69199734 feat(ml): initialise le pipeline d'entrainement LightGBM (ADR 0005)
ML / Lint, typage et tests (push) Successful in 2m2s
2026-09-17 14:12:26 +02:00
Johan LEROY 916b5d246a Merge remote-tracking branch 'origin/dev' into feat/password-policy-forgot-password
# Conflicts:
#	apps/backend/app/api/deps.py
#	apps/backend/pyproject.toml
2026-09-17 12:18:48 +02:00
Johan LEROY d167b64188 Merge remote-tracking branch 'origin/dev' into feat/endpoint-sites-current
# Conflicts:
#	apps/backend/app/repositories/reading.py
#	apps/backend/openapi.json
#	docs/architecture/20-backend.md
2026-09-17 12:17:05 +02:00
Johan LEROYandGitHub 7913518c4b Merge pull request #94 from ineszang/feat/get-readings
feat(backend): expose GET /api/v1/readings avec fenetre bornee et pag…
2026-09-17 12:12:55 +02:00
Dorian a158d6f84c Merge remote-tracking branch 'origin/dev' into feat/get-readings 2026-09-17 11:58:27 +02:00
Dorian 8d28113f03 feat(backend): expose GET /api/v1/readings avec fenetre bornee et pagination 2026-09-17 11:50:20 +02:00
Johan LEROY 517144f7e5 fix(frontend): lockup logo via texte reel plutot qu'un raster recadre
Recomposer icone+texte en une seule image bitmap (recadrage pixel de
l'asset source) donnait un rendu bruite et un espacement fige, impossible
a ajuster proprement (cause du "gros espace entre le texte et l'image"
remonte). Nouveau composant ev-brand : icone PNG nette + texte "EnerVision"
reel en police systeme, tailles liees en em pour que le lockup grossisse en
gardant le meme rapport, et un ecart controlable en CSS plutot que fige
dans un fichier image.
2026-09-17 11:36:29 +02:00
Johan LEROY bbafe7d119 fix(frontend): logo/favicon corrects et pages d'authentification plus posees
Le src="logo.png" relatif resolvait mal sur les routes autres que "/" :
chemin absolu "/logo.png". Titre de page "Frontend" -> "EnerVision", favicon
regenere depuis l'icone reelle du logo. Pages login/change-password
retravaillees (fond degrade de marque, carte plus large, logo et titre plus
presents) via une classe .auth-page partagee plutot que dupliquee par page.
2026-09-17 11:29:07 +02:00