# Bugs et anomalies

## Phase 2.1 — validation fonctionnelle (P1)

- Les scénarios précédents ne constituaient pas une preuve UI : les lots et
  équipements `TEST_UI_PHASE21_*` n'étaient pas présents dans la copie VM
  contrôlée et avaient été préparés directement en base/fixtures.
- Avant correction, la page des horaires ne permettait pas de choisir un
  technicien et `PlanningService` pouvait réutiliser la plage d'un autre
  utilisateur. La sélection et le filtrage sont maintenant corrigés ; le
  parcours doit être revalidé manuellement.
- La création d'un lot démarre depuis l'assistant équipement ; il n'existe
  pas encore de formulaire autonome `/lots/new`.

## UI-001 — Transvasement inaccessible

- Priorité : P1
- Module : Matériel & Produits d'entretien
- URL : `/cleaning/transvasement`
- Compte : `chatgpt` / `super_admin`
- Résultat : HTTP 500, écran générique.
- Attendu : formulaire utilisable ou message métier explicite si le stock est
  vide.
- Impact : dilution et transvasement impossibles.

## UI-002 — Configuration des prévisions inaccessible

- Priorité : P1
- Module : Matériel & Produits d'entretien
- URL : `/cleaning/forecast-config`
- Compte : `chatgpt` / `super_admin`
- Résultat : HTTP 500.
- Attendu : coefficients par défaut affichés et modifiables.
- Impact : coefficients de permanence impossibles à configurer.

## UI-003 — Création de salle bloquée

- Priorité : P1
- Module : Établissement
- URL : `/equipments/rooms/new`
- Résultat : le select « Bâtiment » est vide malgré des bâtiments visibles
  dans `/equipments/buildings/`.
- Attendu : bâtiments proposés, puis zones filtrées par bâtiment.
- Impact : impossibilité de poursuivre les scénarios équipements/interventions.

## UI-004 — Confusion Site/Bâtiment

- Priorité : P2
- URL : `/equipments/buildings/`
- Résultat : le formulaire principal crée un `Site` (Collège), tandis que le
  véritable bâtiment se crée via `/equipments/buildings/new`.
- Recommandation : séparer les deux actions et afficher la hiérarchie
  établissement → bâtiment → zone → salle.

## UI-005 — Commit Docker non identifié

- Priorité : P2
- URL : `/health/`, setup
- Résultat : version `0.1.0-dev.2`, commit `unknown`.
- Recommandation : fournir `GIT_VERSION=$(git rev-parse HEAD)` au build.

## UI-006 — Instabilité sous navigation séquentielle

- Priorité : P1 à confirmer
- Résultat : temps de réponse parfois supérieur à 8–30 secondes, puis
  indisponibilité temporaire.
- Recommandation : surveiller CPU/RAM, Gunicorn, connexions MariaDB et
  documenter les temps de réponse sans lancer de test de charge.

## UI-007 — Disponibilités et horaires semblent partager le même écran

- Priorité : P2
- URL : `/planning/availability`
- Résultat : titre « Horaires et suivi annuel » et structure identique à
  `/planning/time`.
- Attendu : redirection explicite ou écran distinct avec un libellé cohérent.
- Impact : l'utilisateur peut croire qu'il existe deux écrans différents.

## UI-008 — Requête 401 visible dans la console au chargement du login

- Priorité : P3 à confirmer
- Résultat : Playwright signale une ressource 401 sur `/auth/login`.
- Impact : bruit console et appel potentiellement lancé avant la session.

## UI-009 — Soumission produit très lente/non confirmée

- Priorité : P1 à confirmer (environnementale ou applicative)
- URL : `/cleaning/products/new`
- Compte : `chatgpt` / `super_admin`
- Étapes : remplir un produit `TEST_UI_DETERGENT_SOL` puis soumettre une
  seule fois.
- Résultat : l'action Playwright est restée bloquée plus de 30 secondes ; la
  requête n'a pas été répétée.
