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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>