# Librodrome Site vitrine du projet Le Librodrome — livre + chansons sur l'économie du don. - **Rôle** : site éditorial en production sur `librodrome.org` et hub d'intégration de l'écosystème (GrateWizard en popup ; liens libreDecision `decision.librodrome.org`, SejeteralO, sweetHome/LaPlanK dans le YAML de `site/`). 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 1. `git pull --rebase origin main` (règle canon ; voir § Contenu administrable) 2. Vérifier que `data/messages.yml` existe — si absent, signaler avant toute opération 3. 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` (`extends` dans `nuxt.config.ts`, dépendance `git+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 sur `main` → `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 lit `process.cwd()/data`). Créé et semé à la main sur sonic par l'acte `actes/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 : `/data/messages.yml` - Graine : `site/messages.yml` (versionné) copié par `server/plugins/seed-messages.ts` si `data/messages.yml` est absent - ⚠ Hors volume, rien ne persiste : éditions /admin de `site/` et `content/`, 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/pages` liste, `/admin/pages/{path}` édite en YAML - Git sync (`server/utils/gitSync.ts`, actif si `ADMIN_GIT_SYNC=true`) : commit `[admin] …` puis push depuis le conteneur → `git pull --rebase` obligatoire en début de session - ⚠ Constat du 26/10/2026 : la CI ne fixe pas `ADMIN_GIT_SYNC` (défaut `false` dans 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 ```bash 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) ```bash 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** ```bash 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 - CSS via UnoCSS + variables CSS palettes ; composants Vue SFC `