41 Commits

Author SHA1 Message Date
Thomas Fransolet
d36394cabd Carte hors ligne : conception du plan illustré, 3e fournisseur
Ni Google ni Mapbox ne donnent un fond hors ligne gratuit, et Mapbox
se facture au nombre de tuiles, pas à la surface. Pour un musée de
plein air comme le Fourneau Saint-Michel, la réponse est son propre
plan dessiné : les repères se posent sur l'image, le plan est une
Resource, donc embarqué par le pipeline hors ligne existant.

Conception seule, rien n'est implémenté. Mapbox est passé fournisseur
par défaut le 04/09.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-10 12:05:31 +02:00
Thomas Fransolet
4206fde7f0 Ray-Ban Meta : le SDK DAT tel qu'il est réellement intégré
flutter_meta_wearables_dat 0.9.1 et app_links remplacent les
dépendances « à décommenter quand publiées ». Le SDK natif vit sur
GitHub Packages : sans PAT read:packages dans local.properties, le
build tombe en 401 — et un token expiré peut passer inaperçu, Gradle
servant son cache.

Note ce que le SDK ne donne pas (ni micro, ni haut-parleur, ni bouton :
le vocal passe par le routage Bluetooth) et pourquoi iOS n'est pas
activé.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-10 12:05:06 +02:00
Thomas Fransolet
2824ca63c1 Plan de test : entrée du téléchargement hors ligne depuis la home v3
§21.1 bis — 9 cas ajoutés avec le portage du téléchargement dans le
bento (home_3.0.dart, 08/09), dont le piège du fetch qui échoue en
mode avion et laisse les visites téléchargées affichées en « ↓ ».

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-10 12:04:46 +02:00
Thomas Fransolet
c525a936c8 Sauvegardes : scripts livrés, destination GCP, médias copiés
Suivi de la session du 07/09 : scripts de dump dans manager-service,
bucket unov-myinfomate-backups en EU, versioning activé sur le bucket
des médias, 1,43 Go recopiés. rclone n'est pas installé sur le VPS :
rien ne part encore hors site, la case reste ouverte.

Clôt la carte « destination des sauvegardes », ouvre celle du
branchement de notify.sh sur un canal réel.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-10 12:04:33 +02:00
Thomas Fransolet
32c871ad52 Kanban : carte QR / nom d'app / page download / proximité
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-10 11:42:45 +02:00
Thomas Fransolet
b711e654b3 Kanban : le 403 du détail d'instance est clos, l'API ouverte reste
Clos : GET /api/Instance/{id} renvoyait 403 à l'app visiteur. Une clé API donne
maintenant accès à sa seule instance, en vue réduite — plan, quotas, TVA,
facturation et pinCode retirés. Déployé en version-3.1.3 et vérifié en préprod
sur cinq cas d'autorisation.

La carte close garde le piège qui vaut pour tout le projet : le test « est-ce un
utilisateur du manager » ne peut pas se baser sur un claim de permission, parce
qu'AuthorizationMiddleware peuple HttpContext.User depuis le schéma ApiKey avant
de court-circuiter sur [AllowAnonymous]. Et elle rectifie une affirmation fausse
de la première rédaction : StripeCustomerId n'est pas exposé par ToDTO.

Nouveau, en Urgent : GET /api/Configuration répond 200 sans aucune clé. Ce n'est
pas une clé mal vérifiée mais un [AllowAnonymous] explicite, probablement hérité
de la v2. Le périmètre exact reste à établir — les autres routes que consomment
les apps visiteur n'ont pas été passées en revue.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 12:57:51 +02:00
Thomas Fransolet
851b062668 Update docs, kanban etc 2026-09-04 16:48:04 +02:00
Thomas Fransolet
489ccc6c22 Update docs (v2) and kanban 2026-09-03 14:00:51 +02:00
Thomas Fransolet
2d9eaf74dc Développement V1 clos — STATUS, plan et kanban alignés
STATUS.md portait encore le lot J et D5 comme à faire, et son « 📍 Reprendre ici »
datait du 10/08 alors que ses trois étapes sont terminées : il est marqué périmé
et renvoie vers v1-plan.md. La ligne « mode offline » du §1 décrivait un pipeline
commenté, corrigé depuis D1 puis D5.

Nouveau § qui consolide la journée : les lots F et J clos, et les cinq pièges
rencontrés — la garde du proactif qui aurait coûté des jetons pour rien, l'écran
de téléchargement qui ne concluait jamais, le choix de voix du client jamais
honoré, les trois écrans qui journalisaient de fausses questions de visiteur, et
le même code copié trois fois ne portant sa décision qu'une seule.

Kanban : le bandeau annonce que le dev V1 est clos. Compteurs mesurés — Fait
récemment 60, aucun bug ouvert. Republié sur l'artifact.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 16:50:58 +02:00
Thomas Fransolet
438a631c69 Plus rien de codable sur les lots F et J
Purge du journal d'audit (poste oublié à la première passe), mention visiteurs
dans visitapp-web, _toLangCode dédoublonné. Ce qui reste au lot J est juridique :
relecture du §8, conditions réelles de Google, DPA séparé, et les traductions
relues de la mention.

Kanban : Fait récemment 60. ⚠️ Les colonnes À tester et Planifié ont bougé du
fait d'une autre session travaillant en parallèle dans ce repo — ses compteurs
sont cohérents, je n'y ai pas touché.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 16:29:36 +02:00
Thomas Fransolet
016e880a39 Latence vocale, langues et accusés de réception — relevé du 13/08
⚠️ Travail d'une autre session, committé tel quel pour ne pas le laisser en
working tree. Il n'est pas de cette session-ci et n'a pas été relu ici.

