11 KiB
Librodrome
Site vitrine du projet Le Librodrome — livre + chansons sur l'économie du don.
- Rôle : site éditorial en production sur
librodrome.orget hub d'intégration de l'écosystème (GrateWizard en popup ; liens libreDecisiondecision.librodrome.org, SejeteralO, sweetHome/LaPlanK dans le YAML desite/). Cap : plateforme éditoriale de bassin de vie (autonomie collective, économie monnaie libriste, boîte à outils, événementiel). - Port : 3000 (dev), 3099 (smoke du build). Dépôt :
origin=gitea@git.open.us.org:EHV/librodrome.git;main= production.
Protocole de début de session
git pull --rebase origin main(règle canon ; voir § Contenu administrable)- Vérifier que
data/messages.ymlexiste — si absent, signaler avant toute opération - Si l'objectif de la session n'est pas précisé, le demander
Stack
- Nuxt 4 (Vue 3, TypeScript, Nitro) + Nuxt Content, Pinia, UnoCSS, VueUse, Nuxt Image
- Layer
@yvv/nuxt-base(extendsdansnuxt.config.ts, dépendancegit+httpsépinglée#v0.1.0) - Icônes : Lucide + Phosphor (via @iconify-json) ; pnpm épinglé 10.29.3 (
packageManager) - Audience : Umami (
nuxt-umami) - Déploiement : Woodpecker (
.woodpecker.yml) — push surmain→docker compose -f docker/docker-compose.yml -f docker/docker-compose.fabio.yml up --build -d, sans étape de test. Secrets CI :NUXT_ADMIN_PASSWORD,NUXT_ADMIN_SECRET. Healthcheck de l'image :/api/health.
Structure
app/
pages/
numerique/ # index + [slug]
economique/ # index, monnaie-libre, commande, productions-collectives
modele-eco/ # sommaire + chapitres [slug]
citoyenne/ # index + [slug]
en-musique/ # player audio
admin/ # back-office (pages/, book/, songs, messages, media)
components/
book/Actions.vue # boutons partagés (player, PDF, chapitres, commande)
home/ # BookSection, AxisBlock, AxisGrid, HeroSection, HomeMessages
admin/, player/, song/, ui/
composables/ # useAudioPlayer, useBookData, useGrateWizard, usePageContent
stores/palette.ts # 4 palettes saisonnières (été par défaut, persisté localStorage)
assets/css/main.css # UnoCSS + overrides light mode
site/
pages/ # Contenu YAML administrable par section (sous-dossiers)
site.yml # Config globale (nav, footer, GrateWizard)
bookplayer.config.yml # Config player/chapitres
data/
messages.yml # Runtime — prod : volume nommé librodrome-data sur /app/data — JAMAIS dans git
server/
api/content/ # GET pages YAML (chemins imbriqués)
api/admin/content/ # PUT pages YAML + liste
api/messages/ # GET (publiés) + POST (nouveau message)
api/admin/messages/ # GET tous + PUT (type, reply, published) + DELETE
utils/content.ts # readDataYaml/writeDataYaml (data/) + readYaml/writeYaml (site/)
middleware/redirects.ts # 301 : /gestation, /modele-eco, /decision, /lire
docker/
Dockerfile, docker-compose.yml, docker-compose.dev.yml
Données runtime (CRITIQUE)
data/messages.yml: en prod, volume nommélibrodrome-data(external: true) monté sur/app/data(l'image tourne dans/app, le serveur litprocess.cwd()/data). Créé et semé à la main sur sonic par l'acteactes/2026-10-26-persistance-messages.md; un déploiement sans ce volume échoue au lieu de repartir de la graine.- Persisté entre les rebuilds depuis le 26/10/2026 — jamais écrasé par les commits ni par le déploiement (avant, il ne l'a jamais été : voir le dossier d'acte)
- Structure message :
{ id, author, email, text, type, published, createdAt, reply: { text, publishedAt } | null } - Types :
reaction(ancien, affiché "Réaction", plus proposé dans les formulaires) |question|suggestion|retour - En dev local :
<racine>/data/messages.yml - Graine :
site/messages.yml(versionné) copié parserver/plugins/seed-messages.tssidata/messages.ymlest absent - ⚠ Hors volume, rien ne persiste : éditions /admin de
site/etcontent/, médias envoyés par /admin (/app/public, jamais servis). Décisions d'Yvv en attente (HANDOFF). - Avant toute migration de chemin ou écriture sur data/ : demander confirmation
Intégration GrateWizard
- URL dev :
app/app.config.ts→localhost:3001 - URL prod :
https://gratewizard.axiom-team.fr
Contenu administrable
- YAML dans
site/pages/par section ; API supporte les chemins imbriqués - Admin :
/admin/pagesliste,/admin/pages/{path}édite en YAML - Git sync (
server/utils/gitSync.ts, actif siADMIN_GIT_SYNC=true) : commit[admin] …puis push depuis le conteneur →git pull --rebaseobligatoire en début de session - ⚠ Constat du 26/10/2026 : la CI ne fixe pas
ADMIN_GIT_SYNC(défautfalsedans le compose), l'image de prod n'embarque pas.git, et l'historique ne contient aucun commit[admin]. Les éditions /admin en prod ne reviennent donc pas dans git (voir HANDOFF).
Commandes
pnpm dev # Dev server :3000
pnpm build # Build production
PORT=3099 node .output/server/index.mjs # Test build prod (toujours avant commit)
Vérifier
Niveaux V0 à V4 : gabarit harness/skills/boucles/_gabarit.md. Seuls V0 et V3 existent :
aucun test automatisé, ni lint ni typecheck (aucun script, pas de vue-tsc).
V0 — build + smoke (vert le 26/10/2026, build ≈ 1 min)
date; pnpm build # exit 0
NUXT_ADMIN_PASSWORD=jetable NUXT_ADMIN_SECRET=jetable PORT=3099 node .output/server/index.mjs &
sleep 3; for p in / /api/health /api/admin/messages; do
curl -s -o /dev/null -w "$p %{http_code}\n" http://127.0.0.1:3099$p; done # 200, 200, 401
kill $(lsof -ti :3099)
Lancé depuis la racine, le serveur lit et écrit le vrai data/ : aucun POST pendant le
smoke. Le build ne lit pas .env : sans NUXT_ADMIN_SECRET, l'API admin répond 503.
V1 — invariants (à construire) : vitest sur les API messages (POST/GET/DELETE),
admin content (PUT YAML → fichier écrit, format préservé), auth (mauvais mot de passe →
401). data/ et site/ se résolvent depuis process.cwd() : lancer depuis un dossier jetable.
V2 — parcours (à construire) : Playwright, chromium bundlé (HANDOFF, Pièges), mobile +
desktop, ambiances claire et sombre : accueil sans erreur console, les 3 axes, lecteur PDF,
player, formulaire message (data jetable), login admin. Captures dans /tmp/librodrome-shots/.
V3 — données
sha256sum data/messages.yml # avant et après le run : identiques
git status --short # rien sous data/ ni .env
git log --oneline origin/main..HEAD # ce que le prochain push mettrait en ligne
V4 : rapport avec sorties réelles et captures ; tout niveau sauté est annoncé.
Trous : la CI déploie sans gate (un commit cassé part en prod) ; V1 et V2 inexistants.
Prochaines briques : gate build + tests dans .woodpecker.yml avant le up, puis V1 et V2
exposés en pnpm verify.
Gates humains (anneau 1) : push de main (= mise en ligne) ; suppressions admin
(server/api/admin/messages/[id].delete.ts, media/[...path].delete.ts,
chapters/[slug].delete.ts) ; toute écriture sous site/ ou content/book/ (contenu de
prod) ; data/messages.yml ; lien de commande du livre (Bookelis,
site/pages/economique/commande.yml, aucun paiement sur le site) ; auth admin
(server/middleware/admin-auth.ts) et secrets NUXT_ADMIN_*.
Conventions
- Consignes d'Yvv, datées et mot pour mot :
docs/consignes-yvv.md. Les relire avant de toucher au design ; y inscrire toute nouvelle consigne le jour où elle est donnée. - CSS via UnoCSS + variables CSS palettes ; composants Vue SFC
<script setup lang="ts"> - Oiseaux du kit du studio DA (depuis le 03/11/2026, à la place des shadoks) :
UiOiseau,app/utils/oiseaux.ts(copiés tels quels du kit), posés parUiOiseauPoseprès du contenu de leur métier, jamais en rangée. Règles du kit : currentColor, au moins 72 px, opacité 0,18–0,28 près du texte et 0,10–0,14 derrière une carte, un oiseau jamais deux fois sur une page, un seul sous 768 px, pas de miroir pour calligraphe et typographe. Consignes :docs/consignes-yvv.md§ Les oiseaux. - Hexagramme 益 (#42 Yi, Augmentation) dans
layouts/default.vue - Logotype validé du studio DA (
UiLogotype) dansTheHeader.vue, etUiSectionSigndu kit — ne pas modifier sans demander. Source du kit :/home/yvv/Documents/PROD/IMAGES/_atelier/2026-10-27-librodrome-logo/livrables/kit-site/.
SEO & Recherche IA — Checklist permanente
À chaque nouvelle page Vue
- Appeler
useSeoPage()— jamaisuseHead({ title })seuluseSeoPage({ title: 'Titre page — Le Librodrome', // 50–60 chars description: 'Description...', // 120–155 chars image: '/images/og-specifique.jpg', // optionnel, sinon og-default.png (logo §) type: 'website' | 'article' | 'book', // défaut: website }) - og:image : utiliser la couverture
/images/Couv-Economie-du-don.jpgpour les pages livre/musique ;og-default.png(logo §) pour les pages site générales - type: 'article' pour les chapitres du modele-eco ; type: 'book' pour les index livre
À chaque nouveau fichier YAML dans site/pages/
Ajouter le bloc seo: en tête :
seo:
title: "Titre SEO — 50-60 chars max"
description: "Description 120-155 chars, avec mots-clés naturels"
# image: /images/og-specifique.jpg # optionnel
# keywords: [monnaie libre, TRM, économie du don]
Règles description SEO
- Commence par un verbe d'action ou une affirmation forte
- Contient les mots-clés : économie du don, monnaie libre, TRM, June, bassin de vie, autonomie
- 120–155 caractères (ni trop court, ni tronqué)
- Différente du titre et du H1
JSON-LD automatique
- JSON-LD
Organization+Book: injecté globalement dansapp.vue— ne pas redupliquer - Chapitres → og:type
articleviauseSeoPage({ type: 'article' }) - Sitemap : géré par
@nuxtjs/sitemap— ajouter manuellement les nouvelles routes statiques dansnuxt.config.ts > sitemap.urls
Analytics — Nouveaux composants
- Tout bouton CTA externe :
trackCta(label, url)depuisuseTracking() - Tout
<a target="_blank">: capturé automatiquement paruseScrollTracking()dansdefault.vue - Tout nouveau lecteur média : appeler
trackAudioPlay/trackPdfOpendepuisuseTracking()