Files
WhispAssist/src-tauri/src/storage/mod.rs
T
iamdoubz 02834e9cd2 Phase 1
2026-06-30 22:17:30 -05:00

81 lines
3.0 KiB
Rust

//! Storage service (Phase 2, FR-STORE-*, FR-REL-*). SQLite index + on-disk
//! audio/transcript/notes files (ADR-0006). Async via sqlx.
//!
//! Invariant: audio is the source of truth. Derived artifacts (transcript/notes/
//! summary) are regenerable; retention never touches an in-progress meeting.
use crate::models::{MeetingId, MeetingListItem};
use async_trait::async_trait;
#[derive(Debug, thiserror::Error)]
pub enum StoreError {
#[error("db error: {0}")]
Db(String),
#[error("io error: {0}")]
Io(#[from] std::io::Error),
#[error("not found: {0}")]
NotFound(String),
}
pub struct NewMeeting {
pub title: String,
pub calendar_event_id: Option<String>,
}
pub struct Retention {
pub max_age_days: Option<u32>,
pub max_size_gb: Option<u32>,
}
#[async_trait]
pub trait Store: Send + Sync {
async fn create_meeting(&self, m: NewMeeting) -> Result<MeetingId, StoreError>;
async fn finalize_meeting(&self, id: &MeetingId) -> Result<(), StoreError>;
async fn list_meetings(
&self,
query: Option<String>,
) -> Result<Vec<MeetingListItem>, StoreError>;
async fn delete_meeting(&self, id: &MeetingId) -> Result<(), StoreError>;
async fn update_notes(&self, id: &MeetingId, markdown: &str) -> Result<(), StoreError>;
/// Full-text search across transcripts + notes (Phase 8, FR-SEARCH-1).
async fn search(&self, query: &str) -> Result<Vec<MeetingListItem>, StoreError>;
/// Startup reconcile: meetings with audio but no finalized transcript (FR-REL-1).
async fn recover_scan(&self) -> Result<Vec<MeetingId>, StoreError>;
/// Enforce retention; returns count removed. Skips in-progress meetings.
async fn enforce_retention(&self, policy: Retention) -> Result<u32, StoreError>;
}
/// SQLite-backed store. Migrations live in `migrations/` (sqlx::migrate!).
pub struct SqliteStore;
#[async_trait]
impl Store for SqliteStore {
async fn create_meeting(&self, _m: NewMeeting) -> Result<MeetingId, StoreError> {
todo!("Phase 2 — create meeting row + folder")
}
async fn finalize_meeting(&self, _id: &MeetingId) -> Result<(), StoreError> {
todo!("Phase 2 — persist transcript.json + metadata")
}
async fn list_meetings(
&self,
_query: Option<String>,
) -> Result<Vec<MeetingListItem>, StoreError> {
todo!("Phase 2 — list meetings")
}
async fn delete_meeting(&self, _id: &MeetingId) -> Result<(), StoreError> {
todo!("Phase 2 — delete meeting + folder")
}
async fn update_notes(&self, _id: &MeetingId, _markdown: &str) -> Result<(), StoreError> {
todo!("Phase 2 — write notes.md + FTS")
}
async fn search(&self, _query: &str) -> Result<Vec<MeetingListItem>, StoreError> {
todo!("Phase 8 — FTS5 search")
}
async fn recover_scan(&self) -> Result<Vec<MeetingId>, StoreError> {
todo!("Phase 2 — recovery scan")
}
async fn enforce_retention(&self, _policy: Retention) -> Result<u32, StoreError> {
todo!("Phase 2 — retention enforcement")
}
}