Commit Graph
63 Commits
Author SHA1 Message Date
Johan LEROY 90639b5618 feat(frontend): composant app-recommendation-list, jointure alertes/recommandations
Une recommandation ne porte que alert_id et GET /recommendations n'a aucun
filtre : le composant charge en parallèle les alertes (filtrées par site quand
`siteId` est fourni) et toutes les recommandations, puis les joint côté client
(joinByAlert, fonction pure testée à part) en groupes par alerte, du plus récent
au plus ancien. Chaque groupe montre le contexte de l'alerte (sévérité, type,
site, horodatage, message) puis ses actions avec l'explication et la règle.
L'input `alertId` réduit la vue à une alerte et la met en évidence ; `reload()`
rejoue les deux appels. Un échec de l'un des deux vide tout : une demi-jointure
tromperait.
2026-09-21 14:39:56 +02:00
Johan LEROY e147ea69bc feat(frontend): modèle et service Recommendations (liste, détail, génération)
Types alignés sur RecommendationResponse et RecommendationGenerationResponse
du backend. RecommendationsService couvre GET /recommendations,
GET /recommendations/{id} et POST /recommendations/generate?site_id= (réservé
admin côté API). recommendation-presentation.ts traduit les sept règles connues
du moteur et retombe sur la référence brute pour une règle inconnue, la
politique de renommage en -v2 de l'ADR 0006 l'impose.
2026-09-21 14:39: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
Johan LEROY 91752a2b0b fix(frontend): aligne le modèle Alert et AlertsService sur le contrat /alerts
Le modèle front portait un alert_id texte, des value/threshold non nullables et
ignorait metric et prediction_id, alors que l'API sérialise un entier, des
flottants nullables et ces deux champs. Toute comparaison avec l'alert_id d'une
recommandation échouait silencieusement.

- alert.model.ts : alert_id number, value/threshold/metric/prediction_id nullables
- alerts.service.ts : getAlerts(filters) pose site_id et severity en HttpParams,
  les deux filtres que l'API accepte
- alerts.fixture.ts : réaligné sur le contrat (ids entiers, horodatages UTC,
  champs nuls sur outage/sensor, un cas spike)
- alert-presentation.ts : tons, libellés et unités partagés ; low passe en
  neutre, le vert se lisait comme un état sain
2026-09-21 14:25:30 +02:00
Johan LEROY 5a29faaa16 Merge remote-tracking branch 'origin/dev' into pr117-fix 2026-09-21 12:11:39 +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 777cd0ac64 fix(frontend): affiche since comme la dernière lecture reçue, pas comme un début de panne
Le schéma backend dit que since est l'horodatage de la dernière lecture du
site, identique pour tous ses capteurs en panne et sans rapport avec le début
de la panne. Le template annonçait « depuis <date> », ce que l'exploitant lit
comme une date de début de panne.

Un site sans aucune lecture renvoie ses cinq capteurs en échec avec since à
null : le template affichait « depuis » suivi d'une chaîne vide. Ce cas dit
maintenant « aucune lecture reçue ».

Format de date explicite plutôt que 'short' : aucune locale n'est enregistrée
dans app.config.ts, donc 'short' rendait la date au format en-US.
2026-09-21 11:38:52 +02:00
ValentinDeFariaandGitHub f9c2a4610c Update dashboard.ts
Frontend / Audit des dépendances (push) Successful in 6s
SonarQube / build-back (push) Successful in 1m6s
Frontend / build (push) Successful in 9m52s
SonarQube / build-front (push) Successful in 9m44s
SonarQube / test-back (push) Failing after 52s
Frontend / test (push) Failing after 5m0s
SonarQube / test-front (push) Failing after 5m2s
SonarQube / SonarQube (push) Skipped
2026-09-18 16:56:59 +02:00
ValentinDeFariaandGitHub b5fa7b0010 Merge branch 'dev' into feat/supervision-des-capteurs 2026-09-18 16:54:39 +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 d535959fbe Merge remote-tracking branch 'origin/dev' into feat/site-detail-view 2026-09-18 14:11:48 +02:00
Johan LEROYandClaude Opus 5 33807e3038 fix(frontend): traite la revue de phyri0s sur la vue détail d'un site
Quatre points portant sur le code de cette PR :