Deux constats qui touchent le travail livré aujourd'hui : l'assistant vocal ne
parle réellement que FR/NL/EN/DE et retombe silencieusement sur le français, et
les commandes vocales cherchent des mots français en dur dans les quatre langues.
2026-08-13 16:01:43 +02:00
Thomas Fransolet
97d94c34f4 Lots F et J clos, D5 livré — plus aucun bug ouvert
Le volet codable du lot J est fait (agrégats de thèmes, job de regroupement,
interrupteur de collecte, mention visiteurs) et D5 avec lui. Ce qui reste au lot J
est juridique : relecture du §8, conditions réelles de Google, DPA séparé — plus
les 7 traductions de la mention, à commander avec cette relecture.

Kanban : la carte D5 et la carte RGPD quittent leurs colonnes, Bugs ouverts tombe
à 0. Compteurs mesurés : Planifié 22, Fait récemment 59. Republié sur l'artifact.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 16:01:42 +02:00
Thomas Fransolet
fd5e1d7b3c Le lot F est clos
Canal vocal livré, et L9 refermé : la « cible Assistant / Persona » du Mode
preview est exactement ce que le §5 du Guide IA a livré le 11/08 — ce n'était pas
un chantier mais un malentendu entre deux documents. Les trois autres cibles du
Mode preview restent hors V1.

Kanban : la carte du canal vocal quitte Planifié, qui retombe à 22. Compteurs
mesurés : Fait récemment 57. Republié sur l'artifact.

Reste avant la bascule : lot J (RGPD), K6, K9, lot H (tests dont D0), D5, lot I.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 14:32:57 +02:00
Thomas Fransolet
c0308a95c0 Miroir vocal livré — plan, STATUS et kanban
La carte quitte Planifié, qui retombe à 23. Compteurs mesurés : Fait récemment 56.
Kanban republié sur l'artifact.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 13:39:34 +02:00
Thomas Fransolet
a2d4eb2944 Le bloquant du proactif est levé — IsAutoTriggered
Plan, STATUS et kanban répercutent le correctif des trois repos. La carte quitte
Bugs ouverts, qui retombe à 1 (les échecs de téléchargement silencieux, D5).

Compteurs mesurés : Bugs ouverts 1, Planifié 24, Fait récemment 55.
Kanban republié sur l'artifact.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 13:14:30 +02:00
Thomas Fransolet
c92c28098e Kanban : tampon de date au 13/08, republié sur l'artifact
La version publiée était restée au 12/08 (Planifié 26, Fait 48). Le fichier local
était strictement en avance — il contenait déjà les 3 cartes V2 de l'autre
session — donc rien à fusionner, pas de force.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 12:14:27 +02:00
Thomas Fransolet
2c49acf79e Proactif, M3, voix du CMS — et le périmètre de D0 ramené à l'installation neuve
Ce qui a été livré côté mymuseum-visitapp est répercuté dans le plan, STATUS et
le kanban. Trois corrections de docs, toutes vérifiées dans le code :

- Meta-Rayban-Test et AI-Assistant-test sont les branches de travail à jour, pas
  des POC. Le §5bis affirmait le contraire et c'est ce qui avait fabriqué la
  réserve « à clarifier avant K6 ». Il n'y a rien à clarifier.
- « L'APK se construit sans le POC dedans » était faux : les 4 erreurs Dart
  étaient dans deux ancêtres morts, pas dans le POC vivant, qui est bien
  embarqué. Conséquence inverse de celle qui était écrite — « démontrable » ne
  demandait pas de remettre les secrets ElevenLabs.
- « TTS = ElevenLabs, basculer sur Gemini avant de vendre l'add-on » : déjà fait.
  constants.dart dit « ElevenLabs retiré du pipeline (trop cher) ».

Nouveau, et non résolu : les déclenchements proactifs écriraient leur prompt
machine dans VisitorQuestion, donc dans l'onglet « Ce que demandent vos
visiteurs » — et gonfleraient le bloc « questions sans réponse ». Même famille
que WeatherSyncService noyant le journal d'audit. Carte en Bugs ouverts, à
traiter dans manager-service puis mymuseum-visitapp avant d'allumer le mode.

D0 — périmètre ramené aux 15 cas d'origine : aucun visiteur n'a l'app installée
et la consigne est « supprimer puis réinstaller ». Vérifié que _onCreate contient
déjà dateUpdate, donc une installation neuve naît en v4 sans passer par
_onUpgrade. Le code qui gère les .unknown reste, il ne coûte rien. Et 21.2.1 est
réécrit : il testait un scénario impossible, remplacer une image créant un
nouvel id.

Kanban : M3 fermé, la carte proactif devient un bug bloquant, trois entrées en
Fait. Compteurs mesurés — Bugs ouverts 2, Planifié 24, Fait récemment 54.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 11:58:10 +02:00
Thomas Fransolet
6c455e4d7c Lot F livré côté serveur, manager-app et landing — et six points de STATUS qui affirmaient du faux
Le volet manager-service du lot F est refermé, plus le bouton du portail,
le diviseur de questions et la FAQ de la landing.