- Impact : impossible de confirmer la création d'un produit dans cette passe.
- Qualification : vérifier les logs et la charge VM avant de conclure à un
  bug applicatif.

## UI-010 — Soumission prévention très lente/non confirmée

- Priorité : P1 à confirmer (environnementale ou applicative)
- URL : `/prevention/`
- Compte : `chatgpt` / `super_admin`
- Étapes : remplir le formulaire d'agent prévention avec des données
  `TEST_UI_*`, puis soumettre une seule fois.
- Résultat : clic bloqué au-delà du délai ; aucune répétition.
- Impact : impossible de confirmer la création d'un personnel de prévention
  dans cette passe.

## UI-011 — Lien Documents renvoie 404

- Priorité : P2
- URL : `/documents/`
- Compte : `chatgpt` / `super_admin`
- Résultat : HTTP 404.
- Attendu : liste documentaire ou redirection vers le module documentaire
  réellement utilisé.
- Impact : lien cassé pour un utilisateur qui cherche les documents.

## UI-012 — Menu non filtré selon les permissions

- Priorité : P1
- Comptes : `TEST_UI_USER_MULTI` et `TEST_UI_USER_NONE`.
- Résultat : les deux dashboards contiennent les mêmes liens équipements,
  interventions et nettoyage, y compris pour `TEST_UI_USER_NONE` sans rôle.
- Backend : `TEST_UI_USER_NONE` reçoit bien 403 sur ces URLs ; le backend est
  donc plus strict que le menu.
- Résultat multi-rôles : `TEST_UI_USER_MULTI` reçoit 200 sur patrimoine et
  interventions, puis 403 patrimoine après un refus individuel, tandis que
  les interventions restent accessibles.
- Impact : UX trompeuse et risque d'erreurs ; un utilisateur voit des liens
  qu'il ne peut pas ouvrir.

## UI-013 — Pagination absente ou non supportée sur plusieurs listes

- Priorité : P2
- `/lots/?page=2` et `/equipments/?page=2` répondent 200.
- `/interventions/?page=2` et `/companies/?page=2` répondent 404.
- Attendu : pagination cohérente, ou absence explicite du paramètre avec une
  interface qui ne l'affiche pas.
- Impact : incohérence de navigation lorsque le volume de données augmente.

## UI-014 — Entreprises sans recherche ni filtre visible

- Priorité : P2
- URL : `/companies/`
- Résultat : aucune zone de recherche ou de tri dans la liste.
- Attendu : recherche par nom/contact lorsque le nombre d'entreprises croît.

## UI-015 — Formulaire entreprise vide provoque une erreur 500

- Priorité : P1
- URL : `/companies/new`
- Étapes : soumettre le formulaire vide avec un CSRF valide.
- Résultat : HTTP 500 au lieu d'une validation utilisateur.
- Attendu : HTTP 400 ou retour formulaire avec champ obligatoire signalé.

## UI-016 — Formulaire intervention vide provoque une erreur 500

- Priorité : P1
- URL : `/interventions/new`
- Étapes : soumettre le formulaire vide avec un CSRF valide.
- Résultat : HTTP 500.
- Attendu : validation des champs obligatoires et message compréhensible.

## UI-017 — Liste interventions casse avec une intervention sans salle

- Priorité : P1
- URL : `/interventions/`
- Donnée : `TEST_UI_INTERVENTION_ELECTRICITE` (ID 1), créée sans salle ni
  équipement pour tester le cas autorisé par le formulaire.
- Résultat : le détail `/interventions/1` répond 200, mais la liste renvoie
  HTTP 500.
- Attendu : afficher l'intervention avec « Salle non renseignée » ou demander
  une salle avant validation.
- Impact : une intervention valide au niveau formulaire rend la liste
  principale inutilisable.

## UI-018 — Titre d'édition ambigu

- Priorité : P2
- URL : `/interventions/1/edit`
- Résultat : le titre HTML reste « Nouvelle intervention » en édition.
- Attendu : « Modifier l'intervention » avec identifiant/titre existant.

