Contract-first API with DTOs, validation, and server-side OpenAPI post-processing
All checks were successful
CI / build (push) Successful in 1m27s
CI / docker (push) Successful in 2m6s
CI / deploy (push) Successful in 30s

Add dedicated request/response DTOs for all controllers, replacing raw
JsonNode parameters with validated types. Move OpenAPI path-prefix stripping
and ProcessorNode children injection into OpenApiCustomizer beans so the
spec served at /api/v1/api-docs is already clean — eliminating the need for
the ui/scripts/process-openapi.mjs post-processing script.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-03-14 15:33:37 +01:00
parent 50bb22d6f6
commit 465f210aee
43 changed files with 1561 additions and 509 deletions

View File

@@ -1,10 +1,15 @@
{
"openapi": "3.1.0",
"info": {
"title": "OpenAPI definition",
"version": "v0"
"title": "Cameleer3 Server API",
"version": "1.0"
},
"servers": [],
"security": [
{
"bearer": []
}
],
"tags": [
{
"name": "Agent SSE",
@@ -26,6 +31,10 @@
"name": "Ingestion",
"description": "Data ingestion endpoints"
},
{
"name": "Authentication",
"description": "Login and token refresh endpoints"
},
{
"name": "OIDC Config Admin",
"description": "OIDC provider configuration (ADMIN only)"
@@ -94,7 +103,7 @@
"content": {
"*/*": {
"schema": {
"type": "object"
"$ref": "#/components/schemas/OidcAdminConfigResponse"
}
}
}
@@ -111,7 +120,7 @@
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/OidcConfigRequest"
"$ref": "#/components/schemas/OidcAdminConfigRequest"
}
}
},
@@ -123,7 +132,7 @@
"content": {
"*/*": {
"schema": {
"type": "object"
"$ref": "#/components/schemas/OidcAdminConfigResponse"
}
}
}
@@ -133,7 +142,7 @@
"content": {
"*/*": {
"schema": {
"type": "object"
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
@@ -378,8 +387,9 @@
"/auth/refresh": {
"post": {
"tags": [
"ui-auth-controller"
"Authentication"
],
"summary": "Refresh access token",
"operationId": "refresh",
"requestBody": {
"content": {
@@ -393,11 +403,21 @@
},
"responses": {
"200": {
"description": "OK",
"description": "Token refreshed",
"content": {
"*/*": {
"schema": {
"type": "object"
"$ref": "#/components/schemas/AuthTokenResponse"
}
}
}
},
"401": {
"description": "Invalid refresh token",
"content": {
"*/*": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
@@ -408,8 +428,9 @@
"/auth/oidc/callback": {
"post": {
"tags": [
"oidc-auth-controller"
"Authentication"
],
"summary": "Exchange OIDC authorization code for JWTs",
"operationId": "callback",
"requestBody": {
"content": {
@@ -423,11 +444,41 @@
},
"responses": {
"200": {
"description": "OK",
"description": "Authentication successful",
"content": {
"*/*": {
"schema": {
"type": "object"
"$ref": "#/components/schemas/AuthTokenResponse"
}
}
}
},
"401": {
"description": "OIDC authentication failed",
"content": {
"*/*": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
},
"403": {
"description": "Account not provisioned",
"content": {
"*/*": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
},
"404": {
"description": "OIDC not configured or disabled",
"content": {
"*/*": {
"schema": {
"$ref": "#/components/schemas/AuthTokenResponse"
}
}
}
@@ -438,8 +489,9 @@
"/auth/login": {
"post": {
"tags": [
"ui-auth-controller"
"Authentication"
],
"summary": "Login with local credentials",
"operationId": "login",
"requestBody": {
"content": {
@@ -453,11 +505,21 @@
},
"responses": {
"200": {
"description": "OK",
"description": "Login successful",
"content": {
"*/*": {
"schema": {
"type": "object"
"$ref": "#/components/schemas/AuthTokenResponse"
}
}
}
},
"401": {
"description": "Invalid credentials",
"content": {
"*/*": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
@@ -487,7 +549,7 @@
"content": {
"application/json": {
"schema": {
"type": "string"
"$ref": "#/components/schemas/AgentRefreshRequest"
}
}
},
@@ -499,7 +561,7 @@
"content": {
"*/*": {
"schema": {
"type": "string"
"$ref": "#/components/schemas/AgentRefreshResponse"
}
}
}
@@ -509,7 +571,7 @@
"content": {
"*/*": {
"schema": {
"type": "string"
"$ref": "#/components/schemas/AgentRefreshResponse"
}
}
}
@@ -519,7 +581,7 @@
"content": {
"*/*": {
"schema": {
"type": "string"
"$ref": "#/components/schemas/AgentRefreshResponse"
}
}
}
@@ -577,7 +639,7 @@
"content": {
"application/json": {
"schema": {
"type": "string"
"$ref": "#/components/schemas/CommandRequest"
}
}
},
@@ -589,7 +651,7 @@
"content": {
"*/*": {
"schema": {
"type": "string"
"$ref": "#/components/schemas/CommandSingleResponse"
}
}
}
@@ -599,7 +661,7 @@
"content": {
"*/*": {
"schema": {
"type": "string"
"$ref": "#/components/schemas/CommandSingleResponse"
}
}
}
@@ -609,7 +671,7 @@
"content": {
"*/*": {
"schema": {
"type": "string"
"$ref": "#/components/schemas/CommandSingleResponse"
}
}
}
@@ -665,7 +727,7 @@
"content": {
"application/json": {
"schema": {
"type": "string"
"$ref": "#/components/schemas/AgentRegistrationRequest"
}
}
},
@@ -677,7 +739,7 @@
"content": {
"*/*": {
"schema": {
"type": "string"
"$ref": "#/components/schemas/AgentRegistrationResponse"
}
}
}
@@ -687,7 +749,7 @@
"content": {
"*/*": {
"schema": {
"type": "string"
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
@@ -697,7 +759,7 @@
"content": {
"*/*": {
"schema": {
"type": "string"
"$ref": "#/components/schemas/AgentRegistrationResponse"
}
}
}
@@ -727,7 +789,7 @@
"content": {
"application/json": {
"schema": {
"type": "string"
"$ref": "#/components/schemas/CommandRequest"
}
}
},
@@ -739,7 +801,7 @@
"content": {
"*/*": {
"schema": {
"type": "string"
"$ref": "#/components/schemas/CommandBroadcastResponse"
}
}
}
@@ -749,7 +811,7 @@
"content": {
"*/*": {
"schema": {
"type": "string"
"$ref": "#/components/schemas/CommandBroadcastResponse"
}
}
}
@@ -769,7 +831,7 @@
"content": {
"application/json": {
"schema": {
"type": "string"
"$ref": "#/components/schemas/CommandRequest"
}
}
},
@@ -781,7 +843,7 @@
"content": {
"*/*": {
"schema": {
"type": "string"
"$ref": "#/components/schemas/CommandBroadcastResponse"
}
}
}
@@ -791,7 +853,7 @@
"content": {
"*/*": {
"schema": {
"type": "string"
"$ref": "#/components/schemas/CommandBroadcastResponse"
}
}
}
@@ -812,7 +874,7 @@
"content": {
"*/*": {
"schema": {
"type": "object"
"$ref": "#/components/schemas/OidcTestResult"
}
}
}
@@ -822,7 +884,7 @@
"content": {
"*/*": {
"schema": {
"type": "object"
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
@@ -941,7 +1003,17 @@
],
"responses": {
"200": {
"description": "OK",
"description": "Execution detail found",
"content": {
"*/*": {
"schema": {
"$ref": "#/components/schemas/ExecutionDetail"
}
}
}
},
"404": {
"description": "Execution not found",
"content": {
"*/*": {
"schema": {
@@ -981,7 +1053,20 @@
],
"responses": {
"200": {
"description": "OK",
"description": "Snapshot data",
"content": {
"*/*": {
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
}
}
},
"404": {
"description": "Snapshot not found",
"content": {
"*/*": {
"schema": {
@@ -1018,9 +1103,14 @@
"200": {
"description": "Diagram rendered successfully",
"content": {
"*/*": {
"image/svg+xml": {
"schema": {
"type": "object"
"type": "string"
}
},
"application/json": {
"schema": {
"$ref": "#/components/schemas/DiagramLayout"
}
}
}
@@ -1041,16 +1131,37 @@
"/auth/oidc/config": {
"get": {
"tags": [
"oidc-auth-controller"
"Authentication"
],
"summary": "Get OIDC config for SPA login flow",
"operationId": "getConfig_1",
"responses": {
"200": {
"description": "OK",
"description": "OIDC configuration",
"content": {
"*/*": {
"schema": {
"type": "object"
"$ref": "#/components/schemas/OidcPublicConfigResponse"
}
}
}
},
"404": {
"description": "OIDC not configured or disabled",
"content": {
"*/*": {
"schema": {
"$ref": "#/components/schemas/OidcPublicConfigResponse"
}
}
}
},
"500": {
"description": "Failed to retrieve OIDC provider metadata",
"content": {
"*/*": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
@@ -1082,7 +1193,10 @@
"content": {
"*/*": {
"schema": {
"type": "string"
"type": "array",
"items": {
"$ref": "#/components/schemas/AgentInstanceResponse"
}
}
}
}
@@ -1092,7 +1206,7 @@
"content": {
"*/*": {
"schema": {
"type": "string"
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
@@ -1252,8 +1366,9 @@
}
}
},
"OidcConfigRequest": {
"OidcAdminConfigRequest": {
"type": "object",
"description": "OIDC configuration update request",
"properties": {
"enabled": {
"type": "boolean"
@@ -1281,6 +1396,51 @@
}
}
},
"ErrorResponse": {
"type": "object",
"description": "Error response",
"properties": {
"message": {
"type": "string"
}
},
"required": [
"message"
]
},
"OidcAdminConfigResponse": {
"type": "object",
"description": "OIDC configuration for admin management",
"properties": {
"configured": {
"type": "boolean"
},
"enabled": {
"type": "boolean"
},
"issuerUri": {
"type": "string"
},
"clientId": {
"type": "string"
},
"clientSecretSet": {
"type": "boolean"
},
"rolesClaim": {
"type": "string"
},
"defaultRoles": {
"type": "array",
"items": {
"type": "string"
}
},
"autoSignup": {
"type": "boolean"
}
}
},
"SearchRequest": {
"type": "object",
"properties": {
@@ -1373,7 +1533,19 @@
"diagramContentHash": {
"type": "string"
}
}
},
"required": [
"agentId",
"correlationId",
"diagramContentHash",
"durationMs",
"endTime",
"errorMessage",
"executionId",
"routeId",
"startTime",
"status"
]
},
"SearchResultExecutionSummary": {
"type": "object",
@@ -1396,7 +1568,13 @@
"type": "integer",
"format": "int32"
}
}
},
"required": [
"data",
"limit",
"offset",
"total"
]
},
"RefreshRequest": {
"type": "object",
@@ -1406,6 +1584,22 @@
}
}
},
"AuthTokenResponse": {
"type": "object",
"description": "JWT token pair",
"properties": {
"accessToken": {
"type": "string"
},
"refreshToken": {
"type": "string"
}
},
"required": [
"accessToken",
"refreshToken"
]
},
"CallbackRequest": {
"type": "object",
"properties": {
@@ -1428,6 +1622,165 @@
}
}
},
"AgentRefreshRequest": {
"type": "object",
"description": "Agent token refresh request",
"properties": {
"refreshToken": {
"type": "string"
}
},
"required": [
"refreshToken"
]
},
"AgentRefreshResponse": {
"type": "object",
"description": "Refreshed access token",
"properties": {
"accessToken": {
"type": "string"
}
},
"required": [
"accessToken"
]
},
"CommandRequest": {
"type": "object",
"description": "Command to send to agent(s)",
"properties": {
"type": {
"type": "string",
"description": "Command type: config-update, deep-trace, or replay"
},
"payload": {
"type": "object",
"description": "Command payload JSON"
}
},
"required": [
"type"
]
},
"CommandSingleResponse": {
"type": "object",
"description": "Result of sending a command to a single agent",
"properties": {
"commandId": {
"type": "string"
},
"status": {
"type": "string"
}
},
"required": [
"commandId",
"status"
]
},
"AgentRegistrationRequest": {
"type": "object",
"description": "Agent registration payload",
"properties": {
"agentId": {
"type": "string"
},
"name": {
"type": "string"
},
"group": {
"type": "string",
"default": "default"
},
"version": {
"type": "string"
},
"routeIds": {
"type": "array",
"items": {
"type": "string"
}
},
"capabilities": {
"type": "object",
"additionalProperties": {
"type": "object"
}
}
},
"required": [
"agentId",
"name"
]
},
"AgentRegistrationResponse": {
"type": "object",
"description": "Agent registration result with JWT tokens and SSE endpoint",
"properties": {
"agentId": {
"type": "string"
},
"sseEndpoint": {
"type": "string"
},
"heartbeatIntervalMs": {
"type": "integer",
"format": "int64"
},
"serverPublicKey": {
"type": "string"
},
"accessToken": {
"type": "string"
},
"refreshToken": {
"type": "string"
}
},
"required": [
"accessToken",
"agentId",
"refreshToken",
"serverPublicKey",
"sseEndpoint"
]
},
"CommandBroadcastResponse": {
"type": "object",
"description": "Result of broadcasting a command to multiple agents",
"properties": {
"commandIds": {
"type": "array",
"items": {
"type": "string"
}
},
"targetCount": {
"type": "integer",
"format": "int32"
}
},
"required": [
"commandIds"
]
},
"OidcTestResult": {
"type": "object",
"description": "OIDC provider connectivity test result",
"properties": {
"status": {
"type": "string"
},
"authorizationEndpoint": {
"type": "string"
}
},
"required": [
"authorizationEndpoint",
"status"
]
},
"ExecutionStats": {
"type": "object",
"properties": {
@@ -1471,7 +1824,19 @@
"type": "integer",
"format": "int64"
}
}
},
"required": [
"activeCount",
"avgDurationMs",
"failedCount",
"p99LatencyMs",
"prevAvgDurationMs",
"prevFailedCount",
"prevP99LatencyMs",
"prevTotalCount",
"totalCount",
"totalToday"
]
},
"StatsTimeseries": {
"type": "object",
@@ -1482,7 +1847,10 @@
"$ref": "#/components/schemas/TimeseriesBucket"
}
}
}
},
"required": [
"buckets"
]
},
"TimeseriesBucket": {
"type": "object",
@@ -1511,7 +1879,15 @@
"type": "integer",
"format": "int64"
}
}
},
"required": [
"activeCount",
"avgDurationMs",
"failedCount",
"p99DurationMs",
"time",
"totalCount"
]
},
"ExecutionDetail": {
"type": "object",
@@ -1561,7 +1937,22 @@
"$ref": "#/components/schemas/ProcessorNode"
}
}
}
},
"required": [
"agentId",
"correlationId",
"diagramContentHash",
"durationMs",
"endTime",
"errorMessage",
"errorStackTrace",
"exchangeId",
"executionId",
"processors",
"routeId",
"startTime",
"status"
]
},
"ProcessorNode": {
"type": "object",
@@ -1595,9 +1986,171 @@
},
"errorStackTrace": {
"type": "string"
},
"children": {
"type": "array",
"items": {
"$ref": "#/components/schemas/ProcessorNode"
}
}
},
"required": [
"children",
"diagramNodeId",
"durationMs",
"endTime",
"errorMessage",
"errorStackTrace",
"processorId",
"processorType",
"startTime",
"status"
]
},
"DiagramLayout": {
"type": "object",
"properties": {
"width": {
"type": "number",
"format": "double"
},
"height": {
"type": "number",
"format": "double"
},
"nodes": {
"type": "array",
"items": {
"$ref": "#/components/schemas/PositionedNode"
}
},
"edges": {
"type": "array",
"items": {
"$ref": "#/components/schemas/PositionedEdge"
}
}
}
},
"PositionedEdge": {
"type": "object",
"properties": {
"sourceId": {
"type": "string"
},
"targetId": {
"type": "string"
},
"label": {
"type": "string"
},
"points": {
"type": "array",
"items": {
"type": "array",
"items": {
"type": "number",
"format": "double"
}
}
}
}
},
"PositionedNode": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"label": {
"type": "string"
},
"type": {
"type": "string"
},
"x": {
"type": "number",
"format": "double"
},
"y": {
"type": "number",
"format": "double"
},
"width": {
"type": "number",
"format": "double"
},
"height": {
"type": "number",
"format": "double"
}
}
},
"OidcPublicConfigResponse": {
"type": "object",
"description": "OIDC configuration for SPA login flow",
"properties": {
"issuer": {
"type": "string"
},
"clientId": {
"type": "string"
},
"authorizationEndpoint": {
"type": "string"
},
"endSessionEndpoint": {
"type": "string",
"description": "Present if the provider supports RP-initiated logout"
}
},
"required": [
"authorizationEndpoint",
"clientId",
"issuer"
]
},
"AgentInstanceResponse": {
"type": "object",
"description": "Agent instance summary",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"group": {
"type": "string"
},
"status": {
"type": "string"
},
"routeIds": {
"type": "array",
"items": {
"type": "string"
}
},
"registeredAt": {
"type": "string",
"format": "date-time"
},
"lastHeartbeat": {
"type": "string",
"format": "date-time"
}
},
"required": [
"group",
"id",
"lastHeartbeat",
"name",
"registeredAt",
"routeIds",
"status"
]
},
"SseEmitter": {
"type": "object",
"properties": {
@@ -1632,7 +2185,22 @@
"type": "string",
"format": "date-time"
}
}
},
"required": [
"createdAt",
"displayName",
"email",
"provider",
"roles",
"userId"
]
}
},
"securitySchemes": {
"bearer": {
"type": "http",
"scheme": "bearer",
"bearerFormat": "JWT"
}
}
}