Sprint 2 : moteur de documents + sanctuaire
Backend: - CRUD complet documents/items/versions (update, delete, accept, reject, reorder) - Service IPFS (upload/retrieve/pin via kubo HTTP API) - Service sanctuaire : pipeline SHA-256 + IPFS + on-chain (system.remark) - Verification integrite des entrees sanctuaire - Recherche par reference (document -> entrees sanctuaire) - Serialisation deterministe des documents pour archivage - 14 tests unitaires supplementaires (document service) Frontend: - 9 composants : StatusBadge, MarkdownRenderer, DiffView, ItemCard, ItemVersionDiff, DocumentList, SanctuaryEntry, IPFSLink, ChainAnchor - Page detail item avec historique des versions et diff - Page detail sanctuaire avec verification integrite - Modal de creation de document + proposition de version - Archivage document vers sanctuaire depuis la page detail Documentation: - API reference mise a jour (9 nouveaux endpoints) - Guides utilisateur documents et sanctuaire enrichis Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -32,6 +32,20 @@ export interface Document {
|
||||
items_count: number
|
||||
}
|
||||
|
||||
export interface ItemVersion {
|
||||
id: string
|
||||
item_id: string
|
||||
version_number: number
|
||||
proposed_text: string
|
||||
rationale: string | null
|
||||
diff: string | null
|
||||
status: string
|
||||
proposed_by: string | null
|
||||
reviewed_by: string | null
|
||||
created_at: string
|
||||
updated_at: string
|
||||
}
|
||||
|
||||
export interface DocumentCreate {
|
||||
slug: string
|
||||
title: string
|
||||
@@ -40,10 +54,16 @@ export interface DocumentCreate {
|
||||
version?: string
|
||||
}
|
||||
|
||||
export interface VersionProposal {
|
||||
proposed_text: string
|
||||
rationale?: string | null
|
||||
}
|
||||
|
||||
interface DocumentsState {
|
||||
list: Document[]
|
||||
current: Document | null
|
||||
items: DocumentItem[]
|
||||
versions: ItemVersion[]
|
||||
loading: boolean
|
||||
error: string | null
|
||||
}
|
||||
@@ -53,6 +73,7 @@ export const useDocumentsStore = defineStore('documents', {
|
||||
list: [],
|
||||
current: null,
|
||||
items: [],
|
||||
versions: [],
|
||||
loading: false,
|
||||
error: null,
|
||||
}),
|
||||
@@ -139,11 +160,122 @@ export const useDocumentsStore = defineStore('documents', {
|
||||
},
|
||||
|
||||
/**
|
||||
* Clear the current document and items.
|
||||
* Fetch all versions for a specific item within a document.
|
||||
*/
|
||||
async fetchItemVersions(slug: string, itemId: string) {
|
||||
this.loading = true
|
||||
this.error = null
|
||||
|
||||
try {
|
||||
const { $api } = useApi()
|
||||
this.versions = await $api<ItemVersion[]>(
|
||||
`/documents/${slug}/items/${itemId}/versions`,
|
||||
)
|
||||
} catch (err: any) {
|
||||
this.error = err?.data?.detail || err?.message || 'Erreur lors du chargement des versions'
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Propose a new version for a document item.
|
||||
*/
|
||||
async proposeVersion(slug: string, itemId: string, data: VersionProposal) {
|
||||
this.error = null
|
||||
|
||||
try {
|
||||
const { $api } = useApi()
|
||||
const version = await $api<ItemVersion>(
|
||||
`/documents/${slug}/items/${itemId}/versions`,
|
||||
{
|
||||
method: 'POST',
|
||||
body: data,
|
||||
},
|
||||
)
|
||||
this.versions.unshift(version)
|
||||
return version
|
||||
} catch (err: any) {
|
||||
this.error = err?.data?.detail || err?.message || 'Erreur lors de la proposition'
|
||||
throw err
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Accept a proposed version.
|
||||
*/
|
||||
async acceptVersion(slug: string, itemId: string, versionId: string) {
|
||||
this.error = null
|
||||
|
||||
try {
|
||||
const { $api } = useApi()
|
||||
const updated = await $api<ItemVersion>(
|
||||
`/documents/${slug}/items/${itemId}/versions/${versionId}/accept`,
|
||||
{ method: 'POST' },
|
||||
)
|
||||
const idx = this.versions.findIndex(v => v.id === versionId)
|
||||
if (idx >= 0) this.versions[idx] = updated
|
||||
return updated
|
||||
} catch (err: any) {
|
||||
this.error = err?.data?.detail || err?.message || 'Erreur lors de l\'acceptation'
|
||||
throw err
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Reject a proposed version.
|
||||
*/
|
||||
async rejectVersion(slug: string, itemId: string, versionId: string) {
|
||||
this.error = null
|
||||
|
||||
try {
|
||||
const { $api } = useApi()
|
||||
const updated = await $api<ItemVersion>(
|
||||
`/documents/${slug}/items/${itemId}/versions/${versionId}/reject`,
|
||||
{ method: 'POST' },
|
||||
)
|
||||
const idx = this.versions.findIndex(v => v.id === versionId)
|
||||
if (idx >= 0) this.versions[idx] = updated
|
||||
return updated
|
||||
} catch (err: any) {
|
||||
this.error = err?.data?.detail || err?.message || 'Erreur lors du rejet'
|
||||
throw err
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Archive a document into the Sanctuary.
|
||||
*/
|
||||
async archiveDocument(slug: string) {
|
||||
this.error = null
|
||||
|
||||
try {
|
||||
const { $api } = useApi()
|
||||
const doc = await $api<Document>(
|
||||
`/documents/${slug}/archive`,
|
||||
{ method: 'POST' },
|
||||
)
|
||||
// Update current if viewing this document
|
||||
if (this.current?.slug === slug) {
|
||||
this.current = doc
|
||||
}
|
||||
// Update in list
|
||||
const idx = this.list.findIndex(d => d.slug === slug)
|
||||
if (idx >= 0) this.list[idx] = doc
|
||||
return doc
|
||||
} catch (err: any) {
|
||||
this.error = err?.data?.detail || err?.message || 'Erreur lors de l\'archivage'
|
||||
throw err
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Clear the current document, items and versions.
|
||||
*/
|
||||
clearCurrent() {
|
||||
this.current = null
|
||||
this.items = []
|
||||
this.versions = []
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user