Ce que la vérification dans le code a corrigé dans les docs :
- la ligne « À faire » du §1 de STATUS était périmée sur six points. Le
  rate limiting y figurait comme à faire alors qu'il est livré (politique,
  UseRateLimiter et les deux endpoints décorés), tout comme l'écran d'audit
  log, la gestion des users et ParcoursIds. L'unification QuestionType n'est
  pas « à faire » mais écartée.
- l'endpoint de mise à jour d'ApplicationInstance n'a jamais manqué : le CRUD
  est complet. Ce qui manque est l'écran SuperAdmin, déjà parqué en V2.
- les quotas seed 5M/20M étaient déjà alignés.

Kanban : la carte du portail est close, deux entrées entrent dans Fait
récemment. Compteurs re-mesurés — Planifié 25, Fait récemment 51 —
colonnes et bandeau vérifiés l'un contre l'autre, jamais par delta.

Ce commit emporte aussi les 3 cartes V2 stagées par une autre session
(nettoyage downloadConfiguration, swagger périmés, colonne path écrasée) :
elles vivent dans le même fichier kanban.html.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 10:11:35 +02:00
Thomas Fransolet
fdd0213757 Plan de test manager-app pour les 8 commits du 9 au 12 août
356 lignes couvrant ce qui a été livré sur manager-app et jamais ouvert dans un
navigateur : écran Guide IA, éditeur de parcours refondu, écran d'audit log,
compteur d'utilisateurs, compression des images.

