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