- L'échec de chargement laissait à l'écran le site précédemment affiché sous le
  bandeau d'erreur : `reportUnavailable()` vide désormais site, mesure et
  historique, pour qu'on ne lise pas les chiffres de A en croyant regarder B.
- L'historique était tracé à rebours : l'API trie en timestamp décroissant
  (`ReadingRepository.list_history`), le graphique rétablit la chronologie.
- Une consommation `null` (panne capteur) alimentait la jauge avec un 0,
  indiscernable d'un site qui ne consomme rien : la jauge n'est plus montée dans
  ce cas, la raison de l'absence est affichée à la place. Une consommation
  réellement mesurée à 0 continue d'afficher la jauge.
- `getSite` et `getCurrent` ne dépendent pas l'un de l'autre : `forkJoin` économise
  un aller-retour en série à chaque ouverture de la page.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-18 14:11:44 +02:00
ineszang44 77feabcbad Merge branch 'feat/sonar-dashboard' of https://github.com/ineszang/ProjetPiscine_EnerVision into feat/sonar-dashboard 2026-09-18 12:22:41 +02:00
ineszang44 18a4be6e38 feat+rollback: job de test sur le backend dans le workflow du front pour sonar, properties de sonar dans la racine du projet 2026-09-18 12:17:43 +02:00
Dorian db81290026 Merge remote-tracking branch 'origin/dev' into feat/service-de-scoring 2026-09-18 12:05:38 +02:00
Valentin 7f710c9084 feat(frontend): supervision des capteurs par site (admin) 2026-09-18 12:02:48 +02:00
ineszang44 12fb8860d1 chore: fichier de configuration pour chaque module (front et back) 2026-09-18 11:54:21 +02:00
Dorian d9229e5a93 feat(frontend): affiche les prévisions de consommation sur le dashboard 2026-09-18 11:51:02 +02:00
ineszang44 7c2936f2ef chore: fichier de configuration pour chaque module (front et back) 2026-09-18 11:26:45 +02:00
Johan LEROY 9d3e402ca4 test(frontend): couvre la vue détail sur le contrat SiteCurrentResponse
Le cas « site sans mesure » ne passe plus par une réponse nulle mais par
`timestamp` à null : il ne doit alors pas interroger `/readings`, et la vue
annonce l'absence de mesure au lieu de six métriques de cause inconnue.
2026-09-18 11:11:12 +02:00
Johan LEROY 7db57f162c refactor(frontend): aligne la vue détail sur le contrat SiteCurrentResponse
`/sites/{site_id}/current` renvoie un objet toujours présent, sans `reading_id`
ni `source`, avec `timestamp` nullable et `null_reasons` non nullable. La vue
s'appuyait sur une réponse nulle pour détecter l'absence de mesure : elle
s'appuie désormais sur `timestamp`, et affiche `data_quality`, que le contrat
précédent ne portait pas.

`getCurrent()` rejoint `SitesService`, l'endpoint appartenant à `/sites`.
2026-09-18 11:03:57 +02:00
Johan LEROY 9ccc603d88 Merge branch 'dev' into feat/site-detail-view
Le backend de la branche réimplémentait `/sites/{site_id}/current` en renvoyant
`ReadingResponse | None`. La PR #84, mergée entre-temps, l'expose via
`SiteCurrentResponse`. Les cinq conflits sont donc tranchés en faveur de `dev`,
et tout `apps/backend/` est repris à l'identique : la branche redevient
purement frontend.
2026-09-18 11:01:45 +02:00
ineszang44 c8383014a8 Merge branch 'dev' into feat/sonar-dashboard 2026-09-18 09:52:27 +02:00
Johan LEROY e26948932e fix(frontend): annule le chargement en cours lors d'un changement rapide de site
Sans switchMap sur le flux externe, une réponse HTTP en retard pouvait écraser
l'affichage du site actuellement sélectionné après une navigation rapide entre
deux sites.
2026-09-17 16:47:40 +02:00
Johan LEROYandClaude Sonnet 5 41acdb54b6 fix(frontend): désactive les fixtures mock, le backend est alimenté
Le dataset historique 2023-2024 est chargé en base. /stats/summary et
/alerts servaient encore des fixtures déconnectées de ces données réelles.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012i5NteMLRZgfTAKB5GD37X
2026-09-17 16:43:40 +02:00
Johan LEROYandClaude Sonnet 5 5d921a9b1e feat: vue détail d'un site (#51)
Ajoute la page de détail d'un site (fiche, mesure instantanée, jauge de
consommation, historique) en remplacement du placeholder. Les champs
null sont affichés explicitement avec leur raison plutôt que masqués.

