Skip to main content

systemprompt_models/api/cloud/
mod.rs

1//! Cloud Management API types shared between CLI and API server.
2
3mod provisioning;
4
5pub use provisioning::{
6    ActivityData, ActivityRequest, CheckoutEvent, CheckoutRequest, CheckoutResponse,
7    DeployResponse, ProvisioningEvent, ProvisioningEventType,
8};
9
10use schemars::JsonSchema;
11use serde::{Deserialize, Serialize};
12use std::collections::HashMap;
13use systemprompt_identifiers::ContextId;
14
15#[derive(Debug, Clone, Serialize, Deserialize)]
16pub struct CloudApiResponse<T> {
17    pub data: T,
18}
19
20#[derive(Debug, Clone, Serialize, Deserialize)]
21pub struct CloudApiError {
22    pub error: CloudApiErrorDetail,
23}
24
25#[derive(Debug, Clone, Serialize, Deserialize)]
26pub struct CloudApiErrorDetail {
27    pub code: String,
28    pub message: String,
29}
30
31#[derive(Debug, Clone, Serialize, Deserialize)]
32pub struct CloudUserInfo {
33    pub id: systemprompt_identifiers::UserId,
34    pub email: String,
35    #[serde(default, skip_serializing_if = "Option::is_none")]
36    pub name: Option<String>,
37}
38
39#[derive(Debug, Clone, Serialize, Deserialize)]
40pub struct CloudCustomerInfo {
41    pub id: String,
42    #[serde(default, skip_serializing_if = "Option::is_none")]
43    pub status: Option<String>,
44}
45
46#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
47#[serde(rename_all = "snake_case")]
48pub enum SubscriptionStatus {
49    Active,
50    Trialing,
51    PastDue,
52    Paused,
53    Canceled,
54}
55
56#[derive(Debug, Clone, Serialize, Deserialize)]
57pub struct CloudPlanInfo {
58    #[serde(default, skip_serializing_if = "Option::is_none")]
59    pub id: Option<String>,
60    pub name: String,
61    pub memory_mb: i32,
62    pub volume_gb: i32,
63}
64
65#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
66pub struct CloudPlan {
67    pub id: String,
68    pub name: String,
69    pub paddle_price_id: systemprompt_identifiers::PriceId,
70    #[serde(default)]
71    pub memory_mb_default: i32,
72    #[serde(default)]
73    pub volume_gb: i32,
74    #[serde(default, skip_serializing_if = "Option::is_none")]
75    pub max_tenants: Option<i32>,
76}
77
78#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
79#[serde(rename_all = "snake_case")]
80pub enum CloudTenantStatus {
81    Pending,
82    Active,
83    Suspended,
84    Deleted,
85}
86
87#[derive(Debug, Clone, Serialize, Deserialize)]
88pub struct CloudTenantInfo {
89    pub id: String,
90    pub name: String,
91    #[serde(default, skip_serializing_if = "Option::is_none")]
92    pub subscription_id: Option<String>,
93    #[serde(default, skip_serializing_if = "Option::is_none")]
94    pub subscription_status: Option<SubscriptionStatus>,
95    #[serde(default, skip_serializing_if = "Option::is_none")]
96    pub app_id: Option<String>,
97    #[serde(default, skip_serializing_if = "Option::is_none")]
98    pub hostname: Option<String>,
99    #[serde(default, skip_serializing_if = "Option::is_none")]
100    pub region: Option<String>,
101    #[serde(default, skip_serializing_if = "Option::is_none")]
102    pub status: Option<CloudTenantStatus>,
103    #[serde(default, skip_serializing_if = "Option::is_none")]
104    pub plan: Option<CloudPlanInfo>,
105    #[serde(default)]
106    pub external_db_access: bool,
107    pub database_url: String,
108}
109
110#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
111pub struct CloudTenant {
112    pub id: String,
113    pub name: String,
114    #[serde(skip_serializing_if = "Option::is_none")]
115    pub fly_app_name: Option<String>,
116    #[serde(skip_serializing_if = "Option::is_none")]
117    pub fly_hostname: Option<String>,
118    #[serde(default, skip_serializing_if = "Option::is_none")]
119    pub hostname: Option<String>,
120}
121
122#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
123pub struct CloudTenantStatusResponse {
124    pub status: String,
125    #[serde(default, skip_serializing_if = "Option::is_none")]
126    pub message: Option<String>,
127    #[serde(default, skip_serializing_if = "Option::is_none")]
128    pub app_url: Option<String>,
129    #[serde(default, skip_serializing_if = "Option::is_none")]
130    pub secrets_url: Option<String>,
131}
132
133#[derive(Debug, Clone, Serialize, Deserialize)]
134pub struct CloudTenantSecrets {
135    pub jwt_secret: String,
136    pub database_url: String,
137    pub internal_database_url: String,
138    pub app_url: String,
139    #[serde(default, skip_serializing_if = "Option::is_none")]
140    pub sync_token: Option<String>,
141    #[serde(default, skip_serializing_if = "Option::is_none")]
142    pub anthropic_api_key: Option<String>,
143    #[serde(default, skip_serializing_if = "Option::is_none")]
144    pub openai_api_key: Option<String>,
145    #[serde(default, skip_serializing_if = "Option::is_none")]
146    pub gemini_api_key: Option<String>,
147}
148
149#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
150pub struct SetExternalDbAccessRequest {
151    pub enabled: bool,
152}
153
154#[derive(Debug, Clone, Serialize, Deserialize)]
155pub struct ExternalDbAccessResponse {
156    pub tenant_id: systemprompt_identifiers::TenantId,
157    pub external_db_access: bool,
158    pub database_url: String,
159}
160
161#[derive(Debug, Clone, Serialize, Deserialize)]
162pub struct RotateCredentialsResponse {
163    pub status: String,
164    pub message: String,
165    pub internal_database_url: String,
166    pub external_database_url: String,
167}
168
169#[derive(Debug, Clone, Serialize, Deserialize)]
170pub struct RotateSyncTokenResponse {
171    pub sync_token: String,
172}
173
174#[derive(Debug, Clone, Serialize, Deserialize)]
175pub struct CloudEnterpriseLicenseInfo {
176    pub id: String,
177    pub name: String,
178    pub domain: String,
179    #[serde(default, skip_serializing_if = "Option::is_none")]
180    pub plan: Option<CloudPlanInfo>,
181}
182
183#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
184pub struct UsageWindow {
185    pub requests: i64,
186    pub tokens: i64,
187    pub cost_microdollars: i64,
188    #[serde(default, skip_serializing_if = "Option::is_none")]
189    pub previous_cost_microdollars: Option<i64>,
190}
191
192#[derive(Debug, Clone, Serialize, Deserialize)]
193pub struct ModelShare {
194    pub model: String,
195    pub requests: i64,
196    pub tokens: i64,
197    pub cost_microdollars: i64,
198    pub token_share: f64,
199}
200
201#[derive(Debug, Clone, Serialize, Deserialize)]
202pub struct ConversationGroup {
203    pub name: String,
204    pub conversations: i64,
205    pub ai_requests: i64,
206}
207
208#[derive(Debug, Clone, Serialize, Deserialize)]
209pub struct RecentConversationSummary {
210    pub context_id: ContextId,
211    pub last_activity: chrono::DateTime<chrono::Utc>,
212    pub ai_requests: i64,
213    #[serde(default, skip_serializing_if = "Option::is_none")]
214    pub model: Option<String>,
215    #[serde(default, skip_serializing_if = "Option::is_none")]
216    pub agent_name: Option<String>,
217}
218
219#[derive(Debug, Clone, Default, Serialize, Deserialize)]
220pub struct ConversationSummary {
221    pub total_conversations: i64,
222    pub total_ai_requests: i64,
223    #[serde(default)]
224    pub by_model: Vec<ConversationGroup>,
225    #[serde(default)]
226    pub by_agent: Vec<ConversationGroup>,
227    #[serde(default)]
228    pub recent: Vec<RecentConversationSummary>,
229}
230
231#[derive(Debug, Clone, Serialize, Deserialize)]
232pub struct BridgeProfileUsage {
233    pub d1: UsageWindow,
234    pub d7: UsageWindow,
235    pub d30: UsageWindow,
236    #[serde(default)]
237    pub top_models: Vec<ModelShare>,
238    #[serde(default)]
239    pub conversations: ConversationSummary,
240}
241
242#[derive(Debug, Clone, Serialize, Deserialize)]
243pub struct UserMeResponse {
244    pub user: CloudUserInfo,
245    #[serde(default, skip_serializing_if = "Option::is_none")]
246    pub customer: Option<CloudCustomerInfo>,
247    #[serde(default)]
248    pub tenants: Vec<CloudTenantInfo>,
249    #[serde(default, skip_serializing_if = "Option::is_none")]
250    pub enterprise: Option<CloudEnterpriseLicenseInfo>,
251}
252
253#[derive(Debug, Clone, Serialize, Deserialize)]
254pub struct CloudListResponse<T> {
255    pub data: Vec<T>,
256}
257
258#[derive(Debug, Clone, Serialize, Deserialize)]
259pub struct RegistryToken {
260    pub registry: String,
261    pub username: String,
262    pub token: String,
263    pub repository: String,
264    pub tag: String,
265}
266
267#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
268pub struct CloudStatusResponse {
269    pub status: String,
270}
271
272#[derive(Debug, Clone, Serialize, Deserialize)]
273pub struct SetSecretsRequest {
274    pub secrets: HashMap<String, String>,
275}
276
277#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
278pub struct CloudLogEntry {
279    pub timestamp: String,
280    pub message: String,
281    #[serde(default, skip_serializing_if = "Option::is_none")]
282    pub level: Option<String>,
283}
284
285#[derive(Debug, Clone, Serialize, Deserialize)]
286pub struct CloudLogsResponse {
287    pub logs: Vec<CloudLogEntry>,
288}
289
290#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
291pub struct ListSecretsResponse {
292    pub keys: Vec<String>,
293}
294
295#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
296pub struct SetCustomDomainRequest {
297    pub domain: String,
298}
299
300#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
301pub struct DnsInstructions {
302    pub record_type: String,
303    pub host: String,
304    pub value: String,
305    pub ttl: u32,
306}
307
308#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
309pub struct CustomDomainResponse {
310    pub domain: String,
311    pub status: String,
312    pub verified: bool,
313    pub dns_target: String,
314    pub dns_instructions: DnsInstructions,
315    #[serde(default, skip_serializing_if = "Option::is_none")]
316    pub created_at: Option<String>,
317    #[serde(default, skip_serializing_if = "Option::is_none")]
318    pub verified_at: Option<String>,
319}
320
321pub type ApiResponse<T> = CloudApiResponse<T>;
322pub type ApiError = CloudApiError;
323pub type ApiErrorDetail = CloudApiErrorDetail;
324pub type UserInfo = CloudUserInfo;
325pub type CustomerInfo = CloudCustomerInfo;
326pub type PlanInfo = CloudPlanInfo;
327pub type Plan = CloudPlan;
328pub type TenantInfo = CloudTenantInfo;
329pub type Tenant = CloudTenant;
330pub type TenantStatus = CloudTenantStatusResponse;
331pub type TenantSecrets = CloudTenantSecrets;
332pub type ListResponse<T> = CloudListResponse<T>;
333pub type StatusResponse = CloudStatusResponse;
334pub type LogEntry = CloudLogEntry;
335pub type LogsResponse = CloudLogsResponse;
336pub type EnterpriseLicenseInfo = CloudEnterpriseLicenseInfo;