ccboard_types/analytics/
mod.rs1use chrono::{DateTime, Utc};
7use std::sync::Arc;
8
9use crate::models::session::SessionMetadata;
10
11pub mod anomalies;
12pub mod forecasting;
13pub mod insights;
14pub mod patterns;
15pub mod trends;
16
17pub use anomalies::{detect_anomalies, Anomaly, AnomalyMetric, AnomalySeverity};
21pub use forecasting::{forecast_usage, ForecastData, TrendDirection};
22pub use insights::{generate_budget_alerts, generate_insights, Alert};
23pub use patterns::{detect_patterns, UsagePatterns};
24pub use trends::{compute_trends, SessionDurationStats, TrendsData};
25
26#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
28pub enum Period {
29 Days(usize),
31 Available,
33}
34
35impl Period {
36 pub fn last_7d() -> Self {
38 Self::Days(7)
39 }
40
41 pub fn last_30d() -> Self {
43 Self::Days(30)
44 }
45
46 pub fn last_90d() -> Self {
48 Self::Days(90)
49 }
50
51 pub fn available() -> Self {
53 Self::Available
54 }
55
56 pub fn days(&self) -> usize {
58 match self {
59 Period::Days(n) => *n,
60 Period::Available => 36500, }
62 }
63
64 pub fn display(&self, total_loaded: usize) -> String {
66 match self {
67 Period::Days(n) => format!("Last {} days", n),
68 Period::Available => format!("All loaded ({} sessions)", total_loaded),
69 }
70 }
71}
72
73#[derive(Debug, Clone)]
75pub struct AnalyticsData {
76 pub trends: TrendsData,
78 pub forecast: ForecastData,
80 pub patterns: UsagePatterns,
82 pub insights: Vec<String>,
84 pub computed_at: DateTime<Utc>,
86 pub period: Period,
88}
89
90impl AnalyticsData {
91 pub fn compute(sessions: &[Arc<SessionMetadata>], period: Period) -> Self {
99 let trends = compute_trends(sessions, period.days());
100 let forecast = forecast_usage(&trends);
101 let patterns = detect_patterns(sessions, period.days());
102 let insights = generate_insights(&trends, &patterns, &forecast);
103
104 Self {
105 trends,
106 forecast,
107 patterns,
108 insights,
109 computed_at: Utc::now(),
110 period,
111 }
112 }
113
114 pub fn from_sessions_only(sessions: &[Arc<SessionMetadata>], period: Period) -> Self {
119 Self {
122 trends: compute_trends(sessions, period.days()),
123 forecast: ForecastData::unavailable("Stats cache required for cost forecasting"),
124 patterns: detect_patterns(sessions, period.days()),
125 insights: vec!["Limited insights: stats cache unavailable".to_string()],
126 computed_at: Utc::now(),
127 period,
128 }
129 }
130}