Ajoute l'endpoint GET /sites/{id}/current côté backend, qui retourne la
dernière mesure connue d'un site sans filtre temporel, conformément au
contrat de l'issue.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012i5NteMLRZgfTAKB5GD37X
2026-09-17 16:43:15 +02:00
Johan LEROY 8fb5ab9f65 fix(frontend): traite la revue de phyri0s sur la PR #95
Frontend / build (push) Successful in 9m42s
Frontend / test (push) Failing after 5m23s
Frontend / SonarQube (push) Skipped
- Reutilise .ev-link pour le lien "Detail" de la liste des sites au
  lieu de dupliquer ses regles de style.
- site.location vide est traite comme absent (affiche "-"), pas
  seulement null/undefined.
- siteId de la page detail suit desormais route.paramMap de facon
  reactive plutot qu'une lecture ponctuelle du snapshot, pour rester
  a jour quand Angular reutilise l'instance du composant en changeant
  de site.
- Ajoute provideRouter([]) manquant dans un test dashboard existant,
  necessaire depuis l'ajout du lien "Voir les sites" au rebase sur dev.
2026-09-17 16:01:15 +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 5581cb1ef3 feat(frontend): vue liste des sites
Nouveau SitesService (GET /sites) et page SiteList consommant le design
système (ev-card, ev-badge, ev-alert, ev-brand). Ajoute la route /sites,
un lien depuis le dashboard, et une route détail /sites/:siteId pointant
vers un placeholder minimal en attendant l'issue #51.

Closes #49
2026-09-17 15:58:35 +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 LEROY d7f775f9f7 feat(auth): verifie le lien de reset des le chargement, sans le consommer
Ajoute GET /auth/reset-password/validate (lecture seule, sans rate
limit : le jeton est un secret de 256 bits non brute-forcable) pour que
la page reset-password redirige immediatement vers /login si le lien
est invalide ou expire, plutot que d'attendre la soumission du
formulaire. La verification a la soumission (confirm_password_reset)
reste la seule source de verite atomique.
2026-09-17 15:28:50 +02:00
Johan LEROY e381e0de09 feat(frontend): checklist de complexite du mot de passe sur reset-password
Remplace l'indice statique sous le champ nouveau mot de passe par une
checklist qui coche chaque regle (longueur, majuscule, minuscule,
chiffre, caractere special) au fur et a mesure de la saisie. Les regles
individuelles (PASSWORD_REQUIREMENTS) sont exposees depuis le meme
validateur que PASSWORD_PATTERN pour rester la seule source de verite.
2026-09-17 14:57:05 +02:00
Johan LEROY 7674955637 fix(frontend): un lien de reset absent ou expire renvoie vers login avec un message standard
Avant, un token absent affichait un message inline sur /reset-password, et
un token invalide/expire ne se voyait qu'apres soumission du formulaire.
Les deux cas redirigent maintenant vers /login avec le motif
"lien-expire", qui y affiche le message standard "Ce lien de
reinitialisation est invalide ou a expire. Connectez-vous ou
redemandez-en un."
2026-09-17 14:49:46 +02:00
Johan LEROY 063092f2c7 fix(frontend): le rafraichissement de session au demarrage ne doit pas ecraser un lien de reset
Le refresh de session lance par provideAppInitializer echoue silencieusement
sans cookie valide, mais l'intercepteur forcait quand meme un
router.navigate(['/login']) sur le 401 resultant, ecrasant la navigation
vers /reset-password?token=... venue de l'email. L'intercepteur ne
redirige plus quand on est deja sur une route invitee (login,
forgot-password, reset-password).
2026-09-17 14:40:53 +02:00
Johan LEROY 921da48eb1 fix(auth): corrige 4 failles de la revue de securite sur la PR #90
Anti-enumeration cassee sur /auth/forgot-password : l'envoi SMTP etait
synchrone dans le chemin de reponse, donc un email existant prenait plus
de temps qu'un email inconnu (et pouvait renvoyer 500 si le relais SMTP
echouait, contre 202 sinon). L'envoi part desormais en BackgroundTasks,
apres que la reponse 202 a ete envoyee au client, avec un try/except qui
logue plutot que de laisser une exception SMTP remonter.