Le fichier n'était pas suivi par git — un add explicite ne l'avait jamais vu,
et il serait resté sur un seul disque.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 17:50:50 +02:00
Thomas Fransolet
83bc8c51ad Arbitrages du 12/08, D2 livré, et deux docs qui affirmaient du faux
Décidé et inscrit : thèmes du lot J complets (job + table d'agrégats, donc le
§8.4 des CGU n'est pas à amender), meterZoneGPS sur mymuseum et visitapp-web,
D3/D4 sans attendre D0, rate limiting et Customer Portal confirmés V1, lunettes
Ray-Ban ramenées en V1, K9 (repasse visuelle de la borne, bento compris),
déclenchement proactif ouvert à tous, miroir de la conversation vocale.

Trois lignes du plan étaient périmées : le nettoyage de manager_api_new et la
sécurité du lot A sont faits depuis un moment, et un PUT ApplicationInstance
existe déjà.

Deux documents affirmaient un fallback Voice vers Mobile qui n'existe pas —
guide-ia-screen-plan.md et le commentaire d'AiController se confirmaient
mutuellement. Le code fait un FirstOrDefault sur le canal exact puis Forbid() :
envoyer AppType.Voice au chat sans ApplicationInstance de ce type rendrait 403
à chaque question. Corrigé côté doc ; le commentaire reste à corriger.

Le vocal n'est donc pas un canal mais un attribut : marqué dans
VisitEvent.Metadata, colonne JSON déjà existante, aucune migration.
AppTypeDistribution compte une entrée par session et tranche sur l'événement le
plus ancien — avec le miroir, une session est mixte, et un canal Voice aurait
mesuré « sessions démarrées en vocal », pas la part du vocal.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 17:47:34 +02:00
Thomas Fransolet
de428d06da Kanban : fermer la carte C4, oubliée à la livraison
La compression d'images est livrée depuis ce matin mais sa carte était
toujours dans la colonne Migration v3 : j'avais ajouté le done-item sans
retirer la carte. Relevé par relecture, pas par le contrôle de
cohérence — les compteurs étaient justes, ils comptaient simplement une
carte qui n'avait plus lieu d'être.

C'est la limite du contrôle automatique : il vérifie que le nombre
annoncé égale le nombre réel, pas qu'une carte encore ouverte décrit un
chantier encore ouvert. Rien ne remplace la relecture des titres.

Migration v3 passe à 1 carte — il ne reste que C6, le retrait de la
suppression de blob côté manager-app, qui attend I9 à juste titre : tant
que Firebase:StorageBucket est vide, le serveur ne supprime rien et ce
code client est le seul qui nettoie encore.

Vérification faite sur les autres colonnes : aucune autre carte ne décrit
un chantier livré aujourd'hui. K3, K5, K7 et K8 avaient bien été
retirées.

Compteurs recalés par mesure, six colonnes cohérentes, 40 cartes,
44 done-items. Artifact republié.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 16:11:19 +02:00
Thomas Fransolet
396debb4ff C4 et K8 livrés, et le travail DOCS de la session manager-service
Ce commit porte deux sessions à la fois — voir la note de collision en
fin de message.

C4 — compression des images à l'upload, flutter build web vert. Un seul
helper appelé par les deux chemins d'upload de resources_screen, le
motif exact qui a fait diverger Create et Upload côté serveur en C1 puis
en C3. La compression se fait avant resourceCreate parce que le pré-vol
de quota de C3 porte sur sizeBytes à la création. Écart assumé à
l'énoncé « JPEG q82 » : un PNG à canal alpha reste un PNG, sinon la
transparence se remplit de noir. Défaut préexistant trouvé au passage :
le second chemin d'upload ne renseignait sizeBytes ni avant ni après,
donc tout ce qui est passé par là compte 0 octet au quota.

K8 — retour à l'accueil après 5 min, flutter build apk vert. Écrit une
seule fois dans section_page_detail, qui enveloppe les treize types.
Le retour passe par le même dispose, donc il émet un sectionLeave avec
sa durée réelle : K8 répare une statistique en plus d'un écran.

Checklist D0 ajoutée — DOCS/claude design/checklist-d0-offline.html.
Les 15 cas du §21, chaque groupe relié au bug qu'il décide : 21.2 tranche
D2 et D4, 21.1.4 tranche D3, 21.4.1 tranche D5. Les cas 21.1.2/3/5/6 sont
la première vérification RÉELLE de D1, corrigé le 11/08 mais validé par
l'analyse seule. Si tout passe, le lot D se ferme et le plan perd un à
deux jours — c'est le lien L11.

COLLISION SUR DOCS, à retenir. La session manager-service avait des
modifications stagées et non commitées sur STATUS.md, kanban.html et
v1-plan.md, alors que son prompt lui demandait de ne pas toucher à
DOCS/. Rien n'est perdu : ses changements et les miens coexistent, et
ils sont tous dans ce commit — deux cartes ferées de son côté (tests du
RAG, dettes serveur audit & plafond users) plus ses done-items.

Ce que ça a produit : mes compteurs de kanban étaient calculés par
arithmétique à partir d'un état déjà périmé, donc faux de trois cartes.
Ils sont désormais recalés sur la MESURE — on compte les <article> et on
écrit le résultat, on ne raisonne plus par delta. Planifié 19, six
colonnes cohérentes, 44 done-items, bandeau et libellé alignés.

Leçon pour la suite : un compteur dérivé d'un delta est faux dès qu'une
autre main touche le fichier. Mesurer, toujours.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 16:03:20 +02:00
Thomas Fransolet
3fe18e088b K3 et K7 livrés : la borne couvre 12 des 13 types
flutter build apk --debug vert, APK produit. SectionArticle et
SectionEvent sont branchés dans main_view.getContent ; seul
SectionParcours reste dehors, et définitivement.

Quatre choses que l'implémentation a corrigées ou apprises, toutes
reportées dans le plan, STATUS et la maquette :

- La barre de pied de la maquette n'appartient pas aux écrans.
  section_page_detail la dessine déjà pour les treize types, avec les
  clés back/menu selon isFromMenu. La dessiner aurait affiché deux
  boutons retour. La maquette est corrigée sur ce point.
- Un seul constructeur de marqueurs au lieu des quatre de mymuseum.
  MapAnnotationDTO et MapAnnotation ont des champs rigoureusement
  identiques mais sont deux types Dart distincts. Normalisé par une
  classe interne — L5 appliqué au front, et il porte d'autant plus que
  la convention [lng, lat] est l'endroit exact où une divergence ne
  lève aucune erreur.
- L'audio d'article se résout dans contents avant l'API, donc sans
  appel réseau quand il est embarqué, donc hors ligne aussi. Mymuseum
  appelle l'API systématiquement en ligne.
- Clé i18n event.live ajoutée aux 10 langues. Sans les 10,
  getFromLocale renvoie "" et la pastille rendrait une boîte vide.
  PL, CN, UK et AR sont de ma main et demandent une relecture humaine.

Ce qui n'est pas prouvé, et qui est écrit comme tel : le rendu. Aucun
des deux écrans n'a été vu à l'œil — un build vert ne dit rien d'une
mise en page, c'est la leçon du §1bis appliquée au design. Et aucun
SectionEvent n'existe en base, le type étant né avec Postgres v3 : le
§19.13 cas E en créera un.

Kanban : la carte « Types de section manquants sur le kiosk » quitte
Urgent (2 -> 1) pour Fait récemment (40 -> 41), bandeau du haut et
libellé « Quarante et un » compris. Compteurs des six colonnes
revérifiés un à un.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 15:20:29 +02:00
Thomas Fransolet
4a4523e3a2 Correction : tablet-app a bien un i18n, et V2 gagne l'orientation
Correction d'une affirmation fausse écrite plus tôt dans la journée et
reprise dans la maquette, le plan et une décision validée : « tablet-app
n'a aucun i18n ». Il en a un — lib/Helpers/translations.dart, table de 10
langues (FR EN NL DE IT ES PL CN AR UK), ~150 entrées, lue par
TranslationHelper.getFromLocale à 19 endroits, avec déjà une clé back.
Ce n'est pas de l'ARB : chercher l10n/ ou AppLocalizations ne le trouve
pas, alors que le CLAUDE.md du repo le décrit.

Ce que ça change : le motif donné pour « hors dates, aucune prose » — un
bandeau serait français pour un néerlandophone — était faux. Un libellé
traduit coûte une clé × 10 langues. La règle reste défendable (rien à
traduire vaut mieux que quelque chose à traduire) mais devient un choix,
pas une contrainte. À reconfirmer.

Corollaire d'implémentation : le bouton Retour des deux écrans passe par
la clé back existante, il ne s'écrit pas en dur.

Ajouté en V2 — portrait et paysage sur toute la borne. tablet-app n'a
aucune stratégie d'orientation : chaque écran est écrit pour la forme
qu'on lui a vue, et la maquette du 12/08 ne tranche que le paysage, pour
deux types. Une borne se monte pourtant aussi bien en totem qu'en
comptoir, et le choix appartient au lieu. Le chantier n'est pas
« ajouter le portrait » mais rendre les treize types indifférents à
l'orientation — repasse UI transversale, même famille que la repasse
globale de manager-app. La maquette est compatible (le rail qui tombe
sous le texte est le comportement portrait) mais ne le spécifie pas.

Kanban : carte V2 ajoutée, Planifié 21 -> 22 (colonne et bandeau). Le
motif « et tablet-app ne compile même plus » de la carte Kiosk web est
corrigé — il est tombé avec K1.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 14:55:39 +02:00
Thomas Fransolet
c2bda75885 Maquette : Article et Événement en paysage sur la borne (K3, K7, K8)
Une seule passe de design pour les deux écrans. Les trancher séparément
donnerait deux grammaires différentes sur la même dalle, alors qu'ils
posent la même question : ces écrans sont dessinés pour un téléphone tenu
debout, une borne fait 1280 px de large et se lit à un mètre.

Six règles communes, chacune corrigeant un idiome de téléphone qui devient
faux sur une dalle large et fixe : deux colonnes (un ancrage fixe, un flux
qui défile), texte plafonné à ~65 caractères, héros à 26 % au lieu de 52 %,
plus de showModalBottomSheet (il y a la place à côté), carte affichée à sa
taille utile sans « Agrandir », et accents dérivés de
configuration.primaryColor — précédent K4, tablet-app n'a pas de flavor.

Quatre décisions prises le 12/08 :

- Fond clair, aux valeurs réelles de l'app (kBackgroundColor #FFFFFF,
  kBackgroundLight #F3F3F3), pour que la section ne dénote pas.
- Pas de sélecteur de langue : elle est choisie en amont.
- Hors dates, aucune prose : le programme reste, sans pastille EN COURS,
  et les dates du héros disent qu'on est avant ou après.
- Retour automatique après 5 min : adopté mais sorti du périmètre, K8.

Trois états incomplets, tous possibles en configuration. La règle qui les
couvre : le rail média n'existe que s'il a quelque chose à ancrer.

- Sans audio : le dock tombe, l'image reprend la hauteur.
- Sans photo : le rail tombe — une colonne de 38 % avec un seul lecteur
  serait un trou. L'audio passe en tête de la colonne de lecture.
- Texte seul : une colonne centrée, toujours plafonnée. Le vide latéral
  est voulu, c'est lui qui garde le texte lisible.

Quatre vérifications faites dans le code plutôt que supposées :

- Les statistiques sont déjà acquises. section_page_detail émet
  sectionView et sectionLeave avec durée et enveloppe les treize types :
  l'article sera compté dès que son case entre dans le switch.
- tablet-app n'a aucun i18n — pas de l10n/, pas d'AppLocalizations,
  libellés français en dur. C'est ce qui interdit un bandeau « Édition
  passée » et impose d'exprimer l'état hors dates par des dates.
- audioIds est une List<TranslationDTO> : « sans audio » est un état de
  la langue courante, pas de l'article. Un article peut avoir sa version
  française et pas sa néerlandaise.
- isContentTop existe déjà et dit si le texte passe avant le média. En
  paysage il ne veut plus dire « au-dessus » mais « à gauche » : à
  câbler, sinon un réglage déjà offert dans manager-app reste sans effet.

Retiré de la maquette : un repère « 3 / 8 » en pied d'article, inventé
pour occuper la place libérée par le sélecteur de langue. SectionPageDetail
ne reçoit qu'une section et un booléen isFromMenu, jamais la liste de ses
voisines — le repère n'était adossé à aucune donnée.

K8 ajouté au plan et au kanban : le retour à l'accueil s'écrit une seule
fois dans section_page_detail. Bénéfice de bord, il passe par le même
dispose et émet donc un sectionLeave avec sa durée réelle au lieu de
laisser une consultation ouverte jusqu'au visiteur suivant.

Source de vérité dans le repo, artifact pour la diffusion (convention DB0).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 14:55:39 +02:00
Thomas Fransolet
b5883be088 Maquette : Article et Événement en paysage sur la borne (K3, K7, K8)
Une seule passe de design pour les deux écrans. Les trancher séparément
donnerait deux grammaires différentes sur la même dalle, alors qu'ils
posent la même question : ces écrans sont dessinés pour un téléphone tenu
debout, une borne fait 1280 px de large et se lit à un mètre.

Six règles communes, chacune corrigeant un idiome de téléphone qui devient
faux sur une dalle large et fixe : deux colonnes (un ancrage fixe, un flux
qui défile), texte plafonné à ~65 caractères, héros à 26 % au lieu de 52 %,
plus de showModalBottomSheet (il y a la place à côté), carte affichée à sa
taille utile sans « Agrandir », et accents dérivés de
configuration.primaryColor — précédent K4, tablet-app n'a pas de flavor.

Quatre décisions prises le 12/08 :

- Fond clair, aux valeurs réelles de l'app (kBackgroundColor #FFFFFF,
  kBackgroundLight #F3F3F3), pour que la section ne dénote pas.
- Pas de sélecteur de langue : elle est choisie en amont.
- Hors dates, aucune prose : le programme reste, sans pastille EN COURS,
  et les dates du héros disent qu'on est avant ou après.
- Retour automatique après 5 min : adopté mais sorti du périmètre, K8.

Trois états incomplets, tous possibles en configuration. La règle qui les
couvre : le rail média n'existe que s'il a quelque chose à ancrer.

- Sans audio : le dock tombe, l'image reprend la hauteur.
- Sans photo : le rail tombe — une colonne de 38 % avec un seul lecteur
  serait un trou. L'audio passe en tête de la colonne de lecture.
- Texte seul : une colonne centrée, toujours plafonnée. Le vide latéral
  est voulu, c'est lui qui garde le texte lisible.

Quatre vérifications faites dans le code plutôt que supposées :

- Les statistiques sont déjà acquises. section_page_detail émet
  sectionView et sectionLeave avec durée et enveloppe les treize types :
  l'article sera compté dès que son case entre dans le switch.
- tablet-app n'a aucun i18n — pas de l10n/, pas d'AppLocalizations,
  libellés français en dur. C'est ce qui interdit un bandeau « Édition
  passée » et impose d'exprimer l'état hors dates par des dates.
- audioIds est une List<TranslationDTO> : « sans audio » est un état de
  la langue courante, pas de l'article. Un article peut avoir sa version
  française et pas sa néerlandaise.
- isContentTop existe déjà et dit si le texte passe avant le média. En
  paysage il ne veut plus dire « au-dessus » mais « à gauche » : à
  câbler, sinon un réglage déjà offert dans manager-app reste sans effet.

Retiré de la maquette : un repère « 3 / 8 » en pied d'article, inventé
pour occuper la place libérée par le sélecteur de langue. SectionPageDetail
ne reçoit qu'une section et un booléen isFromMenu, jamais la liste de ses
voisines — le repère n'était adossé à aucune donnée.

K8 ajouté au plan et au kanban : le retour à l'accueil s'écrit une seule
fois dans section_page_detail. Bénéfice de bord, il passe par le même
dispose et émet donc un sectionLeave avec sa durée réelle au lieu de
laisser une consultation ouverte jusqu'au visiteur suivant.

Source de vérité dans le repo, artifact pour la diffusion (convention DB0).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 14:39:06 +02:00
Thomas Fransolet
f099dbbc5f K5 livré, et deux corrections que la vérification a sorties
K5 — les 3 flavors de mymuseum-visitapp construisent. La prémisse du lot
était fausse : sa config Android était déjà à niveau, ce sont les dix
crans du 12/08 qui ont amené tablet-app jusqu'à lui. Restaient deux
alignements (NDK 28.2.13676358 réclamé par speech_to_text, Kotlin 2.3.10).
Un cran de plus existe — Gradle 8.14.0 / AGP 8.11.1 — délibérément non
pris : terrain neuf pour les deux repos, le faire ici seul les désaligne.

Correction 1 — tablet-app couvre 10 des 13 types, pas 11. Le switch de
main_view.getContent traite Map, Slider, Video, Web, Menu, Quiz, Pdf,
Game, Agenda, Weather. SectionArticle (type 6) a son case commenté
« TODO » et un article_view.dart d'1 Ko : un article rend « Ce type n'est
pas supporté ». Contrairement à SectionEvent et SectionParcours, ce type
existait dans Mongo — c'est un vrai retard, et il sortira de la migration
avec du contenu réel. Ajouté au plan en K7.

Le travail de K7 n'est pas la copie mais le passage en paysage : les
écrans de mymuseum sont pensés pour un téléphone debout, une borne est
large. K3 (SectionEvent) pose la même question — une seule passe de
design pour les deux, sinon deux mises en page sur la même borne.

Correction 2 — le travail V1 des deux apps visiteur est committé sur des
branches qui ne sont pas master : Meta-Rayban-Test pour mymuseum-visitapp,
AI-Assistant-test pour tablet-app. Le §5bis décrit pourtant la première
comme « un POC jamais mergé ». À trancher avant K6 (publier les APK).
Corollaire relevé au §5bis : l'APK se construit sans le POC dedans, les
4 erreurs Ray-Ban étant hors du graphe de main.dart.

kanban.html : carte build mymuseum retirée d'Urgent (3 -> 2), done-item
K5 ajouté (39 -> 40), bandeau du haut réaligné, carte périmètre kiosk
corrigée. Compteurs de colonnes revérifiés un à un.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 14:18:55 +02:00
Thomas Fransolet
b6cdf01ae1 Plan : règle de parallélisation entre conversations
Deux sessions ont débordé de leur périmètre le 12/08 en committant le repo
d'une autre. Rien de perdu, mais la règle manquait au §4bis.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 12:25:27 +02:00
Thomas Fransolet
059ba3ac2c Lot K livré côté tablet-app, et les pièges de vérification de la journée
v1-plan.md — le tableau des crans d'outillage passe de six à dix : le compte de
six datait du moment où la chaîne Gradle passait, avant que la compilation Kotlin
ne révèle la suite. K2 et K4 marqués livrés, avec les deux bugs latents trouvés
pendant le portage et la décision de rendu de l'écran Game (couleurs dérivées de
la configuration, faute de flavor sur tablet-app).

