openapi: 3.0.3 info: title: System Console Control Tower (Spec 114) version: 0.1.0 description: | Planning contract for System Console Control Tower read models. NOTE: Filament/Livewire pages render server-side. This OpenAPI file documents the intended query surfaces as if they were JSON endpoints to keep fields and filtering semantics explicit during implementation. servers: - url: /system paths: /dashboard: get: summary: Control Tower KPIs parameters: - in: query name: window schema: type: string enum: [1h, 24h, 7d] required: false responses: '200': description: KPI + top offenders content: application/json: schema: $ref: '#/components/schemas/ControlTowerResponse' /directory/workspaces: get: summary: Workspaces directory parameters: - in: query name: q schema: { type: string } - in: query name: health schema: type: string enum: [ok, warn, critical, unknown] responses: '200': description: Workspaces list content: application/json: schema: $ref: '#/components/schemas/WorkspaceListResponse' /directory/workspaces/{workspaceId}: get: summary: Workspace detail parameters: - in: path name: workspaceId required: true schema: { type: integer } responses: '200': description: Workspace detail content: application/json: schema: $ref: '#/components/schemas/WorkspaceDetailResponse' /directory/tenants: get: summary: Tenants directory parameters: - in: query name: q schema: { type: string } - in: query name: workspace_id schema: { type: integer } responses: '200': description: Tenants list content: application/json: schema: $ref: '#/components/schemas/TenantListResponse' /directory/tenants/{tenantId}: get: summary: Tenant detail parameters: - in: path name: tenantId required: true schema: { type: integer } responses: '200': description: Tenant detail content: application/json: schema: $ref: '#/components/schemas/TenantDetailResponse' /ops/runs: get: summary: Global operation runs parameters: - in: query name: window schema: type: string enum: [1h, 24h, 7d] - in: query name: status schema: type: string enum: [queued, running, completed] - in: query name: outcome schema: type: string - in: query name: type schema: type: string - in: query name: workspace_id schema: { type: integer } - in: query name: tenant_id schema: { type: integer } responses: '200': description: Runs list content: application/json: schema: $ref: '#/components/schemas/RunListResponse' /ops/runs/{runId}: get: summary: Canonical run detail parameters: - in: path name: runId required: true schema: { type: integer } responses: '200': description: Run detail content: application/json: schema: $ref: '#/components/schemas/RunDetailResponse' /ops/failures: get: summary: Failed runs (prefilter) parameters: - in: query name: window schema: type: string enum: [1h, 24h, 7d] responses: '200': description: Failed runs list content: application/json: schema: $ref: '#/components/schemas/RunListResponse' /ops/stuck: get: summary: Stuck runs (prefilter) parameters: - in: query name: window schema: type: string enum: [1h, 24h, 7d] responses: '200': description: Stuck runs list content: application/json: schema: $ref: '#/components/schemas/RunListResponse' /security/access-logs: get: summary: Access logs parameters: - in: query name: window schema: type: string enum: [1h, 24h, 7d] - in: query name: actor_id schema: { type: integer } - in: query name: status schema: type: string enum: [success, failure] responses: '200': description: Access logs list content: application/json: schema: $ref: '#/components/schemas/AccessLogListResponse' components: schemas: ControlTowerResponse: type: object required: [window, kpis, top_offenders] properties: window: { type: string } kpis: type: object additionalProperties: { type: integer } top_offenders: type: array items: type: object required: [dimension, id, label, failed_count] properties: dimension: { type: string, enum: [tenant, workspace, run_type] } id: { type: integer } label: { type: string } failed_count: { type: integer } WorkspaceListResponse: type: object required: [data] properties: data: type: array items: $ref: '#/components/schemas/WorkspaceSummary' WorkspaceDetailResponse: type: object required: [workspace] properties: workspace: $ref: '#/components/schemas/WorkspaceSummary' tenants: type: array items: $ref: '#/components/schemas/TenantSummary' TenantListResponse: type: object required: [data] properties: data: type: array items: $ref: '#/components/schemas/TenantSummary' TenantDetailResponse: type: object required: [tenant] properties: tenant: $ref: '#/components/schemas/TenantSummary' provider_connections: type: array items: $ref: '#/components/schemas/ProviderConnectionSummary' permissions: type: array items: $ref: '#/components/schemas/TenantPermissionSummary' recent_runs: type: array items: $ref: '#/components/schemas/RunSummary' RunListResponse: type: object required: [data] properties: data: type: array items: $ref: '#/components/schemas/RunSummary' RunDetailResponse: type: object required: [run] properties: run: allOf: - $ref: '#/components/schemas/RunSummary' - type: object properties: summary_counts: type: object additionalProperties: { type: integer } failure_summary: type: array items: $ref: '#/components/schemas/RunFailure' context: type: object additionalProperties: true AccessLogListResponse: type: object required: [data] properties: data: type: array items: $ref: '#/components/schemas/AccessLogEntry' WorkspaceSummary: type: object required: [id, name, slug] properties: id: { type: integer } name: { type: string } slug: { type: string } tenant_count: { type: integer } health: { type: string, enum: [ok, warn, critical, unknown] } last_activity_at: { type: string, format: date-time, nullable: true } TenantSummary: type: object required: [id, external_id, name, workspace_id] properties: id: { type: integer } external_id: { type: string } name: { type: string } workspace_id: { type: integer } status: { type: string } environment: { type: string, nullable: true } health: { type: string, enum: [ok, warn, critical, unknown] } last_activity_at: { type: string, format: date-time, nullable: true } ProviderConnectionSummary: type: object required: [provider, is_default] properties: provider: { type: string } is_default: { type: boolean } last_health_check_at: { type: string, format: date-time, nullable: true } health: { type: string, nullable: true } TenantPermissionSummary: type: object required: [key, status] properties: key: { type: string } status: { type: string } last_checked_at: { type: string, format: date-time, nullable: true } RunSummary: type: object required: [id, workspace_id, type, status, outcome, created_at] properties: id: { type: integer } workspace_id: { type: integer } tenant_id: { type: integer, nullable: true } type: { type: string } status: { type: string } outcome: { type: string } initiator_name: { type: string } created_at: { type: string, format: date-time } started_at: { type: string, format: date-time, nullable: true } completed_at: { type: string, format: date-time, nullable: true } RunFailure: type: object required: [code, message] properties: code: { type: string } reason_code: { type: string, nullable: true } message: { type: string } AccessLogEntry: type: object required: [id, recorded_at, action, status] properties: id: { type: integer } recorded_at: { type: string, format: date-time } action: { type: string } status: { type: string } actor_id: { type: integer, nullable: true } actor_email: { type: string, nullable: true } actor_name: { type: string, nullable: true } ip: { type: string, nullable: true } user_agent: { type: string, nullable: true }