//! Monthly review domain types. use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use crate::id_types::{MonthlyGoalId, MonthlyReflectionId, UserId}; // ============ Monthly Goal ============ /// Status of a monthly goal. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "lowercase")] pub enum MonthlyGoalStatus { Active, Done, Abandoned, } impl MonthlyGoalStatus { pub fn as_str(&self) -> &str { match self { Self::Active => "active", Self::Done => "done", Self::Abandoned => "abandoned", } } } impl std::str::FromStr for MonthlyGoalStatus { type Err = crate::CoreError; fn from_str(s: &str) -> std::result::Result { match s { "active" => Ok(Self::Active), "done" => Ok(Self::Done), "abandoned" => Ok(Self::Abandoned), _ => Err(crate::CoreError::parse(format!("Invalid goal status: {s}"))), } } } /// A monthly goal — free-text item set at the start of each month. #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct MonthlyGoal { pub id: MonthlyGoalId, pub user_id: UserId, /// Month in YYYY-MM format. pub month: String, pub text: String, pub status: MonthlyGoalStatus, /// Position 1-3. pub position: i32, pub created_at: DateTime, pub updated_at: DateTime, } // ============ Monthly Reflection ============ /// A monthly reflection capturing highlights and areas for improvement. #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct MonthlyReflection { pub id: MonthlyReflectionId, pub user_id: UserId, /// Month in YYYY-MM format. pub month: String, pub highlight_text: String, pub change_text: String, pub completed_at: DateTime, }