Correction intégrale de l'audit du 4 septembre — devis, quotas, base, front, build, contenu
Suite de AUDIT-2026-09-04.md (§10 pour le détail et §10.3 pour les points écartés ou laissés au propriétaire).
Nous appliquons à notre propre site les standards que nous livrons à nos clients. Chaque amélioration est consignée publiquement — une preuve vivante de notre exigence.
Suite de AUDIT-2026-09-04.md (§10 pour le détail et §10.3 pour les points écartés ou laissés au propriétaire).
Suite de AUDIT-2026-09-03.md (§11 pour le détail des corrections et des arbitrages).
À la demande du client. La mention reste sur /mentions-legales, où la LCEN l'exige.
L'aide nationale France Num n'existe plus ; ces cinq pages renvoyaient encore vers un montant faux. Textes alignés sur les dispositifs réels (Atouts Numériques, IA Booster, aides locales) et sur le paiement en trois fois sans frais.
Bug signalé : les six boutons de /tarifs et le CTA « Lancer le projet » (79 pages) menaient en haut de l'accueil, sans configurateur. Trois causes : aucune prise en charge de l'ancre en navigation interne (ScrollRestoration remontait en haut), configurateur monté seulement à l'approche de l'écran, CTA en <a href>…
ProjectWizard.tsx faisait 1 331 lignes, seul fichier du dépôt au-delà de la limite de 800. Trois modules en sortent, sans changer une ligne de rendu ni de logique : wizard-data.ts (139 lignes) : types, projets, budgets, délais, forfaits de service, aides publiques, numéro de devis ;
Sur les 150 points de la liste, 117 étaient déjà en place ; 26 sont implémentés ici, 7 écartés avec justification (AUDIT-150-2026-09-02.md).
Le formulaire de contact est prérendu : entre l'affichage du HTML et l'hydratation, un clic sur « Envoyer » déclenchait la soumission native du navigateur — rechargement de la page, saisie perdue, aucun message.
Six pages du site tenaient en quelques centaines de mots — la page des services en comptait 473, celle de la méthode 219, les pages de Villeurbanne, Bron et Vénissieux environ 200 chacune, quasi identiques.
La charte appliquée le 1er septembre (fond crème, terracotta, Poppins et Lora) est retirée : le site retrouve ses jetons de couleur, ses polices, ses ombres, son image de partage et son manifeste d'origine. Tout ce qui a été fait depuis reste en place — corrections légales, mesure d'audience, chorégraphies de la Hero et des sections, transitions de page.
Chaque mise en production remplace les fichiers hachés de /assets/, et Vercel cesse de servir ceux du déploiement précédent. Une page obtenue avant le déploiement — onglet resté ouvert, cache — réclame alors une feuille de style et un script qui n'existent plus : le site s'affiche brut, sans style ni interactivité.
Chaque clic sur un lien interne enveloppe désormais la navigation dans `document.startViewTransition` : l'ancienne page s'efface en montant légèrement, la nouvelle se pose en venant du bas, et l'en-tête comme le bandeau supérieur restent nets pendant que le contenu change dessous.
Deux composants secondaires tiraient encore la bibliothèque (41 Ko compressés, chunk proxy-*.js) sur l'accueil : le badge technologique, pour un survol à ressort, et le carrousel de témoignages, pour la sortie animée de la citation quittant l'écran.
Sur mobile, le chapô du premier écran est le plus grand bloc de texte visible dès que le titre est affiché : c'est lui que Chrome retient comme élément LCP. Le masque qui le dévoilait retardait donc sa première peinture, et la mesure en production le confirmait — 3,0 s avant la Hero animée, 3,3 à 3,4 s après.
Après la Hero, le reste de l'accueil et le pied de page reçoivent la même signature de mouvement. Tout repose sur un déclencheur unique, `Reveal` (un IntersectionObserver par groupe), et sur des classes CSS d'attente et d'entrée : les fondus génériques de framer-motion disparaissent de six sections, qui n'importent…
La Hero était statique : un fondu générique sur les chiffres, rien d'autre. Elle reçoit une chorégraphie complète, réglée depuis une seule table de délais dans Hero.tsx : le titre se révèle mot par mot depuis un masque (écrans larges) ou se pose en cascade sans jamais être caché (mobile, où le H1 est l'élément LCP —…
L'éditeur relève de la franchise en base. Le site affichait pourtant un numéro de TVA intracommunautaire en pied de page, dans les mentions légales, dans les CGV et sur le devis — et le simulateur ajoutait 20 % au total.
L'éditeur confirme que l'agrément « Entreprise solidaire d'utilité sociale » n'est plus d'actualité. Il restait affiché à neuf endroits, dont plusieurs très en vue : la promesse d'ouverture de la page Expertise, un argument de sa liste de forces, un paragraphe de présentation, un point de la page Agence Web Lyon, le…
Les mentions légales indiquent désormais la forme juridique réelle de l'éditeur — entreprise individuelle au régime de la micro-entreprise — avec les nom et prénom que la LCEN exige pour un site tenu par une personne physique. La mention de capital social, sans objet pour une entreprise individuelle, est retirée ; « Kayzen Web » y figure comme nom commercial.
La balise GA4 se déclenchait sur les environnements de prévisualisation dès qu'un consentement était enregistré, et le trafic de test se mêlait à celui des visiteurs réels. Elle ne démarre plus que sur www.kayzen-lyon.com ; les autres hôtes légitimes redirigent tous vers celui-ci, aucun visiteur n'y séjourne.
Le site pousse quatorze types d'événements dans le dataLayer : cta_click, form_step, form_submit, form_error, scroll_depth, package_select, web_vitals, js_error, les trois événements du popup de sortie, et surtout SUBMIT_LEAD_FORM, poussé par le formulaire de contact et par le devis.
La fiche Google annonçait 09:00-19:00, le site 9h-18h. L'éditeur confirme que la fiche a raison. Google recoupe ces deux sources : un écart d'une heure sur l'horaire de fermeture affaiblit la corroboration entre le site et la fiche, au même titre que l'écart d'adresse corrigé plus tôt — et il envoie surtout un…
Le sous-domaine internet.kayzen-lyon.fr reste indexé séparément de www.kayzen-lyon.com. Le dépôt donnait pourtant l'impression du contraire : vercel.json déclare bien une redirection permanente pour cet hôte.
La sonde qui vérifie que la page 404 déclare bien « noindex » capturait l'en-tête avant que la directive ne soit posée, et refusait au hasard des déploiements pourtant corrects. Elle attend désormais la balise qu'elle contrôle : le garde-fou garde tout son sens, mais ne se déclenche plus sur sa propre latence.
L'entreprise a deux adresses : un siège social (6 rue Pierre Termier, celui du Kbis) et des locaux (6 rue de Bourgogne). Le site n'affichait QUE le siège — y compris là où il annonce une adresse de visite : pied de page, carte, ligne « Localisation », JSON-LD LocalBusiness, llms.txt, repli sans JavaScript.
Le CID de la fiche a été relevé dans le panneau propriétaire : 13733496944041442777. L URL est construite dessus plutôt que sur un raccourci maps.app.goo.gl, qui peut expirer et masque l entité visée ; le CID, lui, survit à un changement de nom ou d adresse.
Un audit local externe relève qu'aucune carte Google n'est associée au site. Le constat est exact, pour deux raisons distinctes.
Quatre pages de service montraient des sites qui n'existent pas.
Palette officielle sur les 79 pages : Dark #141413, Light #faf9f5, Mid Gray #b0aea5, Light Gray #e8e6dc, et les trois accents orange, bleu et vert. Titrage en Poppins, texte courant en Lora, les deux auto-hébergées comme l'étaient Outfit et Plus Jakarta Sans — la CSP déclare font-src 'self' et aucune requête ne part…
Les 37 réalisations n'étaient que des vignettes suivies d'un lien sortant : aucune page indexable, et le visiteur quittait le site au moment précis où il était convaincu. Chacune dispose désormais de sa page /portfolio/<slug>, qui expose le raisonnement du projet — contexte, contrainte, décisions de design et de…
Le produit était promu depuis le portfolio, le bandeau d'appel et le script de capture des visuels par une adresse technique de déploiement. Il s'affiche désormais sous le domaine du groupe, comme Nexus, DocuSûr et Konforme ; l'ancienne adresse en .fr y redirige. Le repointage n'a été fait qu'une fois le domaine vérifié en ligne.
Les trois produits du groupe étaient référencés sous l'ancien domaine, dont la zone DNS avait disparu avec le changement d'hébergeur. Onze liens ne menaient donc plus nulle part : dans la signature des emails sortants, le portfolio, le fichier llms.txt, les deux bandeaux d'appel Nexus, la page Solutions métiers IA et la liste de références du devis PDF. Tous pointent désormais vers les adresses en kayzen-lyon.com, qui répondent.
Le domaine kayzen-lyon.fr portait la boutique solidaire, pas l'agence : celle-ci vivait sous internet.kayzen-lyon.fr avant de passer en kayzen-lyon.com. L'activité de reconditionnement s'arrêtant, l'agence reprend le domaine principal et toutes les traces de la boutique quittent le site.
Ces textes font 12 px (`text-xs`) : ils ne relèvent jamais du « grand texte », et WCAG 1.4.3 (niveau AA) exige donc 4,5:1. Mesuré en production, en thème clair, sur le fond quasi blanc que produit `bg-<couleur>-500/10` : React 3,91:1 · Tailwind 3,58:1 · Node.js 3,60:1 · Supabase 3,60:1
`ChatBot` était monté sur toutes les pages dès que le navigateur passait au repos (`requestIdleCallback` dans Layout). Or son module tire deux dépendances lourdes : `react-markdown` avec sa chaîne micromark/remark (121 Ko) et `framer-motion` (120 Ko) — dont il est le seul importateur.
GA4 envoie ses mesures à `region1.analytics.google.com`. La directive `connect-src` autorisait `analytics.google.com` — mais en CSP un hôte ne couvre pas ses sous-domaines : chaque hit partait puis était refusé par le navigateur.
Trois points relevés par un audit externe. Deux sont corrigés, le troisième est documenté parce qu'il n'est pas corrigeable sans casser le site.
Le site tourne désormais sur la version 19 de React. Le verrou était la brique qui écrit le titre, la description et les balises de partage de chaque page : elle n'était plus compatible et laissait des balises en double, ce qui dégrade le référencement. Elle a été remplacée par une version maintenue, à l'identique pour le reste du code. Le contrôle a porté sur le HTML réellement servi, comparé balise par balise à celui de la version précédente : 51 balises de part et d'autre, identiques. Effet de bord bienvenu, le titre de la page se met maintenant à jour lors des changements de page, ce qui n'était plus le cas.
Le site avait été démarré à partir d'un modèle fourni avec une bibliothèque complète de composants d'interface. Le site final n'en utilise que quatre : les 45 autres n'étaient appelés par aucune page. Ils ont été retirés, avec les 37 briques externes qu'ils faisaient installer. Rien ne change pour le visiteur — ce code n'était déjà pas envoyé au navigateur — mais le projet est plus simple à maintenir et à faire évoluer.
zod valide le formulaire de contact. La 4 remplace l'option `errorMap`, qui prenait une fonction renvoyant un objet, par `error`, qui prend directement la chaîne. Deux appels concernés : le schéma de src/pages/Contact.tsx et sa copie dans le test.
React 19, nouvelle version de la bibliothèque qui fait tourner l'interface, dupliquait les balises de référencement : deux titres et deux descriptions par page au lieu d'un seul, sur les 42 pages. La cause a été identifiée — la gestion des métadonnées, pas le site lui-même — et les composants qui bloquaient la mise à niveau ont été relevés. Le passage effectif a suivi, une fois le défaut traité.
Le composant qui gère les liens et les changements de page est passé à sa version majeure suivante, qui corrige deux défauts publiés par ses mainteneurs. Toutes les dépendances du site sont désormais à jour de leurs correctifs.
Les trois bibliothèques qui touchent le rendu partout : lucide-react dans 84 fichiers, framer-motion dans 44, tailwind-merge dans le helper `cn()` dont dépend chaque classe utilitaire du site.
Quatre majeures sans portée visuelle générale. web-vitals alimente la mesure des Core Web Vitals (src/lib/web-vitals.ts), sonner les notifications ; vaul et @hookform/resolvers ne servent qu'à des composants shadcn isolés.
TypeScript 7.0.2 est bien la dernière version publiée, et le dépôt la traverse sans une seule erreur de type. Elle n'est pourtant pas retenue : au premier lint, typescript-eslint s'interrompt sur « typescript-eslint does not support TS 7.0 ».
Aucun de ces paquets n'est servi au visiteur : ils ne tournent qu'au lint et aux tests. Le lot est donc traité en premier, à risque nul pour la production.
Aucune version majeure ici, donc aucune rupture attendue : les plages de `package.json` sont inchangées, seul le lockfile bouge. L'intérêt est de réduire l'écart avant d'attaquer les majeures, pour qu'un échec ultérieur désigne la majeure fautive et non un retard accumulé.
nanoid, js-yaml et dompurify sont relevés vers leurs versions corrigées dans le fichier de verrouillage, sans changement de plage dans package.json. Lint, types, tests et build inchangés.
Les scripts de vérification (`--check`) comparent leur sortie au fichier du dépôt octet par octet. Ils écrivent en LF, tandis que `core.autocrlf=true` extrait en CRLF : le contenu est identique, la comparaison échoue quand même, et `npm run build` s'arrête dès le clone sur `stack-versions.generated.ts`.
Six défauts inédits, dont un que les audits précédents ne pouvaient pas voir : ils vérifiaient le HTML servi (prérendu, donc correct), jamais le DOM après navigation interne.
La forme juridique, le capital social et le directeur de la publication étaient annoncés comme « à compléter » — le dernier figurant dans le pied de page, donc sur l'ensemble des pages du site. Les informations du registre du commerce sont désormais publiées. Un contrôle automatique bloque toute mise en production qui laisserait réapparaître une mention provisoire.
L'ossature du site (en-tête, pied de page, assistant, réglages d'accessibilité) était reconstruite à chaque changement de page : les boutons flottants disparaissaient jusqu'à trois secondes et l'historique de conversation était perdu. Elle est désormais montée une seule fois. Une bibliothèque d'animation de 131 Ko était par ailleurs chargée sur les 42 pages, y compris celles qui n'animent rien. Neuf visuels du portfolio étaient servis en 4 914 pixels de large pour un affichage à 441 : la page passe de 3,71 à 2,30 Mo. Deux images hébergées chez un tiers étaient bloquées par la politique de sécurité du site et ne s'affichaient pas en production ; elles sont rapatriées. La case « Publicité et remarketing » du bandeau cookies était enregistrée sans jamais être appliquée — les quatre signaux de consentement sont maintenant transmis.
`send-wizard-email` insère dans `public.wizard_leads` depuis avril 2026. La table n'a jamais existé : l'insertion échouait à chaque appel, et aucune demande de devis n'a été conservée. `quotes` et `contact_messages` sont à 0 ligne, la table `wizard_leads` est absente de la base — vérifié ce jour.
/changelog affichait un tableau saisi à la main, resté figé au 24/04/2026. Quarante commits plus tard — bascule de domaine, refonte, prérendu des 42 routes, durcissement CSP, deux audits — la page « Transparence radicale » annonçait encore l'état du site au lendemain de sa mise en ligne.
L'accordéon de l'accueil était le seul du site à utiliser ce motif. Les 17 FAQ de pages service passent par AccordionTrigger, donc par un chevron : un seul geste d'ouverture sur tout le site.
Revue de l'intégralité du dépôt sur la sécurité, le RGPD et l'AI Act, l'accessibilité, le SEO et la conversion. Correctifs majeurs : formulaire de contact durci, plafond journalier sur l'endpoint IA, hébergeur déclaré rendu cohérent entre mentions légales et pied de page, sous-traitants nommés dans la politique de confidentialité.
Conséquence directe du défaut de prérendu : seize pages de service se présentaient à Google sous un titre et une description identiques. Métadonnées propres à chacune rétablies.
Le serveur renvoyait le même index.html pour toutes les pages : titre, description et Open Graph n'étaient injectés qu'après exécution du JavaScript. Tout robot qui n'exécute pas JavaScript — LinkedIn, WhatsApp, Slack, Bing, les assistants IA — ne voyait que les métadonnées de l'accueil. Chaque route est désormais servie en HTML complet.
Sentinel by Kayzen — pentest autonome par agents IA, produit du groupe au même titre que Nexus et DocuSur. Météo Climat France — service météo national, maille de 247 points. BTP EA. S'y ajoutent deux propositions clients.
Montée de version de toute la chaîne de build : esbuild disparaît de l'arbre de dépendances, remplacé par rolldown et son minifieur natif oxc. L'ensemble des dépendances est à jour de ses correctifs.
La politique de sécurité des contenus n'accepte plus aucun script en ligne : chaque script est identifié par une empreinte SHA-256 — l'équivalent correct d'un nonce en hébergement statique.
Mise à jour de brace-expansion et gel de react-router en 6.30.4, dont les versions suivantes introduisaient une rupture d'API.
La table qui compte les envois par adresse se vidait lorsqu'elle débordait, ce qui relâchait la limite au moment précis où elle devait s'appliquer. L'éviction suit désormais un ordre sûr — entrées périmées, puis entrées sous le seuil — et un test de régression couvre le cas.
Applique les 150 améliorations de l'audit multi-expertise (AUDIT-150.md).
Nouveau domaine public de l'agence : 250 occurrences reprises sur 63 fichiers (canoniques, sitemap, robots.txt, llms.txt, origines CORS). L'ancien domaine .fr redirige de façon permanente. Au passage, trois dépendances mises à jour.
Mesures Lighthouse production du jour, après optimisations déployées (CLS 0,71→0, LCP 18,1→4,5 s, −4,4 Mo d'images selon les sites).
23 sites audités ce jour (mobile, 4 axes) + les 8 phares déjà mesurés. Marqueur flagship explicite pour la section « La performance, mesurée. » ; les jauges PageSpeed s'affichent désormais sur chaque fiche projet.
Une balise canonique figée dans index.html se propageait à l'ensemble des pages de l'application : chacune se déclarait à Google comme étant l'accueil. Supprimée au profit de la canonique propre à chaque route.
Accessibilité (EAA/RGAA, WCAG 2.1 AA) : - Contrastes : terracotta 16 71% 42% (4,91:1 texte, 5,31:1 boutons), gold, muted-foreground, destructive recalibrés ; résiduels Tarifs/mockups traités - Hiérarchie de titres : h4 footer/menus → p, structure conforme - aria-label alignés sur les textes visibles (portfolio,…
Les valeurs d'ombre et la courbe d'accélération des accordéons deviennent des jetons du design system, au lieu d'être réécrites au cas par cas.
L'offre de formations, qui n'était plus commercialisée, disparaît du site. Purge des emojis dans les contenus, contraste du pied de page relevé.
Nouvelle page /services/conformite-eaa (outil Konforme, EAA, RGAA/WCAG) ; suppression du service hébergement + 301 via vercel.json · Solutions IA & Métiers : sections CRM/ERP (Twenty, Odoo — réf. Hans Leutenegger) et cartographie 3D LIDAR IGN (Muller Toiture, Aéro Toit) + Nexus
Héro : double accroche (site + process), sous-titre web/IA, badge Agence Web & IA · Piliers : Solutions IA & Automatisation remplace Design & Branding (Option A) · Grille services : Solutions Web + Solutions IA & Métiers en tête, carte IA enrichie MCP
Échéancier de paiement 40/40/20, délais harmonisés avec le simulateur de projet, SIRET et FAQ Sites Vitrines mis en conformité.
Captures WebP de 24 projets livrés, ajoutées à la page Réalisations.
Trois nouvelles pages publiques exposant notre infrastructure, nos tokens de design et l'évolution continue du site — transparence totale.
Balisage structuré multi-types pour optimiser la présence dans les AI Overviews Google, Perplexity et ChatGPT Search.
Composant <Picture> avec AVIF/WebP/fallback automatique. Hook useVisiblePrefetch qui précharge les pages liées lors de leur apparition dans le viewport.
Mode sombre OLED pur (#000 — économie batterie), easter egg Konami, fond gradient mesh animé GPU-composited pour les pages d'accueil clés.
Composant LiveSocialProof affichant l'activité récente. SmartStickyCta qui change de message selon la section du site visitée.
Fichier llms.txt enrichi, FAQ structurée, données chiffrées citables, questions PAA intégrées en H3.
Plugin Critters actif en production. Polices Outfit et Plus Jakarta Sans auto-hébergées (zéro réseau externe, zéro CLS).
Skip-link, focus-visible, contrastes audités, min-tap-target 44px, AccessibilityToggle avec mode contraste élevé et police dyslexique.
Formulaire multi-étapes guidé pour obtenir un devis estimé en temps réel. Export PDF du résumé du projet.
AidesSimulator.tsx : quiz d'éligibilité pour France Num, Atouts Numériques AuRA et chèques numériques régionaux.
Pages pillar pour chaque service, pages locales Villeurbanne/Bron/Vénissieux avec maillage interne optimisé.
Code-splitting agressif par route, lazy-loading des consumers framer-motion, analytics GTM différé après interaction.
Content-Security-Policy restrictive, HSTS preload, Permissions-Policy, COOP same-origin via vercel.json.
Utilitaires .glass, .glass-strong, .glass-premium avec backdrop-filter optimisés, palette étendue (rose, violet, cyan, gold, indigo).
Nouveaux composants mockups (Safari, iPhone, iMac) avec animations Framer Motion et parallaxe au scroll.
Migration de la stack vers Vite, Tailwind CSS, shadcn/ui, Radix primitives. Zero runtime CSS, bundle < 200Ko gzipped.
Ce journal n'est pas un simple historique : c'est la promesse que votre site, s'il est créé par Kayzen Web, recevra la même attention continue. Nos clients bénéficient des améliorations documentées ici.