Skip to main content

ferro_notifications/channels/
in_app.rs

1//! In-app SSE notification channel.
2
3use serde::{Deserialize, Serialize};
4
5/// Severity hint for in-app notification rendering.
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
7#[serde(rename_all = "lowercase")]
8pub enum InAppSeverity {
9    /// Informational notice.
10    Info,
11    /// Success notice.
12    Success,
13    /// Warning notice.
14    Warning,
15    /// Error notice.
16    Error,
17}
18
19/// An in-app notification message.
20///
21/// Persisted via `DatabaseNotificationStore` and broadcast via `Broadcaster`
22/// per CONTEXT.md D-08 (DB-store leg first, broadcast leg second).
23#[derive(Debug, Clone, Serialize, Deserialize)]
24pub struct InAppMessage {
25    /// Notification type identifier (e.g. "OrderShipped").
26    pub notification_type: String,
27    /// Free-form payload (broadcast as-is to the SSE channel).
28    pub data: serde_json::Value,
29    /// Optional severity hint for client-side rendering.
30    pub severity: Option<InAppSeverity>,
31}
32
33impl InAppMessage {
34    /// Create a new in-app message with the given type. Data defaults to `null`, severity to `None`.
35    pub fn new(notification_type: impl Into<String>) -> Self {
36        Self {
37            notification_type: notification_type.into(),
38            data: serde_json::Value::Null,
39            severity: None,
40        }
41    }
42
43    /// Set the data payload.
44    pub fn data(mut self, data: serde_json::Value) -> Self {
45        self.data = data;
46        self
47    }
48
49    /// Set the severity hint.
50    pub fn severity(mut self, level: InAppSeverity) -> Self {
51        self.severity = Some(level);
52        self
53    }
54}
55
56#[cfg(test)]
57mod tests {
58    use super::*;
59
60    #[test]
61    fn test_in_app_message_builder() {
62        let msg = InAppMessage::new("OrderShipped")
63            .data(serde_json::json!({"order_id": 42}))
64            .severity(InAppSeverity::Success);
65        assert_eq!(msg.notification_type, "OrderShipped");
66        assert_eq!(msg.data, serde_json::json!({"order_id": 42}));
67        assert_eq!(msg.severity, Some(InAppSeverity::Success));
68    }
69
70    #[test]
71    fn test_in_app_severity_serialization() {
72        for (level, expected) in &[
73            (InAppSeverity::Info, "\"info\""),
74            (InAppSeverity::Success, "\"success\""),
75            (InAppSeverity::Warning, "\"warning\""),
76            (InAppSeverity::Error, "\"error\""),
77        ] {
78            let json = serde_json::to_string(level).unwrap();
79            assert_eq!(&json, expected);
80        }
81    }
82}