Aller au contenu
Webcosa Développeurs

#Journal des changements

Ce que la plateforme a gagné, perdu ou corrigé, à la date où c’est arrivé. Les entrées sont tirées de l’historique du dépôt, pas d’une feuille de route : chacune correspond à du code qui tourne.

#Ce que ce journal couvre

Trois choses, et rien d’autre :

  • le format des thèmes — ce qu’un thème peut lire, écrire et rendre ;
  • le CLI — ses commandes, ses options, ses confirmations ;
  • l’API HTTP — ses routes, ses portées, ses codes d’erreur.

Ce qui bouge dans le CMS lui-même — l’interface, la facturation, l’assistant — n’y figure que si un développeur peut s’en apercevoir depuis son éditeur.

Il n’y a pas de numéros de version

Webcosa est un service : il n’existe qu’une version en ligne, celle d’aujourd’hui. Un thème n’épingle donc pas une version du format, et il n’y a rien à mettre à jour. En contrepartie, ce journal est le seul endroit qui dise ce qui a changé sous les pieds d’un thème déjà écrit — les entrées marquées rupture sont celles qui demandent une action.

#5 octobre 2026

Aucune rupture. Un thème qui ne déclare ni templates/blog.json ni templates/article.json — c’est le cas des huit thèmes d’origine — rend exactement comme avant, blog compris.

#Des sections écrites par Cosa

L’éditeur de thème sait faire écrire par Cosa une section que le thème n’a pas. Elle arrive dans le thème comme un fichier sections/genere-<nom>.liquid, ouvert par un commentaire de provenance, aux styles tous rangés sous #cosa-{{ section.id }} et sans JavaScript. Rien ne change pour un thème existant ; si tu en trouves un dans un thème que tu maintiens, c’est une section comme une autre. Voir Les sections.

#Le blog, rendu par le thème

Deux gabarits de plus, au modèle de Shopify : templates/article.json rend un article (/blog/<blog>/<article>), templates/blog.json les listes (/blog et /blog/<blog>). Avec eux, deux objets : article — titre, extrait, adresse, image, date, contenu et son blog — et blog — titre, description, adresse, articles, blogs. Ils n’existent que sur ces vues.

Jusqu’ici, le blog était toujours servi dans la page de la plateforme : sans l’en-tête, le menu, le pied ni les polices du thème. C’est encore le cas quand le gabarit manque, et il n’y a pas de repli sur page.json : c’est le fichier qui décide. Voir Les templates.

#L’éditeur de code du CMS souligne ce qui casse en silence

