[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"theme-db":3,"$fsildTc8g1slpHXpqjaAcbNeVksg288qNMZgOD6qKeLI":22,"$ffvMCWvRrXK-SXbuGNVaKzL6VQjhdGHCdyAbInH862fo":615,"client-config-ac-hub":637,"header-db":688,"$fP0FV7zZkQhZStJelKMQF2vnI2nbZQB210etjzdyGslw":698,"megamenu":769,"megamenu-contexts-ac-hub":829,"$ffA2_eFkN9XKgB9jzDDiARvtJXvRwD8gCOu2aHaDW8eo":831,"footer-db":833,"$fINI4gZJ9jGrKkdeKMLokcXFtTu9GlSBjqf36q2YjjHQ":843,"$faflpQLaKfFpxIzCi-U7Y-JeTh8zpg9vVngdnTSwzBio":879},{"theme":4},{"colors":5,"typography":13,"ui":17,"defaultColorMode":21},{"primary":6,"secondary":7,"background":8,"foreground":9,"muted":10,"headerBg":11,"footerBg":12,"topBarBg":9,"topBarText":11},"#4F46E5","#0D9488","#F9FAFB","#111827","#6B7280","#ffffff","#020617",{"fontFamily":14,"fontUrl":15,"baseFontSize":16},"Inter, system-ui, sans-serif","https:\u002F\u002Ffonts.googleapis.com\u002Fcss2?family=Inter:wght@400;500;600;700&family=Playfair+Display:ital,wght@0,400;0,700;0,800;0,900;1,400;1,700&display=swap","16px",{"borderRadius":18,"contentWidth":19,"shadow":20},"lg","7xl",true,"light",{"modules":23},[24,45,53,61,69,76,83,90,98,105,115,123,130,137,150,163,175,189,201,211,223,234,248,259,271,280,292,305,318,329,339,347,356,364,374,382,390,400,408,429,446,463,490,514,538,562,589],{"name":25,"codename":26,"icon":27,"category":28,"flywheel":29,"description":30,"features":31,"tags":35,"status":40,"link":41,"slug":42,"summary":42,"contentMd":42,"ficheSlug":43,"version":44},"AC Corse TVA","ac_corsetva","🇫🇷","commerce","reach","Bascule automatique TVA 5,5% → 2,1% sur adresses corses (CP 20xxx). Tax-rules PS natives, factures conformes.",[32,33,34],"PS native tax_rule","Multi-groupes TVA","Audit log validateOrder",[36,37,38,39],"tva","corse","food","compta","Production","\u002Fadmin\u002Findex.php?controller=AdminModules&configure=ac_corsetva",null,"ac-corsetva","",{"name":46,"codename":47,"icon":44,"category":48,"flywheel":44,"description":49,"features":50,"tags":51,"status":40,"link":44,"slug":42,"summary":42,"contentMd":42,"ficheSlug":52,"version":44},"AC Playbook","ac_playbook","administration","Playbooks par rôle : procédures, guides et checklists pour chaque profil employé.",[],[],"ac-playbook",{"name":54,"codename":55,"icon":44,"category":56,"flywheel":44,"description":57,"features":58,"tags":59,"status":40,"link":44,"slug":42,"summary":42,"contentMd":42,"ficheSlug":60,"version":44},"AC Category Extra","ac_categoryextra","catalogue","Extension 1:1 ps_category — H1 custom par langue (ps_ac_category_extra + _lang). Remplace ac_categoryoverride (doublonait ps_category_lang.meta_*).",[],[],"ac-categoryextra",{"name":62,"codename":63,"icon":44,"category":64,"flywheel":44,"description":65,"features":66,"tags":67,"status":40,"link":44,"slug":42,"summary":42,"contentMd":42,"ficheSlug":68,"version":44},"AC Homepage Section","ac_homepagesection","homepage","Sections homepage (ps_ac_homepage_section + _lang). Extrait de ac_homepage (builder front) — 11 sections types : hero-slider, features, categories, promotions, new-products, narrative-blocks, banners, bestsellers, blog, instagram, faq. Prefooter et blocks scindés en modules dédiés (scission règle 13bis, v1.6.0).",[],[],"ac-homepagesection",{"name":70,"codename":71,"icon":44,"category":64,"flywheel":44,"description":72,"features":73,"tags":74,"status":40,"link":44,"slug":42,"summary":42,"contentMd":42,"ficheSlug":75,"version":44},"AC Prefooter Section","ac_prefootersection","Sections du prefooter (ps_ac_prefooter_section + _lang). Extrait de ac_homepagesection v1.5.0 (règle 13bis 1 module = 1 domaine). Pattern zéro-migration.",[],[],"ac-prefootersection",{"name":77,"codename":78,"icon":44,"category":64,"flywheel":44,"description":79,"features":80,"tags":81,"status":40,"link":44,"slug":42,"summary":42,"contentMd":42,"ficheSlug":82,"version":44},"AC Homepage Block","ac_homepageblock","Blocks universels sous-items d une section homepage (ps_ac_homepage_block + _lang). Remplace les arrays JSON imbriqués dans payload_json. block_kind: slide\u002Ffeature\u002Fcategory\u002Fnarrative\u002Fbanner\u002Ffaq_group\u002Ffaq_item\u002Fcta. Dépend de ac_homepagesection (FK id_section). Extrait v1.5.0 (règle 13bis).",[],[],"ac-homepageblock",{"name":84,"codename":85,"icon":44,"category":56,"flywheel":44,"description":86,"features":87,"tags":88,"status":40,"link":44,"slug":42,"summary":42,"contentMd":42,"ficheSlug":89,"version":44},"AC Product Extra","ac_productextra","Extension 1:1 ps_product (h1 i18n) + passerelle CRM Nuxt (9 controllers AJAX + queue IA AC_PRODUCTEXTRA_AI_TOKEN). Absorbe ac_smartproducts (backlog #206).",[],[],"ac-productextra",{"name":91,"codename":92,"icon":44,"category":93,"flywheel":44,"description":94,"features":95,"tags":96,"status":40,"link":44,"slug":42,"summary":42,"contentMd":42,"ficheSlug":97,"version":44},"AC Customer Extra","ac_customerextra","clients","Profil B2B étendu du client (activité : GMS, CHR, Grossiste, …). Remplace la dépendance sur ps_addifycustomercustomdata.",[],[],"ac-customerextra",{"name":99,"codename":100,"icon":44,"category":56,"flywheel":44,"description":101,"features":102,"tags":103,"status":40,"link":44,"slug":42,"summary":42,"contentMd":42,"ficheSlug":104,"version":44},"AC Product Food","ac_productfood","MDM food vertical (composition, nutrition, origine, calibre, conformité) et mentions légales — 1:1 ps_product. Fusion ac_productspec + ac_productlegal (backlog #207).",[],[],"ac-productfood",{"name":106,"codename":107,"icon":108,"category":109,"flywheel":110,"description":111,"features":112,"tags":113,"status":40,"link":44,"slug":42,"summary":42,"contentMd":42,"ficheSlug":114,"version":44},"Points de fidélité B2B","ac_loyalty","⭐","marketing","retention","Programme de fidélité B2B : attribution automatique de points (1 € TTC = 1 point), expiration glissante 12 mois, conversion en bons de réduction par paliers fixes. Compatible PS 1.7.6 → 9.x.",[],[],"ac-loyalty",{"name":116,"codename":117,"icon":44,"category":118,"flywheel":44,"description":119,"features":120,"tags":121,"status":40,"link":44,"slug":42,"summary":42,"contentMd":42,"ficheSlug":122,"version":44},"AC CMS Queue","ac_cmsqueue","blog","Queue jobs async IA articles blog via job_type. Rename ac_redaction.",[],[],"ac-cmsqueue",{"name":124,"codename":125,"icon":44,"category":56,"flywheel":44,"description":126,"features":127,"tags":128,"status":40,"link":44,"slug":42,"summary":42,"contentMd":42,"ficheSlug":129,"version":44},"AC Category Queue","ac_categoryqueue","Queue jobs async IA catégorie via job_type. Rename ac_categoryredaction.",[],[],"ac-categoryqueue",{"name":131,"codename":132,"icon":44,"category":56,"flywheel":44,"description":133,"features":134,"tags":135,"status":40,"link":44,"slug":42,"summary":42,"contentMd":42,"ficheSlug":136,"version":44},"AC Product Queue","ac_productqueue","Queue jobs async IA produit (redaction, covergen, translate…) via job_type. Rename ac_productredaction.",[],[],"ac-productqueue",{"name":138,"codename":139,"icon":140,"category":141,"flywheel":142,"description":143,"features":144,"tags":145,"status":40,"link":44,"slug":42,"summary":42,"contentMd":42,"ficheSlug":149,"version":44},"Base — Authentification Headless","ac_base","🛡️","infra","Socle Technique","Module socle. Gère l'authentification employé\u002Fclient entre PrestaShop et le frontend Nuxt 3 (login, logout, session sécurisée).",[],[146,147,148],"Authentification","Headless","Sécurité","ac-base",{"name":151,"codename":152,"icon":153,"category":154,"flywheel":155,"description":156,"features":157,"tags":158,"status":40,"link":44,"slug":42,"summary":42,"contentMd":42,"ficheSlug":162,"version":44},"SmartLead — CRM Contacts","ac_smartlead","👥","crm","Étape 4 — Traction","Gestion complète des contacts et leads. CRUD, segmentation, historique des interactions. Interface intégrée au Hub.",[],[159,160,161],"CRM","Contacts","Segmentation","ac-smartlead",{"name":164,"codename":165,"icon":166,"category":154,"flywheel":155,"description":167,"features":168,"tags":169,"status":40,"link":44,"slug":42,"summary":42,"contentMd":42,"ficheSlug":174,"version":44},"SmartProject — CRM Projets","ac_smartproject","📋","Gestion de projets complète avec vue kanban, tâches, documents, intégration WhatsApp et automations. Le centre névralgique de la relation client.",[],[170,171,172,173],"Kanban","Tâches","WhatsApp","Automation","ac-smartproject",{"name":176,"codename":177,"icon":178,"category":179,"flywheel":180,"description":181,"features":182,"tags":183,"status":40,"link":44,"slug":42,"summary":42,"contentMd":42,"ficheSlug":188,"version":44},"AutoBlog — Rédaction IA","ac_autoblogarticle","✍️","ia","Étape 3 — Moteur IA","File d'attente de génération d'articles de blog par intelligence artificielle. L'IA rédige, vous validez, Google indexe. Le moteur SEO de la Flywheel.",[],[184,185,186,187],"IA","SEO","Blog","Contenu","ac-autoblogarticle",{"name":190,"codename":191,"icon":192,"category":193,"flywheel":155,"description":194,"features":195,"tags":196,"status":40,"link":44,"slug":42,"summary":42,"contentMd":42,"ficheSlug":200,"version":44},"AutoSocial — Publication Multi-Réseaux","ac_autosocialpost","📱","comm","Publication automatisée sur X, LinkedIn, Facebook et Instagram. Génération IA du contenu adaptée à chaque plateforme. Planification et file d'attente.",[],[197,184,198,199],"Social Media","LinkedIn","X","ac-autosocialpost",{"name":202,"codename":203,"icon":204,"category":141,"flywheel":142,"description":205,"features":206,"tags":207,"status":40,"link":44,"slug":42,"summary":42,"contentMd":42,"ficheSlug":210,"version":44},"HeadlessContact — Formulaire Découplé","ac_headlesscontact","✉️","Formulaire de contact headless qui transmet les données au back-office PrestaShop sans exposition du front PS. Compatible RGPD.",[],[208,147,209],"Formulaire","RGPD","ac-headlesscontact",{"name":212,"codename":213,"icon":214,"category":141,"flywheel":142,"description":215,"features":216,"tags":217,"status":40,"link":44,"slug":42,"summary":42,"contentMd":42,"ficheSlug":222,"version":44},"Fleet Manager — Gestion de Flotte","ac_fleet","🖥️","Registre centralisé des instances CodeMyShop déployées. Stocke les credentials, le MRR, le statut et les données d'infrastructure de chaque tenant dans une table dédiée. API REST complète (CRUD).",[],[218,219,220,221],"Infrastructure","Multi-Tenant","API REST","Credentials","ac-fleet",{"name":224,"codename":225,"icon":226,"category":179,"flywheel":180,"description":227,"features":228,"tags":229,"status":40,"link":44,"slug":42,"summary":42,"contentMd":42,"ficheSlug":233,"version":44},"Brand DNA — ADN de Marque","ac_branddna","🧬","Stocke l'identité de marque de chaque client (positionnement, valeurs, ton, USP, mots interdits). Utilisé par l'IA pour maintenir la cohérence des contenus générés.",[],[184,230,231,232],"Branding","Copywriting","Cohérence","ac-branddna",{"name":235,"codename":236,"icon":237,"category":179,"flywheel":238,"description":239,"features":240,"tags":241,"status":40,"link":246,"slug":42,"summary":42,"contentMd":42,"ficheSlug":247,"version":44},"Academy — Formation Interactive","ac_academy","🎓","Étape 2 — Headless","Onboarding client interactif avec mentors IA historiques. Modules pédagogiques, leçons, quiz, certificats. Chaque concept e-commerce expliqué par un mentor spécialisé.",[],[242,243,244,245],"Formation","Mentors IA","Onboarding","Pédagogie","\u002Facademy","ac-academy",{"name":249,"codename":250,"icon":251,"category":179,"flywheel":180,"description":252,"features":253,"tags":254,"status":40,"link":44,"slug":42,"summary":42,"contentMd":42,"ficheSlug":258,"version":44},"SEO Console — Pilotage Référencement","ac_seoconsole","📊","Dashboard SEO intégré au Hub. Monitoring des positions Google Search Console, détection d'opportunités, suivi des Core Web Vitals. Le cockpit du référencement.",[],[185,255,256,257],"GSC","Core Web Vitals","Analytics","ac-seoconsole",{"name":260,"codename":261,"icon":262,"category":154,"flywheel":142,"description":263,"features":264,"tags":265,"status":40,"link":44,"slug":42,"summary":42,"contentMd":42,"ficheSlug":270,"version":44},"SmartOrders — Gestion Commandes","ac_smartorders","🛒","Gestion avancée des commandes avec vue consolidée, filtres intelligents, export automatisé et synchronisation multi-boutiques. L'interface que PrestaShop aurait dû livrer.",[],[266,267,268,269],"Commandes","Multi-Boutique","Export","Dashboard","ac-smartorders",{"name":272,"codename":273,"icon":274,"category":193,"flywheel":155,"description":275,"features":276,"tags":277,"status":40,"link":44,"slug":42,"summary":42,"contentMd":42,"ficheSlug":279,"version":44},"WhatsApp — Messagerie Automatisée","ac_whatsappapi","📲","Intégration WhatsApp Business API. Notifications automatiques (commande, livraison, relance), CRM conversationnel, templates pré-approuvés.",[],[172,159,278,173],"Notifications","ac-whatsappapi",{"name":281,"codename":282,"icon":108,"category":193,"flywheel":155,"description":283,"features":284,"tags":285,"status":40,"link":290,"slug":42,"summary":42,"contentMd":42,"ficheSlug":291,"version":44},"Founder Review — Avis Fondateur","ac_founder_review","Système d'avis authentiques avec badge 'Avis vérifié par le fondateur'. Preuve sociale premium — chaque témoignage est validé personnellement, pas par un algorithme.",[],[286,287,288,289],"Preuve Sociale","Avis","Authenticité","Conversion","\u002Fa-propos","ac-founder-review",{"name":293,"codename":294,"icon":295,"category":179,"flywheel":180,"description":296,"features":297,"tags":298,"status":40,"link":303,"slug":42,"summary":42,"contentMd":42,"ficheSlug":304,"version":44},"Agents IA — Orchestration Synedre","ac_agents","🤖","Le cœur du système. Registre des agents IA spécialisés, heartbeat en temps réel, historique d'activité. Chaque agent a son profil, ses checks, ses cicatrices.",[],[299,300,301,302],"Multi-Agents","Synedre","Orchestration","Temps Réel","\u002Freacteur","ac-agents",{"name":306,"codename":307,"icon":308,"category":141,"flywheel":142,"description":309,"features":310,"tags":311,"status":40,"link":316,"slug":42,"summary":42,"contentMd":42,"ficheSlug":317,"version":44},"Incidents — Monitoring Production","ac_incidents","🚨","Suivi des incidents en production avec post-mortem automatique. Chaque bug détecté est tracé, analysé, et transformé en épreuve de Drill pour les agents.",[],[312,313,314,315],"Monitoring","Post-Mortem","Fiabilité","Drill","\u002Fdrill","ac-incidents",{"name":319,"codename":320,"icon":321,"category":179,"flywheel":180,"description":322,"features":323,"tags":324,"status":40,"link":44,"slug":42,"summary":42,"contentMd":42,"ficheSlug":328,"version":44},"Content Queue — Pipeline Contenu","ac_contentqueue","🔄","File d'attente intelligente qui croise les données GSC et le trafic pour décider quel contenu publier en priorité. La Flywheel qui ferme la boucle contenu → trafic → contenu.",[],[325,255,326,327],"Content Intelligence","Flywheel","Pipeline","ac-contentqueue",{"name":330,"codename":331,"icon":332,"category":333,"flywheel":334,"description":335,"features":336,"tags":337,"status":40,"link":44,"slug":42,"summary":42,"contentMd":42,"ficheSlug":338,"version":44},"Header Config","ac_header","🏷️","navigation","Marque → Headless","Config header multi-tenant avec table dédiée ps_ac_header. Logo, top bar, features, contact.",[],[],"ac-header",{"name":340,"codename":341,"icon":342,"category":333,"flywheel":334,"description":343,"features":344,"tags":345,"status":40,"link":44,"slug":42,"summary":42,"contentMd":42,"ficheSlug":346,"version":44},"Megamenu","ac_megamenu","🧭","Menu de navigation multi-tenant avec support megamenu grid, dropdowns et liens simples. Table dédiée ps_ac_megamenu par client DB.",[],[],"ac-megamenu",{"name":348,"codename":349,"icon":350,"category":351,"flywheel":334,"description":352,"features":353,"tags":354,"status":40,"link":44,"slug":42,"summary":42,"contentMd":42,"ficheSlug":355,"version":44},"Thème","ac_theme","🎨","design","Thème visuel multi-tenant avec table dédiée ps_ac_theme par client DB. Couleurs, typographie, UI.",[],[],"ac-theme",{"name":357,"codename":358,"icon":359,"category":333,"flywheel":334,"description":360,"features":361,"tags":362,"status":40,"link":44,"slug":42,"summary":42,"contentMd":42,"ficheSlug":363,"version":44},"Footer Config","ac_footer_config","🦶","Config footer multi-tenant ps_ac_footer_config. Identité, contact, social, bottom bar.",[],[],"ac-footer-config",{"name":365,"codename":366,"icon":367,"category":368,"flywheel":44,"description":369,"features":370,"tags":371,"status":372,"link":44,"slug":42,"summary":42,"contentMd":42,"ficheSlug":373,"version":44},"Événement","ac_event","calendar-days","communication","Présenter des événements (online ou IRL) avec inscriptions et liste des participants. Supporte les events hybrides, limite de places, deadline d'inscription, géoloc IRL.",[],[],"available","ac-event",{"name":375,"codename":376,"icon":44,"category":154,"flywheel":377,"description":378,"features":379,"tags":380,"status":40,"link":44,"slug":42,"summary":42,"contentMd":42,"ficheSlug":381,"version":44},"AC Customer Extra — Profil B2B étendu","ac_customer_extra","customer_b2b","Attributs commerciaux B2B du client (activité, etc.) — source de vérité unifiée hors schéma PS core. Remplace la dépendance directe sur ps_addifycustomercustomdata.",[],[],"ac-customer-extra",{"name":383,"codename":384,"icon":385,"category":141,"flywheel":44,"description":386,"features":387,"tags":388,"status":40,"link":44,"slug":42,"summary":42,"contentMd":42,"ficheSlug":389,"version":44},"AC Hook","ac_hook","🪝","Points de greffe runtime Nuxt : un module PS déclare ses composants à afficher sur les pages CMS\u002Fcatégorie\u002Fproduit sans toucher au code des pages.",[],[],"ac-hook",{"name":391,"codename":392,"icon":393,"category":394,"flywheel":44,"description":395,"features":396,"tags":397,"status":398,"link":44,"slug":42,"summary":42,"contentMd":42,"ficheSlug":399,"version":44},"AC Module Registry","ac_moduleregistry","cog","admin","Registre runtime des modules ac_* (PS vs Nuxt) — POC headless-modules-ts. Owne ps_ac_module_registry, source unique du runtime par tenant.",[],[],"Beta","ac-moduleregistry",{"name":401,"codename":402,"icon":403,"category":28,"flywheel":44,"description":404,"features":405,"tags":406,"status":40,"link":44,"slug":42,"summary":42,"contentMd":42,"ficheSlug":407,"version":44},"AC Payment","ac_payment","CreditCard","Paiement souverain CodeMyShop — virement bancaire MVP, extensible Stripe\u002FCB\u002FSEPA.",[],[],"ac-payment",{"name":409,"codename":410,"icon":411,"category":412,"flywheel":44,"description":413,"features":414,"tags":419,"status":40,"link":424,"slug":425,"summary":426,"contentMd":427,"ficheSlug":425,"version":428},"Baba CreateDoc","baba_createdoc","📄","libre","Crée des documents PDF avec en-tête (logo de la boutique, titre, date) à partir d'un texte libre, depuis Outils > Création de documents.",[415,416,417,418],"PDF avec en-tête de boutique","Texte libre saisi au back-office","Onglet Outils > Création de documents","PrestaShop 9.0 et PHP 8.1 à 8.4",[420,421,422,423,412],"agpl-3.0","prestashop-9","pdf","documents","\u002Fmodules\u002Fbaba_createdoc-1.1.0.zip","creer-document-pdf-prestashop","Écrivez un texte dans le back-office, obtenez un PDF à l'en-tête de votre boutique — logo, titre et date déjà en place. Rendu par le moteur PDF de PrestaShop lui-même, celui de vos factures.","## À quoi ça sert\n\nVous avez besoin d'un document à l'en-tête de votre boutique : une attestation,\nune note à joindre à un colis, un mot pour un fournisseur, une consigne interne.\nOuvrir un traitement de texte, retrouver le logo, le placer, exporter en PDF —\npour trois lignes de texte.\n\nCe module vous laisse écrire le texte dans le back-office et rend le PDF, avec\nle logo de la boutique, le titre et la date déjà en place.\n\n## Comment ça marche\n\nL'écran vit sous **Paramètres avancés → Création de documents**.\n\n1. **Ajouter** : un éditeur de texte enrichi, et c'est le seul champ. Gras,\n   listes, liens — ce que vous écrivez est ce qui sortira.\n2. **Enregistrer** : le document rejoint la liste, avec sa date d'ajout.\n3. **L'icône PDF** de la ligne ouvre le document dans un nouvel onglet.\n\nLa liste montre un extrait de 120 caractères par document, sans les balises :\non retrouve ce qu'on cherche sans ouvrir chaque ligne. Chaque document reste\nmodifiable et supprimable.\n\n## Ce que porte le PDF\n\nLe PDF est rendu par le **moteur de PrestaShop lui-même**, celui de vos factures\net de vos bons de livraison — pas par une bibliothèque ajoutée pour l'occasion.\nL'en-tête reprend donc le logo de votre boutique tel que PrestaShop le connaît,\net le document suit la langue du contexte.\n\n## Les limites, dites franchement\n\n- **Un seul champ de texte.** Pas de modèle, pas de variables, pas de\n  destinataire : ce module compose un document à l'en-tête de la boutique, il ne\n  remplace pas un générateur de devis ou de facture.\n- **Aucune donnée de commande ou de client** n'y entre automatiquement. Ce que\n  vous voulez voir dans le document, vous l'écrivez.\n- **Le document n'est pas envoyé.** Il s'ouvre, vous l'enregistrez ou vous\n  l'imprimez.\n\n## Si vous veniez de la version 1.0.0\n\nSur PrestaShop 9, la 1.0.0 déclarait son écran comme un onglet **caché et\ninactif** : le module s'installait, et la page restait introuvable dans le menu.\n\nLa 1.1.0 répare cet onglet — ou le crée s'il manque — sous *Paramètres avancés*,\net retire ce que la 1.0.0 laissait derrière elle : un greffon d'en-tête de\nback-office qui ne servait plus, et un accès rapide posé dans le menu.\n\n## Accès\n\nLe module n'expose **rien** côté boutique. Son écran est un contrôleur\nd'administration, derrière la session employé et le jeton que PrestaShop pose\nlui-même.\n\n## Installation\n\nBack-office → Modules → Installer un module → déposer le `.zip`. L'écran\napparaît sous **Paramètres avancés → Création de documents** ; le bouton\n« Configurer » du module y mène directement.\n","1.1.0",{"name":430,"codename":431,"icon":432,"category":412,"flywheel":44,"description":433,"features":434,"tags":439,"status":40,"link":442,"slug":443,"summary":444,"contentMd":445,"ficheSlug":443,"version":428},"Baba Dépenses","baba_depenses","🧾","Enregistre les dépenses de l'entreprise depuis le back-office : intitulé, référence, montants HT \u002F TVA \u002F TTC, pièce justificative et rapprochement bancaire, sous Paramètres avancés > Dépenses.",[435,436,437,438,418],"Montants HT \u002F TVA \u002F TTC par dépense","Pièce justificative jamais servie par une URL publique","Rapprochement bancaire daté","Écran sous Paramètres avancés > Dépenses",[420,421,440,441,412],"comptabilite","depenses","\u002Fmodules\u002Fbaba_depenses-1.1.0.zip","gestion-depenses-prestashop","Enregistre les dépenses de l'entreprise depuis le back-office : intitulé, montants HT \u002F TVA \u002F TTC, pièce justificative et rapprochement bancaire. Les justificatifs ne sont jamais servis par une URL publique.","## À quoi ça sert\n\nVos dépenses d'entreprise vivent dans un tableur, et vos justificatifs dans un\ndossier de téléchargements. Au moment de rapprocher les deux, il faut tout\nrouvrir.\n\nCe module les tient dans le back-office de la boutique : intitulé, référence,\ndescription, montants HT \u002F TVA \u002F TTC, pièce justificative et rapprochement\nbancaire, sur une même ligne.\n\n## Comment ça marche\n\nL'écran vit sous **Paramètres avancés → Dépenses**. Le module n'a **aucun\nréglage** : le bouton « Configurer » mène directement à la liste.\n\nChaque dépense porte :\n\n- un **intitulé** et une **référence** ;\n- une **description** libre ;\n- les montants **HT, TVA et TTC** ;\n- une **pièce justificative** ;\n- une **date de rapprochement bancaire**, facultative — une dépense peut être\n  enregistrée avant d'être rapprochée, et c'est le cas le plus fréquent.\n\n## Les pièces justificatives ne sont jamais publiques\n\nC'est le point qui mérite d'être lu avant d'installer quoi que ce soit sur une\nboutique en ligne.\n\nLes pièces sont déposées dans un dossier propre au module, **hors de tout\ndossier partagé**, et ne sont **jamais servies par une URL publique** : le\ntéléchargement passe par l'écran d'administration, donc par la session employé\net le jeton que PrestaShop pose lui-même. Une facture de fournisseur n'est pas\nune image de catalogue.\n\nFormats acceptés : `pdf`, `png`, `jpg`, `jpeg`, `gif`, `webp`, `txt`, `rtf`,\n`doc`, `docx`, `odt` — 8 Mio au plus. Supprimer une dépense supprime sa pièce.\n\n## Ce que ce module n'est pas\n\n- **Ce n'est pas une comptabilité.** Pas de plan comptable, pas d'écriture, pas\n  de journal, pas d'export vers un logiciel comptable. C'est un registre de\n  dépenses avec ses justificatifs.\n- **Il ne calcule pas la TVA pour vous.** Les trois montants sont saisis.\n- **Il ne lit aucun relevé bancaire.** Le rapprochement est une date que vous\n  posez quand vous l'avez fait.\n\n## Si vous veniez de la version 1.0.0\n\nLa 1.0.0 s'installait sur PrestaShop 9, mais son écran répondait une **erreur\nserveur** : elle appelait une méthode de traduction que PrestaShop 9 a retirée.\nLe module était donc inutilisable.\n\nLa 1.1.0 le porte, et répare ce que la 1.0.0 laissait derrière elle :\n\n- la date de rapprochement devient **facultative** ;\n- l'onglet d'administration est **activé**, sous *Paramètres avancés* ;\n- l'accès rapide sans jeton est **retiré** ;\n- les réglages inutilisés sont effacés — dont **un mot de passe stocké en\n  clair** ;\n- les pièces déjà déposées sont **déplacées** vers le dossier propre au module.\n\n## Installation\n\nBack-office → Modules → Installer un module → déposer le `.zip`. L'écran\napparaît sous **Paramètres avancés → Dépenses**.\n",{"name":447,"codename":448,"icon":140,"category":412,"flywheel":44,"description":449,"features":450,"tags":456,"status":40,"link":459,"slug":460,"summary":461,"contentMd":462,"ficheSlug":460,"version":428},"Baba Auto Index","baba_autoindex","Pose un index.php de garde dans chaque sous-répertoire des thèmes ou des modules, pour empêcher le listage des dossiers. Sur une boutique PrestaShop 9 neuve, 477 répertoires en manquaient.",[451,452,453,454,455],"Parcours récursif des thèmes ou des modules","N'écrase jamais un index.php existant","Ne suit aucun lien symbolique","Compte rendu chiffré : posées \u002F déjà là \u002F non écrites","Aucune dépendance et aucun processus lancé",[420,421,457,458,412],"securite","index","\u002Fmodules\u002Fbaba_autoindex-1.1.0.zip","empecher-listage-dossiers-prestashop","Pose un fichier de garde dans chaque sous-répertoire des thèmes ou des modules, pour que demander un dossier n'affiche plus la liste de son contenu. Il n'écrase jamais un index.php existant, et ne lance aucun processus.","## Le problème\n\nSur certains hébergements, demander un dossier de la boutique au lieu d'un\nfichier affiche la **liste de son contenu** : les noms de vos modules, de vos\nthèmes, de vos fichiers. Ce n'est pas une faille en soi, mais c'est une carte\nofferte à qui cherche une version vulnérable à attaquer.\n\nLa bonne réponse est de couper le listage dans la configuration du serveur. Ce\nmodule sert les hébergements où l'on n'y a pas la main.\n\n## Comment ça marche\n\nIl pose un fichier `index.php` de garde dans chaque sous-répertoire des\n**thèmes** ou des **modules** de la boutique. Un dossier qui contient un\n`index.php` ne montre plus son contenu : il exécute ce fichier, qui ne fait rien.\n\nL'écran vit sous **Modules → baba_autoindex → Configurer**. Un choix, un bouton,\net un compte rendu chiffré : répertoires parcourus, gardes posées, gardes déjà\nprésentes, et le cas échéant répertoires non accessibles en écriture.\n\n## Ce qu'il ne fait pas, et c'est l'essentiel\n\n- **Il n'écrase jamais un `index.php` existant.** Un fichier déjà là peut porter\n  du code : il est compté comme « déjà présent », pas remplacé.\n- **Il ne suit aucun lien symbolique**, et chaque répertoire est confronté au\n  chemin réel de la racine choisie avant écriture. Un lien posé dans `modules\u002F`\n  ne fait donc pas sortir l'écriture de la boutique.\n- **Il ne lance aucun processus.** Pas de commande système, pas de binaire, pas\n  de dépendance tierce.\n- **Il ne remplace pas une configuration de serveur.** Couper le listage dans\n  Apache ou nginx reste plus sûr qu'un fichier par dossier.\n\n## Si vous veniez de la version 1.0.0\n\nMettez-la à jour, et voici pourquoi.\n\nLa 1.0.0 passait la valeur du formulaire dans une **commande système sans\néchappement**. L'écran exigeait bien une session employé — mais tout employé\nayant accès à cette page pouvait faire exécuter une commande arbitraire sur le\nserveur de la boutique.\n\nLa 1.1.0 ne lance plus aucun processus : le formulaire envoie une **clé**\n(`themes` ou `modules`), et le module seul sait à quel répertoire elle\ncorrespond. Il n'y a plus rien à échapper, parce qu'il n'y a plus de commande.\n\nElle retire aussi ce que la 1.0.0 laissait derrière elle : une table ne portant\nqu'une clé primaire et jamais écrite, deux greffons déclarés sans\nimplémentation, un réglage jamais relu — et **quatre dépendances tierces**, dont\nune console Symfony en version 3.4, hors d'âge et susceptible d'entrer en\nconflit avec le Symfony de PrestaShop 9.\n\n## Installation\n\nBack-office → Modules → Installer un module → déposer le `.zip`, puis\n**Configurer**.\n",{"name":464,"codename":465,"icon":466,"category":412,"flywheel":44,"description":467,"features":468,"tags":477,"status":484,"link":485,"slug":486,"summary":487,"contentMd":488,"ficheSlug":486,"version":489},"SIRET : fiche client B2B remplie","code_sirenapiv3","🏛️","Le client B2B tape son SIRET : la raison sociale apparaît pendant la saisie, puis le code APE et l'adresse du siège sont renseignés à l'inscription. Aucun réglage, aucune clé d'API, aucun compte à créer : il interroge l'annuaire public des entreprises.",[469,470,471,472,473,474,475,476],"La raison sociale apparaît pendant la saisie du SIRET, avant toute validation","Code APE et adresse du siège renseignés à la création du compte","Aucune clé d'API ni compte à créer — l'annuaire public répond sans authentification","La clé de contrôle du SIRET vérifiée avant tout appel (Luhn, cas de La Poste inclus)","N'écrase jamais une saisie du client et n'ajoute jamais une seconde adresse","N'empêche jamais une inscription d'aboutir : 3 s de délai, panne silencieuse et journalisée","Point d'entrée public borné : POST seul, jeton de page, 10 appels par minute","Un essai à blanc dans l'écran de configuration, sans rien écrire",[478,479,480,481,482,483],"B2B","SIRET","inscription","annuaire des entreprises","PrestaShop 9","AGPL","published","\u002Fmodules\u002Fcode_sirenapiv3-2.1.0.zip","inscription-siret-prestashop","Le client professionnel tape son SIRET : la raison sociale apparaît pendant la saisie, puis le code d'activité et l'adresse du siège sont renseignés à l'inscription. Aucun réglage, aucune clé d'API, aucun compte à créer.","## Le problème\n\nUn client professionnel s'inscrit sur votre boutique. Il tape son SIRET, et\nc'est tout ce que vous obtenez : pas de raison sociale fiable, pas de code\nd'activité, pas d'adresse de siège. Vous les ressaisissez à la main, ou vous\nfaites sans.\n\nCe module remplit ces champs tout seul — **sans réglage, sans clé d'API, sans\ncompte à créer.**\n\n## Ce qu'il faut pour qu'il serve à quelque chose\n\nLe **mode B2B** doit être actif, dans *Paramètres de la boutique → Clients*.\nSans lui, PrestaShop ne demande pas de SIRET à l'inscription, et le module n'a\nrien à lire. L'écran de configuration vous le dit en clair plutôt que de rester\nmuet.\n\n## Pendant la saisie du formulaire\n\nDès que quatorze chiffres valides sont tapés dans le champ SIRET, le champ\n**Société** se remplit si le visiteur ne l'a pas déjà renseigné, et un court\ntexte sous le champ dit ce qui a été reconnu. Le visiteur sait tout de suite\nqu'il ne s'est pas trompé de numéro, au lieu de le découvrir après validation.\n\nC'est un **confort, pas le mécanisme** : sans JavaScript, sur un thème qui ne\nporte pas ces champs, ou si l'annuaire ne répond pas, il ne se passe rien de\nvisible et l'inscription suit son cours. L'enrichissement ci-dessous a lieu de\ntoute façon.\n\n## À la création du compte\n\n1. La **clé de contrôle** du SIRET est vérifiée localement, avec le cas\n   particulier de La Poste — un numéro fautif n'est jamais envoyé à l'annuaire.\n2. L'annuaire est interrogé sur ce SIRET. S'il ne connaît pas cet établissement,\n   une seconde requête porte sur le **SIREN**, les neuf premiers chiffres, qui\n   désigne l'entreprise : c'est alors l'adresse de son siège qui est posée, et\n   l'étiquette de l'adresse le dit.\n3. La **raison sociale** et le **code d'activité** sont écrits sur la fiche\n   client.\n4. Une adresse **« Siège social »** est créée.\n\nLes établissements fermés sont bien indexés par leur SIRET, contrairement à ce\nqu'on pourrait croire : le repli sur le SIREN n'est pas là pour eux, mais pour un\nnuméro juste de clé et absent de l'index — un établissement trop récent, par\nexemple.\n\n## Ce qu'il ne fait pas, volontairement\n\n- **Il n'écrase jamais une saisie.** Raison sociale et code d'activité ne sont\n  remplis que s'ils sont vides : le client qui a tapé son nom d'usage a plus de\n  raisons d'avoir raison que l'annuaire.\n- **Il n'ajoute pas une seconde adresse.** Si le client en a déjà une, aucune\n  n'est créée — un carnet d'adresses en double au premier jour est une gêne.\n- **Il n'empêche jamais une inscription d'aboutir.** Le délai d'appel est de\n  trois secondes, et toute panne — annuaire muet, SIRET inconnu, réponse\n  illisible — laisse le compte se créer sans enrichissement. L'incident part\n  dans les journaux de la boutique, pas à la figure du visiteur.\n- **Il ne valide pas le SIRET à la saisie.** Refuser une inscription parce qu'un\n  service externe n'a pas répondu coûte plus cher qu'une fiche incomplète.\n- **Il n'enrichit pas la modification** d'une fiche existante.\n- **Il ne crée aucune table et n'a aucun réglage.**\n\n## Ce qu'il écrit sur votre serveur, et ce qu'il n'écrit pas\n\nDeux fichiers dans le cache de la boutique : les réponses de l'annuaire, pour ne\npas le solliciter deux fois pour le même numéro, et les compteurs du plafond de\ndébit. Les supprimer est sans conséquence, ils se recréent.\n\n**Il ne conserve l'adresse IP de personne.** Le plafond de débit a besoin de\nsavoir si deux appels viennent du même endroit, pas d'où ils viennent : il n'en\ngarde qu'un condensé tronqué, salé par la clé de votre boutique — ni réversible,\nni rapprochable d'une autre boutique. Ces compteurs s'effacent au bout d'une\nheure d'inactivité.\n\n## Sur le nom du module\n\nLe nom technique `code_sirenapiv3` est historique. La version 1.0.0 visait l'API\nSirene v3 de l'INSEE, qui exige un compte et une clé ; depuis la 2.0.0 le module\nne s'en sert plus et interroge l'annuaire des entreprises de la DINUM, qui\nrépond sans authentification. Le nom est conservé pour ne pas casser les\ninstallations existantes.\n\n## Installation\n\nBack-office → Modules → Installer un module → déposer le `.zip`. Vérifiez que le\nmode B2B est actif, et c'est tout : il n'y a rien à configurer.\n","2.1.0",{"name":491,"codename":492,"icon":493,"category":412,"flywheel":44,"description":494,"features":495,"tags":506,"status":40,"link":510,"slug":511,"summary":512,"contentMd":513,"ficheSlug":511,"version":428},"Image de remplacement sur 404","cafe_default404image","🖼️","Un visuel absent du disque fait rendre la page 404 complète de la boutique : une cinquantaine de kilo-octets de HTML, un cookie de session et un rendu de thème, pour une image. Le module répond à sa place une image minuscule, en 404, sans toucher au thème — mesuré sur une boutique PrestaShop 9.0.3 neuve, 971 octets au lieu de 51 053. Il agit sur les images de catégorie, de CMS, de marque, de fournisseur et de boutique, ainsi que sur les scripts, styles, polices et source maps. Il ne se mêle pas des images produit demandées par leur URL réécrite : PrestaShop sert déjà son propre substitut pour celles-là.",[496,497,498,499,500,501,502,503,504,505],"Une image absente répond 404 avec une image, pas avec 51 ko de HTML — mesuré : 971 octets","Aucun Set-Cookie sur ces réponses : elles redeviennent cachables","Un .svg reçoit un vrai SVG valide, jamais un GIF annoncé sous un type SVG","Scripts, styles et polices : 404 au corps vide, et un interrupteur séparé pour les couper","X-Robots-Tag: noindex — un contrôleur de liens voit que l'image n'existe pas","Image de remplacement au choix dans img\u002F, ou un pixel transparent qui ne déforme aucune mise en page","Le back-office refuse un chemin hostile et NOMME la raison, au lieu d'enregistrer en silence","Durée de cache réglable de 0 à 3600 s","Aucune table créée ; désinstallé, le module retire ses quatre réglages","37 vérifications livrées avec le module, rejouables sans PHPUnit ni base",[420,421,507,508,509,412],"performance","404","images","\u002Fmodules\u002Fcafe_default404image-1.1.0.zip","image-manquante-404-prestashop","Une image absente fait rendre la page 404 complète : 51 ko de HTML et une session ouverte, par visuel manquant. Ce module répond une image minuscule et sort — 971 octets, sans session, mesuré sur PrestaShop 9.0.3.","## Le problème\n\nUn visuel absent du disque ne devrait pas coûter un rendu de page complet.\n\nPrestaShop renvoie vers son point d'entrée toute URL qui ne correspond à aucun\nfichier. Pour une image manquante, il instancie donc le contrôleur « page\nintrouvable », qui rend **la page 404 entière** : le thème, l'en-tête, le pied,\nles requêtes de menu, de panier, de devises.\n\nUne page qui demande cinquante visuels absents fait rendre cinquante fois la page\n404 — environ **2,5 Mo de HTML et cinquante sessions ouvertes**.\n\n## Le gain, mesuré\n\nSur PrestaShop 9.0.3 neuf, même boutique, même URL, module désinstallé puis\ninstallé :\n\n| | sans le module | avec le module |\n|---|---|---|\n| une image absente | **50 858 à 51 053 octets** de HTML | **971 octets**, ou 43 sans image de remplacement |\n| un script, un style, une police | **50 858 à 51 053 octets** de HTML | **0 octet** |\n| cookie de session envoyé | **1 par requête** | **aucun** |\n| mise en cache | interdite | une minute |\n| consigne aux moteurs | absente | **ne pas indexer** |\n\nLe module se greffe sur la première ligne de l'initialisation du contrôleur de\nboutique. Si l'URL demandait une image, il répond une image minuscule et sort :\nni thème, ni devises, ni une seule requête du rendu.\n\n## Ce qu'il fait exactement\n\n| URL demandée | Réponse |\n|---|---|\n| `.png`, `.jpg`, `.jpeg`, `.gif`, `.webp`, `.avif`, `.ico`, `.bmp` | **404** et votre image de remplacement, sinon un pixel transparent de 43 octets |\n| `.svg` | **404** et un SVG vide et valide — jamais un GIF annoncé comme un SVG |\n| `.js`, `.css`, `.map`, `.woff`, `.woff2`, `.ttf`, `.eot`, `.otf` | **404**, corps vide |\n| tout le reste | le module ne fait rien : la page 404 habituelle s'affiche |\n\nLa réponse est un **404**, pas un 200 : l'image n'existe pas, et un moteur de\nrecherche comme un contrôleur de liens doit pouvoir le voir.\n\n## Ce qu'il couvre, et ce qu'il ne couvre pas\n\n**Il agit sur** les images de catégorie, de page CMS, de marque, de fournisseur\net de boutique, les URL d'image directes — celles qu'emploient un contenu\néditorial, un export, un courriel ou un flux — et les scripts, styles, polices\net cartes de source.\n\n**Il n'agit pas** sur les images **produit** demandées par leur URL réécrite :\nPrestaShop sert déjà son propre substitut pour celles-là. Mesuré, un 200 de\n64 585 octets. Le module ne s'en mêle pas.\n\n**Il ne voit pas** les requêtes que le serveur web refuse avant PHP. Les dossiers\n`img\u002F`, `js\u002F` et `themes\u002F` de PrestaShop portent chacun une liste d'extensions\nautorisées, et Apache confronte cette liste au **premier segment de chemin\nmanquant**, pas au nom de fichier demandé. Un dossier intermédiaire absent donne\ndonc un segment sans extension, donc un **403** qui n'atteint jamais le module.\n\nMesuré sur PrestaShop 9.0.3 : `\u002Fthemes\u002Fclassic\u002Fassets\u002Fimg\u002Fabsent.jpg` répond 403\nparce que `assets\u002Fimg` n'existe pas, là où `\u002Fthemes\u002Fclassic\u002Fassets\u002Fcss\u002Fabsent.css`\n— dont tous les dossiers existent — répond bien 404 avec un corps vide. Rien à\ncorriger dans le module : c'est la configuration du serveur, et elle répond déjà\ncourt (277 octets, sans session).\n\n## Réglages\n\nBack-office → Modules → *Image de remplacement sur 404* → Configurer.\n\n- **Répondre aux images** et **aux scripts, styles et polices** : deux\n  interrupteurs indépendants.\n- **Image de remplacement** : un chemin dans le dossier `img\u002F` de la boutique,\n  par exemple `404.gif` ou `cms\u002Findisponible.png`. Laissé vide, le module répond\n  un pixel transparent qui **ne déforme aucune mise en page** — une balise\n  d'image garde les dimensions que le style lui donne.\n\n  Si le chemin est refusé, le back-office le dit et **nomme la raison**, au lieu\n  d'enregistrer en silence. Sont refusés : une sortie du dossier `img\u002F` (`..\u002F`,\n  lien symbolique, chemin absolu — c'est le système de fichiers qui tranche, pas\n  une lecture de la chaîne), une extension qui n'est pas une image, un `.svg`\n  (il peut porter du script), un fichier illisible ou absent, et tout caractère\n  de contrôle.\n- **Durée de cache** : réglable de 0 à 3600 secondes. Une valeur longue fait\n  attendre un visiteur après la réparation d'un visuel ; zéro interdit la mise\n  en cache.\n\nLe module ne crée **aucune table**. Désinstallé, il retire ses quatre réglages.\n\n## Installation\n\nBack-office → Modules → Installer un module → déposer le `.zip`, puis\n**Configurer**.\n",{"name":515,"codename":516,"icon":517,"category":412,"flywheel":44,"description":518,"features":519,"tags":530,"status":40,"link":533,"slug":534,"summary":535,"contentMd":536,"ficheSlug":534,"version":537},"Masquer les produits épuisés","baba_productqtvisibility","🙈","Masque un produit pendant sa rupture de stock, puis lui rend EXACTEMENT la visibilité qu'il avait au retour du stock — « catalogue seul » reste « catalogue seul », et un produit que vous avez masqué vous-même n'est jamais rendu visible par surprise. Le module lit le stock total du produit : une seule déclinaison épuisée ne masque pas les autres. Mesuré sur PrestaShop 9.0.3 : là où la version précédente écrasait le réglage du marchand par « visible partout » et masquait un produit qui avait encore 300 unités en stock, la 2.0.0 rend « catalogue seul » et le laisse visible.",[520,521,522,523,524,525,526,527,528,529],"Rend la visibilité d'origine, pas « visible partout » — « catalogue seul » et « recherche seule » survivent à la rupture","Un produit que vous avez masqué vous-même n'est jamais rendu visible","Le stock TOTAL décide : une seule déclinaison épuisée ne masque pas le produit","Un produit commandable en rupture reste vendable — et c'est réglable","La désinstallation rend sa visibilité à chaque produit masqué, avant de supprimer la table","Seuil de rupture réglable, et visibilité de rupture au choix (nulle part, recherche seule, catalogue seul)","L'écran affiche combien de produits sont masqués en ce moment, lu en base","N'écrit que la colonne visibility — jamais Product::update(), qui réécrirait tout le produit","Multiboutique : écrit dans la boutique du mouvement","42 vérifications livrées avec le module, rejouables sans PHPUnit ni base",[420,421,531,56,532,412],"stock","visibilite","\u002Fmodules\u002Fbaba_productqtvisibility-2.0.0.zip","masquer-produits-epuises-prestashop","Masque les produits en rupture, puis leur rend exactement la visibilité qu'ils avaient au retour du stock — jamais « visible partout ». Un produit réglé sur « catalogue seul » le redevient, et celui que vous avez masqué vous-même reste masqué.","## Le problème\n\nUn produit en rupture reste dans votre catalogue, dans vos listes et dans votre\nmoteur de recherche interne. Le visiteur clique, et trouve un produit qu'il ne\npeut pas acheter.\n\nCe module le masque le temps de la rupture, puis **lui rend exactement la\nvisibilité qu'il avait** quand le stock revient.\n\n## Ce que le module garantit, et pourquoi c'est la seule chose qui compte\n\n**Il ne rend que ce qu'il a pris.** Avant de masquer un produit, il écrit dans sa\npropre table la visibilité qu'il remplace. Au retour du stock, il remet\n*celle-là* — pas « visible partout ».\n\nC'est la différence entre un module utilisable et un module qui détruit votre\ntravail. Une boutique vivante a des produits réglés sur « catalogue seul » (hors\nrecherche), sur « recherche seule » (accessibles par un lien, hors navigation),\nou masqués exprès. Un module qui écrit « visible partout » au retour du stock\nefface ces décisions, une par une, à chaque réapprovisionnement — et rien ne\nvous le signale.\n\nQuatre conséquences, toutes mesurées sur une boutique réelle :\n\n| Situation | Ce qui se passe |\n|---|---|\n| Produit en « catalogue seul », rupture puis retour | il redevient **« catalogue seul »** |\n| Produit que vous avez masqué vous-même, rupture puis retour | il **reste masqué** — ce n'est pas nous qui l'avons mis là |\n| Vous changez sa visibilité pendant la rupture | la mémoire **tient** : c'est l'originale qui vous sera rendue |\n| Le module est désinstallé | **chaque produit masqué retrouve sa visibilité** avant que la table ne disparaisse |\n\n## Les déclinaisons comptent comme un tout\n\nLe module lit le **stock total du produit**, toutes déclinaisons confondues. Une\nseule taille épuisée ne masque pas le produit : les autres sont encore à vendre.\n\nMesuré : produit à deux déclinaisons de 300, l'une vidée — total 300, le produit\n**reste visible**. Les deux vidées — total 0, il est masqué. L'une\nréapprovisionnée — il revient.\n\n## Un produit commandable en rupture reste vendable\n\nSi la commande en rupture est autorisée, sur le produit ou par le réglage de la\nboutique, le masquer ferait perdre la vente. Le module ne le masque donc pas — et\nc'est réglable, si vous préférez l'inverse.\n\nLe réglage PrestaShop a **trois** états, pas deux : refusée, autorisée, ou\n« comme la boutique ». Le troisième est lu pour ce qu'il est.\n\n## Réglages\n\nBack-office → Modules → *Masquer les produits épuisés* → Configurer.\n\n- **Activer le masquage** : coupé, le module ne touche plus à rien. Les produits\n  déjà masqués le restent — un bouton les rend tous d'un geste, et la\n  désinstallation le fait toute seule.\n- **Seuil de rupture** : un produit est traité comme épuisé quand son stock total\n  est **inférieur ou égal** à ce nombre. `0` = épuisé au sens strict. Borné de 0\n  à 1 000 000.\n- **Visibilité en rupture** : *nulle part*, *recherche seule* ou *catalogue\n  seul*. C'est ce qu'on écrit pendant la rupture ; la visibilité d'avant est\n  retenue quoi qu'il arrive.\n- **Ne pas masquer si la commande en rupture est autorisée** : par défaut oui.\n\nL'écran affiche aussi **combien de produits le module masque en ce moment** — un\nchiffre lu en base, pas une promesse.\n\n## Ce que le module ne fait pas\n\n- Il ne touche **pas** aux prix, aux stocks, ni à quoi que ce soit d'autre que la\n  visibilité du produit.\n- Il ne passe **pas** par la mise à jour complète du produit, qui réécrit toutes\n  les colonnes et toutes les langues et prévient tous les modules — à chaque\n  mouvement de stock, donc des milliers de fois pendant un import. Deux écritures\n  ciblées suffisent.\n- En **multiboutique**, il écrit dans la boutique du mouvement, et ne touche au\n  reflet global que si le mouvement concerne la boutique par défaut du produit.\n- Il ne purge **aucun cache de page**. Si un cache de pages complètes est devant\n  votre boutique, la disparition du produit suivra l'expiration de ce cache.\n\n## Le test est livré avec le module\n\n```bash\nphp tests\u002FVisibiliteStockTest.php\n```\n\n42 vérifications, sans dépendance ni base de données. La décision — masquer,\nrendre, ou ne rien faire — vit à part du reste, et se rejoue seule.\n\n## Installation\n\nBack-office → Modules → Installer un module → déposer le `.zip`, puis\n**Configurer**.\n","2.0.0",{"name":539,"codename":540,"icon":541,"category":412,"flywheel":44,"description":542,"features":543,"tags":555,"status":40,"link":558,"slug":559,"summary":560,"contentMd":561,"ficheSlug":559,"version":537},"Doublons de titres produit","baba_duplicatechecker","👯","Trouve les produits qui portent le même nom — un problème de référencement autant que de catalogue — et laisse les renommer ou en retirer un, depuis le back-office seulement. La version précédente exposait ces deux actions dans un contrôleur FRONT, public et sans jeton : mesuré sur PrestaShop 9.0.3 par de simples requêtes anonymes, n'importe qui pouvait changer le prix d'un produit, puis le supprimer. Ce contrôleur n'existe plus, et les mêmes requêtes rendent désormais 404.",[544,545,546,547,548,549,550,551,552,553,554],"La version 1.0.0 laissait n'importe qui supprimer n'importe quel produit — mesuré, puis refermé : les mêmes requêtes anonymes rendent 404","La garde n'est pas qu'une authentification : seul un produit membre d'un groupe de doublons d'au moins deux est supprimable, et les groupes sont recalculés à chaque action","Le dernier exemplaire d'un nom n'est jamais supprimable — dédoublonner ne doit pas vouloir dire perdre le produit","Renommer, le geste non destructeur, obéit au même périmètre","La casse et les espaces de bordure ne séparent pas : Chemise bleue et chemise BLEUE forment un groupe","Aucune table créée, aucun greffon enregistré, rien d'exposé côté boutique","La langue et la boutique courantes décident — la version précédente les écrivait en dur","Le préfixe de tables est lu, plus écrit en dur : le module tourne sur une boutique dont le préfixe n'est pas ps_","Nombre de groupes affichés réglable de 1 à 500 — la version précédente en montrait 10, sans le dire","La montée de version retire le greffon, l'accès rapide et la table morte laissés en base","45 vérifications livrées avec le module, rejouables sans PHPUnit ni base",[420,421,457,56,556,557,412],"seo","doublons","\u002Fmodules\u002Fbaba_duplicatechecker-2.0.0.zip","doublons-titres-produits-prestashop","Trouve les produits qui portent le même nom — un problème de référencement autant que de catalogue — et laisse les renommer ou en retirer un, depuis le back-office seulement. Le dernier exemplaire d'un nom n'est jamais supprimable.","## Le problème\n\nDeux produits portent le même nom. C'est un problème de catalogue — un client\nqui hésite entre deux fiches identiques — et un problème de référencement : deux\npages qui se disputent la même requête s'affaiblissent l'une l'autre.\n\nEncore faut-il les trouver. Ce module les groupe par nom, et laisse les renommer\nou en retirer un, **depuis le back-office seulement**.\n\n## Ce que l'écran montre\n\nLes produits sont groupés par nom, à partir de deux exemplaires. La casse et les\nespaces de bordure ne séparent pas : *Chemise bleue* et *chemise BLEUE* forment\nun groupe.\n\nChaque ligne du groupe porte deux gestes : renommer, ou supprimer. Le nombre de\ngroupes affichés est réglable de 1 à 500 — la version précédente en montrait 10,\nsans le dire.\n\n## La garde, et pourquoi elle est plus qu'une authentification\n\n**Seul un produit membre d'un groupe de doublons d'au moins deux est\nsupprimable**, et les groupes sont recalculés à chaque action. Le **dernier\nexemplaire d'un nom n'est jamais supprimable** : dédoublonner ne doit pas vouloir\ndire perdre le produit. Renommer, le geste non destructeur, obéit au même\npérimètre.\n\n## Si vous veniez de la version 1.0.0\n\nMettez-la à jour, et ce n'est pas une formule.\n\nLa 1.0.0 exposait ces deux actions dans un contrôleur **côté boutique**, public\net sans jeton. Mesuré sur PrestaShop 9.0.3 par de simples requêtes anonymes :\nn'importe qui pouvait changer le prix d'un produit, puis le supprimer. Aucune\nsession, aucun mot de passe.\n\nCe contrôleur n'existe plus. Les mêmes requêtes rendent désormais **404** —\nmesuré aussi.\n\nLa mise à jour retire par ailleurs ce que la 1.0.0 laissait derrière elle : un\ngreffon devenu inutile, un accès rapide, et une table morte en base.\n\n## Ce que la version 2.0.0 corrige en plus\n\n- La **langue et la boutique courantes** décident de ce qui est comparé. La\n  version précédente les écrivait en dur, donc comparait les noms d'une autre\n  langue que celle que vous regardiez.\n- Le **préfixe des tables est lu**, plus écrit en dur : le module tourne sur une\n  boutique dont le préfixe n'est pas celui d'une installation neuve.\n- **Aucune table créée, aucun greffon enregistré, rien d'exposé côté boutique.**\n\n## Le test est livré avec le module\n\n```bash\nphp tests\u002FDoublonsTest.php\n```\n\n45 vérifications, sans dépendance ni base de données.\n\n## Installation\n\nBack-office → Modules → Installer un module → déposer le `.zip`, puis\n**Configurer**. Le module ne pose aucun onglet dans le menu : son écran est sa\npage de configuration, derrière la session employé et le jeton d'administration\nque PrestaShop pose lui-même. La désinstallation ne laisse rien derrière elle.\n",{"name":563,"codename":564,"icon":565,"category":412,"flywheel":44,"description":566,"features":567,"tags":581,"status":40,"link":585,"slug":586,"summary":587,"contentMd":588,"ficheSlug":586,"version":537},"Régler les stocks depuis un CSV","cafe_quantitybycsv","📥","Vous déposez l'inventaire de votre fournisseur ou le comptage sorti de votre tableur, le module vous montre ce qu'il changerait, et vous décidez d'écrire. L'essai à blanc est actif par défaut. La version précédente ne fonctionnait pas du tout sur PHP 8 : mesuré sur PrestaShop 9.0.3, un fichier de moins de 500 lignes n'écrivait aucune ligne et rendait une erreur serveur. Elle faisait surtout dériver le stock des produits à déclinaisons — 10 demandé, 29 annoncé à la première vente.",[568,569,570,571,572,573,574,575,576,577,578,579,580],"La version 1.0.0 n'écrivait rien sur PHP 8 — mesuré : une TypeError fatale avant le dernier lot, donc un fichier de moins de 500 lignes ne changeait rien du tout","Elle faisait dériver le stock des produits à déclinaisons : 10 demandé, 29 annoncé à la première vente. Une ligne à deux colonnes sur un produit à déclinaisons est désormais refusée, et le message dit quoi ajouter","L'essai à blanc est actif par défaut : il lit le fichier, montre le séparateur détecté, les lignes applicables et les refusées, et n'écrit rien","Un refus porte sur une ligne, pas sur le fichier : l'import va au bout sans elle et le rapport nomme son numéro de ligne","Une cellule de texte ne met plus un produit à zéro, et une quantité décimale n'est pas tronquée en silence","Le séparateur est détecté — point-virgule, virgule, tabulation ou barre verticale — et le CSV UTF-8 de votre tableur convient tel quel, marque d'octets comprise","La première ligne ne passe pour un en-tête que si elle ne commence pas par un nombre : un export sans titres garde son premier produit","Une déclinaison qui appartient à un autre produit est refusée — une erreur de colonnes ne crée pas de stock fantôme","Aucune requête SQL dans les tables de stock : le module passe par StockAvailable::setQuantity(), donc la ligne agrégée, le mouvement de stock et actionUpdateQuantity restent justes","La quantité est relue après écriture et comparée à celle demandée — le rapport ne dit « réglé » que sur ce qui l'est","Les bornes refusent AVANT la première écriture (8 Mo, 20 000 lignes) : un import tué par le max_execution_time ne laisse pas un catalogue à moitié réglé","Aucune table créée, aucun greffon posé, aucune clé de configuration : la désinstallation ne laisse rien","61 vérifications et 10 mutations livrées avec le module, rejouables sans PHPUnit ni boutique",[420,421,531,582,583,584,56,412],"import","csv","declinaisons","\u002Fmodules\u002Fcafe_quantitybycsv-2.0.0.zip","import-quantites-csv-prestashop","Déposez l'inventaire de votre fournisseur ou le comptage sorti de votre tableur : le module montre ce qu'il changerait, puis vous décidez d'écrire. L'essai à blanc est actif par défaut, et une ligne douteuse est refusée seule, sans arrêter l'import.","## Le problème\n\nVotre fournisseur vous envoie un inventaire. Vous sortez un comptage de votre\ntableur. Et il faut reporter trois cents quantités à la main dans le\nback-office, une fiche après l'autre.\n\n## Comment ça marche\n\nDeux colonnes suffisent : l'identifiant du produit, et la quantité.\n\n```\nid;quantite\n42;17\n43;0\n```\n\nTrois colonnes pour viser une déclinaison précise :\n\n```\nid;declinaison;quantite\n51;120;8\n51;121;3\n```\n\nLe séparateur est **détecté** : point-virgule, virgule, tabulation ou barre\nverticale. Le fichier que votre tableur vient de produire convient tel quel, y\ncompris en « CSV UTF-8 » avec sa marque d'octets invisible.\n\nLa première ligne n'est traitée comme un en-tête que si elle ne commence pas par\nun nombre : un export sans ligne de titres garde donc son premier produit.\n\n## L'essai à blanc est actif par défaut\n\nSur un module qui écrit dans votre stock, le premier geste ne doit pas être celui\nqui écrit. L'essai à blanc lit le fichier, affiche le séparateur détecté,\nl'en-tête reconnu, les lignes applicables et les lignes refusées — **et n'écrit\nrien**.\n\n## Ce qu'il refuse, et pourquoi c'est le cœur du module\n\nUn refus porte sur **une ligne**, pas sur le fichier : l'import va au bout sans\nelle, et le rapport nomme son numéro de ligne.\n\n| Ligne | Ce qui se passe |\n|---|---|\n| `42;rupture` | **refusée**. Une cellule de texte ne met pas un produit à zéro. |\n| `42;10.6` | **refusée**. Une quantité décimale n'est pas tronquée à 10 — c'est une question à vous poser. |\n| `42;12 pièces` | **refusée**. Elle ne vaut pas 12. |\n| `REF-123;10` | **refusée**. Ce module travaille sur les identifiants de produit, pas sur les références. |\n| `51;8` quand 51 a des déclinaisons | **refusée**, et le message vous dit d'ajouter la colonne de déclinaison. |\n| `51;999;8` quand 999 appartient à un autre produit | **refusée**. Une erreur de colonnes ne crée pas de stock fantôme. |\n| `42;10` deux fois | la **dernière** vaut, et le rapport nomme la ligne remplacée. Les quantités ne s'additionnent pas. |\n\nUn produit à déclinaisons ne peut pas être réglé en deux colonnes, et le module\nle dit plutôt que de deviner. La table de stock porte une ligne par déclinaison,\nplus une ligne agrégée que PrestaShop recalcule comme leur somme : écrire la même\nvaleur partout donne un stock juste à l'instant de l'import, puis faux à la\npremière vente.\n\n## Ce qu'il écrit, et par où\n\nAucune requête SQL dans les tables de stock. Le module passe par l'API de la\nboutique — celle qui tient la ligne agrégée, respecte le contexte de boutique,\ninscrit le mouvement de stock et prévient les autres modules qui en dépendent.\n\nAprès l'import, la quantité est **relue** et comparée à celle demandée : le\nrapport ne dit « réglé » que sur ce qui l'est vraiment. En multiboutique,\nl'import s'applique à la boutique du contexte courant, et le rapport la nomme.\n\n## Les bornes\n\n| Borne | Valeur | Pourquoi |\n|---|---|---|\n| Taille du fichier | 8 Mo | au-delà, découpez |\n| Nombre de lignes | 20 000 | un import tué par le délai d'exécution du serveur laisse un catalogue à moitié réglé sans qu'on sache où il s'est arrêté. Le refus arrive **avant** la première écriture. |\n| Lignes par appel | 500 | borne la mémoire, ne change rien au résultat |\n\n## Si vous veniez de la version 1.0.0\n\n**Elle ne fonctionnait pas sur PHP 8**, et c'est mesuré : un fichier de moins de\n500 lignes ne changeait rien du tout, et l'écran rendait une erreur serveur. Elle\nfaisait aussi dériver le stock des produits à déclinaisons — 10 demandé, 29\nannoncé à la première vente.\n\nLes quantités déjà posées par la 1.0.0 ne sont pas corrigées par la mise à jour :\nelle ne peut pas savoir ce que vous vouliez. Un produit dont le stock a dérivé se\nrègle en redéposant son fichier, cette fois avec la colonne de déclinaison —\nl'essai à blanc vous montrera le résultat avant de l'écrire.\n\n## Installation\n\nBack-office → Modules → Installer un module → déposer le `.zip`, puis\n**Configurer**. Aucune table créée, aucun greffon posé, aucune clé de\nconfiguration : la désinstallation ne laisse rien derrière elle.\n\nLe module n'a qu'un seul point d'entrée, la page de configuration, derrière la\nsession employé et le jeton d'administration que PrestaShop pose lui-même.\n",{"name":590,"codename":591,"icon":332,"category":412,"flywheel":44,"description":592,"features":593,"tags":607,"status":40,"link":611,"slug":612,"summary":613,"contentMd":614,"ficheSlug":612,"version":537},"Régler les métas SEO des catégories depuis un CSV","cafe_seotitlebycsv","Règle meta_title et meta_description des catégories PrestaShop depuis un fichier CSV, avec un essai à blanc qui montre l'avant et l'après, un rapport ligne par ligne, et la garantie qu'aucun champ n'est vidé sans que vous l'ayez demandé.",[594,595,596,597,598,599,573,600,601,602,603,604,605,606],"Il ne vide JAMAIS un champ : une colonne absente du fichier, ou une cellule laissée vide, laisse la métadonnée en place. La version 1.0.0 écrivait une chaîne vide et effaçait le titre SEO — mesuré","L'essai à blanc est actif par défaut : il affiche, catégorie par catégorie, le titre actuel barré et le nouveau en dessous, et n'écrit rien","La langue se choisit dans un écran, parmi celles installées — elle n'est plus celle de l'employé connecté. Une colonne id_lang du fichier la règle ligne par ligne","Les autres langues ne sont pas touchées, et en multiboutique les autres boutiques non plus : la 1.0.0 écrivait sans id_shop et écrasait toutes les boutiques à la fois — mesuré","Un refus porte sur une ligne, pas sur le fichier : l'import va au bout sans elle et le rapport nomme son numéro de ligne et son motif","Un titre trop long est refusé AVANT que MySQL ne le tronque, avec sa longueur en caractères — 255 pour le titre, 512 pour la description","Les colonnes se nomment dans l'en-tête et l'ordre n'a pas d'importance ; un fichier sans en-tête reste lu dans l'ordre historique","Une catégorie qui n'existe pas est signalée comme non écrite : un UPDATE sur zéro ligne réussit sans rien faire, et ce n'est pas un succès","Deux lignes pour la même cible : la dernière vaut, et le rapport nomme la ligne remplacée","Chaque valeur écrite passe par pSQL : Db::update interpole les valeurs telles quelles, rien n'échappe à votre place","Les caches de catégorie et de gabarits sont purgés après écriture — sans quoi vos pages continueraient d'être servies avec les anciennes métadonnées","Aucun contrôleur, aucun greffon, aucune table, aucune clé de configuration : la désinstallation ne laisse rien","80 vérifications de décision et 16 mutations livrées avec le module, rejouables sans PHPUnit ni boutique, plus 43 preuves de comportement sur de vraies catégories",[420,421,556,608,609,610,582,583,412],"meta-title","meta-description","categories","\u002Fmodules\u002Fcafe_seotitlebycsv-2.0.0.zip","metas-seo-categories-csv-prestashop","Reportez les titres et descriptions SEO de vos catégories depuis un tableur. Le module montre ce qu'il changerait avant d'écrire, et ne vide jamais un champ que votre fichier ne remplit pas — une colonne absente laisse la métadonnée en place.","## Le problème\n\nVous avez deux cents catégories, et un tableur où vous avez enfin écrit les\ntitres et les descriptions SEO qui vont bien. Il faut maintenant les reporter\nune par une dans le back-office, onglet SEO, catégorie après catégorie.\n\nEt si vous avez déjà essayé de le faire en masse, vous connaissez la peur qui va\navec : un import qui se trompe sur vos métadonnées ne les abîme pas, il les\n**efface**. Le travail de référencement de six mois tient dans deux colonnes de\nbase de données qui ne gardent aucun historique.\n\n## Comment ça marche\n\nLes colonnes se **nomment**, et l'ordre n'a pas d'importance :\n\n```\nid_category;meta_title;meta_description\n12;Turbos reconditionnés garantis 2 ans;Nos turbos révisés sur banc, livrés en 48 h\n13;Injecteurs diesel toutes marques;Injecteurs testés, garantie pièce et main-d'œuvre\n```\n\nVous pouvez n'en remplir qu'une :\n\n```\nid_category;meta_title\n14;Pompes haute pression révisées\n```\n\nLe séparateur est **détecté** : point-virgule, virgule, tabulation ou barre\nverticale. Le fichier que votre tableur vient de produire convient tel quel, y\ncompris en « CSV UTF-8 » avec sa marque d'octets invisible.\n\n| Colonne | Rôle |\n|---|---|\n| `id_category` | obligatoire, un entier strictement positif |\n| `meta_title` | facultative, 255 caractères au plus |\n| `meta_description` | facultative, 512 caractères au plus |\n| `id_lang` | facultative, pour régler la langue **ligne par ligne** |\n\n## Il ne vide jamais un champ\n\nC'est la règle du module, et elle n'a pas d'exception.\n\nUne colonne que vous ne mettez pas dans le fichier laisse la métadonnée **en\nplace**. Une cellule que vous laissez vide, aussi. Et une ligne qui ne demande ni\ntitre ni description est **refusée** plutôt qu'appliquée comme un effacement.\n\nPour vider une métadonnée, passez par la fiche de la catégorie : c'est un geste\nqui se fait une fois, en la regardant, pas en masse depuis un tableur.\n\n## L'essai à blanc est actif par défaut\n\nSur un module qui écrit dans votre référencement, le premier geste ne doit pas\nêtre celui qui écrit.\n\nL'essai à blanc lit le fichier et affiche, catégorie par catégorie, **le titre\nactuel barré et le nouveau en dessous**. Ce qui ne change pas est marqué comme\ninchangé. Et rien n'est écrit.\n\n## La langue, vous la choisissez\n\nUn écran vous demande dans quelle langue écrire, parmi celles installées sur la\nboutique. Elle est pré-remplie avec la vôtre, mais vous la voyez avant de\nvalider.\n\nSi votre fichier porte une colonne `id_lang`, c'est elle qui décide, ligne par\nligne : un seul fichier peut donc régler le français et l'anglais d'une même\ncatégorie.\n\nLes autres langues ne sont pas touchées. En multiboutique, les autres boutiques\nnon plus.\n\n## Ce qu'il refuse, et pourquoi\n\nUn refus porte sur **une ligne**, pas sur le fichier : l'import va au bout sans\nelle, et le rapport nomme son numéro de ligne et son motif.\n\n| Ligne | Ce qui se passe |\n|---|---|\n| `12` seule | **refusée**. Elle ne demande ni titre ni description — et elle n'efface pas les deux. |\n| `REF-7;Mon titre` | **refusée**. Ce module travaille sur les identifiants de catégorie. |\n| `12 produits;Mon titre` | **refusée**. Cela ne vaut pas la catégorie 12. |\n| un titre de 256 caractères | **refusée**, avec sa longueur. La colonne en accepte 255, et une phrase coupée en deux dans Google n'est pas un résultat. |\n| un titre portant `\u003C`, `>`, `{` ou `}` | **refusée**. PrestaShop les refuse aussi, mais plus loin — autant le dire tout de suite. |\n| `12;Premier jet` puis `12;Titre corrigé` | la **dernière** vaut, et le rapport nomme la ligne remplacée. |\n| une catégorie qui n'existe pas | **signalée** comme non écrite. Un `UPDATE` sur zéro ligne réussit sans rien faire : ce n'est pas un succès. |\n\n## Ce qui a été mesuré\n\nLe module est livré avec ses deux jeux d'épreuves, rejouables sans PHPUnit et\nsans boutique pour le premier :\n\n- **80 vérifications** sur la décision — ce qu'un fichier demande, avant toute\n  écriture — et **16 mutations** jouées, dont 16 rougissent. Une décision\n  qu'aucune épreuve ne garde est une décision qui se perdra à la prochaine\n  retouche.\n- **43 preuves de comportement** sur de vraies catégories, en PrestaShop 9.0.3 et\n  PHP 8.4.15 : l'effacement est mesuré sur la version précédente, puis le refus\n  sur la même ligne ; la séparation des langues est vérifiée sur deux langues\n  installées ; un titre de 255 caractères accentués est relu entier.\n\nDeux de ces mutations ont dit ce que la relecture ne voyait pas. C'est leur\nintérêt.\n\n## Ce qu'il ne fait pas\n\n- Il ne touche **que** les catégories. Les produits et les pages ont leurs\n  propres métadonnées, et un autre module.\n- Il n'écrit **aucune** table, ne pose **aucun** greffon, ne garde **aucune** clé\n  de configuration. La désinstallation ne laisse rien derrière elle.\n- Il n'a **aucun** contrôleur, ni public ni d'administration. Son seul point\n  d'entrée est sa page « Configurer », derrière votre session employé et le jeton\n  du back-office. Il n'y a rien à atteindre de l'extérieur.\n\n## Si vous veniez de la version 1.0.0\n\nMontez, puis relisez vos métadonnées sur quelques catégories.\n\nLa 1.0.0 effaçait dès qu'une ligne de votre fichier avait moins de trois\ncolonnes, et elle ne le disait pas. La 2.0.0 ne peut pas réparer cela : la table\nne garde pas d'historique, et rien ne dit ce qu'il y avait avant. Vos recours\nsont une sauvegarde de base antérieure, ou ce que l'index de Google garde encore\nde vos anciens titres.\n\nCe qui est écrit noir sur blanc dans le fichier de montée du module, plutôt que\ndécouvert plus tard.",{"footer":616},{"theme":617,"description":42,"hours":42,"logo":618,"contact":622,"social":623,"bottomBar":633,"newsletter":634},"dark",{"src":619,"href":620,"alt":621},"\u002Flogo-ac.svg","\u002F","Alexandre Carette",{"email":42,"phone":42,"address":42,"cta":42},[624,627,630],{"platform":625,"href":626,"label":625},"linkedin","https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Falexandre-carette\u002F",{"platform":628,"href":629,"label":628},"malt","https:\u002F\u002Fwww.malt.fr\u002Fprofile\u002Falexandrecarette",{"platform":631,"href":632,"label":631},"github","https:\u002F\u002Fgithub.com\u002Fprest4cafe",{"copyright":42},{"show":635,"title":42,"description":42,"placeholder":42,"ctaLabel":42,"consentText":636},false,"J'accepte de recevoir par e-mail les actualités de CodeMyShop et d'Alexandre Carette : nouveaux modules libres, astuces PrestaShop, SEO et performance. Je peux me désinscrire à tout moment grâce au lien présent dans chaque message.",{"faq":638,"theme":675,"domain":679,"clientId":683,"features":684,"contactEmail":686,"defaultColorMode":21,"gscSiteUrl":687},[639,642,645,648,651,654,657,660,663,666,669,672],{"reponse":640,"question":641},"L'architecture Headless sépare le moteur e-commerce (PrestaShop via API REST) de l'interface (Nuxt 4, SSR). Résultat : des performances 3× supérieures en Core Web Vitals, une liberté de design totale, et la possibilité d'intégrer l'IA nativement dans le parcours d'achat. Je le recommande car je l'ai éprouvé sur +10 ans de projets : la maîtrise technique est entière, les données restent chez vous.","Qu'est-ce que l'architecture PrestaShop Headless et pourquoi la recommandez-vous ?",{"reponse":643,"question":644},"Dans le cadre d'une mission, j'intègre l'IA comme un outil de production, pas un gadget. Concrètement : génération automatique de fiches produit optimisées SEO, transcréation multilingue adaptée culturellement (FR\u002FEN\u002FDE), publication sociale automatisée, scripts vidéo Shorts, nurturing client. Tout est orchestré depuis un Hub centralisé avec suivi FinOps des coûts IA en temps réel — que vous voyez à chaque livraison.","Comment intégrez-vous l'IA dans un projet e-commerce ?",{"reponse":646,"question":647},"Mon conseil est clair : les solutions SaaS comme Shopify offrent une mise en route rapide, mais vous cèdent votre infrastructure, vos données et une part de votre CA. Avec PrestaShop Headless, vous êtes propriétaire du code, des données et de l'infrastructure. Pas de dépendance plateforme, souveraineté RGPD, liberté technique totale pour scaler et intégrer l'IA. Je prends en charge la migration ou le build complet dans le cadre d'un forfait ou d'une régie au TJM.","Pourquoi PrestaShop Headless plutôt que Shopify ou WooCommerce ?",{"reponse":649,"question":650},"Tout commence par un premier échange de 30 min pour cadrer votre besoin. Je vous remets ensuite un devis (forfait ou régie au TJM) avec des jalons clairs et sans surprise. Une fois accepté, je réalise la mission ; à la livraison, le code et les accès vous appartiennent intégralement. Pas d'abonnement, pas de dépendance : vous repartez autonomes.","Comment se déroule une mission avec vous ?",{"reponse":652,"question":653},"Le SSR (Server-Side Rendering) via Nuxt 4 garantit un HTML complet pour les crawlers Google et les LLM (ChatGPT, Perplexity). J'optimise les Core Web Vitals, la structure des URLs, le maillage interne, le balisage Schema.org (Product, FAQ, Person) et l'architecture de contenu pour maximiser le trafic organique et la visibilité dans les réponses IA.","Comment fonctionne le SEO technique sur une architecture Headless ?",{"reponse":655,"question":656},"Le tarif est calé sur la nature de la mission (audit, refonte, accompagnement long, build complet) et discuté en début de relation. Chaque mission démarre par un audit technique gratuit de 30 minutes pour cadrer le besoin, suivi d'un devis détaillé avec jalons clairs et sans surprise. +10 ans d'expertise, 193 projets livrés et une maîtrise complète de la stack (PrestaShop, Nuxt 4, Docker, IA).","Quel est votre tarif et comment se structure une mission ?",{"reponse":658,"question":659},"Oui, dans le cadre d'une mission. Je déploie des infrastructures containerisées (Docker, Nginx, Redis, PM2) sur VPS souverain français, avec CI\u002FCD GitHub Actions et déploiements Zero-Downtime. Vos données restent en France, conformément au RGPD. À la livraison, vous maîtrisez votre stack : je vous forme et vous remets la documentation d'exploitation.","Prenez-vous en charge l'infrastructure et le DevOps ?",{"reponse":661,"question":662},"Oui — c'est l'une de mes spécialités. Je développe des modules PrestaShop sur mesure dans le cadre d'une mission (forfait ou régie). CRM, génération IA de contenu, catalogue headless, automatisations métier : chaque module est sécurisé, documenté et vous appartient intégralement à la livraison. Pas de catalogue produit : chaque module est conçu pour votre besoin précis.","Développez-vous des modules PrestaShop sur mesure ?",{"reponse":664,"question":665},"Je configure une boucle d'analyse qui croise trois sources que vous possédez : vos logs serveur, votre Google Search Console via API, et les comportements visiteurs via Matomo auto-hébergé sur votre VPS. L'IA identifie le contenu manquant — requêtes sans page, pages à faible conversion — et le génère. Zéro donnée ne transite par des serveurs tiers. Le coût IA est suivi token par token et vous est reporté.","Comment l'IA identifie-t-elle le contenu à produire pour mon site ?",{"reponse":667,"question":668},"Basé à Metz (Grand Est), j'accompagne des entreprises dans toute la France. Audit initial en visio, suivi de projet en temps réel, et déploiements automatisés. La distance n'est jamais un frein — 119 avis 5 étoiles sur Malt en témoignent.","Acceptez-vous des clients partout en France ?",{"reponse":670,"question":671},"Le forfait convient aux périmètres bien définis : refonte, module précis, audit. Le prix et le délai sont fixés à l'avance, sans surprise. La régie (au TJM) convient aux missions évolutives : accompagnement technique long, sprints itératifs, roadmap ouverte. Dans les deux cas, le code vous appartient à la livraison et je n'impose aucun abonnement ni dépendance.","Quelle différence entre une mission au forfait et une mission en régie (TJM) ?",{"reponse":673,"question":674},"Cliquez sur \"Réserver un appel\" pour un échange gratuit de 30 minutes. J'analyse vos enjeux e-commerce, votre stack actuelle et les opportunités d'optimisation SEO et IA. Aucun engagement — juste un diagnostic clair et actionnable.","Comment réserver un premier échange pour discuter de mon projet ?",{"ui":676,"colors":677,"typography":678},{"shadow":20,"borderRadius":18},{"muted":10,"primary":6,"footerBg":11,"headerBg":11,"topBarBg":9,"secondary":7,"background":8,"foreground":9,"topBarText":11},{"fontUrl":15,"fontFamily":14},[680,681,682],"alexandrecarette.fr","www.alexandrecarette.fr","localhost","ac-hub",{"showLogin":20,"showSearch":635,"showContact":635,"headerLayout":685,"showWishlist":635,"stickyHeader":635},"inline","contact@alexandrecarette.fr","https:\u002F\u002Falexandrecarette.fr\u002F",{"header":689},{"logo":690,"topBar":693,"contactEmail":686,"contactPhone":42,"features":696,"navBar":42,"headerLinks":697,"storesHref":42},{"src":619,"alt":691,"text":621,"href":620,"class":692},"Alexandre Carette — Architecte E-commerce Souverain","h-10 w-10",{"message":42,"messageMobile":42,"showLanguages":635,"align":694,"languages":695},"left",[],{"showSearch":635,"showWishlist":635,"showLogin":20,"showContact":635,"showCart":635,"showQuoteButton":20,"showBlogLink":635,"showContactLink":635,"showGiftcardLink":635,"showStoresLink":635,"stickyHeader":20,"staticHeader":635,"headerLayout":685},{},{"columns":699},[700,716,742,758],{"title":701,"position":702,"links":703},"Plateforme",1,[704,707,710,713],{"label":705,"href":706,"external":635},"Tarifs","\u002Ftarifs",{"label":708,"href":709,"external":635},"Devenir Ambassadeur","\u002Fambassadeur",{"label":711,"href":712,"external":635},"Méthode","\u002Fmodules",{"label":714,"href":715,"external":20},"CodeMyShop (open-source)","https:\u002F\u002Fcodemyshop.com",{"title":717,"position":718,"links":719},"Le Synedre",2,[720,723,726,729,731,734,736,739],{"label":721,"href":722,"external":635},"L'histoire","\u002Fsynedre",{"label":724,"href":725,"external":20},"Constitution","https:\u002F\u002Fsynedre.com\u002Ffr\u002Fconstitution",{"label":727,"href":728,"external":20},"L'équipe","https:\u002F\u002Fsynedre.com\u002Ffr\u002Fagents",{"label":730,"href":303,"external":635},"Le réacteur en direct",{"label":732,"href":733,"external":20},"Le Drill (entraînement)","https:\u002F\u002Fsynedre.com\u002Ffr\u002Fdrill",{"label":735,"href":728,"external":20},"Les agents IA",{"label":737,"href":738,"external":20},"La Conduite","https:\u002F\u002Fsynedre.com\u002Ffr\u002Fconduite",{"label":740,"href":741,"external":20},"Charte plateforme","https:\u002F\u002Fsynedre.com\u002Ffr\u002Fcharte",{"title":743,"position":744,"links":745},"Ressources",3,[746,748,750,753,755],{"label":186,"href":747,"external":635},"\u002Fblog",{"label":749,"href":246,"external":635},"Academy",{"label":751,"href":752,"external":635},"Expertise PrestaShop","\u002Fexpertise",{"label":326,"href":754,"external":635},"\u002Fflywheel",{"label":756,"href":757,"external":635},"Manifeste","\u002Fmanifeste",{"title":759,"position":760,"links":761},"À propos",4,[762,763,766],{"label":621,"href":290,"external":635},{"label":764,"href":765,"external":20},"Dossier de presse","https:\u002F\u002Fsynedre.com\u002Ffr\u002Fpresse",{"label":767,"href":768,"external":635},"Contact","\u002Fcontact",{"items":770},[771,780,785,790,797,804,811,817,823],{"id":772,"type":773,"label":774,"href":752,"icon":42,"iconRole":776,"description":42,"badge":42,"groupTitle":42,"groupKey":42,"style":42,"gridColumns":42,"cssClass":42,"psCategoryId":42,"psProductId":42,"showPsChildren":635,"position":777,"barVisible":20,"children":778,"psChildren":779},41,"link",{"fr":775},"Expertise","picto",0,[],[],{"id":781,"type":773,"label":782,"href":747,"icon":42,"iconRole":776,"description":42,"badge":42,"groupTitle":42,"groupKey":42,"style":42,"gridColumns":42,"cssClass":42,"psCategoryId":42,"psProductId":42,"showPsChildren":635,"position":702,"barVisible":20,"children":783,"psChildren":784},42,{"fr":186},[],[],{"id":786,"type":773,"label":787,"href":712,"icon":42,"iconRole":776,"description":42,"badge":42,"groupTitle":42,"groupKey":42,"style":42,"gridColumns":42,"cssClass":42,"psCategoryId":42,"psProductId":42,"showPsChildren":635,"position":718,"barVisible":20,"children":788,"psChildren":789},43,{"fr":711},[],[],{"id":791,"type":773,"label":792,"href":794,"icon":42,"iconRole":776,"description":42,"badge":42,"groupTitle":42,"groupKey":42,"style":42,"gridColumns":42,"cssClass":42,"psCategoryId":42,"psProductId":42,"showPsChildren":635,"position":744,"barVisible":20,"children":795,"psChildren":796},49,{"fr":793},"Modules gratuits","\u002Fmodules-libres",[],[],{"id":798,"type":773,"label":799,"href":801,"icon":42,"iconRole":776,"description":42,"badge":42,"groupTitle":42,"groupKey":42,"style":42,"gridColumns":42,"cssClass":42,"psCategoryId":42,"psProductId":42,"showPsChildren":635,"position":760,"barVisible":20,"children":802,"psChildren":803},44,{"fr":800},"Outils IA","\u002Foutils-ia",[],[],{"id":805,"type":773,"label":806,"href":706,"icon":42,"iconRole":776,"description":42,"badge":42,"groupTitle":42,"groupKey":42,"style":807,"gridColumns":42,"cssClass":42,"psCategoryId":42,"psProductId":42,"showPsChildren":635,"position":808,"barVisible":20,"children":809,"psChildren":810},45,{"fr":705},{"highlight":20},5,[],[],{"id":812,"type":773,"label":813,"href":246,"icon":42,"iconRole":776,"description":42,"badge":42,"groupTitle":42,"groupKey":42,"style":42,"gridColumns":42,"cssClass":42,"psCategoryId":42,"psProductId":42,"showPsChildren":635,"position":814,"barVisible":20,"children":815,"psChildren":816},46,{"fr":749},6,[],[],{"id":818,"type":773,"label":819,"href":290,"icon":42,"iconRole":776,"description":42,"badge":42,"groupTitle":42,"groupKey":42,"style":42,"gridColumns":42,"cssClass":42,"psCategoryId":42,"psProductId":42,"showPsChildren":635,"position":820,"barVisible":20,"children":821,"psChildren":822},47,{"fr":759},7,[],[],{"id":824,"type":773,"label":825,"href":768,"icon":42,"iconRole":776,"description":42,"badge":42,"groupTitle":42,"groupKey":42,"style":42,"gridColumns":42,"cssClass":42,"psCategoryId":42,"psProductId":42,"showPsChildren":635,"position":826,"barVisible":20,"children":827,"psChildren":828},48,{"fr":767},8,[],[],{"contexts":830},[],{"sections":832},[],{"footer":834},{"theme":617,"description":42,"hours":42,"logo":835,"contact":836,"social":837,"bottomBar":841,"newsletter":842},{"src":619,"href":620,"alt":621},{"email":42,"phone":42,"address":42,"cta":42},[838,839,840],{"platform":625,"href":626,"label":625},{"platform":628,"href":629,"label":628},{"platform":631,"href":632,"label":631},{"copyright":42},{"show":635,"title":42,"description":42,"placeholder":42,"ctaLabel":42,"consentText":636},{"reviews":844,"total":878,"business":42},[845,851,857,862,868,874],{"author":846,"company":847,"rating":808,"title":848,"text":849,"date":850,"source":628},"Office","MONOGRAM","Nous travaillons avec Alexandre depuis quelques mois et sommes ravis de son a","Nous travaillons avec Alexandre depuis quelques mois et sommes ravis de son accompagnement. Alexandre comprend parfaitement les enjeux et problématiques liés à notre activité et parvient, en réponse, à nous apporter des solutions techniques et fonctionnelles en respectant coûts et délais.","2023-07-18",{"author":852,"company":853,"rating":808,"title":854,"text":855,"date":856,"source":628},"Marine","MES-Distribution","La résolution de mes problèmes à été rapide et efficace, je recommande :)","La résolution de mes problèmes à été rapide et efficace, je recommande :).","2023-01-20",{"author":858,"company":859,"rating":808,"title":860,"text":860,"date":861,"source":628},"Jl","Kaigan","Super","2022-10-25",{"author":863,"company":864,"rating":808,"title":865,"text":866,"date":867,"source":628},"Elite Cbd","Canna Elite Europe Ltd","Au Top","Au Top. tout simplement","2022-06-21",{"author":869,"company":870,"rating":808,"title":871,"text":872,"date":873,"source":628},"Lorie","GRIIN outdoor","Configuration d''un VPS et migration réalisée avec succès, bons conseils, dia","Configuration d'un VPS et migration réalisée avec succès, bons conseils, diagnostique rapide et efficace de nos problèmes. Je recommande.","2022-06-01",{"author":863,"company":864,"rating":808,"title":875,"text":876,"date":877,"source":628},"Toujours aussi clair et clairvoyant","Toujours aussi clair et clairvoyant... ;) Un plaisir de travailler avec Alexandre","2022-05-16",33,{"ok":20,"alternates":880},{"fr":794}]