Visite hors ligne quasi non fonctionnelle
-Le switch de collecte des ressources est commenté dans Export et côté visitapp. Une visite téléchargée n'embarque ni images d'articles ni audios.
diff --git a/STATUS.md b/STATUS.md
index 1b059b5..97b9861 100644
--- a/STATUS.md
+++ b/STATUS.md
@@ -308,6 +308,12 @@ Les lots 1 et 2 sont terminés. **Le lot 3 et le lot médias sont tous les deux
**Chemin critique** : A (assainir) → B (geler le schéma) → G (`MigrationController`) → H (tests) → **J (RGPD)** → I (bascule). C, D, D-bis, E, F se parallélisent.
+**D1 — le bug offline nº1 est corrigé (2026-08-11).** Le `switch` de collecte des ressources était commenté **des deux côtés** : 157 lignes mortes dans `ConfigurationController.Export`, 126 dans `Import`, et le pendant dans `downloadConfiguration.dart`. Une visite téléchargée n'embarquait donc que l'image de la configuration, celle du loader et l'image de chaque section.
+
+Remplacé par `GetReferencedResourceIds()`, déjà implémentée sur les 13 sous-types. Côté import et côté client, la charge est enregistrée en une passe au lieu d'être redécouverte section par section — ce qui répare au passage la purge des fichiers obsolètes, pilotée par `usedImageOrAudioIds`. **4 tests**, dont un qui vérifie par réflexion que les 13 sous-types implémentent la collecte : le trou venait d'un `switch` où un type oublié passait dans le `default` sans bruit. `dotnet test` **148/148**.
+
+⚠️ Le volet visiteur ne tient que sur `flutter analyze` — l'APK de `mymuseum-visitapp` ne compile pas (Gradle/NDK, §1bis). **À confirmer sur device au §21.**
+
**Lot G — les 8 écarts sont clos et le dry run est joué (2026-08-11).** `dotnet build` vert, `dotnet test` **143/143**.
**Trois des huit n'existaient pas.** Le plan les décrivait en « perte de données » ; l'export Mongo dit qu'il n'y a rien à perdre :
@@ -375,9 +381,9 @@ Constat du 2026-08-11, plus ouvert que ce que ce fichier annonçait : l'écran G
|---|---|
| DB0 — rapatrier les maquettes | ✅ 2026-08-11 |
| DB1 — socle visuel `constants.dart` | ✅ 2026-08-11 — 11 rôles typographiques, 8 espacements, 5 rayons. **Échelle des maquettes, couleurs de l'app** : un écran neuf se fond dans manager-app, il n'y ouvre pas une seconde palette. Pas de thème sombre |
-| DB2 — sauvegarde au fil de l'eau SectionParcours | 🔨 2026-08-11 — **la perte silencieuse est fermée**. Les trois dialogues (`showNewOrUpdateGuidedPath`, `…GuidedStep`, `…QuizQuestion`) faisaient `Navigator.pop` sur « Annuler » sans rien demander, chacun jetant tout ce qui était saisi sous lui — le plus coûteux étant une question de quiz avec ses réponses. Confirmation ajoutée aux trois (réutilise `showConfirmationDialog`, pas de nouveau composant) + `PopScope` contre le retour navigateur. Détection par instantané JSON pris **après la première frame**, parce que `ensureSimpleResponse` écrit dans la question pendant la construction et ferait passer un dialog intact pour modifié. 3 clés i18n FR/EN/NL, `flutter build web` ✅.
**Décidé le même jour : la persistance incrémentale passe à DB4**, les deux étant alternatives — voir v1-plan.md |
+| DB2 — sauvegarde au fil de l'eau SectionParcours | ✅ 2026-08-11, **puis retiré le même jour par DB4**. Le garde-fou (confirmation d'abandon sur les trois dialogues + `PopScope`) a fermé la perte silencieuse le temps que la persistance arrive. Les trois dialogues n'existent plus et il n'y a plus de travail non enregistré à perdre : les 3 clés i18n sont supprimées. C'était l'issue prévue par l'arbitrage — les deux étaient alternatives, pas cumulables |
| DB3 — écran Guide IA 2 onglets | 🔨 2026-08-11 — coquille à onglets, aperçu de conversation sur le **vrai** `/api/AI/chat`, onglet « Ce que demandent vos visiteurs » **alimenté** par `GET /api/Ai/insights/{id}`, carte « Ce que connaît votre guide » sur `GET /api/Ai/knowledge/{id}`, journalisation `VisitorQuestion` branchée dans `AiController.Chat`. 34 clés i18n FR/EN/NL. **Reste** : le job de regroupement en thèmes, la purge 90 j, **le RGPD dans les CGU avant mise en service**, l'onglet « Vocal » des stats |
-| DB4 — forme SectionParcours | ❌ — **option A recommandée**. Le seul gain de B était une colonne d'aperçu, déjà couverte par l'aperçu du Guide IA |
+| DB4 — forme SectionParcours | 🔨 2026-08-11 — **option A livrée : une fenêtre, un rail d'étapes, profondeur 2**. Les trois `showNewOrUpdate…` sont supprimés au profit de `guided_path_editor.dart` (coquille : fil d'Ariane, rail réordonnable, panneau, pied « Enregistré ») et de trois widgets de champs autonomes — `ParcoursFields`, `EtapeFields`, `QuestionFields` dans `Parcours/Fields/`. Une question se **déplie dans le panneau de l'étape**, plus dans une 4ᵉ fenêtre.
**Sauvegarde à la saisie** : `guided_path_api.dart` masque le choix `sectionParcoursApi` / `sectionMapApi`, un débounce de 700 ms écrit le parcours (PUT), chaque étape (POST/PUT/DELETE) et ses questions avec elle. Le parcours est **créé à la première modification**, pas à l'ouverture — fermer une fenêtre neuve sans rien saisir ne laisse rien en base. **Deux pièges du backend** : `UpdateGuidedPath` **supprime les étapes absentes du DTO**, donc le payload n'emporte que celles qui ont déjà un id (les autres attendent leur `CreateGuidedStep` et feraient un doublon) ; et les questions n'ayant pas d'endpoint, leur id entier est récupéré après coup **par `order`**, seul repère stable entre les deux listes. Échec d'écriture : la fenêtre refuse de se fermer et le pied de page porte un « Réessayer ». 14 clés i18n FR/EN/NL, 3 retirées (DB2). `flutter analyze` propre sur le dossier, `flutter build web` ✅.
**Reste** : DB5, la vérification à l'œil contre la maquette |
**`AIApi` était dans le client généré mais exposé nulle part** dans `client.dart` — les 18 autres façades y sont. Câblé le 2026-08-11.
diff --git a/kanban.html b/kanban.html
index cc3063f..88b0911 100644
--- a/kanban.html
+++ b/kanban.html
@@ -456,11 +456,11 @@
Le switch de collecte des ressources est commenté dans Export et côté visitapp. Une visite téléchargée n'embarque ni images d'articles ni audios.
Le filtre incrémental teste la présence du fichier, pas sa version. Une image remplacée dans le CMS ne remonte jamais sur le device. Invisible pour le client.
@@ -656,7 +649,7 @@Cinq surfaces empilées pour poser une question sur une étape et l'écrire en NL. Option A recommandée (fenêtre unique, rail d'étapes toujours visible, profondeur max 2) : le seul gain réel de l'option B était une colonne d'aperçu visiteur, déjà couverte par l'aperçu de conversation du Guide IA. Maquette rapatriée dans claude design/sectionparcours-refonte-flux.html.
Extraire d'abord ParcoursFields / EtapeFields / QuestionFields en widgets autonomes : sert A et B à l'identique.
Porte aussi la sauvegarde incrémentale, héritée de DB2 le 11/08 : les deux sont alternatives, et c'est le rail d'étapes de l'option A qui rend la persistance à la saisie naturelle. Le terrain est déballé — CreateGuidedStep / UpdateGuidedStep / DeleteGuidedStep existent déjà sur sectionParcoursApi et sectionMapApi, et le backend persiste bien les questions imbriquées. Il n'y a pas d'endpoint QuizQuestion : les questions partent avec leur étape, c'est voulu.
La coquille à onglets, l'aperçu de conversation et la carte de connaissance compilent (flutter build web ✅) mais n'ont jamais été affichés dans un navigateur — le défaut récurrent de ce tableau. Exige un manager-service qui tourne et une session ouverte : flutter run -d chrome, puis comparaison côte à côte avec claude design/guide-ia-screen.html.
Deux écrans neufs compilent (flutter build web ✅) mais n'ont jamais été affichés dans un navigateur — le défaut récurrent de ce tableau. Le Guide IA (coquille à onglets, aperçu de conversation, carte de connaissance) et l'éditeur de parcours refondu (rail d'étapes, panneau, questions dépliées, enregistrement à la saisie).
Exige un manager-service qui tourne et une session ouverte : flutter run -d chrome, puis comparaison côte à côte avec claude design/guide-ia-screen.html et claude design/sectionparcours-refonte-flux.html. Pour le parcours, rejouer aussi test-plan.md §19.13 cas 0.
Trente chantiers clos entre le 5 et le 11 août 2026.
+Trente et un chantiers clos entre le 5 et le 11 août 2026.
switch qui collecte les ressources d'une configuration était commenté des deux côtés : 157 lignes mortes dans ConfigurationController.Export, 126 dans Import, et le pendant dans downloadConfiguration.dart. Une visite téléchargée n'embarquait donc que l'image de la configuration, celle du loader et l'image de chaque section — ni contenus d'articles, ni audios, ni icônes de carte, ni images de quiz. Remplacé par GetReferencedResourceIds(), qui existait déjà sur les 13 sous-types et n'attendait que d'être appelée. Côté import et côté client, la charge est enregistrée en une passe au lieu d'être redécouverte section par section : le serveur sait maintenant ce qu'il envoie, le client n'a plus à le deviner — et ça répare au passage la purge des fichiers obsolètes, pilotée par la même liste d'ids utilisés. 4 tests, dont un qui vérifie par réflexion que les 13 sous-types implémentent la collecte : le trou venait d'un switch où un type oublié passait dans le default sans bruit, et c'est exactement ce qu'il ne faut plus pouvoir refaire. dotnet test 148/148. ⚠️ Le volet visiteur ne tient que sur l'analyse — l'APK ne compile pas — confirmation sur device au §21, carte « Visite hors ligne sur device » déjà en attente.
+ SectionEvent et SectionParcours sont nés avec Postgres v3, le default est un filet et non un trou, et le « scénario carnaval » qu'on croyait menacé est du contenu à créer, pas à migrer. (f) les trois booléens forcés à false : ces colonnes n'existent pas dans Mongo, false est le bon défaut — et le contrôle inverse a été fait, les cinq réglages qui existent vraiment dans l'export (IsDate, IsHour, IsSectionImageBackground, RoundedValue, ScreenPercentageSectionsMainPage) sont bien mappés sur AppConfigurationLink. (g) était tombé avec le rename du lot B. Trois cartes de la colonne « Bascule prod » se ferment sans une ligne de code.
@@ -926,7 +916,13 @@
Navigator.pop sur « Annuler » sans rien demander, pas un — Parcours, Étape et Question, chacun jetant tout ce qui était saisi sous lui. Le plus coûteux est le plus profond : une question de quiz avec ses réponses. Ce n'était pas « la croix » comme le disait cette carte, c'était le bouton Annuler, et le clic hors fenêtre était déjà neutralisé — le vrai chemin de perte restant est le retour arrière du navigateur, couvert par PopScope. Détection des modifications par instantané JSON, pris après la première frame : le dialog Question normalise ses réponses pendant sa construction, un instantané pris avant aurait déclaré « modifié » une fenêtre intacte. Réutilise showConfirmationDialog plutôt que d'ouvrir un second composant de confirmation. 3 clés i18n FR/EN/NL, flutter build web ✅.
+ Le défaut était pire que décrit : trois dialogues faisaient Navigator.pop sur « Annuler » sans rien demander, pas un — Parcours, Étape et Question, chacun jetant tout ce qui était saisi sous lui. Le plus coûteux est le plus profond : une question de quiz avec ses réponses. Ce n'était pas « la croix » comme le disait cette carte, c'était le bouton Annuler, et le clic hors fenêtre était déjà neutralisé — le vrai chemin de perte restant est le retour arrière du navigateur, couvert par PopScope. Détection des modifications par instantané JSON, pris après la première frame : le dialog Question normalise ses réponses pendant sa construction, un instantané pris avant aurait déclaré « modifié » une fenêtre intacte. Réutilise showConfirmationDialog plutôt que d'ouvrir un second composant de confirmation. 3 clés i18n FR/EN/NL, flutter build web ✅. Retiré le jour même par la carte suivante — c'était l'issue prévue : un garde-fou n'a plus d'objet quand il n'y a plus rien à perdre.
+ showNewOrUpdate… sont supprimés au profit d'un rail d'étapes toujours visible à gauche, d'un panneau de détail à droite, et d'une question qui se déplie sur place au lieu d'ouvrir une quatrième fenêtre : la profondeur maximale retombe à 2 — l'éditeur, puis la traduction. Les champs sont d'abord sortis en trois widgets autonomes (ParcoursFields, EtapeFields, QuestionFields) — c'est ce qui a rendu la refonte possible sans tout réécrire, et ce qui resterait transposable si l'écran plein cadre revenait un jour.
+ Plus de bouton « Sauvegarder » : tout part à la saisie (débounce 700 ms ; les ajouts, suppressions et réordonnancements partent sans attendre). Deux pièges du backend, trouvés en lisant le contrôleur plutôt qu'en le supposant : UpdateGuidedPath supprime les étapes absentes du DTO, donc le payload n'emporte que celles qui ont déjà un id — les autres attendent leur CreateGuidedStep et seraient dupliquées ; et comme les questions n'ont pas d'endpoint propre (c'est voulu, elles partent avec leur étape), leur id entier est récupéré après coup par order, seul repère stable entre la liste locale et celle du serveur. Le parcours est créé à la première modification, pas à l'ouverture : une fenêtre neuve refermée intacte ne laisse rien en base. Si une écriture échoue, la fenêtre refuse de se fermer et le pied de page porte un « Réessayer ». 14 clés i18n FR/EN/NL, 3 retirées, flutter build web ✅. Reste la vérification à l'œil (DB5).