data_modelling_sdk/models/
domain.rs

1//! Business Domain schema models
2//!
3//! Defines structures for organizing systems, CADS nodes, and ODCS nodes within business domains.
4
5use super::cads::CADSKind;
6use super::enums::InfrastructureType;
7use super::table::{ContactDetails, SlaProperty};
8use chrono::{DateTime, Utc};
9use serde::{Deserialize, Serialize};
10use std::collections::HashMap;
11use uuid::Uuid;
12
13/// Cardinality for Crowsfeet notation relationships between ODCS nodes
14#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
15#[serde(rename_all = "PascalCase")]
16pub enum CrowsfeetCardinality {
17    /// One-to-one relationship (1:1)
18    OneToOne,
19    /// One-to-many relationship (1:N)
20    OneToMany,
21    /// Zero-or-one relationship (0:1)
22    ZeroOrOne,
23    /// Zero-or-many relationship (0:N)
24    ZeroOrMany,
25}
26
27/// System - Physical infrastructure entity
28///
29/// Systems are physical entities like Kafka, Cassandra, EKS, EC2, etc.
30/// They inherit DataFlow node metadata (owner, SLA, contact_details, infrastructure_type, notes).
31#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
32pub struct System {
33    /// Unique identifier
34    pub id: Uuid,
35    /// System name
36    pub name: String,
37    /// Infrastructure type (Kafka, Cassandra, EKS, EC2, etc.)
38    pub infrastructure_type: InfrastructureType,
39    /// Parent domain ID
40    pub domain_id: Uuid,
41    /// System description
42    #[serde(skip_serializing_if = "Option::is_none")]
43    pub description: Option<String>,
44    /// System endpoints
45    #[serde(default)]
46    pub endpoints: Vec<String>,
47    /// Owner (from DataFlow metadata)
48    #[serde(skip_serializing_if = "Option::is_none")]
49    pub owner: Option<String>,
50    /// SLA properties (from DataFlow metadata)
51    #[serde(skip_serializing_if = "Option::is_none")]
52    pub sla: Option<Vec<SlaProperty>>,
53    /// Contact details (from DataFlow metadata)
54    #[serde(skip_serializing_if = "Option::is_none")]
55    pub contact_details: Option<ContactDetails>,
56    /// Notes (from DataFlow metadata)
57    #[serde(skip_serializing_if = "Option::is_none")]
58    pub notes: Option<String>,
59    /// Version (semantic version) - required when sharing, optional for local systems
60    #[serde(skip_serializing_if = "Option::is_none")]
61    pub version: Option<String>,
62    /// Additional metadata
63    #[serde(default)]
64    pub metadata: HashMap<String, serde_json::Value>,
65    /// Creation timestamp
66    #[serde(skip_serializing_if = "Option::is_none")]
67    pub created_at: Option<DateTime<Utc>>,
68    /// Last update timestamp
69    #[serde(skip_serializing_if = "Option::is_none")]
70    pub updated_at: Option<DateTime<Utc>>,
71}
72
73/// SystemConnection - ERD-style connection between systems
74///
75/// Represents bidirectional connections between systems with connection metadata.
76#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
77pub struct SystemConnection {
78    /// Unique identifier
79    pub id: Uuid,
80    /// Source system ID
81    pub source_system_id: Uuid,
82    /// Target system ID
83    pub target_system_id: Uuid,
84    /// Connection type (e.g., "data_flow", "api_call", "message_queue")
85    pub connection_type: String,
86    /// Whether the connection is bidirectional
87    #[serde(default)]
88    pub bidirectional: bool,
89    /// Connection metadata
90    #[serde(default)]
91    pub metadata: HashMap<String, serde_json::Value>,
92    /// Creation timestamp
93    #[serde(skip_serializing_if = "Option::is_none")]
94    pub created_at: Option<DateTime<Utc>>,
95    /// Last update timestamp
96    #[serde(skip_serializing_if = "Option::is_none")]
97    pub updated_at: Option<DateTime<Utc>>,
98}
99
100/// Shared node reference
101///
102/// Used for referencing nodes shared from other domains.
103#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
104pub struct SharedNodeReference {
105    /// Domain ID where the node is defined
106    pub domain_id: Uuid,
107    /// Node ID in the source domain
108    pub node_id: Uuid,
109    /// Node version (semantic version)
110    pub node_version: String,
111}
112
113/// CADSNode - Reference to a CADS asset
114///
115/// Can be a local CADS asset or a shared reference from another domain.
116#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
117pub struct CADSNode {
118    /// Unique identifier
119    pub id: Uuid,
120    /// Parent system ID
121    pub system_id: Uuid,
122    /// CADS asset ID (if local)
123    #[serde(skip_serializing_if = "Option::is_none")]
124    pub cads_asset_id: Option<Uuid>,
125    /// CADS asset kind
126    pub kind: CADSKind,
127    /// Shared reference (if shared from another domain)
128    #[serde(skip_serializing_if = "Option::is_none")]
129    pub shared_reference: Option<SharedNodeReference>,
130    /// Local metadata overrides (for shared nodes)
131    #[serde(default)]
132    pub custom_metadata: Vec<HashMap<String, serde_json::Value>>,
133    /// Creation timestamp
134    #[serde(skip_serializing_if = "Option::is_none")]
135    pub created_at: Option<DateTime<Utc>>,
136    /// Last update timestamp
137    #[serde(skip_serializing_if = "Option::is_none")]
138    pub updated_at: Option<DateTime<Utc>>,
139}
140
141/// ODCSNode - Reference to an ODCS Table
142///
143/// Can be a local ODCS Table or a shared reference from another domain.
144#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
145pub struct ODCSNode {
146    /// Unique identifier
147    pub id: Uuid,
148    /// Parent system ID
149    pub system_id: Uuid,
150    /// ODCS Table ID (if local)
151    #[serde(skip_serializing_if = "Option::is_none")]
152    pub table_id: Option<Uuid>,
153    /// Node role (e.g., "source", "destination", "intermediate")
154    pub role: String,
155    /// Shared reference (if shared from another domain)
156    #[serde(skip_serializing_if = "Option::is_none")]
157    pub shared_reference: Option<SharedNodeReference>,
158    /// Local metadata overrides (for shared nodes)
159    #[serde(default)]
160    pub custom_metadata: Vec<HashMap<String, serde_json::Value>>,
161    /// Creation timestamp
162    #[serde(skip_serializing_if = "Option::is_none")]
163    pub created_at: Option<DateTime<Utc>>,
164    /// Last update timestamp
165    #[serde(skip_serializing_if = "Option::is_none")]
166    pub updated_at: Option<DateTime<Utc>>,
167}
168
169/// NodeConnection - Crowsfeet notation relationship between ODCS nodes
170///
171/// Represents cardinality-based relationships (1:1, 1:N, 0:1, 0:N) between ODCS nodes.
172#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
173pub struct NodeConnection {
174    /// Unique identifier
175    pub id: Uuid,
176    /// Source node ID (ODCSNode)
177    pub source_node_id: Uuid,
178    /// Target node ID (ODCSNode)
179    pub target_node_id: Uuid,
180    /// Cardinality (OneToOne, OneToMany, ZeroOrOne, ZeroOrMany)
181    pub cardinality: CrowsfeetCardinality,
182    /// Relationship type (e.g., "foreign_key", "data_flow", "derived_from")
183    pub relationship_type: String,
184    /// Additional metadata
185    #[serde(default)]
186    pub metadata: HashMap<String, serde_json::Value>,
187    /// Creation timestamp
188    #[serde(skip_serializing_if = "Option::is_none")]
189    pub created_at: Option<DateTime<Utc>>,
190    /// Last update timestamp
191    #[serde(skip_serializing_if = "Option::is_none")]
192    pub updated_at: Option<DateTime<Utc>>,
193}
194
195/// Domain - Top-level container for a business domain
196///
197/// Organizes systems, CADS nodes, and ODCS nodes within a business domain.
198#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
199pub struct Domain {
200    /// Unique identifier
201    pub id: Uuid,
202    /// Domain name
203    pub name: String,
204    /// Domain description
205    #[serde(skip_serializing_if = "Option::is_none")]
206    pub description: Option<String>,
207    /// Systems in this domain
208    #[serde(default)]
209    pub systems: Vec<System>,
210    /// CADS nodes in this domain
211    #[serde(default)]
212    pub cads_nodes: Vec<CADSNode>,
213    /// ODCS nodes in this domain
214    #[serde(default)]
215    pub odcs_nodes: Vec<ODCSNode>,
216    /// System connections (ERD-style)
217    #[serde(default)]
218    pub system_connections: Vec<SystemConnection>,
219    /// Node connections (Crowsfeet notation)
220    #[serde(default)]
221    pub node_connections: Vec<NodeConnection>,
222    /// Creation timestamp
223    #[serde(skip_serializing_if = "Option::is_none")]
224    pub created_at: Option<DateTime<Utc>>,
225    /// Last update timestamp
226    #[serde(skip_serializing_if = "Option::is_none")]
227    pub updated_at: Option<DateTime<Utc>>,
228}
229
230impl Domain {
231    /// Create a new Domain
232    pub fn new(name: String) -> Self {
233        Self {
234            id: Uuid::new_v4(),
235            name,
236            description: None,
237            systems: Vec::new(),
238            cads_nodes: Vec::new(),
239            odcs_nodes: Vec::new(),
240            system_connections: Vec::new(),
241            node_connections: Vec::new(),
242            created_at: Some(chrono::Utc::now()),
243            updated_at: Some(chrono::Utc::now()),
244        }
245    }
246
247    /// Add a system to the domain
248    pub fn add_system(&mut self, mut system: System) {
249        system.domain_id = self.id;
250        system.created_at = Some(chrono::Utc::now());
251        system.updated_at = Some(chrono::Utc::now());
252        self.systems.push(system);
253        self.updated_at = Some(chrono::Utc::now());
254    }
255
256    /// Add a CADS node to the domain
257    pub fn add_cads_node(&mut self, mut node: CADSNode) {
258        node.created_at = Some(chrono::Utc::now());
259        node.updated_at = Some(chrono::Utc::now());
260        self.cads_nodes.push(node);
261        self.updated_at = Some(chrono::Utc::now());
262    }
263
264    /// Add an ODCS node to the domain
265    pub fn add_odcs_node(&mut self, mut node: ODCSNode) {
266        node.created_at = Some(chrono::Utc::now());
267        node.updated_at = Some(chrono::Utc::now());
268        self.odcs_nodes.push(node);
269        self.updated_at = Some(chrono::Utc::now());
270    }
271
272    /// Add a system connection
273    pub fn add_system_connection(&mut self, mut connection: SystemConnection) {
274        connection.created_at = Some(chrono::Utc::now());
275        connection.updated_at = Some(chrono::Utc::now());
276        self.system_connections.push(connection);
277        self.updated_at = Some(chrono::Utc::now());
278    }
279
280    /// Add a node connection
281    pub fn add_node_connection(&mut self, mut connection: NodeConnection) {
282        connection.created_at = Some(chrono::Utc::now());
283        connection.updated_at = Some(chrono::Utc::now());
284        self.node_connections.push(connection);
285        self.updated_at = Some(chrono::Utc::now());
286    }
287
288    /// Import domain from YAML
289    pub fn from_yaml(yaml_content: &str) -> Result<Self, serde_yaml::Error> {
290        serde_yaml::from_str(yaml_content)
291    }
292
293    /// Export domain to YAML
294    pub fn to_yaml(&self) -> Result<String, serde_yaml::Error> {
295        serde_yaml::to_string(self)
296    }
297}
298
299impl System {
300    /// Create a new System
301    pub fn new(name: String, infrastructure_type: InfrastructureType, domain_id: Uuid) -> Self {
302        Self {
303            id: Uuid::new_v4(),
304            name,
305            infrastructure_type,
306            domain_id,
307            description: None,
308            endpoints: Vec::new(),
309            owner: None,
310            sla: None,
311            contact_details: None,
312            notes: None,
313            version: None,
314            metadata: HashMap::new(),
315            created_at: Some(chrono::Utc::now()),
316            updated_at: Some(chrono::Utc::now()),
317        }
318    }
319}
320
321impl CADSNode {
322    /// Create a new local CADS node
323    pub fn new_local(system_id: Uuid, cads_asset_id: Uuid, kind: CADSKind) -> Self {
324        Self {
325            id: Uuid::new_v4(),
326            system_id,
327            cads_asset_id: Some(cads_asset_id),
328            kind,
329            shared_reference: None,
330            custom_metadata: Vec::new(),
331            created_at: Some(chrono::Utc::now()),
332            updated_at: Some(chrono::Utc::now()),
333        }
334    }
335
336    /// Create a new shared CADS node reference
337    pub fn new_shared(
338        system_id: Uuid,
339        kind: CADSKind,
340        shared_reference: SharedNodeReference,
341    ) -> Self {
342        Self {
343            id: Uuid::new_v4(),
344            system_id,
345            cads_asset_id: None,
346            kind,
347            shared_reference: Some(shared_reference),
348            custom_metadata: Vec::new(),
349            created_at: Some(chrono::Utc::now()),
350            updated_at: Some(chrono::Utc::now()),
351        }
352    }
353}
354
355impl ODCSNode {
356    /// Create a new local ODCS node
357    pub fn new_local(system_id: Uuid, table_id: Uuid, role: String) -> Self {
358        Self {
359            id: Uuid::new_v4(),
360            system_id,
361            table_id: Some(table_id),
362            role,
363            shared_reference: None,
364            custom_metadata: Vec::new(),
365            created_at: Some(chrono::Utc::now()),
366            updated_at: Some(chrono::Utc::now()),
367        }
368    }
369
370    /// Create a new shared ODCS node reference
371    pub fn new_shared(
372        system_id: Uuid,
373        role: String,
374        shared_reference: SharedNodeReference,
375    ) -> Self {
376        Self {
377            id: Uuid::new_v4(),
378            system_id,
379            table_id: None,
380            role,
381            shared_reference: Some(shared_reference),
382            custom_metadata: Vec::new(),
383            created_at: Some(chrono::Utc::now()),
384            updated_at: Some(chrono::Utc::now()),
385        }
386    }
387}