Skip to main content

systemprompt_models/profile/
retention.rs

1//! How long the high-volume operational tables keep their rows.
2//!
3//! One place, on the profile, for every retention window the scheduler's
4//! `database_cleanup` job enforces. Every field has a default, so a profile
5//! that says nothing gets bounded tables; a profile that names a window gets
6//! exactly that window. Days, never "forever": a table with no deletion
7//! path is how a self-hosted instance ran out of memory rebuilding its
8//! analytics baseline.
9//!
10//! Copyright (c) systemprompt.io — Business Source License 1.1.
11//! See <https://systemprompt.io> for licensing details.
12
13use serde::{Deserialize, Serialize};
14
15/// Retention windows, in days, for the high-volume operational tables.
16///
17/// Each field names the table it bounds and rows older than the window are
18/// deleted, with two exceptions worth knowing:
19///
20/// - `ai_request_messages_days` drops the stored messages and keeps the request
21///   row; `None` follows `ai.history.retention_days` from the services
22///   configuration instead.
23/// - `ai_request_payload_raw_days` sets the raw request and response bodies on
24///   `ai_request_payloads` to NULL rather than deleting the row; the excerpts,
25///   hashes and sizes stay.
26#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
27#[serde(deny_unknown_fields)]
28#[expect(
29    clippy::struct_field_names,
30    reason = "every field is a window in days; the unit belongs in the name"
31)]
32pub struct RetentionConfig {
33    #[serde(default = "default_logs_days")]
34    pub logs_days: u32,
35    #[serde(default = "default_analytics_events_days")]
36    pub analytics_events_days: u32,
37    #[serde(default)]
38    pub ai_request_messages_days: Option<u32>,
39    #[serde(default = "default_mcp_tool_executions_days")]
40    pub mcp_tool_executions_days: u32,
41    #[serde(default = "default_outbox_processed_days")]
42    pub outbox_processed_days: u32,
43    #[serde(default = "default_ai_request_payload_raw_days")]
44    pub ai_request_payload_raw_days: u32,
45    #[serde(default = "default_governance_decisions_days")]
46    pub governance_decisions_days: u32,
47}
48
49impl Default for RetentionConfig {
50    fn default() -> Self {
51        Self {
52            logs_days: default_logs_days(),
53            analytics_events_days: default_analytics_events_days(),
54            ai_request_messages_days: None,
55            mcp_tool_executions_days: default_mcp_tool_executions_days(),
56            outbox_processed_days: default_outbox_processed_days(),
57            ai_request_payload_raw_days: default_ai_request_payload_raw_days(),
58            governance_decisions_days: default_governance_decisions_days(),
59        }
60    }
61}
62
63const fn default_logs_days() -> u32 {
64    30
65}
66
67const fn default_analytics_events_days() -> u32 {
68    90
69}
70
71const fn default_mcp_tool_executions_days() -> u32 {
72    365
73}
74
75const fn default_outbox_processed_days() -> u32 {
76    7
77}
78
79const fn default_ai_request_payload_raw_days() -> u32 {
80    7
81}
82
83const fn default_governance_decisions_days() -> u32 {
84    180
85}