Skip to main content

ralph/productivity/
types.rs

1//! Productivity stats data structures.
2//!
3//! Responsibilities:
4//! - Define all data structures for productivity tracking (stats, streaks, milestones, reports).
5//!
6//! Not handled here:
7//! - Persistence logic (see `super::persistence`).
8//! - Calculations and business logic (see `super::calculations`).
9//! - Report formatting and display (see `super::reports`).
10
11use serde::{Deserialize, Serialize};
12use std::collections::BTreeMap;
13
14use crate::constants::versions::STATS_SCHEMA_VERSION;
15use crate::timeutil;
16
17/// Root productivity data structure
18#[derive(Debug, Clone, Serialize, Deserialize)]
19pub struct ProductivityStats {
20    /// Schema version for migrations
21    pub version: u32,
22    /// When stats were first created
23    pub first_task_completed_at: Option<String>,
24    /// Last update timestamp
25    pub last_updated_at: String,
26    /// Daily completion records (YYYY-MM-DD -> DayStats)
27    pub daily: BTreeMap<String, DayStats>,
28    /// Current streak information
29    pub streak: StreakInfo,
30    /// Total completed task counter for milestones
31    pub total_completed: u64,
32    /// Milestones achieved
33    pub milestones: Vec<Milestone>,
34}
35
36impl Default for ProductivityStats {
37    fn default() -> Self {
38        let now = timeutil::now_utc_rfc3339_or_fallback();
39        Self {
40            version: STATS_SCHEMA_VERSION,
41            first_task_completed_at: None,
42            last_updated_at: now,
43            daily: BTreeMap::new(),
44            streak: StreakInfo::default(),
45            total_completed: 0,
46            milestones: Vec::new(),
47        }
48    }
49}
50
51/// Stats for a single day
52#[derive(Debug, Clone, Serialize, Deserialize, Default)]
53pub struct DayStats {
54    pub date: String,
55    pub completed_count: u32,
56    pub tasks: Vec<CompletedTaskRef>,
57}
58
59/// Reference to a completed task
60#[derive(Debug, Clone, Serialize, Deserialize)]
61pub struct CompletedTaskRef {
62    pub id: String,
63    pub title: String,
64    pub completed_at: String,
65}
66
67/// Streak tracking information
68#[derive(Debug, Clone, Serialize, Deserialize, Default)]
69pub struct StreakInfo {
70    pub current_streak: u32,
71    pub longest_streak: u32,
72    pub last_completed_date: Option<String>,
73}
74
75/// A milestone achievement
76#[derive(Debug, Clone, Serialize, Deserialize)]
77pub struct Milestone {
78    pub threshold: u64,
79    pub achieved_at: String,
80    pub celebrated: bool,
81}
82
83/// Result of recording a task completion
84#[derive(Debug, Clone)]
85pub struct CompletionResult {
86    /// Milestone achieved (if any)
87    pub milestone_achieved: Option<u64>,
88    /// Whether streak was updated
89    pub streak_updated: bool,
90    /// New streak count
91    pub new_streak: u32,
92    /// Total completed count
93    pub total_completed: u64,
94}
95
96/// Velocity metrics for a given time period
97#[derive(Debug, Clone, Serialize, Deserialize)]
98pub struct VelocityMetrics {
99    pub days: u32,
100    pub total_completed: u32,
101    pub average_per_day: f64,
102    pub best_day: Option<(String, u32)>,
103}
104
105/// Estimation accuracy metrics for tasks with both estimated and actual minutes.
106#[derive(Debug, Clone, Serialize, Deserialize)]
107pub struct EstimationMetrics {
108    /// Number of tasks analyzed (have both estimated and actual minutes).
109    pub tasks_analyzed: u32,
110    /// Average estimation accuracy ratio (actual/estimated).
111    /// 1.0 = perfect estimation, <1.0 = overestimated, >1.0 = underestimated.
112    pub average_accuracy_ratio: f64,
113    /// Median estimation accuracy ratio.
114    pub median_accuracy_ratio: f64,
115    /// Percentage of tasks estimated within 25% of actual.
116    pub within_25_percent: f64,
117    /// Average absolute error in minutes.
118    pub average_absolute_error_minutes: f64,
119}
120
121/// Single task estimation data point.
122#[derive(Debug, Clone, Serialize, Deserialize)]
123pub struct TaskEstimationPoint {
124    pub task_id: String,
125    pub task_title: String,
126    pub estimated_minutes: u32,
127    pub actual_minutes: u32,
128    pub accuracy_ratio: f64,
129}
130
131/// Session summary for display after run loop
132#[derive(Debug, Clone)]
133pub struct SessionSummary {
134    pub tasks_completed: Vec<String>,
135    pub session_start: String,
136    pub session_duration_seconds: i64,
137}
138
139/// Productivity summary report
140#[derive(Debug, Clone, Serialize)]
141pub struct ProductivitySummaryReport {
142    pub total_completed: u64,
143    pub current_streak: u32,
144    pub longest_streak: u32,
145    pub last_completed_date: Option<String>,
146    pub next_milestone: Option<u64>,
147    pub milestones: Vec<Milestone>,
148    pub recent_completions: Vec<CompletedTaskRef>,
149}
150
151/// Productivity streak report
152#[derive(Debug, Clone, Serialize)]
153pub struct ProductivityStreakReport {
154    pub current_streak: u32,
155    pub longest_streak: u32,
156    pub last_completed_date: Option<String>,
157}
158
159/// Productivity velocity report
160#[derive(Debug, Clone, Serialize)]
161pub struct ProductivityVelocityReport {
162    pub window_days: u32,
163    pub total_completed: u32,
164    pub average_per_day: f64,
165    pub best_day: Option<(String, u32)>,
166}
167
168/// Productivity estimation report
169#[derive(Debug, Clone, Serialize)]
170pub struct ProductivityEstimationReport {
171    pub tasks_analyzed: u32,
172    pub average_accuracy_ratio: f64,
173    pub median_accuracy_ratio: f64,
174    pub within_25_percent: f64,
175    pub average_absolute_error_minutes: f64,
176}