## UI-019 — Tableau de bord en erreur avec une intervention sans équipement

- Priorité : P1
- URL : `/`
- Utilisateur : `chatgpt` (super-administrateur)
- Précondition : l'intervention de test ID 1 existe sans équipement associé.
- Étapes : ouvrir une session puis demander `/`.
- Résultat : HTTP 500. Le journal indique
  `dashboard/index.html:495` et l'expression `interv.equipment.name` alors que
  `interv.equipment` vaut `None`.
- Attendu : le tableau de bord doit afficher une valeur de remplacement
  (« Aucun équipement ») ou exclure proprement la relation absente.
- Impact : erreur critique pour la page d'entrée et perte d'accès au tableau
  de bord dès qu'une intervention sans équipement est enregistrée.

## UI-020 — Lien Journaux visible mais accès refusé

- Priorité : P2
- URL : `/logs/`
- Utilisateur : `chatgpt` (rôle personnalisé `chatgpt`)
- Étapes : ouvrir une page autorisée contenant la navigation, puis suivre le
  lien « Journaux » ; ouvrir également `/logs/` directement.
- Résultat : le lien `/logs/` est présent dans le HTML de navigation, mais le
  serveur répond HTTP 403. Le compte possède les permissions d'audit visibles
  dans sa matrice, sans permission effective acceptée par cette route.
- Attendu : masquer le lien si l'accès est refusé, ou attribuer/vérifier la
  permission réellement requise par la route.
- Impact : incohérence UI/backend et perte de temps pour l'utilisateur.

## UI-021 — Certains formulaires planning dépendent de l'injection JavaScript du CSRF

- Priorité : P2
- URLs : `/planning/availability/closure/new`, `/planning/tasks/new`
- Résultat : le HTML initial ne contient pas de champ caché `csrf_token` ; le
  jeton est ajouté par le JavaScript global. Une soumission sans JavaScript
  reçoit bien 400, mais le formulaire ne peut alors pas être utilisé.
- Attendu : rendre le champ CSRF dans le formulaire serveur, tout en gardant
  l'injection JS comme secours pour les requêtes dynamiques.
- Impact : dépendance inutile à JavaScript et accessibilité dégradée.

## UI-022 — État du stock en erreur après une réception valide

- Priorité : P1
- URL : `/cleaning/stock`
- Précondition : produit, référence, conditionnement, emplacement et deux lots
  `TEST_UI_*` réceptionnés avec succès.
- Étapes : ouvrir l'état du stock après les réceptions.
- Résultat : HTTP 500, alors que le journal des mouvements reste accessible et
  affiche les réceptions, la sortie FEFO, le transfert et la correction
  d'inventaire.
- Attendu : afficher les soldes par lot et emplacement, même lorsque les
  mouvements précédents ont modifié les quantités.
- Impact : l'écran central de consultation du stock est inutilisable dès
  qu'un stock réel existe.

## UI-023 — Aucun contrôle UI pour autoriser un produit sur les fiches de demande

- Priorité : P2
- URLs : `/cleaning/products/new`, `/cleaning/products/1/edit`,
  `/cleaning/requests/new`
- Résultat : le modèle distingue `request_enabled`, mais les formulaires du
  produit ne proposent aucun champ pour l'activer. Le formulaire de profil
  affiche donc zéro produit sélectionnable, et la fiche imprimée ne contient
  aucune ligne.
- Attendu : case « Autoriser sur les fiches de demande » dans le produit, avec
  un état visible dans le profil.
- Impact : la fonctionnalité de fiches papier ne peut pas être configurée
  depuis l'interface.

## UI-024 — Valeur numérique invalide sur l'édition d'un produit → 500

- Priorité : P1
- URL : `/cleaning/products/1/edit`
- Étapes : remplacer « Stock minimum » par `abc` et soumettre le produit de
  test.
