Sprint 1 : scaffolding complet de Glibredecision
Plateforme de decisions collectives pour Duniter/G1. Backend FastAPI async + PostgreSQL (14 tables, 8 routers, 6 services, moteur de vote avec formule d'inertie WoT/Smith/TechComm). Frontend Nuxt 4 + Nuxt UI v3 + Pinia (9 pages, 5 stores). Infrastructure Docker + Woodpecker CI + Traefik. Documentation technique et utilisateur (15 fichiers). Seed : Licence G1, Engagement Forgeron v2.0.0, 4 protocoles de vote. 30 tests unitaires (formules, mode params, vote nuance) -- tous verts. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
17
docs/content/dev/1.index.md
Normal file
17
docs/content/dev/1.index.md
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
title: Documentation technique
|
||||
description: Architecture, API et reference technique de Glibredecision
|
||||
---
|
||||
|
||||
# Documentation technique
|
||||
|
||||
Bienvenue dans la documentation technique de Glibredecision.
|
||||
|
||||
## Sections
|
||||
|
||||
- [Architecture](/dev/architecture) -- Vue d'ensemble de l'architecture
|
||||
- [Reference API](/dev/api-reference) -- Endpoints et schemas
|
||||
- [Schema de base de donnees](/dev/database-schema) -- Tables et relations
|
||||
- [Formules](/dev/formulas) -- Formules mathematiques de seuil
|
||||
- [Integration blockchain](/dev/blockchain-integration) -- Duniter V2, IPFS, on-chain
|
||||
- [Contribution](/dev/contributing) -- Guide de contribution
|
||||
81
docs/content/dev/2.architecture.md
Normal file
81
docs/content/dev/2.architecture.md
Normal file
@@ -0,0 +1,81 @@
|
||||
---
|
||||
title: Architecture
|
||||
description: Vue d'ensemble de l'architecture technique de Glibredecision
|
||||
---
|
||||
|
||||
# Architecture
|
||||
|
||||
## Vue d'ensemble
|
||||
|
||||
Glibredecision est organise en monorepo avec trois composants principaux :
|
||||
|
||||
```
|
||||
Glibredecision/
|
||||
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).
|
||||
106
docs/content/dev/3.api-reference.md
Normal file
106
docs/content/dev/3.api-reference.md
Normal file
@@ -0,0 +1,106 @@
|
||||
---
|
||||
title: Reference API
|
||||
description: Liste des endpoints de l'API Glibredecision
|
||||
---
|
||||
|
||||
# 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 |
|
||||
| POST | `/{slug}/items/{item_id}/versions` | Proposer une nouvelle version d'un item | 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 |
|
||||
| POST | `/{id}/steps` | Ajouter une etape a une decision | Oui |
|
||||
|
||||
## Votes (`/api/v1/votes`)
|
||||
|
||||
| Methode | Endpoint | Description | Auth |
|
||||
| ------- | --------------------------- | -------------------------------------------- | ---- |
|
||||
| POST | `/sessions` | Creer une session de vote | Oui |
|
||||
| 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 |
|
||||
|
||||
## 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 |
|
||||
|
||||
## 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 |
|
||||
| GET | `/formulas` | Lister les configurations de formules | Non |
|
||||
| POST | `/formulas` | Creer une configuration de formule | Oui |
|
||||
|
||||
## 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 |
|
||||
|
||||
## 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) |
|
||||
|
||||
## 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`).
|
||||
312
docs/content/dev/4.database-schema.md
Normal file
312
docs/content/dev/4.database-schema.md
Normal file
@@ -0,0 +1,312 @@
|
||||
---
|
||||
title: Schema de base de donnees
|
||||
description: Tables et relations de la base de donnees PostgreSQL
|
||||
---
|
||||
|
||||
# Schema de base de donnees
|
||||
|
||||
Glibredecision 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.
|
||||
|
||||
| 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 |
|
||||
| chain_anchor | VARCHAR(128) | Hash de transaction on-chain |
|
||||
| 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.).
|
||||
|
||||
| Colonne | Type | Description |
|
||||
| ------------------- | ------------ | ------------------------------------------------- |
|
||||
| id | UUID (PK) | Identifiant unique |
|
||||
| document_id | UUID (FK) | -> documents.id |
|
||||
| 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 |
|
||||
| voting_protocol_id | UUID (FK) | -> voting_protocols.id (protocole specifique) |
|
||||
| sort_order | INTEGER | Ordre de tri |
|
||||
| created_at | TIMESTAMPTZ | Date de creation |
|
||||
| updated_at | TIMESTAMPTZ | Date de derniere mise a jour |
|
||||
|
||||
### `item_versions`
|
||||
|
||||
Historique des versions proposees pour chaque item.
|
||||
|
||||
| Colonne | Type | Description |
|
||||
| -------------- | ------------ | ------------------------------------------------------ |
|
||||
| id | UUID (PK) | Identifiant unique |
|
||||
| item_id | UUID (FK) | -> document_items.id |
|
||||
| proposed_text | TEXT | Texte propose |
|
||||
| diff_text | TEXT | Diff unifie entre texte courant et propose |
|
||||
| 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.
|
||||
|
||||
| Colonne | Type | Description |
|
||||
| ------------------- | ------------ | -------------------------------------------------------- |
|
||||
| id | UUID (PK) | Identifiant unique |
|
||||
| title | VARCHAR(256) | Titre de la decision |
|
||||
| description | TEXT | Description |
|
||||
| context | TEXT | Contexte additionnel |
|
||||
| decision_type | VARCHAR(64) | Type : runtime_upgrade, document_change, mandate_vote, 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 |
|
||||
|
||||
### `decision_steps`
|
||||
|
||||
Etapes d'un processus decisionnel.
|
||||
|
||||
| Colonne | Type | Description |
|
||||
| ---------------- | ------------ | -------------------------------------------------------- |
|
||||
| id | UUID (PK) | Identifiant unique |
|
||||
| decision_id | UUID (FK) | -> decisions.id |
|
||||
| step_order | INTEGER | Ordre de l'etape |
|
||||
| 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 (session de vote associee) |
|
||||
| outcome | TEXT | Resultat de l'etape |
|
||||
| created_at | TIMESTAMPTZ | Date de creation |
|
||||
|
||||
### `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.
|
||||
|
||||
| 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) |
|
||||
| decision_id | UUID (FK) | -> decisions.id (decision associee) |
|
||||
| starts_at | TIMESTAMPTZ | Date de debut |
|
||||
| ends_at | TIMESTAMPTZ | Date de fin |
|
||||
| created_at | TIMESTAMPTZ | Date de creation |
|
||||
| updated_at | TIMESTAMPTZ | Date de derniere mise a jour |
|
||||
|
||||
### `mandate_steps`
|
||||
|
||||
Etapes du cycle de vie d'un mandat.
|
||||
|
||||
| Colonne | Type | Description |
|
||||
| ---------------- | ------------ | ------------------------------------------------------------- |
|
||||
| id | UUID (PK) | Identifiant unique |
|
||||
| mandate_id | UUID (FK) | -> mandates.id |
|
||||
| step_order | INTEGER | Ordre de l'etape |
|
||||
| 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 (session de vote associee) |
|
||||
| outcome | TEXT | Resultat de l'etape |
|
||||
| created_at | TIMESTAMPTZ | Date de creation |
|
||||
|
||||
### `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).
|
||||
|
||||
| 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 |
|
||||
| title | VARCHAR(256) | Titre |
|
||||
| content_hash | VARCHAR(128) | Hash SHA-256 du contenu |
|
||||
| ipfs_cid | VARCHAR(128) | CID IPFS |
|
||||
| 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
|
||||
|
||||
document_items
|
||||
|-- 1:N --> item_versions
|
||||
|-- N:1 --> voting_protocols
|
||||
|
||||
item_versions
|
||||
|-- N:1 --> decisions
|
||||
|
||||
decisions
|
||||
|-- 1:N --> decision_steps
|
||||
|
||||
decision_steps
|
||||
|-- N:1 --> vote_sessions
|
||||
|
||||
vote_sessions
|
||||
|-- 1:N --> votes
|
||||
|-- N:1 --> voting_protocols
|
||||
|
||||
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
|
||||
```
|
||||
137
docs/content/dev/5.formulas.md
Normal file
137
docs/content/dev/5.formulas.md
Normal file
@@ -0,0 +1,137 @@
|
||||
---
|
||||
title: Formules
|
||||
description: Formules mathematiques de seuil WoT, criteres Smith et TechComm
|
||||
---
|
||||
|
||||
# Formules de seuil
|
||||
|
||||
Glibredecision 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
|
||||
|
||||
| Symbole | Parametre | Description | Defaut |
|
||||
| ------- | ------------------- | ------------------------------------------------ | ------ |
|
||||
| $C$ | `constant_base` | Base constante additive (plancher) | 0.0 |
|
||||
| $B$ | `base_exponent` | Exposant de base. $B^W$ devient negligeable quand $W$ est grand ($0 < B < 1$) | 0.1 |
|
||||
| $W$ | `wot_size` | Taille du corpus des votants eligibles (membres WoT) | -- |
|
||||
| $T$ | `total_votes` | Nombre total de votes exprimes (pour + contre) | -- |
|
||||
| $M$ | `majority_pct / 100`| Ratio de majorite. 0.5 = majorite simple a pleine participation | 50 |
|
||||
| $G$ | `gradient_exponent` | Controle la vitesse de convergence de la super-majorite vers $M$ | 0.2 |
|
||||
|
||||
### Mecanisme d'inertie
|
||||
|
||||
Le coeur de la formule est le facteur d'inertie :
|
||||
|
||||
$$
|
||||
\text{inertia} = 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.
|
||||
|
||||
### Exemple de reference
|
||||
|
||||
Avec les parametres `M50 B.1 G.2` et le vote de l'Engagement Forgeron v2.0.0 :
|
||||
|
||||
- $W = 7224$ (membres WoT)
|
||||
- $T = 120$ (97 pour + 23 contre)
|
||||
- Seuil calcule : $94$
|
||||
- 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 | Defaut |
|
||||
| ------- | ---------------- | ---------------------------- | ------ |
|
||||
| $S$ | `smith_exponent` | Exposant pour le critere Smith | null (desactive) |
|
||||
|
||||
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 \rceil
|
||||
$$
|
||||
|
||||
Le critere TechComm fonctionne de maniere identique au critere Smith mais pour les membres du Comite Technique.
|
||||
|
||||
| Symbole | Parametre | Description | Defaut |
|
||||
| ------- | ------------------- | ------------------------------- | ------ |
|
||||
| $T$ | `techcomm_exponent` | Exposant pour le critere TechComm | null (desactive) |
|
||||
|
||||
Avec un exposant de $T = 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)
|
||||
|
||||
## 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 | Exemple |
|
||||
| ---- | --------------------- | ----- | ------------ |
|
||||
| D | `duration_days` | int | D30 = 30 jours |
|
||||
| M | `majority_pct` | int | M50 = 50% |
|
||||
| B | `base_exponent` | float | B.1 = 0.1 |
|
||||
| G | `gradient_exponent` | float | G.2 = 0.2 |
|
||||
| C | `constant_base` | float | C0 = 0.0 |
|
||||
| S | `smith_exponent` | float | S.1 = 0.1 |
|
||||
| T | `techcomm_exponent` | float | T.1 = 0.1 |
|
||||
| N | `ratio_multiplier` | float | N1.5 = 1.5 |
|
||||
| R | `is_ratio_mode` | bool | 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), Glibredecision supporte un vote nuance a 6 niveaux :
|
||||
|
||||
| Niveau | Label |
|
||||
| ------ | ------------- |
|
||||
| 0 | CONTRE |
|
||||
| 1 | PAS DU TOUT |
|
||||
| 2 | PAS D'ACCORD |
|
||||
| 3 | NEUTRE |
|
||||
| 4 | D'ACCORD |
|
||||
| 5 | TOUT A FAIT |
|
||||
|
||||
### 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.
|
||||
|
||||
Par defaut : `threshold_pct = 80%`, `min_participants = 59`.
|
||||
165
docs/content/dev/6.blockchain-integration.md
Normal file
165
docs/content/dev/6.blockchain-integration.md
Normal file
@@ -0,0 +1,165 @@
|
||||
---
|
||||
title: Integration blockchain
|
||||
description: Integration Duniter V2, IPFS et ancrage on-chain
|
||||
---
|
||||
|
||||
# Integration blockchain
|
||||
|
||||
Glibredecision 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
|
||||
|
||||
```
|
||||
glibredecision: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"glibredecision: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
docs/content/dev/7.contributing.md
Normal file
145
docs/content/dev/7.contributing.md
Normal file
@@ -0,0 +1,145 @@
|
||||
---
|
||||
title: Contribution
|
||||
description: Guide de contribution au projet Glibredecision
|
||||
---
|
||||
|
||||
# Guide de contribution
|
||||
|
||||
Merci de votre interet pour contribuer a Glibredecision. 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/glibredecision.git
|
||||
cd glibredecision
|
||||
|
||||
# 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.
|
||||
Reference in New Issue
Block a user