Skip to main content

systemprompt_models/api/
cloud.rs

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