- Résultat : HTTP 500 au lieu d'un message de validation.
- Attendu : conserver les valeurs saisies et signaler que les quantités
  doivent être numériques, comme le fait déjà la création.
- Impact : une faute de saisie rend l'écran d'édition inutilisable.

## UI-025 — Doublon de référence commerciale accepté sans avertissement

- Priorité : P2
- URL : `/cleaning/references/new`
- Étapes : créer une seconde référence `TEST_UI_REF_DETERGENT_SOL` pour le
  même produit générique.
- Résultat : la soumission est acceptée (302) et deux occurrences apparaissent
  dans la liste, sans avertissement ni indication d'historique.
- Attendu : avertir l'utilisateur ou demander une référence fabricant/
  fournisseur distincte avant de créer un doublon involontaire.
- Impact : catalogue commercial ambigu et risque d'erreur lors des réceptions.

## UI-026 — Labels de formulaires non associés aux contrôles

- Priorité : P2
- Périmètre : formulaires produits, références, conditionnements, réceptions,
  sorties, transferts et prévention.
- Résultat : les libellés sont visuellement présents, mais n'ont pas
  d'attribut `for` et les contrôles n'ont pas d'identifiant associé. Le clic
  sur le libellé ne place donc pas le focus et les lecteurs d'écran ne peuvent
  pas relier automatiquement le nom au champ.
- Attendu : associer chaque `<label for="…">` à un `id` unique, ou envelopper
  explicitement le contrôle dans le label.
- Impact : accessibilité clavier et compréhension des champs dégradées pour
  les utilisateurs débutants ou avec assistance vocale.

## UI-027 — Habilitation prévention accepte des dates inversées

- Priorité : P2
- URL : `/prevention/` (formulaire `/prevention/authorization`)
- Étapes : pour `TEST_UI_AGENT ENTRETIEN`, saisir une date d'émission
  31/12/2026 et une expiration 01/01/2026.
- Résultat : POST accepté avec redirection 302, sans message d'erreur ni
  validation de l'ordre chronologique.
- Attendu : refuser une expiration antérieure à l'émission et expliquer la
  correction attendue.
- Impact : historique d'habilitations incohérent.

## UI-028 — Les habilitations ne sont pas visibles dans le récapitulatif prévention

- Priorité : P2
- URL : `/prevention/`
- Résultat : le formulaire d'ajout d'habilitation est présent, mais aucune
  liste des habilitations enregistrées n'est affichée ; l'entrée de test ne
  peut donc pas être relue ou contrôlée dans l'interface.
- Attendu : tableau agent, habilitation, date d'émission, expiration et
  émetteur, avec signalement des habilitations expirées.
- Impact : absence de suivi opérationnel malgré la possibilité de saisie.

## UI-029 — Listes stock et produits sans recherche ni filtre

- Priorité : P2
- URLs : `/cleaning/products`, `/cleaning/references`,
  `/cleaning/movements`, `/cleaning/requests`
- Résultat : les listes ne présentent ni champ de recherche, ni filtre, ni
  pagination visible. Après ajout de lots et mouvements, retrouver un produit
  ou une opération nécessite de parcourir toute la page.
- Attendu : recherche par produit/référence/lot et filtres par période,
  emplacement et type de mouvement, avec pagination.
- Impact : ergonomie insuffisante dès que le catalogue ou l'historique grandit.

## UI-030 — Document téléversé absent du détail de l'intervention

- Priorité : P1
- URLs : `/interventions/1`, `/documents/upload/intervention/1`
- Étapes : téléverser le fichier artificiel `test_document.pdf` depuis le
  détail de l'intervention de test, puis revenir au détail.
- Résultat : le POST est accepté (302) et le téléchargement
  `/documents/intervention/download/1` répond 200, mais aucun nom ou lien de
   document n'est affiché sur `/interventions/1`.
- Attendu : afficher le document, sa description, sa date et les actions
  téléchargement/suppression dans le détail.
- Impact : l'utilisateur ne sait pas si son fichier a été enregistré et ne
  peut pas le gérer depuis l'intervention.

