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