gradatum-vault 0.4.3

Multi-vault registry + lifecycle (create/list/swap/delete) + forward-compat
Documentation
//! Historique des versions d'une note — `NoteHistoryEntry`.
//!
//! `NoteHistoryEntry` représente une transition atomique entre deux versions.
//! Le champ `diff_text` est actuellement toujours une chaîne vide — le diff unifié
//! (représentation textuelle des changements entre deux versions) sera calculé
//! via la lib `similar` (diff Myers) dans une version future.
//!
//! L'historique CoW est stocké dans `.history/<note_id>/<ts_ms>.md` sur disque.
//! Persistance SQL dans une table dédiée `note_history` est différée.

use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use ulid::Ulid;

use gradatum_core::author::AuthorRef;
use gradatum_core::identity::{NoteId, NoteVersion};

/// Entrée d'historique pour une version d'une note.
///
/// Représente une transition atomique entre deux versions d'une note.
/// Le diff unifié et la persistance SQL sont différés.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NoteHistoryEntry {
    /// Identifiant de la note concernée.
    pub note_id: NoteId,

    /// Version avant la transition.
    pub from_version: NoteVersion,

    /// Version après la transition.
    pub to_version: NoteVersion,

    /// Diff textuel unifié entre les deux versions.
    ///
    /// Actuellement toujours chaîne vide `""`.
    /// Le diff format unifié via `similar::TextDiff` est différé.
    pub diff_text: String,

    /// Timestamp de la transition.
    pub committed_at: DateTime<Utc>,

    /// Auteur de la transition (humain, agent, système).
    pub committed_by: AuthorRef,

    /// Message décrivant le changement (optionnel).
    ///
    /// Analogue au commit message Git.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub commit_message: Option<String>,

    /// Identifiant de corrélation pour tracer les opérations multi-notes.
    ///
    /// Utile pour corréler une session d'édition batch ou un import massif.
    /// Identifiant de corrélation — `None` si non renseigné.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub correlation_id: Option<Ulid>,
}

impl NoteHistoryEntry {
    /// Crée une entrée d'historique (diff vide, pas de correlation_id).
    pub fn new(
        note_id: NoteId,
        from_version: NoteVersion,
        to_version: NoteVersion,
        committed_by: AuthorRef,
        commit_message: Option<String>,
    ) -> Self {
        Self {
            note_id,
            from_version,
            to_version,
            diff_text: String::new(),
            committed_at: Utc::now(),
            committed_by,
            commit_message,
            correlation_id: None,
        }
    }
}