Files
decision/CLAUDE.md
T
YvvandClaude Opus 5.5 94907afb20 v3 : points de la relecture indépendante — une personne une voix, ordre de déploiement, durcissements
- Dans Monnaie libre (électorat = toile de confiance), seuls les membres de la
  toile votent (trustin_access::votes_in) ; une identité d'invitation y lit,
  propose et signale. L'interface le dit à la place des boutons (fr/en/es).
- Un lien d'invitation ne vise jamais une identité Ğ1 ; le lien est réservé
  avant de créer l'identité (deux acceptations simultanées : une seule passe).
- Un nombre n'est jamais une coquille (« 50 » → « 5,0 », « 1 5 » → « 15 »).
- Redirection après connexion : caractères de contrôle refusés.
- En-têtes : X-Frame-Options DENY, frame-ancestors 'none', nosniff, Referrer-Policy.
- Déploiement : le produit passe en premier ; la maquette attend son succès.
  Les conteneurs, même arrêtés, qui revendiquent encore la racine sortent de
  « restart: always » (ils reviendraient au redémarrage de Docker).
- Tests : 57 Rust (dont 14 scénarios d'API), e2e 12 / 12 avec C11.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 04:23:51 +02:00

101 lines
6.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# libreDecision
Rendre possible la décision collective — en fonction du contexte, processus et modalités,
boîte à outils. **v3 : Rust + Svelte**, un chantier à la fois, chacun livré en production avant
le suivant (`docs/chantiers/README.md`).
**Référence du chantier en cours : `docs/chantiers/acte-certification/CHANTIER.md`** — toute
décision de comportement s'y adosse ; les décisions durables dans `docs/adr/`.
La maquette v2 (Nuxt + FastAPI) vit dans `maquette/`, **intacte** (Yvv la présente) — ne pas y
développer.
## Protocole de début de session
1. `git pull --rebase origin main` (puis la branche du chantier : `chantier/acte-certification`)
2. Lire `HANDOFF.md` (où on en est, ce qui attend Yvv)
3. Si l'objectif de la session n'est pas précisé, le demander
## Stack
- **Serveur** : Rust edition 2024, toolchain **1.99** épinglée (`rust-toolchain.toml`) ;
rustup installé sans PATH → `export PATH=$HOME/.cargo/bin:$PATH`. axum 0.8, sqlx 0.8
(SQLite, requêtes runtime + `migrate!`), tokio, reqwest rustls.
- **Interface** : SvelteKit 2 / Svelte 5 (runes), adapter-static SPA, vite 7, vitest,
Playwright ; npm. Polices Literata (textes) + Nunito (interface), fontsource.
- **Ports** : dev interface **3002** (strict, proxy `/api` → 8002) · serveur **8002** ·
serveur jetable des e2e **8092**.
- **Déploiement** : une image (`docker/app.Dockerfile`), Woodpecker `ci.open.us.org` dépôt
LPK/decision → sonic (fabio). `.woodpecker/app.yml` = le produit sur
**decision.librodrome.org** ; `.woodpecker/maquette.yml` = la maquette sur
**maquette.decision.librodrome.org** (le produit passe en premier et retire de la racine tout conteneur qui la revendique ; la maquette attend un déploiement réussi du produit).
Push sur `prod` (`gitea@git.open.us.org:EHV/decision.git`) branche `main` = déploiement.
## Structure
```
crates/
ld-engine/ # PUR (zéro I/O) : threshold (formule inertielle, presets), edit (coquille vs fond,
# diff), assist (découpage, similarité, longueur), compose (adoption, aperçus)
trustin-access/ # règles d'accès de trustinWallet : sees / opens / manages_access, groupes par défaut
ld-server/
migrations/ # schéma SQLite — additif seulement
src/ # lib.rs (routes, csrf, run) · config.rs (LD_*) · auth.rs (connect OAuth2, invitations,
# dev, bootstrap) · docs.rs (lecture, aperçus) · proposals.rs (écrire, voter, signaler,
# traduire) · adoption.rs (balayage, verrou) · publish.rs (file → git) · wot.rs (W
# sur la chaîne) · seed.rs · web.rs (sert web/build)
tests/api.rs # scénarios bout en bout
seeds/ # acte-engagement-certification.json (trilingue, 33 articles, I1/E1/E2 en vigueur)
web/src/
lib/i18n/ # fr.ts SOURCE (types Key) · en.ts · es.ts — parité testée
lib/components/ # Sidebar, DocPanel, VoteView, ProposeView, UnitBlock, DeepList, Seal, Stamp…
routes/ # / · connexion · invitation · groupes · g/[group] · g/[group]/docs/[doc] (lecteur,
# panneau dans l'URL ?onglet=&article=) · acces (trustinWallet) · decisions/mandats/
# protocoles (à venir)
web/e2e/ # Playwright C1–C11 + M1 ; serve.sh = serveur jetable /tmp/ld-e2e sur :8092
docker/ # app.Dockerfile · app-compose.yml (sonic)
.woodpecker/ # app.yml · maquette.yml
docs/ # chantiers/ · adr/ · dev/BLUEPRINT-V2.md (doctrine de la maquette) · recherche/
maquette/ # v2 intacte (frontend Nuxt, backend FastAPI, docker, docs-v1)
```
## Données runtime — jamais écrasées
- **Production** : volume `lpk-libredecision-app_data` (`/data` : `libredecision.db`, `textes/`
= clone du dépôt publié, `keys/` = clé de publication, `bootstrap-admin.txt`). Jamais
`down -v`, jamais recréé.
- **Maquette** : volumes `lpk-decision-main_postgres-data` / `_ipfs-data` (inchangés).
- **Local** : `data/` (gitignoré) — le supprimer repart du seed. Les e2e utilisent `/tmp/ld-e2e`.
- Un document seedé n'est **jamais** réinstancié : dès qu'il existe en base, c'est de la donnée.
## Commandes — la boucle (tout vert = fait)
```bash
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 && npm test && npm run build && npm run e2e # e2e : 12 contrôles
LD_DEV_LOGIN=1 cargo run -p ld-server # :8002, sert web/build
cd web && npm run dev # :3002 à chaud
docker build -f docker/app.Dockerfile --target production . # rejoue toute la boucle
```
## Conventions / pièges
- **UI français, code anglais** ; **trilingue** : aucune chaîne affichée en dur, tout passe par
`web/src/lib/i18n/fr.ts` puis en/es (test de parité + `FORBIDDEN_UI_TERMS`). Tutoyer ; le sujet
est la personne ou le groupe, jamais le système. Le français du texte voté fait foi.
- **Moteur pur** : une règle de vote / édition / composition s'écrit et se teste dans
`ld-engine` avant d'être câblée. Le serveur ne décide jamais l'accès seul : `trustin-access`.
- **Invariants** : une seule voix ne fait jamais passer un texte (C = 50 pour Monnaie libre) ;
une coquille ne demande pas de vote, un changement de fond si ; un signalement de
contradiction bloque ; l'inertie se vote au cran au-dessus ; le groupe d'essai ne publie jamais.
- **Écritures** : en-tête `x-requested-with: libredecision` obligatoire (CSRF) ; cookie
`ld_session`. Les tests d'API passent par `Client` (`tests/api.rs`).
- **Pièges vus** : `pkill -f target/debug/ld-server` tue son propre shell → `pkill -x ld-server` ;
un `from_secret` absent fait refuser tout le pipeline Woodpecker ; la route hôte `/*` de fabio
masque le webroot ACME → arrêter le service avant `acme.sh --issue` ; Playwright en locale
`fr-FR` (sinon l'interface part en anglais).
- **Design** : sans bordures, arrondis 16/12/20/14, ambiances `pierre` / `nuit`
(`data-mood`, posé avant le premier rendu), sceau hexagramme 井 #48 en SVG (`Seal`, `Stamp` —
jamais le glyphe, qui s'affiche mal). Mouvement réduit respecté.
- **Domaine** : decision.librodrome.org ; dépôt des textes `git.duniter.org/Yvv/libredecision-textes`.