Skip to main content

systemprompt_models/events/
analytics_event.rs

1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, Serialize, Deserialize)]
5#[serde(tag = "type", rename_all = "SCREAMING_SNAKE_CASE")]
6pub enum AnalyticsEvent {
7    SessionStarted {
8        timestamp: DateTime<Utc>,
9        #[serde(flatten)]
10        payload: SessionStartedPayload,
11    },
12    SessionEnded {
13        timestamp: DateTime<Utc>,
14        #[serde(flatten)]
15        payload: SessionEndedPayload,
16    },
17    PageView {
18        timestamp: DateTime<Utc>,
19        #[serde(flatten)]
20        payload: PageViewPayload,
21    },
22    EngagementUpdate {
23        timestamp: DateTime<Utc>,
24        #[serde(flatten)]
25        payload: EngagementUpdatePayload,
26    },
27    RealTimeStats {
28        timestamp: DateTime<Utc>,
29        #[serde(flatten)]
30        payload: RealTimeStatsPayload,
31    },
32    Heartbeat {
33        timestamp: DateTime<Utc>,
34    },
35}
36
37impl AnalyticsEvent {
38    pub const fn timestamp(&self) -> DateTime<Utc> {
39        match self {
40            Self::SessionStarted { timestamp, .. }
41            | Self::SessionEnded { timestamp, .. }
42            | Self::PageView { timestamp, .. }
43            | Self::EngagementUpdate { timestamp, .. }
44            | Self::RealTimeStats { timestamp, .. }
45            | Self::Heartbeat { timestamp } => *timestamp,
46        }
47    }
48}
49
50#[derive(Debug, Clone, Serialize, Deserialize)]
51pub struct SessionStartedPayload {
52    pub session_id: String,
53    pub device_type: Option<String>,
54    pub browser: Option<String>,
55    pub os: Option<String>,
56    pub country: Option<String>,
57    pub referrer_source: Option<String>,
58    pub is_bot: bool,
59}
60
61#[derive(Debug, Clone, Serialize, Deserialize)]
62pub struct SessionEndedPayload {
63    pub session_id: String,
64    pub duration_ms: i64,
65    pub page_count: i64,
66    pub request_count: i64,
67}
68
69#[derive(Debug, Clone, Serialize, Deserialize)]
70pub struct PageViewPayload {
71    pub session_id: String,
72    pub user_id: Option<String>,
73    pub page_url: String,
74    pub content_id: Option<String>,
75    pub referrer: Option<String>,
76}
77
78#[derive(Debug, Clone, Serialize, Deserialize)]
79pub struct EngagementUpdatePayload {
80    pub session_id: String,
81    pub page_url: String,
82    pub scroll_depth: i32,
83    pub time_on_page_ms: i64,
84    pub click_count: i32,
85}
86
87#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
88pub struct RealTimeStatsPayload {
89    pub active_sessions: i64,
90    pub active_users: i64,
91    pub requests_per_minute: i64,
92    pub page_views_last_5m: i64,
93    pub bot_requests_last_5m: i64,
94}
95
96#[derive(Debug, Clone, Copy)]
97pub struct AnalyticsEventBuilder;
98
99impl AnalyticsEventBuilder {
100    pub fn session_started(payload: SessionStartedPayload) -> AnalyticsEvent {
101        AnalyticsEvent::SessionStarted {
102            timestamp: Utc::now(),
103            payload,
104        }
105    }
106
107    pub fn session_ended(
108        session_id: String,
109        duration_ms: i64,
110        page_count: i64,
111        request_count: i64,
112    ) -> AnalyticsEvent {
113        AnalyticsEvent::SessionEnded {
114            timestamp: Utc::now(),
115            payload: SessionEndedPayload {
116                session_id,
117                duration_ms,
118                page_count,
119                request_count,
120            },
121        }
122    }
123
124    pub fn page_view(
125        session_id: String,
126        user_id: Option<String>,
127        page_url: String,
128        content_id: Option<String>,
129        referrer: Option<String>,
130    ) -> AnalyticsEvent {
131        AnalyticsEvent::PageView {
132            timestamp: Utc::now(),
133            payload: PageViewPayload {
134                session_id,
135                user_id,
136                page_url,
137                content_id,
138                referrer,
139            },
140        }
141    }
142
143    pub fn engagement_update(
144        session_id: String,
145        page_url: String,
146        scroll_depth: i32,
147        time_on_page_ms: i64,
148        click_count: i32,
149    ) -> AnalyticsEvent {
150        AnalyticsEvent::EngagementUpdate {
151            timestamp: Utc::now(),
152            payload: EngagementUpdatePayload {
153                session_id,
154                page_url,
155                scroll_depth,
156                time_on_page_ms,
157                click_count,
158            },
159        }
160    }
161
162    pub fn realtime_stats(
163        active_sessions: i64,
164        active_users: i64,
165        requests_per_minute: i64,
166        page_views_last_5m: i64,
167        bot_requests_last_5m: i64,
168    ) -> AnalyticsEvent {
169        AnalyticsEvent::RealTimeStats {
170            timestamp: Utc::now(),
171            payload: RealTimeStatsPayload {
172                active_sessions,
173                active_users,
174                requests_per_minute,
175                page_views_last_5m,
176                bot_requests_last_5m,
177            },
178        }
179    }
180
181    pub fn heartbeat() -> AnalyticsEvent {
182        AnalyticsEvent::Heartbeat {
183            timestamp: Utc::now(),
184        }
185    }
186}