## Corrections locales — passe P1

Les éléments ci-dessous sont **CORRIGÉS DANS LE CODE — À REVALIDER SUR VM DE TEST**.
La VM et sa base `TEST_UI_*` ne sont pas accessibles depuis cet environnement.

| Bug | Cause racine | Correction locale | Tests locaux |
|---|---|---|---|
| UI-001 | `ReusableContainer` manquait dans les imports de la route | Import explicite du modèle et chargement défensif de la page | `test_cleaning_module.py`, `test_ui_p1_regressions.py` |
| UI-002 | Le nom de contexte `config` masquait la configuration Flask dans `base.html`, en plus de l'import manquant | Import de `CleaningForecastConfig` et contexte renommé `forecast_config` | `test_ui_p1_regressions.py::test_cleaning_pages_load_without_reference_data` |
| UI-003 | La route ne fournissait pas `buildings` au template et n'assurait pas la cohérence zone/bâtiment | Contexte complet, validation serveur et conservation des saisies | `test_ui_p1_regressions.py::test_room_form_lists_buildings_and_rejects_cross_building_zone`, `test_equipment_forms.py` |
| UI-015 | Le nom entreprise était envoyé directement en base sans validation | Validation obligatoire et retour formulaire HTTP 400 | `test_ui_p1_regressions.py::test_empty_intervention_and_company_are_validation_errors` |
| UI-016 | Le titre et les dates d'intervention étaient parsés sans validation | Validation du titre et des dates/heures avec message français | `test_ui_p1_regressions.py::test_empty_intervention_and_company_are_validation_errors` |
| UI-017 | Le template appelait `interv.equipment.name` lorsque l'équipement était absent | Affichage salle/localisation générale de remplacement | `test_ui_p1_regressions.py::test_optional_location_is_safe_in_interventions` |
| UI-019 | Le dashboard appelait `interv.equipment.name` lorsque l'équipement était absent | Garde équipement/salle/aucune localisation | `test_ui_p1_regressions.py::test_optional_equipment_is_safe_on_dashboard` |
| UI-022 | La vue stock n'injectait pas `current_date`, utilisé par le template | Passage explicite de la date courante | `test_ui_p1_regressions.py::test_cleaning_pages_load_without_reference_data`, tests stock existants |
| UI-024 | `Decimal()` non protégé dans l'édition produit | Validation numérique et rollback sans 500 | `test_ui_p1_regressions.py::test_invalid_product_quantity_is_validation_error` |
| UI-030 | La fiche module utilisait des endpoints de documents inexistants et une relation dynamique directement dans Jinja | Endpoints réels, liste de documents matérialisée dans la route et template | `test_ui_p1_regressions.py::test_intervention_detail_template_exposes_document_actions` |
| UI-012 | Les groupes de navigation et liens métier étaient statiques | Filtrage des groupes, liens et raccourci logs par `has_permission()` | Vérification de compilation/rendu des templates et suite ciblée |

Les résultats ci-dessus sont des tests automatisés locaux uniquement ; ils ne
valident pas la base distante ni le rendu sur la VM d'audit.

## Revalidation sur la VM de test — 22 août 2026

Passe exécutée séquentiellement sur `http://82.64.101.239/` avec `chatgpt`.
La base existante et les données `TEST_UI_*` ont été conservées ; aucun
watchdog, intégration externe ou utilisateur `alban` n'a été modifié.

