systemprompt_analytics/models/
engagement.rs1use chrono::{DateTime, Utc};
7use serde::{Deserialize, Serialize};
8use sqlx::FromRow;
9use systemprompt_identifiers::{ContentId, EngagementEventId, SessionId, UserId};
10
11#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
12pub struct EngagementEvent {
13 pub id: EngagementEventId,
14 pub session_id: SessionId,
15 pub user_id: UserId,
16 pub page_url: String,
17 pub content_id: Option<ContentId>,
18 pub event_type: String,
19 pub time_on_page_ms: i32,
20 pub time_to_first_interaction_ms: Option<i32>,
21 pub time_to_first_scroll_ms: Option<i32>,
22 pub max_scroll_depth: i32,
23 pub scroll_velocity_avg: Option<f32>,
24 pub scroll_direction_changes: Option<i32>,
25 pub click_count: i32,
26 pub mouse_move_distance_px: Option<i32>,
27 pub keyboard_events: Option<i32>,
28 pub copy_events: Option<i32>,
29 pub focus_time_ms: i32,
30 pub blur_count: i32,
31 pub tab_switches: i32,
32 pub visible_time_ms: i32,
33 pub hidden_time_ms: i32,
34 pub is_rage_click: Option<bool>,
35 pub is_dead_click: Option<bool>,
36 pub reading_pattern: Option<String>,
37 pub created_at: DateTime<Utc>,
38 pub updated_at: DateTime<Utc>,
39}
40
41#[derive(Debug, Clone, Deserialize)]
42#[serde(default)]
43pub struct CreateEngagementEventInput {
44 #[serde(default)]
45 pub page_url: String,
46 #[serde(default = "default_event_type")]
47 pub event_type: String,
48 #[serde(default)]
49 pub time_on_page_ms: i32,
50 #[serde(default)]
51 pub max_scroll_depth: i32,
52 #[serde(default)]
53 pub click_count: i32,
54 #[serde(default)]
55 pub event_data: Option<serde_json::Value>,
56 #[serde(flatten)]
57 pub optional_metrics: EngagementOptionalMetrics,
58}
59
60impl Default for CreateEngagementEventInput {
61 fn default() -> Self {
62 Self {
63 page_url: String::new(),
64 event_type: default_event_type(),
65 time_on_page_ms: 0,
66 max_scroll_depth: 0,
67 click_count: 0,
68 event_data: None,
69 optional_metrics: EngagementOptionalMetrics::default(),
70 }
71 }
72}
73
74#[derive(Debug, Clone, Default, Deserialize)]
75pub struct EngagementOptionalMetrics {
76 pub time_to_first_interaction_ms: Option<i32>,
77 pub time_to_first_scroll_ms: Option<i32>,
78 pub scroll_velocity_avg: Option<f32>,
79 pub scroll_direction_changes: Option<i32>,
80 pub mouse_move_distance_px: Option<i32>,
81 pub keyboard_events: Option<i32>,
82 pub copy_events: Option<i32>,
83 pub focus_time_ms: Option<i32>,
84 pub blur_count: Option<i32>,
85 pub tab_switches: Option<i32>,
86 pub visible_time_ms: Option<i32>,
87 pub hidden_time_ms: Option<i32>,
88 pub is_rage_click: Option<bool>,
89 pub is_dead_click: Option<bool>,
90 pub reading_pattern: Option<String>,
91}
92
93fn default_event_type() -> String {
94 "page_exit".to_owned()
95}