Sprint 4 : decisions et mandats -- workflow complet + vote integration

Backend: 7 nouveaux endpoints (advance, assign, revoke, create-vote-session),
services enrichis avec creation de sessions de vote, assignation de mandataire
et revocation. 35 nouveaux tests (104 total). Frontend: store mandates, page
cadrage decisions, detail mandats, composants DecisionWorkflow, DecisionCadrage,
DecisionCard, MandateTimeline, MandateCard. Documentation mise a jour.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Yvv
2026-02-28 14:28:34 +01:00
parent cede2a585f
commit 3cb1754592
24 changed files with 3988 additions and 354 deletions

View File

@@ -39,6 +39,20 @@ export interface DecisionCreate {
voting_protocol_id?: string | null
}
export interface DecisionUpdate {
title?: string
description?: string | null
context?: string | null
decision_type?: string
voting_protocol_id?: string | null
}
export interface DecisionStepCreate {
step_type: string
title?: string | null
description?: string | null
}
interface DecisionsState {
list: Decision[]
current: Decision | null
@@ -59,10 +73,12 @@ export const useDecisionsStore = defineStore('decisions', {
return (status: string) => state.list.filter(d => d.status === status)
},
activeDecisions: (state): Decision[] => {
return state.list.filter(d => d.status === 'active' || d.status === 'in_progress')
return state.list.filter(d =>
d.status === 'qualification' || d.status === 'review' || d.status === 'voting',
)
},
completedDecisions: (state): Decision[] => {
return state.list.filter(d => d.status === 'completed' || d.status === 'closed')
return state.list.filter(d => d.status === 'executed' || d.status === 'closed')
},
},
@@ -128,6 +144,108 @@ export const useDecisionsStore = defineStore('decisions', {
}
},
/**
* Update an existing decision.
*/
async update(id: string, data: DecisionUpdate) {
this.error = null
try {
const { $api } = useApi()
const updated = await $api<Decision>(`/decisions/${id}`, {
method: 'PUT',
body: data,
})
if (this.current?.id === id) this.current = updated
const idx = this.list.findIndex(d => d.id === id)
if (idx >= 0) this.list[idx] = updated
return updated
} catch (err: any) {
this.error = err?.data?.detail || err?.message || 'Erreur lors de la mise a jour de la decision'
throw err
}
},
/**
* Delete a decision.
*/
async delete(id: string) {
this.error = null
try {
const { $api } = useApi()
await $api(`/decisions/${id}`, { method: 'DELETE' })
this.list = this.list.filter(d => d.id !== id)
if (this.current?.id === id) this.current = null
} catch (err: any) {
this.error = err?.data?.detail || err?.message || 'Erreur lors de la suppression de la decision'
throw err
}
},
/**
* Advance the decision to the next step in its workflow.
*/
async advance(id: string) {
this.error = null
try {
const { $api } = useApi()
const updated = await $api<Decision>(`/decisions/${id}/advance`, {
method: 'POST',
})
if (this.current?.id === id) this.current = updated
const idx = this.list.findIndex(d => d.id === id)
if (idx >= 0) this.list[idx] = updated
return updated
} catch (err: any) {
this.error = err?.data?.detail || err?.message || 'Erreur lors de l\'avancement de la decision'
throw err
}
},
/**
* Add a step to a decision.
*/
async addStep(id: string, step: DecisionStepCreate) {
this.error = null
try {
const { $api } = useApi()
const newStep = await $api<DecisionStep>(`/decisions/${id}/steps`, {
method: 'POST',
body: step,
})
if (this.current?.id === id) {
this.current.steps.push(newStep)
}
return newStep
} catch (err: any) {
this.error = err?.data?.detail || err?.message || 'Erreur lors de l\'ajout de l\'etape'
throw err
}
},
/**
* Create a vote session for a specific step.
*/
async createVoteSession(decisionId: string, stepId: string) {
this.error = null
try {
const { $api } = useApi()
const result = await $api<any>(`/decisions/${decisionId}/steps/${stepId}/create-vote-session`, {
method: 'POST',
})
// Refresh decision to get updated step with vote_session_id
await this.fetchById(decisionId)
return result
} catch (err: any) {
this.error = err?.data?.detail || err?.message || 'Erreur lors de la creation de la session de vote'
throw err
}
},
/**
* Clear the current decision.
*/