Skip to main content

systemprompt_models/admin/
mod.rs

1//! Admin-dashboard read models.
2//!
3//! Aggregate DTOs surfaced by the admin API: user metrics with trend
4//! deltas, content statistics, recent conversations, activity trends,
5//! and traffic breakdowns (browser, device, geography, bot share).
6//! These are projection types — they carry no behaviour and are never
7//! persisted directly.
8
9use chrono::{DateTime, Utc};
10use serde::{Deserialize, Serialize};
11use systemprompt_identifiers::{ContextId, UserId};
12
13#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
14#[serde(rename_all = "lowercase")]
15pub enum LogLevel {
16    Trace,
17    Debug,
18    #[default]
19    Info,
20    Warn,
21    Error,
22}
23
24impl std::fmt::Display for LogLevel {
25    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26        match self {
27            Self::Trace => write!(f, "TRACE"),
28            Self::Debug => write!(f, "DEBUG"),
29            Self::Info => write!(f, "INFO"),
30            Self::Warn => write!(f, "WARN"),
31            Self::Error => write!(f, "ERROR"),
32        }
33    }
34}
35
36#[derive(Debug, Clone, Serialize, Deserialize)]
37pub struct LogEntry {
38    pub timestamp: DateTime<Utc>,
39    pub level: LogLevel,
40    pub module: String,
41    pub message: String,
42}
43
44#[derive(Debug, Clone, Serialize, Deserialize)]
45pub struct UserInfo {
46    pub id: UserId,
47    pub name: String,
48    pub email: Option<String>,
49    pub active_sessions: i64,
50    pub last_session_at: Option<DateTime<Utc>>,
51    pub roles: Vec<String>,
52}
53
54#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
55pub struct UserMetricsWithTrends {
56    pub total_users: i64,
57    pub active_users: i64,
58    pub new_users_today: i64,
59    pub new_users_week: i64,
60    pub new_users_month: i64,
61    pub users_trend_7d: f64,
62    pub users_trend_30d: f64,
63    pub active_trend_7d: f64,
64    pub active_trend_30d: f64,
65}
66
67#[derive(Debug, Clone, Serialize, Deserialize)]
68pub struct ContentStat {
69    pub content_type: String,
70    pub count: i64,
71    pub total_size: Option<i64>,
72}
73
74#[derive(Debug, Clone, Serialize, Deserialize)]
75pub struct RecentConversation {
76    pub context_id: ContextId,
77    pub user_name: Option<String>,
78    pub message_count: i64,
79    pub last_activity: DateTime<Utc>,
80    pub agent_name: Option<String>,
81}
82
83#[derive(Debug, Clone, Serialize, Deserialize)]
84pub struct ActivityTrend {
85    pub date: String,
86    pub message_count: i64,
87    pub user_count: i64,
88    pub task_count: i64,
89}
90
91#[derive(Debug, Clone, Serialize, Deserialize)]
92pub struct BrowserBreakdown {
93    pub browser: String,
94    pub count: i64,
95    pub percentage: f64,
96}
97
98#[derive(Debug, Clone, Serialize, Deserialize)]
99pub struct DeviceBreakdown {
100    pub device_type: String,
101    pub count: i64,
102    pub percentage: f64,
103}
104
105#[derive(Debug, Clone, Serialize, Deserialize)]
106pub struct GeographicBreakdown {
107    pub country: String,
108    pub count: i64,
109    pub percentage: f64,
110}
111
112#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
113pub struct BotTrafficStats {
114    pub total_requests: i64,
115    pub bot_requests: i64,
116    pub human_requests: i64,
117    pub bot_percentage: f64,
118}
119
120#[derive(Debug, Clone, Serialize, Deserialize)]
121pub struct AnalyticsData {
122    pub user_metrics: Option<UserMetricsWithTrends>,
123    pub content_stats: Vec<ContentStat>,
124    pub recent_conversations: Vec<RecentConversation>,
125    pub activity_trends: Vec<ActivityTrend>,
126    pub traffic: Option<TrafficData>,
127}
128
129#[derive(Debug, Clone, Default, Serialize, Deserialize)]
130pub struct TrafficData {
131    pub browsers: Vec<BrowserBreakdown>,
132    pub devices: Vec<DeviceBreakdown>,
133    pub countries: Vec<GeographicBreakdown>,
134    pub bot_traffic: BotTrafficStats,
135}