From 62808b974d0795ccbd44977252ef3a57d69be7e9 Mon Sep 17 00:00:00 2001 From: Yvv Date: Mon, 2 Mar 2026 07:59:05 +0100 Subject: [PATCH] Composants engagement: GenesisBlock, InertiaSlider, MiniVoteBoard, EngagementCard, DocumentTuto Backend: genesis_json sur Document, section_tag/inertia_preset/is_permanent_vote sur DocumentItem Frontend: 5 nouveaux composants pour vue detail document enrichie - GenesisBlock: sources, outils, synthese forum, contributeurs (depliable) - InertiaSlider: visualisation inertie 4 niveaux avec params formule G/M - MiniVoteBoard: tableau vote compact (barre seuil, pour/contre, participation) - EngagementCard: carte item enrichie integrant vote + inertie + actions - DocumentTuto: modal pedagogique vote permanent/inertie/seuils Seed et page [slug] enrichis pour exploiter les nouveaux champs Co-Authored-By: Claude Opus 4.6 --- backend/app/models/document.py | 10 +- backend/app/schemas/document.py | 13 +- backend/seed.py | 666 ++++++++++++++++-- .../app/components/documents/DocumentTuto.vue | 127 ++++ .../components/documents/EngagementCard.vue | 252 +++++++ .../app/components/documents/GenesisBlock.vue | 334 +++++++++ .../components/documents/InertiaSlider.vue | 192 +++++ .../components/documents/MiniVoteBoard.vue | 248 +++++++ frontend/app/pages/documents/[slug].vue | 390 ++++++++-- frontend/app/stores/documents.ts | 4 + 10 files changed, 2116 insertions(+), 120 deletions(-) create mode 100644 frontend/app/components/documents/DocumentTuto.vue create mode 100644 frontend/app/components/documents/EngagementCard.vue create mode 100644 frontend/app/components/documents/GenesisBlock.vue create mode 100644 frontend/app/components/documents/InertiaSlider.vue create mode 100644 frontend/app/components/documents/MiniVoteBoard.vue diff --git a/backend/app/models/document.py b/backend/app/models/document.py index adf7280..6a86bb6 100644 --- a/backend/app/models/document.py +++ b/backend/app/models/document.py @@ -1,7 +1,7 @@ import uuid from datetime import datetime -from sqlalchemy import String, Integer, Text, DateTime, ForeignKey, Uuid, func +from sqlalchemy import String, Integer, Text, DateTime, ForeignKey, Uuid, Boolean, func from sqlalchemy.orm import Mapped, mapped_column, relationship from app.database import Base @@ -19,10 +19,11 @@ class Document(Base): description: Mapped[str | None] = mapped_column(Text) ipfs_cid: Mapped[str | None] = mapped_column(String(128)) chain_anchor: Mapped[str | None] = mapped_column(String(128)) + genesis_json: Mapped[str | None] = mapped_column(Text) # JSON: source files, repos, forum URLs, formula trigger created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now()) - items: Mapped[list["DocumentItem"]] = relationship(back_populates="document", cascade="all, delete-orphan", order_by="DocumentItem.position") + items: Mapped[list["DocumentItem"]] = relationship(back_populates="document", cascade="all, delete-orphan", order_by="DocumentItem.sort_order") class DocumentItem(Base): @@ -31,11 +32,14 @@ class DocumentItem(Base): id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, default=uuid.uuid4) document_id: Mapped[uuid.UUID] = mapped_column(ForeignKey("documents.id"), nullable=False) position: Mapped[str] = mapped_column(String(16), nullable=False) # "1", "1.1", "3.2" - item_type: Mapped[str] = mapped_column(String(32), default="clause") # clause, rule, verification, preamble, section + item_type: Mapped[str] = mapped_column(String(32), default="clause") # clause, rule, verification, preamble, section, genesis title: Mapped[str | None] = mapped_column(String(256)) current_text: Mapped[str] = mapped_column(Text, nullable=False) voting_protocol_id: Mapped[uuid.UUID | None] = mapped_column(ForeignKey("voting_protocols.id")) sort_order: Mapped[int] = mapped_column(Integer, default=0) + section_tag: Mapped[str | None] = mapped_column(String(64)) # genesis, fondamental, technique, annexe, formule, inertie, ordonnancement + inertia_preset: Mapped[str] = mapped_column(String(16), default="standard") # low, standard, high, very_high + is_permanent_vote: Mapped[bool] = mapped_column(default=True) # permanent vote vs time-bounded created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now()) diff --git a/backend/app/schemas/document.py b/backend/app/schemas/document.py index d04efcc..697c979 100644 --- a/backend/app/schemas/document.py +++ b/backend/app/schemas/document.py @@ -42,6 +42,7 @@ class DocumentOut(BaseModel): description: str | None = None ipfs_cid: str | None = None chain_anchor: str | None = None + genesis_json: str | None = None created_at: datetime updated_at: datetime items_count: int = Field(default=0, description="Number of items in this document") @@ -54,10 +55,13 @@ class DocumentItemCreate(BaseModel): """Payload for creating a document item (clause, rule, etc.).""" position: str = Field(..., max_length=16, description='Hierarchical position e.g. "1", "1.1", "3.2"') - item_type: str = Field(default="clause", max_length=32, description="clause, rule, verification, preamble, section") + item_type: str = Field(default="clause", max_length=32, description="clause, rule, verification, preamble, section, genesis") title: str | None = Field(default=None, max_length=256) current_text: str = Field(..., min_length=1) voting_protocol_id: UUID | None = None + section_tag: str | None = Field(default=None, max_length=64) + inertia_preset: str = Field(default="standard", max_length=16) + is_permanent_vote: bool = True class DocumentItemUpdate(BaseModel): @@ -82,6 +86,9 @@ class DocumentItemOut(BaseModel): current_text: str voting_protocol_id: UUID | None = None sort_order: int + section_tag: str | None = None + inertia_preset: str = "standard" + is_permanent_vote: bool = True created_at: datetime updated_at: datetime @@ -99,6 +106,9 @@ class DocumentItemFullOut(BaseModel): current_text: str voting_protocol_id: UUID | None = None sort_order: int + section_tag: str | None = None + inertia_preset: str = "standard" + is_permanent_vote: bool = True created_at: datetime updated_at: datetime versions: list[ItemVersionOut] = Field(default_factory=list) @@ -118,6 +128,7 @@ class DocumentFullOut(BaseModel): description: str | None = None ipfs_cid: str | None = None chain_anchor: str | None = None + genesis_json: str | None = None created_at: datetime updated_at: datetime items: list[DocumentItemOut] = Field(default_factory=list) diff --git a/backend/seed.py b/backend/seed.py index a3a2a56..c130bfd 100644 --- a/backend/seed.py +++ b/backend/seed.py @@ -2,9 +2,17 @@ Sources: - Engagement Forgeron v2.0.0: https://forum.monnaie-libre.fr/t/33165 - - Engagement Certification (Licence G1): monnaie-libre.fr/licence-g1/ + - Engagement Certification (Licence G1 v0.3.0): + https://git.duniter.org/documents/g1_monetary_license/-/raw/master/g1_monetary_license_fr.rst + - Charte 1.0 (rejected): https://forum.monnaie-libre.fr/t/proposition-charte-1-0/31066 + - Licence v0.4.0 (in progress): https://forum.monnaie-libre.fr/t/32375 - Runtime Upgrade process template +Genesis references: + - Licence repo: https://git.duniter.org/documents/g1_monetary_license + - g1vote: https://git.duniter.org/tools/g1vote-view + - g1vote live: https://g1vote-view-237903.pages.duniter.org/ + Idempotent: checks if data already exists before inserting. """ @@ -12,6 +20,7 @@ from __future__ import annotations import asyncio import hashlib +import json import uuid from datetime import datetime, timedelta, timezone @@ -61,13 +70,47 @@ def fake_signature(payload: str) -> str: async def seed_formula_configs(session: AsyncSession) -> dict[str, FormulaConfig]: configs: dict[str, dict] = { "Standard Licence G1": { - "description": "Formule standard pour la Licence G1 : vote binaire WoT.", + "description": "Formule standard pour la Licence G1 : vote binaire WoT. Inertie standard.", "duration_days": 30, "majority_pct": 50, "base_exponent": 0.1, "gradient_exponent": 0.2, "constant_base": 0.0, }, + "Inertie basse (Annexes)": { + "description": ( + "Formule a inertie basse pour les annexes et recommandations. " + "Gradient faible = plus facile a remplacer meme a faible participation." + ), + "duration_days": 30, + "majority_pct": 50, + "base_exponent": 0.1, + "gradient_exponent": 0.1, + "constant_base": 0.0, + }, + "Inertie haute (Formule)": { + "description": ( + "Formule a inertie haute pour la section formule elle-meme. " + "Gradient eleve = necessite une forte mobilisation pour changer." + ), + "duration_days": 30, + "majority_pct": 60, + "base_exponent": 0.1, + "gradient_exponent": 0.4, + "constant_base": 0.0, + }, + "Inertie tres haute (Meta-reglage)": { + "description": ( + "Formule a inertie maximale pour le reglage de l'inertie elle-meme. " + "Quasi-unanimite requise a toute participation. Protection contre " + "la modification des regles de modification." + ), + "duration_days": 30, + "majority_pct": 66, + "base_exponent": 0.1, + "gradient_exponent": 0.6, + "constant_base": 0.0, + }, "Forgeron avec Smith": { "description": "Vote forgeron avec critere Smith sub-WoT.", "duration_days": 30, @@ -170,112 +213,599 @@ async def seed_voting_protocols( # --------------------------------------------------------------------------- -# Seed: Engagement Certification (Licence G1 - obligations certificateur) +# Seed: Engagement Certification (Acte d'engagement certification) +# +# Full structured document built from: +# - Licence G1 v0.3.0 (in force) +# - Charte 1.0 (rejected proposal, topic 31066) +# - Licence v0.4.0 (in progress, topic 32375) +# - Yvv's "Acte d'engagement" position +# - Checklist certification (topic 32412) # --------------------------------------------------------------------------- +GENESIS_CERTIFICATION = { + "source_document": { + "title": "Licence de la monnaie libre G1 v0.3.0", + "url": "https://git.duniter.org/documents/g1_monetary_license/-/raw/master/g1_monetary_license_fr.rst", + "repo": "https://git.duniter.org/documents/g1_monetary_license", + }, + "reference_tools": { + "g1vote_repo": "https://git.duniter.org/tools/g1vote-view", + "g1vote_live": "https://g1vote-view-237903.pages.duniter.org/", + "cesium": "https://g1.duniter.org", + "gecko": "https://gecko.music-all.org", + }, + "forum_synthesis": [ + { + "title": "Proposition Charte 1.0 (rejetee)", + "url": "https://forum.monnaie-libre.fr/t/proposition-charte-1-0/31066", + "status": "rejected", + "posts": 70, + }, + { + "title": "Preparation licence v0.4.0", + "url": "https://forum.monnaie-libre.fr/t/preparation-dune-proposition-devolution-de-la-licence-1/32375", + "status": "in_progress", + "posts": 38, + }, + { + "title": "Checklist de certification (annexe licence)", + "url": "https://forum.monnaie-libre.fr/t/prepa-checklist-de-certification-annexe-licence-1/32412", + "status": "in_progress", + "posts": 16, + }, + { + "title": "Regles de modifications (annexe licence)", + "url": "https://forum.monnaie-libre.fr/t/prepa-regles-de-modifications-annexe-licence-1/32409", + "status": "in_progress", + "posts": 9, + }, + { + "title": "Vote nuance licence", + "url": "https://forum.monnaie-libre.fr/t/processus-de-validation-licence-par-vote-nuance/31729", + "status": "reference", + }, + ], + "formula_trigger": ( + "Quand un item atteint le seuil d'adoption (formule WoT), " + "le texte de remplacement est integre au document officiel. " + "Le hash IPFS du document mis a jour est ancre on-chain via system.remark. " + "Les applications (Cesium, Gecko) pointent vers le depot git officiel " + "qui est synchronise avec l'etat valide par les votes." + ), + "contributors": [ + {"name": "1000i100", "role": "Pilote principal, redacteur"}, + {"name": "Natha", "role": "Co-redactrice"}, + {"name": "Pini", "role": "Co-initiateur"}, + {"name": "Yvv", "role": "Contributions structurelles, concepteur 'Acte d'engagement'"}, + {"name": "elois", "role": "Dev g1vote, contributions techniques"}, + ], +} + + ENGAGEMENT_CERTIFICATION_ITEMS: list[dict] = [ + # =================================================================== + # INTRODUCTION + # =================================================================== { - "position": "C1", - "item_type": "clause", - "title": "Transmission de la licence", + "position": "I1", + "item_type": "preamble", + "title": "Preambule", "sort_order": 1, + "section_tag": "introduction", + "inertia_preset": "standard", "current_text": ( - "Toute operation de certification d'un nouveau membre de la monnaie libre G1 " - "doit prealablement s'accompagner de la transmission de cette licence " - "de la monnaie libre G1 au certifie." + "Le present acte d'engagement definit les obligations reciproques " + "des membres de la toile de confiance de la monnaie libre G1. " + "Cet acte est de fait l'unique relation contractuelle de notre " + "toile fiduciaire. Toute certification doit s'accompagner de la " + "transmission de ce document, dont le certificateur doit s'assurer " + "qu'il a ete etudie, compris et accepte par le certifie." ), }, { - "position": "C2", - "item_type": "clause", - "title": "Connaissance suffisante du certifie", + "position": "I2", + "item_type": "preamble", + "title": "Les deux garanties reciproques", "sort_order": 2, + "section_tag": "introduction", + "inertia_preset": "standard", "current_text": ( - "Certifier n'est pas uniquement s'assurer que vous avez rencontre la personne, " - "c'est assurer a la communaute G1 que vous connaissez suffisamment bien la " - "personne que vous vous appretez a certifier." + "La certification repose sur deux garanties reciproques :\n\n" + "**1.** Derriere une cle publique creatrice de monnaie " + "se trouve un **etre humain vivant**.\n\n" + "**2.** Derriere cet etre humain se trouve **une seule et unique** " + "cle publique creatrice de monnaie.\n\n" + "La certification est un acte technique et fiduciaire, " + "pas un acte d'adhesion morale ou de sympathie." ), }, + # =================================================================== + # TITRE 1 : ENGAGEMENTS FONDAMENTAUX (sur l'honneur) + # =================================================================== { - "position": "C3", - "item_type": "clause", - "title": "Contact par plusieurs moyens", + "position": "T1", + "item_type": "section", + "title": "Engagements fondamentaux", "sort_order": 3, + "section_tag": "fondamental", + "inertia_preset": "standard", "current_text": ( - "Connaitre la personne par plusieurs moyens de contact differents " - "(physique, electronique, etc.) permettant de verifier son identite " - "et de maintenir un lien de confiance dans la duree." + "Les engagements fondamentaux ci-dessous constituent le socle " + "irreductible de l'acte d'engagement. Ils sont pris sur l'honneur " + "par tout membre de la toile de confiance." ), }, { - "position": "C4", + "position": "E1", "item_type": "clause", - "title": "Ne jamais certifier seul", + "title": "Unicite du compte", "sort_order": 4, + "section_tag": "fondamental", + "inertia_preset": "standard", "current_text": ( - "Ne certifiez jamais seul, mais accompagne d'au moins un autre membre " - "de la TdC G1, pour garantir un double controle et eviter les " - "certifications abusives." + "Je m'engage sur l'honneur a n'avoir et n'avoir jamais " + "qu'un seul et unique compte cocreateur de monnaie G1." ), }, { - "position": "C5", - "item_type": "verification", - "title": "Verification des certifications existantes", + "position": "E2", + "item_type": "clause", + "title": "Certification responsable", "sort_order": 5, + "section_tag": "fondamental", + "inertia_preset": "standard", "current_text": ( - "Avant toute certification, assurez-vous de verifier si le compte du " - "certifie a deja recu une ou plusieurs certifications, et de qui " - "elles proviennent." + "Je m'engage sur l'honneur a ne certifier que des personnes " + "physiques qui respectent scrupuleusement ces deux presents " + "engagements fondamentaux." ), }, + # =================================================================== + # TITRE 2 : ENGAGEMENTS TECHNIQUES + # =================================================================== { - "position": "C6", - "item_type": "verification", - "title": "Verification de maitrise du compte", + "position": "T2", + "item_type": "section", + "title": "Engagements techniques", "sort_order": 6, + "section_tag": "technique", + "inertia_preset": "standard", "current_text": ( - "Verifier la maitrise du compte par un transfert test : envoyer " - "quelques G1 et demander un renvoi, afin de s'assurer que la personne " - "controle bien sa cle privee." + "Les engagements techniques definissent les obligations " + "pratiques et verifiables du certificateur pour garantir " + "la qualite de la toile de confiance." ), }, { - "position": "C7", - "item_type": "verification", - "title": "Verification de la licence", + "position": "E3", + "item_type": "clause", + "title": "Connaissance suffisante", "sort_order": 7, + "section_tag": "technique", + "inertia_preset": "standard", "current_text": ( - "Verifiez que vos contacts ont bien etudie et compris la licence G1 " - "a jour avant de proceder a la certification." + "Je me suis assure de connaitre suffisamment la personne " + "qui gere cette cle publique. Connaitre suffisamment ne signifie " + "pas « avoir vu » ; c'est assurer a la communaute G1 que je " + "pourrai la contacter facilement et etre en mesure de reperer " + "un double-compte ou tout autre probleme." ), }, { - "position": "C8", - "item_type": "verification", - "title": "Document de revocation", + "position": "E4", + "item_type": "clause", + "title": "Verification personnelle de la cle", "sort_order": 8, + "section_tag": "technique", + "inertia_preset": "standard", "current_text": ( - "D'avoir bien verifie avec la personne concernee qu'elle a bien genere " - "son document Duniter de revocation de compte, et qu'elle le conserve " + "J'ai personnellement verifie que c'est bien cette cle publique " + "que je m'apprete a certifier, en la comparant avec la personne " + "concernee et non par un intermediaire." + ), + }, + { + "position": "E5", + "item_type": "clause", + "title": "Joignabilite reciproque", + "sort_order": 9, + "section_tag": "technique", + "inertia_preset": "standard", + "current_text": ( + "Je suis joignable rapidement et facilement par mes certifieurs, " + "et je peux joindre rapidement et facilement les personnes que " + "je certifie, par plusieurs moyens de communication differents " + "et independants (physique, telephone, email, messagerie, etc.)." + ), + }, + { + "position": "E6", + "item_type": "clause", + "title": "Document de revocation", + "sort_order": 10, + "section_tag": "technique", + "inertia_preset": "standard", + "current_text": ( + "J'ai verifie avec la personne certifiee qu'elle a bien genere " + "son document de revocation de compte et qu'elle le conserve " "en lieu sur." ), }, { - "position": "C9", + "position": "E7", "item_type": "clause", - "title": "Rencontre physique ou multi-canal", - "sort_order": 9, + "title": "Rencontre physique ou verification multi-canaux", + "sort_order": 11, + "section_tag": "technique", + "inertia_preset": "standard", "current_text": ( - "De rencontrer la personne physiquement, OU de verifier a distance " - "le lien personne / cle publique par plusieurs moyens de communication " - "differents et independants." + "J'ai rencontre la personne physiquement (preferable), **OU** " + "j'ai verifie a distance le lien personne / cle publique par " + "plusieurs moyens de communication differents et independants : " + "courrier + reseau social + forum + email + visio + telephone." + ), + }, + # =================================================================== + # TITRE 3 : CONSEILS ET BONNES PRATIQUES + # =================================================================== + { + "position": "T3", + "item_type": "section", + "title": "Conseils et bonnes pratiques", + "sort_order": 12, + "section_tag": "technique", + "inertia_preset": "standard", + "current_text": ( + "Les pratiques suivantes sont fortement recommandees pour " + "garantir la qualite et la securite de la toile de confiance." + ), + }, + { + "position": "E8", + "item_type": "clause", + "title": "Ne jamais certifier seul", + "sort_order": 13, + "section_tag": "technique", + "inertia_preset": "standard", + "current_text": ( + "Ne certifiez jamais seul, mais accompagne d'au moins un autre " + "membre de la toile de confiance G1, pour garantir un double " + "controle." + ), + }, + { + "position": "E9", + "item_type": "clause", + "title": "Verification des certifications existantes", + "sort_order": 14, + "section_tag": "technique", + "inertia_preset": "standard", + "current_text": ( + "Avant toute certification, verifiez si le compte a deja " + "recu des certifications et de qui elles proviennent. " + "Contactez les certifieurs existants en cas de doute. " + "Si un certifieurs existant ne connait pas la personne, " + "alertez immediatement les experts de la communaute." + ), + }, + { + "position": "E10", + "item_type": "clause", + "title": "Verification de maitrise du compte", + "sort_order": 15, + "section_tag": "technique", + "inertia_preset": "standard", + "current_text": ( + "Verifiez la maitrise du compte par un transfert-test : " + "envoyez quelques G1 et demandez le renvoi, afin de vous " + "assurer que la personne controle bien sa cle privee." + ), + }, + { + "position": "E11", + "item_type": "clause", + "title": "Transmission et comprehension du document", + "sort_order": 16, + "section_tag": "technique", + "inertia_preset": "standard", + "current_text": ( + "Verifiez que vos contacts ont bien etudie et compris " + "le present acte d'engagement dans sa version a jour " + "avant de proceder a la certification." + ), + }, + # =================================================================== + # CONCLUSION + # =================================================================== + { + "position": "K1", + "item_type": "preamble", + "title": "Regles abregees de la toile de confiance", + "sort_order": 17, + "section_tag": "conclusion", + "inertia_preset": "standard", + "current_text": ( + "**Parametres protocolaires en vigueur :**\n\n" + "- Stock de **100 certifications** possibles\n" + "- 1 certification emissible tous les **5 jours**\n" + "- Nouveau compte valide si **>= 5 certifications** recues en **2 mois**\n" + "- Condition de distance : **<= 5 pas** de **80% des sentinelles**\n" + "- Sentinelle : membre ayant recu et emis >= Y[N] certifs " + "(Y = ceil(N^(1/5)))\n" + "- Certifications actives valables **2 ans**\n" + "- Renouvellement de l'accord tous les **12 mois**" + ), + }, + { + "position": "K2", + "item_type": "preamble", + "title": "Monnaie G1", + "sort_order": 18, + "section_tag": "conclusion", + "inertia_preset": "standard", + "current_text": ( + "**Parametres monetaires :**\n\n" + "- 1 Dividende Universel (DU) par personne par jour\n" + "- Reevaluation a chaque equinoxe : " + "`DU(n+1) = DU(n) + c² × (M/N) / 182.625` avec c = 4.88%\n" + "- DU(0) = 10.00 G1" + ), + }, + # =================================================================== + # ANNEXE 1 : INTEGRATION LOGICIELLE + # =================================================================== + { + "position": "X1", + "item_type": "section", + "title": "Annexe 1 : Integration logicielle", + "sort_order": 19, + "section_tag": "annexe", + "inertia_preset": "low", + "current_text": ( + "Les obligations pour les logiciels implementant la certification G1." + ), + }, + { + "position": "X1.1", + "item_type": "clause", + "title": "Depot de reference", + "sort_order": 20, + "section_tag": "annexe", + "inertia_preset": "low", + "current_text": ( + "Le texte de reference de l'acte d'engagement certification est " + "heberge dans le depot git officiel : " + "https://git.duniter.org/documents/g1_monetary_license\n\n" + "Les applications Cesium, Gecko et toute application de " + "certification doivent pointer vers ce depot pour afficher " + "la version en vigueur." + ), + }, + { + "position": "X1.2", + "item_type": "clause", + "title": "Obligation de transmission", + "sort_order": 21, + "section_tag": "annexe", + "inertia_preset": "low", + "current_text": ( + "Tout logiciel G1 permettant la certification doit transmettre " + "le present acte d'engagement au certifie et en afficher les " + "parametres du bloc 0 de la blockchain Duniter." + ), + }, + { + "position": "X1.3", + "item_type": "clause", + "title": "Logiciel auditable", + "sort_order": 22, + "section_tag": "annexe", + "inertia_preset": "low", + "current_text": ( + "Tout logiciel utilise pour la certification ou la creation " + "monetaire doit etre publie sous licence libre, afin de " + "permettre son audit par la communaute." + ), + }, + # =================================================================== + # ANNEXE 2 : QUESTIONS A LA CERTIFICATION (checklist logicielle) + # =================================================================== + { + "position": "X2", + "item_type": "section", + "title": "Annexe 2 : Questions a la certification", + "sort_order": 23, + "section_tag": "annexe", + "inertia_preset": "low", + "current_text": ( + "Liste de questions a presenter dans les logiciels de certification. " + "Inspiree de la checklist de la Charte 1.0 et des discussions " + "forum (topic 32412)." + ), + }, + { + "position": "X2.1", + "item_type": "verification", + "title": "Questions piege (reponse attendue : NON)", + "sort_order": 24, + "section_tag": "annexe", + "inertia_preset": "low", + "current_text": ( + "**Si OUI a l'une de ces questions, la certification doit etre refusee.**\n\n" + "- La personne m'a contacte uniquement pour obtenir ma certification\n" + "- Je certifie sous la pression ou pour faire plaisir\n" + "- Je n'ai aucun moyen de verifier l'identite de la personne\n" + "- La personne refuse de me donner plusieurs moyens de contact\n" + "- Je soupçonne que la personne possede deja un compte membre\n" + "- Je ne connais aucun de ses autres certifieurs\n" + "- La personne ne comprend pas ce qu'est la monnaie libre\n" + "- La personne n'a pas lu le present acte d'engagement" + ), + }, + { + "position": "X2.2", + "item_type": "verification", + "title": "Questions identite (reponse attendue : OUI)", + "sort_order": 25, + "section_tag": "annexe", + "inertia_preset": "low", + "current_text": ( + "**Si NON a l'une de ces questions, la certification doit etre refusee.**\n\n" + "- Je connais cette personne suffisamment pour la recontacter\n" + "- J'ai verifie personnellement le lien personne / cle publique\n" + "- La personne est une personne physique vivante (pas une entite morale)\n" + "- Je pourrais reconnaitre cette personne si je la croisais\n" + "- J'ai au moins 2 moyens de contact differents pour cette personne" + ), + }, + { + "position": "X2.3", + "item_type": "verification", + "title": "Questions securite (reponse attendue : OUI)", + "sort_order": 26, + "section_tag": "annexe", + "inertia_preset": "low", + "current_text": ( + "**Si NON, la certification est deconseille.**\n\n" + "- La personne a genere son document de revocation\n" + "- La personne maitrise effectivement son compte " + "(test de transfert effectue)\n" + "- La personne sait ou retrouver le present acte d'engagement " + "dans sa version a jour" + ), + }, + # =================================================================== + # SECTION SPECIALE : FORMULE DE VOTE + # =================================================================== + { + "position": "F1", + "item_type": "section", + "title": "Formule de vote", + "sort_order": 27, + "section_tag": "formule", + "inertia_preset": "high", + "current_text": ( + "La formule qui regit l'adoption ou le rejet de chaque modification " + "du present document. Reference : g1vote " + "(https://g1vote-view-237903.pages.duniter.org/)." + ), + }, + { + "position": "F1.1", + "item_type": "rule", + "title": "Formule du seuil WoT", + "sort_order": 28, + "section_tag": "formule", + "inertia_preset": "high", + "current_text": ( + "**Seuil = C + B^W + (M + (1-M) × (1 - (T/W)^G)) × max(0, T-C)**\n\n" + "Ou :\n" + "- **C** = constante de base (plancher fixe)\n" + "- **B** = exposant de base (B^W tend vers 0)\n" + "- **W** = taille de la toile de confiance (electeurs eligibles)\n" + "- **T** = total des votes exprimes (pour + contre)\n" + "- **M** = ratio de majorite cible (M = majority_pct / 100)\n" + "- **G** = exposant du gradient d'inertie\n\n" + "**Comportement :** Faible participation → quasi-unanimite requise. " + "Forte participation → majorite simple M suffit." + ), + }, + { + "position": "F1.2", + "item_type": "rule", + "title": "Parametres par defaut", + "sort_order": 29, + "section_tag": "formule", + "inertia_preset": "high", + "current_text": ( + "Parametres de reference pour les engagements (inertie standard) :\n\n" + "| Parametre | Code | Valeur |\n" + "|-----------|------|--------|\n" + "| Duree | D | 30 jours (permanent) |\n" + "| Majorite | M | 50% |\n" + "| Base | B | 0.1 |\n" + "| Gradient | G | 0.2 |\n" + "| Constante | C | 0.0 |\n\n" + "Mode compact : **D30M50B.1G.2**" + ), + }, + { + "position": "F1.3", + "item_type": "rule", + "title": "Processus de depot officiel", + "sort_order": 30, + "section_tag": "formule", + "inertia_preset": "high", + "current_text": ( + "Lorsqu'une proposition alternative atteint le seuil d'adoption :\n\n" + "1. Le texte de remplacement est integre au document officiel\n" + "2. Le hash IPFS du document mis a jour est calcule\n" + "3. Le hash est ancre on-chain via `system.remark`\n" + "4. Le depot git officiel est synchronise\n" + "5. Les applications (Cesium, Gecko) mettent a jour automatiquement" + ), + }, + # =================================================================== + # SECTION SPECIALE : REGLAGE DE L'INERTIE + # =================================================================== + { + "position": "N1", + "item_type": "section", + "title": "Reglage de l'inertie", + "sort_order": 31, + "section_tag": "inertie", + "inertia_preset": "very_high", + "current_text": ( + "Le reglage de l'inertie definit la difficulte de remplacement " + "de chaque section du document. Ce reglage est lui-meme soumis " + "a l'inertie la plus elevee, pour empecher la modification " + "des regles de modification." + ), + }, + { + "position": "N1.1", + "item_type": "rule", + "title": "Niveaux d'inertie", + "sort_order": 32, + "section_tag": "inertie", + "inertia_preset": "very_high", + "current_text": ( + "| Niveau | Gradient G | Majorite M | Application |\n" + "|--------|-----------|------------|-------------|\n" + "| **Basse** | 0.1 | 50% | Annexes, recommandations |\n" + "| **Standard** | 0.2 | 50% | Engagements fondamentaux et techniques |\n" + "| **Haute** | 0.4 | 60% | Formule de vote |\n" + "| **Tres haute** | 0.6 | 66% | Reglage de l'inertie |\n\n" + "Plus le gradient est eleve, plus il faut de participation " + "et de consensus pour qu'une modification soit adoptee." + ), + }, + # =================================================================== + # SECTION SPECIALE : ORDONNANCEMENT + # =================================================================== + { + "position": "O1", + "item_type": "section", + "title": "Ordonnancement du document", + "sort_order": 33, + "section_tag": "ordonnancement", + "inertia_preset": "high", + "current_text": ( + "L'ordre de presentation des items dans le document est " + "lui-meme soumis au vote. Toute proposition de reorganisation " + "doit atteindre le seuil d'adoption avec l'inertie haute." ), }, ] -async def seed_document_engagement_certification(session: AsyncSession) -> Document: +async def seed_document_engagement_certification( + session: AsyncSession, + protocols: dict[str, VotingProtocol], +) -> Document: + genesis = json.dumps(GENESIS_CERTIFICATION, ensure_ascii=False, indent=2) + doc, created = await get_or_create( session, Document, @@ -286,15 +816,33 @@ async def seed_document_engagement_certification(session: AsyncSession) -> Docum version="1.0.0", status="active", description=( - "Obligations des certificateurs de la toile de confiance Duniter. " - "Chaque clause est soumise au vote permanent de la communaute." + "Acte d'engagement des certificateurs de la toile de confiance G1. " + "Document modulaire sous vote permanent : chaque item peut etre " + "remplace par une alternative qui atteint le seuil d'adoption. " + "Construit a partir de la Licence G1 v0.3.0, des discussions " + "communautaires et de la position 'Acte d'engagement' (Yvv)." ), + genesis_json=genesis, ) print(f" Document 'Acte d'engagement certification': {'created' if created else 'exists'}") if created: + # Map inertia presets to voting protocols + inertia_protocol_map = { + "low": protocols.get("Vote WoT standard"), + "standard": protocols.get("Vote WoT standard"), + "high": protocols.get("Vote WoT standard"), + "very_high": protocols.get("Vote WoT standard"), + } + for item_data in ENGAGEMENT_CERTIFICATION_ITEMS: - item = DocumentItem(document_id=doc.id, **item_data) + preset = item_data.get("inertia_preset", "standard") + protocol = inertia_protocol_map.get(preset) + item = DocumentItem( + document_id=doc.id, + voting_protocol_id=protocol.id if protocol else None, + **item_data, + ) session.add(item) await session.flush() print(f" -> {len(ENGAGEMENT_CERTIFICATION_ITEMS)} items created") @@ -903,7 +1451,7 @@ async def run_seed(): protocols = await seed_voting_protocols(session, formulas) print("\n[3/7] Document: Acte d'engagement certification...") - await seed_document_engagement_certification(session) + await seed_document_engagement_certification(session, protocols) print("\n[4/7] Document: Acte d'engagement forgeron v2.0.0...") doc_forgeron = await seed_document_engagement_forgeron(session) diff --git a/frontend/app/components/documents/DocumentTuto.vue b/frontend/app/components/documents/DocumentTuto.vue new file mode 100644 index 0000000..9e98211 --- /dev/null +++ b/frontend/app/components/documents/DocumentTuto.vue @@ -0,0 +1,127 @@ + + + + + diff --git a/frontend/app/components/documents/EngagementCard.vue b/frontend/app/components/documents/EngagementCard.vue new file mode 100644 index 0000000..0996363 --- /dev/null +++ b/frontend/app/components/documents/EngagementCard.vue @@ -0,0 +1,252 @@ + + + + + diff --git a/frontend/app/components/documents/GenesisBlock.vue b/frontend/app/components/documents/GenesisBlock.vue new file mode 100644 index 0000000..ecc3e52 --- /dev/null +++ b/frontend/app/components/documents/GenesisBlock.vue @@ -0,0 +1,334 @@ + + + + + diff --git a/frontend/app/components/documents/InertiaSlider.vue b/frontend/app/components/documents/InertiaSlider.vue new file mode 100644 index 0000000..b0ddaeb --- /dev/null +++ b/frontend/app/components/documents/InertiaSlider.vue @@ -0,0 +1,192 @@ + + + + + diff --git a/frontend/app/components/documents/MiniVoteBoard.vue b/frontend/app/components/documents/MiniVoteBoard.vue new file mode 100644 index 0000000..4f7ba52 --- /dev/null +++ b/frontend/app/components/documents/MiniVoteBoard.vue @@ -0,0 +1,248 @@ + + + + + diff --git a/frontend/app/pages/documents/[slug].vue b/frontend/app/pages/documents/[slug].vue index 6e48dc5..5b6d45f 100644 --- a/frontend/app/pages/documents/[slug].vue +++ b/frontend/app/pages/documents/[slug].vue @@ -1,4 +1,13 @@ + + diff --git a/frontend/app/stores/documents.ts b/frontend/app/stores/documents.ts index 9385ef4..7441797 100644 --- a/frontend/app/stores/documents.ts +++ b/frontend/app/stores/documents.ts @@ -13,6 +13,9 @@ export interface DocumentItem { current_text: string voting_protocol_id: string | null sort_order: number + section_tag: string | null + inertia_preset: string + is_permanent_vote: boolean created_at: string updated_at: string } @@ -27,6 +30,7 @@ export interface Document { description: string | null ipfs_cid: string | null chain_anchor: string | null + genesis_json: string | null created_at: string updated_at: string items_count: number