# Audit SEO / GEO — myinfomate-landing > Audit en lecture seule du repo `myinfomate-landing`, réalisé le 2026-09-09. > Périmètre : code source uniquement. Aucun test réseau sur `https://myinfomate.be` n'a été fait — > tout ce qui n'est pas dérivable du code est marqué **non vérifiable depuis le code**. --- ## 0. Suivi d'avancement > Mis à jour le 2026-09-10. Les numéros renvoient au plan d'action du §6. | # | Action | État | |---|---|---| | 1 | Hiérarchie `h2`/`h3` | ✅ 2026-09-10 — libellé décoratif en `

`, titre de section en `h2`, cartes en `h3` (home + segments) | | 2 | Schema `Organization` | ✅ 2026-09-10 — adresse, `vatID`, `taxID`, `areaServed`, `sameAs` LinkedIn Unov ; `url` passé à `https://unov.be` | | 3 | 9 panneaux `ModulesSection` dans le DOM | ✅ 2026-09-10 — vérifié dans le HTML servi | | 4 | Offres Essentiel/Pro/Premium + `AggregateOffer` | ✅ 2026-09-10 — `src/data/structured-data.ts`, HTVA (`valueAddedTaxIncluded: false`) | | 5 | Liens morts `href="#"` | ✅ 2026-09-10 — logo et ACCUEIL → `/{lang}`, globe du footer → unov.be (home **et** segments, le 2ᵉ n'était pas relevé par l'audit) | | M4 | TVA écrite dans les mentions légales | ✅ 2026-09-10 | | M7 | Profils sociaux | ✅ 2026-09-10 — vitrine LinkedIn MyInfoMate créée, dans `sameAs` du `SoftwareApplication` ; fiche produit LinkedIn soumise pour évaluation | | 6 | `llms.txt` FR + prix + `robots.txt` | ✅ 2026-09-10 — `llms.txt` en français (vocabulaire acheteur, grille complète, TVA), anglais déplacé dans `llms-en.txt`, les deux cités dans `robots.txt` | | 7 | Prérendu statique | ✅ 2026-09-10 — `` dans `[lang]/layout.tsx` (layout racine par langue), pages légales dans le groupe `(legal)` avec leur propre layout, plus de `headers()` ni de `x-pathname`. **58 pages prérendues**, servies en `x-nextjs-cache: HIT` | | 8 | `/{lang}/tarifs` | ✅ 2026-09-10 — grille + 7 FAQ tarifaires ×4 langues, `FAQPage` + offres ; lien « Tarifs » du menu (home et segments) pointe dessus ; grille extraite dans `components/PricingPlans.tsx` (était copiée deux fois) | | 9 | `/{lang}/assistant-ia` | ✅ 2026-09-10 — **4 langues** (736 à 846 mots), 6 FAQ + `FAQPage` par langue, `hreflang` complet, liée depuis la section IA de la home et dans le sitemap. Section « Ce qu'il ne fait pas » assumée : dire les limites plutôt que survendre l'IA | | — | Liens légaux du footer | ✅ 2026-09-10 — passés en `` (home, segments, signup) : **le lint du repo est à 0 erreur**, il en comptait 15 | | — | Page CGU | ✅ 2026-09-10 — `/conditions-generales` publiée (~4 000 mots) : la case de consentement de `/signup` faisait accepter des CGU **introuvables**. Liée depuis les pieds de page et le sitemap. ⚠️ validation juridique toujours due | | M4 | Frais de mise en place | ✅ 2026-09-10 — **décision de Thomas : pas de montant affiché.** À la place, dans les 4 langues : « frais de mise en place **uniques, chiffrés dans le devis** », et la FAQ de `/tarifs` dit ce qu'ils couvrent et qu'ils précèdent la signature (voir carte kanban 180) | | 12 | Vocabulaire acheteur dans les 6 segments | 🟠 2026-09-10 — **français fait**. Nouvelles FAQ par segment : RGPD (les 6), marchés publics (5 — pas hôtels, secteur privé), accessibilité/Access-i (3). « Médiation numérique », « parcours de visite » et « cartel numérique » injectés dans les intros. **NL/EN/DE pas encore traduits** : les FAQ françaises sont plus fournies que les autres langues | | 14 | Page marchés publics | 🟠 partiellement couvert par la FAQ des segments ; page dédiée toujours à faire | | 10 | FAQ sur la homepage | ✅ 2026-09-10 — 8 questions ×4 langues + `FAQPage` (produit, prix, canaux, hors ligne, marque blanche, délai, hébergement des données). C'était la page qu'un LLM atteint en premier, et elle n'avait aucune FAQ | | 13 | `BreadcrumbList` | ✅ 2026-09-10 — sur segments, cas clients (liste et détail), tarifs et assistant IA ; helper `breadcrumbSchema()` dans `structured-data.ts` | | 21 | Dates du sitemap | ✅ 2026-09-10 — `lastModified: new Date()` (date du build sur les 55 URLs) remplacé par des dates réelles par famille de pages, constante `LAST_MODIFIED` en tête de `sitemap.ts` **à mettre à jour avec le contenu** | | 12 bis | Traduction des FAQ segments | ✅ 2026-09-10 — **42 items** ajoutés en EN/NL/DE. Parité atteinte : 10 / 10 / 8 / 7 / 8 / 9 FAQ par segment dans les 4 langues | | 16 | Images | ✅ 2026-09-10 — recompressées (palette PNG, `effort: 10`) : `app-screenshot-1` 731 → **232 Ko**, `app-screenshot-2` 547 → **185 Ko**, `myinfomate-logo` 240 → **57 Ko**. Qualité vérifiée à l'œil. `map_generated` déjà optimale. **1,1 Mo économisé.** `sharp` a servi en installation temporaire, il n'est **pas** ajouté aux dépendances | | — | `google-maps-route.png` (699 Ko) | ⚠️ **référencé nulle part dans `src/`** — supprimable, mais je n'y touche pas sans ton accord | | — | Captures d'écran de l'app | ✅ 2026-09-10 — remplacées par les **vraies captures de la V3** fournies par Thomas (app du Fort de Saint-Héribert) : accueil sombre en grille bento et fiche article dans les deux téléphones du hero, liste des sections dans le mockup « white label », où un cadre vide affichait une icône de palette. Anciennes captures `.png` supprimées, nouvelles en JPEG (129 / 121 / 107 Ko). **Textes alternatifs réécrits et localisés** dans les 4 langues — ils étaient en anglais et décrivaient l'ancienne interface | | 14 | `/{lang}/marches-publics` | ✅ 2026-09-10 — 4 langues, 5 FAQ. Argument central : **Visit Namur, attribué sur cahier des charges publié**. Dit franchement l'absence de certification Access-i et d'audit, et renvoie au service marchés pour les seuils plutôt que de citer un chiffre non vérifié | | 17 | `/{lang}/borne-kiosk` et `/{lang}/visite-hors-ligne` | ✅ 2026-09-10 — 4 langues, 4 FAQ chacune, adossées à Visit Namur et au Fort de Saint-Héribert. Gabarit partagé `components/ContentPage.tsx` | | — | Optimisation d'images en prod | ✅ 2026-09-10 — **`sharp` ajouté aux dépendances, après mesure** : sans lui, `/_next/image` renvoyait le JPEG source (64 Ko) ; avec lui, du **WebP de 26 Ko**. ⚠️ à confirmer au premier build Docker (binaires `linuxmusl`) | | — | Maillage interne vers les 5 pages produit | ✅ 2026-09-10 — colonne « Solutions » dans le pied de page de la **home et des pages segment** (3 colonnes vides récupérées), plus des liens **dans le contenu**, qui valent davantage : carte « Mode Kiosk » → `/borne-kiosk`, point « Contenu hors ligne » → `/visite-hors-ligne`, bandeau acheteur public sous la grille de `/tarifs` → `/marches-publics`. Compté sur les pages servies : chaque page produit reçoit 1 à 3 liens par page. **Sitemap : 67 URLs** | | 15 | Pages légales en 4 langues | ✅ 2026-09-10 — mentions légales et confidentialité **traduites**, CGU laissées en français avec un **avis traduit** (« la version française fait foi ») et le corps marqué `lang="fr"` : traduire un contrat qu'un juriste va corriger, c'est du travail à refaire. Les 3 pages vivent sous `/{lang}/…`, les anciennes URLs redirigent vers la langue du visiteur | | 18 | Pages comparatives | ✅ 2026-09-10 — `/fr/comparatif/myinfomate-vs-smartify` et `…-vs-stqry`, **prix relevés à la source le 10/09** (Smartify : 1 800 / 3 500 / 9 500 £ par an ; STQRY : 199 $/mois, +100 $ Pro, 2 000 $ de frais uniques d'app native), sources liées et datées. Chaque page dit **ce que le concurrent fait mieux**. ⚠️ Guideius et izi.TRAVEL écartés : le premier ne publie aucun prix, le second a un modèle gratuit non comparable | | 20 | Blog `/fr/ressources` | ✅ 2026-09-10 — index + 2 articles (audioguide vs application, borne vs BYOD), schema `BlogPosting`. **Français seulement** ; les autres langues répondent 404, c'est volontaire | | 11 | Témoignages clients | ⏸️ **écarté le 2026-09-10 par Thomas** — il ne souhaite pas solliciter les clients pour l'instant, même satisfaits. Le type `CasClient` reste sans champ témoignage : à rouvrir le jour où un client en propose un spontanément | | 19 | Pages XR | ⬜ **deux pages à prévoir, pas une** : `/lunettes-connectees` et `/casque-vr`. À écrire quand chaque module sera démontrable — cf. `DOCS/v2/vr-quest-unity-plan.md` et `DOCS/rayban-meta-integration.md` | Tout est **stagé, pas encore committé** au 2026-09-10 (en attente de validation). Point connu : une URL inexistante (`/fr/xyz`) répond bien **404 + `noindex`**, mais son HTML initial est le shell d'erreur de Next ; la page 404 (`[lang]/not-found.tsx`) s'affiche après hydratation. Effet de l'absence de layout racine commun ; le corriger demanderait `experimental.globalNotFound`. Sans impact SEO. Posts LinkedIn de lancement : `DOCS/linkedin-posts-lancement.md`. --- ## 1. Verdict en 5 lignes 1. **Oui, partiellement citable.** Le contenu textuel principal est rendu côté serveur (composants serveur + client components pré-rendus par Next), les prix sont en texte brut, `llms.txt` existe et est bon, et aucun crawler IA n'est bloqué. Un LLM interrogé sur « audioguide pour musée en Belgique » a de la matière. 2. **Mais le site n'est trouvable que sur des requêtes produit, pas sur les requêtes d'acheteur.** Les 6 pages segment sont bien construites (~1 130 mots FR + 6 FAQ chacune), mais il n'existe **aucune** page `/tarifs`, `/assistant-ia`, `/borne-kiosk`, `/visite-offline`, ni page lunettes connectées : le différenciateur IA n'a pas d'URL propre. 3. **Le vocabulaire de l'acheteur public belge est absent** : zéro occurrence de « médiation numérique », « scénographie », « cartel numérique », « accessibilité », « Access-i », « marché public », « RGPD » dans les ~5 700 lignes de contenu de `src/data/`. 4. **Deux fuites de contenu réelles** : 8 des 9 descriptions de modules de la homepage ne sont pas dans le HTML (`ModulesSection.tsx:135`), et aucune page n'est pré-rendue statiquement (`layout.tsx:36` force le SSR sur tout l'arbre). 5. **Les preuves clients sont là mais désincarnées** : 3 cas clients datés et nommés, mais aucun logo, aucun témoignage attribué, aucun lien sortant vers un site client ou une fiche store — c'est ce qui manque le plus à un dossier de marché public. --- ## 2. Inventaire factuel ### Framework et mode de rendu | Élément | Valeur | Source | |---|---|---| | Framework | Next.js **16.1.6**, React 19.2.3, App Router | `package.json:12-13` | | CSS | Tailwind v4 (`@tailwindcss/postcss`) | `package.json:22` | | Build | `output: "standalone"`, React Compiler activé | `next.config.ts:5-6` | | Déploiement | Docker `node:22-alpine`, `node server.js` derrière Traefik | `Dockerfile:8-18`, `README.md` | | Routing i18n | Middleware Next 16 (`src/proxy.ts`) → redirect vers `/{locale}` selon `Accept-Language` | `src/proxy.ts:28-32` | | Locales | `fr`, `en`, `nl`, `de` — `fr` par défaut, html lang `fr-BE` / `nl-BE` | `src/i18n.ts:1-17` | | **Mode de rendu effectif** | **SSR dynamique sur 100 % des pages de contenu — 0 page prérendue** | voir ci-dessous | **Le contenu texte est bien dans le HTML servi** — ce n'est pas une SPA client-only, donc le point critique redouté n'est pas présent. Deux composants seulement sont des client components porteurs de contenu (`SegmentPageClient.tsx:1`, `ModulesSection.tsx:1`) ; Next les rend quand même dans le HTML initial, donc leur texte est extractible **à l'exception de ce qui est conditionné par un `useState`** (voir bloquant B2). **En revanche, la génération statique ne fonctionne pas.** Le `prerender-manifest.json` du dernier build présent dans `.next/` (daté du 13/08) ne contient que trois routes prérendues : ``` PRERENDERED: ['/_global-error', '/icon.png', '/sitemap.xml'] DYNAMIC: [] ``` Cause : `src/app/layout.tsx:36-37` appelle `await headers()` pour lire `x-pathname`. Cet accès aux headers de requête opte **tout l'arbre de routes** hors du rendu statique. Résultat : les `generateStaticParams()` déclarés dans `[lang]/page.tsx:27`, `[lang]/[segment]/page.tsx:9` et `[lang]/signup/page.tsx:25` ne produisent aucun HTML statique — chaque visite, y compris chaque crawl, déclenche un rendu React complet. ### Routes trouvées | Route | Fichier | Titre (FR) | H1 | Contenu | |---|---|---|---|---| | `/{lang}` | `src/app/[lang]/page.tsx` | *MyInfoMate — Application guide visiteur pour musées & lieux* | `MyInfoMate - La solution facile pour créer, gérer et diffuser du contenu interactif` (`HomeClient.tsx:29-31`) | ~1 990 mots FR | | `/{lang}/musees` | `[segment]/page.tsx` | *Application Guide de Visite pour Musées \| MyInfoMate* | `Votre musée mérite une application à la hauteur de vos collections` | ~1 134 mots FR, 6 FAQ | | `/{lang}/offices-tourisme` | idem | même structure, meta propre | H1 hero segment | ~1 100 mots, 6 FAQ | | `/{lang}/parcs-naturels` | idem | | | ~1 100 mots, 6 FAQ | | `/{lang}/hotels-loisirs` | idem | | | ~1 100 mots, 6 FAQ | | `/{lang}/evenements` | idem | | | ~1 100 mots, 6 FAQ | | `/{lang}/education-culture` | idem | | | ~1 100 mots, 6 FAQ | | `/{lang}/cas-clients` | `cas-clients/page.tsx` | listing | oui | court | | `/{lang}/cas-clients/musee-de-la-fraise` | `cas-clients/[slug]/page.tsx` | *Musée de la Fraise — Premier client MyInfoMate \| Kiosk & App Mobile* | `De la vitrine au numérique : la naissance de MyInfoMate` (`:101`) | ~400 mots | | `/{lang}/cas-clients/fort-de-saint-heribert` | idem | | | ~400 mots | | `/{lang}/cas-clients/visit-namur` | idem | | | ~400 mots | | `/{lang}/signup` | `signup/page.tsx` | *Créer mon compte — Plan Essentiel* | — | **`robots: {index:false}`** (`:41`) — correct | | `/mentions-legales` | `app/mentions-legales/page.tsx` | *Mentions légales* | `Mentions légales` (`:18`) | FR uniquement, hors `[lang]` | | `/confidentialite` | `app/confidentialite/page.tsx` | *Politique de confidentialité* | `Politique de confidentialité` (`:18`) | FR uniquement, hors `[lang]` | **Total indexable : 11 URLs × 4 langues + 2 pages légales = 46 URLs.** Cohérent avec `src/app/sitemap.ts`, qui génère exactement ces entrées avec `alternates.languages` par entrée (`sitemap.ts:8-15`). ### Fondations techniques — état | Point | État | Détail | |---|---|---| | `robots.txt` | ✅ présent | `public/robots.txt` — `User-agent: *` / `Allow: /` / `Disallow: /api/` | | Blocage crawlers IA | ✅ **aucun bloqué** | GPTBot, ClaudeBot, anthropic-ai, PerplexityBot, Google-Extended, CCBot, Bingbot sont **tous autorisés** par le `User-agent: *`. Aucune règle nominative, ni Allow ni Disallow (`robots.txt:1-3`) | | `sitemap.xml` | ✅ généré + référencé | `src/app/sitemap.ts`, référencé `robots.txt:5` | | `llms.txt` | ✅ présent et de bonne qualité | `public/llms.txt`, 85 lignes — produit, features, modes de déploiement, assistant IA, clients, pricing, société | | Canonical | ✅ sur toutes les pages | `[lang]/page.tsx:60`, `[segment]/page.tsx:48`, `cas-clients/[slug]`, légales `:7` | | hreflang | ✅ complet + `x-default` | `layout.tsx:68-71`, `[lang]/page.tsx:59-62`, et aussi dans `sitemap.ts:13` | | Open Graph | ✅ | `layout.tsx:53-62` + per-page ; **OG image dynamique** `[lang]/opengraph-image.tsx` (edge runtime, 1200×630, locale-aware) et variante par segment | | Twitter Card | ✅ `summary_large_image` | `layout.tsx:63-67` | | Données structurées | ✅ **JSON-LD** (pas microdata) | Organization + WebSite + SoftwareApplication (home) ; FAQPage + SoftwareApplication (segments) ; Article (cas clients) | | BreadcrumbList | ❌ absent | aucune occurrence dans le repo | | Images | ⚠️ | `next/image` partout (donc WebP/AVIF à la volée), `priority` sur le hero (`HomeClient.tsx:53`), `alt` renseignés. Mais les sources sont des PNG lourds : `app-screenshot-1.png` 748 Ko, `google-maps-route.png` 715 Ko, `app-screenshot-2.png` 560 Ko, `myinfomate-logo.png` 246 Ko | | Temps de chargement réel | **non vérifiable depuis le code** — le Lighthouse est d'ailleurs encore coché « à faire » dans `TODO-SEO.md:39` | --- ## 3. Bloquants critiques ### B1 — Aucune page n'est prérendue : tout est SSR à chaque requête **Fichier : `src/app/layout.tsx:36-37`** ```ts const h = await headers(); const pathname = h.get("x-pathname") ?? "/"; ``` Cet appel dans le layout racine force le rendu dynamique de l'intégralité de l'application. `prerender-manifest.json` le confirme : trois routes prérendues, aucune page de contenu. Les `generateStaticParams()` déclarés dans trois fichiers sont inertes. *Conséquence* : pas de blocage d'indexation (le HTML est bien complet dans la réponse), mais un TTFB dépendant du serveur à chaque crawl, et la perte de toute mise en cache statique/CDN. Sur un VPS unique derrière Traefik (`README.md`), c'est le premier facteur de lenteur. *Correctif* : le layout racine n'a besoin de la locale que pour `` et des métadonnées de repli — or elle est déjà disponible via le segment `[lang]`. Déplacer `resolveLocale()` + `generateMetadata` vers un `src/app/[lang]/layout.tsx` (à créer) recevant `params.lang`, et laisser le layout racine muet. `[lang]/page.tsx:31` et `[segment]/page.tsx:16` définissent déjà leurs métadonnées complètes, donc le layout racine est en grande partie redondant. ### B2 — 8 des 9 descriptions de modules de la homepage sont absentes du HTML **Fichier : `src/components/ModulesSection.tsx:20, 73, 125, 135`** ```tsx const [activeModule, setActiveModule] = useState(0); ...