STATUS.md — §1bis passe tablet-app en  ; le diagnostic « un seul défaut, purement
Gradle » y disait le faux depuis le 6 août. §1sexies porte le détail du lot K.

Trois pièges de vérification consignés, tous rencontrés aujourd'hui :
- `flutter build apk … | tail` renvoie le code de sortie du tail, pas celui du
  build : un échec y ressort en « exit code 0 ».
- `flutter analyze` écrit « error - », pas « error • » : un grep sur la mauvaise
  forme a fait conclure à 0 erreur alors qu'il en restait 10.
- un build jamais lancé ne vaut pas un build vert supposé. « À reconfirmer par un
  vrai build » dans une doc veut dire que ce n'est pas confirmé, et un point non
  confirmé ne doit pas être chiffré comme une demi-heure.

Réflexe noté pour K5 : trois des quatre derniers crans étaient de simples
alignements sur mymuseum-visitapp. Commencer par un diff des gradle.properties et
build.gradle des deux repos plutôt que de remonter les erreurs une par une.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 12:18:45 +02:00
Thomas Fransolet
ff80d9e6d2 Docs : lot médias terminé côté serveur (C2, C3) et K2 livré
Lot C — C2 et C3 passent en livré dans v1-plan.md et STATUS.md §1sexies,
avec ce que la doc annonçait de faux et qu'il ne faut pas re-croire :

