1use serde::{Deserialize, Serialize};
8
9pub const DEFAULT_TENANT: &str = "default";
11
12#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
14pub struct TenantId(pub String);
15
16impl TenantId {
17 pub fn default_tenant() -> Self {
18 Self(DEFAULT_TENANT.to_string())
19 }
20
21 pub fn as_str(&self) -> &str {
22 &self.0
23 }
24}
25
26impl Default for TenantId {
27 fn default() -> Self {
28 Self::default_tenant()
29 }
30}
31
32impl std::fmt::Display for TenantId {
33 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
34 write!(f, "{}", self.0)
35 }
36}
37
38impl From<&str> for TenantId {
39 fn from(s: &str) -> Self {
40 Self(s.to_string())
41 }
42}
43
44impl From<String> for TenantId {
45 fn from(s: String) -> Self {
46 Self(s)
47 }
48}
49
50#[derive(Debug, Clone, Serialize, Deserialize)]
52pub struct Tenant {
53 pub id: TenantId,
54 pub name: String,
55 pub status: TenantStatus,
56 #[serde(skip_serializing_if = "Option::is_none")]
58 pub policy: Option<serde_json::Value>,
59 #[serde(skip_serializing_if = "Option::is_none")]
61 pub limits: Option<TenantLimits>,
62 pub created_at: chrono::DateTime<chrono::Utc>,
63 pub updated_at: chrono::DateTime<chrono::Utc>,
64}
65
66#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
68#[serde(rename_all = "snake_case")]
69pub enum TenantStatus {
70 Active,
71 Suspended,
72 Archived,
73}
74
75impl TenantStatus {
76 pub fn as_str(&self) -> &'static str {
77 match self {
78 Self::Active => "active",
79 Self::Suspended => "suspended",
80 Self::Archived => "archived",
81 }
82 }
83
84 pub fn parse(s: &str) -> Self {
85 match s {
86 "suspended" => Self::Suspended,
87 "archived" => Self::Archived,
88 _ => Self::Active,
89 }
90 }
91}
92
93impl Tenant {
94 pub fn policy_set(&self) -> Option<jamjet_ir::workflow::PolicySetIr> {
98 self.policy
99 .as_ref()
100 .and_then(|v| serde_json::from_value(v.clone()).ok())
101 }
102}
103
104#[derive(Debug, Clone, Serialize, Deserialize)]
106pub struct TenantLimits {
107 #[serde(skip_serializing_if = "Option::is_none")]
109 pub max_concurrent_executions: Option<u32>,
110 #[serde(skip_serializing_if = "Option::is_none")]
112 pub max_workflows: Option<u32>,
113 #[serde(skip_serializing_if = "Option::is_none")]
115 pub max_tokens_per_month: Option<u64>,
116 #[serde(skip_serializing_if = "Option::is_none")]
118 pub max_cost_per_month_usd: Option<f64>,
119}