| Bug | Résultat VM | Scénario et données |
|---|---|---|
| UI-003 | **VALIDÉ SUR VM** | `/equipments/rooms/new` propose les bâtiments existants ; création de `TEST_UI_REVALIDATION_SALLE` ; bâtiment 2 + zone 1 est refusé en HTTP 400. |
| UI-017 | **TOUJOURS REPRODUCTIBLE** | `/interventions/` reste en HTTP 500 avec l'intervention ID 1 sans salle/équipement. |
| UI-019 | **VALIDÉ SUR VM** | `/` renvoie 200 et affiche « Aucun équipement », sans `None`, `null` ni `undefined` visibles. |
| UI-001 | **VALIDÉ SUR VM** | `/cleaning/transvasement` 200 ; transvasement test de 0,1 L enregistré et quantité impossible refusée proprement. |
| UI-002 | **VALIDÉ SUR VM** | `/cleaning/forecast-config` 200 ; coefficient non numérique renvoyé en 400 avec message, sans 500. |
| UI-022 | **VALIDÉ SUR VM** | `/cleaning/stock` 200 après lots, réceptions, sortie, transfert et correction ; produits, lots et emplacements visibles. |
| UI-015 | **VALIDÉ SUR VM** | POST vide `/companies/new` en 400 avec formulaire ; `TEST_UI_REVALIDATION_ENTREPRISE` créé (ID 2). |
| UI-016 | **VALIDÉ SUR VM** | POST vide `/interventions/new` en 400 ; `TEST_UI_REVALIDATION_INTERVENTION` créé (ID 2). |
| UI-024 | **VALIDÉ SUR VM** | `stock_minimum=abc` sur le produit ID 1 renvoie 400 et conserve le formulaire. |
| UI-030 | **VALIDÉ SUR VM** | PDF artificiel `TEST_UI_REVALIDATION_DOCUMENT.pdf` visible dans le détail de l'intervention 1 et téléchargeable (document ID 2). |
| UI-012 | **CORRIGÉ PARTIELLEMENT — PROBLÈME RÉSIDUEL** | Le bouton global `/logs/` reste visible alors que l'URL renvoie 403. Les comptes `TEST_UI_USER_MULTI` et `TEST_UI_USER_NONE` n'ont pas pu être reconnectés : leurs mots de passe ne sont pas documentés. |

### UI-031 — nouveau blocage observé

Les groupes `TEST_UI_EQ_CHAISES` (30 individuels) et
`TEST_UI_EQ_CHAISE_UNITAIRE` créés dans `TEST_UI_CLASSE_101` apparaissent dans
`/equipments/` et dans la salle, mais `/equipments/1` et `/equipments/2`
renvoient HTTP 500. `/equipments/<id>/hierarchy` renvoie une liste de zones
vide. Les déplacements et cycles de vie restent donc bloqués. Anomalie
documentée uniquement, sans correction pendant cette passe.

## Passe corrective ciblée — 22 août 2026

Les trois blocages restants ont été corrigés dans le dépôt local. La VM
auditée n'est pas accessible depuis cette passe : chaque statut ci-dessous
reste **CORRIGÉ DANS LE CODE — À REVALIDER SUR VM**.

### UI-017 — liste des interventions

- Cause : les templates de liste et du planning préventif accédaient
  directement à `interv.equipment.name` pour des relations optionnelles.
- Correction : affichage conditionnel de l'équipement, puis de la salle, puis
  du libellé humain `Localisation non renseignée`.
- Fichiers : les deux templates `interventions/index.html` et les deux
  templates `interventions/planning.html`.
- Tests : quatre combinaisons salle/équipement couvrent liste, détail et
  dashboard.
- Statut : **CORRIGÉ DANS LE CODE — À REVALIDER SUR VM**.

### UI-031 — détail et hiérarchie des équipements groupés

- Cause du détail 500 : le template global affichait
  `equipment.preventive_count`, propriété absente du modèle `Equipment`.
- Correction : ajout de cette propriété calculée au modèle, sans migration.
- Cause de la hiérarchie vide : l'endpoint ne sélectionnait que les
  descendants ; une famille quantitative sans enfant produisait zéro ligne,
  même si sa salle était renseignée.
- Correction : si aucun descendant n'est trouvé, l'équipement racine est
  ajouté avec son bâtiment, sa zone, sa salle et sa quantité effective.
- Fichiers : `app_new/core/models/equipment.py` et
  `app_new/equipments/main.py`.
