# MyInfoMate — Tableau de bord > Point d'entrée unique : "où j'en suis, qu'est-ce que je peux avancer". Chaque section renvoie vers le document détaillé pertinent — ce fichier ne duplique pas le contenu, il donne juste la vue d'ensemble et l'état. > > Dernière mise à jour : 2026-09-15. --- ## 1. Produit — features manquantes / en cours → Détail complet, granulaire, à jour : **[todo-features.md](todo-features.md)** Résumé de la table de suivi de ce fichier : - **Fait** : SectionEvent, Escape/Puzzle games, GuidedPath + progression carte, push, stats tracking, sync agenda/météo, traduction IA, quotas (IA/stockage/stats) par plan, audit log backend fiabilisé, refacto SectionParcours/GuidedPath/SectionGame (backend, vérifié 2026-07-15). - **Partiel** : Beacons/geofencing (manager-app UI ⚠️), AI Assistant (manager-app ⚠️), ~~**mode offline**~~ ✅ **corrigé le 2026-08-11 (D1) puis complété le 13/08 (D5)** — le pipeline de collecte n'est plus commenté, une visite embarque désormais contenus, audios et icônes, et une visite incomplète ne s'annonce plus téléchargée. **Reste à confirmer sur device** (§21 / D0), c'est le seul point encore ouvert du volet offline. Repasse UI globale, refacto SectionParcours côté manager-app/visitapp-web/mymuseum-visitapp (UI présente mais sous-comportements non revérifiés en détail — voir section "Refactoring majeur" de todo-features.md). - **🧪 Implémenté mais jamais testé (2026-08-05)** : **onboarding self-service complet** — inscription sur myinfomate-landing (`/[lang]/signup`), création auto de l'instance + du premier user, essai 14j, Stripe (customer/Checkout/webhook/Tax), 9 emails Resend (domaine vérifié, envoi réel validé), job Hangfire du cycle d'essai, watermark « Aperçu » visitapp-web, écran Abonnement manager-app, mot de passe oublié + invitation user, plafond IA d'essai. Les 4 repos compilent, migrations appliquées en base locale, **aucun parcours exécuté** → checklist de test dans `todo-features.md` (section "🧪 Checklist de test end-to-end"). Reste à faire côté config : alias mail `onboarding@myinfomate.be`, et `whsec_` de la Stripe CLI pour tester le webhook en local. - **🧪 Codé et committé le 2026-09-10 (rien de poussé), pas encore testé** : scan d'id brut (QR du Fort) depuis l'accueil, drapeau « afficher le scan QR » et **nom de l'application** par app (Mobile/Web), liens stores (SuperAdmin), QR du manager vers la nouvelle page **`app.myinfomate.be/download/…`**, suggestions de proximité beacon + GPS avec **notification écran verrouillé** (mobile) et suggestion GPS dans la page (web). Tests : [test-plan.md §23](test-plan.md) ; restes hors code (redirection `web.mymuseum.be`, déclarations stores) : carte kanban « QR codes, nom d'application… ». - **À faire** : dashboard super-admin V2, facturation V2. ✅ **Le Stripe Customer Portal est complet le 2026-08-13** (backend + bouton manager-app). - ⚠️ **Cette ligne était périmée sur six points, revérifiés dans le code le 2026-08-13.** Sont **faits** : écran audit log manager-app (front livré le 12/08), **rate limiting API Keys** (livré, pas seulement décidé — politique `ai` dans `Startup.cs:279`, `UseRateLimiter()` en `:344`, les deux endpoints décorés), gestion des users par instance (plafond serveur + compteur UI, 12/08), nettoyage `SectionEvent.ParcoursIds` (11/08), et le **backend** du Customer Portal (13/08). L'**unification `QuestionType`** n'est pas « à faire » mais **écartée** : le trio TextLibre/Digicode/ExpectedAnswer n'a jamais existé dans le code, l'enum a trois valeurs et le digicode est un comportement dérivé, pas un type — reste une propreté front, elle aussi livrée (alias nommés, 11/08). - **📦 Reporté en V2 (décidé le 2026-08-07)** : **SectionForm**, **ressource 360°**, **AR image tracking (Mind AR)**. Les trois sont spécifiés en détail dans [todo-features.md](todo-features.md) mais sortent du périmètre V1 — aucun n'est un prérequis de la migration Postgres ni de la mise en prod. À reprendre tels quels quand la V1 sera stabilisée. **SectionForm a été analysé dans le code le 2026-09-15** : plan complet dans [v2/section-form-plan.md](v2/section-form-plan.md) (réponses **anonymes**, les **trois** fronts visiteur kiosk compris, table `FormSubmission` dédiée, réponses jamais indexées pour le RAG) — **ne pas refaire l'analyse**. - **📦 Reporté en V2 (décidé le 2026-09-15)** : **loader animé composable par le client**. Aujourd'hui le loader est une image fixe (`Configuration.LoaderImageUrl`), et ça suffit pour la V1. La suite est **décidée, pas exécutée** : on transporte des **paramètres** (`{preset, couleurs[], logoResourceId, vitesse}`) et chaque front rend 5-6 presets nativement — **pas de format de fichier animé**. ⛔ SVG animé et Lottie ont été évalués et **écartés** (`flutter_svg` ignore SMIL et les keyframes CSS ; aucun runtime Lottie sérieux sur Unity/Quest) — **ne pas refaire l'analyse des formats**, tout est dans la carte kanban « Loader animé — presets paramétriques » (`cards/5-planifie/285-…`). - **🐛 Bug ouvert (relevé le 2026-08-25)** : **la jauge de stockage du menu latéral ne se rafraîchit pas** après l’ajout (ni la suppression) d’une ressource. `QuotaBarsWidget` n’appelle `instanceGetQuota` qu’une fois, dans `initState` (`quota_bars_widget.dart:23`), et il vit dans le pied du menu **persistant** (`main_screen.dart:477`) : le chiffre affiché date de l’ouverture de session. ⚠️ **Le comptage serveur est correct** — `storageUsedBytes` est recalculé à chaque appel (`SUM(SizeBytes)`, `InstanceController.cs:383`) et le contrôle d’upload refait un `GET /quota` avant de téléverser (`resources_screen.dart:186-198`). D’où l’incohérence visible : une jauge à « 0 KB » et un refus 413 sur le même chiffre. Détail dans [todo-features.md](todo-features.md) — Quota stockage. **Prochaine chose à faire si tu as 1h** : jouer le **§19.13 cas E** du plan de test (chasse au trésor / carnaval) de bout en bout, depuis la création dans manager-app. C'est le scénario le plus complet — il valide SectionMap + SectionParcours + géodéclenchement + questions + mode jeu d'un coup. --- ## 1bis. État des builds — mesuré le 2026-08-06 > Aucune app n'était buildable au début de l'audit. Deux corrections ont débloqué les 3 apps Flutter. > Détail : **[parity-manager-visitapp.md §6](parity-manager-visitapp.md)** · checklist : **[test-plan.md §0](test-plan.md)** | Repo | Build | Note | |---|---|---| | manager-service | ✅ `dotnet build` et ✅ `dotnet test` **124/124** (2026-08-06) | La remise en route de la suite a révélé un **bug backend réel** : `BuildAuditEntries()` ajoutait un `AuditLog` au contexte *pendant* l'énumération du `ChangeTracker` → `InvalidOperationException: Collection was modified` sur toute écriture d'entité auditée (Section, Resource, Configuration, Device, User, Instance). Corrigé : énumération matérialisée, logs ajoutés après la boucle. Invisible jusque-là parce que les tests ne compilaient plus | | manager-app | ✅ `flutter build web` | débloqué : `// @dart=2.18` manquant dans `manager_api_new/lib/api/onboarding_api.dart` (fichier ajouté à la main pour l'onboarding, sans l'annotation de version que porte `api.dart`) — **cassait les 3 apps Flutter d'un coup** | | mymuseum-visitapp | ✅ `flutter build apk` — **les 3 flavors, vérifiés le 2026-08-12** (`dev`, `mdlf`, `fortsaintheribert`) | ⛔ **Le ❌ « revérifié le 2026-08-11 » était périmé.** Le build passe, et sa config Android était **déjà à niveau** — c'est `tablet-app` qui était en retard sur lui, pas l'inverse. K5 s'est donc réduit à deux alignements que le build réclamait en avertissement : NDK 27.0.12077973 → **28.2.13676358** (`speech_to_text` le réclame nommément) et Kotlin 2.1.0 → **2.3.10** (seuil 2.2.20 annoncé par Flutter ; même version que `tablet-app`). L'APK passe de 382 à **349 Mo**. Les 4 erreurs Dart Ray-Ban restent hors du graphe de `main.dart` et ne gênent pas le build (§5bis) | | visitapp-web | ✅ `npm run build` | débloqué : helper `getGeoPointLatLng()` dans `src/lib/geo.ts`, les 7 erreurs venaient d'un `unknown` non narrowé. ⚠️ ce type d'erreur est **invisible en `next dev`** | | tablet-app | ✅ `flutter build apk` — **réparé le 2026-08-12**, APK produit pour la première fois depuis le 16 avril | ⛔ **Le diagnostic « un seul défaut, purement Gradle, peut-être réglé par `5a6701d` » était doublement faux.** Il a tenu des mois parce que personne n'avait lancé la commande. Réalité : **dix crans d'outillage** (Gradle 7.5 → 8.11.1, AGP 7.2.0 → 8.9.1, Kotlin 1.9.0 → 2.3.10, option AGP supprimée, jcenter mort, heap Gradle 1536M → 4096M, Jetifier coupé, `resolutionStrategy` sur `androidx.lifecycle` retiré) — **corrigés le 2026-08-12** — **puis 132 erreurs Dart** que le Gradle masquait : l'app est restée sur **l'ancien contrat d'API**, celui d'avant Postgres v3. Détail complet et suite : **[v1-plan.md lot K](v1-plan.md)** | **Leçon** : `flutter analyze` et `next dev` ne suffisent pas. Seuls `flutter build` / `npm run build` / `dotnet test` disent la vérité — d'où la nouvelle section §0 du plan de test. **Leçon renforcée le 2026-08-12** : un build **jamais lancé** ne vaut pas mieux qu'un build vert supposé. Trois affirmations de ce tableau ont sauté d'un coup dès qu'on a tapé la commande. Corollaire à retenir : *« à 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. ⚠️ **Et un piège de vérification à connaître** : `flutter build apk … | tail` renvoie **le code de sortie du `tail`**, pas celui du build. Un échec y ressort en « exit code 0 ». Rediriger vers un fichier et lire `$?` séparément. --- ## 1ter. Chantier « migration Postgres v3 » — ordre de bataille (ajouté le 2026-08-07) > Postgres n'est pas encore en prod. Trois chantiers ont été analysés le 2026-08-07 et découpés selon une règle unique : > > **Ce qui touche aux données déjà écrites part avec la migration. Ce qui est purement additif attend.** > > Chaque ligne est faite pour être attaquée dans une conversation dédiée : lire le doc, faire l'étape. > > ⚠️ Cette section dit **ce qui doit entrer dans le schéma**, pas comment on remplit la base. L'opération de bascule elle-même — et l'état de `MigrationController` — sont au **§1quinquies**. → **Détail complet : [status/postgres-v3.md](status/postgres-v3.md)** --- ## 1quater. Chantier « Guide IA V1 » — ordre d'exécution (arrêté le 2026-08-07) > Cette section ne décrit **rien de neuf** : elle donne l'ordre dans lequel exécuter ce que trois plans détaillent déjà, parce que le chantier les traverse tous les trois et qu'aucun ne porte la vue d'ensemble. > > **Décision : tout est fait d'un coup, sans mise en prod intermédiaire.** Rien ne part en prod avant que le backlog (kanban + ce fichier) soit terminé — voir §1ter, la base Postgres est vide et c'est une fenêtre à ne pas refermer. → **Détail complet : [status/guide-ia-v1.md](status/guide-ia-v1.md)** --- ## 1sexies. Ordre d'exécution de toute la V1 — et le lot design (ajouté le 2026-08-11) > Ce fichier dit **ce qu'il reste**, par domaine. Le kanban dit **où en est chaque chantier**. Ni l'un ni l'autre ne disait **dans quel ordre**, ni ce qui bloque quoi. > > → **[v1-plan.md](v1-plan.md)** — 9 lots (A à I plus D-bis), 18 liens de dépendance, chemin critique, arbitrages en attente. **4 à 5 semaines**, portées à 5-6 avec le lot design. → **Détail complet : [status/ordre-execution-v1.md](status/ordre-execution-v1.md)** --- ## 1quinquies. La bascule elle-même — Mongo → Postgres en prod (ajouté le 2026-08-09) > **Trou identifié le 2026-08-09** : le §1ter dit *ce qui doit entrer dans le schéma avant que la base se remplisse*. Il ne dit nulle part **comment on remplit la base**. L'opération de bascule n'était écrite ni ici, ni dans le kanban, ni dans aucun plan de `v2/`. > > Rappel : la prod tourne **encore sur MongoDB**. Le transfert se fait par `MigrationController` (`POST /api/migration/run`, paramètres `dryRun` et `instanceId`), qui rejoue Instances → Resources → Users → Configurations → ApplicationInstances → Sections → Devices, puis relie les menus et enrichit les ressources PDF. → **Détail complet : [status/bascule-prod.md](status/bascule-prod.md)** --- ## 2. Tests → Détail complet : **[test-plan.md](test-plan.md)** Checklist manuelle organisée en 20 sections + non-régression. À cocher au fur et à mesure avant une mise en prod. Section "Hors scope" = features non implémentées, pas testées. Ordre conseillé : 0. **§21 — Visite hors ligne** (ajouté le 2026-08-07) : bugs suspectés d'après le code, à confirmer sur device avant de planifier le chantier 1. **§0 — Porte d'entrée build** (5 commandes, bloquant absolu) 2. **§19 — Parité manager-app → apps visiteur**, par type de section : c'est le chapitre qui répond à « tout ce que je configure est-il visible ? ». Le §19.13 (SectionParcours, 5 cas d'usage) est le plus à risque. 3. §18 — Onboarding self-service (jamais exécuté) 4. §1-17 — features par lot, §16 non-régression --- ## 2bis. Parité manager-app → apps visiteur → **[parity-manager-visitapp.md](parity-manager-visitapp.md)** (audit du 2026-08-05, sur le code réel) - **Couverture par type de section : complète** — les 13 `SectionType` sont dispatchés dans `mymuseum-visitapp` et `visitapp-web`, aucun écran vide. - **17 écarts au niveau champ** au moment de l'audit : 7 côté mobile, 10 côté web. Le plus lourd — l'absence d'assistant IA côté web, alors que le plan Essentiel est web-only — est **résolu le 2026-08-06**, et répercuté sur mobile le même jour. - Suivi des corrections : table du **[test-plan.md §20](test-plan.md)**. → **Détail complet : [status/parite-manager-visitapp.md](status/parite-manager-visitapp.md)** --- ## 3. Sécurité & dette technique → Audits : **[security/audit-securite-manager-service.md](security/audit-securite-manager-service.md)** et **[security/audit-manager-app.md](security/audit-manager-app.md)** (2026-07-13/14) - **manager-service** — le point critique est la **rotation des secrets committés** (JWT signing key, clés API, connection strings, MQTT, Telegram). Gravité inchangée, mais **déplacée en fin de backlog le 2026-08-11** : les 6 repos sont privés sur un Gitea auto-hébergé. ⚠️ Contrainte à ne pas perdre — **la rotation doit précéder I3** (compose/Traefik prod), sinon la prod naît avec les clés de l'historique et il faut rotationner deux fois. Puis quatre niveaux Haute → Basse. - **manager-app** — le critique (`manager_api_new` désynchronisé, 68 erreurs de bruit) est ✅ **résolu le 2026-08-11** : `flutter analyze` passe à 3 issues et redevient un feu vert utilisable. Au passage, les 3 déclencheurs de génération OpenAPI ont été supprimés, ce qui **verrouille la règle « `manager_api_new` s'édite à la main »**. Reste Haute → Basse : duplication du shell de dialog, `build()` monolithiques, i18n contournée, clé AES en dur. → **La duplication du shell de dialog a désormais sa maquette et sa carte** : `DOCS/claude design/refonte-configuration-sections.html` §6 (coquille, inventaire des 29 dialogues, deux dialogues dessinés) et `kanban/cards/5-planifie/290-…`. ⚠️ **Ordre imposé** : les 8 `showNewOrUpdate*` sont *absorbés* par l'éditeur de collection du gabarit B — extraire un scaffold pour eux d'abord, ce serait refactoriser du code à supprimer. Voir la note dans `security/audit-manager-app.md`. → **Détail complet, par priorité et avec les cases à cocher : [status/securite-dette-technique.md](status/securite-dette-technique.md)** --- ## 4. Infrastructure & Ops - [x] ✅ **Travail non committé — résorbé. Revérifié le 2026-08-11 (2e passe) : plus rien en attente.** Les **9 repos** (DOCS compris) sont propres (`git status --porcelain` vide partout) **et à jour avec leur remote** (aucun `ahead`/`behind`). L'alerte du 2026-08-09 et sa révision du matin du 11/08 (« ~41 fichiers en working tree dont 9 non suivis ») sont toutes deux **périmées** : le lot 3 RAG est dans `18e4240`, le socle visuel + Guide IA dans `eb8e849`. **L'étape 1 du lot A est terminée** — ne pas la re-planifier - Derniers commits par repo : `manager-service` `18e4240` (RAG : pipeline d'ingestion, endpoints du guide IA, journalisation RGPD) · `manager-app` `eb8e849` (socle visuel et écran Guide IA à deux onglets) · `visitapp-web` `473fc3a` · `mymuseum-visitapp` `af44927` · `tablet-app` `5a6701d` (drapeaux du migrateur Flutter) · `myinfomate-landing` `d91cf7f` · `unov-landing` `cfa70c4` · `OpenGlasses` `1d887d7` - Rappel de l'état des branches : `manager-service` → `MyInfoMate_3.0`, `manager-app` → `Interface-refacto`, `mymuseum-visitapp` → `Meta-Rayban-Test` (23 commits d'avance sur `master`, voir §5bis), `tablet-app` → `AI-Assistant-test`, `visitapp-web` et les deux landings → `master` - [ ] **pg_dump quotidien** pour `manager-service` (Postgres `my_info_mate`), en complément du snapshot OVH. ⚠️ **Bloquant au moment de la bascule** : point 18 du [§1quinquies](#1quinquies-la-bascule-elle-même--mongo--postgres-en-prod-ajouté-le-2026-08-09), le seul filet du jour J - 🔨 **Scripts livrés et testés le 2026-09-07** — `manager-service/ManagerService/Deployment/backup/`, installation et restauration documentées dans `README.md` et **`RESTORE.md`**. Cycle complet validé sur la base de dev : dump → vérification de relecture → restauration dans une base jetable → **25 tables aux comptages identiques**. Extraction par instance validée aussi (les deux extractions totalisent exactement le global). Embeddings exclus : dump de 12 Mo → **1,7 Mo** - ✅ **Destination créée le 2026-09-07** — projet GCP `myinfomate-backups` (séparé de `mymuseum-3b97f`), bucket `gs://unov-myinfomate-backups` en `EU` multi-région, versioning activé, accès public interdit, lifecycle 400 jours sous `pg/` seulement. Service account `backup-writer` en `objectCreator` + `objectViewer` : **incapable de supprimer, et vérifié** (l'écriture passe, le `rm` renvoie `403 storage.objects.delete denied`). Détail et test rejouable dans `Deployment/backup/README.md` - ⛔ **Ce n'est pas encore une sauvegarde** : `rclone` n'est ni installé ni configuré sur le VPS, donc rien ne part encore hors site. Et `notify.sh` n'est branché sur aucun canal — carte kanban « Brancher `notify.sh` sur un canal réel » - 📌 **Volume des médias : 1,43 Go** (`gcloud storage du -s gs://mymuseum-3b97f.appspot.com`, 2026-09-07). Le bucket connaissait la réponse que le plan attendait du backfill. Assez petit pour tenir dans le même bucket de sauvegarde sous `media/` — **pas besoin d'OVH Object Storage**, la disposition croisée envisagée le 07/09 est abandonnée pour cette raison - ✅ **Versioning activé sur le bucket des médias le 2026-09-07** — `versioning_enabled: True` sur `gs://mymuseum-3b97f.appspot.com`, plus une lifecycle rule qui purge les versions périmées à 30 jours (le bucket n'avait **aucune** règle auparavant, rien n'a été écrasé). L'ordre importait : le filet est en place **avant** que `Firebase:StorageBucket` soit renseignée (carte « Poser `Firebase:StorageBucket` »), jour où la suppression de blob devient réelle. Le bucket portait déjà une soft delete de 7 jours depuis mars 2024 - 📌 **Décision de conception** : **un dump global, pas un par client.** Une restauration par client se fait par extraction depuis le dump global (`extract-instance.sh`) — 14 tables portent `InstanceId`, 7 tables filles se rattachent par leur parent. Des sauvegardes par client multiplieraient par N les jobs à planifier, les échecs à surveiller et les restaurations à tester, pour la même capacité de récupération - ✅ **Médias copiés le 2026-09-07** — 1,43 Go, 2407 objets, `gcloud storage rsync` serveur à serveur vers `gs://unov-myinfomate-backups/media/`. **Taille identique à l'octet**, zéro erreur. C'est la première sauvegarde des médias depuis le début du projet. ⛔ **Pas encore planifiée** : c'est une copie unique. **Storage Transfer Service envisagé puis écarté le 2026-09-07** — 5 attributions IAM et un agent de service avec droit de suppression, pour automatiser une commande à relancer toutes les quelques semaines sur des données qui bougent de ~2 ressources par mois : disproportionné. Le mécanisme reste le `rsync`, qui tourne avec un compte humain sans aucun changement de permission, et sera ajouté aux timers du VPS avec la sauvegarde Postgres - 🔍 **L'inventaire des orphelins est à moitié fait, gratuitement** — 27 objets sur 2408 n'appartiennent à aucun client : 19 sous un id à un caractère de celui de MyInfoMate (`…f1` vs `…f2`), 2 sous MNAHA (qui n'existe qu'en base de dev), et 6 fichiers de test à la racine du bucket (`giphy.gif`, une vidéo Cybertruck, des `file_example_*`) qui ne suivent pas le schéma `pictures/{instanceId}/{id}` et sont donc invisibles au quota. Détail et réserves dans [v2/media-storage-plan.md](v2/media-storage-plan.md) - ⛔ **Deuxième chose qu'il débloque** : le job `visit-events-purge` (purge des stats au-delà de 13 mois) est codé et enregistré mais **volontairement inactif** — il ne supprimera rien tant que `Stats:RetentionDays` n'est pas défini. Ne l'activer (`Stats__RetentionDays=395`) qu'une fois ce pg_dump réellement hors site - [ ] **Fermer le port PostgreSQL exposé publiquement** via Traefik/Docker (détail dans [todo-features.md](todo-features.md), section "Infrastructure — Sécurité réseau") — accès DBeaver via tunnel SSH uniquement - [x] 🔨 **Sauvegarde de la prod Mongo — faite le 2026-09-07.** `Deployment/backup/dump-mongo-prod.sh`, lecture seule (aucun `mongorestore` dans le script, volontairement). L'export de référence datait du 1er avril. Delta sur 5 mois : 11 sections créées, 3 supprimées, 17 modifiées, 9 ressources créées. **VisitNamur crée du contenu, MDLF retouche l'existant, Fort Saint Héribert n'a rien touché** — utile à savoir avant de reprendre contact avec eux. ⚠️ Piège : le formatage des dates change entre versions de `mongoexport` (`.420Z` → `.42Z`) et fait apparaître 239 fausses modifications ; normaliser avant de comparer - [ ] **Backup Mongo automatique en cron** — le script existe désormais, reste à le planifier. Voir [todo-landing-deploy.md](todo-landing-deploy.md), section 5 (dump + `docker cp` vers l'hôte, pas seulement dans le conteneur) - [x] Déploiement landing page (`docker-compose-landing.yml` séparé, ne jamais toucher au compose principal) — voir [todo-landing-deploy.md](todo-landing-deploy.md) pour les règles à respecter --- ## 5. Roadmap produit — nouveaux canaux & IA Dix-neuf chantiers de canaux et d'IA, chacun avec son plan détaillé. État au 2026-09-02 : - **V1** — **visiteur web** : `visitapp-web` build ✅, les 13 types de section rendus, assistant IA inclus ; **il ne manque que le Dockerfile et l'entrée `app.myinfomate.be` au compose**. Bloquant, le plan Essentiel vendu par l'onboarding est web-only. Plus l'**écran Guide IA**. La **Médiathèque** (basculée en V1 le 2026-09-02) est **codée de bout en bout le même jour** — index inverse des usages, panneau de détail, facettes, suppression protégée, les deux bugs corrigés ; `dotnet test` 236/236 et `flutter build web` verts, **mais la checklist de 15 points reste à passer dans un navigateur** (colonne « À tester » du kanban). Voir [v1-mediatheque-plan.md](v1-mediatheque-plan.md). - **Livrés** — export PDF des stats à la demande, historique 13 mois pour tous les plans, refonte de l'écran Statistiques (⚠️ jamais ouvert dans un navigateur). - **V2** — module Studio (génération IA d'images), Personnages (une entité `Persona` unifiant trois plans), TTS pré-généré, kiosk web, VR Meta Quest, import IA + RAG. 🛠️ **Studio : lots 0 à 6 codés et commités (branche `studio`, pas encore poussée), calibrage §9.4 fait le 2026-09-15** (≈ 3 $ réels, unité de crédit arrêtée : 1 crédit = 0,015 $ de coût fal, prix de vente avec marge). Lot 7 : échantillons de style et figures d'archétypes embarqués, reste l'écoute des voix. **Lots 8 et 8bis codés et commités le 2026-09-15, jamais exécutés en réel** — narrateurs assignables et chaîne de résolution, génération audio Gemini TTS → MP3 (1 crédit par minute, état « à régénérer »), onglet Narrateurs du parcours, blocs sur l'article et le point de carte, cartes Narration et Personnages dans l'écran Configuration, portrait du narrateur et écran « les personnes que vous allez rencontrer » sur les trois apps visiteur, lecteur audio dans la fiche d'un point de carte (lot 8e, ajouté le même soir). ⚠️ Au passage, les apps visiteur ne jouaient pas un audio rangé par identifiant de ressource — corrigé. **À faire** : passer [test-plan-studio-narration.md](test-plan-studio-narration.md) (clé Gemini + ffmpeg), extraits d'écoute des voix, lot 8f (la narration et le casting dans l'app VR, carte 315), test du conservateur (gate lot 4), push de la branche `studio`. Le prérequis « le backend ne sait pas écrire dans le bucket » est levé depuis le lot 0. - 📄 **La frontière entre le Studio IA et le canal XR est tranchée depuis le 2026-09-11** : [v2/immersif-frontiere-plan.md](v2/immersif-frontiere-plan.md). Les deux plans se renvoyaient la balle (le Studio mettait la 3D en « dépend du chantier VR », le plan VR décrivait les POI sur GLB sans dire d'où venait le GLB). Trois couches : ressources immersives (360/GLB, **se vendent sans casque**), consommation, et le Studio comme *source d'approvisionnement* de la première. **Cinq décisions de rétro-compat touchent des lots antérieurs à la 3D** — à lire avant la première migration du Studio, pas en arrivant au lot 11. - ✅ **Le backend du canal XR est fait le 2026-09-11** (lot `XR-1` de [v2/vr-quest-unity-plan.md](v2/vr-quest-unity-plan.md)) : `Device.AppType` + migration, `DeviceController` résout l'`ApplicationInstance` sur le canal au lieu de `Tablet` en dur, `Get` filtre par canal, `ApiKeyAppType.VrApp`, `appType` dans `manager_api_new`. 224 tests au vert. Et **`XR-3` était déjà fait** — l'export est ouvert aux apps depuis `9cc45c5`, le plan était en retard sur le code. - ✅ **`XR-2` fait le 2026-09-12 — le canal VR est administrable.** L'écran XR est une coquille à deux sous-onglets : « Configuration » réutilise `AppConfigurationLinkScreen` tel quel (déjà générique sur l'`appType`, zéro code neuf), « Casques » est la grille avec pincode d'appairage, état connecté, batterie, version et dernier vu. i18n FR/EN/NL. ⚠️ Deux affirmations du plan étaient fausses : la grille kiosk liste des `AppConfigurationLink`, pas des `Device` (le filtre par canal était déjà implicite, et le paramètre `appType` de `/api/device` ne sert pas à cet écran), et batterie/version/dernier vu ne sont que dans `DeviceDetailDTO` — donc un appel de détail par casque, assumé sur une flotte qui se compte en unités. Ne restent que deux puces documentaires de `XR-3` (contrat d'export versionné, décision multilingue). - ⚠️ **Nommage** : les lots du chantier XR s'appellent `XR-1`…`XR-5` (renommés le 11/09, ils s'appelaient `V-1`…`V-5` et se confondaient avec « V1 »). Les lots du backlog V1 sont lettrés `A`…`J` dans [v1-plan.md](v1-plan.md). - ✅ **L'app Unity tourne sur un vrai casque depuis le 2026-09-11** (lot `XR-4`, items `E0` et `E1` sauf l'Interaction SDK) : Unity 6000.0.83f1, projet URP dans [`vr-app/`](../vr-app/README.md), APK sideloadé sur un Quest 2 en Horizon OS v207. **Le prérequis qui bloquait tout le lot est levé.** Mesuré sur le casque : un décor glTF de 50 Mo charge en **1,4 s** et tient **72 FPS**, mais avec le GPU au maximum — le budget de scène devra être chiffré. La **conversion d'axes glTF→Unity est prouvée** (`NegateX`), au repère de calibration, donc elle ne se redémontre plus. - ⚠️ **Deux numérotations E0-E se confondaient** : celle de `XR-4` (E0-E11, l'app Unity complète) et celle du plan de la piste Scène 3D. La seconde est renommée **S0-S8** le 11/09 — [vr-app/docs/04-phase3-plan.md](../vr-app/docs/04-phase3-plan.md). **Le plan unifié gouverne** ; en cas de contradiction, le document le plus récemment mis à jour tranche. Fait dans la piste S : S0, S1 (sauf le cercle de navigation), S2 ; S3 (viewer web) écrit mais jamais essayé. - ➡️ **Prochain travail sur le canal XR** : le POC de `XR-4`, soit `E2` (appairage par pincode, `POST /api/device`) → `E3` (lecture de `GET /api/configuration/{id}/export`) → `E5` (menu flottant) → `E6` (360°). E2 et E3 sont débloqués par XR-1 et XR-3, tous deux faits. - ⚠️ **Deux numérotations E0-E se confondaient** : celle de `XR-4` (E0-E11, l'app Unity complète) et celle du plan de la piste Scène 3D. La seconde est renommée **S0-S8** le 11/09 - [vr-app/docs/04-phase3-plan.md](../vr-app/docs/04-phase3-plan.md). **Le plan unifié gouverne** ; en cas de contradiction, le document le plus récemment mis à jour tranche. Fait dans la piste S : S0, S1 (sauf le cercle de navigation), S2 ; S3 (viewer web) écrit mais jamais essayé. - 🟡 **`E2` et `E3` écrits le 2026-09-12, jamais essayés** : `vr-app/.../Net/` — `ApiClient` (le seul point de contact avec le backend), `PairingService` (pincode → clé d'API → `POST /api/device` avec `appType = 3`, appairage persistant), `ConfigurationExport` (un appel pour tout le contenu), et `PairingBootstrap` qui affiche le résultat dans le casque. Compile contre les DLL Unity + Newtonsoft ; **rien n'a encore parlé à un vrai serveur ni tourné sur le Quest**. ⚠️ Confirmé au passage : l'export **ne rend qu'une langue** (`GetReferencedResourceIds(language)`), donc changer de langue à chaud impose de recharger — c'est la question ouverte de XR-3. ⚠️ Et les scripts Unity parlaient encore `E1`/`E2` pour `S1`/`S2` : renommés `S1Bootstrap`/`S2Bootstrap` le 12/09. - 🟡 **`E4` (cache offline) et `E9` (télémétrie) écrits le 2026-09-12, jamais essayés** : `ContentCache` (écriture atomique — une borne débranchée le soir ne laisse pas de JSON tronqué), `ContentService` (**cache d'abord**, rafraîchissement de fond dont l'échec est silencieux), `Telemetry` (« tire et oublie »). ⚠️ La route des stats est **`/api/stats/event`**, et `appType` y part en **chaîne parsée par nom** : une faute de frappe retombe sur `Mobile` sans erreur, et les visites du casque seraient comptées en mobile. - 🟡 **`E5` — le menu flottant, écrit le 2026-09-12, jamais essayé** : arc de panneaux à 2,2 m qui **ne suit pas la tête**, vignettes chargées après coup, télémétrie branchée, et **trois moyens de viser** — manette (gâchette), main (pincement), tête (temporisation 1,2 s). ⚠️ **« À la tête », pas « aux yeux »** : le Quest 2 n'a pas d'eye tracking, seul le Quest Pro en a. ⚠️ **La dépendance `E5 → E1` du plan était fausse** : `OVRInput` et `OVRHand` viennent du **Core** SDK, déjà installé — l'Interaction SDK n'apporte que le confort. **E1 sort du chemin critique du POC** (voir le §8bis du plan). - 🟡 **`E8` — quatre types de section, écrits le 2026-09-12, jamais essayés** : Slider, Map, Parcours et Event, tous dans la même vue paginée (`PagedView` + `SectionPages`) — une chose à la fois, grande, devant soi. ⚠️ **Deux écarts assumés** : la **Map est une liste de POI**, pas la maquette 3D promise (ça demande `SectionModel3D`, et une carte Google sur panneau flottant serait *moins* bonne qu'un téléphone) ; le **Parcours** est rendu comme une Map, pour la même raison. L'**Event** ne montre que la journée en cours et retombe sur les dates suivantes si elle est vide. Une section non gérée affiche son titre et le dit. - 🟡 **`E10` — la session de borne, écrite le 2026-09-12, jamais essayée** : fin de visite à la **repose du casque** (via `CommonUsages.userPresence` d'Unity XR, donc sans SDK Meta ni rien à configurer) ou après **90 s sans activité**, retour au menu **recentré devant le visiteur suivant**, nouvelle session de stats, écran qui ne s'endort pas. ⚠️ Le verrouillage de l'app sur le casque n'est **pas** du code : c'est le mode appareil de Meta. - ✅ **La ressource 360° est faite le 2026-09-12** — le dernier prérequis du POC est levé. `ResourceType.Image360` (11), `Video360` (12), `Model3D` (13) **en fin d'enum**, sans migration (colonne déjà `integer`), verrouillées par un test valeur par valeur. Côté manager : la pastille de type du sélecteur de médias devient **cliquable** pour déclarer une 360 (aucune extension ne le dit — un panorama est un `.jpg` comme un autre), le `.glb` est accepté et déduit seul, i18n FR/EN/NL. ⚠️ **Le vrai piège n'était pas l'enum mais la compression** : `ImageCompressor` ramène toute image à 2560 px, ce qui ferait d'une équirectangulaire 8192×4096 une bouillie dans un casque — les trois types en sont exclus, sur les **deux** chemins d'upload. ✅ Et le prérequis « le backend ne sait pas écrire dans le bucket » **ne s'applique pas** : `manager-app` pousse directement dans Firebase puis enregistre l'URL. - 🟡 **`E6` — la lecture 360°, écrite le 2026-09-12, jamais essayée** : image et vidéo équirectangulaires dans le même shader `Skybox/Panoramic`, la vidéo par une `RenderTexture` alimentée depuis le cache disque, et le ciel d'origine restauré à la fermeture (c'est un réglage global). **Le retour au menu ne reste pas affiché** — 4 s au début, puis il s'efface et revient quand le visiteur baisse les yeux ou prend une manette, et il est reposé sous le regard courant : en 360 on tourne sur soi-même. ⚠️ **`Skybox/Panoramic` doit être dans *Always Included Shaders*** — sinon le ciel sort **magenta sur le casque et correct dans l'éditeur**, le piège déjà payé avec glTFast. ⚠️ **Mémoire** : `LoadImage` décode en RGBA32, soit **134 Mo pour une 8192×4096** — compressée en ASTC au chargement et libérée à la sortie, sinon l'app se fait tuer au bout de quelques 360 (invisible sur un essai unique, fatal en borne). - 🟡 **`XR-5` — la supervision de flotte, l'essentiel écrit le 2026-09-12** : `PUT /api/device/{id}/heartbeat` (batterie, version ; le serveur pose lui-même `Connected` et `LastSeen` — recevoir le battement *est* la preuve) et `FleetReporter` côté casque, toutes les 3 min plus une fois au démarrage. **Battement HTTP plutôt que MQTT** : à 1-3 casques, MQTT coûterait dix fois plus de code pour remonter trois chiffres ; il redeviendra utile pour **pousser** vers le casque, pas pour remonter. ⚠️ `Update` n'écrivait **ni `AppVersion` ni `LastSeen`** : les deux colonnes que l'onglet XR affiche n'avaient aucun chemin d'écriture. - 🔴 **Trois bugs de production trouvés et corrigés le 2026-09-12, tous sur le même mur** : outre l'appairage ci-dessous, `GET /api/Device/{id}/detail` était fermé aux clés — or c'est le **premier appel d'une tablette qui démarre**, celui qui lui dit quelle configuration afficher : une tablette déjà appairée ne retrouvait plus son contenu au redémarrage. Et `tablet-app/lib/main.dart:38` reconstruisait son client **sans clé**, alors qu'elle est persistée en base locale. La route refusait les clés, l'app n'en envoyait pas : les deux se tenaient. - 🔴 `POST /api/device` répondait **403 à toute tablette** depuis le **13/03/2026** — la policy `InstanceAdmin` posée sur `DeviceController` contre une clé d'API qui ne porte que `AppRead`/`Viewer`, et `tablet-app` ne s'authentifie jamais autrement. Une tablette déjà appairée ne rappelle jamais cette route : **seul un nouvel appareil échouait**, donc personne ne l'a vu pendant six mois. ⚠️ **À vérifier sur le terrain** — les tests appellent le contrôleur directement, sans filtre d'autorisation, donc ils ne prouvent rien sur l'accès. - 🟡 **`E7` — la maquette 3D et ses points d'intérêt, écrite le 2026-09-12, jamais essayée.** `SectionModel3D` est **un vrai type de section**, pas une Map augmentée : une maquette n'a ni fond cartographique, ni zoom, ni coordonnées terrestres. Ce qu'on réutilise, c'est le **`GeoPoint`** — il portait déjà `SectionMapId` *et* `SectionEventId`, un troisième rattachement suit le patron, et les points gardent titre, description, audio et multilingue. Migration `AddSectionModel3DAndPoiPosition` (3 colonnes nullable). ✅ **L'« éditeur de placement 3D », annoncé comme le seul morceau non trivial, n'était pas à écrire** : `vr-app/viewer` sait déjà le faire et **son protocole `postMessage` existait déjà**, pensé pour ce cas — il parle en manifeste de scène, le même objet que lit le casque. Le manager le monte en **iframe**, comme il le fait déjà trois fois ailleurs. Côté casque, `Model3DView` ne dessine rien non plus : il construit un `SceneManifest` depuis la section et le passe au `SceneBuilder` de la piste S. ⚠️ **Le viewer n'a jamais tourné** (S3), et il doit être servi sous le même domaine que le manager. - 🔴 **Deux trous de l'export trouvés et corrigés le 2026-09-12** — et ils ne concernaient **pas que la VR**, l'export est ce qui part en visite hors ligne. **Un** : il ne portait **aucun champ spécifique de section** (`Section.ToDTO()` n'est pas virtuelle, l'export l'appelait sur une variable de type `Section`) — une galerie sans ses images, une carte sans ses points. **Deux** : les collections des sous-types n'étaient pas chargées, donc une Map exportait zéro point. Corrigés par `SectionFactory.ToDTO` + pré-chargement, verrouillés par six tests. ✅ Au passage, la question multilingue de `XR-3` se tranche toute seule : `language` ne filtre que les **ressources**, l'omettre rend toutes les langues — le casque change donc de langue **sans aucun appel**. - ✅ **`XR-3` est clos le 2026-09-12** : le JSON d'export est un **contrat versionné** (`exportVersion: 1`, `generatedAt`, règles de compatibilité écrites sur le DTO), et la question multilingue est tranchée par le code lui-même. - ✅ **`XR-5` est clos aussi** : **pousser une configuration vers le casque sans MQTT** — la réponse au battement porte la configuration assignée, le casque compare et recharge en revenant au menu, sans redémarrage. Coût : trois minutes de latence au pire. Ce que ça évite : une connexion permanente sur une borne et une bibliothèque MQTT dans le build IL2CPP. Le publish serveur existe déjà si un jour trois minutes sont trop. Plus l'**alerte « casque muet »** après une heure sans battement — elle corrige un mensonge, la pastille « connecté » venant du dernier battement reçu. - ➡️ **Prochain travail sur le canal XR** : **jouer le §25 du [plan de test](test-plan.md)** — 11 blocs, **135 cas**. Le §25.7 (déclarer une 360 dans le manager) et le §25.9.7 (appairer une nouvelle tablette) se jouent **sans casque** ; le reste demande le Quest. **Le POC est écrit en entier** : rien de E2 à E10 n'a jamais tourné, et c'est la seule chose qui manque. - **Abandonné le 2026-09-02** — talking head : son lipsync reposait sur `enable_time_pointing` de Google Cloud TTS, or le code livré tourne sur Gemini TTS. Le plan était sans fondation, pas « à faire ». → **Détail complet, la table des 19 chantiers : [status/roadmap-canaux.md](status/roadmap-canaux.md)** --- ## 5bis. Lunettes Ray-Ban Meta — état réel du code (relevé le 2026-08-09) > Cette section corrige une erreur de ce fichier : la roadmap classait l'AR lunettes en « pas commencé, pilote subventionné quand le SDK sort de preview ». **Un POC fonctionnel existe depuis mai-juin 2026**, ~2 700 lignes de Dart dans `mymuseum-visitapp`, sur la branche **`Meta-Rayban-Test`** (23 commits d'avance sur `master`, jamais mergée — c'est la branche de travail courante du repo). → **Détail complet : [status/rayban-meta.md](status/rayban-meta.md)** --- ## 5ter. Visibilité — SEO/GEO de la landing & LinkedIn (ouvert le 2026-09-10) → Plan en 21 actions et suivi : **[myinfomate-landing/audit-seo-geo.md](../myinfomate-landing/audit-seo-geo.md)** (§0) · posts : **[linkedin-posts-lancement.md](linkedin-posts-lancement.md)** - ✅ **Corrections rapides (actions 1 à 5)** faites le 2026-09-10 : titres, schema `Organization` (adresse, TVA), 3 offres dans le schema, 9 modules dans le HTML, liens morts. Build OK, vérifié dans le HTML servi. **Stagées, pas committées.** - ✅ **LinkedIn** : vitrine MyInfoMate créée sous Unov, fiche produit soumise à LinkedIn. - ✅ **Actions 6 à 8** faites le 2026-09-10 : `llms.txt` en français, **prérendu statique rétabli** (58 pages, le layout racine est désormais `[lang]/layout.tsx`), page **`/{lang}/tarifs`** avec FAQ tarifaire. Stagées, pas committées. - ✅ **`/assistant-ia` livrée le 2026-09-10 dans les 4 langues** (relue par Thomas en FR) — 6 FAQ par langue, `hreflang` complet. **62 pages prérendues, 54 URLs au sitemap.** Au passage, les liens légaux des footers sont passés en `` : le lint est à **0 erreur** (15 avant). - ✅ **CGU publiées le 2026-09-10** sur `myinfomate.be/conditions-generales` — le lien de la case de consentement de `/signup` pointait jusque-là vers `/{lang}#`, c'est-à-dire nulle part. Lien ajouté aussi dans les pieds de page des 4 langues et dans le sitemap. **Deux contradictions corrigées dans [cgu-myinfomate.md](cgu-myinfomate.md)** : §6.1 citait Starter/Standard (2 et 10 Go) et §7.1 réservait l'IA aux « plans Standard et Premium ». Ce fichier reste la source ; la page Next en est le rendu, à tenir synchrone. - ⚠️ **Reste dû : la validation juridique des CGU** (jamais faite, le document le dit depuis avril) et le **DPA** qu'un acheteur public demandera. Carte kanban dédiée ; à faire **avant** d'ouvrir l'inscription à de vrais clients payants, pas avant la mise en prod technique. - ✅ **Vocabulaire acheteur injecté dans les 6 segments, en français, le 2026-09-10** — le site n'écrivait « RGPD », « marché public », « accessibilité » ni « médiation numérique` nulle part. Ajouté par segment : une FAQ **RGPD** (les 6), une FAQ **marchés publics** (5 — pas les hôtels, secteur privé), une FAQ **accessibilité** disant franchement qu'il n'y a **ni certification Access-i ni audit** (3 segments publics). L'argument central : Visit Namur, retenu sur **cahier des charges publié**. - ✅ **Trois chantiers techniques bouclés le 2026-09-10** : **FAQ de la page d'accueil** (8 questions ×4 langues + `FAQPage` — la page qu'un LLM atteint en premier n'en avait aucune), **`BreadcrumbList`** sur segments, cas clients, tarifs et assistant IA, et **vraies dates dans le sitemap** (toutes les URLs portaient la date du build ; constante `LAST_MODIFIED` en tête de `sitemap.ts`, à mettre à jour avec le contenu). - ✅ **FAQ des segments traduites le 2026-09-10** : 42 items en EN/NL/DE, parité atteinte dans les 4 langues. Et **images recompressées** — 1,1 Mo économisé sur trois fichiers (`sharp` en installation temporaire, **pas** ajouté aux dépendances ; l'ajouter en dépendance améliorerait l'optimisation d'images en prod, mais c'est une décision de déploiement, à trancher avec le Dockerfile). - ✅ **Captures d'écran de la landing renouvelées le 2026-09-10** — Thomas a fourni les vraies captures de la V3 (app du Fort) : accueil sombre en grille bento et fiche article dans le hero, liste des sections dans le mockup « white label ». Les textes alternatifs, jusque-là en anglais et décrivant l'ancienne interface, sont réécrits et **localisés dans les 4 langues** (`imgAlt` dans `translations.ts`). - ⚠️ `public/google-maps-route.png` (699 Ko) n'est **référencé nulle part** dans `src/` — supprimable, pas supprimé. ⚠️ Le hero utilise encore `map_generated.png`, une carte **générée**, pas une capture réelle. - ✅ **Trois pages de plus le 2026-09-10, en 4 langues** : `/marches-publics` (argument : Visit Namur attribué sur cahier des charges publié), `/borne-kiosk` et `/visite-hors-ligne`. Gabarit partagé `components/ContentPage.tsx`. Le pied de page a désormais une colonne « Solutions » qui lie les 5 pages produit. **75 pages prérendues, 67 URLs au sitemap.** - ✅ **`sharp` ajouté aux dépendances, sur mesure et non sur croyance** : sans lui `/_next/image` renvoyait le JPEG source (64 Ko), avec lui du WebP (26 Ko). ⚠️ **À confirmer au premier build Docker** : le lockfile a été généré sous Windows et sharp installe des binaires par plateforme ; si `npm ci` sur Alpine ne prend pas la variante `linuxmusl`, il faudra une ligne dans le Dockerfile. Le Dockerfile n'a **pas** été modifié. - ✅ **Pages légales, blog et comparatifs livrés le 2026-09-10.** Légales : mentions et confidentialité traduites en 4 langues, CGU laissées en français avec avis traduit (un juriste va les corriger, traduire maintenant serait à refaire) ; les 3 pages passent sous `/{lang}/…` et les anciennes URLs redirigent vers la langue du visiteur. Blog `/fr/ressources` avec 2 articles. **Comparatifs** `myinfomate-vs-smartify` et `-vs-stqry`, **prix relevés à la source le 10/09 et datés sur la page**. **89 pages prérendues, 81 URLs au sitemap.** - ⏸️ **Témoignages clients écartés par Thomas** : il ne veut pas solliciter les clients pour l'instant. À rouvrir si un client en propose un. - ⏭️ **Reste au plan SEO** : deux pages XR à écrire quand les modules seront démontrables — **`/lunettes-connectees` et `/casque-vr`**, cette dernière ajoutée le 10/09 à la demande de Thomas. - ⚠️ **Les prix des concurrents vieillissent** : la page comparative affiche sa date de relevé. À revérifier avant toute campagne qui s'appuie dessus. ⚠️ Toujours aucun document d'appel d'offres (attestations fiscale/ONSS, DPA, attestations de bonne exécution) : ne rien promettre à ce sujet. - ⚠️ **Posts LinkedIn en deux vagues** : les posts sur des déploiements réels peuvent partir maintenant ; ceux qui poussent à l'inscription (IA, prix, essai) attendent la bascule prod et un onboarding testé. --- ## 6. Sous-projets MyInfoMate - **MyInfoMate Sport** — pilote Hockey Namur. Vue d'ensemble : [sport/solution-overview.md](sport/solution-overview.md), spec : [sport/myinfomate-sport-spec.md](sport/myinfomate-sport-spec.md), pitch : [sport/pitch-commercial.md](sport/pitch-commercial.md) - **MyInfoMate Crèche** — pilote childcare en cours. Vue d'ensemble : [creche/solution-overview.md](creche/solution-overview.md), spec : [creche/myinfomate-creche-spec.md](creche/myinfomate-creche-spec.md), pitch : [creche/pitch-commercial.md](creche/pitch-commercial.md) --- ## 6bis. Cohérence de la doc — audit du 2026-08-07 Passage en revue de tous les fichiers `DOCS/` (hors `sport/` et `creche/`). Corrigé directement : | Fichier | Ce qui était faux | |---|---| | [roadmap.md](roadmap.md) | Annonçait **Claude API** comme LLM à 4 endroits — c'est **Gemini 2.5 Flash-Lite**. Quota IA en requêtes → tokens | | [parity-manager-visitapp.md](parity-manager-visitapp.md) | L'intro du §6 disait « visitapp-web reste cassé » et B2 « tests backend ❌ » alors que les deux sont corrigés depuis le 2026-08-06 — le doc se contredisait lui-même | | [v2/tts-pregenerated-plan.md](v2/tts-pregenerated-plan.md) | Chemin Firebase « à confirmer » et faux. Le vrai est `pictures/{instanceId}/{resourceId}`, sans extension. Le refactor uploads est partiellement devancé par `media-storage-plan.md` | | [plan-import-ia-stats-subsides.md](plan-import-ia-stats-subsides.md) | « Aucune infra email n'existe » → **Resend est en place** (9 templates, domaine vérifié). Quota `AiRequestsPerMonth` → `AiTokensPerMonth` | | [security/audit-securite-manager-service.md](security/audit-securite-manager-service.md) | `ImageHelper` : confirmé **code mort** qui planterait sur Linux. Double `SaveChangesAsync` : à revérifier après le fix `BuildAuditEntries` du 2026-08-06 | | [solution-overview.md](solution-overview.md) | Grille tarifaire **Starter/Standard/Premium (69/99/199 €)** — structure abandonnée. Marquée obsolète | ### 🔴 Demande ton arbitrage — non corrigé volontairement **[cgu-myinfomate.md](cgu-myinfomate.md) §5 décrit des plans qui n'existent plus** : Starter / Standard / Premium (69 / 99 / 199 € HTVA), quotas IA en requêtes. La réalité est Essentiel / Pro / Premium / Enterprise (39 / 99 / 179 €), quotas en tokens. C'est un **document contractuel** — je ne l'ai pas réécrit. À reprendre en vérifiant d'abord ce que les clients existants ont effectivement signé. ### Ménage — décidé le 2026-08-07 - **`offre-commerciale.md` : ne pas supprimer.** Vérification faite, il ne contient pas qu'une grille : clients cibles, services complémentaires, forfait événementiel, frais de mise en place, projection de revenus. **Retirer les seules tables de prix** et garder le reste comme document de stratégie commerciale. - Quatre documents portaient une grille tarifaire (roadmap, solution-overview, offre-commerciale, cgu) alors que la source de vérité est `myinfomate-landing` → **supprimer les tables, garder un lien**. - ✅ **CGU §5 reprises le 2026-08-07** depuis la landing : Essentiel/Pro/Premium/Enterprise (39/99/179/devis), et un §5.1bis qui définit le quota IA **en tokens** en renvoyant au back-office pour les valeurs — plutôt que de figer un chiffre dans un contrat. - ✅ **Landing corrigée** — la clé `features.reqPerMonth` n'existe plus dans `myinfomate-landing/src` (vérifié le 2026-08-11). Ce point était encore listé comme ouvert à deux endroits de ce fichier alors que le kanban le donnait fait : c'est le kanban qui avait raison. - ⚠️ **Champs morts — partiellement traités.** `FactContent`, `IsStepLocked`, `IsHiddenInitially` sont bien supprimés (migration `RemoveDeadGuidedStepFlags`). **Restent en base** : `SectionEvent.ParcoursIds`, `SectionEvent.IconResourceId`, `SectionMap.MapResourceId` — ce dernier étant en plus mappé vers `iconResourceId` dans son DTO, ce qui ajoute une confusion de nommage. - **Champs « morts » — décision révisée le 2026-08-07 après vérification du code.** Deux des trois ne sont pas morts : - `SectionMap.MapResourceId` → **à renommer, pas à supprimer.** Il est branché de bout en bout (`SectionFactory:179/511`, `SectionMap.ToDTO:58`, `MigrationController:469`) et exposé au front sous le nom `iconResourceId` : la colonne porte l'icône de la carte, pas une « ressource carte ». Le renommer en `IconResourceId` supprime la confusion. Reste à décider si le web doit l'honorer (écart W10). - `SectionEvent.ParcoursIds` → **à investiguer avant de trancher.** Intention produit documentée (depuis un SectionEvent mis en avant, retrouver les parcours liés aux jours d'un carnaval). `GuidedPath.SectionEventId` couvre le lien au niveau *événement* ; reste à vérifier qu'il couvre aussi le niveau *jour / bloc de programme*. Ne pas supprimer tant que ce n'est pas établi. - `SectionEvent.IconResourceId` → sans usage visiteur identifié, seul candidat réel à la suppression. - **`Section.meterZoneGPS` : à implémenter, pas à retirer.** Le rayon de déclenchement a une vraie raison d'être variable — une salle de musée demande ~10 m, un parcours extérieur comme le Fort en demande 50-100. La constante en dur à 100 m est fausse dans les deux cas. --- ## 7. Documents de référence (pas des todos — pas besoin de "traiter") - [solution-overview.md](solution-overview.md) — présentation produit core - [parity-manager-visitapp.md](parity-manager-visitapp.md) — audit de parité manager-app → apps visiteur (2026-08-05) : couverture par section, 17 écarts au niveau champ, état des builds, méthode pour refaire l'audit - [guided-path-types.md](guided-path-types.md) — guide de référence SectionParcours - [section-event-map-setup.md](section-event-map-setup.md) — guide setup SectionEvent/SectionMap - [design-prompts.md](design-prompts.md) — prompts design pour Google Stitch/Claude Design - [competitor-analysis.md](competitor-analysis.md) — comparatif concurrents - [cgu-myinfomate.md](cgu-myinfomate.md) — CGU - ⚠️ [offre-commerciale.md](offre-commerciale.md) — **obsolète**, source de vérité = myinfomate-landing (voir mémoire `project_pricing_plans`) - ⚠️ [roadmap.md](roadmap.md) — contient aussi une table "Modules existants" + une table de prix en dehors de la section XR (section 5 ci-dessus) : cette table de prix est une **ancienne copie**, potentiellement désynchronisée de myinfomate-landing (source de vérité) — à vérifier avant de s'y fier - `openwakeword/` — scripts/notebook d'entraînement de modèle wake word (code, pas de la doc à jour manuellement) - `claude design/` — mockups HTML générés (MyInfoMate Parcours), à consulter visuellement, pas du texte à synchroniser --- ## Comment mettre à jour ce fichier > 🗂️ **Le kanban en est le reflet.** Source de vérité du contenu : **[kanban/](kanban/)**, versionné à côté de ce fichier — `kanban.html` en est le rendu généré. > Publié à l'adresse https://claude.ai/code/artifact/4c317904-2e23-45d3-ac14-dcca678ae5d3 > > ⚠️ **L'artifact appartient au compte propriétaire.** Lecture et republication **fonctionnent** quand la machine est connectée à ce compte (vérifié le 2026-08-11 ; la note « impossible depuis cette machine » datait d'une session où un autre compte était actif). Si l'artifact n'apparaît pas, basculer de compte. **Avant de republier : lire la version publiée et fusionner** — le fichier du repo et la version en ligne peuvent avoir divergé (constaté le 2026-08-11, une colonne entière de 10 cartes existait en ligne sans être dans le fichier). Jamais de `force:true`. D'où le découpage : > > | | Qui | Quoi | > |---|---|---| > | Contenu | n'importe quelle session | éditer `DOCS/kanban/` — **un chantier = un fichier `.md`** — puis `python3 DOCS/tools/build_kanban.py` | > | Diffusion | le compte propriétaire | republier `kanban.html` sur l'artifact | > > ⚠️ **`DOCS/kanban.html` est généré : ne pas l'éditer à la main.** Les compteurs (colonnes **et** bandeau du haut) sont calculés à partir du nombre de fichiers — il n'y a plus rien à compter ni à vérifier. Ajouter = créer un fichier dans le dossier de la colonne ; déplacer = déplacer le fichier ; clore = déplacer vers `kanban/done/`. Détail : [kanban/README.md](kanban/README.md). > > Un hook `PostToolUse` (`.claude/hooks/status-kanban-reminder.py`) rappelle ce report à chaque écriture sur ce fichier. Il rappelle, il ne publie pas — une correction de formulation ne justifie pas de toucher au tableau. Ce fichier est un index, pas une source de vérité duplicée. **Les sections lourdes vivent dans [status/](status/)** — une section par fichier ; ici ne restent que leur chapeau et le lien. Éditer le détail dans `status/`, et ne toucher au chapeau que si l'état d'ensemble change. - Nouvelle feature terminée/à faire → éditer **todo-features.md**, pas ici (sauf si ça change le résumé de la section 1) - Nouveau point sécurité traité → cocher dans **[status/securite-dette-technique.md](status/securite-dette-technique.md)** **et** noter "Déjà corrigé" dans le fichier audit correspondant - Nouveau chantier roadmap → ajouter une ligne dans la table de **[status/roadmap-canaux.md](status/roadmap-canaux.md)**, créer le plan détaillé séparément si ça dépasse quelques lignes