Commit Graph
231 Commits
Author SHA1 Message Date
Johan LEROY af2b8cb768 ci(sonar): déclenche l'analyse quand sonar-project.properties change
SonarQube / build-back (push) Successful in 1m9s
SonarQube / build-front (push) Successful in 9m35s
SonarQube / test-back (push) Failing after 59s
SonarQube / test-front (push) Failing after 5m2s
SonarQube / SonarQube (push) Skipped
Le fichier pilote le périmètre, la classification des tests et les rapports de
couverture, mais il ne figurait pas dans les paths du workflow : un commit qui
ne touchait que lui laissait le quality gate figé sur son verdict précédent.
2026-09-18 14:28:50 +02:00
Johan LEROY 9e6a5c0663 ci(sonar): classe tout apps/backend/tests comme test, pas les seuls test_*.py
Le quality gate de la PR tombait à 0 % de couverture sur le nouveau code :
tests/api/acces.py ne matche ni `**/*test_*.py` ni `**/*test.py`, donc Sonar
le comptait en code de production, qu'aucun rapport de couverture ne mesure.
Le pattern `tests` des exclusions ne l'attrapait pas non plus : sans wildcard,
il ne désigne que le chemin `tests` à la racine du dépôt.

Même défaut pour tests/factories.py et les __init__.py, déjà sur dev.
2026-09-18 14:28:05 +02:00
Johan LEROY bd1da05587 Merge remote-tracking branch 'origin/dev' into test/matrice-acces-roles
Conflit sur .github/workflows/backend.yml : dev y a ajouté le job
`security-audit` (PR #100) pendant que cette branche y ajoutait le job
`integration`. Les deux jobs sont conservés côte à côte.
2026-09-18 14:22:10 +02:00
Johan LEROYandGitHub 9376420868 Merge pull request #103 from ineszang/feat/site-detail-view
feat(frontend): vue détail d'un site
2026-09-18 14:14:55 +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
ineszangandGitHub c914d41f33 Merge pull request #110 from ineszang/feat/sonar-dashboard
feat: sonar -> analyse des TU dans le backend
2026-09-18 13:59:33 +02:00
ineszang44 d3047f53e8 Merge branch 'feat/sonar-dashboard' of https://github.com/ineszang/ProjetPiscine_EnerVision into feat/sonar-dashboard 2026-09-18 13:56:06 +02:00
ineszang44 ec63798807 fix: lcov -> xml pour le rapport de couverture 2026-09-18 13:55:46 +02:00
ineszangandGitHub 1e168ef03e Merge branch 'dev' into feat/sonar-dashboard 2026-09-18 13:48:18 +02:00
ineszang44 ddf7e17788 test: properties sonar 2026-09-18 13:39:51 +02:00
ineszang44 56e8f95729 test: jobs de tests et de build de sonarqube 2026-09-18 13:22:31 +02:00
ineszang44 91d435748c test: jobs de tests et de build de sonarqube 2026-09-18 13:17:31 +02:00
ineszang44 0b41580310 test: jobs de tests et de build de sonarqube 2026-09-18 13:14:50 +02:00
ineszang44 e3d436ea53 test: jobs de tests et de build de sonarqube 2026-09-18 13:13:23 +02:00
Johan LEROYandGitHub c453700b13 Merge pull request #101 from ineszang/chore/coverage-tests-frontend-ci
chore(ci): ajoute la couverture de tests au job test du frontend
2026-09-18 12:38:15 +02:00
ineszang44 f427f8a8f3 chore+feat: allègement du workflow front, workflow pour sonarqube 2026-09-18 12:32:18 +02:00
Johan LEROY 7be8a44e89 Merge branch 'dev' into chore/coverage-tests-frontend-ci
Résolution du conflit sur .github/workflows/frontend.yml :
- conserve les étapes upload/download de l'artifact lcov ajoutées sur dev,
  sans lesquelles le rapport ne quitte pas le runner du job test et
  n'atteint jamais le scanner Sonar ;
- conserve le job security-audit et le retrait du bloc deploy commenté ;
- retient la commande de test de la branche.

Le séparateur `--` manquait côté dev : npm consommait les trois flags
comme sa propre configuration et ng test tournait sans argument. De plus
`--code-coverage` n'existe pas dans le builder @angular/build:unit-test,
où l'option s'appelle `coverage`.
2026-09-18 12:30:10 +02:00
Johan LEROYandGitHub 2095ad6bd3 Merge pull request #100 from ineszang/chore/audit-dependances-ci
chore(ci): ajoute un audit de sécurité des dépendances (npm audit, pi…
2026-09-18 12:26:46 +02:00
Johan LEROY fb06bf0062 chore(ci): isole l'audit de sécurité et le fait porter sur le verrou
Backend / Audit des dépendances (push) Successful in 1m30s
Frontend / Audit des dépendances (push) Successful in 7s
Backend / Lint, typage et tests (push) Successful in 4m15s
Frontend / build (push) Successful in 11m3s
Frontend / test (push) Failing after 5m7s
Frontend / SonarQube (push) Skipped
L'audit backend était la dernière étape du job de vérification : un lint
ou un test en échec suffisait à le sauter, et `pip-audit` sans argument
auditait l'environnement courant, donc aussi les 28 paquets injectés par
son propre `--with`. Il audite maintenant l'export du verrou, dans un job
dédié, en symétrie avec le frontend.

Côté frontend, `npm audit` lit le verrou et n'a besoin ni de `npm ci` ni
du job `build`. Le workflow déclare enfin ses permissions, comme
backend.yml et ml.yml.
2026-09-18 12:23:50 +02:00
Johan LEROY e27142c7db Merge branch 'dev' into chore/audit-dependances-ci 2026-09-18 12:23:25 +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
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
Johan LEROY 173f91f26f ci(backend): joue les tests d'intégration sur un service TimescaleDB
`pyproject.toml` écarte le marqueur `integration` par défaut, et aucun workflow ne montait de
base : 97 tests, dont les neuf fichiers de dépôts et le schéma de données, n'avaient jamais
été joués ailleurs que sur un poste. La condition avait été déléguée à #20, fermée le 17/09
sans l'avoir livrée.

Le job monte l'image de `docker-compose.yml` et non une image `postgres` nue : la première
migration refuse de s'appliquer sans l'extension TimescaleDB, et un écart d'image rendrait ce
job vert sur une base qui n'est pas la nôtre. `db/init/110-test-database.sql` n'étant pas
monté ici, l'extension est créée en une étape avant `alembic upgrade head`.

Le job `verification` est inchangé : il reste jouable sans Docker, avec son seuil de
couverture de 85 %.
2026-09-18 12:09:12 +02:00
Johan LEROY 1cd3688256 test(backend): croise chaque route gardée avec les trois rôles
Le dépôt vérifiait le refus d'un lecteur sur les cinq routes `admin`, et rien de plus. Les
huit routes `lecteur` n'étaient jouées qu'avec un lecteur : une garde posée trop haut, par
exemple `AdminDep` sur `/sites`, n'aurait fait échouer aucun test.

La matrice couvre les deux sens. Un rôle insuffisant reçoit un 403 `Droits insuffisants`,
un rôle suffisant ne le reçoit jamais. L'assertion porte sur le refus de la garde et pas sur
un 200, sans quoi elle dépendrait du contenu de la base : un 404 ou un 422 est une réponse
acceptable, un 403 non.

Sous le marqueur `integration`, la même matrice est rejouée avec de vrais jetons obtenus par
`/auth/login`, donc en traversant le décodage du JWT et la relecture du compte en base que
`dependency_overrides` court-circuite. Deux invariants y sont figés : `operateur` n'ouvre
aujourd'hui aucune route de plus que `lecteur`, faute d'écriture métier dans l'API, et
`/auth/logout-all` échappe au refus `password_change_required` parce qu'elle prend un
`CurrentPrincipalDep` nu. Le second est signalé, pas corrigé.

Closes #61
2026-09-18 12:08:59 +02:00
Johan LEROY 7eef960a30 test(backend): classe les routes du contrat et dérive les listes d'autorisation
`ROUTES_A_ROLE` était recopiée dans `test_openapi.py`, et deux de ses entrées portaient
`{id}` là où le contrat expose `{user_id}`. Elles ne correspondaient donc à aucune
opération, et `test_every_role_guarded_route_documents_the_role_refusal` passait au vert
sans rien vérifier sur `PATCH /users/{user_id}` ni sur sa réinitialisation de mot de passe :
11 des 13 routes gardées étaient réellement couvertes.

`tests/api/acces.py` porte désormais la classification des 24 routes du contrat en quatre
ensembles, dont la table `ROLE_MINIMUM`, et `test_every_declared_route_is_classified` refuse
aussi bien une route non classée qu'une entrée qui ne correspond plus à rien. C'est ce que
`docs/architecture/20-backend.md` annonçait comme impossible : « ces deux listes sont
maintenues à la main, pas dérivées ».

Au passage, `chemin_concret()` substitue les trois gabarits du contrat et non plus le seul
`{user_id}`, ce qui est sans effet sur le refus anonyme mais nécessaire à un appel qui doit
aboutir.
2026-09-18 12:08:59 +02:00
ineszang44 12fb8860d1 chore: fichier de configuration pour chaque module (front et back) 2026-09-18 11:54:21 +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
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
ineszangandGitHub af58172742 Merge pull request #99 from ineszang/feat/sonar-dashboard
test: ajout de propriétés dans le fichier de config pour sonarqube
2026-09-18 10:31:19 +02:00
Johan LEROY b433e01fa8 fix(backend): départage aussi les égalités de timestamp dans latest_by_site
Backend / Lint, typage et tests (push) Successful in 1m18s
`latest_by_site` portait le même défaut que `latest_for_site` : `DISTINCT ON (site_id)`
ordonné sur `site_id, timestamp DESC` sans départage, alors que `uq_reading_source`
autorise deux lignes au même `site_id`+`timestamp` quand la `source` diffère.
`/stats/summary` pouvait donc afficher une consommation différente d'un appel à
l'autre pour un site alimenté par un backfill CSV et une écriture live.

Test `integration` dédié, qui échoue sans le correctif.
2026-09-18 10:28:04 +02:00
Johan LEROY 5eb74aa64a fix(backend): traite la revue de phyri0s sur la PR #84
Tri non déterministe : `latest_for_site` départage désormais les égalités de
timestamp par `reading_id` décroissant, comme `list_history`. `uq_reading_source`
autorise deux lignes au même `site_id`+`timestamp` quand la `source` diffère, donc
le `LIMIT 1` pouvait renvoyer l'une ou l'autre d'un appel à l'autre.

Tests : trois tests `integration` sur `latest_for_site` (plus récente, égalité de
timestamp, isolation par site). Le test d'égalité échoue sans le correctif ci-dessus.

Duplication : `DataQuality` et le repli vers `critical` sortent dans
`app/services/data_quality.py`, partagé par `stats.py`, `site.py` et `sensor.py`,
qui en portaient trois copies indépendantes. Supprime au passage deux
`# type: ignore[assignment]`.
2026-09-18 10:28:04 +02:00
ineszang44 cc0a58ac4c test: sonarqube 2026-09-18 10:23:09 +02:00
ineszang44 2400b6f05e test: sonarqube 2026-09-18 10:21:56 +02:00
ineszang44 9e33c276d6 test: sonarqube 2026-09-18 10:16:31 +02:00
ineszang44 6cb9ac00cb test: sonarqube 2026-09-18 10:14:06 +02:00
ineszang44 c1f63889c1 test: sonarqube 2026-09-18 10:10:05 +02:00
ineszang44 5875e8c239 test: sonarqube 2026-09-18 10:01:28 +02:00
ineszang44 c8383014a8 Merge branch 'dev' into feat/sonar-dashboard 2026-09-18 09:52:27 +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 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 LEROYandGitHub 56c134beb0 Merge pull request #95 from ineszang/feat/site-list-view
feat(frontend): vue liste des sites
2026-09-17 16:04:09 +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