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:
149
frontend/app/stores/documents.ts
Normal file
149
frontend/app/stores/documents.ts
Normal file
@@ -0,0 +1,149 @@
|
||||
/**
|
||||
* Documents store: reference documents, their items, and item versions.
|
||||
*
|
||||
* Maps to the backend /api/v1/documents endpoints.
|
||||
*/
|
||||
|
||||
export interface DocumentItem {
|
||||
id: string
|
||||
document_id: string
|
||||
position: string
|
||||
item_type: string
|
||||
title: string | null
|
||||
current_text: string
|
||||
voting_protocol_id: string | null
|
||||
sort_order: number
|
||||
created_at: string
|
||||
updated_at: string
|
||||
}
|
||||
|
||||
export interface Document {
|
||||
id: string
|
||||
slug: string
|
||||
title: string
|
||||
doc_type: string
|
||||
version: string
|
||||
status: string
|
||||
description: string | null
|
||||
ipfs_cid: string | null
|
||||
chain_anchor: string | null
|
||||
created_at: string
|
||||
updated_at: string
|
||||
items_count: number
|
||||
}
|
||||
|
||||
export interface DocumentCreate {
|
||||
slug: string
|
||||
title: string
|
||||
doc_type: string
|
||||
description?: string | null
|
||||
version?: string
|
||||
}
|
||||
|
||||
interface DocumentsState {
|
||||
list: Document[]
|
||||
current: Document | null
|
||||
items: DocumentItem[]
|
||||
loading: boolean
|
||||
error: string | null
|
||||
}
|
||||
|
||||
export const useDocumentsStore = defineStore('documents', {
|
||||
state: (): DocumentsState => ({
|
||||
list: [],
|
||||
current: null,
|
||||
items: [],
|
||||
loading: false,
|
||||
error: null,
|
||||
}),
|
||||
|
||||
getters: {
|
||||
byType: (state) => {
|
||||
return (docType: string) => state.list.filter(d => d.doc_type === docType)
|
||||
},
|
||||
activeDocuments: (state): Document[] => {
|
||||
return state.list.filter(d => d.status === 'active')
|
||||
},
|
||||
draftDocuments: (state): Document[] => {
|
||||
return state.list.filter(d => d.status === 'draft')
|
||||
},
|
||||
},
|
||||
|
||||
actions: {
|
||||
/**
|
||||
* Fetch all documents with optional filters.
|
||||
*/
|
||||
async fetchAll(params?: { doc_type?: string; status?: string }) {
|
||||
this.loading = true
|
||||
this.error = null
|
||||
|
||||
try {
|
||||
const { $api } = useApi()
|
||||
const query: Record<string, string> = {}
|
||||
if (params?.doc_type) query.doc_type = params.doc_type
|
||||
if (params?.status) query.status = params.status
|
||||
|
||||
this.list = await $api<Document[]>('/documents/', { query })
|
||||
} catch (err: any) {
|
||||
this.error = err?.data?.detail || err?.message || 'Erreur lors du chargement des documents'
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Fetch a single document by slug and its items.
|
||||
*/
|
||||
async fetchBySlug(slug: string) {
|
||||
this.loading = true
|
||||
this.error = null
|
||||
|
||||
try {
|
||||
const { $api } = useApi()
|
||||
|
||||
const [doc, items] = await Promise.all([
|
||||
$api<Document>(`/documents/${slug}`),
|
||||
$api<DocumentItem[]>(`/documents/${slug}/items`),
|
||||
])
|
||||
|
||||
this.current = doc
|
||||
this.items = items
|
||||
} catch (err: any) {
|
||||
this.error = err?.data?.detail || err?.message || 'Document introuvable'
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Create a new reference document.
|
||||
*/
|
||||
async createDocument(payload: DocumentCreate) {
|
||||
this.loading = true
|
||||
this.error = null
|
||||
|
||||
try {
|
||||
const { $api } = useApi()
|
||||
const doc = await $api<Document>('/documents/', {
|
||||
method: 'POST',
|
||||
body: payload,
|
||||
})
|
||||
this.list.unshift(doc)
|
||||
return doc
|
||||
} catch (err: any) {
|
||||
this.error = err?.data?.detail || err?.message || 'Erreur lors de la creation du document'
|
||||
throw err
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Clear the current document and items.
|
||||
*/
|
||||
clearCurrent() {
|
||||
this.current = null
|
||||
this.items = []
|
||||
},
|
||||
},
|
||||
})
|
||||
Reference in New Issue
Block a user