feat: page Santé de l'API dans le back-office, carte des routes qui ne peut pas diverger du code #175

Merged
Corentin merged 2 commits from feat/admin-health into dev 2026-09-27 16:20:59 +02:00
Owner

Une page du back-office, /admin/health, qui montre l'API vivante : son etat, de vrais appels, le trajet d'une requete, et la carte de ses 157 routes. Permission role.manage, aucune permission ajoutee.

Les quatre blocs

  • Etat en direct : version servie, environnement, affichage des erreurs, base joignable avec temps de reponse mesure, migrations et jeux de donnees appliques, activite des 24 dernieres heures (comptes seulement). Relu toutes les 15 s par GET /admin/api/health.
  • Sept appels reels : 200, 200, 401 AUTH_REQUIRED, 403 CSRF_INVALID, 415, 404, 405 — tous refuses avant toute ecriture.
  • Le trajet anime d'un appel, couche par couche, avec la simulation de chaque refus.
  • La carte des 157 routes, lue en direct dans le routeur.

Pourquoi la carte ne peut pas mentir

  • Les routes quittent le controleur frontal pour src/app/Core/routes.php : la page les lit dans le routeur. Un test compare les 155 routes existantes a origin/dev : meme ordre, memes gestionnaires.
  • Les exigences de chaque route vivent dans une seule table, App\Health\RouteSecurity, que les tests lisent aussi :
    • couverture routeur <-> table dans les deux sens ;
    • le test de matrice de l'API perd sa copie : 227 -> 230 cas (les 52 routes d'avant + la nouvelle) ;
    • chaque badge du back-office HTML est verifie par un test de comportement sur 91 routes : session, permission dans les deux sens, jeton, code personnel (toujours, et seulement si le prix ou la TVA change), et aucune exigence fantome.
  • Ces tests ont trouve une fausse affirmation le jour meme : POST /logout etait annonce « session requise », le controleur ne verifie que le jeton. Table corrigee.

Pourquoi les appels sont sans danger

Les deux sondes d'ecriture visent une route gardee par role.manage, la permission meme de la page : le refus observe est celui du jeton ou du type de contenu, examines avant toute ecriture. Un test fait passer chaque sonde par le vrai routeur, les vrais controleurs et une vraie MariaDB, et verifie que les compteurs d'ecriture du serveur n'ont pas bouge.

Ce qui ne change pas

/api/health, la sonde du deploiement continu, est strictement inchangee (reponse figee par son test existant).

Verifications

Controle Resultat
PHPUnit (MariaDB reelle) 2345 tests, 7761 assertions, 0 echec (1725 avant)
PHPStan niveau 6 0 erreur
Tests JavaScript 399, 0 echec (374 avant)
Audit d'accessibilite mesure 19 ecrans, 943 contrastes, 0 violation ; la page : 26 regles conformes, 62 contrastes
Navigateur reel, pile jetable page 200, 157 routes, 7/7 sondes conformes, relecture a 15 s, aucune erreur de script ni violation CSP ; manager : page et API en 403

Limites assumees

  • Le conteneur applicatif ne monte pas db/ : la page affiche les migrations appliquees, pas le nombre de fichiers presents, et le dit.
  • Le JavaScript de la page n'a pas ete ecrit strictement tests d'abord.
  • L'audit du jour a ete joue une fois, sans double passage.

Fiche de decision : docs/adr/0019-page-sante-api-carte-vivante.md · Journal : docs/journal/2026-09-27--page-sante-api.md · Preuve : docs/soutenance/preuves/06-audit-accessibilite-mesure.md section 5 quater

