v3 : socle Rust (moteur pur, accès trustinWallet, serveur) ; maquette Nuxt rangée dans maquette/

- crates/ld-engine : formule inertielle (parité avec la maquette, garde C),
  coquille / changement de fond, assistant d'édition à règles, composition
  d'un document sous vote permanent (adoptions, aperçus, rivales).
- crates/trustin-access : qui voit, qui ouvre, qui gère les accès.
- crates/ld-server : API axum + SQLite, connexion Ğ1 (client OAuth2 de
  connect.monnaie-libre.fr), invitations, entrée en vigueur automatique,
  signalements de contradiction, traductions éditoriales, publication git,
  taille de la toile lue sur la chaîne.
- seeds/acte-engagement-certification.json : 33 articles, fr + en + es ;
  en vigueur : préambule, E1, E2 (seed a minima).
- maquette/ : frontend, backend et docker v2 déplacés tels quels.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Yvv
2026-10-21 02:04:42 +02:00
co-authored by Claude Opus 5.5
parent 4b1732916d
commit 67ddee28b2
275 changed files with 8979 additions and 0 deletions
+65
View File
@@ -0,0 +1,65 @@
---
title: Documentation technique
description: Architecture, API et reference technique de libreDecision
---
# Documentation technique
Bienvenue dans la documentation technique de libreDecision, la plateforme de decisions collectives pour la communaute Duniter/G1.
## Presentation
libreDecision est une plateforme de gouvernance decentralisee qui permet aux membres de la Toile de Confiance (WoT) Duniter V2 de gerer des documents de reference modulaires sous vote permanent, prendre des decisions collectives multi-etapes, attribuer des mandats et archiver de maniere immuable les resultats via IPFS et la blockchain Duniter.
## Stack technique
| Couche | Technologie |
| ------------ | -------------------------------------------------- |
| Frontend | Nuxt 4 + Nuxt UI v3 + Pinia + UnoCSS |
| Backend | Python FastAPI + SQLAlchemy 2.0 (async) + Pydantic v2 |
| Base de donnees | PostgreSQL 16 (asyncpg) |
| Authentification | Duniter V2 Ed25519 challenge-response |
| Sanctuaire | IPFS (kubo) + hash on-chain (system.remark) |
| CI/CD | Woodpecker CI + Docker + Traefik |
| Temps reel | WebSocket pour les mises a jour de vote en direct |
## Historique des sprints
| Sprint | Contenu principal | Statut |
| ------ | ----------------- | ------ |
| Sprint 1 | Architecture, modeles de base (documents, items, versions, identites, protocoles, formules), API documents et authentification | Termine |
| Sprint 2 | Sanctuaire (IPFS + on-chain), gestion complete des items (CRUD, reorder), verification d'integrite, archivage de documents | Termine |
| Sprint 3 | Systeme de vote complet (sessions, votes signes, seuil WoT, criteres Smith/TechComm), meta-gouvernance, simulateur de formules, WebSocket temps reel | Termine |
| Sprint 4 | Decisions multi-etapes (workflow, avancement, vote lie), mandats (candidature, election, assignation, revocation), vote nuance | Termine |
| Sprint 5 | Stabilisation, documentation complete, deploiement production, audit securite | En cours |
## Version et statut
- **Version** : 1.0.0-rc
- **Statut** : Release candidate -- Sprint 5 (documentation et stabilisation)
- **Depot** : [git.duniter.org/tools/libredecision](https://git.duniter.org/tools/libredecision)
## Sections
### Architecture et conception
- [Architecture](/dev/architecture) -- Vue d'ensemble de l'architecture, stack, flux de communication
### Reference technique
- [Reference API](/dev/api-reference) -- Tous les endpoints REST et WebSocket avec schemas
- [Schema de base de donnees](/dev/database-schema) -- Tables, colonnes, relations et diagramme
### Domaines fonctionnels
- [Formules](/dev/formulas) -- Formules mathematiques de seuil WoT, criteres Smith/TechComm, simulateur, meta-gouvernance
- [Integration blockchain](/dev/blockchain-integration) -- Duniter V2 RPC, IPFS, ancrage on-chain
### Operations
- [Deploiement](/dev/deployment) -- Docker, Traefik, migrations, sauvegarde, mise a jour, troubleshooting
- [Securite](/dev/security) -- Authentification, integrite des votes, rate limiting, en-tetes, audit
### Contribution
- [Guide de contribution](/dev/contributing) -- Installation locale, conventions, tests, processus de contribution
@@ -0,0 +1,239 @@
# Spike : Moteur de workflow — Protocole Embarquement Forgerons
**Date** : 2026-03-02
**Statut** : Spike / Pré-étude
**Auteur** : Yvv + Claude
---
## Contexte : deux objets distincts
L'app a déjà deux concepts qui se côtoient dans "Protocoles" :
| Objet | Ce que c'est | Exemple |
|-------|-------------|---------|
| **VotingProtocol** | Règle de vote (formule, seuils, critères) | "Vote forgeron (Smith)" — D30M50B.1G.2S.1 |
| **Decision + Steps** | Processus multi-étapes (one-shot) | "Runtime Upgrade" — 5 étapes séquentielles |
Il manque un **troisième** objet : le **Protocole opérationnel réutilisable** — un template de workflow qui s'instancie pour chaque candidat/cas.
### Exemple : Embarquement Forgerons
Ce n'est pas une décision ponctuelle. C'est un **processus répétable** :
```
[Candidat] ──invite──▶ [Invitation on-chain]
│
◀──accept──
│
──setSessionKeys──▶ [Preuve technique]
│
┌──checklist aspirant (aléatoire, avec pièges)
│
├──certif smith 1 (checklist certificateur)
├──certif smith 2 (checklist certificateur)
└──certif smith 3 (checklist certificateur)
│
──goOnline──▶ [Autorité active]
```
Chaque étape a :
- Un **acteur** (candidat, certificateur, système)
- Des **prérequis** (étapes précédentes complétées)
- Une **preuve** (on-chain tx, checklist complétée, vote)
- Un **délai** (optionnel)
---
## Volume croissant prévisible
| Protocole opérationnel | Acteurs | Instances/an estimées |
|----------------------|---------|----------------------|
| Embarquement Forgerons | candidat + 3 certifieurs | ~10-50 |
| Embarquement Membre (Certification) | certifié + 5 certifieurs | ~500-2000 |
| Runtime Upgrade | CoTec + forgerons + communauté | ~4-12 |
| Modification Document | proposeur + communauté | ~10-50 |
| Mandat (élection/révocation) | candidat + communauté | ~5-20 |
| Engagement CoTec | candidat + CoTec | ~2-5 |
**Observation clé** : l'Embarquement Membre est le plus massif et partage la même structure que l'Embarquement Forgeron (checklist + certifications multiples). L'architecture doit être pensée pour ce volume.
---
## Options évaluées
### Option A : n8n (workflow automation)
**n8n** est un outil d'automatisation visuel (self-hosted, open source).
| Pour | Contre |
|------|--------|
| Éditeur visuel de workflows | Dépendance externe lourde (~500 MB Docker) |
| Webhooks, triggers, crons intégrés | Latence réseau (appels HTTP entre services) |
| 400+ intégrations (email, matrix, etc.) | Pas de MCP server configuré actuellement |
| Pas de code à écrire pour l'orchestration | Pas de concept natif de "checklist aléatoire" |
| | Les preuves on-chain nécessitent du dev custom de toute façon |
| | La communauté Duniter refuse les dépendances centralisées |
**Verdict** : n8n est excellent pour les **automations périphériques** (notifications, alertes, reporting), pas pour le **cœur du workflow**. Le cœur doit rester dans l'app.
**Usage recommandé de n8n** : connecteur optionnel pour les triggers de notification (webhook quand une étape change de statut → email/matrix/telegram). Ne pas en faire le moteur.
### Option B : Dev maison — étendre Decision/DecisionStep
Étendre le modèle `Decision` existant avec un concept de **template**.
```python
class ProcessTemplate(Base):
"""Reusable workflow template (e.g. "Embarquement Forgeron")."""
id: UUID
slug: str # "embarquement-forgeron"
name: str # "Embarquement Forgerons"
description: str
category: str # "onboarding", "governance", "upgrade"
step_templates: JSON # Ordered list of step definitions
checklist_document_id: UUID # FK to Document (engagement forgeron)
voting_protocol_id: UUID # FK to VotingProtocol
is_active: bool
class ProcessInstance(Base):
"""One execution of a template (e.g. "Embarquement de Matograine")."""
id: UUID
template_id: UUID # FK to ProcessTemplate
candidate_id: UUID # FK to DuniterIdentity (le candidat)
status: str # invited, accepted, keys_set, checklist, certifying, online, failed
current_step: int
started_at: datetime
completed_at: datetime | None
metadata: JSON # on-chain tx hashes, certifier IDs, etc.
class ProcessStepExecution(Base):
"""One step within an instance."""
id: UUID
instance_id: UUID
step_order: int
step_type: str # "on_chain", "checklist", "certification", "manual"
actor_id: UUID | None # Who must act
status: str # pending, active, completed, failed, skipped
proof: JSON | None # tx_hash, checklist_result, vote_session_id
started_at: datetime | None
completed_at: datetime | None
```
| Pour | Contre |
|------|--------|
| Zéro dépendance externe | Plus de code à écrire |
| Contrôle total sur la checklist (ordre aléatoire, pièges) | Faut designer le moteur de transitions |
| Les preuves on-chain sont natives (substrate-interface) | Le workflow avancé (timeouts, escalation) sera simpliste |
| S'intègre avec le vote engine existant | |
| La DB track tout (audit trail complet) | |
| Volume OK avec PostgreSQL (100k instances/an = rien) | |
**Verdict** : c'est la voie naturelle. Le modèle actuel `Decision + Steps` est une version simplifiée de ça. On l'étend proprement.
### Option C : Temporal.io / autre moteur de workflow distribué
| Pour | Contre |
|------|--------|
| Garanties transactionnelles fortes | Énorme pour le use case (~GB de RAM) |
| Retry/timeout/escalation natifs | Cluster Temporal = infra supplémentaire |
| Bon pour les longs workflows (jours/semaines) | Surcharge conceptuelle |
| | Aucune intégration native blockchain |
**Verdict** : overkill. À considérer uniquement si on dépasse 10 protocoles actifs avec des centaines d'instances simultanées. Pas avant 2028.
---
## Recommandation
### Sprint 2 : Option B — Dev maison, progressif
**Phase 1** (Sprint 2) — Fondations :
1. Créer `ProcessTemplate` + `ProcessInstance` + `ProcessStepExecution`
2. Seed : template "Embarquement Forgerons" avec ses 7 étapes
3. Frontend : page `/protocols/embarquement-forgerons` avec timeline visuelle
4. API : `POST /processes/{template_slug}/start` → crée une instance
5. API : `POST /processes/instances/{id}/advance` → passe à l'étape suivante
**Phase 2** (Sprint 3) — Checklist interactive :
1. UI de checklist avec ordre aléatoire + détection pièges
2. Liaison avec le Document (engagement forgeron) pour les clauses
3. Signature Ed25519 du résultat de checklist (preuve cryptographique)
**Phase 3** (Sprint 4+) — On-chain :
1. Trigger on-chain via substrate-interface (invite, accept, certify, goOnline)
2. Listener d'événements blockchain pour compléter automatiquement les étapes on-chain
3. Optionnel : webhook n8n pour notifications matrix/telegram
### Architecture cible
```
┌─────────────────────────────────────────────────┐
│ Frontend │
│ /protocols/embarquement-forgerons │
│ ├── Vue template (timeline, étapes) │
│ ├── Checklist interactive (aléatoire + pièges) │
│ └── Instance dashboard (candidats en cours) │
└──────────────────┬──────────────────────────────┘
│ API REST
┌──────────────────▼──────────────────────────────┐
│ Backend │
│ ProcessService │
│ ├── create_instance(template, candidate) │
│ ├── advance_step(instance, proof) │
│ ├── evaluate_checklist(instance, answers) │
│ └── on_chain_trigger(instance, extrinsic) │
│ │
│ SubstrateService (substrate-interface) │
│ ├── smithsMembership.invite() │
│ ├── smithsMembership.acceptInvitation() │
│ ├── smithsMembership.setSessionKeys() │
│ └── authorityMembers.goOnline() │
└──────────────────┬──────────────────────────────┘
│ Events
┌──────────────────▼──────────────────────────────┐
│ n8n (optionnel) │
│ Webhook → Notification matrix/telegram/email │
│ Cron → Relance candidats inactifs │
└─────────────────────────────────────────────────┘
```
### Ce que n8n ne fait PAS (et qu'on doit coder) :
- Checklist aléatoire avec clause piège et interruption
- Signature Ed25519 du résultat
- Appels substrate-interface (invite, certify, goOnline)
- Calcul de seuil unani-majoritaire
- Intégrité du workflow (preuve on-chain de chaque étape)
### Ce que n8n PEUT faire (optionnel, sprint 4+) :
- Webhook → notification email quand un candidat arrive à l'étape "certification"
- Cron → rappel hebdo aux certificateurs qui n'ont pas agi
- Webhook → post forum automatique quand un forgeron est accepté
- Dashboard monitoring (combien de candidats en cours, taux de completion)
---
## Nomenclature proposée dans l'UI
| Menu | Sous-section | Contenu |
|------|-------------|---------|
| **Protocoles** | Protocoles de vote | VotingProtocol (binaire, nuancé, smith, techcomm) |
| | Simulateur de formules | FormulaConfig interactif |
| | **Protocoles opérationnels** | ProcessTemplate (embarquement, upgrade, etc.) |
| **Décisions** | (inchangé) | Decision + Steps (instances one-shot) |
Les protocoles opérationnels ont leur propre section dans `/protocols` avec :
- Carte par template (nom, description, nb d'instances actives)
- Page détail : timeline template + liste d'instances en cours
- Page instance : suivi temps réel d'un candidat spécifique
---
## Prochaine étape
Valider cette orientation avec Yvv, puis :
1. Créer les 3 tables (ProcessTemplate, ProcessInstance, ProcessStepExecution)
2. Migration Alembic
3. Seed le template "Embarquement Forgerons" (7 étapes)
4. Router + service backend
5. Frontend : page template + page instance
File diff suppressed because it is too large Load Diff
+81
View File
@@ -0,0 +1,81 @@
---
title: Architecture
description: Vue d'ensemble de l'architecture technique de libreDecision
---
# Architecture
## Vue d'ensemble
libreDecision est organise en monorepo avec trois composants principaux :
```
libreDecision/
backend/ # API Python FastAPI (port 8002)
frontend/ # Application Nuxt 4 (port 3002)
docker/ # Fichiers Docker et orchestration
docs/ # Documentation (Nuxt Content)
```
## Stack technique
| Couche | Technologie |
| ------------ | -------------------------------------------------- |
| Frontend | Nuxt 4 + Nuxt UI v3 + Pinia + UnoCSS |
| Backend | Python FastAPI + SQLAlchemy 2.0 (async) + Pydantic v2 |
| Base de donnees | PostgreSQL 16 (asyncpg) |
| Authentification | Duniter V2 Ed25519 challenge-response |
| Sanctuaire | IPFS (kubo) + hash on-chain (system.remark) |
| CI/CD | Woodpecker CI + Docker + Traefik |
## Domaines fonctionnels
L'application est decoupee en 5 domaines metier, chacun avec ses modeles, schemas, routes et services :
1. **Documents** -- Documents de reference modulaires (licence, engagements, reglement) composes d'items individuels versionnables.
2. **Decisions** -- Processus decisionnels multi-etapes (qualification, examen, vote, execution, rapport).
3. **Votes** -- Sessions de vote binaire ou nuance avec formule de seuil WoT, critere Smith et critere TechComm.
4. **Mandats** -- Mandats assignes a des membres (techcomm, forgeron, personnalise) avec cycle de vie complet.
5. **Protocoles** -- Configurations de formules de vote et protocoles de vote reutilisables.
Un domaine transversal, le **Sanctuaire**, assure l'archivage immuable via IPFS et ancrage on-chain.
## Principes d'architecture
- **Async everywhere** : toute la couche donnees et HTTP est asynchrone (asyncpg, AsyncSession, FastAPI async).
- **Separation modeles / schemas / routes / services** : chaque domaine suit ce decoupage strict.
- **API versionnee** : tous les endpoints sont sous `/api/v1/`.
- **Preuve cryptographique** : chaque vote est signe avec la cle Ed25519 du votant.
- **Vote permanent** : les documents de reference sont sous vote permanent, chaque item peut etre modifie par proposition et vote.
## Schema de communication
```
Navigateur
|
v
[Nuxt 4 Frontend] -- SSR/CSR, port 3000 (prod) / 3002 (dev)
|
v (fetch /api/v1/*)
[FastAPI Backend] -- port 8002
|
+---> [PostgreSQL 16] -- Donnees relationnelles
+---> [IPFS kubo] -- Stockage distribue (Sanctuaire)
+---> [Duniter V2 RPC] -- WoT, Smith, TechComm, system.remark
```
## Flux d'authentification
1. Le client envoie son adresse Duniter SS58 via `POST /api/v1/auth/challenge`.
2. Le serveur genere un challenge aleatoire (64 hex) et le stocke en memoire (TTL 5 min).
3. Le client signe le challenge avec sa cle privee Ed25519 et soumet via `POST /api/v1/auth/verify`.
4. Le serveur verifie la signature, cree ou retrouve l'identite `DuniterIdentity`, et retourne un token de session.
5. Le token est utilise en header `Authorization: Bearer <token>` pour les requetes authentifiees.
## Flux de vote
1. Un protocole de vote et sa formule sont crees ou selectionnes.
2. Une session de vote est creee avec un snapshot des tailles WoT/Smith/TechComm.
3. Les membres votent (binaire ou nuance) avec signature cryptographique.
4. A la cloture, le seuil WoT est calcule, les criteres Smith et TechComm sont verifies.
5. Le resultat (adopte/rejete) est archive dans le Sanctuaire (IPFS + on-chain).
+648
View File
@@ -0,0 +1,648 @@
---
title: Reference API
description: Liste des endpoints de l'API libreDecision
---
# Reference API
Tous les endpoints sont prefixes par `/api/v1`. L'API est auto-documentee via OpenAPI/Swagger a l'adresse `/docs` en mode debug.
## Authentification (`/api/v1/auth`)
| Methode | Endpoint | Description | Auth |
| ------- | ------------- | ----------------------------------------------------- | ---- |
| POST | `/challenge` | Generer un challenge Ed25519 pour une adresse Duniter | Non |
| POST | `/verify` | Verifier la signature du challenge et obtenir un token | Non |
| GET | `/me` | Retourner l'identite authentifiee courante | Oui |
| POST | `/logout` | Invalider la session courante | Oui |
## Documents (`/api/v1/documents`)
| Methode | Endpoint | Description | Auth |
| ------- | -------------------------------------- | ---------------------------------------- | ---- |
| GET | `/` | Lister les documents (filtres: doc_type, status) | Non |
| POST | `/` | Creer un nouveau document | Oui |
| GET | `/{slug}` | Obtenir un document par son slug | Non |
| PUT | `/{slug}` | Mettre a jour un document | Oui |
| POST | `/{slug}/items` | Ajouter un item au document | Oui |
| GET | `/{slug}/items` | Lister les items d'un document | Non |
| GET | `/{slug}/items/{item_id}` | Obtenir un item avec son historique | Non |
| PUT | `/{slug}/items/{item_id}` | Mettre a jour un item (titre, texte, position, type) | Oui |
| DELETE | `/{slug}/items/{item_id}` | Supprimer un item du document | Oui |
| POST | `/{slug}/items/{item_id}/versions` | Proposer une nouvelle version d'un item | Oui |
| GET | `/{slug}/items/{item_id}/versions` | Lister les versions d'un item | Non |
| PUT | `/{slug}/items/{item_id}/versions/{version_id}/accept` | Accepter une version proposee (applique le texte a l'item) | Oui |
| PUT | `/{slug}/items/{item_id}/versions/{version_id}/reject` | Rejeter une version proposee | Oui |
| PUT | `/{slug}/items/reorder` | Reordonner les items d'un document | Oui |
| POST | `/{slug}/archive` | Archiver le document dans le sanctuaire (hash SHA-256 + IPFS + on-chain) | Oui |
## Decisions (`/api/v1/decisions`)
| Methode | Endpoint | Description | Auth |
| ------- | ---------------- | ------------------------------------------------ | ---- |
| GET | `/` | Lister les decisions (filtres: decision_type, status) | Non |
| POST | `/` | Creer une nouvelle decision | Oui |
| GET | `/{id}` | Obtenir une decision avec ses etapes | Non |
| PUT | `/{id}` | Mettre a jour une decision | Oui |
| DELETE | `/{id}` | Supprimer une decision (brouillon uniquement) | Oui |
| POST | `/{id}/steps` | Ajouter une etape a une decision | Oui |
| POST | `/{id}/advance` | Avancer la decision a l'etape suivante | Oui |
| POST | `/{id}/steps/{step_id}/create-vote-session` | Creer une session de vote pour une etape | Oui |
## Votes (`/api/v1/votes`)
| Methode | Endpoint | Description | Auth |
| ------- | ------------------------------- | -------------------------------------------- | ---- |
| POST | `/sessions` | Creer une session de vote | Oui |
| GET | `/sessions` | Lister les sessions de vote (filtres: status, protocol_id, decision_id) | Non |
| GET | `/sessions/{id}` | Obtenir une session de vote | Non |
| POST | `/sessions/{id}/vote` | Soumettre un vote (signe) | Oui |
| GET | `/sessions/{id}/votes` | Lister les votes d'une session | Non |
| GET | `/sessions/{id}/result` | Calculer et retourner le resultat courant | Non |
| POST | `/sessions/{id}/close` | Cloturer la session et calculer le resultat final | Oui |
| GET | `/sessions/{id}/threshold` | Obtenir le detail du calcul de seuil (formule, parametres, valeurs intermediaires) | Non |
| POST | `/sessions/{id}/tally` | Forcer un recomptage des votes et recalcul du seuil | Oui |
## Mandats (`/api/v1/mandates`)
| Methode | Endpoint | Description | Auth |
| ------- | ----------------- | ---------------------------------------------- | ---- |
| GET | `/` | Lister les mandats (filtres: mandate_type, status) | Non |
| POST | `/` | Creer un nouveau mandat | Oui |
| GET | `/{id}` | Obtenir un mandat avec ses etapes | Non |
| PUT | `/{id}` | Mettre a jour un mandat | Oui |
| DELETE | `/{id}` | Supprimer un mandat (brouillon uniquement) | Oui |
| POST | `/{id}/steps` | Ajouter une etape a un mandat | Oui |
| GET | `/{id}/steps` | Lister les etapes d'un mandat | Non |
| POST | `/{id}/advance` | Avancer le mandat a l'etape suivante | Oui |
| POST | `/{id}/assign` | Assigner un mandataire au mandat | Oui |
| POST | `/{id}/revoke` | Revoquer un mandat actif | Oui |
| POST | `/{id}/steps/{step_id}/create-vote-session` | Creer une session de vote pour une etape | Oui |
## Protocoles (`/api/v1/protocols`)
| Methode | Endpoint | Description | Auth |
| ------- | ------------------- | -------------------------------------------------- | ---- |
| GET | `/` | Lister les protocoles de vote | Non |
| POST | `/` | Creer un protocole de vote | Oui |
| GET | `/{id}` | Obtenir un protocole avec sa configuration formule | Non |
| PUT | `/{id}` | Mettre a jour un protocole (meta-gouvernance) | Oui |
| GET | `/formulas` | Lister les configurations de formules | Non |
| POST | `/formulas` | Creer une configuration de formule | Oui |
| GET | `/formulas/{id}` | Obtenir une configuration de formule par son ID | Non |
| PUT | `/formulas/{id}` | Mettre a jour une configuration de formule (meta-gouvernance) | Oui |
| POST | `/simulate` | Simuler le calcul d'une formule avec des parametres arbitraires | Non |
## Sanctuaire (`/api/v1/sanctuary`)
| Methode | Endpoint | Description | Auth |
| ------- | --------------------------------- | ---------------------------------------------------------- | ---- |
| GET | `/` | Lister les entrees du sanctuaire (filtre: entry_type) | Non |
| GET | `/{id}` | Obtenir une entree du sanctuaire | Non |
| POST | `/` | Creer une entree (hash SHA-256, CID IPFS, TX on-chain) | Oui |
| GET | `/{id}/verify` | Verifier l'integrite d'une entree (recalcul SHA-256, verification IPFS et on-chain) | Non |
| GET | `/by-reference/{reference_id}` | Obtenir les entrees liees a une entite source par son UUID | Non |
## WebSocket (`/api/v1/ws`)
| Endpoint | Description |
| --------- | -------------------------------------------------------- |
| `/ws` | Connexion WebSocket pour notifications temps reel (votes, decisions) |
## Sante
| Methode | Endpoint | Description |
| ------- | -------------- | -------------------------- |
| GET | `/api/health` | Verification de sante (hors versionning) |
## Details des endpoints Sprint 2
### `PUT /api/v1/documents/{slug}/items/{item_id}` -- Mettre a jour un item
Met a jour les champs d'un item existant (titre, texte courant, position, type). Seuls les champs fournis sont mis a jour (mise a jour partielle).
**Corps de la requete** (tous les champs sont optionnels) :
```json
{
"title": "Nouveau titre",
"current_text": "Texte mis a jour...",
"position": "2.1",
"item_type": "rule"
}
```
**Reponse** : `200 OK` avec l'item mis a jour (`DocumentItemOut`).
---
### `DELETE /api/v1/documents/{slug}/items/{item_id}` -- Supprimer un item
Supprime un item d'un document. La suppression est en cascade : toutes les versions associees sont egalement supprimees.
**Reponse** : `204 No Content`.
---
### `GET /api/v1/documents/{slug}/items/{item_id}/versions` -- Lister les versions d'un item
Retourne l'historique complet des versions proposees pour un item, ordonne par date de creation decroissante.
**Parametres de requete** : `skip`, `limit` (pagination standard).
**Reponse** : `200 OK` avec une liste de `ItemVersionOut`.
---
### `PUT /api/v1/documents/{slug}/items/{item_id}/versions/{version_id}/accept` -- Accepter une version
Accepte une version proposee. Le texte propose remplace le texte courant de l'item. Toutes les autres versions en statut `proposed` ou `voting` pour cet item sont automatiquement rejetees.
**Reponse** : `200 OK` avec la version mise a jour (`ItemVersionOut`, statut `accepted`).
---
### `PUT /api/v1/documents/{slug}/items/{item_id}/versions/{version_id}/reject` -- Rejeter une version
Rejette une version proposee. Le texte courant de l'item reste inchange.
**Reponse** : `200 OK` avec la version mise a jour (`ItemVersionOut`, statut `rejected`).
---
### `PUT /api/v1/documents/{slug}/items/reorder` -- Reordonner les items
Modifie l'ordre d'affichage des items dans un document en mettant a jour le champ `sort_order` de chaque item.
**Corps de la requete** :
```json
{
"items": [
{ "item_id": "uuid-1", "sort_order": 0 },
{ "item_id": "uuid-2", "sort_order": 1 },
{ "item_id": "uuid-3", "sort_order": 2 }
]
}
```
**Reponse** : `200 OK` avec la liste des items reordonnes.
---
### `POST /api/v1/documents/{slug}/archive` -- Archiver un document
Archive le document complet dans le sanctuaire. Le processus :
1. Le contenu integral du document (metadonnees + items) est serialise.
2. Un hash SHA-256 est calcule sur le contenu.
3. Le contenu est envoye sur IPFS (CID retourne).
4. Le hash est ancre on-chain via `system.remark` sur Duniter V2.
5. Une entree `sanctuary_entries` est creee avec les references.
6. Le statut du document passe a `archived` et les champs `ipfs_cid` et `chain_anchor` sont mis a jour.
**Reponse** : `200 OK` avec le document mis a jour incluant `ipfs_cid` et `chain_anchor`.
---
### `GET /api/v1/sanctuary/{id}/verify` -- Verifier l'integrite d'une entree
Verifie l'integrite d'une entree du sanctuaire en effectuant trois controles :
1. **Hash SHA-256** : recalcul du hash a partir du contenu source et comparaison avec `content_hash`.
2. **IPFS** : verification que le CID IPFS pointe vers un contenu valide (si disponible).
3. **On-chain** : verification que le hash est present dans le `system.remark` du bloc reference (si disponible).
**Reponse** :
```json
{
"entry_id": "uuid",
"hash_valid": true,
"ipfs_valid": true,
"chain_valid": true,
"verified_at": "2026-02-28T12:00:00Z",
"details": "Tous les controles sont valides."
}
```
---
### `GET /api/v1/sanctuary/by-reference/{reference_id}` -- Entrees par reference
Retourne toutes les entrees du sanctuaire liees a une entite source (document, decision ou session de vote) identifiee par son UUID.
**Parametres de requete** : `skip`, `limit` (pagination standard).
**Reponse** : `200 OK` avec une liste de `SanctuaryEntryOut`.
## Details des endpoints Sprint 3
### `GET /api/v1/votes/sessions` -- Lister les sessions de vote
Retourne la liste des sessions de vote avec pagination et filtres optionnels.
**Parametres de requete** :
| Parametre | Type | Description |
| ------------- | ------ | ---------------------------------------------- |
| `status` | string | Filtrer par statut (`open`, `closed`, `draft`) |
| `protocol_id` | uuid | Filtrer par protocole de vote |
| `decision_id` | uuid | Filtrer par decision associee |
| `skip` | int | Offset de pagination (defaut 0) |
| `limit` | int | Nombre max de resultats (defaut 50, max 200) |
**Reponse** : `200 OK` avec une liste de `VoteSessionOut`.
---
### `POST /api/v1/votes/sessions/{id}/close` -- Cloturer une session
Cloture une session de vote ouverte et calcule le resultat final. Le calcul inclut la formule WoT, les criteres Smith et TechComm le cas echeant. La session passe au statut `closed` et le resultat est fige.
**Preconditions** :
- La session doit etre au statut `open`.
- L'utilisateur doit etre le createur de la session ou un membre du Comite Technique.
**Reponse** :
```json
{
"session_id": "uuid",
"status": "closed",
"closed_at": "2026-02-28T12:00:00Z",
"result": {
"votes_for": 97,
"votes_against": 23,
"total_votes": 120,
"wot_size": 7224,
"threshold": 94,
"adopted": true,
"smith_threshold": 2,
"smith_votes_for": 5,
"smith_met": true,
"techcomm_threshold": null,
"techcomm_votes_for": null,
"techcomm_met": null
}
}
```
---
### `GET /api/v1/votes/sessions/{id}/threshold` -- Detail du calcul de seuil
Retourne le detail complet du calcul de seuil pour une session de vote, incluant les valeurs intermediaires de la formule. Utile pour la transparence et le debug.
**Reponse** :
```json
{
"session_id": "uuid",
"formula_config_id": "uuid",
"mode_params": "D30M50B.1G.2",
"parameters": {
"constant_base": 0.0,
"base_exponent": 0.1,
"majority_pct": 50,
"gradient_exponent": 0.2,
"smith_exponent": null,
"techcomm_exponent": null
},
"inputs": {
"wot_size": 7224,
"total_votes": 120,
"smith_wot_size": 20,
"techcomm_size": 5
},
"computation": {
"base_term": 7.943e-08,
"participation_ratio": 0.0166,
"participation_ratio_powered": 0.4217,
"inertia_factor": 0.7892,
"effective_threshold": 94.70,
"threshold_ceiled": 95,
"threshold_final": 94
},
"criteria": {
"smith_threshold": null,
"techcomm_threshold": null
}
}
```
---
### `POST /api/v1/votes/sessions/{id}/tally` -- Forcer un recomptage
Force le recalcul du decompte des votes et du seuil pour une session. Utile si des votes ont ete invalides manuellement ou si la taille WoT a ete corrigee.
**Preconditions** :
- L'utilisateur doit etre le createur de la session ou un membre du Comite Technique.
**Corps de la requete** (optionnel) :
```json
{
"wot_size_override": 7250,
"smith_wot_size_override": null,
"techcomm_size_override": null
}
```
Si aucun corps n'est fourni, les tailles sont reprises du snapshot initial.
**Reponse** : `200 OK` avec le meme format que le resultat de cloture.
---
### `PUT /api/v1/protocols/{id}` -- Mettre a jour un protocole
Met a jour un protocole de vote existant. Les modifications de protocoles actifs (utilises par des sessions ouvertes) sont soumises a **meta-gouvernance** : une session de vote doit d'abord valider la modification.
**Corps de la requete** (champs optionnels) :
```json
{
"name": "Nouveau nom du protocole",
"description": "Description mise a jour",
"vote_type": "nuanced",
"duration_days": 60,
"formula_config_id": "uuid-de-la-nouvelle-formule"
}
```
**Reponse** : `200 OK` avec le protocole mis a jour (`ProtocolOut`).
**Code 409** : Si le protocole est utilise par une session ouverte et qu'aucune validation meta-gouvernance n'est fournie.
---
### `GET /api/v1/protocols/formulas/{id}` -- Obtenir une formule
Retourne une configuration de formule par son identifiant, incluant tous les parametres et le `mode_params` encode.
**Reponse** : `200 OK` avec un `FormulaConfigOut`.
---
### `PUT /api/v1/protocols/formulas/{id}` -- Mettre a jour une formule
Met a jour une configuration de formule existante. Comme pour les protocoles, les formules actives sont protegees par la meta-gouvernance.
**Corps de la requete** (champs optionnels) :
```json
{
"name": "Configuration amendee",
"majority_pct": 66,
"base_exponent": 0.05,
"gradient_exponent": 0.3,
"constant_base": 0.0,
"smith_exponent": 0.1,
"techcomm_exponent": 0.1,
"ratio_multiplier": null,
"is_ratio_mode": false
}
```
Le champ `mode_params` est recalcule automatiquement a partir des valeurs fournies.
**Reponse** : `200 OK` avec la formule mise a jour (`FormulaConfigOut`).
**Code 409** : Si la formule est liee a un protocole actif sans validation meta-gouvernance.
---
### `POST /api/v1/protocols/simulate` -- Simuler une formule
Simule le calcul de seuil d'une formule avec des parametres arbitraires, sans creer ni modifier aucune donnee. Endpoint ouvert (pas d'authentification requise) pour permettre l'experimentation.
**Corps de la requete** :
```json
{
"wot_size": 7224,
"total_votes": 120,
"majority_pct": 50,
"base_exponent": 0.1,
"gradient_exponent": 0.2,
"constant_base": 0.0,
"smith_wot_size": 20,
"smith_exponent": 0.1,
"techcomm_size": 5,
"techcomm_exponent": 0.1,
"votes_for": 97
}
```
**Reponse** :
```json
{
"threshold": 94,
"inertia_factor": 0.7892,
"participation_ratio": 0.0166,
"base_term": 7.943e-08,
"smith_threshold": 2,
"techcomm_threshold": 2,
"adopted": true,
"details": {
"wot_threshold_met": true,
"smith_met": true,
"techcomm_met": true
}
}
```
## Details des endpoints Sprint 4
### `POST /api/v1/decisions/{id}/advance` -- Avancer une decision
Avance une decision a l'etape suivante de son workflow. Complete l'etape active courante et active la prochaine etape en attente. Si toutes les etapes sont terminees, le statut global de la decision avance au statut suivant dans le cycle de vie (`draft` -> `qualification` -> `review` -> `voting` -> `executed` -> `closed`).
**Comportement** :
- S'il y a une etape `active` : elle passe a `completed`, la prochaine etape `pending` est activee.
- S'il n'y a pas d'etape active : la premiere etape `pending` est activee. Si la decision est en `draft`, elle passe a `qualification`.
- Si toutes les etapes sont terminees : le statut global avance.
**Preconditions** :
- La decision ne doit pas etre au statut `closed`.
- L'utilisateur doit etre authentifie.
**Reponse** : `200 OK` avec un `DecisionAdvanceOut` :
```json
{
"id": "uuid",
"title": "Runtime upgrade v3.2.0",
"description": "...",
"context": "...",
"decision_type": "runtime_upgrade",
"status": "review",
"voting_protocol_id": "uuid",
"created_by_id": "uuid",
"created_at": "2026-02-28T10:00:00Z",
"updated_at": "2026-02-28T12:00:00Z",
"steps": [
{"id": "uuid", "step_order": 0, "step_type": "qualification", "status": "completed", "...": "..."},
{"id": "uuid", "step_order": 1, "step_type": "review", "status": "active", "...": "..."},
{"id": "uuid", "step_order": 2, "step_type": "vote", "status": "pending", "...": "..."}
],
"message": "Etape 'Qualification' completee. Etape 'Examen' activee."
}
```
**Code 400** : Si la decision est deja cloturee ou qu'aucun avancement n'est possible.
---
### `DELETE /api/v1/decisions/{id}` -- Supprimer une decision
Supprime une decision. La suppression n'est autorisee que si la decision est au statut `draft`. Les etapes associees sont supprimees en cascade.
**Preconditions** :
- La decision doit etre au statut `draft`.
- L'utilisateur doit etre authentifie.
**Reponse** : `204 No Content`.
**Code 400** : Si la decision n'est pas au statut `draft`.
---
### `POST /api/v1/decisions/{id}/steps/{step_id}/create-vote-session` -- Creer une session de vote pour une etape de decision
Cree une session de vote liee a une etape specifique d'une decision. La session est configuree automatiquement a partir du protocole de vote de la decision.
**Comportement** :
1. Verifie que la decision et l'etape existent.
2. Verifie que l'etape est de type `vote` et au statut `active`.
3. Cree une session de vote avec le protocole de la decision.
4. Fait un snapshot des tailles WoT, Smith et TechComm.
5. Calcule la date de fin a partir de la duree de la formule.
6. Rattache la session a l'etape via `vote_session_id`.
**Reponse** : `201 Created` avec un `VoteSessionOut`.
**Code 400** : Si l'etape n'est pas de type `vote`, n'est pas `active`, ou si une session est deja liee.
---
### `POST /api/v1/mandates/{id}/advance` -- Avancer un mandat
Avance un mandat a l'etape suivante de son workflow. Fonctionne de maniere identique a l'avancement des decisions, avec le cycle de vie specifique aux mandats (`draft` -> `candidacy` -> `voting` -> `active` -> `reporting` -> `completed`).
**Comportement** :
- S'il y a une etape `active` : elle passe a `completed`, la prochaine etape `pending` est activee.
- S'il n'y a pas d'etape active : la premiere etape `pending` est activee. Si le mandat est en `draft`, il passe a `candidacy`.
- Si toutes les etapes sont terminees : le statut global avance.
**Preconditions** :
- Le mandat ne doit pas etre au statut `completed` ou `revoked`.
- L'utilisateur doit etre authentifie.
**Reponse** : `200 OK` avec un `MandateAdvanceOut` :
```json
{
"id": "uuid",
"title": "Membre Comite Technique 2026",
"description": "...",
"mandate_type": "techcomm",
"status": "candidacy",
"mandatee_id": null,
"decision_id": null,
"starts_at": null,
"ends_at": null,
"created_at": "2026-02-28T10:00:00Z",
"updated_at": "2026-02-28T12:00:00Z",
"steps": [
{"id": "uuid", "step_order": 0, "step_type": "formulation", "status": "completed", "...": "..."},
{"id": "uuid", "step_order": 1, "step_type": "candidacy", "status": "active", "...": "..."}
],
"message": "Etape 'Formulation' completee. Etape 'Candidature' activee."
}
```
**Code 400** : Si le mandat est deja en statut terminal (`completed` ou `revoked`).
---
### `POST /api/v1/mandates/{id}/assign` -- Assigner un mandataire
Assigne un mandataire (membre elu) a un mandat apres un vote reussi.
**Corps de la requete** :
```json
{
"mandatee_id": "uuid-de-l-identite-duniter"
}
```
**Comportement** :
1. Verifie que le mandat existe et qu'il est dans un statut permettant l'assignation.
2. Definit le `mandatee_id` du mandat.
3. Le mandat peut ensuite etre avance vers le statut `active`.
**Preconditions** :
- L'utilisateur doit etre authentifie.
- Le `mandatee_id` doit correspondre a une identite Duniter existante.
**Reponse** : `200 OK` avec un `MandateOut` mis a jour.
**Code 404** : Si le mandat ou l'identite Duniter n'existe pas.
---
### `POST /api/v1/mandates/{id}/revoke` -- Revoquer un mandat
Revoque un mandat actif de maniere anticipee. Le statut du mandat passe directement a `revoked`, mettant fin aux responsabilites du mandataire.
**Preconditions** :
- Le mandat doit etre au statut `active` ou `reporting`.
- L'utilisateur doit etre authentifie.
**Reponse** : `200 OK` avec un `MandateOut` mis a jour (statut `revoked`).
**Code 400** : Si le mandat n'est pas dans un statut permettant la revocation.
---
### `POST /api/v1/mandates/{id}/steps/{step_id}/create-vote-session` -- Creer une session de vote pour une etape de mandat
Cree une session de vote liee a une etape specifique d'un mandat. Fonctionne de maniere identique a la creation de session pour les decisions.
**Comportement** :
1. Verifie que le mandat et l'etape existent.
2. Verifie que l'etape est de type `vote` et au statut `active`.
3. Cree une session de vote avec le protocole associe.
4. Fait un snapshot des tailles WoT, Smith et TechComm.
5. Calcule la date de fin a partir de la duree de la formule.
6. Rattache la session a l'etape via `vote_session_id`.
**Reponse** : `201 Created` avec un `VoteSessionOut`.
**Code 400** : Si l'etape n'est pas de type `vote`, n'est pas `active`, ou si une session est deja liee.
---
## Pagination
Les endpoints de liste acceptent les parametres `skip` (offset, defaut 0) et `limit` (max 200, defaut 50).
## Authentification
Les endpoints marques "Oui" dans la colonne Auth requierent un header :
```
Authorization: Bearer <token>
```
Le token est obtenu via le flux challenge-response (`/auth/challenge` puis `/auth/verify`).
+328
View File
@@ -0,0 +1,328 @@
---
title: Schema de base de donnees
description: Tables et relations de la base de donnees PostgreSQL
---
# Schema de base de donnees
libreDecision utilise PostgreSQL 16 avec SQLAlchemy 2.0 en mode asynchrone (asyncpg). Toutes les cles primaires sont des UUID v4.
## Tables
### `duniter_identities`
Identites Duniter V2 connues de la plateforme.
| Colonne | Type | Description |
| -------------- | ------------ | ---------------------------------------------- |
| id | UUID (PK) | Identifiant unique |
| address | VARCHAR(64) | Adresse SS58 Duniter (unique, indexee) |
| display_name | VARCHAR(128) | Nom d'affichage |
| wot_status | VARCHAR(32) | Statut WoT : member, pending, revoked, unknown |
| is_smith | BOOLEAN | Membre Smith (forgeron) |
| is_techcomm | BOOLEAN | Membre du Comite Technique |
| created_at | TIMESTAMPTZ | Date de creation |
| updated_at | TIMESTAMPTZ | Date de derniere mise a jour |
### `sessions`
Sessions d'authentification (tokens).
| Colonne | Type | Description |
| ------------ | ------------ | ---------------------------------- |
| id | UUID (PK) | Identifiant unique |
| token_hash | VARCHAR(128) | Hash du token (unique, indexe) |
| identity_id | UUID (FK) | -> duniter_identities.id |
| created_at | TIMESTAMPTZ | Date de creation |
| expires_at | TIMESTAMPTZ | Date d'expiration |
### `documents`
Documents de reference modulaires. Le cycle de vie d'un document suit les statuts `draft` -> `active` -> `archived`. Lors de l'archivage (Sprint 2), les champs `ipfs_cid` et `chain_anchor` sont renseignes automatiquement par le service sanctuaire.
| Colonne | Type | Description |
| ------------ | ------------ | ----------------------------------------------------- |
| id | UUID (PK) | Identifiant unique |
| slug | VARCHAR(128) | Identifiant lisible (unique, indexe) |
| title | VARCHAR(256) | Titre du document |
| doc_type | VARCHAR(64) | Type : licence, engagement, reglement, constitution |
| version | VARCHAR(32) | Version semantique (defaut "0.1.0") |
| status | VARCHAR(32) | Statut : draft, active, archived |
| description | TEXT | Description du document |
| ipfs_cid | VARCHAR(128) | CID IPFS de la derniere version archivee (renseigne lors de l'archivage) |
| chain_anchor | VARCHAR(128) | Hash de transaction on-chain (renseigne lors de l'archivage) |
| created_at | TIMESTAMPTZ | Date de creation |
| updated_at | TIMESTAMPTZ | Date de derniere mise a jour |
### `document_items`
Items individuels composant un document (clauses, regles, verifications, etc.). Chaque item peut etre modifie, supprime ou reordonne individuellement (Sprint 2). Le champ `current_text` est mis a jour automatiquement lorsqu'une version est acceptee.
| Colonne | Type | Description |
| ------------------- | ------------ | ------------------------------------------------- |
| id | UUID (PK) | Identifiant unique |
| document_id | UUID (FK) | -> documents.id (cascade delete) |
| position | VARCHAR(16) | Numero de position ("1", "1.1", "3.2") |
| item_type | VARCHAR(32) | Type : clause, rule, verification, preamble, section |
| title | VARCHAR(256) | Titre de l'item |
| current_text | TEXT | Texte courant de l'item (mis a jour lors de l'acceptation d'une version) |
| voting_protocol_id | UUID (FK) | -> voting_protocols.id (protocole specifique) |
| sort_order | INTEGER | Ordre de tri (modifiable via endpoint reorder) |
| created_at | TIMESTAMPTZ | Date de creation |
| updated_at | TIMESTAMPTZ | Date de derniere mise a jour |
### `item_versions`
Historique des versions proposees pour chaque item. Lors de l'acceptation d'une version (Sprint 2), le `current_text` de l'item parent est remplace par le `proposed_text` de la version, et toutes les autres versions en attente (`proposed`, `voting`) sont automatiquement rejetees.
| Colonne | Type | Description |
| -------------- | ------------ | ------------------------------------------------------ |
| id | UUID (PK) | Identifiant unique |
| item_id | UUID (FK) | -> document_items.id (cascade delete) |
| proposed_text | TEXT | Texte propose |
| diff_text | TEXT | Diff unifie entre texte courant et propose (genere automatiquement) |
| rationale | TEXT | Justification de la modification |
| status | VARCHAR(32) | Statut : proposed, voting, accepted, rejected |
| decision_id | UUID (FK) | -> decisions.id (decision associee) |
| proposed_by_id | UUID (FK) | -> duniter_identities.id (auteur de la proposition) |
| created_at | TIMESTAMPTZ | Date de creation |
### `decisions`
Processus decisionnels multi-etapes. Le cycle de vie suit un ordre strict de statuts gere par le service `decision_service.advance_decision()`.
| Colonne | Type | Description |
| ------------------- | ------------ | -------------------------------------------------------- |
| id | UUID (PK) | Identifiant unique |
| title | VARCHAR(256) | Titre de la decision |
| description | TEXT | Description |
| context | TEXT | Contexte additionnel (cadrage) |
| decision_type | VARCHAR(64) | Type : runtime_upgrade, document_change, mandate_vote, parameter_change, custom |
| status | VARCHAR(32) | Statut : draft, qualification, review, voting, executed, closed |
| voting_protocol_id | UUID (FK) | -> voting_protocols.id |
| created_by_id | UUID (FK) | -> duniter_identities.id |
| created_at | TIMESTAMPTZ | Date de creation |
| updated_at | TIMESTAMPTZ | Date de derniere mise a jour |
**Workflow des statuts** : `draft` -> `qualification` -> `review` -> `voting` -> `executed` -> `closed`. La transition est geree par le service `advance_decision` qui complete l'etape active, active la suivante, et avance le statut global quand toutes les etapes sont terminees. La suppression n'est autorisee qu'en statut `draft`.
### `decision_steps`
Etapes d'un processus decisionnel. Chaque etape est traitee sequentiellement selon `step_order`. Le service `advance_decision` complete l'etape `active` et active la prochaine `pending`.
| Colonne | Type | Description |
| ---------------- | ------------ | -------------------------------------------------------- |
| id | UUID (PK) | Identifiant unique |
| decision_id | UUID (FK) | -> decisions.id (cascade delete) |
| step_order | INTEGER | Ordre de l'etape (0-indexed, determine la sequence) |
| step_type | VARCHAR(32) | Type : qualification, review, vote, execution, reporting |
| title | VARCHAR(256) | Titre de l'etape |
| description | TEXT | Description |
| status | VARCHAR(32) | Statut : pending, active, completed, skipped |
| vote_session_id | UUID (FK) | -> vote_sessions.id (renseigne via create-vote-session pour les etapes de type `vote`) |
| outcome | TEXT | Resultat de l'etape |
| created_at | TIMESTAMPTZ | Date de creation |
**Types d'etapes** : `qualification` (verification recevabilite), `review` (examen communautaire), `vote` (session de vote formelle), `execution` (mise en oeuvre), `reporting` (compte-rendu). Les etapes de type `vote` sont les seules a pouvoir avoir un `vote_session_id` renseigne.
### `vote_sessions`
Sessions de vote avec snapshot des tailles WoT et decompte en temps reel.
| Colonne | Type | Description |
| ------------------- | ------------ | ---------------------------------------------- |
| id | UUID (PK) | Identifiant unique |
| decision_id | UUID (FK) | -> decisions.id |
| item_version_id | UUID (FK) | -> item_versions.id |
| voting_protocol_id | UUID (FK) | -> voting_protocols.id |
| wot_size | INTEGER | Taille WoT au debut de la session |
| smith_size | INTEGER | Taille Smith au debut de la session |
| techcomm_size | INTEGER | Taille TechComm au debut de la session |
| starts_at | TIMESTAMPTZ | Date de debut |
| ends_at | TIMESTAMPTZ | Date de fin |
| status | VARCHAR(32) | Statut : open, closed, tallied |
| votes_for | INTEGER | Nombre de votes pour |
| votes_against | INTEGER | Nombre de votes contre |
| votes_total | INTEGER | Nombre total de votes |
| smith_votes_for | INTEGER | Votes pour des membres Smith |
| techcomm_votes_for | INTEGER | Votes pour des membres TechComm |
| threshold_required | FLOAT | Seuil calcule requis |
| result | VARCHAR(32) | Resultat : adopted, rejected, null |
| chain_recorded | BOOLEAN | Enregistre sur la blockchain |
| chain_tx_hash | VARCHAR(128) | Hash de la transaction on-chain |
| created_at | TIMESTAMPTZ | Date de creation |
### `votes`
Votes individuels avec preuve cryptographique.
| Colonne | Type | Description |
| ---------------- | ------------ | -------------------------------------------- |
| id | UUID (PK) | Identifiant unique |
| session_id | UUID (FK) | -> vote_sessions.id |
| voter_id | UUID (FK) | -> duniter_identities.id |
| vote_value | VARCHAR(32) | Valeur : for, against, ou niveau nuance |
| nuanced_level | INTEGER | Niveau nuance (0-5) pour les votes nuances |
| comment | TEXT | Commentaire optionnel |
| signature | TEXT | Signature Ed25519 du payload |
| signed_payload | TEXT | Payload signe (pour verification) |
| voter_wot_status | VARCHAR(32) | Statut WoT du votant au moment du vote |
| voter_is_smith | BOOLEAN | Le votant est-il forgeron |
| voter_is_techcomm| BOOLEAN | Le votant est-il membre TechComm |
| is_active | BOOLEAN | Vote actif (false si remplace) |
| created_at | TIMESTAMPTZ | Date de creation |
### `mandates`
Mandats assignes a des membres. Le cycle de vie suit un ordre strict de statuts gere par le service `mandate_service.advance_mandate()`. La revocation (`POST /mandates/{id}/revoke`) permet de passer directement au statut terminal `revoked`.
| Colonne | Type | Description |
| ------------- | ------------ | ------------------------------------------------------- |
| id | UUID (PK) | Identifiant unique |
| title | VARCHAR(256) | Titre du mandat |
| description | TEXT | Description |
| mandate_type | VARCHAR(64) | Type : techcomm, smith, custom |
| status | VARCHAR(32) | Statut : draft, candidacy, voting, active, reporting, completed, revoked |
| mandatee_id | UUID (FK) | -> duniter_identities.id (titulaire du mandat, renseigne via `POST /mandates/{id}/assign`) |
| decision_id | UUID (FK) | -> decisions.id (decision associee, optionnel) |
| starts_at | TIMESTAMPTZ | Date de debut (renseignee lors de l'assignation) |
| ends_at | TIMESTAMPTZ | Date de fin (renseignee lors de l'assignation) |
| created_at | TIMESTAMPTZ | Date de creation |
| updated_at | TIMESTAMPTZ | Date de derniere mise a jour |
**Workflow des statuts** : `draft` -> `candidacy` -> `voting` -> `active` -> `reporting` -> `completed`. Les statuts terminaux sont `completed` et `revoked`. La suppression n'est autorisee qu'en statut `draft`. La revocation est possible depuis les statuts `active` ou `reporting`.
### `mandate_steps`
Etapes du cycle de vie d'un mandat. Chaque etape est traitee sequentiellement selon `step_order`. Le service `advance_mandate` complete l'etape `active` et active la prochaine `pending`.
| Colonne | Type | Description |
| ---------------- | ------------ | ------------------------------------------------------------- |
| id | UUID (PK) | Identifiant unique |
| mandate_id | UUID (FK) | -> mandates.id (cascade delete) |
| step_order | INTEGER | Ordre de l'etape (0-indexed, determine la sequence) |
| step_type | VARCHAR(32) | Type : formulation, candidacy, vote, assignment, reporting, completion, revocation |
| title | VARCHAR(256) | Titre de l'etape |
| description | TEXT | Description |
| status | VARCHAR(32) | Statut : pending, active, completed, skipped |
| vote_session_id | UUID (FK) | -> vote_sessions.id (renseigne via create-vote-session pour les etapes de type `vote`) |
| outcome | TEXT | Resultat de l'etape |
| created_at | TIMESTAMPTZ | Date de creation |
**Types d'etapes** : `formulation` (definition du mandat), `candidacy` (depot des candidatures), `vote` (election par vote WoT), `assignment` (attribution au candidat elu), `reporting` (compte-rendu), `completion` (fin normale), `revocation` (fin anticipee). Les etapes de type `vote` sont les seules a pouvoir avoir un `vote_session_id` renseigne.
### `voting_protocols`
Protocoles de vote reutilisables.
| Colonne | Type | Description |
| ------------------ | ------------ | ----------------------------------------------- |
| id | UUID (PK) | Identifiant unique |
| name | VARCHAR(128) | Nom du protocole |
| description | TEXT | Description |
| vote_type | VARCHAR(32) | Type de vote : binary, nuanced |
| formula_config_id | UUID (FK) | -> formula_configs.id |
| mode_params | VARCHAR(64) | Parametres compacts ("D30M50B.1G.2T.1") |
| is_meta_governed | BOOLEAN | Le protocole est-il sous meta-gouvernance |
| created_at | TIMESTAMPTZ | Date de creation |
### `formula_configs`
Configurations de formules de seuil WoT.
| Colonne | Type | Description |
| ------------------------- | ------------ | ----------------------------------------- |
| id | UUID (PK) | Identifiant unique |
| name | VARCHAR(128) | Nom de la configuration |
| description | TEXT | Description |
| duration_days | INTEGER | Duree du vote en jours |
| majority_pct | INTEGER | Pourcentage de majorite (0-100) |
| base_exponent | FLOAT | Exposant de base B |
| gradient_exponent | FLOAT | Exposant de gradient G |
| constant_base | FLOAT | Base constante C |
| smith_exponent | FLOAT | Exposant Smith S (null si non requis) |
| techcomm_exponent | FLOAT | Exposant TechComm T (null si non requis) |
| nuanced_min_participants | INTEGER | Participants minimum (vote nuance) |
| nuanced_threshold_pct | INTEGER | Seuil positif % (vote nuance) |
| created_at | TIMESTAMPTZ | Date de creation |
### `sanctuary_entries`
Entrees du sanctuaire (archivage immuable). Le champ `reference_id` permet de retrouver toutes les entrees liees a un document, une decision ou une session de vote via l'endpoint `/by-reference/{reference_id}` (Sprint 2). L'endpoint `/verify` recalcule le hash et verifie la coherence IPFS/on-chain.
| Colonne | Type | Description |
| -------------- | ------------ | ------------------------------------------ |
| id | UUID (PK) | Identifiant unique |
| entry_type | VARCHAR(64) | Type : document, decision, vote_result |
| reference_id | UUID | UUID de l'entite source (indexe pour recherche par reference) |
| title | VARCHAR(256) | Titre |
| content_hash | VARCHAR(128) | Hash SHA-256 du contenu |
| ipfs_cid | VARCHAR(128) | CID IPFS (renseigne lors de l'upload) |
| chain_tx_hash | VARCHAR(128) | Hash de la transaction on-chain |
| chain_block | INTEGER | Numero de bloc de la transaction |
| metadata_json | TEXT | Metadonnees JSON supplementaires |
| created_at | TIMESTAMPTZ | Date de creation |
### `blockchain_cache`
Cache des donnees blockchain pour eviter les appels RPC repetes.
| Colonne | Type | Description |
| ------------ | ------------ | -------------------------------- |
| id | UUID (PK) | Identifiant unique |
| cache_key | VARCHAR(256) | Cle de cache (unique, indexee) |
| cache_value | JSONB | Valeur en cache |
| fetched_at | TIMESTAMPTZ | Date de recuperation |
| expires_at | TIMESTAMPTZ | Date d'expiration du cache |
## Diagramme des relations
```
duniter_identities
|-- 1:N --> sessions
|-- 1:N --> votes (voter_id)
|-- 1:N --> item_versions (proposed_by_id)
|-- 1:N --> decisions (created_by_id)
|-- 1:N --> mandates (mandatee_id)
documents
|-- 1:N --> document_items
|-- 1:N ..> sanctuary_entries (via reference_id, non FK)
document_items
|-- 1:N --> item_versions (cascade delete)
|-- N:1 --> voting_protocols
item_versions
|-- N:1 --> decisions
decisions
|-- 1:N --> decision_steps
|-- 1:N ..> sanctuary_entries (via reference_id, non FK)
decision_steps
|-- N:1 --> vote_sessions
vote_sessions
|-- 1:N --> votes
|-- N:1 --> voting_protocols
|-- 1:N ..> sanctuary_entries (via reference_id, non FK)
mandates
|-- 1:N --> mandate_steps
|-- N:1 --> decisions
mandate_steps
|-- N:1 --> vote_sessions
voting_protocols
|-- N:1 --> formula_configs
formula_configs
|-- 1:N --> voting_protocols
sanctuary_entries
|-- reference_id ..> documents | decisions | vote_sessions (lien logique)
```
> **Note Sprint 2** : Les liens `..>` (pointilles) representent des references logiques via le champ `reference_id` de `sanctuary_entries`. Ce ne sont pas des cles etrangeres PostgreSQL car `reference_id` peut pointer vers differentes tables selon le `entry_type`.
+284
View File
@@ -0,0 +1,284 @@
---
title: Formules
description: Formules mathematiques de seuil WoT, criteres Smith et TechComm, simulation et meta-gouvernance
---
# Formules de seuil
libreDecision utilise un systeme de formules mathematiques pour determiner les seuils d'adoption des votes. Le mecanisme central est la **formule d'inertie WoT** qui impose une quasi-unanimite en cas de faible participation et converge vers une majorite simple a participation elevee.
## Formule principale -- Seuil WoT
$$
\text{Result} = C + B^W + \left( M + (1 - M) \cdot \left(1 - \left(\frac{T}{W}\right)^G \right) \right) \cdot \max(0,\; T - C)
$$
### Variables et plages de valeurs
| Symbole | Parametre | Description | Plage | Defaut |
| ------- | ------------------- | ------------------------------------------------ | ------------------- | ------ |
| $C$ | `constant_base` | Base constante additive (plancher minimum de votes favorables requis) | $[0, +\infty[$ | 0.0 |
| $B$ | `base_exponent` | Exposant de base. $B^W$ ajoute un terme negligeable quand $W$ est grand | $]0, 1[$ | 0.1 |
| $W$ | `wot_size` | Taille du corpus des votants eligibles (membres WoT) | $[1, +\infty[$ | -- |
| $T$ | `total_votes` | Nombre total de votes exprimes (pour + contre) | $[0, W]$ | -- |
| $M$ | `majority_pct / 100`| Ratio de majorite cible a pleine participation | $]0, 1]$ | 0.50 |
| $G$ | `gradient_exponent` | Controle la vitesse de convergence de la super-majorite vers $M$ | $]0, +\infty[$ | 0.2 |
#### Detail des parametres
**$C$ -- Base constante** : Nombre minimum absolu de votes favorables requis, independamment de la participation. Avec $C = 3$, il faut au moins 3 votes favorables meme si la formule calcule un seuil inferieur. En general, $C = 0$.
**$B$ -- Exposant de base** : Genere un terme $B^W$ qui decroit exponentiellement avec la taille de la WoT. Pour $B = 0.1$ et $W = 7224$, $B^W = 0.1^{7224} \approx 0$. Ce terme n'est pertinent que pour de tres petites communautes. Plus $B$ est proche de 0, plus le terme decroit vite. Plus $B$ est proche de 1, plus il reste significatif.
**$M$ -- Ratio de majorite** : Determine la proportion de votes favorables necessaire quand toute la WoT vote. $M = 0.5$ signifie qu'a pleine participation, la majorite simple (50%+1) suffit. $M = 0.66$ impose une super-majorite des 2/3 meme a pleine participation.
**$G$ -- Gradient** : Controle la courbure de la transition entre quasi-unanimite (faible participation) et majorite $M$ (pleine participation). Plus $G$ est petit, plus la transition est rapide : l'inertie chute vite des les premieres participations. Plus $G$ est grand, plus l'exigence de quasi-unanimite persiste a des taux de participation eleves.
### Mecanisme d'inertie
Le coeur de la formule est le facteur d'inertie :
$$
\text{inertia}(T, W) = M + (1 - M) \cdot \left(1 - \left(\frac{T}{W}\right)^G \right)
$$
- Quand la **participation est faible** ($T \ll W$) : le ratio $T/W$ est petit, $(T/W)^G$ est proche de 0, donc l'inertie tend vers $M + (1-M) = 1$. Il faut quasiment l'unanimite.
- Quand la **participation est elevee** ($T \to W$) : le ratio $T/W$ tend vers 1, $(T/W)^G$ tend vers 1, donc l'inertie tend vers $M$. La majorite simple suffit.
Le facteur d'inertie represente la **proportion de votes favorables necessaire** parmi les votants effectifs. Il multiplie ensuite $(T - C)$ pour obtenir le seuil absolu.
### Table d'inertie (WoT = 7224, M = 0.50, G = 0.2)
Le tableau suivant montre comment le facteur d'inertie evolue en fonction de la participation, pour les parametres de reference `M50 G.2` avec une WoT de 7224 membres :
| Participation $T$ | Ratio $T/W$ | $(T/W)^G$ | Inertie | Seuil (votes favorables requis) | % favorables requis |
| -----------------: | ----------: | ---------: | ------: | ------------------------------: | ------------------: |
| 10 | 0.0014 | 0.2512 | 0.8744 | 9 | 87.4% |
| 50 | 0.0069 | 0.3548 | 0.8226 | 42 | 82.3% |
| 100 | 0.0138 | 0.3981 | 0.8010 | 81 | 80.1% |
| 120 | 0.0166 | 0.4102 | 0.7949 | 96 | 79.5% |
| 200 | 0.0277 | 0.4467 | 0.7766 | 156 | 77.7% |
| 500 | 0.0692 | 0.5129 | 0.7435 | 372 | 74.4% |
| 1000 | 0.1384 | 0.5754 | 0.7123 | 713 | 71.2% |
| 2000 | 0.2769 | 0.6452 | 0.6774 | 1355 | 67.7% |
| 3612 | 0.5000 | 0.7071 | 0.6464 | 2335 | 64.6% |
| 5000 | 0.6920 | 0.7490 | 0.6255 | 3128 | 62.6% |
| 7224 | 1.0000 | 1.0000 | 0.5000 | 3612 | 50.0% |
On constate que meme a 500 votants (6.9% de participation), il faut encore 74.4% de votes favorables. L'inertie ne descend en dessous de 66% qu'au-dela de 2000 votants (27.7% de participation).
### Decomposition pas a pas
Pour le vote de l'Engagement Forgeron v2.0.0 avec $W = 7224$, $T = 120$, $M = 0.50$, $B = 0.1$, $G = 0.2$, $C = 0$ :
$$
\begin{aligned}
B^W &= 0.1^{7224} \approx 0 \\[6pt]
\frac{T}{W} &= \frac{120}{7224} \approx 0.0166 \\[6pt]
\left(\frac{T}{W}\right)^G &= 0.0166^{0.2} \approx 0.4102 \\[6pt]
1 - \left(\frac{T}{W}\right)^G &\approx 0.5898 \\[6pt]
\text{inertia} &= 0.50 + 0.50 \times 0.5898 = 0.7949 \\[6pt]
\text{Result} &= 0 + 0 + 0.7949 \times \max(0, 120 - 0) \\[3pt]
&= 0.7949 \times 120 \approx 95.39 \\[3pt]
&\Rightarrow \text{Seuil} = 94 \quad \text{(arrondi inferieur)}
\end{aligned}
$$
Resultat : **adopte** (97 >= 94).
## Critere Smith (Forgerons)
$$
\text{SmithThreshold} = \lceil \text{SmithWotSize}^S \rceil
$$
Le critere Smith exige un nombre minimum de votes favorables de la part des membres Smith (forgerons) pour que certaines decisions soient valides.
| Symbole | Parametre | Description | Plage | Defaut |
| ------- | ---------------- | ---------------------------- | ---------------- | ------------------ |
| $S$ | `smith_exponent` | Exposant pour le critere Smith | $]0, 1]$ | null (desactive) |
L'exposant $S$ controle l'exigence en fonction de la taille du groupe Smith. Plus $S$ est petit, moins de forgerons doivent voter favorablement. Plus $S$ est grand (proche de 1), plus le seuil se rapproche de la taille totale du groupe.
| SmithWotSize | $S = 0.1$ | $S = 0.3$ | $S = 0.5$ | $S = 0.7$ |
| -----------: | --------: | --------: | --------: | --------: |
| 5 | 2 | 2 | 3 | 4 |
| 10 | 2 | 2 | 4 | 6 |
| 20 | 2 | 3 | 5 | 10 |
| 50 | 2 | 4 | 8 | 19 |
| 100 | 2 | 4 | 10 | 26 |
Avec un exposant de $S = 0.1$ et 20 forgerons :
$$
\lceil 20^{0.1} \rceil = \lceil 1.35 \rceil = 2
$$
Au minimum 2 votes favorables de forgerons sont requis.
## Critere TechComm (Comite Technique)
$$
\text{TechCommThreshold} = \lceil \text{CoTecSize}^{T_c} \rceil
$$
Le critere TechComm fonctionne de maniere identique au critere Smith mais pour les membres du Comite Technique.
| Symbole | Parametre | Description | Plage | Defaut |
| ------- | ------------------- | ------------------------------- | -------------- | ------------------ |
| $T_c$ | `techcomm_exponent` | Exposant pour le critere TechComm | $]0, 1]$ | null (desactive) |
Avec un exposant de $T_c = 0.1$ et 5 membres TechComm :
$$
\lceil 5^{0.1} \rceil = \lceil 1.17 \rceil = 2
$$
Au minimum 2 votes favorables de membres TechComm sont requis.
## Resultat final
Un vote est **adopte** si et seulement si les trois conditions sont remplies simultanement :
1. `votes_for >= seuil_WoT` (formule principale)
2. `smith_votes_for >= seuil_Smith` (si critere Smith actif)
3. `techcomm_votes_for >= seuil_TechComm` (si critere TechComm actif)
En notation formelle :
$$
\text{Adopte} = \left( V_{\text{pour}} \geq \text{Seuil}_{\text{WoT}} \right) \;\wedge\; \left( S_{\text{actif}} \Rightarrow V_{\text{smith}} \geq \lceil W_S^S \rceil \right) \;\wedge\; \left( T_{\text{actif}} \Rightarrow V_{\text{tech}} \geq \lceil W_T^{T_c} \rceil \right)
$$
## Parametres de mode (mode_params)
Les parametres de formule sont encodes dans une chaine compacte pour faciliter la lecture et le partage. Format : une lettre majuscule suivie d'une valeur numerique.
| Code | Parametre | Type | Plage | Exemple |
| ---- | --------------------- | ----- | -------------- | ------------ |
| D | `duration_days` | int | $[1, 365]$ | D30 = 30 jours |
| M | `majority_pct` | int | $[1, 100]$ | M50 = 50% |
| B | `base_exponent` | float | $]0, 1[$ | B.1 = 0.1 |
| G | `gradient_exponent` | float | $]0, +\infty[$| G.2 = 0.2 |
| C | `constant_base` | float | $[0, +\infty[$| C0 = 0.0 |
| S | `smith_exponent` | float | $]0, 1]$ | S.1 = 0.1 |
| T | `techcomm_exponent` | float | $]0, 1]$ | T.1 = 0.1 |
| N | `ratio_multiplier` | float | $]0, +\infty[$| N1.5 = 1.5 |
| R | `is_ratio_mode` | bool | $\{0, 1\}$ | R1 = true |
### Exemples
- `"D30M50B.1G.2"` -- 30 jours, majorite 50%, base 0.1, gradient 0.2
- `"D30M50B.1G.2S.1T.1"` -- Idem avec critere Smith (0.1) et TechComm (0.1)
- `"D60M66B.05G.3"` -- 60 jours, majorite 66%, base 0.05, gradient 0.3
## Vote nuance
En plus du vote binaire (pour/contre), libreDecision supporte un vote nuance a 6 niveaux :
| Niveau | Label | Valeur normalisee |
| ------ | ------------- | ----------------: |
| 0 | CONTRE | 0.0 |
| 1 | PAS DU TOUT | 0.2 |
| 2 | PAS D'ACCORD | 0.4 |
| 3 | NEUTRE | 0.6 |
| 4 | D'ACCORD | 0.8 |
| 5 | TOUT A FAIT | 1.0 |
### Regle d'adoption (vote nuance)
Un vote nuance est adopte si :
1. Le nombre de votes aux niveaux 3, 4 et 5 (positifs) represente au moins `threshold_pct`% du total des votes.
2. Le nombre minimum de participants (`min_participants`) est atteint.
En notation formelle :
$$
\text{Adopte}_{\text{nuance}} = \left( \frac{V_3 + V_4 + V_5}{T} \geq \frac{\text{threshold\_pct}}{100} \right) \;\wedge\; \left( T \geq \text{min\_participants} \right)
$$
Par defaut : `threshold_pct = 80%`, `min_participants = 59`.
## Simulateur de formules
L'API expose un endpoint de simulation qui permet de tester le comportement de la formule sans creer de session de vote. Cela permet aux utilisateurs d'experimenter differentes configurations avant de les proposer.
### Utilisation de l'API de simulation
**Endpoint** : `POST /api/v1/protocols/simulate`
**Exemple de requete** :
```bash
curl -X POST https://libredecision.example.org/api/v1/protocols/simulate \
-H "Content-Type: application/json" \
-d '{
"wot_size": 7224,
"total_votes": 120,
"majority_pct": 50,
"base_exponent": 0.1,
"gradient_exponent": 0.2,
"constant_base": 0.0,
"votes_for": 97
}'
```
**Exemple de reponse** :
```json
{
"threshold": 94,
"inertia_factor": 0.7949,
"participation_ratio": 0.0166,
"base_term": 0.0,
"smith_threshold": null,
"techcomm_threshold": null,
"adopted": true,
"details": {
"wot_threshold_met": true,
"smith_met": null,
"techcomm_met": null
}
}
```
### Cas d'usage du simulateur
1. **Calibration** : Tester differentes valeurs de $M$ et $G$ pour trouver un equilibre entre exigence et praticabilite.
2. **Comparaison** : Comparer les seuils entre deux configurations sur les memes donnees de participation.
3. **Prediction** : Estimer le seuil pour un vote a venir en fonction de la participation attendue.
4. **Pedagogie** : Comprendre visuellement l'impact de chaque parametre sur le seuil.
## Meta-gouvernance
La meta-gouvernance est le mecanisme par lequel les **regles du vote elles-memes** sont soumises au vote. Concretement, modifier un protocole de vote ou une formule de seuil active est un acte de gouvernance qui necessite une validation collective.
### Principe
Quand un utilisateur propose une modification d'un protocole ou d'une formule en cours d'utilisation (lies a au moins une session ouverte), le systeme :
1. **Bloque la modification directe** (reponse HTTP 409).
2. **Cree automatiquement une session de vote** portant sur la modification proposee.
3. **Applique le protocole de vote en vigueur** pour valider ou rejeter la modification.
4. Si le vote est **adopte**, la modification est appliquee aux futures sessions de vote. Les sessions en cours ne sont pas affectees.
5. Si le vote est **rejete**, la modification est archivee et le protocole reste inchange.
### Quels objets sont proteges ?
| Objet | Endpoint de modification | Meta-gouvernance |
| ----------------- | -------------------------- | ---------------- |
| Protocole actif | `PUT /api/v1/protocols/{id}` | Oui |
| Formule active | `PUT /api/v1/protocols/formulas/{id}` | Oui |
| Protocole inactif | `PUT /api/v1/protocols/{id}` | Non (modification directe) |
| Formule inactive | `PUT /api/v1/protocols/formulas/{id}` | Non (modification directe) |
Un protocole ou une formule est considere **actif** s'il est lie a au moins une session de vote au statut `open`.
### Cas d'usage
- **Changer la duree de vote** : Un membre propose de passer de 30 a 60 jours. La proposition est soumise au vote avec les regles actuelles. Si adoptee, les prochains votes dureront 60 jours.
- **Modifier le gradient** : Un membre estime que le gradient $G = 0.2$ est trop permissif et propose $G = 0.4$. Le vote decide.
- **Ajouter un critere Smith** : Un membre propose d'activer le critere Smith avec $S = 0.1$ pour impliquer les forgerons. Le vote decide.
La meta-gouvernance garantit qu'aucun parametre fondamental du systeme de decision ne peut etre modifie unilateralement.
@@ -0,0 +1,165 @@
---
title: Integration blockchain
description: Integration Duniter V2, IPFS et ancrage on-chain
---
# Integration blockchain
libreDecision s'integre a la blockchain Duniter V2 pour trois fonctions essentielles :
1. **Authentification** -- Verification de l'identite des membres via signature Ed25519
2. **Donnees WoT** -- Recuperation des tailles WoT, Smith et TechComm pour le calcul des seuils
3. **Ancrage on-chain** -- Archivage immuable des resultats via `system.remark`
## Duniter V2 RPC
La communication avec le noeud Duniter V2 utilise la bibliotheque `substrate-interface` via WebSocket RPC.
### Configuration
```
DUNITER_RPC_URL=wss://gdev.p2p.legal/ws
```
### Requetes principales
#### Taille de la WoT (membres)
```python
from substrateinterface import SubstrateInterface
substrate = SubstrateInterface(url="wss://gdev.p2p.legal/ws")
result = substrate.query(
module="Membership",
storage_function="MembershipCount",
)
wot_size = int(result.value)
```
#### Taille Smith (forgerons)
```python
result = substrate.query(
module="SmithMembers",
storage_function="SmithMembershipCount",
)
smith_size = int(result.value)
```
#### Taille TechComm
```python
result = substrate.query(
module="TechnicalCommittee",
storage_function="Members",
)
techcomm_size = len(result.value) if result.value else 0
```
### Cache blockchain
Pour eviter des appels RPC repetes, les donnees blockchain sont mises en cache dans la table `blockchain_cache` avec une duree d'expiration configurable. La cle de cache est une chaine descriptive (ex: `"wot_size"`, `"smith_size"`), la valeur est stockee en JSONB.
## IPFS (kubo)
Le composant IPFS est un noeud kubo qui sert de stockage distribue pour le Sanctuaire. Chaque document adopte, resultat de vote ou decision finalisee est uploade sur IPFS.
### Configuration
```
IPFS_API_URL=http://localhost:5001
IPFS_GATEWAY_URL=http://localhost:8080
```
### Upload de contenu
```python
import httpx
async with httpx.AsyncClient() as client:
response = await client.post(
f"{IPFS_API_URL}/api/v0/add",
files={"file": ("content.txt", content.encode("utf-8"))},
)
response.raise_for_status()
ipfs_cid = response.json()["Hash"]
```
### Acces au contenu
Le contenu est accessible via la passerelle IPFS :
```
GET http://localhost:8080/ipfs/{cid}
```
## Ancrage on-chain (system.remark)
L'ancrage on-chain consiste a soumettre un extrinsic `system.remark` contenant le hash SHA-256 du contenu archive. Cela cree une preuve immuable et horodatee sur la blockchain Duniter V2.
### Format du remark
```
libredecision:sanctuary:{content_hash_sha256}
```
### Soumission
```python
from substrateinterface import SubstrateInterface, Keypair
substrate = SubstrateInterface(url="wss://gdev.p2p.legal/ws")
call = substrate.compose_call(
call_module="System",
call_function="remark",
call_params={"remark": f"libredecision:sanctuary:{content_hash}"},
)
extrinsic = substrate.create_signed_extrinsic(call=call, keypair=keypair)
receipt = substrate.submit_extrinsic(extrinsic, wait_for_inclusion=True)
tx_hash = receipt.extrinsic_hash
block_number = receipt.block_number
```
### Verification
Pour verifier qu'un contenu a ete ancre, il suffit de :
1. Recalculer le hash SHA-256 du contenu
2. Rechercher le remark correspondant dans la blockchain
3. Verifier que le hash correspond
## Flux complet du Sanctuaire
```
Contenu adopte
|
v
[SHA-256] --> content_hash
|
+---> [IPFS /api/v0/add] --> ipfs_cid
|
+---> [system.remark] --> tx_hash, block_number
|
v
[sanctuary_entries] -- Enregistrement en base avec content_hash, ipfs_cid, chain_tx_hash, chain_block
```
## Authentification Ed25519
Le flux d'authentification utilise un mecanisme challenge-response :
1. Le serveur genere un challenge aleatoire (64 caracteres hexadecimaux)
2. Le client signe le challenge avec sa cle privee Ed25519 (Duniter V2)
3. Le serveur verifie la signature a l'aide de la cle publique derivee de l'adresse SS58
```python
from substrateinterface import Keypair
keypair = Keypair(ss58_address=address)
is_valid = keypair.verify(challenge_bytes, signature_bytes)
```
Cette methode garantit que seul le proprietaire de l'adresse Duniter peut s'authentifier, sans jamais transmettre la cle privee.
+145
View File
@@ -0,0 +1,145 @@
---
title: Contribution
description: Guide de contribution au projet libreDecision
---
# Guide de contribution
Merci de votre interet pour contribuer a libreDecision. Ce guide explique comment configurer l'environnement de developpement, les conventions a respecter et le processus de contribution.
## Prerequis
- Python 3.11+
- Node.js 20+
- PostgreSQL 16
- Docker et Docker Compose (optionnel mais recommande)
- Git
## Installation locale
### Methode 1 : Docker (recommandee)
```bash
# Cloner le depot
git clone https://git.duniter.org/tools/libredecision.git
cd libredecision
# Copier le fichier d'environnement
cp .env.example .env
# Demarrer tous les services
docker compose -f docker/docker-compose.yml -f docker/docker-compose.dev.yml up
```
Les services sont accessibles sur :
- Frontend : http://localhost:3002
- Backend : http://localhost:8002
- API docs : http://localhost:8002/docs
### Methode 2 : Installation manuelle
```bash
# Backend
cd backend
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
uvicorn app.main:app --port 8002 --reload
# Frontend (dans un autre terminal)
cd frontend
npm install
npm run dev
```
Assurez-vous qu'une instance PostgreSQL est disponible et que `DATABASE_URL` dans `.env` pointe vers celle-ci.
## Conventions
### Langues
- **Code** (variables, commentaires, docstrings) : anglais
- **Interface utilisateur** (labels, messages, documentation) : francais
### Structure du code
Le backend est organise par domaine :
```
backend/app/
models/ # Modeles SQLAlchemy (un fichier par domaine)
schemas/ # Schemas Pydantic v2 (un fichier par domaine)
routers/ # Routes FastAPI (un fichier par domaine)
services/ # Logique metier (un fichier par domaine)
engine/ # Moteur de calcul (formules, seuils)
tests/ # Tests unitaires
```
Le frontend suit les conventions Nuxt 4 :
```
frontend/app/
components/ # Composants Vue (un dossier par domaine)
composables/ # Composables reutilisables
pages/ # Pages (un dossier par domaine)
stores/ # Stores Pinia
utils/ # Utilitaires
```
### Style de code
- **Python** : PEP 8, type hints systematiques, docstrings au format NumPy
- **TypeScript/Vue** : ESLint + Prettier (via configuration Nuxt)
- **SQL** : noms de tables au pluriel, noms de colonnes en snake_case
### API
- Versionne sous `/api/v1/`
- Schemas Pydantic v2 pour la validation
- Async partout (SQLAlchemy AsyncSession, FastAPI async handlers)
- Codes HTTP standards (201 pour creation, 204 pour suppression, 404, 409, etc.)
## Tests
### Backend
```bash
cd backend
pytest app/tests/ -v
```
Les tests du moteur de calcul (`test_threshold.py`) verifient la formule de seuil WoT avec le cas de reference (Engagement Forgeron v2.0.0 : 97/23 avec WoT 7224).
### Frontend
```bash
cd frontend
npm run build # Verification que le build passe
```
## Processus de contribution
1. Creer une branche a partir de `main` : `git checkout -b feature/ma-fonctionnalite`
2. Developper et tester localement
3. S'assurer que les tests passent : `pytest` (backend) et `npm run build` (frontend)
4. Pousser la branche et creer une merge request
5. La pipeline CI (Woodpecker) validera automatiquement les tests
6. Revue de code par un mainteneur
7. Merge dans `main`
## Secrets Woodpecker CI
La pipeline CI utilise les secrets suivants (a configurer dans l'interface Woodpecker) :
| Secret | Description |
| ----------------- | ------------------------------------ |
| `docker_registry` | URL du registre Docker |
| `docker_username` | Nom d'utilisateur du registre |
| `docker_password` | Mot de passe du registre |
| `deploy_host` | Adresse du serveur de deploiement |
| `deploy_username` | Utilisateur SSH du serveur |
| `deploy_key` | Cle privee SSH pour le deploiement |
## Contact
Pour toute question, rendez-vous sur le forum Duniter ou ouvrez une issue sur le depot Git.
+405
View File
@@ -0,0 +1,405 @@
---
title: Deploiement
description: Guide de deploiement en production de libreDecision
---
# Deploiement
Ce guide couvre le deploiement complet de libreDecision en production avec Docker, Traefik, PostgreSQL et IPFS.
## Prerequis
| Composant | Version minimale | Description |
| --------- | ---------------- | ----------- |
| Docker | 24+ | Moteur de conteneurs |
| Docker Compose | 2.20+ | Orchestration multi-conteneurs |
| Nom de domaine | -- | Domaine pointe vers le serveur (ex: `decision.librodrome.org`) |
| Certificat TLS | -- | Genere automatiquement par Traefik via Let's Encrypt |
| Traefik | 2.10+ | Reverse proxy avec terminaison TLS (reseau externe `traefik`) |
| Serveur | 2 vCPU, 4 Go RAM, 40 Go SSD | Ressources recommandees |
### Reseau Traefik
Le deploiement suppose qu'un reseau Docker externe `traefik` existe deja avec une instance Traefik configuree. Si ce n'est pas le cas, creez-le :
```bash
docker network create traefik
```
Et deployez Traefik separement (voir section [Configuration Traefik](#configuration-traefik)).
## Configuration .env
Copiez le fichier `.env.example` et configurez chaque variable pour la production :
```bash
cp .env.example .env
```
### Variables d'environnement
| Variable | Description | Valeur par defaut | Production |
| -------- | ----------- | ----------------- | ---------- |
| `POSTGRES_DB` | Nom de la base de donnees | `libredecision` | `libredecision` |
| `POSTGRES_USER` | Utilisateur PostgreSQL | `libredecision` | `libredecision` |
| `POSTGRES_PASSWORD` | Mot de passe PostgreSQL | `change-me-in-production` | **Generer un mot de passe fort** (32+ caracteres) |
| `DATABASE_URL` | URL de connexion asyncpg | `postgresql+asyncpg://...@localhost:5432/...` | Construite automatiquement dans docker-compose |
| `SECRET_KEY` | Cle secrete pour les tokens de session | `change-me-in-production-with-a-real-secret-key` | **Generer une cle aleatoire** (`openssl rand -hex 64`) |
| `DEBUG` | Mode debug | `true` | **`false`** |
| `CORS_ORIGINS` | Origines CORS autorisees | `["http://localhost:3002"]` | `["https://decision.librodrome.org"]` |
| `DUNITER_RPC_URL` | URL du noeud Duniter V2 RPC | `wss://gdev.p2p.legal/ws` | URL du noeud de production |
| `IPFS_API_URL` | URL de l'API IPFS (kubo) | `http://localhost:5001` | `http://ipfs:5001` (interne Docker) |
| `IPFS_GATEWAY_URL` | URL de la passerelle IPFS | `http://localhost:8080` | `http://ipfs:8080` (interne Docker) |
| `NUXT_PUBLIC_API_BASE` | URL publique de l'API pour le frontend | `http://localhost:8002/api/v1` | `https://decision.librodrome.org/api/v1` |
| `DOMAIN` | Nom de domaine | `decision.librodrome.org` | Votre domaine |
### Generer les secrets
```bash
# Generer POSTGRES_PASSWORD
openssl rand -hex 32
# Generer SECRET_KEY
openssl rand -hex 64
```
::callout{type="warning"}
Ne commitez jamais le fichier `.env` contenant les secrets de production. Ajoutez-le au `.gitignore`.
::
## Lancement avec docker-compose
### Premier deploiement
```bash
# Se placer dans le repertoire du projet
cd /opt/libredecision
# Cloner le depot
git clone https://git.duniter.org/tools/libredecision.git .
# Configurer l'environnement
cp .env.example .env
# Editer .env avec les valeurs de production
# Construire et demarrer les services
docker compose -f docker/docker-compose.yml up -d --build
# Verifier que tous les services sont sains
docker compose -f docker/docker-compose.yml ps
```
### Services deployes
| Service | Description | Port interne | Expose |
| ------- | ----------- | ------------ | ------ |
| `postgres` | Base de donnees PostgreSQL 16 | 5432 | Non (interne uniquement) |
| `backend` | API FastAPI | 8002 | Via Traefik (`/api/*`) |
| `frontend` | Application Nuxt 4 | 3000 | Via Traefik (racine) |
| `ipfs` | Noeud IPFS kubo | 5001, 8080 | Non (interne uniquement) |
### Verifier le deploiement
```bash
# Statut des conteneurs
docker compose -f docker/docker-compose.yml ps
# Logs d'un service specifique
docker compose -f docker/docker-compose.yml logs -f backend
# Health check de l'API
curl -s https://decision.librodrome.org/api/health | jq .
```
## Migration de base de donnees (Alembic)
libreDecision utilise Alembic pour les migrations de schema PostgreSQL.
### Appliquer les migrations
```bash
# Executer les migrations dans le conteneur backend
docker compose -f docker/docker-compose.yml exec backend alembic upgrade head
```
### Verifier l'etat des migrations
```bash
docker compose -f docker/docker-compose.yml exec backend alembic current
```
### Creer une nouvelle migration
```bash
# En developpement uniquement
docker compose -f docker/docker-compose.yml exec backend alembic revision --autogenerate -m "description de la migration"
```
### Rollback d'une migration
```bash
# Revenir d'une migration
docker compose -f docker/docker-compose.yml exec backend alembic downgrade -1
```
## Seed des donnees initiales
Apres la premiere migration, vous pouvez charger les donnees de seed (documents de reference initiaux) :
```bash
# Executer le script de seed dans le conteneur backend
docker compose -f docker/docker-compose.yml exec backend python -m app.seed
```
Les donnees de seed incluent :
- La Licence G1 avec ses items
- L'Engagement Forgeron v2.0.0
- L'Engagement Comite Technique v2.0.0
- Le template de processus de Runtime Upgrade
- Les protocoles de vote par defaut avec leurs formules
## Configuration Traefik
### Configuration minimale Traefik
Si vous n'avez pas encore Traefik, voici une configuration minimale. Creez un fichier `docker-compose.traefik.yml` :
```yaml
version: "3.9"
services:
traefik:
image: traefik:v2.10
restart: unless-stopped
command:
- "--api.dashboard=false"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--providers.docker.network=traefik"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--entrypoints.web.http.redirections.entryPoint.to=websecure"
- "--entrypoints.web.http.redirections.entryPoint.scheme=https"
- "--certificatesresolvers.letsencrypt.acme.tlschallenge=true"
- "--certificatesresolvers.letsencrypt.acme.email=admin@decision.librodrome.org"
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
ports:
- "80:80"
- "443:443"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
- "letsencrypt:/letsencrypt"
networks:
- traefik
volumes:
letsencrypt:
networks:
traefik:
external: true
```
```bash
docker compose -f docker-compose.traefik.yml up -d
```
### Routage
Le `docker-compose.yml` de libreDecision configure automatiquement les labels Traefik :
- **Frontend** : `Host(decision.librodrome.org)` sur le port 3000
- **Backend** : `Host(decision.librodrome.org) && PathPrefix(/api)` sur le port 8002
- Les deux utilisent le certificat Let's Encrypt (`certresolver=letsencrypt`)
- Redirection HTTP vers HTTPS automatique
### Certificat TLS
Le certificat est genere automatiquement par Traefik via Let's Encrypt (challenge TLS-ALPN-01). Assurez-vous que :
1. Le domaine pointe vers l'adresse IP du serveur (enregistrement DNS A)
2. Les ports 80 et 443 sont ouverts dans le firewall
3. L'adresse email dans la configuration Traefik est valide
## Monitoring
### Health checks
Le service PostgreSQL dispose d'un health check integre (`pg_isready`). Le backend expose un endpoint de sante :
```bash
# Health check de l'API
curl -s https://decision.librodrome.org/api/health
# Reponse attendue : {"status": "healthy"}
```
### Logs
```bash
# Suivre les logs de tous les services
docker compose -f docker/docker-compose.yml logs -f
# Logs d'un service specifique
docker compose -f docker/docker-compose.yml logs -f backend
docker compose -f docker/docker-compose.yml logs -f frontend
docker compose -f docker/docker-compose.yml logs -f postgres
# Derniers 100 lignes
docker compose -f docker/docker-compose.yml logs --tail=100 backend
```
### Metriques
Surveillez les indicateurs suivants :
| Indicateur | Commande | Seuil d'alerte |
| ---------- | -------- | --------------- |
| CPU/RAM conteneurs | `docker stats` | > 80% RAM |
| Espace disque | `df -h` | > 85% |
| Connexions PostgreSQL | `docker exec postgres psql -U libredecision -c "SELECT count(*) FROM pg_stat_activity;"` | > 80 |
| Taille base de donnees | `docker exec postgres psql -U libredecision -c "SELECT pg_size_pretty(pg_database_size('libredecision'));"` | Information |
| Statut IPFS | `docker exec ipfs ipfs id` | Erreur |
## Sauvegarde PostgreSQL
### Sauvegarde manuelle
```bash
# Dump complet de la base
docker compose -f docker/docker-compose.yml exec postgres \
pg_dump -U libredecision -Fc libredecision > backup_$(date +%Y%m%d_%H%M%S).dump
```
### Restauration
```bash
# Restaurer un dump
docker compose -f docker/docker-compose.yml exec -T postgres \
pg_restore -U libredecision -d libredecision --clean < backup_20260228_120000.dump
```
### Sauvegarde automatique (cron)
Ajoutez un crontab pour des sauvegardes quotidiennes :
```bash
# Editer le crontab
crontab -e
# Ajouter une sauvegarde quotidienne a 3h du matin
0 3 * * * cd /opt/libredecision && docker compose -f docker/docker-compose.yml exec -T postgres pg_dump -U libredecision -Fc libredecision > /opt/backups/libredecision_$(date +\%Y\%m\%d).dump && find /opt/backups -name "libredecision_*.dump" -mtime +30 -delete
```
Cette commande :
1. Execute un dump quotidien a 3h du matin
2. Stocke les sauvegardes dans `/opt/backups/`
3. Supprime automatiquement les sauvegardes de plus de 30 jours
## Mise a jour
### Procedure standard
```bash
cd /opt/libredecision
# 1. Tirer les dernieres images
docker compose -f docker/docker-compose.yml pull
# 2. Redemarrer les services avec les nouvelles images
docker compose -f docker/docker-compose.yml up -d --remove-orphans
# 3. Appliquer les migrations de base de donnees
docker compose -f docker/docker-compose.yml exec backend alembic upgrade head
# 4. Nettoyer les anciennes images
docker image prune -f
# 5. Verifier le deploiement
docker compose -f docker/docker-compose.yml ps
curl -s https://decision.librodrome.org/api/health
```
### Pipeline CI/CD (Woodpecker)
La pipeline Woodpecker CI automatise le deploiement lors d'un push sur `main` :
1. **test-backend** : execution des tests Python (`pytest`)
2. **test-frontend** : build du frontend Nuxt (`npm run build`)
3. **docker-backend** : construction et push de l'image Docker backend
4. **docker-frontend** : construction et push de l'image Docker frontend
5. **deploy** : connexion SSH au serveur, pull des nouvelles images, redemarrage
Les secrets CI sont configures dans l'interface Woodpecker :
| Secret | Description |
| ------ | ----------- |
| `docker_registry` | URL du registre Docker |
| `docker_username` | Identifiant du registre |
| `docker_password` | Mot de passe du registre |
| `deploy_host` | Adresse du serveur de production |
| `deploy_username` | Utilisateur SSH |
| `deploy_key` | Cle privee SSH |
## Troubleshooting
### Le backend ne demarre pas
**Symptome** : Le conteneur backend redemoarre en boucle.
```bash
# Verifier les logs
docker compose -f docker/docker-compose.yml logs backend
# Causes courantes :
# 1. DATABASE_URL incorrecte -> verifier .env
# 2. PostgreSQL pas encore pret -> verifier le health check
# 3. Migrations non appliquees -> executer alembic upgrade head
```
### Erreur de connexion a PostgreSQL
**Symptome** : `connection refused` ou `password authentication failed`.
```bash
# Verifier que PostgreSQL est sain
docker compose -f docker/docker-compose.yml exec postgres pg_isready
# Verifier les variables d'environnement
docker compose -f docker/docker-compose.yml exec backend env | grep DATABASE
# Reinitialiser le mot de passe si necessaire (attention : destructif)
docker compose -f docker/docker-compose.yml down -v # supprime les volumes
docker compose -f docker/docker-compose.yml up -d # recree avec le nouveau mot de passe
```
### Certificat TLS non genere
**Symptome** : Le site est inaccessible en HTTPS ou affiche un certificat invalide.
1. Verifier que le DNS A/AAAA pointe vers le serveur : `dig decision.librodrome.org`
2. Verifier que les ports 80 et 443 sont ouverts : `ss -tlnp | grep -E '80|443'`
3. Consulter les logs Traefik : `docker logs traefik 2>&1 | grep -i acme`
### IPFS ne repond pas
**Symptome** : Erreur lors de l'archivage dans le Sanctuaire.
```bash
# Verifier le statut du noeud IPFS
docker compose -f docker/docker-compose.yml exec ipfs ipfs id
# Verifier l'espace disque disponible
docker compose -f docker/docker-compose.yml exec ipfs df -h /data/ipfs
# Redemarrer le noeud IPFS
docker compose -f docker/docker-compose.yml restart ipfs
```
### Erreur WebSocket
**Symptome** : L'indicateur de connexion temps reel est rouge.
1. Verifier que Traefik supporte les WebSockets (actif par defaut)
2. Verifier le routage : le WebSocket est sur `/api/v1/ws`
3. Verifier les logs backend pour les erreurs de connexion WebSocket
+278
View File
@@ -0,0 +1,278 @@
---
title: Securite
description: Politique de securite et mesures de protection de libreDecision
---
# Securite
Ce document decrit les mesures de securite implementees dans libreDecision pour proteger l'integrite de la plateforme, des votes et des donnees des utilisateurs.
## Authentification Duniter V2 (Ed25519 challenge-response)
### Principe
libreDecision n'utilise ni mot de passe ni systeme d'inscription classique. L'authentification repose entierement sur la cryptographie Ed25519 de la blockchain Duniter V2.
### Flux challenge-response
```
Client Serveur
| |
|-- POST /auth/challenge ----------->|
| { address: "5Grw..." } |
| |-- Genere challenge (64 hex)
| |-- Stocke en memoire (TTL 5 min)
|<-------- { challenge: "a1b2..." } -|
| |
|-- Signe le challenge localement |
| (cle privee Ed25519) |
| |
|-- POST /auth/verify ------------->|
| { address, challenge, signature}|
| |-- Verifie signature Ed25519
| |-- Verifie identite WoT
| |-- Cree/retrouve DuniterIdentity
| |-- Genere token de session
|<-------- { token: "..." } --------|
```
### Garanties de securite
| Propriete | Mecanisme |
| --------- | --------- |
| **Cle privee jamais transmise** | Seule la signature est envoyee, pas la cle |
| **Anti-replay** | Chaque challenge est usage unique, expire apres 5 minutes |
| **Anti-interception** | HTTPS/TLS obligatoire en production |
| **Identite verifiee** | L'adresse SS58 est verifiee sur la blockchain via `substrate-interface` |
### Verification de la signature
```python
from substrateinterface import Keypair
keypair = Keypair(ss58_address=address)
is_valid = keypair.verify(challenge_bytes, signature_bytes)
```
La cle publique est derivee de l'adresse SS58 sans aucun appel reseau. La verification est locale et instantanee.
## Integrite des votes
### Signature cryptographique des votes
Chaque vote soumis est accompagne d'une **signature Ed25519** qui garantit son authenticite et son integrite.
### Payload signe
Le payload signe contient :
```json
{
"session_id": "uuid-de-la-session",
"vote_value": "for",
"timestamp": "2026-02-28T12:00:00Z"
}
```
Ce payload est signe par la cle privee du votant. La signature est stockee en base de donnees avec le vote, permettant une verification independante a tout moment.
### Proprietes garanties
| Propriete | Description |
| --------- | ----------- |
| **Authenticite** | Seul le proprietaire de l'adresse Duniter peut soumettre un vote en son nom |
| **Integrite** | Le payload ne peut pas etre modifie apres signature sans invalider la signature |
| **Non-repudiation** | Le votant ne peut pas nier avoir vote ; la preuve cryptographique est publique |
| **Transparence** | Les votes signes sont publics et verifiables par quiconque |
### Verification d'un vote
```python
from substrateinterface import Keypair
keypair = Keypair(ss58_address=voter_address)
is_valid = keypair.verify(signed_payload.encode(), signature_bytes)
```
### Protection contre la modification
Quand un votant modifie son vote, l'ancien vote est marque `is_active = false` mais conserve en base. Les deux votes (ancien et nouveau) conservent leur signature. L'historique complet est auditable.
## Rate limiting
### Limites par endpoint
Pour prevenir les abus et les attaques par deni de service, des limites de taux sont appliquees :
| Categorie | Endpoints | Limite | Fenetre |
| --------- | --------- | ------ | ------- |
| Authentification | `/auth/challenge`, `/auth/verify` | 10 requetes | 1 minute |
| Vote | `/votes/sessions/{id}/vote` | 5 requetes | 1 minute |
| Ecriture | `POST`, `PUT`, `DELETE` | 30 requetes | 1 minute |
| Lecture | `GET` | 200 requetes | 1 minute |
| WebSocket | `/ws` | 3 connexions | simultanees par IP |
### Reponse en cas de depassement
Le serveur retourne un code HTTP **429 Too Many Requests** avec un header `Retry-After` indiquant le temps d'attente en secondes.
## En-tetes de securite
Les en-tetes HTTP suivants sont configures en production :
| En-tete | Valeur | Description |
| ------- | ------ | ----------- |
| `Strict-Transport-Security` | `max-age=63072000; includeSubDomains; preload` | Force HTTPS pendant 2 ans, inclut les sous-domaines |
| `Content-Security-Policy` | `default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; connect-src 'self' wss:; img-src 'self' data: https://ipfs.io` | Restreint les sources de contenu autorisees |
| `X-Content-Type-Options` | `nosniff` | Empeche le navigateur de deviner le type MIME |
| `X-Frame-Options` | `DENY` | Empeche l'inclusion dans un iframe (anti-clickjacking) |
| `X-XSS-Protection` | `1; mode=block` | Active la protection XSS du navigateur |
| `Referrer-Policy` | `strict-origin-when-cross-origin` | Limite les informations de referer |
| `Permissions-Policy` | `camera=(), microphone=(), geolocation=()` | Desactive les APIs sensibles non necessaires |
### CSP detaillee
La Content Security Policy est configuree pour :
- Autoriser les scripts uniquement depuis l'origine (`'self'`)
- Autoriser les styles inline (necessaires pour UnoCSS)
- Autoriser les connexions WebSocket (`wss:`)
- Autoriser les images depuis IPFS gateway (`https://ipfs.io`) pour l'affichage des contenus archives
- Bloquer tout le reste
## Sanctuaire : triple preuve d'integrite
### Chaine de verification
```
Contenu --> [SHA-256] --> hash
|
+---> [IPFS] --> CID (content-addressable)
|
+---> [system.remark on-chain] --> preuve horodatee
|
v
Triple preuve :
1. Hash local = hash enregistre (integrite)
2. CID IPFS = contenu identique (distribution)
3. Remark on-chain = hash confirme (immutabilite temporelle)
```
### Garanties
| Preuve | Ce qu'elle garantit | Point de defaillance |
| ------ | ------------------- | -------------------- |
| SHA-256 | Le contenu n'a pas ete modifie | Aucun (mathematique) |
| IPFS CID | Le contenu est distribue et adressable par contenu | Disponibilite des noeuds IPFS |
| On-chain remark | Le hash existait a la date du bloc | Securite de la blockchain Duniter |
### Format du remark on-chain
```
libredecision:sanctuary:{content_hash_sha256}
```
Le prefixe `libredecision:sanctuary:` permet d'identifier les ancrages de libreDecision parmi tous les remarks de la blockchain.
## WebSocket : authentification et securite
### Authentification par token
La connexion WebSocket est authentifiee via le token de session obtenu lors du challenge-response :
```
ws://server/api/v1/ws?token={session_token}
```
Le serveur verifie le token avant d'accepter la connexion. Les connexions non authentifiees sont rejetees.
### Protections WebSocket
| Protection | Description |
| ---------- | ----------- |
| Token valide requis | Pas de connexion anonyme |
| Limite de connexions | Maximum 3 connexions simultanees par IP |
| Heartbeat | Ping/pong periodique pour detecter les connexions mortes |
| Taille maximale des messages | Limite a 64 Ko pour prevenir les abus |
| Broadcast read-only | Les clients recoivent les mises a jour mais ne peuvent pas modifier l'etat via WebSocket |
## Session management
### Tokens de session
| Propriete | Valeur |
| --------- | ------ |
| Duree de vie (TTL) | 24 heures |
| Stockage serveur | Hash SHA-256 du token en base (table `sessions`) |
| Stockage client | Token en clair dans le `localStorage` du navigateur |
| Invalidation | Suppression de l'entree en base via `/auth/logout` |
### Securite des tokens
- Le token est genere avec un generateur cryptographiquement sur (CSPRNG)
- Seul le **hash** du token est stocke en base de donnees. Si la base est compromise, les tokens bruts ne sont pas exposes.
- A chaque requete authentifiee, le token fourni est hashe et compare au hash en base
- Les tokens expires sont nettoyes periodiquement
### Deconnexion
L'appel a `POST /auth/logout` invalide la session cote serveur en supprimant l'entree de la table `sessions`. Le client supprime le token de son `localStorage`.
## Audit logging
### Evenements traces
Les actions suivantes sont enregistrees pour auditabilite :
| Evenement | Donnees enregistrees |
| --------- | -------------------- |
| Authentification reussie | Adresse SS58, timestamp, IP |
| Authentification echouee | Adresse SS58, raison, timestamp, IP |
| Vote soumis | Session ID, voter ID, vote, signature, timestamp |
| Vote modifie | Session ID, voter ID, ancien vote (desactive), nouveau vote |
| Decision creee/avancee | Decision ID, auteur, action, timestamp |
| Document archive | Document ID, hash, CID, tx_hash |
| Session de vote cloturee | Session ID, resultat, seuils |
| Mandat assigne/revoque | Mandate ID, mandataire, action |
### Conservation
Les logs d'audit sont conserves de maniere permanente dans la base de donnees. Les votes et leurs signatures sont particulierement importants car ils constituent la preuve cryptographique des decisions collectives.
## Signalement de vulnerabilite (Responsible disclosure)
### Processus
Si vous decouvrez une vulnerabilite de securite dans libreDecision, merci de suivre cette procedure de divulgation responsable :
1. **Ne divulguez pas publiquement** la vulnerabilite avant qu'un correctif soit disponible.
2. **Contactez l'equipe** via le canal securise indique sur le depot Git Duniter ou via le forum Duniter (message prive aux mainteneurs).
3. **Decrivez la vulnerabilite** avec autant de details que possible :
- Type de vulnerabilite (injection, XSS, CSRF, contournement d'authentification, etc.)
- Etapes pour reproduire
- Impact potentiel
- Suggestion de correctif (si applicable)
4. **Delai de correction** : l'equipe s'engage a accuser reception sous 48 heures et a fournir un correctif sous 14 jours pour les vulnerabilites critiques.
5. **Credit** : les chercheurs en securite qui signalent des vulnerabilites de maniere responsable seront credites dans le changelog (sauf s'ils preferent l'anonymat).
### Perimetre
Le perimetre de la politique de securite couvre :
| Inclus | Exclus |
| ------ | ------ |
| API backend (FastAPI) | Infrastructure d'hebergement tiers |
| Frontend (Nuxt 4) | Blockchain Duniter V2 elle-meme |
| Authentification challenge-response | Extension Polkadot.js |
| Integrite des votes et signatures | Noeud IPFS (kubo) lui-meme |
| WebSocket | Traefik |
| Base de donnees (acces, injection) | -- |
### Exclusions
Les types de signalement suivants sont hors perimetre :
- Deni de service par volume (DDoS)
- Ingenierie sociale
- Attaques physiques sur l'infrastructure
- Vulnerabilites dans les dependances tierces deja connues et trackees (utiliser les issues du depot)
+49
View File
@@ -0,0 +1,49 @@
---
title: Documentation utilisateur
description: Guide d'utilisation de la plateforme libreDecision
---
# Documentation utilisateur
Bienvenue dans la documentation utilisateur de libreDecision, la plateforme de decisions collectives pour la communaute Duniter/G1.
## Qu'est-ce que libreDecision ?
libreDecision est une plateforme de gouvernance decentralisee qui permet aux membres de la Toile de Confiance (WoT) Duniter de :
- Gerer des **documents de reference** modulaires (Licence G1, Engagements Forgeron, Reglement du Comite Technique, etc.) sous vote permanent
- Prendre des **decisions collectives** via des processus multi-etapes (qualification, examen, vote, execution, rapport)
- **Voter** avec un systeme de seuil adaptatif base sur la participation : plus la participation est faible, plus le seuil est exigeant (mecanisme d'inertie)
- Attribuer des **mandats** a des membres de la communaute via des elections formelles
- **Archiver de maniere immuable** les decisions adoptees via IPFS et la blockchain Duniter (triple preuve SHA-256 + IPFS + on-chain)
La plateforme est entierement transparente : tous les votes sont publics, signes cryptographiquement et verifiables par quiconque.
## Guides disponibles
| Guide | Description |
| ----- | ----------- |
| [Premiers pas](/user/getting-started) | Prerequis, premiere connexion, tour de l'interface, premier vote |
| [Documents](/user/documents) | Consulter les documents de reference, proposer des modifications, vote permanent |
| [Decisions](/user/decisions) | Comprendre et participer aux processus decisionnels multi-etapes |
| [Vote](/user/voting) | Types de vote, formule de seuil expliquee, comment voter, jauge de seuil, simulateur |
| [Mandats](/user/mandates) | Elections, candidatures, assignation, reporting, revocation |
| [Sanctuaire](/user/sanctuary) | Archivage immuable, triple preuve, verification d'integrite |
| [FAQ](/user/faq) | Reponses aux questions frequentes sur l'authentification, le vote, les documents, la securite |
## Par ou commencer ?
1. **Nouveau sur libreDecision ?** Commencez par le guide [Premiers pas](/user/getting-started) pour vous connecter et decouvrir l'interface.
2. **Vous voulez voter ?** Consultez le guide [Vote](/user/voting) pour comprendre les types de vote et la formule de seuil.
3. **Vous voulez proposer une modification ?** Le guide [Documents](/user/documents) explique comment proposer des modifications aux textes fondateurs.
4. **Une question ?** La [FAQ](/user/faq) repond aux questions les plus courantes.
## Contribuer a la documentation
Cette documentation est elle-meme un document en evolution. Si vous constatez une erreur, une imprecision ou un manque, vous pouvez :
- Ouvrir une issue sur le [depot Git](https://git.duniter.org/tools/libredecision) de libreDecision
- Proposer une modification directement via une merge request
- En discuter sur le [forum Duniter](https://forum.duniter.org)
La documentation est redigee en Markdown et fait partie du code source du projet (dossier `docs/`). Les contributions suivent le meme processus que le code : branche, merge request, revue.
+181
View File
@@ -0,0 +1,181 @@
---
title: Premiers pas
description: Connexion et prise en main de libreDecision
---
# Premiers pas
Ce guide vous accompagne de votre premiere visite jusqu'a votre premier vote sur libreDecision.
## Prerequis
Avant de commencer, assurez-vous de disposer de :
| Prerequis | Description | Ou l'obtenir |
| --------- | ----------- | ------------ |
| **Navigateur moderne** | Chrome, Firefox, Edge ou Safari a jour | Mis a jour automatiquement |
| **Extension Polkadot.js** | Extension de signature pour Substrate/Duniter V2 | [polkadot.js.org/extension](https://polkadot.js.org/extension/) |
| **Identite Duniter V2** | Adresse SS58 avec une identite confirmee dans la Toile de Confiance | Via Cesium2 ou directement sur la blockchain Duniter V2 |
::callout{type="info"}
Vous pouvez **consulter** les documents, decisions et resultats de vote sans aucune authentification. Seules les actions de participation (voter, proposer, creer) necessitent une identite Duniter.
::
### Installer l'extension Polkadot.js
1. Rendez-vous sur [polkadot.js.org/extension](https://polkadot.js.org/extension/).
2. Installez l'extension pour votre navigateur (Chrome ou Firefox).
3. Creez ou importez votre compte Duniter V2 dans l'extension.
4. Assurez-vous que votre adresse SS58 est bien celle liee a votre identite Duniter.
## Qui peut utiliser libreDecision ?
libreDecision est ouvert a tous les membres de la Toile de Confiance (WoT) Duniter V2. Pour utiliser pleinement la plateforme, vous devez posseder une identite Duniter avec une adresse SS58 valide.
- **Consultation** : tout visiteur peut consulter les documents, decisions et resultats de vote.
- **Participation** (voter, proposer) : reservee aux membres authentifies via leur identite Duniter.
## Premiere connexion
La connexion utilise votre identite Duniter sans jamais transmettre votre cle privee. Le mecanisme est un **challenge-response** cryptographique :
### Comment ca marche (en termes simples)
Imaginez que la plateforme vous montre une phrase aleatoire et vous demande de la signer avec votre cle privee. C'est comme signer un document avec un stylo que vous seul possedez. La plateforme peut verifier que c'est bien votre signature grace a votre cle publique, sans jamais voir votre cle privee.
### Etape par etape
1. Cliquez sur **Se connecter** dans la barre de navigation.
2. Saisissez votre **adresse Duniter** (format SS58, par exemple `5GrwvaEF...`).
3. La plateforme vous envoie un **challenge** : un texte aleatoire de 64 caracteres hexadecimaux.
4. Votre extension Polkadot.js (ou votre portefeuille Cesium) vous demande d'autoriser la signature du challenge avec votre cle privee Ed25519.
5. Signez le challenge. Votre cle privee ne quitte jamais votre appareil.
6. Soumettez la signature. La plateforme verifie que vous etes bien le proprietaire de l'adresse.
7. Vous etes connecte. Un jeton de session est stocke localement (valable 24 heures).
::callout{type="tip"}
Votre cle privee n'est **jamais** transmise au serveur. Seule la signature du challenge est envoyee. C'est le principe fondamental de l'authentification par challenge-response Ed25519.
::
## Tour de l'interface
### Barre de navigation
La barre de navigation en haut de page contient :
- **Logo libreDecision** : retour a l'accueil
- **Menu principal** : acces aux cinq sections
- **Bouton de connexion** / **Votre profil** (si connecte)
- **Indicateur temps reel** : point colore indiquant l'etat de la connexion WebSocket
### Sidebar (menu lateral)
La sidebar sur la gauche donne acces aux cinq sections principales :
| Section | Icone | Description |
| ------------ | ----- | ---------------------------------------------------- |
| Documents | -- | Documents de reference de la communaute |
| Decisions | -- | Processus decisionnels en cours et archives |
| Votes | -- | Sessions de vote actives et resultats |
| Mandats | -- | Mandats attribues aux membres |
| Sanctuaire | -- | Archives immuables (IPFS + blockchain) |
### Dashboard (tableau de bord)
Apres connexion, le tableau de bord affiche un apercu rapide de :
- **Votes en cours** : les sessions de vote ouvertes auxquelles vous pouvez participer
- **Vos derniers votes** : historique de vos votes recents
- **Decisions actives** : les processus decisionnels en cours
- **Mandats** : les mandats actifs et en cours d'election
- **Activite recente** : flux des dernieres actions sur la plateforme
## Votre profil
Apres connexion, votre profil affiche :
- Votre **adresse Duniter** SS58
- Votre **nom d'affichage** (si configure)
- Votre **statut WoT** : membre, en attente, revoque
- Vos **roles** : membre Smith (forgeron) et/ou membre du Comite Technique
Ces informations sont synchronisees depuis la blockchain Duniter V2 et determinent vos droits de vote.
## Premier vote : voter sur un item de document
Voici comment participer a votre premier vote en quelques minutes :
### 1. Trouver un vote ouvert
- Depuis le tableau de bord, consultez la section **Votes en cours**.
- Ou rendez-vous dans la section **Votes** du menu et filtrez par statut "En cours".
- Les sessions ouvertes sont signalees par un badge vert.
### 2. Lire le sujet
- Cliquez sur la session de vote qui vous interesse.
- Lisez attentivement le texte soumis au vote (document, decision, modification d'item).
- Consultez le diff si c'est une modification : les ajouts sont en vert, les suppressions en rouge.
### 3. Voter
- **Vote binaire** : cliquez sur **Pour** (vert) ou **Contre** (rouge).
- **Vote nuance** : choisissez un niveau de 0 (CONTRE) a 5 (TOUT A FAIT) sur l'echelle proposee.
- Ajoutez un **commentaire** si vous souhaitez expliquer votre choix (optionnel mais recommande).
### 4. Signer votre vote
- Apres avoir choisi, la plateforme genere un payload contenant votre vote, l'identifiant de la session et un horodatage.
- Votre extension Polkadot.js vous demande de signer ce payload.
- Signez, puis cliquez sur **Soumettre**.
### 5. Verification
- Un message de confirmation apparait.
- Votre vote est visible dans la liste des votes de la session.
- La jauge de seuil se met a jour en temps reel pour refleter votre vote.
::callout{type="info"}
Vous pouvez modifier votre vote a tout moment tant que la session est ouverte. L'ancien vote est conserve pour l'audit mais seul le dernier compte.
::
## Premiers pas avec les decisions
Au-dela du vote, vous pouvez participer activement a la gouvernance :
### Proposer une modification de document
1. Ouvrez un document de reference dans la section **Documents**.
2. Selectionnez l'item (clause, regle, article) que vous souhaitez modifier.
3. Cliquez sur **Proposer une modification**.
4. Redigez votre nouveau texte et justifiez votre proposition.
5. Soumettez : un diff est genere automatiquement.
Votre proposition sera examinee et soumise au vote par la communaute.
### Creer une decision
1. Rendez-vous dans la section **Decisions**.
2. Cliquez sur **Nouvelle decision**.
3. Renseignez le titre, la description et le contexte.
4. Choisissez le type de decision et le protocole de vote.
5. Definissez les etapes du processus.
### Consulter le Sanctuaire
Le Sanctuaire contient les archives immuables de toutes les decisions adoptees, documents archives et resultats de vote. Rendez-vous dans la section **Sanctuaire** pour explorer l'historique verifiable de la communaute.
## Deconnexion
Cliquez sur votre profil puis **Se deconnecter**. La session est invalidee cote serveur et le jeton local est supprime.
## Pour aller plus loin
| Guide | Description |
| ----- | ----------- |
| [Documents](/user/documents) | Tout savoir sur les documents de reference et leurs modifications |
| [Decisions](/user/decisions) | Comprendre les processus decisionnels multi-etapes |
| [Vote](/user/voting) | Comprendre les types de vote, la formule de seuil et le simulateur |
| [Mandats](/user/mandates) | Elections et responsabilites au sein de la communaute |
| [Sanctuaire](/user/sanctuary) | Archivage immuable et verification d'integrite |
| [FAQ](/user/faq) | Reponses aux questions frequentes |
+233
View File
@@ -0,0 +1,233 @@
---
title: Documents
description: Guide des documents de reference sur libreDecision
---
# Documents de reference
## Qu'est-ce qu'un document de reference ?
Un document de reference est un **texte fondateur** de la communaute Duniter/G1. Il peut s'agir d'une licence monetaire, d'un engagement que les membres s'engagent a respecter, d'un reglement interieur ou d'un texte constitutif. Ces documents definissent les regles, les valeurs et le fonctionnement de la communaute.
Ce qui rend libreDecision unique, c'est que ces documents sont **modulaires** et sous **vote permanent** : chaque document est compose d'items individuels (clauses, regles, verifications, preambules, sections) qui peuvent etre modifies independamment par proposition et vote. La communaute peut faire evoluer ses textes de maniere continue, sans procedure lourde ni periode speciale.
## Types de documents
| Type | Description | Exemples |
| -------------- | --------------------------------------------------- | -------------------------------- |
| Licence | Licence monetaire definissant les regles de la monnaie | Licence G1 |
| Engagement | Engagement des membres a respecter des regles | Engagement Forgeron v2.0.0 |
| Reglement | Reglement interieur d'un organe | Reglement du Comite Technique |
| Constitution | Texte constitutif fondamental | -- |
## Structure : Document, Items et Versions
Un document est organise selon une structure a trois niveaux :
```
Document (ex: Licence G1 v2.0.0)
|
+-- Item 1 (clause 1 : Preambule)
| |-- Version 1.0 (texte courant)
| |-- Version 1.1 (proposition en attente)
|
+-- Item 2 (regle 2.1 : Conditions d'adhesion)
| |-- Version 1.0 (texte courant)
|
+-- Item 3 (verification 3.1 : Distance rule)
|-- Version 1.0 (texte courant)
|-- Version 1.1 (proposition rejetee)
|-- Version 1.2 (proposition en vote)
```
### Document
Le document est le conteneur. Il possede un titre, un type, un numero de version semantique (ex: `2.0.0`), un statut et une description.
### Item
Chaque item est une unite modulaire du document : une clause, une regle, une verification, un preambule ou une section. Chaque item a une position hierarchique (ex: "1", "1.1", "3.2") et un texte courant.
### Version
Chaque modification proposee a un item cree une nouvelle version. La version contient le texte propose, un diff automatique par rapport au texte courant, et la justification de l'auteur. Les versions suivent un cycle de vie : proposee, en vote, acceptee ou rejetee.
## Consulter un document
1. Rendez-vous dans la section **Documents**.
2. Utilisez les filtres (type, statut) pour trouver le document souhaite.
3. Cliquez sur le document pour voir la liste de ses items.
4. Chaque item affiche son texte courant, son type et sa position dans le document.
### Voir un item en detail
Pour consulter un item specifique avec tout son historique :
1. Depuis la liste des items du document, cliquez sur l'item souhaite.
2. La vue detaillee affiche :
- Le **texte courant** de l'item.
- Le **type** (clause, regle, verification, preambule, section) et la **position** hierarchique.
- Le **protocole de vote** specifique a cet item (s'il en a un).
- L'**historique des versions** proposees, avec pour chacune son statut (proposee, en vote, acceptee, rejetee).
3. Pour chaque version, vous pouvez consulter le **diff** (differences entre le texte courant et le texte propose) ainsi que la **justification** de l'auteur.
## Proposer une modification (version)
Tout membre authentifie peut proposer une modification a un item de document :
1. Ouvrez le document et selectionnez l'item a modifier.
2. Cliquez sur **Proposer une modification**.
3. Redigez le **nouveau texte propose**.
4. Ajoutez une **justification** expliquant pourquoi cette modification est necessaire.
5. Soumettez. Un diff automatique est genere entre le texte courant et votre proposition.
La proposition cree une nouvelle **version** de l'item. Cette version passe ensuite par un processus de decision (examen, vote) avant d'etre acceptee ou rejetee.
::callout{type="info"}
Plusieurs versions peuvent etre proposees simultanement pour un meme item. Lorsqu'une version est acceptee, toutes les autres versions en attente sont automatiquement rejetees.
::
## Vote permanent sur les items
Les documents actifs sont sous **vote permanent** : il n'y a pas de periode speciale pour proposer des changements. A tout moment, un membre authentifie peut proposer une modification a n'importe quel item.
Chaque item peut avoir un **protocole de vote specifique** qui definit les parametres de seuil (duree, majorite, gradient, criteres Smith/TechComm). Si aucun protocole specifique n'est defini, le protocole par defaut du document s'applique.
Le vote permanent garantit que les textes fondateurs peuvent evoluer de maniere continue et organique, en refletant en permanence la volonte de la communaute.
## Examiner et accepter/rejeter une version
Les membres habilites (selon le protocole de vote associe) peuvent examiner les versions proposees :
### Consulter les versions en attente
1. Ouvrez le document et selectionnez l'item concerne.
2. Consultez la liste des **versions proposees** dans l'onglet historique.
3. Chaque version affiche :
- Le **texte propose** et le **diff** par rapport au texte courant.
- La **justification** fournie par l'auteur.
- Le **statut** actuel (proposee, en vote, acceptee, rejetee).
- L'**identite** du proposant.
### Accepter une version
1. Selectionnez la version a accepter.
2. Cliquez sur **Accepter cette version**.
3. Le texte propose **remplace automatiquement** le texte courant de l'item.
4. Toutes les autres versions en statut `proposee` ou `en vote` pour cet item sont **automatiquement rejetees**.
### Rejeter une version
1. Selectionnez la version a rejeter.
2. Cliquez sur **Rejeter cette version**.
3. Le texte courant de l'item **reste inchange**.
4. La version est archivee avec le statut `rejetee`.
## Cycle de vie d'une proposition
```
Proposee --> En vote --> Acceptee --> Texte courant mis a jour
--> Rejetee --> Archivee
```
## Cycle de vie d'un document
Un document suit un cycle de vie en trois etapes :
```
Brouillon --> Actif --> Archive
```
### Brouillon (draft)
Le document est en cours de redaction. Les items peuvent etre ajoutes, modifies, supprimes et reordonnes librement. Le document n'est pas encore soumis au vote permanent.
### Actif (active)
Le document est en vigueur et sous **vote permanent**. Tout membre authentifie peut proposer des modifications aux items via le systeme de versions. Les modifications sont soumises au processus de decision (qualification, examen, vote) avant d'etre appliquees.
### Archive (archived)
Le document a ete archive dans le **Sanctuaire**. Son contenu est fige et preserve de maniere immuable via :
- Un hash SHA-256 pour garantir l'integrite.
- Un stockage sur IPFS pour la distribution decentralisee.
- Un ancrage on-chain via `system.remark` sur Duniter V2.
Un document archive ne peut plus etre modifie. Pour le consulter, rendez-vous dans la section Sanctuaire.
## Statuts des documents
| Statut | Description |
| --------- | ------------------------------------------------ |
| Brouillon | En cours de redaction, non soumis au vote |
| Actif | Document en vigueur, sous vote permanent |
| Archive | Document archive dans le Sanctuaire, plus modifiable |
## Archiver un document dans le Sanctuaire
Pour archiver un document actif (necessite une authentification) :
1. Ouvrez le document actif a archiver.
2. Cliquez sur **Archiver dans le Sanctuaire**.
3. Le systeme effectue automatiquement :
- La serialisation complete du document (metadonnees + tous les items).
- Le calcul du hash SHA-256 du contenu.
- L'envoi du contenu sur IPFS.
- L'ancrage du hash on-chain.
4. Le statut du document passe a **Archive**.
5. Les champs **CID IPFS** et **ancrage on-chain** sont renseignes sur le document.
::callout{type="warning"}
L'archivage est une operation irreversible. Une fois archive, le document ne peut plus etre modifie.
::
## Versionnage
Chaque document possede un numero de version semantique (ex: `2.0.0`). Chaque modification adoptee peut entrainer une mise a jour de version selon l'importance du changement.
## Exemple concret : modifier un article de la Licence G1
Prenons un exemple complet de bout en bout. Vous souhaitez modifier la regle de distance (item 3.1) de la Licence G1 pour preciser une condition supplementaire.
### 1. Trouver l'item
- Rendez-vous dans **Documents** et ouvrez la **Licence G1**.
- Faites defiler jusqu'a l'item **3.1 -- Distance rule** et cliquez dessus.
### 2. Consulter le texte courant
- Lisez le texte en vigueur et l'historique des versions precedentes.
- Verifiez que votre modification n'a pas deja ete proposee par quelqu'un d'autre.
### 3. Proposer votre modification
- Cliquez sur **Proposer une modification**.
- Redigez votre nouveau texte. Par exemple, ajoutez une precision sur le nombre de pas de distance autorise.
- Dans le champ **Justification**, expliquez pourquoi : "La regle actuelle ne precise pas le cas ou un membre est a la limite exacte de la distance maximale. Cette modification clarifie que la distance est inclusive."
- Soumettez votre proposition.
### 4. Le diff est genere
Le systeme genere automatiquement un diff montrant les differences :
```diff
- Le membre doit respecter la regle de distance WoT.
+ Le membre doit respecter la regle de distance WoT. La distance
+ maximale est inclusive : un membre a exactement 5 pas est conforme.
```
### 5. Examen et vote
- La communaute peut consulter votre proposition, lire votre justification et examiner le diff.
- Si un processus de decision est lance, une session de vote est creee.
- Les membres votent selon le protocole de vote associe a cet item.
### 6. Resultat
- **Si acceptee** : votre texte remplace le texte courant de l'item 3.1. Toutes les autres propositions en attente pour cet item sont automatiquement rejetees. Le numero de version du document peut etre mis a jour.
- **Si rejetee** : le texte courant reste inchange. Votre proposition est archivee avec le statut "rejetee" pour transparence.
### 7. Archivage
Si la modification est suffisamment importante, le document mis a jour peut etre archive dans le Sanctuaire, creant une trace immuable de cette evolution.
+142
View File
@@ -0,0 +1,142 @@
---
title: Decisions
description: Guide des processus decisionnels sur libreDecision
---
# Decisions
## Principe
Une decision est un processus structure qui conduit a un choix collectif. Chaque decision suit un ensemble d'etapes definies, de la qualification a l'execution. Le systeme garantit la tracabilite de chaque etape et l'integration avec le systeme de vote WoT.
## Types de decisions
| Type | Description | Cas d'usage |
| ------------------ | ------------------------------------------------------ | -------------------------------------------------------- |
| `runtime_upgrade` | Mise a jour du runtime de la blockchain Duniter | Upgrade du reseau, changement de parametres consensus |
| `document_change` | Modification d'un item de document de reference | Amendement de la Licence G1, modification d'un engagement |
| `mandate_vote` | Vote pour l'attribution d'un mandat | Election d'un membre du Comite Technique |
| `parameter_change` | Modification de parametres systeme | Changement de duree de vote, seuil de majorite |
| `custom` | Decision personnalisee | Tout autre type de decision collective |
## Cycle de vie d'une decision
Une decision progresse a travers six statuts successifs :
```
Brouillon --> Qualification --> Examen --> Vote --> Executee --> Cloturee
|
+--> Rejetee (si le vote echoue)
```
| Statut | Description |
| ----------------- | ---------------------------------------------------------------- |
| `draft` | Brouillon initial. La decision est en cours de redaction et peut etre modifiee librement ou supprimee. |
| `qualification` | Phase de verification. On s'assure que la proposition est recevable (forme, competence, pertinence). |
| `review` | Periode d'examen et de discussion par la communaute. Les membres peuvent commenter et suggerer des amendements. |
| `voting` | Session de vote formelle. Le seuil de validation WoT s'applique. Une session de vote est creee et liee a l'etape correspondante. |
| `executed` | La decision a ete adoptee et est en cours de mise en oeuvre. |
| `closed` | La decision est cloturee. Le resultat est archive dans le sanctuaire. |
Si le vote echoue (seuil non atteint), la decision passe en statut "rejetee" et ne peut plus avancer.
## Etapes d'une decision (decision_steps)
Chaque decision est composee d'etapes ordonnees qui definissent le workflow concret. Les types d'etapes disponibles sont :
| Type d'etape | Description |
| --------------- | ---------------------------------------------------------------- |
| `qualification` | Verification que la proposition est recevable |
| `review` | Periode d'examen et de discussion par la communaute |
| `vote` | Session de vote formelle avec seuil de validation WoT |
| `execution` | Mise en oeuvre de la decision adoptee |
| `reporting` | Compte-rendu de l'execution et archivage des resultats |
Chaque etape possede un statut individuel :
| Statut | Description |
| ----------- | ---------------------------------------------------------- |
| `pending` | L'etape n'a pas encore commence |
| `active` | L'etape est en cours |
| `completed` | L'etape est terminee avec succes |
| `skipped` | L'etape a ete ignoree (non applicable pour ce type de decision) |
## Comment le workflow avance
Le workflow d'une decision avance via l'action **"Avancer"** (endpoint `POST /decisions/{id}/advance`). A chaque appel :
1. **S'il y a une etape active** : elle est marquee `completed`, et la prochaine etape `pending` est activee.
2. **S'il n'y a pas d'etape active** : la premiere etape `pending` est activee. Si la decision est en `draft`, elle passe automatiquement en `qualification`.
3. **Si toutes les etapes sont terminees** : le statut global de la decision avance au statut suivant dans le cycle de vie.
Ce mecanisme garantit que les etapes sont parcourues dans l'ordre defini (`step_order`) et qu'aucune etape ne peut etre sautee involontairement.
## Creation d'une session de vote
Quand une etape de type `vote` est active, il faut creer une session de vote liee a cette etape. Cela se fait via l'action **"Creer une session de vote"** (endpoint `POST /decisions/{id}/steps/{step_id}/create-vote-session`).
La session de vote :
- Est automatiquement liee au protocole de vote de la decision
- Prend un snapshot des tailles WoT, Smith et TechComm au moment de la creation
- Calcule la date de fin en fonction de la duree definie dans la formule du protocole
- Est rattachee a l'etape via le champ `vote_session_id`
Une fois la session de vote cloturee (manuellement ou par expiration), l'etape peut etre completee et le workflow peut avancer.
## Creer une decision
Les membres authentifies peuvent creer une decision :
1. Cliquez sur **Nouvelle decision**.
2. Renseignez le **titre** : un intitule clair et concis de la proposition.
3. Renseignez la **description** : le detail de ce qui est propose.
4. Renseignez le **contexte** : pourquoi cette decision est necessaire (cadrage).
5. Choisissez le **type de decision** : `runtime_upgrade`, `document_change`, `mandate_vote`, `parameter_change` ou `custom`.
6. Selectionnez un **protocole de vote** qui definit les parametres de la formule de seuil WoT (duree, majorite, gradient, criteres Smith/TechComm).
7. **Ajoutez les etapes** necessaires dans l'ordre souhaite (qualification, examen, vote, execution, reporting).
8. Soumettez. La decision est creee en statut `draft`.
9. Utilisez l'action **"Avancer"** pour lancer la premiere etape et demarrer le processus.
## Supprimer une decision
Les decisions en statut `draft` peuvent etre supprimees via l'action **"Supprimer"** (endpoint `DELETE /decisions/{id}`). Une fois le processus demarre (statut `qualification` ou au-dela), la decision reste dans le systeme pour tracabilite.
## Suivre une decision
1. Rendez-vous dans la section **Decisions**.
2. Filtrez par type ou statut pour trouver la decision qui vous interesse.
3. La page de detail affiche toutes les etapes avec leur statut (en attente, active, terminee, ignoree).
4. Si une etape de vote est active et qu'une session de vote est ouverte, vous pouvez voter directement depuis la page de decision.
5. Le resultat du vote (seuil, participation, criteres Smith/TechComm) est affiche en temps reel.
## Exemple : Processus de Runtime Upgrade
Un Runtime Upgrade suit un processus en 5 etapes strictement definies :
```
1. Qualification -> Verification technique par le Comite Technique
2. Examen -> Review du code par les forgerons, discussion communautaire
3. Vote -> Vote WoT avec criteres Smith et TechComm obligatoires
4. Execution -> Deploiement du runtime sur le reseau
5. Reporting -> Compte-rendu post-deploiement, verification de stabilite
```
**Deroulement concret :**
1. Un membre cree une decision de type `runtime_upgrade` avec le contexte technique (version, changelog, hash du wasm).
2. Il ajoute les 5 etapes dans l'ordre.
3. Il avance la decision : l'etape "Qualification" devient active. Le Comite Technique verifie le build.
4. Une fois la qualification validee, il avance : l'etape "Examen" devient active. Les forgerons reviewent le code.
5. Il avance : l'etape "Vote" devient active. Une session de vote est creee avec le protocole incluant les criteres Smith et TechComm.
6. Les membres votent. Le seuil WoT s'applique avec inertie. Les criteres Smith (`ceil(SmithWotSize^S)`) et TechComm (`ceil(CoTecSize^T)`) doivent aussi etre atteints.
7. Si adopte, il avance : l'etape "Execution" devient active. Le runtime est deploye.
8. Il avance : l'etape "Reporting" devient active. Le compte-rendu est redige.
9. Il avance une derniere fois : la decision passe en statut `closed`.
## Lien avec les documents
Quand une decision de type `document_change` est adoptee, la modification proposee est automatiquement appliquee a l'item du document concerne. L'ancienne version est conservee dans l'historique des versions (`item_versions`).
## Lien avec les mandats
Les decisions de type `mandate_vote` sont utilisees pour les elections de mandats. La decision contient une etape de vote qui determine le resultat de l'election. Voir la section [Mandats](/user/mandates) pour plus de details.
+411
View File
@@ -0,0 +1,411 @@
---
title: Vote
description: Guide du systeme de vote sur libreDecision
---
# Vote
## Principe
Le systeme de vote de libreDecision est concu pour adapter le seuil d'adoption a la participation reelle. Quand peu de membres votent, une quasi-unanimite est exigee. Quand la participation est elevee, une majorite simple suffit. Ce mecanisme d'**inertie** protege contre les decisions prises par un petit groupe.
## Types de vote
### Vote binaire
Chaque votant choisit **Pour** ou **Contre**. Le seuil est calcule par la formule WoT.
### Vote nuance
Chaque votant exprime son opinion sur une echelle a 6 niveaux :
| Niveau | Label | Signification | Comptage |
| ------ | ------------- | --------------------------------------------------- | -------- |
| 0 | CONTRE | Opposition totale et ferme | Negatif |
| 1 | PAS DU TOUT | Desaccord fort, points essentiels non remplis | Negatif |
| 2 | PAS D'ACCORD | Desaccord modere, des reserves importantes | Negatif |
| 3 | NEUTRE | Ni pour ni contre, ou acceptation sans enthousiasme | Positif |
| 4 | D'ACCORD | Approbation avec eventuellement des reserves mineures | Positif |
| 5 | TOUT A FAIT | Approbation totale et enthousiaste | Positif |
Le vote nuance est adopte si les niveaux positifs (3, 4, 5) representent au moins **80%** des votes et qu'un nombre minimum de participants est atteint (par defaut 59).
### Quand utiliser le vote nuance ?
Le vote nuance est recommande pour :
- Les textes longs comportant de nombreux articles (les votants peuvent exprimer un accord partiel).
- Les decisions ou la nuance est importante (budget, parametre technique).
- Les cas ou il est utile de mesurer le degre d'adhesion, pas seulement le resultat binaire.
## La formule de seuil expliquee simplement
### L'analogie de l'inertie
Imaginez un gros rocher pose au sommet d'une colline. Pour le deplacer, il faut une force considerable : c'est l'**inertie**. Dans libreDecision, le rocher represente le statu quo et la force necessaire represente le nombre de votes favorables.
- **Quand peu de personnes poussent** (faible participation) : il faut que presque tout le monde pousse dans la meme direction. Si seulement 10 personnes sur 7000 votent, il faut que 9 sur 10 soient pour.
- **Quand beaucoup de personnes poussent** (forte participation) : la majorite simple suffit. Si 7000 personnes votent, il suffit que 3500 soient pour (50%).
Ce mecanisme empeche qu'un petit groupe prenne des decisions engageant toute la communaute, tout en permettant une gouvernance efficace quand la participation est large.
### La formule
La formule exacte est :
```
Seuil = C + B^W + (M + (1-M) * (1 - (T/W)^G)) * max(0, T-C)
```
Ou :
| Symbole | Signification | Exemple |
| ------- | ------------- | ------- |
| C | Base constante (plancher minimum) | 0 |
| B | Exposant de base (negligeable pour grandes communautes) | 0.1 |
| W | Taille de la Toile de Confiance (membres eligibles) | 7224 |
| T | Nombre total de votes exprimes | 120 |
| M | Ratio de majorite cible a pleine participation | 0.50 (50%) |
| G | Gradient : vitesse de convergence vers la majorite | 0.2 |
### Exemple concret
Pour le vote de l'**Engagement Forgeron v2.0.0** :
- WoT = 7224 membres, 120 votes (1.7% de participation)
- Parametres : M=50%, B=0.1, G=0.2, C=0
- **Seuil calcule : 94 votes favorables requis** (soit 78% des votants)
- Resultat : 97 pour, 23 contre -- **Adopte** (97 >= 94)
La faible participation a rendu le seuil exigeant : 78% au lieu de 50%. C'est l'inertie en action.
### Tableau d'inertie
Le tableau suivant montre comment l'exigence evolue avec la participation, pour les parametres de reference `M50 G.2` avec une WoT de 7224 :
| Participation | % de la WoT | % favorables requis |
| ------------: | ----------: | ------------------: |
| 10 | 0.1% | 87.4% |
| 50 | 0.7% | 82.3% |
| 100 | 1.4% | 80.1% |
| 120 | 1.7% | 79.5% |
| 200 | 2.8% | 77.7% |
| 500 | 6.9% | 74.4% |
| 1000 | 13.8% | 71.2% |
| 2000 | 27.7% | 67.7% |
| 5000 | 69.2% | 62.6% |
| 7224 | 100% | 50.0% |
On constate que meme a 500 votants (6.9%), il faut encore 74.4% de votes favorables. L'inertie ne descend en dessous de 66% qu'au-dela de 2000 votants.
## Criteres additionnels
### Critere Smith (Forgerons)
Certaines decisions exigent un nombre minimum de votes favorables de la part des **forgerons** (membres Smith de la WoT). Ce critere garantit que les decisions qui affectent le reseau sont soutenues par ceux qui le maintiennent.
Le seuil Smith est calcule par : `ceil(SmithWotSize^S)` ou `S` est l'exposant Smith.
**Exemple** : Avec 20 forgerons et S=0.1, le seuil est `ceil(20^0.1) = ceil(1.35) = 2`. Il faut au minimum 2 votes favorables de forgerons.
### Critere TechComm (Comite Technique)
De maniere similaire, certaines decisions exigent un nombre minimum de votes favorables du **Comite Technique**. Cela concerne les decisions techniques (runtime upgrades, modifications d'infrastructure).
Le seuil TechComm est calcule par : `ceil(CoTecSize^T)` ou `T` est l'exposant TechComm.
**Exemple** : Avec 5 membres TechComm et T=0.1, le seuil est `ceil(5^0.1) = ceil(1.17) = 2`. Il faut au minimum 2 votes favorables du Comite Technique.
### Adoption finale
Un vote n'est adopte que si **les trois conditions** sont remplies simultanement :
1. Les votes favorables atteignent le seuil WoT (formule principale)
2. Les votes favorables des forgerons atteignent le seuil Smith (si actif)
3. Les votes favorables du Comite Technique atteignent le seuil TechComm (si actif)
## Mode params : decoder les parametres
Les parametres de formule sont encodes dans une chaine compacte pour faciliter la lecture. Voici comment decoder `"D30M50B.1G.2T.1"` :
| Code | Valeur | Signification |
| ---- | ------ | ------------- |
| D30 | 30 | Duree du vote : **30 jours** |
| M50 | 50% | Majorite cible : **50%** (majorite simple a pleine participation) |
| B.1 | 0.1 | Exposant de base : **0.1** (negligeable pour grandes WoT) |
| G.2 | 0.2 | Gradient : **0.2** (convergence rapide vers la majorite) |
| T.1 | 0.1 | Exposant TechComm : **0.1** (critere TechComm actif) |
Autres codes possibles :
| Code | Parametre | Exemple | Signification |
| ---- | --------- | ------- | ------------- |
| C | Base constante | C3 | Minimum 3 votes favorables quelle que soit la formule |
| S | Exposant Smith | S.1 | Critere Smith actif avec exposant 0.1 |
| N | Multiplicateur ratio | N1.5 | Multiplicateur 1.5 en mode ratio |
| R | Mode ratio | R1 | Mode ratio active |
### Exemples de configurations
- `"D30M50B.1G.2"` : 30 jours, majorite 50%, configuration standard
- `"D30M50B.1G.2S.1T.1"` : idem avec criteres Smith et TechComm
- `"D60M66B.05G.3"` : 60 jours, super-majorite 66%, gradient plus strict
- `"D14M50B.1G.1"` : 14 jours, gradient rapide (decisions urgentes)
## Comment voter : etapes concretes
### Vote binaire
1. **Acceder a la session de vote** : Rendez-vous dans la section **Votes** depuis le menu principal, ou accedez directement a la page d'une decision en cours. Les sessions ouvertes sont signalees par un badge vert "En cours".
2. **Consulter le sujet** : Lisez attentivement le document ou la decision soumise au vote. Le texte complet est affiche au-dessus du panneau de vote. Vous pouvez deployer chaque article pour consulter le detail.
3. **Choisir votre vote** : Le panneau de vote affiche deux boutons :
- **Pour** (bouton vert) : Vous approuvez la proposition.
- **Contre** (bouton rouge) : Vous rejetez la proposition.
4. **Ajouter un commentaire** (optionnel) : Un champ de texte sous les boutons vous permet d'expliquer votre choix. Le commentaire est public et visible par tous les membres.
5. **Signer votre vote** : Apres avoir clique sur votre choix, la plateforme genere un payload contenant votre vote, l'identifiant de la session et un horodatage. Votre extension de cle ou votre portefeuille Duniter vous demande de **signer ce payload** avec votre cle privee Ed25519.
6. **Confirmer la soumission** : Une fois la signature effectuee, cliquez sur **Soumettre**. Un message de confirmation apparait avec le resume de votre vote.
### Vote nuance
1. **Acceder a la session** : Meme procedure que pour le vote binaire. Les sessions de vote nuance sont identifiees par un badge "Nuance" en plus du badge de statut.
2. **Consulter le sujet** : Lisez le document ou la decision soumise au vote.
3. **Choisir votre niveau** : Le panneau de vote nuance affiche une echelle a 6 niveaux sous forme de curseur ou de boutons. Les niveaux 3, 4 et 5 sont comptes comme **positifs**. Les niveaux 0, 1 et 2 sont comptes comme **negatifs**.
4. **Ajouter un commentaire** (optionnel) : Particulierement utile pour les niveaux intermediaires (1, 2, 3, 4), afin d'expliquer vos reserves ou vos attentes.
5. **Signer et soumettre** : Meme procedure que pour le vote binaire.
### Modifier son vote
Tant que la session est ouverte, vous pouvez changer votre vote :
1. Retournez sur la page de la session de vote.
2. Votre vote actuel est affiche avec un badge "Votre vote".
3. Cliquez sur **Modifier mon vote**.
4. Selectionnez votre nouveau choix et signez a nouveau.
5. L'ancien vote est desactive (conserve dans l'historique pour audit) et remplace par le nouveau.
## Comprendre les resultats : la jauge de seuil
La page de chaque session de vote affiche une **jauge de seuil** qui represente visuellement l'etat du vote en temps reel.
### Elements de la jauge
```
[|||||||||||||||||||||||||||-----] 97 / 94 Adopte
^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^
Votes Pour (vert) Seuil requis (trait vertical)
```
| Element | Description |
| --------------------------- | ------------------------------------------------------------ |
| **Barre verte** | Nombre de votes favorables actuels |
| **Barre rouge** | Nombre de votes defavorables actuels |
| **Trait vertical** | Position du seuil requis (calcule par la formule d'inertie) |
| **Compteur numerique** | `votes_pour / seuil` affiche a droite de la jauge |
| **Badge de resultat** | "Adopte" (vert) ou "Non atteint" (gris) ou "Rejete" (rouge) |
| **Pourcentage de participation** | `total_votes / wot_size` affiche sous la jauge |
### Comportement dynamique
La jauge se **met a jour en temps reel** : a chaque nouveau vote soumis, la barre et le seuil sont recalcules instantanement. Le seuil peut augmenter legerement a mesure que de nouveaux votes arrivent (car la participation $T$ change, ce qui modifie le facteur d'inertie). Le resultat affiche est donc toujours provisoire tant que la session est ouverte.
### Detail du calcul
En cliquant sur le bouton **Voir le detail** sous la jauge, une modale s'ouvre avec :
- Les parametres de la formule utilises (`mode_params`).
- Les valeurs intermediaires du calcul (ratio de participation, facteur d'inertie, etc.).
- Les criteres Smith et TechComm si applicables.
- Un lien vers le simulateur de formules pour experimenter d'autres scenarios.
### Page de resultat
La page de resultat affiche :
| Information | Description |
| ------------------- | ---------------------------------------------------- |
| Votes pour | Nombre de votes favorables |
| Votes contre | Nombre de votes defavorables |
| Total | Nombre total de votes exprimes |
| Taille WoT | Nombre de membres WoT eligibles (snapshot au debut) |
| Seuil requis | Seuil calcule par la formule d'inertie |
| Critere Smith | Seuil et validation des votes Smith (si applicable) |
| Critere TechComm | Seuil et validation des votes TechComm (si applicable) |
| Resultat | **Adopte** ou **Rejete** |
## Simulateur de formules
Le simulateur de formules vous permet de tester le comportement du seuil d'adoption avec differentes configurations, sans creer de session de vote.
### Acceder au simulateur
1. Depuis le menu principal, selectionnez **Outils** puis **Simulateur de formules**.
2. Vous pouvez aussi y acceder depuis le detail du calcul de seuil d'une session de vote (bouton **Ouvrir le simulateur**).
### Utiliser le simulateur
Le simulateur presente un formulaire avec les parametres ajustables :
| Parametre | Description | Curseur/Champ |
| ----------------------- | ---------------------------------------------- | ------------- |
| Taille WoT ($W$) | Nombre de membres eligibles | Curseur |
| Total votes ($T$) | Nombre de votes exprimes | Curseur |
| Majorite ($M$) | Pourcentage de majorite cible | Curseur |
| Base ($B$) | Exposant de base | Champ |
| Gradient ($G$) | Vitesse de convergence | Curseur |
| Base constante ($C$) | Plancher minimum de votes | Champ |
| Votes Pour | Nombre de votes favorables (pour tester l'adoption) | Curseur |
En ajustant les curseurs, le resultat se met a jour en temps reel :
- Le **seuil calcule** est affiche.
- Un graphique montre la courbe du seuil en fonction de la participation.
- Le resultat **Adopte** / **Rejete** s'affiche en fonction des votes pour saisis.
### Exemple de scenario
Vous souhaitez comparer deux configurations pour un vote attendu avec environ 200 participants sur une WoT de 7224 :
1. Configuration actuelle `M50 G.2` : Seuil = 156 (77.7% requis).
2. Configuration proposee `M50 G.4` : Seuil = 171 (85.5% requis).
Le simulateur montre visuellement l'impact : avec un gradient plus eleve, l'exigence est sensiblement plus forte a faible participation.
## Mises a jour en temps reel
libreDecision utilise une connexion **WebSocket** pour diffuser les mises a jour de vote en temps reel a tous les utilisateurs qui consultent une session de vote.
### Ce qui est mis a jour en direct
| Evenement | Effet sur l'interface |
| ---------------------------- | ---------------------------------------------------- |
| Nouveau vote soumis | La jauge de seuil est recalculee et reaffichee |
| Vote modifie | La jauge reflette le changement immediatement |
| Session cloturee | Le badge passe a "Cloture" et le resultat final s'affiche |
| Critere Smith/TechComm atteint | L'indicateur de critere passe au vert |
### Indicateur de connexion
Un petit indicateur en bas a droite de la page de vote affiche l'etat de la connexion temps reel :
- **Point vert** : Connexion active, mises a jour en direct.
- **Point orange** : Reconnexion en cours.
- **Point rouge** : Connexion perdue. Les donnees affichees peuvent etre obsoletes. Rechargez la page.
## Historique des votes
### Consulter ses propres votes
1. Cliquez sur votre avatar ou votre adresse Duniter dans la barre de navigation.
2. Selectionnez **Mon historique de votes**.
3. La liste affiche tous vos votes passes, avec pour chacun :
- Le titre de la session / decision.
- Votre choix (Pour/Contre ou niveau nuance).
- La date et l'heure du vote.
- Le resultat final de la session (Adopte/Rejete) si cloturee.
### Consulter les votes d'une session
Sur la page d'une session de vote, l'onglet **Votes** affiche la liste de tous les votes soumis :
- L'adresse Duniter du votant.
- Le choix exprime.
- Le commentaire (s'il y en a un).
- L'horodatage.
- Un lien pour verifier la signature Ed25519.
Les votes sont publics et verifiables par tous. Il n'y a pas de vote secret dans libreDecision : la transparence est un principe fondamental.
## Meta-gouvernance : voter sur les regles du vote
La meta-gouvernance est la capacite de **modifier les regles du systeme de vote en utilisant le systeme de vote lui-meme**. C'est le mecanisme par lequel la communaute garde le controle sur les parametres fondamentaux de la prise de decision.
### Qu'est-ce qui peut etre modifie par meta-gouvernance ?
| Element modifiable | Exemple de modification |
| ------------------------------- | ---------------------------------------------------------- |
| Duree de vote | Passer de 30 jours a 60 jours |
| Majorite cible ($M$) | Passer de 50% a 66% (super-majorite) |
| Gradient ($G$) | Augmenter de 0.2 a 0.4 (plus exigeant a faible participation) |
| Critere Smith | Activer ou desactiver, changer l'exposant |
| Critere TechComm | Activer ou desactiver, changer l'exposant |
| Type de vote | Passer d'un vote binaire a un vote nuance |
### Comment ca fonctionne ?
1. **Proposition** : Un membre propose une modification d'un protocole ou d'une formule via l'interface (bouton **Proposer une modification** sur la page du protocole).
2. **Verification** : Le systeme detecte que le protocole ou la formule est **actif** (lie a au moins une session de vote ouverte).
3. **Creation automatique d'un vote** : Une session de vote est automatiquement creee pour valider ou rejeter la modification. Cette session utilise les **regles actuelles** (pas les regles proposees).
4. **Vote de la communaute** : Les membres votent sur la proposition de modification selon les regles en vigueur.
5. **Application conditionnelle** :
- Si le vote est **adopte** : les nouvelles regles s'appliquent aux futures sessions de vote. Les sessions en cours ne sont pas affectees.
- Si le vote est **rejete** : le protocole reste inchange.
### Exemple concret
Un membre estime que le gradient $G = 0.2$ est trop permissif et propose de passer a $G = 0.4$ :
1. Il se rend sur la page du protocole actif et clique sur **Proposer une modification**.
2. Il modifie la valeur du gradient de 0.2 a 0.4 dans le formulaire.
3. Il soumet la proposition. Le systeme cree une session de vote intitulee "Modification du gradient de seuil : G.2 vers G.4".
4. Les membres votent pendant 30 jours (duree du protocole actuel).
5. Avec 97 votes pour et 23 contre sur une WoT de 7224, le seuil calcule est de 94. Le vote est adopte (97 >= 94).
6. Le gradient passe a 0.4 pour toutes les futures sessions de vote.
### Pourquoi la meta-gouvernance est importante
- **Aucun parametre n'est grave dans le marbre** : la communaute peut toujours adapter les regles.
- **Protection contre les modifications unilaterales** : personne ne peut changer les regles seul.
- **Transparence** : toute modification de regle est tracable et soumise au vote.
- **Coherence** : les regles de modification sont les memes que les regles de decision (le systeme s'applique a lui-meme).
## Preuve cryptographique
Chaque vote est accompagne d'une signature Ed25519 qui garantit :
- **Authenticite** : seul le proprietaire de l'adresse Duniter peut voter en son nom
- **Integrite** : le vote ne peut pas etre modifie apres soumission
- **Non-repudiation** : le votant ne peut pas nier avoir vote
Les votes signes peuvent etre verifies independamment par quiconque possede la cle publique du votant.
## Protocoles de vote
Chaque session de vote est liee a un **protocole de vote** qui definit :
- Le type de vote (binaire ou nuance)
- La duree du vote (en jours)
- Les parametres de la formule de seuil (majorite, exposants, etc.)
- Les criteres Smith et TechComm eventuels
Les protocoles sont reutilisables et peuvent eux-memes etre soumis a meta-gouvernance.
## FAQ Vote
### Le seuil peut-il changer pendant le vote ?
Oui. Le seuil depend du nombre total de votes exprimes ($T$). A chaque nouveau vote, le seuil est recalcule. Il augmente legerement a mesure que la participation croit, mais converge vers la majorite simple. C'est pourquoi le resultat affiche est toujours provisoire tant que la session est ouverte.
### Que se passe-t-il si le seuil n'est pas atteint a la cloture ?
Le vote est **rejete**. La proposition n'est pas adoptee et le statu quo est maintenu. Le resultat detaille est archive dans le Sanctuaire pour transparence.
### Un vote en cours peut-il etre annule ?
Seul le createur de la session ou un membre du Comite Technique peut cloturer une session de maniere anticipee. La cloture anticipee calcule le resultat avec les votes exprimes a ce moment.
### Comment sont geres les ex aequo ?
Il n'y a pas d'ex aequo possible avec la formule d'inertie. Le seuil est un nombre entier (arrondi inferieur) et le nombre de votes favorables est un entier. Si `votes_pour >= seuil`, le vote est adopte. Sinon, il est rejete.
### Puis-je voter si mon statut WoT change pendant le vote ?
Votre statut WoT est enregistre au moment de votre vote. Si vous perdez votre statut de membre apres avoir vote, votre vote reste comptabilise car le snapshot de la taille WoT est pris au debut de la session.
+172
View File
@@ -0,0 +1,172 @@
---
title: Mandats
description: Guide des mandats sur libreDecision
---
# Mandats
## Principe
Un mandat est une responsabilite attribuee a un membre de la communaute pour une duree determinee, apres validation par vote collectif. Les mandats permettent de formaliser les roles au sein de la gouvernance Duniter et d'assurer la redevabilite des mandataires.
## Types de mandats
| Type | Description | Cas d'usage |
| ---------- | ------------------------------------------------------- | --------------------------------------------------------- |
| `techcomm` | Mandat de membre du Comite Technique | Administration du reseau, validation des runtime upgrades |
| `smith` | Mandat lie au role de forgeron (Smith) | Production de blocs, maintenance de la blockchain |
| `custom` | Mandat personnalise pour tout autre role | Tresorier, secretaire, moderateur, etc. |
Chaque type de mandat peut avoir des criteres de vote specifiques. Par exemple, un mandat `techcomm` peut exiger un critere TechComm (`ceil(CoTecSize^T)`), tandis qu'un mandat `smith` peut exiger un critere Smith (`ceil(SmithWotSize^S)`).
## Cycle de vie d'un mandat
Un mandat progresse a travers les statuts suivants :
```
Brouillon --> Candidature --> Vote --> Actif --> Rapport --> Termine
| |
+--> Rejet (si le +--> Revoque (revocation
vote echoue) anticipee)
```
| Statut | Description |
| ------------ | ------------------------------------------------------------ |
| `draft` | Brouillon initial. Le mandat est en cours de definition et peut etre modifie ou supprime. |
| `candidacy` | Periode de depot des candidatures. Les membres interesses se declarent candidats. |
| `voting` | Vote collectif pour designer le mandataire. Une session de vote est ouverte. |
| `active` | Le mandat est en cours. Le mandataire exerce ses responsabilites. |
| `reporting` | Periode de reporting. Le mandataire rend compte de ses actions. |
| `completed` | Fin normale du mandat a echeance. Le bilan est archive. |
| `revoked` | Fin anticipee du mandat suite a une revocation. |
## Etapes d'un mandat (mandate_steps)
Chaque mandat est compose d'etapes ordonnees qui definissent le processus complet. Les types d'etapes disponibles sont :
| Type d'etape | Description |
| -------------- | ------------------------------------------------------------ |
| `formulation` | Definition du mandat, de ses objectifs et de sa duree |
| `candidacy` | Periode de depot et d'examen des candidatures |
| `vote` | Vote collectif pour designer le mandataire |
| `assignment` | Attribution formelle du mandat au candidat elu |
| `reporting` | Periode de reporting sur l'execution du mandat |
| `completion` | Fin normale du mandat a echeance |
| `revocation` | Fin anticipee du mandat (en cas de manquement) |
Chaque etape possede un statut individuel :
| Statut | Description |
| ----------- | ---------------------------------------------------------- |
| `pending` | L'etape n'a pas encore commence |
| `active` | L'etape est en cours |
| `completed` | L'etape est terminee avec succes |
| `skipped` | L'etape a ete ignoree (non applicable) |
## Comment le workflow avance
Le workflow d'un mandat avance via l'action **"Avancer"** (endpoint `POST /mandates/{id}/advance`). Le fonctionnement est identique a celui des decisions :
1. **S'il y a une etape active** : elle est marquee `completed`, et la prochaine etape `pending` est activee.
2. **S'il n'y a pas d'etape active** : la premiere etape `pending` est activee. Si le mandat est en `draft`, il passe automatiquement en `candidacy`.
3. **Si toutes les etapes sont terminees** : le statut global du mandat avance au statut suivant dans le cycle de vie.
Les statuts terminaux (`completed` et `revoked`) bloquent tout avancement ulterieur.
## Creer un mandat
Les membres authentifies peuvent proposer un nouveau mandat :
1. Cliquez sur **Nouveau mandat**.
2. Renseignez le **titre** : intitule du role ou de la mission.
3. Renseignez la **description** : objectifs, responsabilites, criteres de reussite.
4. Choisissez le **type de mandat** : `techcomm`, `smith` ou `custom`.
5. Optionnellement, liez le mandat a une **decision** existante de type `mandate_vote`.
6. **Ajoutez les etapes** dans l'ordre souhaite (formulation, candidature, vote, assignation, reporting, completion).
7. Soumettez. Le mandat est cree en statut `draft`.
8. Utilisez l'action **"Avancer"** pour demarrer le processus.
## Candidatures
Pendant la phase de candidature (`candidacy`), les membres de la communaute peuvent se declarer candidats. La page du mandat affiche la liste des candidats avec leur profil Duniter (adresse SS58, statut WoT, statut Smith/TechComm).
## Vote pour un mandat
Quand l'etape de type `vote` est active, une session de vote doit etre creee via l'action **"Creer une session de vote"** (endpoint `POST /mandates/{id}/steps/{step_id}/create-vote-session`).
La session de vote fonctionne exactement comme pour les decisions :
- Snapshot des tailles WoT, Smith, TechComm
- Application de la formule de seuil avec inertie
- Criteres supplementaires Smith/TechComm selon le protocole choisi
- Cloture automatique ou manuelle
Le resultat du vote determine si le mandat est attribue au candidat elu.
## Assignation du mandataire
Apres un vote reussi, le mandataire est assigne au mandat via l'action **"Assigner"** (endpoint `POST /mandates/{id}/assign`). Cette action :
- Definit le `mandatee_id` : l'identite Duniter du membre elu
- Definit les dates de debut et de fin du mandat
- Fait passer le mandat en statut `active`
Le corps de la requete contient l'identifiant de l'identite Duniter du mandataire :
```json
{
"mandatee_id": "uuid-de-l-identite-duniter"
}
```
## Reporting et redevabilite
Pendant la phase active du mandat, le mandataire est tenu de rendre compte de ses actions. Quand l'etape de `reporting` est active :
- Le mandataire peut publier des comptes-rendus via le champ `outcome` de l'etape
- Les membres de la communaute peuvent consulter les rapports
- Le bilan est archive dans le sanctuaire a la fin du mandat
## Revocation
Un mandat actif peut etre revoque de maniere anticipee via l'action **"Revoquer"** (endpoint `POST /mandates/{id}/revoke`). La revocation :
- Passe le statut du mandat a `revoked`
- Met fin immediatement aux responsabilites du mandataire
- Archive le motif de revocation
La revocation est une action de gouvernance qui peut necessiter un vote prealable (decision de type `mandate_vote` avec motif de revocation).
## Suppression
Seuls les mandats au statut `draft` peuvent etre supprimes via l'action **"Supprimer"** (endpoint `DELETE /mandates/{id}`). Une fois le processus de candidature lance, le mandat reste dans le systeme pour tracabilite.
## Consulter les mandats
1. Rendez-vous dans la section **Mandats**.
2. Filtrez par type (`techcomm`, `smith`, `custom`) ou par statut.
3. Chaque mandat affiche le titulaire, les dates, les etapes et leur statut.
4. La page de detail montre le workflow complet avec l'historique des etapes.
## Exemple : Election d'un membre du Comite Technique
```
1. Formulation -> Definition du poste : responsabilites, duree (1 an), competences requises
2. Candidature -> Les membres Smith se declarent candidats pendant 14 jours
3. Vote -> Vote WoT avec critere TechComm obligatoire, duree 30 jours
4. Assignation -> Attribution du mandat au candidat elu
5. Reporting -> Rapport d'activite trimestriel
6. Completion -> Fin du mandat apres 1 an, bilan final archive
```
**Deroulement concret :**
1. Un membre cree un mandat de type `techcomm` avec la description du poste.
2. Il ajoute les 6 etapes dans l'ordre.
3. Il avance le mandat : l'etape "Formulation" est activee, puis completee.
4. Il avance : la phase de candidature s'ouvre. Les candidats se declarent.
5. Il avance : l'etape "Vote" est activee. Une session de vote est creee.
6. Les membres votent. Le seuil WoT et le critere TechComm doivent etre atteints.
7. Si adopte, il avance : l'etape "Assignation" est activee. Le mandataire est designe via l'action "Assigner".
8. Il avance : le mandat passe en phase active. Le mandataire exerce ses fonctions.
9. A l'echeance, l'etape "Reporting" est activee pour le bilan.
10. Il avance une derniere fois : le mandat passe en statut `completed`.
+204
View File
@@ -0,0 +1,204 @@
---
title: Sanctuaire
description: Guide de l'archivage immuable sur libreDecision
---
# Sanctuaire
## Qu'est-ce que le Sanctuaire ?
Le Sanctuaire est la couche d'**archivage immuable** de libreDecision. C'est l'endroit ou les decisions adoptees, les documents archives et les resultats de vote sont preserves de maniere permanente et verifiable.
Le principe est simple : une fois qu'un contenu entre dans le Sanctuaire, il ne peut plus etre modifie ni supprime. Meme si la plateforme libreDecision disparaissait, les preuves resteraient accessibles et verifiables de maniere independante.
## Triple preuve : SHA-256 + IPFS + Blockchain
Le Sanctuaire repose sur trois mecanismes complementaires qui forment une **triple preuve** d'integrite :
### 1. Hash SHA-256 -- Preuve d'integrite
Un hash SHA-256 est un empreinte numerique unique du contenu. Si ne serait-ce qu'un seul caractere du document change, le hash est completement different. En recalculant le hash et en le comparant a celui enregistre, on peut verifier que le contenu n'a pas ete modifie.
**Analogie** : C'est comme une empreinte digitale. Deux documents differents n'auront jamais la meme empreinte.
### 2. IPFS -- Stockage distribue et contenu adressable
IPFS (InterPlanetary File System) est un reseau de stockage distribue. Le contenu n'est pas stocke sur un seul serveur mais replique sur plusieurs noeuds du reseau. Chaque contenu est identifie par un **CID** (Content Identifier) qui est derive de son contenu meme.
**Analogie** : Au lieu de dire "le document est a l'adresse www.example.com/doc1" (localisation), on dit "le document dont l'empreinte est Qm1234..." (contenu). Peu importe ou il est stocke, tant que l'empreinte correspond, c'est le bon document.
**Avantages** :
- **Resilience** : le contenu reste accessible meme si un serveur tombe.
- **Integritegarantie** : le CID change si le contenu change, toute falsification est detectable.
- **Perennite** : tant qu'au moins un noeud heberge le contenu, il est accessible.
### Acceder au contenu via IPFS
Chaque entree du Sanctuaire possede un **CID IPFS** qui permet d'acceder au contenu :
- **Passerelle publique** : `https://ipfs.io/ipfs/{CID}`
- **Passerelle locale** (si vous executez un noeud kubo) : `http://localhost:8080/ipfs/{CID}`
En cliquant sur le lien CID dans l'interface, le contenu s'ouvre directement dans votre navigateur.
Si vous avez un noeud IPFS local (kubo), vous pouvez aussi utiliser la ligne de commande :
```bash
# Afficher le contenu
ipfs cat {CID}
# Telecharger le contenu
ipfs get {CID} -o document_archive.txt
```
### 3. Ancrage on-chain -- Preuve horodatee et infalsifiable
L'ancrage on-chain consiste a enregistrer le hash SHA-256 du contenu sur la blockchain Duniter V2, via un appel `system.remark`. Cette transaction est incluse dans un bloc de la blockchain, ce qui fournit :
- **Horodatage** : la date du bloc prouve que le contenu existait a cette date.
- **Immutabilite** : une fois inscrit dans la blockchain, le remark ne peut pas etre modifie.
- **Independance** : la preuve est verifiable sur la blockchain, independamment de libreDecision.
Le format du remark est :
```
libredecision:sanctuary:{hash_sha256_du_contenu}
```
**Analogie** : C'est comme publier un hash dans un journal date et immuable. N'importe qui peut verifier que le hash etait bien la a cette date.
## Pourquoi le Sanctuaire ?
La gouvernance exige la transparence et la tracabilite. Le Sanctuaire garantit que :
- **Aucune decision adoptee ne peut etre modifiee retroactivement** : le hash et l'ancrage on-chain rendent toute falsification detectable.
- **Tout membre peut verifier l'authenticite** d'un document ou d'un resultat de vote de maniere independante.
- **L'historique des decisions est preserve** independamment de la plateforme : meme sans libreDecision, les preuves restent sur IPFS et la blockchain.
## Types d'entrees
| Type | Description |
| ------------ | ------------------------------------------------ |
| Document | Version adoptee d'un document de reference |
| Decision | Decision finalisee avec son resultat |
| Vote result | Resultat detaille d'une session de vote |
## Consulter le Sanctuaire
1. Rendez-vous dans la section **Sanctuaire**.
2. Filtrez par type d'entree si necessaire.
3. Chaque entree affiche :
- Le titre
- Le hash SHA-256 du contenu
- Le CID IPFS (lien vers le contenu sur IPFS)
- Le hash de la transaction on-chain
- Le numero de bloc
- La date d'archivage
## Consulter les entrees par document de reference
Pour retrouver toutes les entrees du Sanctuaire liees a un document, une decision ou une session de vote specifique :
1. Depuis la fiche du document (ou de la decision), cliquez sur **Voir dans le Sanctuaire**.
2. La liste affiche toutes les entrees archivees associees a cette entite source.
3. Vous pouvez aussi acceder directement a cette vue via l'URL : `/sanctuaire/par-reference/{id}`.
Cette fonctionnalite permet de retracer l'historique complet d'archivage d'un document au fil de ses modifications adoptees.
## Comment verifier une archive
### Verification automatique
libreDecision propose une verification automatique d'integrite pour chaque entree du Sanctuaire :
1. Ouvrez l'entree a verifier dans le Sanctuaire.
2. Cliquez sur **Verifier l'integrite**.
3. Le systeme effectue automatiquement trois controles :
- **Hash SHA-256** : le hash est recalcule a partir du contenu source et compare avec le hash enregistre.
- **IPFS** : le contenu est recupere via le CID IPFS et verifie (si le CID est renseigne).
- **On-chain** : le hash est recherche dans le `system.remark` du bloc reference sur la blockchain Duniter V2 (si le hash de transaction est renseigne).
4. Le resultat affiche pour chaque controle un indicateur **valide** ou **invalide**.
::callout{type="info"}
Si les trois controles sont valides, le contenu est authentique et n'a pas ete modifie depuis son archivage.
::
### Verification manuelle (independante de la plateforme)
Pour une verification totalement independante de libreDecision, suivez ces etapes :
#### Etape 1 : Recuperer le contenu via IPFS
Utilisez le CID affiche sur l'entree du Sanctuaire pour telecharger le contenu :
```bash
# Via un noeud IPFS local
ipfs cat QmXyz... > document.txt
# Via une passerelle publique
curl https://ipfs.io/ipfs/QmXyz... > document.txt
```
#### Etape 2 : Calculer le hash SHA-256
```bash
sha256sum document.txt
```
Comparez le hash obtenu avec le hash affiche dans le Sanctuaire. Ils doivent etre identiques.
#### Etape 3 : Verifier l'ancrage on-chain
1. Copiez le **hash de transaction** affiche sur l'entree du Sanctuaire.
2. Ouvrez un explorateur de la blockchain Duniter V2 (par exemple Polkadot.js Apps connecte au reseau Duniter).
3. Recherchez la transaction par son hash ou parcourez le **bloc** indique.
4. Dans les extrinsics du bloc, reperez l'appel `system.remark` contenant le hash SHA-256.
5. Verifiez que le hash dans le remark correspond a celui que vous avez calcule.
#### Resultat
Si les trois hash correspondent (calcul local, Sanctuaire, on-chain), le contenu est authentique, integre et horodate. La triple preuve est confirmee.
::callout{type="tip"}
L'ancrage on-chain fournit une preuve horodatee et infalsifiable de l'existence du contenu a la date du bloc. Meme si la plateforme libreDecision disparait, la preuve reste verifiable sur la blockchain.
::
## Comprendre les informations d'ancrage on-chain
Chaque entree du Sanctuaire affiche des informations relatives a son ancrage sur la blockchain Duniter V2 :
| Information | Description |
| -------------------- | -------------------------------------------------------- |
| Hash de transaction | Identifiant unique de la transaction `system.remark` contenant le hash du contenu |
| Numero de bloc | Le bloc de la blockchain dans lequel la transaction a ete incluse |
| Date d'archivage | Horodatage de la creation de l'entree dans le Sanctuaire |
## Automatisation
L'archivage dans le Sanctuaire est declenche automatiquement lorsqu'un processus decisionnel est finalise :
- Quand une version d'item de document est **acceptee**, le nouveau texte est archive.
- Quand une session de vote est **cloturee**, le resultat detaille est archive.
- Quand une decision est **executee**, l'ensemble de la decision est archive.
- Quand un document est **archive** via le bouton d'archivage, l'integralite du document est archivee dans le Sanctuaire.
## Resume : la chaine de confiance
```
Contenu adopte
|
v
[Calcul SHA-256] --> hash = empreinte unique du contenu
|
+---> [Upload IPFS] --> CID = identifiant distribue du contenu
|
+---> [system.remark on-chain] --> preuve horodatee et immuable
|
v
[Entree Sanctuaire] = hash + CID + tx_hash + block_number
|
v
Verification : recalculer le hash, comparer avec IPFS et on-chain
= Triple preuve d'integrite
```
+258
View File
@@ -0,0 +1,258 @@
---
title: FAQ
description: Questions frequentes sur libreDecision
---
# Questions frequentes
## Acces et authentification
### Ai-je besoin d'un compte Duniter pour utiliser libreDecision ?
Pour **consulter** les documents, decisions et resultats de vote, aucune authentification n'est necessaire. Pour **voter**, **proposer des modifications** ou **creer des decisions**, vous devez posseder une identite Duniter V2 avec une adresse SS58.
### Comment fonctionne la connexion sans mot de passe ?
libreDecision utilise un systeme challenge-response base sur la cryptographie Ed25519. Voici le processus :
1. Vous fournissez votre adresse Duniter SS58.
2. Le serveur genere un texte aleatoire (le "challenge") de 64 caracteres hexadecimaux.
3. Votre extension Polkadot.js ou votre portefeuille Cesium signe ce challenge avec votre cle privee Ed25519.
4. Le serveur verifie la signature avec votre cle publique.
5. Si la verification reussit, un jeton de session vous est attribue.
Votre cle privee n'est **jamais** transmise au serveur. Seule la signature du challenge est envoyee.
### Quels portefeuilles sont compatibles ?
Tout portefeuille supportant la signature Ed25519 sur Substrate est compatible :
- **Extension Polkadot.js** (recommandee) : disponible sur Chrome et Firefox
- **Cesium2** : l'application officielle de la communaute Duniter
- **Tout portefeuille Substrate** supportant Ed25519
### Ma session a expire, que faire ?
Les sessions durent 24 heures. Reconnectez-vous en suivant le meme processus (challenge + signature). Vos votes et propositions precedents ne sont pas affectes.
### Que se passe-t-il si je perds l'acces a ma cle privee ?
libreDecision ne stocke jamais votre cle privee. Si vous perdez l'acces a votre cle, vous ne pourrez plus vous authentifier avec cette adresse. Vos votes passes restent enregistres et comptabilises. Contactez la communaute Duniter pour les procedures de recuperation d'identite si necessaire.
### Puis-je me connecter depuis plusieurs appareils ?
Oui. Chaque connexion genere un jeton de session independant. Vous pouvez etre connecte simultanement depuis plusieurs appareils. Chaque session est independante et expire apres 24 heures.
## Vote
### Comment voter sur un item de document ?
1. Rendez-vous dans la section **Votes** ou accedez a une decision en cours.
2. Lisez le sujet soumis au vote.
3. Choisissez **Pour** ou **Contre** (vote binaire) ou un niveau de 0 a 5 (vote nuance).
4. Optionnellement, ajoutez un commentaire.
5. Signez le payload avec votre cle privee (votre extension de portefeuille vous le demandera).
6. Cliquez sur **Soumettre**.
### Puis-je changer mon vote ?
Oui, tant que la session de vote est ouverte, vous pouvez modifier votre vote autant de fois que necessaire. L'ancien vote est conserve en base de donnees pour l'audit mais marque comme inactif. Seul le dernier vote est pris en compte dans le decompte.
### Pourquoi le seuil est-il si eleve quand peu de personnes votent ?
C'est le mecanisme d'**inertie**. Quand la participation est faible, le seuil est eleve pour empecher qu'un petit groupe prenne des decisions engageant toute la communaute. A mesure que la participation augmente, le seuil converge vers la majorite simple. Cela incite a la participation large.
Par exemple, avec 120 votes sur une WoT de 7224 membres (1.7% de participation), il faut 78% de votes favorables. Si toute la WoT votait, 50% suffiraient.
### Comment comprendre le seuil affiche sur la jauge ?
La jauge de seuil montre :
- **La barre verte** : nombre de votes favorables actuels
- **La barre rouge** : nombre de votes defavorables
- **Le trait vertical** : position du seuil requis (calcule par la formule d'inertie)
- **Le compteur** : `votes_pour / seuil` (par exemple "97 / 94")
- **Le badge** : "Adopte" si votes_pour >= seuil, sinon "Non atteint"
Le seuil est recalcule en temps reel a chaque nouveau vote.
### Qu'est-ce que le critere Smith ?
Certaines decisions exigent un nombre minimum de votes favorables de la part des **forgerons** (membres Smith de la WoT). Le seuil est calcule par `ceil(SmithWotSize^S)` ou S est l'exposant configure. Cela garantit que les decisions techniques sont soutenues par ceux qui maintiennent le reseau.
### Qu'est-ce que le critere TechComm ?
De maniere similaire, certaines decisions exigent un nombre minimum de votes favorables du **Comite Technique**. Le seuil est calcule par `ceil(CoTecSize^T)`. Cela concerne les decisions qui affectent le runtime ou l'infrastructure technique.
### Comment fonctionnent les votes nuances ?
Au lieu de "pour" ou "contre", vous choisissez un niveau de 0 (CONTRE) a 5 (TOUT A FAIT). Les niveaux 3, 4 et 5 comptent comme positifs. Pour que le vote soit adopte, il faut que les votes positifs representent au moins 80% du total et qu'un nombre minimum de participants soit atteint (par defaut 59).
### Que signifie "D30M50B.1G.2S.1T.1" ?
C'est le codage compact des parametres de formule :
- **D30** : duree de 30 jours
- **M50** : majorite cible de 50%
- **B.1** : exposant de base 0.1
- **G.2** : gradient 0.2
- **S.1** : critere Smith avec exposant 0.1
- **T.1** : critere TechComm avec exposant 0.1
### Les votes sont-ils secrets ?
Non. Les votes et leurs signatures cryptographiques sont **publics**, conformement au principe de transparence de la gouvernance. Chaque vote peut etre verifie independamment par quiconque possede la cle publique du votant. Il n'y a pas de vote secret dans libreDecision.
### Le seuil peut-il changer pendant le vote ?
Oui. Le seuil depend du nombre total de votes exprimes. A chaque nouveau vote, le seuil est recalcule. Il augmente legerement a mesure que la participation croit, mais converge vers la majorite simple. C'est pourquoi le resultat affiche est toujours provisoire tant que la session est ouverte.
## Documents
### Qu'est-ce qu'un document de reference ?
Un document de reference est un texte fondateur de la communaute Duniter (Licence G1, Engagement Forgeron, Reglement du Comite Technique, etc.). Il est compose d'items modulaires sous vote permanent.
### Qu'est-ce qu'un item ?
Un item est une unite modulaire d'un document : une clause, une regle, une verification, un preambule ou une section. Chaque item a une position hierarchique (ex: "1", "1.1", "3.2"), un texte courant et un historique de versions.
### Comment proposer une modification ?
1. Ouvrez le document dans la section **Documents**.
2. Selectionnez l'item a modifier.
3. Cliquez sur **Proposer une modification**.
4. Redigez le nouveau texte avec une justification.
5. Soumettez.
Un diff automatique est genere. La proposition sera soumise a examen et vote par la communaute.
### Que signifie "vote permanent" ?
Les documents actifs sont toujours ouverts aux propositions de modification. Il n'y a pas de periode speciale pour proposer des changements. Cela permet une evolution continue et organique des textes.
### Puis-je proposer plusieurs modifications a la fois ?
Oui. Vous pouvez proposer des modifications a differents items d'un meme document, ou a des items de documents differents. Chaque proposition est independante et suit son propre cycle de vie (proposition, examen, vote).
### Que se passe-t-il si ma proposition est rejetee ?
Le texte courant de l'item reste inchange. Votre proposition est archivee avec le statut "rejetee" pour transparence. Vous pouvez proposer une nouvelle modification a tout moment, eventuellement amelioree suite aux retours de la communaute.
### Comment consulter le diff d'une proposition ?
Sur la page de detail d'une version proposee, le diff est affiche automatiquement. Les ajouts sont surlignees en vert, les suppressions en rouge. Vous pouvez basculer entre la vue diff et la vue texte complet.
## Decisions et mandats
### Quelle est la difference entre un document et une decision ?
Un **document** est un texte fondateur sous vote permanent (Licence, Engagement, Reglement). Une **decision** est un processus ponctuel multi-etapes (qualification, examen, vote, execution, rapport) pour prendre un choix collectif specifique (runtime upgrade, attribution de mandat, changement de parametre).
### Comment creer une decision ?
1. Rendez-vous dans la section **Decisions**.
2. Cliquez sur **Nouvelle decision**.
3. Renseignez le titre, la description, le contexte et le type.
4. Choisissez un protocole de vote.
5. Ajoutez les etapes necessaires (qualification, examen, vote, execution, reporting).
6. Soumettez, puis utilisez **Avancer** pour demarrer le processus.
### Qu'est-ce qu'un mandat ?
Un mandat est une responsabilite formelle attribuee a un membre de la communaute pour une duree determinee, apres validation par vote collectif. Les types de mandats sont : `techcomm` (Comite Technique), `smith` (forgeron) et `custom` (personnalise).
### Comment fonctionne l'election d'un mandataire ?
Le processus suit un cycle : formulation du mandat, periode de candidature, vote collectif, assignation du mandataire, exercice du mandat, reporting et completion. Le vote utilise le meme systeme de seuil WoT avec inertie.
### Un mandat peut-il etre revoque ?
Oui. Un mandat actif peut etre revoque de maniere anticipee via l'action "Revoquer". La revocation est une action de gouvernance qui peut necessiter un vote prealable.
## Sanctuaire et archivage
### Pourquoi archiver sur IPFS et la blockchain ?
**IPFS** fournit un stockage distribue : le contenu est accessible meme si la plateforme libreDecision est hors ligne. L'**ancrage on-chain** via `system.remark` cree une preuve horodatee immuable sur la blockchain Duniter V2. Le **hash SHA-256** garantit l'integrite du contenu. Ensemble, ils forment une **triple preuve** que le contenu n'a pas ete modifie depuis son archivage.
### Comment verifier qu'un document n'a pas ete modifie ?
Trois methodes :
1. **Verification automatique** : cliquez sur **Verifier l'integrite** sur l'entree du Sanctuaire. Le systeme recalcule le hash et verifie IPFS et on-chain automatiquement.
2. **Verification manuelle** : telechargez le contenu depuis IPFS via son CID, calculez le hash SHA-256 avec `sha256sum`, puis comparez avec le hash enregistre dans le Sanctuaire et le remark on-chain.
3. **Verification blockchain** : consultez le bloc reference dans un explorateur Duniter V2 et verifiez le `system.remark`.
### L'archivage est-il automatique ?
Oui. L'archivage est declenche automatiquement :
- Quand une version d'item de document est acceptee
- Quand une session de vote est cloturee
- Quand une decision est executee
- Quand un document est archive manuellement
### Puis-je acceder aux archives sans libreDecision ?
Oui. Les contenus archives sont accessibles via :
- **IPFS** : utilisez le CID pour recuperer le contenu depuis n'importe quelle passerelle IPFS publique ou un noeud local
- **Blockchain** : le hash SHA-256 est enregistre dans un `system.remark` sur la blockchain Duniter V2, verifiable via tout explorateur compatible
## Questions techniques
### Sur quelle blockchain libreDecision fonctionne-t-il ?
libreDecision se connecte a la blockchain **Duniter V2** (basee sur Substrate). En environnement de developpement, il se connecte au reseau de test GDev (`wss://gdev.p2p.legal/ws`).
### Que se passe-t-il si la blockchain Duniter est indisponible ?
L'essentiel des fonctionnalites (consultation des documents, votes, decisions) reste accessible car les donnees sont stockees dans la base PostgreSQL locale. Seules les fonctions dependant de la blockchain sont affectees :
- L'authentification peut temporairement echouer si la verification WoT n'est pas en cache
- L'ancrage on-chain des entrees du Sanctuaire est differe jusqu'au retablissement
- Les snapshots de taille WoT/Smith/TechComm utilisent le cache
### Que se passe-t-il si le noeud IPFS est indisponible ?
L'upload sur IPFS est differe si le noeud est temporairement indisponible. Le hash SHA-256 et les metadonnees sont enregistres dans la base de donnees. L'upload peut etre relance ulterieurement. Le contenu deja uploade reste accessible via les passerelles IPFS publiques.
### Les donnees de vote sont-elles publiques ?
Oui. Les votes et leurs signatures cryptographiques sont publics, conformement au principe de transparence de la gouvernance. Chaque vote peut etre verifie independamment.
### Les mises a jour sont-elles en temps reel ?
Oui. libreDecision utilise une connexion WebSocket pour diffuser les mises a jour en temps reel :
- Nouveaux votes soumis : la jauge de seuil est recalculee instantanement
- Votes modifies : la jauge reflette le changement immediatement
- Sessions cloturees : le resultat final s'affiche
- Un indicateur de connexion (point vert/orange/rouge) en bas a droite indique l'etat de la connexion temps reel
### Ou est heberge libreDecision ?
La plateforme est hebergee sur une infrastructure geree par la communaute, avec deploiement automatise via Docker et Woodpecker CI. Le code source est ouvert et disponible sur le depot Git Duniter.
## Securite
### Ma cle privee est-elle transmise au serveur ?
Non. Jamais. L'authentification utilise un mecanisme challenge-response : vous signez un texte aleatoire avec votre cle privee, et seule la signature est envoyee au serveur. La cle privee reste exclusivement dans votre portefeuille (extension Polkadot.js, Cesium, etc.).
### Comment la signature Ed25519 protege-t-elle mon vote ?
Chaque vote est accompagne d'une signature Ed25519 qui garantit :
- **Authenticite** : seul le proprietaire de l'adresse Duniter peut voter en son nom
- **Integrite** : le payload signe contient le vote, l'identifiant de la session et un horodatage. Toute modification du vote apres signature est detectable.
- **Non-repudiation** : le votant ne peut pas nier avoir vote
### Mes votes peuvent-ils etre falsifies ?
Non. Chaque vote est signe cryptographiquement avec votre cle privee Ed25519. Le payload signe contient le vote, l'identifiant de la session et un horodatage. Toute modification du vote apres signature est detectable car la verification de la signature echouerait. De plus, les votes sont publics et verifiables par n'importe qui.
### Comment verifier la signature d'un vote ?
Sur la page d'une session de vote, chaque vote affiche un lien **Verifier la signature**. En cliquant, le systeme utilise la cle publique du votant (derivee de son adresse SS58) pour verifier que la signature correspond bien au payload affiche. Vous pouvez aussi effectuer cette verification de maniere independante avec n'importe quelle bibliotheque Ed25519.