{modules[activeModule].title}

{modules[activeModule].description}

``` Seul le module d'index 0 (Carte interactive) voit sa `description` et sa `value` rendues. Les huit autres — Quiz/jeux, Vidéo, Article, Agenda, **Offline**, Web, Statistiques, **Escape game** — n'existent dans le HTML que sous forme de libellé de bouton (`ModulesSection.tsx:59`). Or « mode offline » et « escape game » sont deux des arguments les plus différenciants : ils figurent dans `llms.txt:26,29` mais pas dans le HTML de la homepage. *Correctif* : rendre les neuf panneaux et masquer les inactifs en CSS (`hidden` / `aria-hidden`), exactement comme le fait déjà correctement la FAQ des pages segment (`SegmentPageClient.tsx:652` — collapse par `max-h-0`, contenu toujours présent dans le DOM). ### B3 — Aucun schema `Offer` pour les plans Pro / Premium / Enterprise **Fichiers : `src/app/[lang]/page.tsx:100-110` et `[segment]/page.tsx:84-94`** Le `SoftwareApplication` ne déclare qu'une seule offre, à 39 €. Les prix 99 € et 179 € sont bien en texte brut dans le HTML (`SegmentPageClient.tsx:460` et suivantes) — donc lisibles par un LLM — mais invisibles pour Google Rich Results et pour tout agent qui s'appuie sur les données structurées. À la question « combien coûte MyInfoMate pour avoir l'assistant IA ? », un LLM devra deviner. *Correctif* : remplacer `offers` par un tableau de trois à quatre `Offer` (`name: "Essentiel" / "Pro" / "Premium"`, `price`, `priceCurrency: "EUR"`, périodicité), plus un `AggregateOffer` avec `lowPrice: 39` / `highPrice: 179`. --- ## 4. Manques importants (existe mais mal fait) ### M1 — Hiérarchie de titres inversée sur toutes les pages Le label décoratif en petites capitales est un `

