Sprint 3 : protocoles de vote et boite a outils

Backend:
- Sessions de vote : list, close, tally, threshold details, auto-expiration
- Protocoles : update, simulate, meta-gouvernance, formulas CRUD
- Service vote enrichi : close_session, get_threshold_details, nuanced breakdown
- Schemas : ThresholdDetailOut, VoteResultOut, FormulaSimulationRequest/Result
- WebSocket broadcast sur chaque vote + fermeture session
- 25 nouveaux tests (threshold details, close, nuanced, simulation)

Frontend:
- 5 composants vote : VoteBinary, VoteNuanced, ThresholdGauge, FormulaDisplay, VoteHistory
- 3 composants protocoles : ProtocolPicker, FormulaEditor, ModeParamsDisplay
- Simulateur de formules interactif (page /protocols/formulas)
- Page detail protocole (/protocols/[id])
- Composable useWebSocket (live updates)
- Composable useVoteFormula (calcul client-side reactif)
- Integration KaTeX pour rendu LaTeX des formules

Documentation:
- API reference : 8 nouveaux endpoints documentes
- Formules : tables d'inertie, parametres detailles, simulation API
- Guide vote : vote binaire/nuance, jauge, historique, simulateur, meta-gouvernance

55 tests passes (+ 1 skipped), 126 fichiers total.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Yvv
2026-02-28 13:29:31 +01:00
parent 2bdc731639
commit cede2a585f
25 changed files with 3964 additions and 188 deletions

View File

@@ -0,0 +1,64 @@
<script setup lang="ts">
/**
* Dropdown/select to pick a voting protocol.
*
* Fetches protocols from the store and renders them in a USelect
* with protocol name, mode params, and vote type badge.
*/
import type { VotingProtocol } from '~/stores/protocols'
const props = defineProps<{
modelValue: string | null
voteType?: string
}>()
const emit = defineEmits<{
'update:modelValue': [value: string | null]
}>()
const protocols = useProtocolsStore()
onMounted(async () => {
if (protocols.protocols.length === 0) {
await protocols.fetchProtocols(props.voteType ? { vote_type: props.voteType } : undefined)
}
})
const filteredProtocols = computed(() => {
if (!props.voteType) return protocols.protocols
return protocols.protocols.filter(p => p.vote_type === props.voteType)
})
const options = computed(() => {
return filteredProtocols.value.map(p => ({
label: buildLabel(p),
value: p.id,
}))
})
function buildLabel(p: VotingProtocol): string {
const typeLabel = p.vote_type === 'binary' ? 'Binaire' : 'Nuance'
const params = p.mode_params ? ` [${p.mode_params}]` : ''
return `${p.name} - ${typeLabel}${params}`
}
function onSelect(value: string) {
emit('update:modelValue', value || null)
}
</script>
<template>
<div>
<USelect
:model-value="modelValue ?? undefined"
:items="options"
placeholder="Selectionnez un protocole..."
:loading="protocols.loading"
value-key="value"
@update:model-value="onSelect"
/>
<p v-if="protocols.error" class="text-xs text-red-500 mt-1">
{{ protocols.error }}
</p>
</div>
</template>