Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a6ba0a6662 | ||
|
|
23b1767e67 | ||
|
|
852a4881a6 | ||
|
|
1c7cc455ab |
@@ -2,17 +2,30 @@
|
|||||||
|
|
||||||
Site vitrine du projet Le Librodrome — livre + chansons sur l'économie du don.
|
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
|
## Protocole de début de session
|
||||||
|
|
||||||
1. `git pull --rebase origin main` (récupère les commits admin git sync YAML prod)
|
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
|
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
|
3. Si l'objectif de la session n'est pas précisé, le demander
|
||||||
|
|
||||||
## Stack
|
## Stack
|
||||||
|
|
||||||
- Nuxt 4 (Vue 3, TypeScript, Nitro) + Nuxt Content, Pinia, UnoCSS, VueUse, Nuxt Image
|
- Nuxt 4 (Vue 3, TypeScript, Nitro) + Nuxt Content, Pinia, UnoCSS, VueUse, Nuxt Image
|
||||||
- Icônes : Lucide + Phosphor (via @iconify-json) ; Package manager : pnpm
|
- Layer `@yvv/nuxt-base` (`extends` dans `nuxt.config.ts`, dépendance `git+https` épinglée `#v0.1.0`)
|
||||||
- Déploiement : Docker + Traefik, CI via Woodpecker
|
- 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
|
## Structure
|
||||||
|
|
||||||
@@ -56,6 +69,12 @@ docker/
|
|||||||
- Structure message : `{ id, author, email, text, type, published, createdAt, reply: { text, publishedAt } | null }`
|
- 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`
|
- Types : `reaction` (ancien, affiché "Réaction", plus proposé dans les formulaires) | `question` | `suggestion` | `retour`
|
||||||
- En dev local : `<racine>/data/messages.yml`
|
- En dev local : `<racine>/data/messages.yml`
|
||||||
|
- Graine : `site/messages.yml` (versionné) copié par `server/plugins/seed-messages.ts`
|
||||||
|
si `data/messages.yml` est absent
|
||||||
|
- ⚠ Constat du 26/10/2026 : l'image tourne dans `/app` (WORKDIR depuis `07bf07a`) et
|
||||||
|
résout `data/` depuis `process.cwd()`, alors que le compose monte `/src/data` et
|
||||||
|
`/src/public`. La persistance en prod n'est donc pas assurée par la config ; effet
|
||||||
|
sur le serveur non vérifié (voir HANDOFF).
|
||||||
- **Avant toute migration de chemin ou écriture sur data/ : demander confirmation**
|
- **Avant toute migration de chemin ou écriture sur data/ : demander confirmation**
|
||||||
|
|
||||||
## Intégration GrateWizard
|
## Intégration GrateWizard
|
||||||
@@ -67,7 +86,12 @@ docker/
|
|||||||
|
|
||||||
- YAML dans `site/pages/` par section ; API supporte les chemins imbriqués
|
- YAML dans `site/pages/` par section ; API supporte les chemins imbriqués
|
||||||
- Admin : `/admin/pages` liste, `/admin/pages/{path}` édite en YAML
|
- Admin : `/admin/pages` liste, `/admin/pages/{path}` édite en YAML
|
||||||
- Git sync auto en prod (`ADMIN_GIT_SYNC=true`) → d'où le `git pull --rebase` obligatoire en début de session
|
- 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
|
## Commandes
|
||||||
|
|
||||||
@@ -77,6 +101,50 @@ pnpm build # Build production
|
|||||||
PORT=3099 node .output/server/index.mjs # Test build prod (toujours avant commit)
|
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
|
## Conventions
|
||||||
|
|
||||||
- CSS via UnoCSS + variables CSS palettes ; composants Vue SFC `<script setup lang="ts">`
|
- CSS via UnoCSS + variables CSS palettes ; composants Vue SFC `<script setup lang="ts">`
|
||||||
|
|||||||
+46
@@ -0,0 +1,46 @@
|
|||||||
|
# HANDOFF — librodrome
|
||||||
|
|
||||||
|
## REPRISE — bascule quota 2026-09-29 14h05
|
||||||
|
|
||||||
|
**Fait, en production** (librodrome.org, déployé et vérifié ; armé par Yvv) :
|
||||||
|
- `67cd869` : refonte. Accueil = console des trois curseurs, seul accueil
|
||||||
|
(`app/components/home/HomeLanding.vue`, `HomeConsole.vue`,
|
||||||
|
`useHomeData.ts`) ; § Playfair (`UiSectionSign`) ; statuts
|
||||||
|
(`UiStatusBadge`) ; LaPlanK, sweetHome, bouquet aligné sur les stacks
|
||||||
|
HCO/LaPlanK ; correctifs du lecteur (pastille, MP3 direct).
|
||||||
|
- `90f77da` : image OG et favicon avec le §, logo JSON-LD corrigé.
|
||||||
|
- Local, non poussé : `1c7cc45` (compte rendu d'acte), `852a488` (ce HANDOFF)
|
||||||
|
et la fusion fiche + boucle dans `CLAUDE.md` du 26/10/2026 ; doc seule, part
|
||||||
|
avec le prochain déploiement. Dossiers : `actes/2026-09-29-*.md`.
|
||||||
|
|
||||||
|
**Prochaine action** : aucune en cours. Attendre les retours d'Yvv sur la prod.
|
||||||
|
|
||||||
|
**Décisions en attente d'Yvv** :
|
||||||
|
- Qui opère cloud.laplank.org : `vision.md` dit LaPlanK, la fiche sweetHome
|
||||||
|
dit warren. Le site suit Yvv (LaPlanK).
|
||||||
|
- Twenty, ERPNext et budgetPilot sont affichés « en service » dans le bouquet
|
||||||
|
public alors qu'ils servent HCO en interne. Les garder ou passer « au catalogue » ?
|
||||||
|
- Ambiance par défaut « été » (crème + terre cuite) : proposer une autre ?
|
||||||
|
- Lien « Mentions légales » du pied de page → page inexistante (défaut antérieur).
|
||||||
|
- Persistance de la prod (constat du 26/10/2026, d'après les fichiers ; non
|
||||||
|
vérifié sur le serveur) : voir `CLAUDE.md`, § Données runtime et § Contenu
|
||||||
|
administrable. Si l'effet se confirme, chaque déploiement repart d'un conteneur
|
||||||
|
neuf : messages visiteurs re-semés depuis `site/messages.yml`, éditions /admin
|
||||||
|
perdues. Rétablir les montages (`/app/...`) et décider du sort du git sync
|
||||||
|
touche aux données de prod : à trancher par Yvv avant le prochain déploiement.
|
||||||
|
|
||||||
|
**Ce qui tourne** : rien (serveur de dev sur 3000 arrêté).
|
||||||
|
|
||||||
|
**Pièges** :
|
||||||
|
- Pousser `main` = mise en ligne sans test → mot « déploie », dossier dans `actes/`.
|
||||||
|
- `git pull --rebase` avant toute modification (le YAML de prod est édité via /admin).
|
||||||
|
- Serveur de dev : après des suppressions ou renommages de composants, le SSR
|
||||||
|
reste périmé (faux mismatch d'hydratation) → relancer `pnpm dev`.
|
||||||
|
- Chromium de Playwright MCP absent : utiliser le chromium bundlé
|
||||||
|
`~/.cache/ms-playwright/chromium-1208` + playwright-core
|
||||||
|
(`/tmp/bp-design/node_modules`). Scripts jetables dans `/tmp/lbshot/`.
|
||||||
|
- Le BookPlayer ferme sur Échap après une animation de sortie de 0,35 s :
|
||||||
|
attendre avant d'asserter.
|
||||||
|
- Statuts : champ YAML `status` (+ `since`), qui prime sur `gestation: true`.
|
||||||
|
- Libellés de la console dans `home.yml > console` ; titre de la boîte à
|
||||||
|
outils dans `home.yml > toolbox`.
|
||||||
@@ -9,7 +9,7 @@ fichiers orphelins ; corriger l'URL du logo JSON-LD (404).
|
|||||||
|
|
||||||
## Commandes exactes
|
## Commandes exactes
|
||||||
```bash
|
```bash
|
||||||
git push origin <SHA de ce commit>:main
|
git push origin 90f77da49b1c77faf9807ba48740b0abd22aff46:main
|
||||||
```
|
```
|
||||||
|
|
||||||
## Contenu sortant
|
## Contenu sortant
|
||||||
@@ -26,5 +26,7 @@ git revert --no-edit HEAD~1 && git push origin HEAD:main
|
|||||||
```
|
```
|
||||||
|
|
||||||
## Vérifications post-acte
|
## Vérifications post-acte
|
||||||
- [ ] og:image en prod = /og-default.png?v=2, fichier servi 200 et identique au local
|
**Exécuté le 2026-09-29** : `67cd869..90f77da -> main`, prod à jour en ~160 s.
|
||||||
- [ ] favicon.ico et favicon.svg servis 200
|
|
||||||
|
- [x] og:image en prod = `https://librodrome.org/og-default.png?v=2` ; JSON-LD logo idem ; fichier servi 200, identique octet pour octet au local
|
||||||
|
- [x] favicon.ico (identique) et favicon.svg servis 200
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ services:
|
|||||||
- "3000:3000"
|
- "3000:3000"
|
||||||
- "4000:4000"
|
- "4000:4000"
|
||||||
- "24678:24678"
|
- "24678:24678"
|
||||||
volumes:
|
# !override : en dev, data/ vient des sources montées, pas du volume de prod.
|
||||||
|
volumes: !override
|
||||||
- sources:/app
|
- sources:/app
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
|
|||||||
@@ -17,8 +17,11 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- 3000
|
- 3000
|
||||||
volumes:
|
volumes:
|
||||||
- ../data:/src/data
|
# Données runtime (messages des visiteurs). L'image tourne dans /app et
|
||||||
- ./public:/src/public
|
# le serveur lit process.cwd()/data : le volume se monte sur /app/data.
|
||||||
|
# Volume nommé, pas un chemin relatif : la CI lance compose depuis son
|
||||||
|
# espace de travail, où un chemin relatif désigne un dossier vide de l'hôte.
|
||||||
|
- data:/app/data
|
||||||
restart: always
|
restart: always
|
||||||
labels:
|
labels:
|
||||||
- "traefik.enable=true"
|
- "traefik.enable=true"
|
||||||
@@ -26,3 +29,12 @@ services:
|
|||||||
- "traefik.http.routers.librodrome.entrypoints=websecure"
|
- "traefik.http.routers.librodrome.entrypoints=websecure"
|
||||||
- "traefik.http.routers.librodrome.tls.certresolver=letsencrypt"
|
- "traefik.http.routers.librodrome.tls.certresolver=letsencrypt"
|
||||||
- "traefik.http.services.librodrome.loadbalancer.server.port=3000"
|
- "traefik.http.services.librodrome.loadbalancer.server.port=3000"
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
# Créé à la main sur le serveur avant le premier déploiement (acte du
|
||||||
|
# 2026-10-26). external : compose ne le crée ni ne le supprime jamais
|
||||||
|
# (`down -v` compris), et un déploiement sans lui échoue au lieu de
|
||||||
|
# repartir de la graine.
|
||||||
|
data:
|
||||||
|
name: librodrome-data
|
||||||
|
external: true
|
||||||
|
|||||||
Reference in New Issue
Block a user