//! Database models for the files table. use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use sqlx::FromRow; use utoipa::ToSchema; use uuid::Uuid; /// TranscriptEntry stored in JSONB - matches frontend TranscriptEntry #[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] #[serde(rename_all = "camelCase")] pub struct TranscriptEntry { pub id: String, pub speaker: String, pub start: f32, pub end: f32, pub text: String, pub is_final: bool, } /// File record from the database. #[derive(Debug, Clone, FromRow, Serialize, ToSchema)] #[serde(rename_all = "camelCase")] pub struct File { pub id: Uuid, pub owner_id: Uuid, pub name: String, pub description: Option, #[sqlx(json)] pub transcript: Vec, pub location: Option, pub created_at: DateTime, pub updated_at: DateTime, } /// Request payload for creating a new file. #[derive(Debug, Deserialize, ToSchema)] #[serde(rename_all = "camelCase")] pub struct CreateFileRequest { /// Name of the file (auto-generated if not provided) pub name: Option, /// Optional description pub description: Option, /// Transcript entries pub transcript: Vec, /// Storage location (e.g., s3://bucket/path) - not used yet pub location: Option, } /// Request payload for updating an existing file. #[derive(Debug, Deserialize, ToSchema)] #[serde(rename_all = "camelCase")] pub struct UpdateFileRequest { /// New name (optional) pub name: Option, /// New description (optional) pub description: Option, /// New transcript (optional) pub transcript: Option>, } /// Response for file list endpoint. #[derive(Debug, Serialize, ToSchema)] #[serde(rename_all = "camelCase")] pub struct FileListResponse { pub files: Vec, pub total: i64, } /// Summary of a file for list views (excludes full transcript). #[derive(Debug, Clone, Serialize, ToSchema)] #[serde(rename_all = "camelCase")] pub struct FileSummary { pub id: Uuid, pub name: String, pub description: Option, pub transcript_count: usize, /// Duration derived from last transcript end time pub duration: Option, pub created_at: DateTime, pub updated_at: DateTime, } impl From for FileSummary { fn from(file: File) -> Self { let duration = file .transcript .iter() .map(|t| t.end) .fold(0.0_f32, f32::max); Self { id: file.id, name: file.name, description: file.description, transcript_count: file.transcript.len(), duration: if duration > 0.0 { Some(duration) } else { None }, created_at: file.created_at, updated_at: file.updated_at, } } }