- Tests : famille quantitative de quantité 30, détail rendu et endpoint
  hierarchy vérifié avec zone/salle/quantité.
- Statut : **CORRIGÉ DANS LE CODE — À REVALIDER SUR VM**.

### Résidu UI-012 — lien Journaux

- Cause : la navigation vérifiait `audit.view`, alors que la garde globale de
  `logs.index` exige `watchdog_dnd.view`.
- Correction : le bouton `/logs/` utilise désormais exactement
  `has_permission('watchdog_dnd.view')`.
- Fichier : `app_new/templates/base.html`.
- Tests : concordance vérifiée avec `required_permission('logs.index', 'GET')`.
- Statut : **CORRIGÉ DANS LE CODE — À REVALIDER SUR VM**.

## Revalidation VM après déploiement — 22 août 2026

Correctifs observés : `8c54f46`, `864f65d`, `f2783a0`, `ce6d8ae`.

### UI-017 — liste des interventions

**Statut : VALIDÉ SUR VM.** `/interventions/` répond HTTP 200 avec
l'intervention sans salle ni équipement et affiche « Localisation non
renseignée ». Les détails testés, le planning (redirigé vers `/planning/`) et
le dashboard répondent également 200. Aucun texte `None`, `null` ou
`undefined` n'est visible.

### UI-031 — détail et hiérarchie des équipements groupés

**Statut : TOUJOURS REPRODUCTIBLE (correction partielle).** Les détails
`/equipments/1` et `/equipments/2` renvoient encore HTTP 500 pour
`TEST_UI_EQ_CHAISES` (quantité 30) et `TEST_UI_EQ_CHAISE_UNITAIRE` (quantité
1). En revanche, les endpoints `/equipments/1/hierarchy` et
`/equipments/2/hierarchy` répondent HTTP 200 et contiennent la hiérarchie
`TEST_UI_ZONE_PEDAGO → TEST_UI_CLASSE_101`, avec les quantités 30 et 1. Les
déplacements, la casse et le cycle de vie n'ont pas été exécutés, car le
détail reste bloquant.

### UI-012 — lien Journaux

**Statut : VALIDÉ SUR VM pour le compte sans permission ; contrôle positif à
compléter.** Avec `chatgpt`, l'accès direct `/logs/` reste HTTP 403 et le
dashboard ne contient plus aucun lien `logs`. Les identifiants des anciens
comptes à permissions réduites ne sont pas documentés ; aucun compte n'a été
modifié et `alban` n'a pas été touché. Le contrôle positif avec
`watchdog_dnd.view` devra être réalisé lors d'une prochaine passe.

## Reproduction et correction locale — UI-031 — 22 août 2026

Sur la copie locale de la base VM, `/equipments/1` reproduisait le 500. Le
traceback exact était `jinja2.exceptions.TemplateRuntimeError: No filter
named 'nl2br' found`, dans `app_new/templates/equipments/detail.html`.

Le filtre est désormais enregistré dans la factory Flask avec échappement du
contenu et conversion des retours à la ligne. Après reconstruction Docker,
les détails réels des équipements 1, 2 et 3 répondent 200. Le test ciblé de
non-régression passe (`1 passed`).

Statut : **VALIDÉ LOCALEMENT SUR COPIE VM**.

## Scénarios équipements locaux

- Groupe quantitatif ID 3 : 30 chaises en salle 2 ; déplacements de 1 puis 5
  unités vers salle 3, groupe cible ID 4 avec 6 unités et mouvements tracés.
- Quantité 999 : refus métier, sans mouvement supplémentaire ni stock
  négatif.
- Réparation : unité ID 5 individualisée, intervention ID 3 créée, puis
  remise en service et événements de cycle de vie présents.
- Rebut : unité ID 6 proposée puis confirmée, statut final `jete`, localisation
  supprimée et historique conservé.
- Équipement fixe : `TEST_UI_EQ_LUMINAIRE_LOCAL` ID 7, déplacement refusé.