confirm_password_reset() ne revalidait pas is_active/kind du compte avant
de changer le mot de passe : un compte desactive dans les 15 minutes
suivant l'emission du lien pouvait quand meme voir son mot de passe
change et son must_change_password efface.

Les plages [A-ZA-Y]/[a-za-y] de la regle de complexite incluaient par
erreur x et / (U+00D7, U+00F7), donc un mot de passe sans aucune
majuscule ou minuscule pouvait passer la validation.

Le validateur frontend (JS, \w ASCII) et le validateur backend (Python,
\w Unicode) divergeaient sur les caracteres accentues : un mot de passe
comme "Securite1" passait cote front puis se faisait rejeter en 422 cote
back. Les deux cotes utilisent maintenant le meme jeu explicite de
caracteres speciaux (SPECIAL_CHARACTERS, partage aussi avec cli.py).
2026-09-17 14:35:14 +02:00
ineszang44 278299c2b1 test: configuration sonarqube + config angular 2026-09-17 14:18:54 +02:00
ineszang44 ff68a51424 feat(frontend): fichier de config pour vitest 2026-09-17 13:36:21 +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 cc7ca2d359 fix(frontend): logo plus grand et fond de page coherent sur toutes les pages
Logo des pages auth agrandi (64px -> 96px) : encore trop petit avec la
premiere passe. Fond de page (--color-bg) applique globalement sur body
plutot que par page, pour que le dashboard et les pages auth partagent le
meme socle visuel. Logo et respiration du dashboard ajustes en consequence.
2026-09-17 11:30:19 +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
Johan LEROY 9c78c6dc38 feat(frontend): design système - tokens, composants ui et restylage des pages
Centralise les couleurs/rayons/espacements dispersés en dur dans chaque page
(login, change-password, dashboard) en tokens CSS partagés, ajoute un petit
set de composants standalone réutilisables (ev-button, ev-card, ev-alert,
ev-badge) et intègre le logo EnerVision en en-tête des pages ainsi que dans
Swagger/ReDoc côté backend.

Refs #91
2026-09-17 11:14:02 +02:00
Johan LEROY 9161b74874 feat(auth): politique de complexite du mot de passe et flux de reinitialisation
Remplace la regle de longueur seule (12 caracteres) par une exigence de
composition (8 caracteres minimum, majuscule, minuscule, chiffre, caractere
special), non documentee dans les exigences officielles du projet, par une
regle explicite partagee entre le backend (validateur Pydantic) et le
frontend.

Ajoute un flux "mot de passe oublie" en libre-service, absent jusqu'ici :
jeton a usage unique hache en base (meme principe que les refresh tokens),
expirant a 15 minutes, envoye par email via un service SMTP (aiosmtplib,
Mailpit en dev), avec limitation de debit dediee et reponse generique pour
eviter l'enumeration des comptes.

Closes #87
2026-09-17 10:53:58 +02:00
Johan LEROYandGitHub 9f465538bf Merge pull request #85 from ineszang/feat/auth-front
feat(frontend): authentification frontend
2026-09-17 09:09:59 +02:00
Johan LEROY 515a92b395 fix(frontend): isole les fichiers de tests vitest pour eviter la pollution de mocks
Le test site-load-chart.spec.ts echouait de facon intermittente en CI : sans
isolation, vitest partage le registre de modules entre fichiers de spec, donc
le mock chart.js d'un fichier pouvait ecraser celui d'un autre selon l'ordre
d'execution.
2026-09-17 09:02:53 +02:00
ValentinDeFariaandGitHub 0174272bdd Update dashboard.html 2026-09-16 17:00:52 +02:00
ineszangandGitHub c740b61b24 Merge pull request #80 from ineszang/feat/pipeline-ci
Feat/pipeline ci
2026-09-16 16:41:55 +02:00
Valentin 5669cd63ec feat(frontend): authentification frontend
ajout de la page login, changement de mot de passe forcé, rafraîchissement de session en mémoire, intercepteur, déconnexion, bouton logout sur le dashboard
2026-09-16 16:07:28 +02:00
ineszang44 06cb60463c fix(frontend): droit d'accès au fichier de config de nginx, réduction de code smells 2026-09-16 15:12:04 +02:00