- La méthode de C2, « SizeBytes par listing du bucket Firebase », était
  inapplicable — le serveur n'avait aucun client de stockage. Le sondage
  passe par HEAD, via un sondeur partagé avec la migration.
- Le pré-vol de C3 existait déjà à moitié sans être documenté : le chemin
  multipart contrôlait, le chemin JSON non, et les deux lectures du quota
  divergeaient entre le plan et l'instance.
- L'angle mort laissé par C1 était une fausse crainte : le type n'entre pas
  dans le chemin de stockage.
- Le « 37 lignes sur 45 » disparaît au profit de l'inventaire que le backfill
  produit lui-même.

Deux suites que ces chantiers créent, consignées pour ne pas se perdre :

- C6, nouvelle ligne du lot C : manager-app supprime toujours le blob de son
  côté, après la ligne et en avalant l'échec. Depuis C3 c'est du code mort.
  À retirer, mais pas avant que Firebase:StorageBucket soit posé en prod,
  sinon plus personne ne supprime.
- I9, nouvelle étape du lot I : renseigner Firebase:StorageBucket, puis
  lancer le backfill en dryRun avant de l'appliquer. Sans lui le quota porte
  sur des SizeBytes à zéro pour tout l'existant et laisse tout passer (L10).
  S'y ajoute un piège de build : dotnet restore échoue en 401 si la source
  NuGet git.dev-espaces-naturels.lu est déclarée dans l'image, et
  Google.Cloud.Storage.V1 est le premier paquet ajouté depuis longtemps.

