Skip to main content

platform_admin_data/
dto.rs

1//! Generic container DTOs for schema-admin endpoints. The record shape is
2//! `serde_json::Value` because the renderer is generic across arbitrary modules.
3
4use platform_core::{StoryDisplayDescriptor, StoryDisplaySource};
5use platform_module::{
6    AdminSchema, AdminSurface, ConsoleSurface, EventSurface, LifecycleSurface, ModuleHttpRoute,
7    ModuleManifestLint, ModuleSource, RuntimeSurface,
8};
9use serde::{Deserialize, Serialize};
10use utoipa::ToSchema;
11
12/// Response for `GET /admin/data/schema`: every admin-capable module's schema.
13#[derive(Debug, Serialize, ToSchema)]
14pub struct AdminSchemaListResponse {
15    pub modules: Vec<AdminModuleSchema>,
16}
17
18/// Response for `POST /admin/data/schema/refresh`.
19#[derive(Debug, Serialize, ToSchema)]
20pub struct AdminSchemaRefreshResponse {
21    pub modules: Vec<AdminModuleSchema>,
22}
23
24/// Response for `GET /admin/data/modules`: every registered module's metadata,
25/// including modules without admin surfaces.
26#[derive(Debug, Serialize, ToSchema)]
27pub struct AdminModuleMetadataListResponse {
28    pub modules: Vec<AdminModuleMetadataDto>,
29    pub refreshed_at: Option<String>,
30    pub refresh_error: Option<String>,
31    pub refresh_history: Vec<AdminModuleRefreshRecordDto>,
32}
33
34/// Response for `GET /admin/data/available-modules`: a read-only list of
35/// remote modules that can be installed from their manifest URL.
36#[derive(Debug, Serialize, ToSchema)]
37pub struct AdminModuleRegistrySnapshotResponse {
38    pub version: u8,
39    pub status: AdminModuleRegistrySnapshotStatus,
40    pub catalog: AdminModuleRegistrySnapshotCatalogDto,
41    pub issues: Vec<AdminModuleRegistrySnapshotIssueDto>,
42    pub modules: Vec<AdminModuleRegistrySnapshotModuleDto>,
43}
44
45#[derive(Debug, Serialize, ToSchema)]
46#[serde(rename_all = "snake_case")]
47pub enum AdminModuleRegistrySnapshotStatus {
48    Passed,
49    Failed,
50}
51
52#[derive(Debug, Serialize, ToSchema)]
53#[serde(rename_all = "camelCase")]
54pub struct AdminModuleRegistrySnapshotCatalogDto {
55    pub modules: usize,
56    pub registry_file: String,
57    pub version: u8,
58}
59
60#[derive(Debug, Serialize, ToSchema)]
61pub struct AdminModuleRegistrySnapshotIssueDto {
62    pub group: String,
63    pub message: String,
64    pub fix: String,
65}
66
67#[derive(Debug, Serialize, ToSchema)]
68#[serde(rename_all = "camelCase")]
69pub struct AdminModuleRegistrySnapshotModuleDto {
70    pub name: String,
71    pub source: ModuleSource,
72    pub catalog_version: String,
73    pub manifest_reference: String,
74    pub summary: Option<String>,
75    pub base_url: Option<String>,
76    pub capabilities: Vec<String>,
77    pub console_package_hints: usize,
78    pub compatibility: Option<AdminModuleCompatibilityDto>,
79    pub host_compatibility: AdminModuleHostCompatibilityDto,
80    pub archived_at: Option<String>,
81    pub archive_reason: Option<String>,
82    pub manifest_name: Option<String>,
83    pub manifest_status: AdminModuleRegistrySnapshotManifestStatus,
84    pub manifest_version: Option<String>,
85    pub install_state: AdminModuleInstallStateDto,
86    pub status: AdminModuleRegistrySnapshotModuleStatus,
87}
88
89#[derive(Debug, Serialize, ToSchema)]
90#[serde(rename_all = "camelCase")]
91pub struct AdminModuleInstallStateDto {
92    pub module_registered: bool,
93    pub linked_source: Option<AdminModuleLinkedSourceInstallStateDto>,
94    pub remote_source: Option<AdminModuleRemoteSourceInstallStateDto>,
95    pub console_plan: AdminModuleConsolePackagePlanStateDto,
96}
97
98#[derive(Debug, Serialize, ToSchema)]
99#[serde(rename_all = "camelCase")]
100pub struct AdminModuleLinkedSourceInstallStateDto {
101    pub env_file: String,
102    pub configured: bool,
103    pub desired_enabled: Option<bool>,
104    pub running_enabled: bool,
105    pub restart_pending: bool,
106    pub restart_reason: Option<String>,
107    pub error: Option<String>,
108}
109
110#[derive(Debug, Serialize, ToSchema)]
111#[serde(rename_all = "camelCase")]
112pub struct AdminModuleRemoteSourceInstallStateDto {
113    pub env_file: String,
114    pub configured: bool,
115    pub desired_base_url: Option<String>,
116    pub running_base_url: Option<String>,
117    pub restart_pending: bool,
118    pub restart_reason: Option<String>,
119    pub error: Option<String>,
120}
121
122#[derive(Debug, Serialize, ToSchema)]
123#[serde(rename_all = "camelCase")]
124pub struct AdminModuleConsolePackagePlanStateDto {
125    pub plan_file: String,
126    pub exists: bool,
127    pub readable: bool,
128    pub error: Option<String>,
129    pub module_entry_present: bool,
130    pub package_count: usize,
131    pub restart_required: Option<bool>,
132    pub packages: Vec<AdminModuleConsolePackagePlanPackageDto>,
133}
134
135/// Response for visually installing an available remote module from the
136/// marketplace catalog.
137#[derive(Debug, Serialize, ToSchema)]
138#[serde(rename_all = "camelCase")]
139pub struct AdminModuleInstallResponse {
140    pub module_name: String,
141    pub manifest_reference: String,
142    pub linked_source: Option<AdminModuleLinkedSourceInstallStateDto>,
143    pub remote_source: Option<AdminModuleRemoteSourceInstallStateDto>,
144    pub console_plan: AdminModuleConsolePackagePlanStateDto,
145    pub restart_required: bool,
146}
147
148#[derive(Debug, Serialize, ToSchema)]
149#[serde(rename_all = "camelCase")]
150pub struct AdminModuleConsolePackagePlanPackageDto {
151    pub key: Option<String>,
152    pub package_name: String,
153    pub export_name: String,
154    pub command: Option<String>,
155    pub route: Option<String>,
156    pub status: Option<String>,
157}
158
159#[derive(Clone, Debug, Deserialize, Serialize, ToSchema)]
160#[serde(rename_all = "camelCase")]
161pub struct AdminModuleCompatibilityDto {
162    pub console_package_api: Option<String>,
163    pub lenso: Option<AdminModuleLensoCompatibilityDto>,
164}
165
166#[derive(Clone, Debug, Deserialize, Serialize, ToSchema)]
167#[serde(rename_all = "camelCase")]
168pub struct AdminModuleLensoCompatibilityDto {
169    pub min_version: Option<String>,
170    pub max_version: Option<String>,
171}
172
173#[derive(Clone, Debug, Serialize, ToSchema)]
174#[serde(rename_all = "camelCase")]
175pub struct AdminModuleHostCompatibilityDto {
176    pub console_package_api: String,
177    pub lenso_version: String,
178}
179
180#[derive(Debug, Serialize, ToSchema)]
181#[serde(rename_all = "snake_case")]
182pub enum AdminModuleRegistrySnapshotManifestStatus {
183    Ok,
184    Invalid,
185    Unreadable,
186    Archived,
187}
188
189#[derive(Debug, Serialize, ToSchema)]
190#[serde(rename_all = "snake_case")]
191pub enum AdminModuleRegistrySnapshotModuleStatus {
192    Ready,
193    NeedsAttention,
194    Archived,
195}
196
197#[derive(Debug, Serialize, ToSchema)]
198pub struct AdminModuleRefreshRecordDto {
199    pub id: String,
200    pub status: AdminModuleRefreshStatusDto,
201    pub started_at: String,
202    pub completed_at: String,
203    pub duration_ms: u64,
204    pub module_count: usize,
205    pub error: Option<String>,
206    pub module_results: Vec<AdminModuleRefreshModuleResultDto>,
207}
208
209#[derive(Debug, Serialize, ToSchema)]
210#[serde(rename_all = "snake_case")]
211pub enum AdminModuleRefreshStatusDto {
212    Success,
213    Error,
214}
215
216#[derive(Debug, Serialize, ToSchema)]
217pub struct AdminModuleRefreshModuleResultDto {
218    pub module_name: String,
219    pub source: ModuleSource,
220    pub status: AdminModuleRefreshModuleStatusDto,
221    pub duration_ms: Option<u64>,
222    pub endpoint: Option<String>,
223    pub error: Option<String>,
224}
225
226#[derive(Debug, Serialize, ToSchema)]
227#[serde(rename_all = "snake_case")]
228pub enum AdminModuleRefreshModuleStatusDto {
229    Loaded,
230    Error,
231}
232
233#[derive(Debug, Serialize, ToSchema)]
234pub struct AdminModuleMetadataDto {
235    pub module_name: String,
236    pub source: ModuleSource,
237    pub status: AdminModuleStatus,
238    pub error: Option<String>,
239    pub source_diagnostics: Option<AdminModuleSourceDiagnosticsDto>,
240    pub http_routes: Vec<ModuleHttpRoute>,
241    pub runtime: Option<RuntimeSurface>,
242    pub events: Option<EventSurface>,
243    pub lifecycle: Option<LifecycleSurface>,
244    pub console: Vec<ConsoleSurface>,
245    pub governance: AdminModuleGovernanceDto,
246    pub manifest_lints: Vec<ModuleManifestLint>,
247    pub story_display: Vec<StoryDisplayDescriptorDto>,
248    pub capabilities: Vec<String>,
249    pub dependencies: Vec<String>,
250    pub admin: Option<AdminSurface>,
251}
252
253#[derive(Debug, Serialize, ToSchema)]
254#[serde(tag = "kind", rename_all = "snake_case")]
255pub enum AdminModuleSourceDiagnosticsDto {
256    Remote(AdminRemoteModuleDiagnosticsDto),
257}
258
259#[derive(Debug, Serialize, ToSchema)]
260pub struct AdminRemoteModuleDiagnosticsDto {
261    pub transport: String,
262    pub base_url: String,
263    pub manifest_url: String,
264    pub timeout_ms: u64,
265    pub auth_configured: bool,
266    pub load_duration_ms: Option<u64>,
267    pub last_checked_at: Option<String>,
268    pub last_load_error: Option<String>,
269}
270
271#[derive(Debug, Serialize, ToSchema)]
272pub struct AdminModuleGovernanceDto {
273    pub activation_state: AdminModuleActivationState,
274    pub activation_reasons: Vec<String>,
275    pub capability_summary: AdminCapabilitySummaryDto,
276    pub capability_issues: Vec<AdminCapabilityIssueDto>,
277}
278
279#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, ToSchema)]
280#[serde(rename_all = "snake_case")]
281pub enum AdminModuleActivationState {
282    Active,
283    NeedsAttention,
284    Blocked,
285}
286
287#[derive(Debug, Serialize, ToSchema)]
288pub struct AdminCapabilitySummaryDto {
289    pub declared_count: usize,
290    pub referenced_count: usize,
291    pub missing_count: usize,
292    pub unused_count: usize,
293}
294
295#[derive(Debug, Serialize, ToSchema)]
296pub struct AdminCapabilityIssueDto {
297    pub capability: String,
298    pub subject: String,
299    pub message: String,
300    pub suggestion: String,
301}
302
303#[derive(Debug, Serialize, ToSchema)]
304pub struct StoryDisplayDescriptorDto {
305    pub source: StoryDisplaySourceDto,
306    pub display_name: String,
307    pub story_title: Option<String>,
308}
309
310#[derive(Debug, Serialize, ToSchema)]
311#[serde(tag = "kind", rename_all = "snake_case")]
312pub enum StoryDisplaySourceDto {
313    ExecutionName { name: String },
314    HttpRequest { method: String, path: String },
315}
316
317impl From<StoryDisplayDescriptor> for StoryDisplayDescriptorDto {
318    fn from(descriptor: StoryDisplayDescriptor) -> Self {
319        Self {
320            source: descriptor.source.into(),
321            display_name: descriptor.display_name,
322            story_title: descriptor.story_title,
323        }
324    }
325}
326
327impl From<StoryDisplaySource> for StoryDisplaySourceDto {
328    fn from(source: StoryDisplaySource) -> Self {
329        match source {
330            StoryDisplaySource::ExecutionName { name } => Self::ExecutionName { name },
331            StoryDisplaySource::HttpRequest { method, path } => Self::HttpRequest { method, path },
332        }
333    }
334}
335
336#[derive(Debug, Serialize, ToSchema)]
337pub struct AdminModuleSchema {
338    pub module_name: String,
339    pub source: ModuleSource,
340    pub status: AdminModuleStatus,
341    pub error: Option<String>,
342    pub schema: AdminSchema,
343}
344
345#[derive(Debug, Clone, Copy, Serialize, ToSchema)]
346#[serde(rename_all = "snake_case")]
347pub enum AdminModuleStatus {
348    Loaded,
349    Error,
350}
351
352/// Response for `GET /admin/data/{module}/{entity}`: a page of records.
353#[derive(Debug, Serialize, ToSchema)]
354pub struct AdminDataListResponse {
355    /// Each record is an arbitrary JSON object whose keys match the entity schema.
356    pub data: Vec<serde_json::Value>,
357    pub page: AdminDataPageInfo,
358}
359
360/// Pagination info. `next_cursor` is an opaque token (not a timestamp like
361/// platform-admin's PageInfo) so it makes no assumption about entity shape.
362#[derive(Debug, Serialize, ToSchema)]
363pub struct AdminDataPageInfo {
364    pub limit: i64,
365    pub next_cursor: Option<String>,
366}
367
368/// Response for `GET /admin/data/{module}/{entity}/{id}`.
369#[derive(Debug, Serialize, ToSchema)]
370pub struct AdminDataDetailResponse {
371    pub data: serde_json::Value,
372}
373
374/// Request body for `POST /admin/data/{module}/actions/{action}`.
375#[derive(Debug, Clone, Deserialize, ToSchema)]
376pub struct AdminActionInvokeRequest {
377    #[serde(default)]
378    pub input: serde_json::Value,
379    #[serde(default)]
380    pub confirmation_phrase: Option<String>,
381}
382
383/// Response for `POST /admin/data/{module}/actions/{action}`.
384#[derive(Debug, Serialize, ToSchema)]
385pub struct AdminActionInvokeResponse {
386    pub data: serde_json::Value,
387    pub invocation: AdminActionInvocationDto,
388}
389
390#[derive(Debug, Serialize, ToSchema)]
391pub struct AdminActionInvocationDto {
392    pub request_id: String,
393    pub correlation_id: String,
394    pub story_node_id: String,
395}