Boîtes à outils enrichies : ContextMapper, SocioElection, WorkflowMilestones

- ContextMapper : 4 questions contexte → méthode de décision optimale
  (advice process Laloux, vote inertiel WoT, consentement sociocratique, Smith…)
- SocioElection : guide élection sociocratique 6 étapes + advice process + clarté de rôle
- WorkflowMilestones : 11 jalons de protocole (7 essentiels), durées recommandées, principes Ostrom
- WorkspaceSelector : sélecteur de collectif multi-site dans le header
- SectionLayout : toolbox en USlideover droit sur mobile, sidebar sticky desktop
- Décisions : ContextMapper intégré + guide consentement
- Mandats : SocioElection intégré + cycle de mandat
- Documents : guide inertie 4 niveaux + structure + IPFS
- Protocoles : WorkflowMilestones + protocole élection sociocratique ajouté
- Renommage projet Glibredecision → libreDecision (dossier + sources)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Yvv
2026-03-17 00:13:08 +01:00
parent 316d205593
commit 290548703d
29 changed files with 4174 additions and 168 deletions

View File

@@ -0,0 +1,551 @@
<script setup lang="ts">
/**
* WorkflowMilestones — 11 jalons de protocole de fonctionnement.
* Sélectif et qualitatif : ce qui fait la différence entre un protocole
* qui tient et un qui dérive.
* Référence : g1vote, sociocracie, Laloux, Elinor Ostrom (gouvernance des communs).
*/
interface Milestone {
num: number
name: string
icon: string
actor: string
duration: { min: string; standard: string; major: string }
description: string
essential: boolean
tip?: string
ostrom?: string
}
const milestones: Milestone[] = [
{
num: 1,
name: 'Prise d\'initiative',
icon: 'i-lucide-lightbulb',
actor: 'Tout membre',
duration: { min: '—', standard: '1-2j', major: '1-2j' },
description: 'Formaliser l\'intention : quel problème, quel besoin, quelle cible visée. Nommer un·e porteur·euse responsable.',
essential: true,
tip: 'Une initiative sans porteur identifié ne décolle pas. La responsabilité individuelle est le premier jalon.',
ostrom: 'Principe 1 — Frontières claires : qui est concerné, pourquoi.',
},
{
num: 2,
name: 'Processus d\'avis (advice)',
icon: 'i-lucide-message-circle',
actor: 'Porteur + experts + impactés',
duration: { min: '1j', standard: '3-7j', major: '7-14j' },
description: 'Consulter les personnes qui ont l\'expertise ET celles qui seront impactées. Écouter vraiment, intégrer ou expliquer pourquoi on n\'intègre pas.',
essential: true,
tip: 'Ce jalon est souvent escamoté. C\'est la principale cause d\'échec ou de résistance en implémentation.',
ostrom: 'Principe 5 — Résolution des conflits accessible et peu coûteuse.',
},
{
num: 3,
name: 'Rédaction + amendements',
icon: 'i-lucide-file-edit',
actor: 'Porteur + communauté',
duration: { min: '1-2j', standard: '3-7j', major: '7-21j' },
description: 'Rédiger la proposition formelle. Ouvrir une période d\'amendements publics. Intégrer les modifications acceptées, rejeter les autres avec justification.',
essential: true,
tip: 'Distinguer amendements substantiels (re-vote possible) et de forme (porteur décide).',
},
{
num: 4,
name: 'Qualification technique',
icon: 'i-lucide-shield-check',
actor: 'Comité technique (si applicable)',
duration: { min: '—', standard: '2-5j', major: '5-10j' },
description: 'Pour les décisions techniques : revue par les experts désignés. Évaluation de faisabilité, risques, impact. Avis formel (non bloquant, sauf veto défini).',
essential: false,
tip: 'Optionnel selon la nature de la décision. Systématique pour les Runtime Upgrades.',
},
{
num: 5,
name: 'Ouverture du vote',
icon: 'i-lucide-vote',
actor: 'Porteur + plateforme',
duration: { min: '—', standard: '1j', major: '1j' },
description: 'Publier la proposition finale. Notifier la communauté. Ouvrir la session de vote avec les paramètres définis (protocole, formule, durée).',
essential: true,
tip: 'L\'ouverture doit être annoncée à l\'avance (délai de préavis selon règlement).',
},
{
num: 6,
name: 'Phase de vote',
icon: 'i-lucide-bar-chart-2',
actor: 'Membres habilités',
duration: { min: '3j', standard: '7-14j', major: '21-30j' },
description: 'Les membres habilités votent selon le protocole. Seuil de participation minimal surveillé. Résultats intermédiaires visibles (ou non, selon le protocole).',
essential: true,
ostrom: 'Principe 3 — Choix collectifs : ceux qui sont concernés participent aux décisions.',
},
{
num: 7,
name: 'Contrôle du quorum',
icon: 'i-lucide-check-circle',
actor: 'Plateforme + porteur',
duration: { min: '—', standard: '—', major: '—' },
description: 'Vérifier que le quorum minimum est atteint avant clôture. Si non atteint : prolonger, relancer, ou annuler selon les règles préétablies.',
essential: true,
tip: 'Définir à l\'avance le quorum et la procédure si non atteint — évite les ambiguïtés.',
ostrom: 'Principe 4 — Supervision des règles par les membres.',
},
{
num: 8,
name: 'Proclamation des résultats',
icon: 'i-lucide-megaphone',
actor: 'Plateforme + porteur',
duration: { min: '—', standard: '1j', major: '1j' },
description: 'Annoncer le résultat officiel avec les chiffres détaillés (votes pour, contre, abstentions, taux participation, seuil requis). Archiver on-chain si adopté.',
essential: true,
tip: 'La transparence des résultats est aussi importante que le résultat lui-même.',
ostrom: 'Principe 8 — Gouvernance emboîtée : résultats remontés aux niveaux supérieurs.',
},
{
num: 9,
name: 'Mise en application',
icon: 'i-lucide-play-circle',
actor: 'Porteur + implémenteurs',
duration: { min: '—', standard: 'Variable', major: 'Variable' },
description: 'Planifier l\'application effective de la décision. Désigner les responsables. Fixer des jalons d\'implémentation si complexe.',
essential: true,
tip: 'Une décision adoptée mais non implémentée érode la confiance dans le processus.',
},
{
num: 10,
name: 'Suivi et accountability',
icon: 'i-lucide-activity',
actor: 'Porteur + communauté',
duration: { min: '—', standard: 'Continu', major: 'Continu' },
description: 'Rapports réguliers sur l\'avancement. Signalement des écarts. Mécanisme de remontée si la décision produit des effets inattendus.',
essential: false,
tip: 'Intégrer dans le prochain cycle de gouvernance si des ajustements s\'imposent.',
ostrom: 'Principe 4 — Surveillance continue des comportements et résultats.',
},
{
num: 11,
name: 'Rétrospective',
icon: 'i-lucide-rotate-ccw',
actor: 'Cercle concerné',
duration: { min: '—', standard: '1-2h', major: '1-2j' },
description: 'Évaluer : le processus a-t-il bien fonctionné ? La décision produit-elle les effets attendus ? Quoi améliorer pour la prochaine fois ?',
essential: false,
tip: 'La rétrospective est le moteur d\'amélioration du protocole lui-même (méta-gouvernance).',
ostrom: 'Principe 7 — Reconnaissance externe de l\'organisation par des autorités supérieures.',
},
]
const showOstrom = ref(false)
const activeDecisionType = ref<'minor' | 'standard' | 'major'>('standard')
const decisionTypes = [
{ value: 'minor', label: 'Mineur', color: 'teal' },
{ value: 'standard', label: 'Standard', color: 'accent' },
{ value: 'major', label: 'Majeur', color: 'secondary' },
]
const essentialMilestones = computed(() =>
milestones.filter(m => m.essential),
)
const optionalMilestones = computed(() =>
milestones.filter(m => !m.essential),
)
const totalDuration = computed(() => {
const type = activeDecisionType.value
const durations = {
minor: '5-10 jours',
standard: '14-30 jours',
major: '45-90 jours',
}
return durations[type]
})
</script>
<template>
<div class="wm">
<!-- Header -->
<div class="wm__header">
<h3 class="wm__title">Jalons de protocole</h3>
<p class="wm__subtitle">
11 jalons, dont 7 indispensables. Durées recommandées selon le type de décision.
</p>
</div>
<!-- Decision type selector -->
<div class="wm__type-selector">
<button
v-for="dt in decisionTypes"
:key="dt.value"
class="wm__type-btn"
:class="[
`wm__type-btn--${dt.color}`,
{ 'wm__type-btn--active': activeDecisionType === dt.value },
]"
@click="activeDecisionType = dt.value as 'minor' | 'standard' | 'major'"
>
{{ dt.label }}
</button>
<span class="wm__total-duration"> {{ totalDuration }}</span>
</div>
<!-- Essential milestones -->
<div class="wm__section">
<div class="wm__section-label">
<span class="wm__section-badge wm__section-badge--essential">7 essentiels</span>
</div>
<div class="wm__milestones">
<div
v-for="m in essentialMilestones"
:key="m.num"
class="wm__milestone wm__milestone--essential"
>
<div class="wm__milestone-left">
<div class="wm__milestone-num">{{ m.num }}</div>
<div v-if="m.num < milestones.length" class="wm__milestone-line" />
</div>
<div class="wm__milestone-icon">
<UIcon :name="m.icon" />
</div>
<div class="wm__milestone-body">
<div class="wm__milestone-head">
<span class="wm__milestone-name">{{ m.name }}</span>
<span class="wm__milestone-duration">
{{ m.duration[activeDecisionType] || '—' }}
</span>
</div>
<p class="wm__milestone-desc">{{ m.description }}</p>
<div v-if="m.tip" class="wm__milestone-tip">
<UIcon name="i-lucide-lightbulb" />
{{ m.tip }}
</div>
</div>
</div>
</div>
</div>
<!-- Optional milestones -->
<div class="wm__section">
<div class="wm__section-label">
<span class="wm__section-badge wm__section-badge--optional">4 contextuels</span>
</div>
<div class="wm__milestones">
<div
v-for="m in optionalMilestones"
:key="m.num"
class="wm__milestone wm__milestone--optional"
>
<div class="wm__milestone-left">
<div class="wm__milestone-num wm__milestone-num--optional">{{ m.num }}</div>
</div>
<div class="wm__milestone-icon wm__milestone-icon--optional">
<UIcon :name="m.icon" />
</div>
<div class="wm__milestone-body">
<div class="wm__milestone-head">
<span class="wm__milestone-name">{{ m.name }}</span>
<span class="wm__milestone-duration">
{{ m.duration[activeDecisionType] || '—' }}
</span>
</div>
<p class="wm__milestone-desc">{{ m.description }}</p>
</div>
</div>
</div>
</div>
<!-- Ostrom toggle -->
<button class="wm__ostrom-toggle" @click="showOstrom = !showOstrom">
<UIcon name="i-lucide-book-open" />
<span>Principes Ostrom appliqués</span>
<UIcon :name="showOstrom ? 'i-lucide-chevron-up' : 'i-lucide-chevron-down'" />
</button>
<Transition name="expand">
<div v-if="showOstrom" class="wm__ostrom">
<p class="wm__ostrom-intro">
Elinor Ostrom (Nobel 2009) a identifié 8 principes pour la gouvernance
durable des communs. Les jalons ci-dessus les incarnent.
</p>
<div class="wm__ostrom-items">
<div
v-for="m in milestones.filter(x => x.ostrom)"
:key="m.num"
class="wm__ostrom-item"
>
<span class="wm__ostrom-jalon">Jalon {{ m.num }}</span>
<span class="wm__ostrom-text">{{ m.ostrom }}</span>
</div>
</div>
</div>
</Transition>
</div>
</template>
<style scoped>
.wm { display: flex; flex-direction: column; gap: 1rem; }
.wm__header { display: flex; flex-direction: column; gap: 0.25rem; }
.wm__title {
font-size: 1rem;
font-weight: 800;
color: var(--mood-text);
margin: 0;
}
.wm__subtitle {
font-size: 0.8125rem;
color: var(--mood-text-muted);
margin: 0;
line-height: 1.5;
}
/* Type selector */
.wm__type-selector {
display: flex;
align-items: center;
gap: 0.375rem;
flex-wrap: wrap;
}
.wm__type-btn {
padding: 0.375rem 0.875rem;
font-size: 0.75rem;
font-weight: 700;
border-radius: 20px;
cursor: pointer;
background: var(--mood-accent-soft);
color: var(--mood-text-muted);
transition: all 0.12s ease;
}
.wm__type-btn--accent.wm__type-btn--active {
background: var(--mood-accent);
color: var(--mood-accent-text);
}
.wm__type-btn--teal.wm__type-btn--active {
background: color-mix(in srgb, var(--mood-success) 20%, transparent);
color: var(--mood-success);
}
.wm__type-btn--secondary.wm__type-btn--active {
background: color-mix(in srgb, var(--mood-secondary, var(--mood-accent)) 20%, transparent);
color: var(--mood-secondary, var(--mood-accent));
}
.wm__total-duration {
font-size: 0.6875rem;
font-weight: 600;
color: var(--mood-text-muted);
margin-left: auto;
}
/* Section */
.wm__section { display: flex; flex-direction: column; gap: 0.5rem; }
.wm__section-label { display: flex; align-items: center; gap: 0.5rem; }
.wm__section-badge {
font-size: 0.6875rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.06em;
padding: 2px 10px;
border-radius: 20px;
}
.wm__section-badge--essential {
background: var(--mood-accent-soft);
color: var(--mood-accent);
}
.wm__section-badge--optional {
background: color-mix(in srgb, var(--mood-text-muted) 12%, transparent);
color: var(--mood-text-muted);
}
/* Milestones */
.wm__milestones { display: flex; flex-direction: column; gap: 0; }
.wm__milestone {
display: flex;
align-items: flex-start;
gap: 0.625rem;
padding: 0.5rem 0;
}
.wm__milestone-left {
display: flex;
flex-direction: column;
align-items: center;
flex-shrink: 0;
width: 1.375rem;
}
.wm__milestone-num {
width: 1.375rem;
height: 1.375rem;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
background: var(--mood-accent);
color: var(--mood-accent-text);
font-size: 0.625rem;
font-weight: 800;
flex-shrink: 0;
z-index: 1;
}
.wm__milestone-num--optional {
background: color-mix(in srgb, var(--mood-text-muted) 20%, transparent);
color: var(--mood-text-muted);
}
.wm__milestone-line {
width: 2px;
flex: 1;
min-height: 1.25rem;
background: color-mix(in srgb, var(--mood-accent) 20%, transparent);
margin-top: 2px;
}
.wm__milestone-icon {
width: 1.75rem;
height: 1.75rem;
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
border-radius: 8px;
background: var(--mood-accent-soft);
color: var(--mood-accent);
font-size: 0.875rem;
}
.wm__milestone-icon--optional {
background: color-mix(in srgb, var(--mood-text-muted) 10%, transparent);
color: var(--mood-text-muted);
}
.wm__milestone-body {
flex: 1;
min-width: 0;
padding-bottom: 0.625rem;
}
.wm__milestone-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 0.5rem;
flex-wrap: wrap;
}
.wm__milestone-name {
font-size: 0.8125rem;
font-weight: 700;
color: var(--mood-text);
}
.wm__milestone--optional .wm__milestone-name {
color: var(--mood-text-muted);
}
.wm__milestone-duration {
font-size: 0.625rem;
font-weight: 600;
font-family: ui-monospace, SFMono-Regular, monospace;
color: var(--mood-accent);
background: var(--mood-accent-soft);
padding: 1px 6px;
border-radius: 20px;
}
.wm__milestone-desc {
font-size: 0.75rem;
color: var(--mood-text-muted);
line-height: 1.5;
margin: 0.125rem 0 0;
}
.wm__milestone-tip {
display: flex;
align-items: flex-start;
gap: 0.375rem;
margin-top: 0.375rem;
padding: 0.375rem 0.5rem;
background: color-mix(in srgb, var(--mood-accent) 8%, transparent);
border-radius: 8px;
font-size: 0.6875rem;
color: var(--mood-accent);
line-height: 1.5;
}
/* Ostrom */
.wm__ostrom-toggle {
display: flex;
align-items: center;
gap: 0.5rem;
width: 100%;
padding: 0.625rem 0.75rem;
background: var(--mood-accent-soft);
border-radius: 10px;
cursor: pointer;
font-size: 0.8125rem;
font-weight: 600;
color: var(--mood-text-muted);
transition: color 0.12s ease;
text-align: left;
}
.wm__ostrom-toggle:hover { color: var(--mood-text); }
.wm__ostrom-toggle .i-lucide-book-open { color: var(--mood-accent); }
.wm__ostrom {
background: var(--mood-accent-soft);
border-radius: 12px;
padding: 0.875rem;
display: flex;
flex-direction: column;
gap: 0.75rem;
}
.wm__ostrom-intro {
font-size: 0.75rem;
color: var(--mood-text-muted);
line-height: 1.6;
margin: 0;
}
.wm__ostrom-items {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.wm__ostrom-item {
display: flex;
gap: 0.625rem;
font-size: 0.75rem;
line-height: 1.5;
}
.wm__ostrom-jalon {
font-weight: 700;
color: var(--mood-accent);
white-space: nowrap;
flex-shrink: 0;
}
.wm__ostrom-text { color: var(--mood-text-muted); }
/* Expand transition */
.expand-enter-active, .expand-leave-active { transition: all 0.2s ease; overflow: hidden; }
.expand-enter-from, .expand-leave-to { max-height: 0; opacity: 0; }
.expand-enter-to, .expand-leave-from { max-height: 1000px; opacity: 1; }
</style>