« Modifier le code » d’un thème passe à un vrai éditeur : complétion des objets, des filtres et des tags que le moteur connaît — et des id du {% schema %} après section.settings., des réglages globaux après settings., des snippets après {% render ' —, multi-curseur, repli, mise en forme du JSON.

Il vérifie pendant qu’on tape, avec la même analyse qu’à l’enregistrement, et signale ce que le moteur laisse passer sans un mot : un filtre ou un objet de Shopify (les absents), un réglage lu mais jamais déclaré, un snippet ou une section qui n’existe pas, 'assets/theme.css' | asset_url, un type de réglage inconnu, un <script> en ligne, une police ou une image d’un autre domaine. Rien ne change pour un thème déjà écrit : ce sont des avertissements, et l’enregistrement ne refuse toujours que les erreurs de syntaxe (les fichiers).

L’assistant du CMS s’y ouvre aussi : il explique un fichier, corrige un problème souligné ou modifie une sélection, et propose chaque changement en différence, à accepter morceau par morceau. Il n’écrit et n’enregistre rien lui-même.

#Les photos retaillées gardent leurs proportions

Depuis le 1er octobre, les photos de la médiathèque servies en plusieurs largeurs (srcset) étaient recadrées en une tranche verticale, puis étirées : elles paraissaient zoomées sur un détail. Elles sont de nouveau réduites à leurs proportions d’origine. Rien à changer dans un thème.

#Les liens internes d’un article

Dans article.contenu, un lien vers une autre page du site (une adresse qui commence par /) est désormais un lien ordinaire. Il sortait en rel="noopener nofollow" et dans un nouvel onglet, comme un lien externe : Google ne suivait pas le maillage interne de l’article. Les liens vers d’autres sites, eux, ne changent pas.

#Les robots d’IA et llms.txt, site par site

Chaque site client sert désormais un /llms.txt : sa fiche (adresse, téléphone, horaires de Paramètres › Coordonnées), ses pages publiées et ses articles, aux adresses canoniques. Il répond 404 si le site est protégé par un code, masqué des moteurs ou sans page publiée.

Son robots.txt ne change pas d’un octet tant que le client laisse la plateforme décider. Depuis l’écran Agentique du CMS, il peut fermer ChatGPT, Perplexity, Claude, Gemini ou l’entraînement des modèles : leurs robots reçoivent alors un groupe Disallow: / à part, et les autres continuent de lire User-agent: *. Côté API, l’onglet ia de /api/parametres/<onglet> porte ce réglage — voir Atelier. Rien à changer dans un thème : ces fichiers sont posés par la plateforme, comme le plan du site.

Le même jour, le llms.txt s’est enrichi de ce que le client écrit dans l’écran Agentique : son métier (une ligne Activité), la date de la dernière mise à jour du contenu (Mis à jour le : AAAA-MM-JJ), et une section ## Questions fréquentes — ses questions-réponses validées, une ### par question, placée avant les listes de liens. Aucune n’y entre sans sa validation, et rien de tout cela ne paraît sur ses pages : pour les montrer, il pose une section de questions fréquentes — qui donne alors aussi à la page ses données structurées FAQPage, puisqu’elles y sont visibles. Rien à changer dans un thème.

#siAbsent : écrire un fichier sans jamais en écraser un

PUT /api/themes/<id>/fichiers accepte un champ facultatif siAbsent. Avec lui, un chemin déjà pris par un autre contenu répond 409 fichier_existe, et le même contenu répond 200 sans rien écrire. Sans lui, rien ne change : le PUT remplace. C’est ce qu’emploie Cosa pour ajouter une section à un thème. Voir Fichiers.

#garde : n’écrire que sur ce qu’on a lu

PATCH /api/menus et PATCH /api/parametres/<onglet> remplacent l’objet entier. Ils acceptent désormais un champ facultatif garde: { site, majLe } — l’identifiant du site visé et l’updated_at lu avant d’écrire (null si l’objet n’existait pas). Si le site courant n’est pas celui-là, la route répond 409 autre_site ; si l’objet a changé depuis, 409 modifie_entre_temps — et rien n’est écrit. Sans garde, rien ne change. C’est ce qu’emploient les propositions de Cosa, qui peuvent être confirmées longtemps après avoir été calculées. Voir Atelier.

#Du 7 au 11 août 2026

Aucune rupture. Tout ce qui suit est un ajout : un thème écrit avant ces dates rend exactement comme avant, et n’a rien à reprendre.

#Les polices, servies par la plateforme

10 août. Un quatorzième type de réglage, font_picker. Sa valeur est l’identifiant d’une famille du catalogue de la plateforme — dix-neuf, servies depuis /polices/ — ou systeme, qui n’en télécharge aucune. Le thème nomme une police, il ne la transporte pas : assets/ n’accepte toujours que .css et .svg.

Deux filtres maison vont avec, et il faut les deux.

layout/theme.liquid — Origoliquid
<style>
  {{ settings.police_titres | font_face }}
</style>

{%- assign pile_titres = settings.police_titres | font_famille -%}
--titre-police: {% if pile_titres != blank %}{{ pile_titres }}{% else %}var(--texte-police){% endif %};

font_face écrit la règle @font-face — le fichier, les graisses, font-display: swap ; font_famille rend la pile complète, la famille puis son repli système. Un identifiant hors catalogue rend une chaîne vide, jamais une erreur — et c’est par là que passe systeme : le thème teste != blank et pose le repli qu’il veut, comme ci-dessus.

#Les éditions

7 août avec Aplomb, généralisées le 11. config/theme.json accepte un tableau editions : plusieurs habillages complets du même thème, chacun ne posant que des valeurs de réglages — jamais une structure, jamais une section, jamais un gabarit. Depuis le 11 août, une édition peut aussi déclarer les metiers auxquels elle va, ce qui relie l’habillage au contenu dans l’aperçu du Store. Le tableau editions lui-même reste facultatif : un thème sans édition s’installe avec ses réglages par défaut, comme avant. Voir Ajouter un thème au catalogue.

#Quatre thèmes d’origine de plus

Aplomb le 7 août, puis Cadence, Épure et Scène le 10. Le catalogue en compte huit.

#5 août 2026

La journée où la plateforme est devenue programmable. Tout ce qui suit est arrivé le même jour, dans cet ordre.

#Les thèmes Liquid

Un site peut désormais être rendu par un thème au format Shopify plutôt que par les composants React du CMS. Six dossiers, layout/theme.liquid comme coquille, des sections déclarées par un bloc {% schema %}, et des templates JSON qui les composent.

L’arborescence admise
layout/     .liquid
sections/   .liquid
snippets/   .liquid
assets/     .css .svg
config/     .json
templates/  .json

Les deux moteurs cohabitent, et c’est délibéré. Un site qui a un thème publié passe par Liquid ; tous les autres continuent exactement comme avant. Aucun site en ligne n’a changé d’apparence ce jour-là — c’est ce qui a permis d’installer les thèmes sans fenêtre de maintenance. Voir l’anatomie d’un thème.

#Quatre thèmes d’origine

Origo d’abord : trente-cinq sections, sept gabarits de page, et de quoi tout régler sans toucher au code — couleurs, typographie, arrondi, largeur, densité. C’est le thème que reçoit tout le monde. Puis Forge, Vela et Piazza, plus typés.

Ils ont été renommés le jour même : leurs premiers noms étaient français et ne se prononçaient nulle part ailleurs. Un thème est un objet de catalogue, il voyage.

#page.demande — remercier sans JavaScript

Le formulaire de contact des thèmes postait dans le vide : il avait l’air de marcher et n’enregistrait rien. Il enregistre maintenant, et la page se rend à nouveau avec un objet de plus :

sections/contact.liquidliquid
{% if page.demande == 'merci' %}
  <p class="merci">Merci, votre message est parti.</p>
{% elsif page.demande == 'erreur' %}
  <p class="erreur">L’envoi a échoué. Réessayez dans un instant.</p>
{% endif %}

La valeur est lue dans la chaîne de requête après la redirection. C’est ce qui permet à une section de remercier sans une ligne de script — et c’est cohérent avec le refus du .js dans assets/.

#Le bac à sable prend ses bornes

Un thème s’exécute sur le serveur qui rend aussi les sites de tous les autres. Quatre bornes sont posées : rendu plafonné à 3 secondes, source analysée à 512 Ko, objets créés à 10⁸, imbrication de sections à 6 niveaux.

Deux détails valent d’être connus, parce qu’ils viennent de défauts réels :

  • les 3 secondes sont appliquées deux fois. Une simple course contre un minuteur ne coupait rien : un rendu synchrone bloque le fil d’exécution de Node, donc le minuteur ne s’exécutait jamais ;
  • le compteur de profondeur vit dans une fermeture, hors de portée du thème. Tant qu’il vivait dans le contexte Liquid, {% assign _profondeur = 0 %} suffisait à le remettre à zéro — un compteur qui surveille du code ne doit pas être écrit par ce code.

Le détail complet est sur la page du bac à sable.

#asset_url ne trouvait aucune feuille de style

Rupture — c’est le correctif qui demande peut-être une action de ta part.

Le filtre ajoutait le segment assets/ à l’adresse qu’il produisait, alors que la route des fichiers de thème n’en veut pas :

Adresse produite
Avant/theme-assets/<id>/assets/theme.css — 404
Après/theme-assets/<id>/theme.css

La route est /theme-assets/<id>/<fichier>, un seul segment de nom, et c’est elle qui remet le préfixe assets/ pour interroger la base. Conséquence : aucun site sur thème Liquid n’avait jamais chargé sa feuille de style depuis que les thèmes existaient. Le défaut ne levait aucune erreur — la page rendait quand même, en HTML nu, ce qui ressemble à un thème mal écrit plutôt qu’à une adresse fausse.

Ce qu’il faut vérifier dans tes thèmes

asset_url prend le nom seul du fichier, jamais son chemin.

liquid
{{ 'theme.css' | asset_url | stylesheet_tag }}

Si un thème écrit {{ 'assets/theme.css' | asset_url }}, il fabrique maintenant une adresse à deux segments qui ne correspond à aucune route : retire le préfixe. Voir la page des assets.

#Le CLI

scripts/theme.mjs transporte les fichiers d’un thème entre un dossier local et un site. Node 20.13 ou plus, aucune dépendance, un seul fichier qu’on peut copier ailleurs que dans ce dépôt.

node scripts/theme.mjs connexionnode scripts/theme.mjs recuperer --theme=Atelier --dossier=~/themes/ateliernode scripts/theme.mjs suivre

Six commandes — connexion, lister, recuperer, pousser, suivre, publier — chacune avec un alias anglais. Trois garde-fous qui n’ont pas été ajoutés après coup :

  • pousser signale les fichiers distants absents en local, il ne les supprime pas. --supprimer les retire, après les avoir listés et demandé confirmation ;
  • recuperer liste les fichiers locaux divergents avant de les écraser ;
  • suivre refuse un thème publié sans --oui-je-sais, et propose de le dupliquer.

Il n’y a pas de serveur d’aperçu local, et il n’y en aura pas : la raison tient en trois paragraphes. Référence complète des commandes sur cette page.

#Les clés d’API

Le CLI ne connaît pas les cookies du navigateur : il s’authentifie avec une clé, créée dans le CMS sous Paramètres → Clés d’API. Deux portées seulement — lecture pour lire, themes pour tout.

Le secret (wc_ suivi de 43 caractères) ne s’affiche qu’une fois. La base n’en garde que l’empreinte : personne, pas même nous, ne peut le rendre. Une clé perdue se révoque et se remplace.

Le site visé se désigne par l’en-tête X-Webcosa-Site-Cible. Le suffixe -Cible n’est pas décoratif : X-Webcosa-Site, sans lui, est un en-tête que le proxy pose lui-même et purge de toute requête entrante. L’envoyer revient à ne rien envoyer, et à écrire dans le premier site venu. Voir l’authentification.

#L’éditeur de code, dans le CMS

Les fichiers d’un thème s’éditent aussi depuis le navigateur, avec la coloration syntaxique et le refus de supprimer les trois fichiers indispensables (layout/theme.liquid, templates/index.json, config/settings_schema.json).

C’est le chemin du dépannage, pas celui du travail quotidien : le CLI garde ton Git, tes raccourcis et ton éditeur. Les deux écrivent dans la même table.

#Le Store prend son adresse

Le catalogue des thèmes vit désormais sur store.webcosa.com, servi par le même déploiement mais sur son propre hôte — et ouvert aux moteurs de recherche. Ajouter un thème au catalogue passe par le guide dédié ; rien n’y monte automatiquement depuis un site.

#Cette documentation

dev.webcosa.com : les pages de référence et les guides, la recherche en ⌘K, et un bouton « Copier la page » qui rend le markdown de la page pour le coller dans un assistant.

Deux écarts ont été relevés en l’écrivant, et documentés tels quels plutôt que corrigés en silence :

theme_basecommentaire de code

Le commentaire annonçait une base /t/<theme> ; la vraie base est /theme-assets/<id>, et /t/… n’existe nulle part. C’est la première ligne qu’on lit en enquêtant sur un 404 d’asset_url — elle envoyait chercher une route absente.

TAILLE_MAX524288

Comparé à la longueur de la chaîne, donc à des unités de code UTF-16, pas à des octets. Un fichier plein d’accents passe la barre un peu plus tard qu’un ls -l ne le laisse croire. Sans conséquence pratique : la borne existe pour arrêter une archive malveillante, pas pour discipliner une feuille de style.

#Avant le 5 août 2026

Rien à signaler ici, et c’est exact : il n’y avait pas de surface développeur. Les sites étaient rendus par les composants React du registre du CMS, réglés depuis l’éditeur visuel. Aucun thème, aucun Liquid, aucune API publique, donc rien qu’un thème écrit aujourd’hui puisse regretter.

Ces sites-là existent toujours et continuent de rendre comme avant. C’est ce que recouvre l’expression « les deux moteurs » dans le reste de la documentation : un site passe par Liquid le jour où on lui publie un thème, jamais avant.

Astuce

Tu as trouvé un comportement qui contredit une page de cette documentation ? C’est un défaut, et il se corrige dans les deux sens — soit le code, soit la page. Écris à bonjour@webcosa.com avec l’adresse de la page.