`, et le vrai titre de section un `

`. Vérifiable partout : - `HomeClient.tsx:78-79` — `

{t.strategic.sectionLabel}

` puis `

{t.strategic.sectionTitle}

` - `HomeClient.tsx:126-127`, `:181-182`, `:301-302`, `:421-422`, `:474-475` - `SegmentPageClient.tsx:310-311`, `:333-334`, `:363-364`, `:398-399`, `:636-637` - `ModulesSection.tsx:34-35` Un extracteur de plan de page lit donc « LE DÉFI DES MUSÉES » comme titre de niveau 2 et « Ce que vivent la plupart des musées » comme sous-titre : l'inverse exact. Correctif purement cosmétique — inverser les balises, garder les classes. ### M2 — Le schema `Organization` n'ancre pas l'entreprise en Belgique **`src/app/[lang]/page.tsx:70-81`** ne contient que `name`, `url`, `logo`, `contactPoint`. Manquent `address` (PostalAddress : Rue René Copette 3, 5020 Namur, BE), `areaServed` (BE / FR / LU), `vatID` ou `taxID` (BCE 0776.895.467), et `sameAs` (aucun profil externe déclaré). Toutes ces données existent pourtant en clair dans `mentions-legales/page.tsx:24-28`. C'est le signal le plus direct qu'un LLM utilise pour répondre à « une solution **belge** ». ### M3 — Les mentions légales sont hors du système i18n `src/app/mentions-legales/page.tsx` et `src/app/confidentialite/page.tsx` vivent hors de `[lang]`, sont explicitement exclues du middleware (`proxy.ts:5`), n'existent qu'en français et n'ont pas de `hreflang`. Un acheteur néerlandophone ou luxembourgeois qui vérifie la conformité de l'éditeur tombe sur du français. Le sitemap ne les référence qu'en une seule version (`sitemap.ts:66-77`). ### M4 — TVA jamais écrite, RGPD jamais mis en avant côté commercial `mentions-legales/page.tsx:25` donne « Numéro d'entreprise BCE : 0776.895.467 » mais jamais le format TVA `BE 0776.895.467` — c'est pourtant la chaîne que cherche le service comptable d'une commune. Par ailleurs « RGPD » n'apparaît **que** dans `confidentialite/page.tsx` : `grep -ric "RGPD" src/data/*.ts` retourne 0. Le seul argument d'hébergement européen est une ligne de la page signup (`translations.ts:207`, « Hébergé en Europe ») — sur une page en `noindex`. ### M5 — Cas clients : aucune preuve vérifiable de l'extérieur `src/data/cas-clients.ts` donne pour chaque client `client`, `year`, `location` (`:49-52`, `:223-225`, `:397-399`), mais l'interface `CasClient` (`:36-42`) ne prévoit **ni URL du site client, ni lien vers une fiche store, ni témoignage, ni logo**. - Aucun témoignage nommé : zéro occurrence de `quote` / `testimonial` / `author` dans le fichier. - Aucun logo client : `public/` ne contient que le logo MyInfoMate et quatre screenshots génériques. - Aucun lien sortant : pas un seul `href="http"` dans `cas-clients/[slug]/page.tsx`. - Les « résultats » sont qualitatifs — `{value:'2021', label:'Premier déploiement'}`, `{value:'100%', label:'Autonomie éditoriale'}` (`cas-clients.ts:97-100`) : aucun chiffre de fréquentation, de nombre de POI, de langues ou de sessions. - Le schema `Article` (`cas-clients/[slug]/page.tsx:56-65`) n'a ni `image`, ni `dateModified`, ni `about`/`mentions` pointant vers le lieu. Les chiffres concrets présents ailleurs restent maigres : `llms.txt:64-68` mentionne iBeacon, offline 100 %, iOS + Android — c'est le contenu le plus factuel du site, et il n'est pas dans le HTML. ### M6 — Aucune date de mise à jour visible `sitemap.ts:18` fixe `lastModified: new Date()`, c'est-à-dire la date du build, appliquée uniformément à toutes les URLs : ce n'est pas un signal de fraîcheur, c'est du bruit. Aucune page n'affiche de date dans son HTML ; les cas clients affichent l'année du projet (`cas-clients/[slug]/page.tsx:99`), pas la date de rédaction. ### M7 — Deux liens morts et aucun profil social - `HomeClient.tsx:766` : `` avec une icône « public » dans le footer — bouton social qui ne pointe nulle part. - `NavBar.tsx:59` et `:149` : logo et « ACCUEIL » en `href="#"` (scroll JS) au lieu de `href={/${lang}}`. Un crawler n'a pas de lien de retour vers la home depuis le header. - Aucun `sameAs` LinkedIn — la création de la page LinkedIn Unov est d'ailleurs encore ouverte dans `TODO-SEO.md:40`. ### M8 — Images sources non optimisées 748 Ko, 715 Ko et 560 Ko en PNG pour des screenshots d'app. `next/image` réencode, mais l'optimiseur travaille sur ces sources à chaque cache miss. `myinfomate-logo.png` (246 Ko) sert à la fois de favicon (`layout.tsx:52`), d'image OG de repli (`layout.tsx:61`) et d'image 32 px dans le footer (`HomeClient.tsx:755-760`). Le paquet `sharp` n'est pas dans `package.json` ; le comportement réel de l'optimiseur dans le conteneur `node:22-alpine` est **non vérifiable depuis le code**. --- ## 5. Opportunités (n'existe pas et devrait exister) ### O1 — Pages par intention manquantes Aucune de ces routes n'existe dans `src/app/` : | URL attendue | État | Commentaire | |---|---|---| | `/tarifs` | ❌ | Les prix ne vivent que dans des sections `#pricing` de la home et des six pages segment. Une requête « prix audioguide musée » n'a aucune page à faire remonter. Le contenu existe déjà (`SegmentPageClient.tsx:395-628`) — il suffit de l'extraire dans une route. | | `/assistant-ia` | ❌ | **Le différenciateur n'a pas de page.** Il est une section de la home (`HomeClient.tsx:170-260`) et un paragraphe de `llms.txt:42-49`. Face à Guideius ou izi.TRAVEL, c'est l'argument qui n'existe nulle part ailleurs — et il n'est pas adressable. | | `/borne-kiosk` | ❌ | Le kiosk n'est qu'un mode de déploiement dans `#deployment-modes` (`translations.ts:53`) ; le cas Visit Namur porte entièrement dessus. Mérite une page. | | `/visite-offline-sans-reseau` | ❌ | Le mode offline est un module (`ModulesSection.tsx:12`) dont la description **n'est même pas dans le HTML** (bloquant B2). Le cas Fort de Saint-Héribert est un argument offline parfait (iBeacon, aucune couverture réseau). | | `/musee-plein-air` | ❌ | Partiellement couvert par `/parcs-naturels`. | | `/lunettes-connectees` | ❌ | Une seule occurrence dans tout le contenu : `translations.ts:60`, « Meta Quest et lunettes connectées », dans un bloc « à venir ». Pas de page, pas de schema. | | `/application-office-de-tourisme` | ✅ équivalent | `/{lang}/offices-tourisme` existe et est complet. | ### O2 — Vocabulaire de l'acheteur culturel : absent `grep -ric` sur `src/data/translations.ts`, `segments.ts`, `cas-clients.ts` : | Terme | Occurrences | |---|---| | « médiation numérique » | **0** | | « scénographie » | **0** | | « cartel numérique » | **0** | | « accessibilité » | **0** | | « Access-i » | **0** | | « marché public » | **0** | | « RGPD » | **0** (hors page confidentialité) | | « réalité augmentée » | **0** | | « BYOD » | 8 (bon) | | « audioguide » / « audio guide » | 24 / 30 (bon) | | « Namur » | 34 (bon, surtout via les cas clients) | | « Wallonie » | 2 | | « Belgique » | 3 (uniquement dans `cas-clients.ts`) | Le site parle la langue du produit, pas celle du conservateur ni celle du service marchés publics. « Médiation numérique » est le terme employé par les appels à projets de la Fédération Wallonie-Bruxelles : ne pas l'avoir écrit une seule fois est une occasion manquée gratuite. ### O3 — Aucune page marchés publics Rien dans le repo sur les seuils, la procédure de marché de faible montant, la capacité à répondre à un cahier des charges, ni de document type. C'est pourtant l'objection numéro un d'une commune ou d'une province. ### O4 — Aucune page comparative `src/app/` ne contient aucune route `comparatif`. Le comparatif existe **à l'intérieur** des pages segment (`Segment.comparison`, `segments.ts:23-26`) mais compare des catégories abstraites (« App visiteur générique », « Fiches pédagogiques papier »). Les seuls concurrents nommés le sont dans les meta descriptions (« Alternative à Smartify », `segments.ts:81`) et dans un pain point (`segments.ts:~120` : « Smartify, SmartGuide ou STQRY coûtent entre €100 et €925/mois »). **Aucune mention de Guideius, izi.TRAVEL, MySmartJourney, Musa Guide, Cirkwi ou Apptree** dans tout le repo — alors que ce sont les noms réellement tapés par un acheteur belge ou français. Ce n'est pas une erreur, c'est le levier GEO le plus rentable qui reste : les pages « alternative à X » sont exactement ce qu'un LLM ingère pour répondre à une question de comparaison. `TODO-SEO.md:56-59` les liste déjà comme à faire. ### O5 — Aucun blog `src/app/` ne contient aucune route `blog`, `ressources` ou `articles`. `TODO-SEO.md:49-54` a déjà les cinq sujets d'articles identifiés ; aucun n'est écrit. Le seul contenu éditorial du site est du contenu produit — pas un texte ne répond à une question que se pose un responsable de musée avant d'avoir entendu parler de MyInfoMate. ### O6 — `llms.txt` : bon fichier, trois angles morts `public/llms.txt` est de bonne facture (85 lignes, structuré, avec liens vers les trois cas clients). Ses faiblesses : - **Il est uniquement en anglais** (`llms.txt:3`) alors que le marché cible est francophone. Un LLM interrogé en français citera plus volontiers une source française. - **Il n'est pas référencé dans `robots.txt`**, ni lié depuis le HTML. - Les prix y sont incomplets (`llms.txt:74`, « Starting from €39/month ») alors que la grille 39 / 99 / 179 est publique sur le site. ### O7 — Pas de FAQ sur la homepage Les six pages segment ont chacune six questions et un `FAQPage` JSON-LD (`[segment]/page.tsx:65-76`) — c'est très bien fait. La homepage n'a **aucune** FAQ ni `FAQPage`. C'est pourtant la page qu'un LLM atteint en premier. --- ## 6. Plan d'action priorisé Trié par ratio impact / effort. **T** = correctif technique, **C** = écriture de contenu. | # | Action | Type | Impact | Effort | |---|---|---|---|---| | 1 | Inverser `h2`/`h3` sur les 12 sections concernées (`HomeClient.tsx:78,126,181,301,421,474` ; `SegmentPageClient.tsx:310,333,363,398,636` ; `ModulesSection.tsx:34`) | T | Moyen | **0,5 h** | | 2 | Enrichir le schema `Organization` : `address`, `areaServed: ["BE","FR","LU"]`, `vatID: "BE0776895467"`, `sameAs` (`[lang]/page.tsx:70-81`) | T | **Fort** | **0,5 h** | | 3 | Rendre les 9 panneaux de `ModulesSection` dans le DOM, masquer en CSS au lieu de `modules[activeModule]` (`ModulesSection.tsx:73,125`) — récupère « offline » et « escape game » dans le HTML | T | **Fort** | **1 h** | | 4 | Passer `SoftwareApplication.offers` à un tableau de 3 `Offer` + `AggregateOffer` 39–179 € (`[lang]/page.tsx:100`, `[segment]/page.tsx:84`) | T | **Fort** | **1 h** | | 5 | Corriger les liens morts : footer `href="#"` (`HomeClient.tsx:766`), logo et ACCUEIL de la NavBar (`NavBar.tsx:59,149`) → `/{lang}` | T | Moyen | **0,5 h** | | 6 | Traduire `llms.txt` en français (ou publier FR + `llms-en.txt`), y ajouter la grille 39/99/179 et le référencer depuis `robots.txt` | C | **Fort** | **1,5 h** | | 7 | Déplacer `resolveLocale()`/`generateMetadata` de `layout.tsx:36` vers un `[lang]/layout.tsx` → réactive le prérendu statique des 46 URLs | T | **Fort** | **2–3 h** | | 8 | Créer `/{lang}/tarifs` en réutilisant la section pricing existante + une FAQ tarifaire | T+C | **Fort** | **3 h** | | 9 | Créer `/{lang}/assistant-ia` — le différenciateur mérite son URL, avec FAQ et schema | C | **Fort** | **4 h** | | 10 | Ajouter un `FAQPage` de 6–8 questions en bas de homepage (réutiliser le format de `segments.ts`) | C | Moyen | **3 h** | | 11 | Ajouter au type `CasClient` : `clientUrl`, `storeUrls`, `testimonial {quote, name, role}` — et les remplir après accord des 3 clients | T+C | **Fort** | **4 h** + relance clients | | 12 | Injecter le vocabulaire acheteur (« médiation numérique », « accessibilité », « scénographie », « parcours de visite », « RGPD », « hébergement européen ») dans `translations.ts` et les 6 segments FR | C | **Fort** | **4–6 h** | | 13 | Ajouter `BreadcrumbList` sur les pages segment et cas clients | T | Faible | **1 h** | | 14 | Créer `/{lang}/marches-publics` : seuils, marché de faible montant, capacité à répondre, coordonnées BCE/TVA | C | **Fort** (public belge) | **4 h** | | 15 | Traduire `/mentions-legales` et `/confidentialite` en 4 langues et les faire passer sous `[lang]` (ajuster `proxy.ts:5`) | T+C | Moyen | **3 h** | | 16 | Recompresser les 4 PNG de `public/` (748 / 715 / 560 / 246 Ko → cible < 150 Ko) et produire un logo 32 px distinct du logo OG | T | Moyen | **1 h** | | 17 | Créer `/{lang}/borne-kiosk` et `/{lang}/visite-offline-sans-reseau`, adossées aux cas Visit Namur et Fort de Saint-Héribert | C | Moyen | **6 h** | | 18 | Trois pages comparatives : `myinfomate-vs-izi-travel`, `myinfomate-vs-guideius`, `myinfomate-vs-smartify` — factuelles, sourcées, sans dénigrement | C | **Fort** (GEO) | **8 h** | | 19 | Créer `/{lang}/lunettes-connectees` (à faire quand le module sera démontrable — cf. `DOCS/rayban-meta-integration.md`) | C | Faible aujourd'hui | **4 h** | | 20 | Ouvrir un blog `/{lang}/ressources` avec les 5 articles déjà listés dans `TODO-SEO.md:49-54` | C | **Fort** à 6 mois | **20 h+** | | 21 | Remplacer `lastModified: new Date()` par une date réelle par contenu (`sitemap.ts:18`) et afficher une date de mise à jour sur les cas clients | T | Faible | **2 h** | **Séquence recommandée.** Les items 1 à 6 tiennent en une demi-journée et corrigent l'essentiel des pertes gratuites. L'item 7 est le seul chantier technique de fond. Les items 8, 9, 12 et 14 sont ceux qui changent réellement la réponse d'un LLM à « quelle solution d'audioguide pour mon musée en Belgique ? ». --- ## Annexe — ce qui est déjà bien fait À ne pas casser : - Le contenu textuel est intégralement dans le HTML servi — ce n'est pas une SPA client-only. - Aucun crawler IA n'est bloqué (`robots.txt:1-2`). - `llms.txt` existe et est structuré — la majorité des concurrents n'en ont pas. - Les six pages segment sont de vraies pages d'intention : ~1 130 mots FR, pain points, features, comparatif, six FAQ, le tout en quatre langues, avec `FAQPage` JSON-LD. - Les FAQ des pages segment sont collapsées en CSS (`max-h-0`, `SegmentPageClient.tsx:652`) et non conditionnées par un `useState` : le texte est bien dans le DOM. C'est le bon pattern — exactement ce que `ModulesSection` ne fait pas. - `hreflang` complet avec `x-default`, sur chaque page **et** dans le sitemap. - `/signup` est correctement en `noindex, follow` (`signup/page.tsx:41`). - OG image générée dynamiquement et localisée, avec une variante par segment. - Les prix (39 / 99 / 179 €) sont en texte brut dans le HTML, pas en image.