Ces scénarios sont **VALIDÉS LOCALEMENT SUR COPIE VM** ; ils restent à
rejouer sur la VM distante si une validation distante est nécessaire.

## UI-023 — correction locale

Le champ `request_enabled` existait en base mais n'était pas présent dans le
formulaire produit, empêchant de rendre un produit disponible sur les fiches
papier. Le champ est maintenant éditable avec un libellé explicite ; la
modification du produit ID 1 a été enregistrée et le produit apparaît dans le
profil de demande. Statut : **VALIDÉ LOCALEMENT SUR COPIE VM**.

## Phase finale — éléments encore ouverts

### UI-011 — centre documentaire global absent (corrigé localement)

- **Reproduction historique** : `GET /documents/` répondait HTTP 404.
- **Correction Phase 1** : route globale par adaptateurs en lecture,
  agrégation interventions/équipements/produits et vue FDS ; aucun fichier
  ni document métier n'est dupliqué.
- **Impact** : un utilisateur peut suivre une URL ou chercher « Documents »
  et recevoir une erreur au lieu d'une orientation.
- **Statut** : **CORRIGÉ DANS LE CODE — À REVALIDER SUR VM**.
- **Limites** : Contract, prévention et documents sensibles restent hors V1 ;
  téléchargement refusé si le fichier physique est absent ou hors racine.

### Observations UX non corrigées

- Menus denses et regroupements hétérogènes, proposition UX-P1.
- États vides ne guidant pas toujours vers la prochaine action, UX-P1.
- Unités et conséquences d'actions à expliciter dans plusieurs formulaires,
  UX-P1/UX-P2.
- Campagne visuelle responsive/accessibilité exhaustive encore partielle.

### Test d'isolation RBAC — corrigé

Le test `test_admin_is_explicit_and_loses_removed_permission` retirait une
permission du rôle système `admin` sans la restaurer, ce qui provoquait un
faux échec ultérieur du smoke stock selon l'ordre d'exécution. Le test restaure
maintenant le lien dans un bloc `finally` (`933f0a5`). La suite ciblée passe
22/22 et la suite complète ne conserve plus que l'échec historique GMAO
lookback hors périmètre et son erreur de teardown.

## Phase 1.5 — anomalies revalidées

- Aucun nouveau bug bloquant observé sur la copie locale.
- L'ancien bouton d'import Pronote « non implémenté » est raccordé au
  planning interne ; les erreurs de récupération sont gérées sans vider les
  créneaux connus.
- Responsive/accessibilité visuels restent à confirmer avec un navigateur
  instrumenté avant VM distante.

## Phase 1.6 — navigation et UX

- Aucun nouveau 404/500 constaté dans les destinations principales du nouveau
  menu lors des tests ciblés.
- L'ancien menu est conservé volontairement ; il ne constitue pas une
  nouvelle surface d'autorisation et reste visible uniquement aux comptes
  disposant de `system.admin`.
- Limitation ouverte : validation visuelle responsive aux trois tailles
  demandées, faute de navigateur instrumenté disponible.
- Le test d'horaires exceptionnels dépendait de fermetures créées par d'autres
  scénarios ; son isolement a été corrigé. Aucun nouvel échec fonctionnel ne
  subsiste dans la suite complète.
- La première présentation de l'ancien menu sous Administration a été
  corrigée : il est désormais une rubrique principale parallèle, sans impact
  sur les permissions backend.
### Revue inventaire navigation historique (2026-08-23)

Le total Phase 1.6 annoncé à 70 était incomplet. La comparaison Git avec la
navigation desktop avant refonte a identifié six entrées conditionnelles
oubliées, dont les quatre fonctions ENT/Pronote signalées. Elles sont
maintenant représentées dans `Ancien menu > Configuration` et dans la matrice
(`MENU_MIGRATION_MATRIX.md`). Aucun endpoint, contrôle RBAC ou comportement
d'intégration n'a été modifié. Nouveau total : 76/76.
