v3 : déploiement (image unique, produit à la racine, maquette en sous-domaine) et documentation du chantier

- docker/app.Dockerfile : une image Rust + Svelte, la construction rejoue toute
  la boucle (fmt, clippy -D warnings, tests, svelte-check, vitest) ; utilisateur
  non-root, volume /data. docker/app-compose.yml pour sonic (fabio).
- .woodpecker/app.yml : produit sur decision.librodrome.org, attend la maquette,
  écarte tout conteneur qui revendique encore la racine, healthcheck du commit.
- .woodpecker/maquette.yml (ex .woodpecker.yml) : la maquette v2 telle quelle,
  sur maquette.decision.librodrome.org, mêmes volumes.
- .env.example de la maquette rangé dans maquette/ ; celui de la v3 à la racine.
- Docs : README, CONTRIBUTING (travail à deux), CLAUDE.md v3, HANDOFF,
  docs/chantiers (feuille de route, fiche, contrôles, onboarding de Chiara,
  demande à poka), docs/adr 0001–0006.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Yvv
2026-10-21 03:50:44 +02:00
co-authored by Claude Opus 5.5
parent c2669a3d0b
commit 1f9c241b41
24 changed files with 1187 additions and 281 deletions
+52 -80
View File
@@ -1,91 +1,63 @@
# Contribuer à libreDecision
La référence produit est `docs/dev/BLUEPRINT-V2.md` — toute contribution qui touche au
comportement doit s'y conformer (ou proposer un amendement du blueprint, argumenté).
On travaille **un chantier à la fois**, livré complet et en production avant le suivant
(`docs/chantiers/README.md`). Le chantier en cours a sa fiche :
`docs/chantiers/acte-certification/CHANTIER.md` — toute décision de comportement s'y adosse,
ou propose de l'amender, argumentée.
## Environnement
Première fois ? Commence par `docs/chantiers/acte-certification/ONBOARDING.md`.
## Les branches — travailler à deux
```
main = la production. Tout push sur prod/main déploie decision.librodrome.org.
chantier/acte-certification = la branche commune du binôme (Yvv · Chiara), toujours verte.
chiara/<sujet>, yvv/<sujet> = une branche courte par sujet, partie de la branche du chantier.
```
1. `git switch chantier/acte-certification && git pull --rebase origin chantier/acte-certification`
2. `git switch -c chiara/<sujet>` — un sujet, une branche, quelques commits.
3. Boucle verte (ci-dessous), puis push de la branche et demande de fusion vers
`chantier/acte-certification` sur la forge (`git.open.us.org/yvv/decision`).
4. Le chantier passe dans `main` quand la boucle est verte et les contrôles d'usage passés.
On ne pousse jamais directement sur `main`, et jamais de `--force` sur une branche partagée.
## La boucle — une tâche n'est faite que si tout est vert
```bash
# Frontend — suffit pour tout le développement v2 (local-first, aucun serveur requis)
cd frontend
npm install
npm run dev # http://localhost:3002 — port strict, jamais de fallback
npm test # vitest — 342 tests
npm run build # doit passer sans erreur avant tout commit
# Backend v1 (optionnel — conservé pour la future synchro)
cd backend
python -m venv venv && source venv/bin/activate
pip install -r requirements.txt
export PATH=$HOME/.cargo/bin:$PATH
cargo fmt --all --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace
cd web
npm run check # svelte-check, zéro avertissement
npm test # vitest : markdown, parité des catalogues i18n, anti-lexique
npm run build
npm run e2e # Playwright : C1–C10 (bureau) + M1 (mobile), serveur jetable sur :8092
```
L'image Docker rejoue les mêmes portes : un contrôle rouge, pas d'image, pas de déploiement.
## Conventions
- **UI en français, code en anglais** (variables, commentaires, docstrings).
- **`app/lexicon.ts` est la source unique des libellés français.** Aucun libellé UI en dur
dans un composant s'il existe (ou devrait exister) dans le lexicon. Ton : tutoyer la
personne dans ses gestes ; actes collectifs à l'infinitif ; le sujet grammatical est
toujours la personne ou le collectif — jamais la formule ni le système.
- **Test anti-lexique** (`tests/lexicon.spec.ts`) : la liste `FORBIDDEN_UI_TERMS` interdit
certains mots dans toute chaîne visible (lexicon + templates `.vue`), insensible à la casse
et aux accents. « Triage », « verdict », « déléguer »… peuvent exister comme identifiants de
code, jamais à l'écran.
- **CSS** : borderless (profondeur via background + box-shadow), palettes par classes
`.mood-*` sur `<html>`, composants natifs (`<input>`, `<select>`, `<button>` custom).
- **Composants** : `pathPrefix: false` — noms de fichiers uniques et parlants, auto-import.
- **Interface en français, code en anglais** (identifiants, commentaires, messages de log).
- **Trilingue dès le départ** : toute chaîne affichée vit dans `web/src/lib/i18n/fr.ts`
(la source), puis `en.ts` et `es.ts`. Le test de parité refuse une clé manquante ou un
paramètre `{x}` qui diffère. Le texte voté est le français ; les traductions sont éditoriales.
- **Ton** : tutoyer la personne ; le sujet est la personne ou le collectif, jamais le système.
Mots interdits à l'écran (`FORBIDDEN_UI_TERMS`) : « triage », « verdict », « déléguer »…
- **Moteur pur** : `crates/ld-engine` n'a ni I/O, ni base, ni réseau. Toute règle de vote,
d'édition ou de composition s'y écrit et s'y teste d'abord.
- **Accès** : le serveur ne décide jamais seul qui voit quoi — il demande à `trustin-access`.
- **Données runtime** (`data/`, volume `lpk-libredecision-app_data`) : jamais écrasées, jamais
réinitialisées ; une migration ajoute, elle ne réécrit pas.
- **Design** : sans bordures (profondeur par fond et ombre), arrondis 16 / 12 / 20 / 14 px,
deux ambiances (pierre, nuit), Literata pour les textes, Nunito pour l'interface.
- **Commits** : en français, une intention par commit, `git add` avec chemins explicites.
## Invariants doctrinaux (non négociables)
## Signaler
- **Jamais de score sur une personne.** Pas de note, pas de réputation, pas d'agrégat
individuel. `Person.attributes` ne sont jamais affichés à autrui ni agrégés ; l'historique
de re-vote n'est visible que de son auteur.
- **Jamais de contenu adopté sans geste humain.** Le moteur constate des seuils sur des
contenus formulés par des humains ; la cristallisation paramétrique, la clôture d'un
dossier découpé, le départage d'une égalité sont des gestes datés — jamais des automatismes.
- **Le repli universel est le consentement** : tout collectif a un protocole Consentement
(`protocolByRange.consent`), tout repli de résolution y mène.
- **Dérogation asymétrique** : alourdir libre (1 tap journalisé) ; alléger = note obligatoire
+ fenêtre d'objection.
- **Budget 400 lignes maximum par page** (`app/pages/`). Au-delà, extraire des composants.
- **Moteurs purs** : `app/engine/` ne dépend de rien (ni Nuxt, ni Pinia, ni DOM), s'importe
uniquement via le barrel `~/engine`, et chaque module a ses tests vitest. Les stores
s'écrivent avec des imports explicites (pas d'auto-import Nuxt) pour rester testables sous
vitest pur.
## Ajouter une modalité de vote
1. `app/types/domain.ts` — étendre `VoteMethod` et les types de session/vote nécessaires.
2. `app/engine/` — le calcul dans un module pur + ses tests (`tests/engine/`). Exporter via
`engine/index.ts`.
3. `app/engine/state.ts` — la règle de clôture (automatique à `closesAt`, ou geste humain).
4. `app/lexicon.ts` — les libellés (et vérifier l'anti-lexique).
5. `app/components/votes/VoteX.vue` — l'écran de la modalité, branché dans
`pages/decisions/[id]/vote.vue`.
6. Seeds et gabarits — un protocole nommé qui la référence (le modifier = amender le Pacte).
## Ajouter un gabarit de collectif
Dans `app/data/templates.ts` : une entrée `TEMPLATE_CARDS` + le montage dans
`buildTemplateBundle()`. Invariants : protocole Consentement au minimum, clause A1
(« Notre finalité »), préambule Autonomie–Équilibre–Liaison proposé et modifiable, cercles
typés `kind`. Un bundle seed passe par le même `importBundle()` que l'import utilisateur.
## Tests
```bash
cd frontend && npm test
```
- `tests/engine/` — les moteurs purs (seuils, triage, états, médiane, impact…).
- `tests/stores/` — la façade decisions sous Pinia nu.
- `tests/seeds/` — tests de non-perte : le bundle Ğ1 doit conserver 33+59 clauses, décomptes
et provenance exacts ; l'Atelier du Canal doit couvrir tous les états.
- `tests/lexicon.spec.ts` — l'anti-lexique.
Le compteur de référence est **342 tests verts**. Toute PR qui en casse un est refusée ;
toute fonctionnalité de moteur arrive avec les siens.
## Build
`npm run build` doit rester vert (zéro erreur, zéro warning nouveau) avant chaque commit.
Vérifier mobile + desktop (zéro régression CSS).
**« Faire un retour »** (dans le menu de gauche, sur chaque page) envoie une note datée avec la
page, la langue et la taille de l'écran ; elles se lisent dans trustinWallet (`/acces`).
Pour un bug reproductible, une issue sur la forge avec les étapes.