DB2 livré, persistance incrémentale rattachée à DB4

Le garde-fou et la persistance au fil de l'eau sont alternatives, pas
cumulables : si chaque étape part à la saisie, le garde-fou n'a plus
d'objet. La persistance impose en outre de créer le parcours dès la 1re
étape — parcours à moitié remplis en base, « Annuler » qui n'annule plus
rien — soit la sémantique qu'apporte le rail d'étapes de l'option A. Elle
rejoint donc DB4, avec le terrain relevé : les endpoints GuidedStep
existent déjà, le backend persiste les questions imbriquées, et il n'y a
volontairement pas d'endpoint QuizQuestion.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Thomas Fransolet 2026-08-11 13:44:03 +02:00
parent 991211d32a
commit 8e82e5b6e7
3 changed files with 14 additions and 16 deletions

View File

@ -338,7 +338,7 @@ 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 | ❌ — indépendante de l'arbitrage A/B, et seul point qui fait perdre du travail au client aujourd'hui |
| 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` ✅.<br>**Décidé le même jour : la persistance incrémentale passe à DB4**, les deux étant alternatives — voir v1-plan.md |
| 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 |

View File

@ -458,9 +458,9 @@
<div class="stat"><span class="n n-info">5</span><span class="k">Migration v3</span></div>
<div class="stat"><span class="n n-warn">7</span><span class="k">Bugs ouverts</span></div>
<div class="stat"><span class="n">6</span><span class="k">À tester</span></div>
<div class="stat"><span class="n">23</span><span class="k">Planifié</span></div>
<div class="stat"><span class="n">22</span><span class="k">Planifié</span></div>
<div class="stat"><span class="n n-gate">11</span><span class="k">Bascule prod</span></div>
<div class="stat"><span class="n n-good">20</span><span class="k">Fait récemment</span></div>
<div class="stat"><span class="n n-good">21</span><span class="k">Fait récemment</span></div>
</section>
<div class="filters" role="group" aria-label="Filtrer par domaine">
@ -678,7 +678,7 @@
<!-- PLANIFIÉ -->
<section class="col" style="--stripe: var(--ink-3)">
<div class="col-head"><h2>Planifié</h2><span class="count">23</span></div>
<div class="col-head"><h2>Planifié</h2><span class="count">22</span></div>
<div class="stack">
<article class="card" data-area="commercial" data-horizon="v1">
@ -729,19 +729,12 @@
<span class="src">v1-plan.md — lot J · cgu-myinfomate.md §8 · mention-information-visiteurs.md</span>
</article>
<article class="card" data-area="manager visitapp" data-horizon="v1">
<div class="card-meta"><span class="tag">SectionParcours</span><span class="flag f-critical">Perte de travail client</span></div>
<h3>Parcours — sauvegarde au fil de l'eau</h3>
<p>Chaque popup travaille sur une copie JSON profonde et ne remonte qu'à la fermeture : <strong>fermer la fenêtre du parcours par la croix jette les questions saisies dessous</strong>, sans un mot. C'est le seul des trois défauts de cet écran qui fait perdre du travail au client aujourd'hui.</p>
<p><strong>Indépendant de l'arbitrage A/B</strong> — à faire sans attendre la refonte de la forme. La maquette prévoit déjà son témoin : « Enregistré · il y a 3 s » en pied de fenêtre.</p>
<span class="src">todo-features.md — SectionParcours · v1-plan.md — DB2</span>
</article>
<article class="card" data-area="manager visitapp" data-horizon="v1">
<div class="card-meta"><span class="tag">manager-app</span><span class="flag f-warn">Arbitrage en attente</span></div>
<h3>Parcours — sortir de l'empilement de popups</h3>
<p>Cinq surfaces empilées pour poser une question sur une étape et l'écrire en NL. <strong>Option A recommandée</strong> (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, <em>déjà couverte</em> par l'aperçu de conversation du Guide IA. Maquette rapatriée dans <code>claude design/sectionparcours-refonte-flux.html</code>.</p>
<p>Extraire d'abord <code>ParcoursFields</code> / <code>EtapeFields</code> / <code>QuestionFields</code> en widgets autonomes : sert A et B à l'identique.</p>
<p><strong>Porte aussi la sauvegarde incrémentale</strong>, 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é — <code>CreateGuidedStep</code> / <code>UpdateGuidedStep</code> / <code>DeleteGuidedStep</code> existent déjà sur <code>sectionParcoursApi</code> et <code>sectionMapApi</code>, et le backend persiste bien les questions imbriquées. Il n'y a <em>pas</em> d'endpoint QuizQuestion : les questions partent avec leur étape, c'est voulu.</p>
<span class="src">todo-features.md — SectionParcours · v1-plan.md — DB4, lien L18</span>
</article>
@ -946,11 +939,16 @@
<section class="done">
<h2>Fait récemment</h2>
<p>Vingt chantiers clos entre le 5 et le 11 août 2026.</p>
<p>Vingt et un chantiers clos entre le 5 et le 11 août 2026.</p>
<div class="done-grid">
<div class="done-item">
<strong>Plus rien sur un seul disque — les 8 repos sont propres</strong>
<strong>Parcours — on ne perd plus son travail sans être averti</strong>
<span>Le défaut était pire que décrit : <strong>trois</strong> dialogues faisaient <code>Navigator.pop</code> sur « Annuler » sans rien demander, pas un — Parcours, Étape et Question, chacun jetant tout ce qui était saisi <em>sous</em> 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 <strong>retour arrière du navigateur</strong>, couvert par <code>PopScope</code>. Détection des modifications par instantané JSON, pris <strong>après la première frame</strong> : le dialog Question normalise ses réponses pendant sa construction, un instantané pris avant aurait déclaré « modifié » une fenêtre intacte. Réutilise <code>showConfirmationDialog</code> plutôt que d'ouvrir un second composant de confirmation. 3 clés i18n FR/EN/NL, <code>flutter build web</code> ✅.</span>
</div>
<div class="done-item">
<strong>Plus rien sur un seul disque — les 9 repos sont propres</strong>
<span>La carte la plus ancienne de la colonne « Urgent » se referme. L'alerte du 09/08 (« rien depuis le 17/07 », 75 + 40 + 14 + 4 fichiers) avait déjà été révisée le matin du 11/08 en « ~41 fichiers dont 9 non suivis » ; <strong>les deux versions sont maintenant périmées</strong>. Vérifié au <code>git status --porcelain</code> sur les huit repos : vide partout, et aucun <code>ahead</code>/<code>behind</code> face au remote. Le lot 3 RAG est dans <code>18e4240</code>, le socle visuel et l'écran Guide IA dans <code>eb8e849</code>. Ce qui rendait le point urgent — neuf fichiers non suivis qui n'existaient nulle part ailleurs et disparaissaient au premier <code>git checkout</code> — n'existe plus. À ne pas re-planifier : c'était l'étape 1 du lot A.</span>
</div>

View File

@ -143,9 +143,9 @@ Même découpage que le kanban : **contenu versionné dans le repo, diffusion pa
|---|---|---|
| ~~**DB0**~~ ✅ 2026-08-11 | **HTML des maquettes rapatrié** dans `DOCS/claude design/``guide-ia-screen.html` (31,8 Ko), `statistics-screen.html` (27,4 Ko), `sectionparcours-refonte-flux.html` (45,6 Ko), JS interactif compris. Méthode : bascule temporaire sur le compte propriétaire, lecture de la source, copie. L'assistant `visitapp-web` n'a jamais été publié ; le kanban vit déjà dans `DOCS/kanban.html` | La source de vérité du design vit désormais dans le repo, l'artifact ne sert plus qu'à la diffusion. **Constat** : Guide IA et Statistiques déclarent des tokens **rigoureusement identiques** — c'était déjà un design system, jamais porté en Dart. Et `--brand #264863` **est** `kPrimaryColor` |
| ~~**DB1**~~ ✅ 2026-08-11 | **Socle visuel dans `constants.dart`** : 11 rôles typographiques, 8 pas d'espacement, 5 rayons, paddings de carte et de page. `flutter analyze` propre. **Décision du 2026-08-11 : l'échelle vient des maquettes, les couleurs restent celles de l'app** — un écran neuf se fond dans manager-app, il n'y ouvre pas une seconde palette. Seules les valeurs sans équivalent existant sont reprises (`kSurface2/3`, `kLine`, `kLineSoft`, `kInk3`, `kWarning`). Pas de thème sombre. Reste : `size.width * 0.2` de `NumberInputContainer` | **L17** — sert aussi les 12 autres types de section. La reprise des écrans existants vers ces tokens est un chantier distinct (« repasse UI globale »), pas un effet de bord de celui-ci |
| DB2 | **SectionParcours — sauvegarde au fil de l'eau**, sans attendre l'arbitrage A/B | **Indépendante du design**, et seul point des trois qui fait perdre du travail au client aujourd'hui : fermer la popup Parcours jette les questions saisies dessous, sans avertir |
| ~~**DB2**~~ 🔨 2026-08-11 | **SectionParcours — plus de perte silencieuse.** Confirmation avant d'abandonner du travail non enregistré, sur les **trois** niveaux de dialogue (Parcours, Étape, Question — chacun perdait tout ce qui était saisi sous lui), plus interception du retour navigateur par `PopScope`. 3 clés i18n FR/EN/NL. `flutter build web` ✅ | **Arbitrage du 2026-08-11 : DB2 se limite au garde-fou, la persistance incrémentale part avec DB4.** Motif : les deux sont **alternatives, pas cumulables** — si chaque étape est persistée à la saisie, le garde-fou n'a plus d'objet. Et la persistance impose de créer le parcours dès la 1ʳᵉ étape (donc des parcours à moitié remplis en base si l'utilisateur renonce, et un « Annuler » qui n'annule plus rien) : c'est précisément la sémantique qu'apporte le rail d'étapes de l'option A. L'écrire maintenant, c'est la câbler dans les callbacks `onSave` que DB4 supprime |
| DB3 | **Écran Guide IA complet, 2 onglets, stats assistant comprises**. 🔨 **Front livré le 2026-08-11** : coquille à onglets, §5 Aperçu de conversation branché sur le **vrai** `POST /api/AI/chat` (`AIApi` était dans le client généré mais jamais exposé dans `client.dart` — câblé), onglet « Ce que demandent vos visiteurs » avec ses tuiles, son bloc ambre des questions sans réponse et ses trois cartes de barres, 24 clés i18n FR/EN/NL. `flutter analyze` propre, `flutter build web` ✅.<br>**Complété le 2026-08-11** : carte §4 « Ce que connaît votre guide » sur `GET /api/Ai/knowledge/{id}` (agrégats `ContentEmbedding`), journalisation `VisitorQuestion` dans `AiController.Chat`, et `GET /api/Ai/insights/{id}` qui remplit l'onglet. `dotnet test` 130/130, `flutter build web` ✅.<br>**Reste dans ce lot** : l'onglet « Vocal » des stats et la vérification à l'œil (DB5). Le job de thèmes et tout le volet RGPD sont **déplacés au lot J**, en fin de backlog. La purge à 90 jours est livrée (`VisitorQuestionPurgeService`) | **L15**, **L16** — le contrat de données est fixé par `GuideIaInsights` dans `visitor_questions_tab.dart`, et `GuideInsightsDTO` en est le miroir exact : c'est lui que le job de thèmes doit remplir, pas l'inverse. **L9** : le §5 converge avec le Mode preview |
| DB4 | **SectionParcours — la forme**, après arbitrage. Extraire d'abord `ParcoursFields` / `EtapeFields` / `QuestionFields` en widgets autonomes : sert A et B à l'identique | **L18** — recommandation : **A** |
| DB4 | **SectionParcours — la forme**, après arbitrage. 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 2026-08-11 | **L18** — recommandation : **A**. Point de départ concret côté persistance : les endpoints `CreateGuidedStep` / `UpdateGuidedStep` / `DeleteGuidedStep` existent déjà sur `sectionParcoursApi` **et** `sectionMapApi`, et le backend persiste correctement les questions imbriquées (`GuidedStep.FromDTO` appelle `SyncQuizQuestions`) — vérifié le 2026-08-11. Il n'y a **pas** d'endpoint QuizQuestion : les questions partent avec leur étape, c'est voulu. Le garde-fou de DB2 devient inutile dès que cette persistance est en place, le retirer alors |
| DB5 | **Boucle de vérification, à chaque écran** : `flutter run -d chrome`, capture, comparaison côte à côte avec la maquette | `flutter analyze` ne prouve rien sur du design — et reste inexploitable tant que le lot A n'a pas nettoyé `manager_api_new` (**L8**) |
Ne change pas : la popup de traduction (un niveau justifié, langues verticales, pas d'onglets), et la conception des composants de `Components/` — leur problème est le dimensionnement, pas la structure.