Cocon SEO
Le module Cocon SEO est le moteur de génération massive de pages SEO du Labo du Yeti. Il permet de produire automatiquement des centaines de pages cohérentes à partir d'un seul template HTML et de quelques listes de variables. Chaque page générée est rangée dans un content group (groupe de contenu) qui définit les variables, les patrons de slug, de titre et de SEO, ainsi que la fréquence à laquelle l'IA peut produire de nouvelles pages.
Ce module est l'un des trois grands piliers éditoriaux du CMS, aux côtés des pages classiques et du blog IA. Il est conçu pour bâtir des cocons sémantiques à deux niveaux : une page parent (la pilier d'un service) et un ensemble de pages enfants (les variantes locales ou catégorielles). Le code de production se trouve principalement dans backend/src/services/cocon-service.js, backend/src/services/quota-service.js et backend/src/services/notification-service.js.
requireCapability('cocon'). Les rôles owner, admin, webmaster et editor ont la capacité activée par défaut ; un owner peut la désactiver pour un rôle via la matrice des droits.Content groups
Un content group est l'unité de configuration d'un cocon. Il est persisté dans la table cocon_groups (legacy KV cocon.content_groups en cours de migration) et regroupe :
- un template HTML source, uploadé via
POST /api/cocon/groupsavecuploadHtml.single; - un dictionnaire de variables (clé → liste de valeurs) ;
- des patrons (
slug_pattern,title_pattern, patrons SEO) avec interpolation{{var}}; - un quota (nombre maximum de pages générables sur une fenêtre glissante) ;
- une hiérarchie optionnelle via
parent_id(lien vers un autre groupe).
Variables et patrons d'interpolation
Les variables sont déclarées sous forme de listes nommées. Exemple pour un cocon d'agence locale :
{
"id": "grp_plombier_villes",
"title": "Plombier — villes Île-de-France",
"variables": {
"service": ["debouchage", "fuite", "chauffe-eau"],
"ville": ["Paris", "Versailles", "Boulogne", "Saint-Denis"]
},
"slug_pattern": "{{service}}/{{ville}}",
"title_pattern": "Plombier {{service}} à {{ville}} | Intervention 24/7",
"seo": {
"meta_description_pattern": "Plombier spécialisé {{service}} à {{ville}}. Devis gratuit, intervention rapide.",
"h1_pattern": "Plombier {{service}} {{ville}}"
}
}
L'interpolation {{var}} est résolue au moment de la génération par cocon-service.js. Chaque clé entre doubles accolades est remplacée par la valeur courante de la combinaison en cours. Les patrons peuvent contenir n'importe quel nombre de variables, mais toute clé non déclarée dans variables provoque un rejet à la validation du groupe.
Combinaisons cartésiennes
Les combinaisons sont calculées au runtime par produit cartésien des listes de variables. Pour le groupe ci-dessus, on obtient 3 × 4 = 12 combinaisons. L'endpoint GET /api/cocon/groups/:id/combinations retourne cette matrice prévisualisée afin de valider visuellement les slugs et titres avant de lancer la génération.
| service | ville | slug | title |
|---|---|---|---|
| debouchage | Paris | debouchage/paris | Plombier debouchage à Paris | Intervention 24/7 |
| debouchage | Versailles | debouchage/versailles | Plombier debouchage à Versailles | Intervention 24/7 |
| fuite | Paris | fuite/paris | Plombier fuite à Paris | Intervention 24/7 |
| chauffe-eau | Saint-Denis | chauffe-eau/saint-denis | Plombier chauffe-eau à Saint-Denis | Intervention 24/7 |
slug_pattern. Les patrons de titre, en revanche, conservent les majuscules et accents pour rester naturels en SERP.Hiérarchie parent / enfant
Le cocon SEO du Labo du Yeti repose sur une architecture à deux niveaux : un groupe parent et un ou plusieurs groupes enfants. Cette structure est matérialisée par le champ parent_id sur les groupes enfants et par le même champ sur les pages générées.
| Rôle | Nombre de variables | Exemple | Pages produites |
|---|---|---|---|
| Groupe parent | 1 variable | service | N pages parents (1 par service) |
| Groupe enfant | 2 variables ou plus | service + ville | N × M pages enfants |
Slugs composites
Les enfants héritent automatiquement du segment de slug de leur parent. Si la page parent debouchage a pour slug /debouchage, ses enfants auront pour slugs /debouchage/paris, /debouchage/versailles, etc. Cette composition est faite au moment du build pour garantir que l'URL physique reflète la hiérarchie sémantique.
Section « Voir aussi »
Chaque page parent peut afficher en bas de contenu une section « Voir aussi » (ou « Voir plus ») qui liste automatiquement les pages enfants associées, filtrées par la variable commune. La configuration de cette section est portée par le composant frontend RelatedSectionPanel et permet de régler :
- le layout (grille, liste, carrousel) ;
- le nombre d'items affichés et l'ordre (alphabétique, date, manuel) ;
- les couleurs (titre, fond, bordure, accent CTA) ;
- le libellé de la section et le texte de chaque card.
Cette configuration est stockée dans le groupe parent et appliquée au moment du rendu HTML par le pipeline de moteur HTML.
Quotas de génération
Pour éviter le spam IA et lisser le coût des appels Anthropic, chaque groupe possède un quota propre : un nombre maximum de pages générables sur une fenêtre glissante en jours. La valeur par défaut est 5 pages / 7 jours, modifiable via PUT /api/cocon/groups/:id/quota.
Le contrôle est centralisé dans backend/src/services/quota-service.js qui expose la méthode canGenerate(groupId). Elle est appelée avant chaque batch par la route POST /api/cocon/groups/:id/generate et retourne :
{
"allowed": true,
"remaining": 3,
"window_days": 7,
"max": 5,
"used": 2,
"next_slot_at": "2026-06-04T14:32:00.000Z"
}
Si allowed vaut false, l'API répond POST 429 avec la date du prochain créneau libre. L'endpoint GET /api/cocon/groups/:id/quota-status permet à l'UI d'afficher en temps réel l'état du compteur.
aiGenLimiter (10 générations IA par minute, toutes ressources confondues) qui protège l'API Anthropic d'un emballement global.Ordre parent → enfant strict
Une règle d'or structure tout le pipeline de cocon : les enfants ne peuvent pas être générés tant que les parents associés ne sont pas générés ET publiés. « Publiés » signifie ici qu'un build a effectivement été lancé via POST /api/build et que le HTML statique des parents existe dans public/.
- L'admin crée le groupe parent (1 variable) puis lance la génération.
- L'admin déclenche un build du site pour figer les pages parents.
- Le module cocon débloque automatiquement le groupe enfant correspondant.
- L'admin peut alors générer les pages enfants par lots (en respectant le quota).
Ce verrouillage évite deux pièges classiques : des liens internes « Voir aussi » qui pointent vers des parents inexistants, et des cocons enfants orphelins en cas d'abandon de campagne. Côté API, toute tentative de générer un enfant sans parent buildé répond 409 Conflict avec un message explicite.
UI Programmation
L'écran Programmation de la sidebar Contenu → Cocon SEO est le tableau de bord centralisé. Il combine deux blocs :
- une matrice quota par groupe qui rend visibles d'un coup d'œil les compteurs
used / max, la fenêtre glissante et la date du prochain créneau libre ; - un état du pipeline par cocon, qui montre si le groupe parent est généré, buildé, et combien d'enfants restent à produire.
Cette UI consomme GET /api/cocon/groups/:id/quota-status et GET /api/cocon/groups/:id/generation-progress. La progression IA est diffusée par polling : le service backend met à jour un compteur en mémoire à chaque appel terminé.
Notifications email de créneaux
Pour ne jamais « oublier » un créneau de génération, le module notification-service.js envoie automatiquement un rappel email aux utilisateurs concernés 5 minutes après chaque créneau libéré. La constante SLOT_NOTIFICATION_ROLES = ['admin', 'webmaster'] contrôle qui reçoit ces notifications.
| Rôle | Reçoit les rappels de créneau | Justification |
|---|---|---|
owner | Non (par défaut) | Le owner reste libre, il peut s'abonner manuellement. |
admin | Oui | Pilote opérationnel du cocon. |
webmaster | Oui | Responsable du build et de la mise en ligne. |
editor | Non | Pas la main sur la programmation des batches. |
Le mail est envoyé via la configuration SMTP gérée dans Réglages → Général et utilise les helpers de backend/src/lib/datetime.js pour afficher l'heure du prochain créneau en français.
Médiathèque cocon dédiée
Le cocon SEO possède sa propre médiathèque, distincte de la médiathèque globale du CMS. Elle est portée par les routes GET/POST/PUT/DELETE /api/cocon/media et persistée dans cocon.media.
Ses images sont réutilisables dans tous les groupes : une fois uploadée, une image peut servir d'illustration aux pages d'un groupe Plombier comme à celles d'un groupe Électricien. C'est utile pour les visuels génériques (icônes service, photos d'équipe, illustrations de réassurance) qui n'ont pas besoin d'être contextualisés par ville.
RelatedSectionPanel
Le composant frontend RelatedSectionPanel est l'éditeur visuel de la section « Voir aussi ». Il s'affiche en latéral droit lors de l'édition d'une page parent de cocon et permet de configurer :
- Layout : grille 2/3/4 colonnes, liste verticale, carrousel horizontal ;
- Items : nombre affiché, tri (alpha, date, manuel), filtre par variable commune ;
- Couleurs : titre de section, fond de card, bordure, accent de CTA, hover ;
- Textes : libellé de la section, gabarit de titre de card (avec
{{var}}), libellé du CTA.
La configuration est sérialisée dans le groupe parent et propagée à toutes ses pages au build. La règle de sécurité du builder s'applique : seuls les styles « sûrs » (couleur, alignement, gras/italique) sont éditables, le HTML structurel reste figé pour préserver le SEO.
Récapitulatif API
| Méthode | Route | Usage |
|---|---|---|
| GET | /api/cocon/groups | Liste les groupes |
| POST | /api/cocon/groups | Crée un groupe + upload du template |
| GET | /api/cocon/groups/:id/combinations | Prévisualise la matrice cartésienne |
| GET | /api/cocon/groups/:id/quota-status | État du quota (used/max/remaining) |
| PUT | /api/cocon/groups/:id/quota | Modifie le quota du groupe |
| POST | /api/cocon/groups/:id/generate | Lance un batch de génération IA (rate limit 10/min) |
| GET | /api/cocon/groups/:id/generation-progress | Suit l'avancée d'un batch en cours |
| DELETE | /api/cocon/groups/:id/pages | Supprime toutes les pages générées du groupe |
| GET | /api/cocon/media | Médiathèque cocon dédiée |