Une page du back-office, **`/admin/health`**, qui montre l'API vivante : son etat, de vrais appels, le trajet d'une requete, et la carte de ses 157 routes. Permission `role.manage`, aucune permission ajoutee. ## Les quatre blocs - **Etat en direct** : version servie, environnement, affichage des erreurs, base joignable avec temps de reponse mesure, migrations et jeux de donnees appliques, activite des 24 dernieres heures (comptes seulement). Relu toutes les 15 s par `GET /admin/api/health`. - **Sept appels reels** : 200, 200, 401 `AUTH_REQUIRED`, 403 `CSRF_INVALID`, 415, 404, 405 — tous refuses avant toute ecriture. - **Le trajet anime** d'un appel, couche par couche, avec la simulation de chaque refus. - **La carte des 157 routes**, lue en direct dans le routeur. ## Pourquoi la carte ne peut pas mentir - Les routes quittent le controleur frontal pour `src/app/Core/routes.php` : la page les lit dans le routeur. Un test compare les 155 routes existantes a `origin/dev` : meme ordre, memes gestionnaires. - Les exigences de chaque route vivent dans **une seule table**, `App\Health\RouteSecurity`, que les tests lisent aussi : - couverture routeur <-> table dans les deux sens ; - le test de matrice de l'API perd sa copie : **227 -> 230 cas** (les 52 routes d'avant + la nouvelle) ; - **chaque badge du back-office HTML est verifie par un test de comportement** sur 91 routes : session, permission dans les deux sens, jeton, code personnel (toujours, et seulement si le prix ou la TVA change), et aucune exigence fantome. - **Ces tests ont trouve une fausse affirmation le jour meme** : `POST /logout` etait annonce « session requise », le controleur ne verifie que le jeton. Table corrigee. ## Pourquoi les appels sont sans danger Les deux sondes d'ecriture visent une route gardee par `role.manage`, la permission meme de la page : le refus observe est celui du jeton ou du type de contenu, examines avant toute ecriture. Un test fait passer chaque sonde par le vrai routeur, les vrais controleurs et une vraie MariaDB, et verifie que les compteurs d'ecriture du serveur n'ont pas bouge. ## Ce qui ne change pas **`/api/health`**, la sonde du deploiement continu, est strictement inchangee (reponse figee par son test existant). ## Verifications | Controle | Resultat | |---|---| | PHPUnit (MariaDB reelle) | 2345 tests, 7761 assertions, 0 echec (1725 avant) | | PHPStan niveau 6 | 0 erreur | | Tests JavaScript | 399, 0 echec (374 avant) | | Audit d'accessibilite mesure | 19 ecrans, 943 contrastes, 0 violation ; la page : 26 regles conformes, 62 contrastes | | Navigateur reel, pile jetable | page 200, 157 routes, **7/7 sondes conformes**, relecture a 15 s, aucune erreur de script ni violation CSP ; manager : page et API en 403 | ## Limites assumees - Le conteneur applicatif ne monte pas `db/` : la page affiche les migrations appliquees, pas le nombre de fichiers presents, et le dit. - Le JavaScript de la page n'a pas ete ecrit strictement tests d'abord. - L'audit du jour a ete joue une fois, sans double passage. Fiche de decision : `docs/adr/0019-page-sante-api-carte-vivante.md` · Journal : `docs/journal/2026-09-27--page-sante-api.md` · Preuve : `docs/soutenance/preuves/06-audit-accessibilite-mesure.md` section 5 quater
feat: live API health page in the back-office, with a route map that cannot drift from the code
Some checks failed
CI / secret-scan (push) Failing after 20s
CI / php-lint (push) Successful in 24s
CI / static-tests (push) Successful in 2m34s
CI / js-tests (push) Successful in 39s
CI / shell-tests (push) Successful in 7s
CI / secret-scan (pull_request) Failing after 21s
CI / php-lint (pull_request) Successful in 25s
CI / static-tests (pull_request) Successful in 2m38s
CI / js-tests (pull_request) Failing after 3m58s
CI / shell-tests (pull_request) Successful in 6s
7793c36a1a
New /admin/health page (role.manage, no new permission) and GET /admin/api/health:
- live state: served version, environment, display_errors, database reachability
  with measured latency, applied migrations and seeds, last-24h activity as counts only;
  re-read every 15 s, paused while the tab is hidden
- seven real calls fired from the page (200, 200, 401, 403 token, 415, 404, 405),
  all refused before any write
- animated request journey, ported from the reviewed standalone page
- map of the 157 routes read live from the router

Routes move from the front controller to src/app/Core/routes.php, loaded by index.php
at the same place (same order, same handlers, verified against origin/dev). Per-route
requirements live in one table, App\Health\RouteSecurity, which the tests read too:
- router <-> table coverage in both directions
- RouteMatrixTest loses its duplicated table: 227 -> 230 cases (52 routes + health)
- behaviour tests for every badge on the 91 HTML back-office routes: session,
  permission both ways, token, PIN (always and price-only), no phantom PIN
- probes run through the real router, controllers and MariaDB; server write counters
  checked unchanged

The behaviour tests caught one wrong claim on day one: POST /logout was listed as
session-required, the controller only checks the token. Table corrected.

/api/health, the continuous-deployment probe, is unchanged.
Accessibility audit: 19 screens, 943 contrast measurements, 0 violation.
PHPUnit 2345 green, PHPStan level 6 clean, 399 JS tests green.
ADR-0019, journal entry, evidence notes 04 and 06 updated.
Corentin scheduled this pull request to auto merge when all checks succeed 2026-09-27 15:51:25 +02:00
test: replace a high-entropy fake import token that gitleaks flagged as an API key
All checks were successful
CI / secret-scan (push) Successful in 24s
CI / php-lint (push) Successful in 40s
CI / static-tests (push) Successful in 2m59s
CI / js-tests (push) Successful in 1m4s
CI / shell-tests (push) Successful in 7s
CI / secret-scan (pull_request) Successful in 20s
CI / php-lint (pull_request) Successful in 26s
CI / static-tests (pull_request) Successful in 2m37s
CI / js-tests (pull_request) Successful in 1m5s
CI / shell-tests (pull_request) Successful in 8s
b7ab74bf9b
Sign in to join this conversation.
No reviewers
No labels
auto-merge
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
AcadeNice/corentin_wakdo!175
No description provided.