Lot K — K2 livré : tablet-app est rebranché sur le contrat d'API de
Postgres v3, les 132 erreurs de contrat sont tombées, et la table des
conventions de coordonnées est consignée. Reste K4, le renommage
Puzzle → Game. Point de vigilance noté : le filtre des configurations
tablette a changé de source, à valider sur device.

Compteurs du kanban recomptés colonne par colonne : Urgent 4, Migration v3 2,
Bugs ouverts 5, À tester 6, Planifié 20, Bascule prod 8, Fait récemment 38.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 12:05:47 +02:00
Thomas Fransolet
d6501252a8 Docs du 12/08 : lot K découvert, lot F livré côté manager-app
Deux chantiers menés en parallèle, consignés dans la même passe parce que
l'index de ce repo est partagé et que leurs modifications s'entrelacent
dans STATUS.md, v1-plan.md et kanban.html.

Lot K — les apps visiteur parlent l'ancien contrat. Découvert en lançant le
premier vrai flutter build apk sur tablet-app depuis des mois, la commande
que trois documents disaient « à reconfirmer ». Le diagnostic « un seul
défaut, purement Gradle, peut-être réglé par 5a6701d » était doublement
faux : six crans d'outillage Android (Gradle 7.5 → 8.11.1, AGP 7.2.0 →
8.9.1, Kotlin 2.0.10, option AGP supprimée, jcenter mort), corrigés le
12/08, puis 132 erreurs Dart que le Gradle masquait. Elles tiennent en trois
causes — les cinq champs de ConfigurationDTO migrés vers
AppConfigurationLinkDTO, GeoPointDTO.latitude/longitude devenus
GeometryDTO geometry avec PostGIS, et les min() sur dynamic qui en
découlent. mymuseum-visitapp a déjà fait ce portage : c'est une copie, pas
une conception. Bloquant de la bascule (lien L19) : les tablettes en service
chez MDLF et au Fort ne s'arrêteraient pas proprement le jour J, elles
dégraderaient sans erreur visible. +3 à 5 jours de travail déjà dû.

Périmètre kiosk tranché : SectionParcours exclu définitivement d'une borne
fixe, SectionEvent à supporter. Leçon générale ajoutée au §1bis — un build
jamais lancé ne vaut pas mieux qu'un build vert supposé, et « à reconfirmer
par un vrai build » veut dire que ce n'est pas confirmé.

Lot F — le volet manager-app est livré. Écran d'audit log sur GET /api/Audit
réservé au SuperAdmin, et compteur « X / 5 utilisateurs » avec bouton d'ajout
désactivé au plafond. Deux dettes serveur ouvertes par ce chantier et
laissées ouvertes à dessein, le périmètre étant manager-app seul : le
plafond de 5 n'est appliqué nulle part côté serveur — ce qui est livré est
un garde-fou d'interface, un POST direct sur l'API passe toujours — et
aucune section n'est journalisée, AuditedTypes.Contains exigeant l'égalité
exacte de type alors que Section est abstraite, si bien que le journal
couvre tout sauf le contenu, précisément ce que l'écran devait tracer.
Chacune a sa carte au kanban et son entrée dans todo-features.md.

Compteurs du kanban recomptés : Urgent 4, Migration v3 3, Bugs 5, À tester 6,
Planifié 20, Bascule prod 7, Fait récemment 36.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 11:04:49 +02:00
Thomas Fransolet
acf6ea4344 Kanban : compteur Fait récemment aligné sur 32 items après DB4
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 17:12:36 +02:00
Thomas Fransolet
c69cb15ba2 D1 corrigé : le bug offline nº1 était 283 lignes de code mort
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 16:57:23 +02:00
Thomas Fransolet
92d86fa066 Recette de bascule : comparer l'app d'aujourd'hui à la base migrée
test-plan.md §22. Le dry run compare des comptages ; cette recette compare le
contenu — un compte juste ne dit pas qu'un quiz a gardé ses questions ni
qu'un article a gardé ses traductions.

