routa_core/models/
note.rs1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3use std::collections::HashMap;
4
5use super::task::TaskStatus;
6
7pub const SPEC_NOTE_ID: &str = "spec";
8
9#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
10#[serde(rename_all = "lowercase")]
11pub enum NoteType {
12 Spec,
13 Task,
14 General,
15}
16
17impl NoteType {
18 pub fn as_str(&self) -> &'static str {
19 match self {
20 Self::Spec => "spec",
21 Self::Task => "task",
22 Self::General => "general",
23 }
24 }
25
26 #[allow(clippy::should_implement_trait)]
27 pub fn from_str(s: &str) -> Self {
28 match s {
29 "spec" => Self::Spec,
30 "task" => Self::Task,
31 _ => Self::General,
32 }
33 }
34}
35
36#[derive(Debug, Clone, Serialize, Deserialize)]
37#[serde(rename_all = "camelCase")]
38pub struct NoteMetadata {
39 #[serde(rename = "type")]
40 pub note_type: NoteType,
41 #[serde(skip_serializing_if = "Option::is_none")]
42 pub task_status: Option<TaskStatus>,
43 #[serde(skip_serializing_if = "Option::is_none")]
44 pub assigned_agent_ids: Option<Vec<String>>,
45 #[serde(skip_serializing_if = "Option::is_none")]
46 pub parent_note_id: Option<String>,
47 #[serde(skip_serializing_if = "Option::is_none")]
48 pub linked_task_id: Option<String>,
49 #[serde(skip_serializing_if = "Option::is_none")]
50 pub custom: Option<HashMap<String, String>>,
51}
52
53impl Default for NoteMetadata {
54 fn default() -> Self {
55 Self {
56 note_type: NoteType::General,
57 task_status: None,
58 assigned_agent_ids: None,
59 parent_note_id: None,
60 linked_task_id: None,
61 custom: None,
62 }
63 }
64}
65
66#[derive(Debug, Clone, Serialize, Deserialize)]
67#[serde(rename_all = "camelCase")]
68pub struct Note {
69 pub id: String,
70 pub title: String,
71 pub content: String,
72 pub workspace_id: String,
73 #[serde(skip_serializing_if = "Option::is_none")]
75 pub session_id: Option<String>,
76 pub metadata: NoteMetadata,
77 pub created_at: DateTime<Utc>,
78 pub updated_at: DateTime<Utc>,
79}
80
81impl Note {
82 pub fn new(
83 id: String,
84 title: String,
85 content: String,
86 workspace_id: String,
87 metadata: Option<NoteMetadata>,
88 ) -> Self {
89 let now = Utc::now();
90 Self {
91 id,
92 title,
93 content,
94 workspace_id,
95 session_id: None,
96 metadata: metadata.unwrap_or_default(),
97 created_at: now,
98 updated_at: now,
99 }
100 }
101
102 pub fn new_with_session(
104 id: String,
105 title: String,
106 content: String,
107 workspace_id: String,
108 session_id: Option<String>,
109 metadata: Option<NoteMetadata>,
110 ) -> Self {
111 let now = Utc::now();
112 Self {
113 id,
114 title,
115 content,
116 workspace_id,
117 session_id,
118 metadata: metadata.unwrap_or_default(),
119 created_at: now,
120 updated_at: now,
121 }
122 }
123
124 pub fn new_spec(workspace_id: String) -> Self {
125 Self::new(
126 SPEC_NOTE_ID.to_string(),
127 "Spec".to_string(),
128 String::new(),
129 workspace_id,
130 Some(NoteMetadata {
131 note_type: NoteType::Spec,
132 ..Default::default()
133 }),
134 )
135 }
136}