Six volets : comptages globaux, comptages par type de section (où se cachent
les pertes qu'un total masque), collections filles, colonnes que la migration
génère ou décide et qui n'ont aucun équivalent à comparer, comparaison à
l'écran, et relecture des Skipped.

À jouer juste après le run et avant la bascule DNS : c'est la seule fenêtre
où les deux bases coexistent. Reliée depuis I7 du plan.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 16:44:46 +02:00
Thomas Fransolet
526bb904b1 Dry run joué : 20 sections orphelines, et une décision produit en attente
Recette d'import documentée (MigrationController lit un Mongo vivant, pas les
fichiers de migration-data/), résultats des comptages, et les deux réserves :
l'export a 4 mois alors que la prod tourne encore sur Mongo, et les 20
sections orphelines sont du contenu MDLF réel dont le sort doit être tranché
avec le client — recréer les 2 configurations, ou acter la perte.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 16:40:11 +02:00
Thomas Fransolet
1321f0cebe Lot G : 8 écarts clos, dont trois qui n'existaient pas
Trois cartes « Bascule prod » se ferment sans une ligne de code : l'export
Mongo, lu plutôt que supposé, montre qu'il n'y avait rien à perdre.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 16:26:01 +02:00
Thomas Fransolet
c180230f49 Décisions tarifaires et requalification de deux écarts du lot G
Décisions consignées pour ne pas être re-tranchées : plans alignés sur la
grille, add-on IA sur les plans sans IA, affectation des 4 clients
existants, et les deux pièges qui vont avec (sémantique asymétrique du 0,
rattrapage d'indexation non déclenché par un UPDATE en SQL).

Requalification de deux écarts du lot G, vérifiés dans l'export Mongo :
- (a) « BuildSection ne couvre que 11 types sur 13 » est une fausse alerte :
  les 327 sections de l'export ne contiennent que les types 0 à 10.
  SectionEvent et SectionParcours n'existaient pas dans Mongo, ils sont nés
  avec Postgres v3. Le default est un filet, pas un trou.
- (c) « Instance : 4 champs migrés sur ~35 » n'est pas un oubli de mapping :
  la source ne contient que 4 champs. Les 31 autres sont à générer, dériver
  ou décider.

Signalé sans le traiter : la FAQ de la landing appelle encore le plan à
179€ « Bundle » (41 occurrences, 4 langues) là où la grille dit Premium.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 16:06:36 +02:00
Thomas Fransolet
005f5c1606 Lot B, C1 et lot E livrés ; deux erreurs de doc corrigées
Deux points où suivre la doc à la lettre aurait produit un correctif
inopérant ou destructeur, tous deux consignés pour ne pas être rouverts :

- « Supprimer SectionEvent.IconResourceId » (lot B) : ce champ n'existe pas.
  La ligne visée appartient à la classe imbriquée MapAnnotation, partagée par
  trois types de section et lue par cinq contrôleurs.
- « Cas PDF dans getElementForResource » (lot E) : cette fonction retourne
  CachedCustomResource avant son switch, qui est donc du code mort. Le vrai
  dispatcher en a deux.

Également : C1 montre que le « prérequis levé le 10/08 » du backfill n'était
vrai que d'un chemin de création sur deux, et le fournisseur de carte en web
est tranché (Leaflet) avec la correction de ce que l'option impliquait
réellement.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 15:32:19 +02:00
Thomas Fransolet
8e82e5b6e7 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>
2026-08-11 13:44:03 +02:00
Thomas Fransolet
991211d32a Contrôle du code du 2026-08-11 : corrections d'état et lot A révisé
STATUS.md et v1-plan.md portaient plusieurs affirmations périmées, toutes
revérifiées dans le code.

Ce qui tombe :
- §4 : les 9 repos sont propres et synchronisés (DOCS en est un). L'étape 1
  du lot A est terminée, à ne pas re-planifier.
- §3 : diagnostic manager_api_new fermé — 139 `part` pour 153 fichiers, les
  14 orphelins hors graphe de compilation. Et ils étaient trois
  déclencheurs de génération, pas un : mymuseum-visitapp et tablet-app en
  avaient aussi.
- §1bis : la piste Dart du build tablet-app (ContentGeoPoint) est écartée —
  les deux références sont dans des blocs commentés. Le problème est
  purement Gradle.

Ce qui se déplace :
- Rotation des secrets → lot I (I0), repos privés auto-hébergés. Le lien L1
  reste entier : elle précède I3, donc la fin du lot H. La boucle du graphe
  de dépendances disparaît.

Ce qui apparaît :
- §1bis / §5bis : mymuseum-visitapp ne construit plus son APK (Gradle/NDK,
  pas Dart) et le POC Ray-Ban ne compile plus — kElevenLabsApiKey et
  kElevenLabsVoiceId absents de constants.dart, jamais committés.

kanban.html : carte « travail non committé » close, carte des secrets
déplacée en Bascule prod, nouvelle carte pour le build mymuseum, cartes
tablet-app et client généré réécrites. Compteurs revérifiés par script.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 12:13:09 +02:00
Thomas Fransolet
a5a8ecdb20 Documentation interne MyInfoMate / Unov
Import initial de la documentation : statut, roadmap, plans V1/V2,
specs verticales (creche, sport), audits securite, plan de test,
analyse concurrentielle et maquettes de design.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 11:17:01 +02:00