feat: migrate UI to @cameleer/design-system, add backend endpoints
Some checks failed
CI / build (push) Failing after 47s
CI / cleanup-branch (push) Has been skipped
CI / docker (push) Has been skipped
CI / deploy (push) Has been skipped
CI / deploy-feature (push) Has been skipped

Backend:
- Add agent_events table (V5) and lifecycle event recording
- Add route catalog endpoint (GET /routes/catalog)
- Add route metrics endpoint (GET /routes/metrics)
- Add agent events endpoint (GET /agents/events-log)
- Enrich AgentInstanceResponse with tps, errorRate, activeRoutes, uptimeSeconds
- Add TimescaleDB retention/compression policies (V6)

Frontend:
- Replace custom Mission Control UI with @cameleer/design-system components
- Rebuild all pages: Dashboard, ExchangeDetail, RoutesMetrics, AgentHealth,
  AgentInstance, RBAC, AuditLog, OIDC, DatabaseAdmin, OpenSearchAdmin, Swagger
- New LayoutShell with design system AppShell, Sidebar, TopBar, CommandPalette
- Consume design system from Gitea npm registry (@cameleer/design-system@0.0.1)
- Add .npmrc for scoped registry, update Dockerfile with REGISTRY_TOKEN arg

CI:
- Pass REGISTRY_TOKEN build-arg to UI Docker build step

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-03-19 17:38:39 +01:00
parent 82124c3145
commit 2b111c603c
150 changed files with 2750 additions and 21779 deletions

View File

@@ -0,0 +1,24 @@
package com.cameleer3.server.app.dto;
import com.cameleer3.server.core.agent.AgentEventRecord;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import java.time.Instant;
@Schema(description = "Agent lifecycle event")
public record AgentEventResponse(
@NotNull long id,
@NotNull String agentId,
@NotNull String appId,
@NotNull String eventType,
String detail,
@NotNull Instant timestamp
) {
public static AgentEventResponse from(AgentEventRecord record) {
return new AgentEventResponse(
record.id(), record.agentId(), record.appId(),
record.eventType(), record.detail(), record.timestamp()
);
}
}

View File

@@ -4,10 +4,11 @@ import com.cameleer3.server.core.agent.AgentInfo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import java.time.Duration;
import java.time.Instant;
import java.util.List;
@Schema(description = "Agent instance summary")
@Schema(description = "Agent instance summary with runtime metrics")
public record AgentInstanceResponse(
@NotNull String id,
@NotNull String name,
@@ -15,13 +16,29 @@ public record AgentInstanceResponse(
@NotNull String status,
@NotNull List<String> routeIds,
@NotNull Instant registeredAt,
@NotNull Instant lastHeartbeat
@NotNull Instant lastHeartbeat,
double tps,
double errorRate,
int activeRoutes,
int totalRoutes,
long uptimeSeconds
) {
public static AgentInstanceResponse from(AgentInfo info) {
long uptime = Duration.between(info.registeredAt(), Instant.now()).toSeconds();
return new AgentInstanceResponse(
info.id(), info.name(), info.group(),
info.state().name(), info.routeIds(),
info.registeredAt(), info.lastHeartbeat()
info.registeredAt(), info.lastHeartbeat(),
0.0, 0.0,
0, info.routeIds() != null ? info.routeIds().size() : 0,
uptime
);
}
public AgentInstanceResponse withMetrics(double tps, double errorRate, int activeRoutes) {
return new AgentInstanceResponse(
id, name, group, status, routeIds, registeredAt, lastHeartbeat,
tps, errorRate, activeRoutes, totalRoutes, uptimeSeconds
);
}
}

View File

@@ -0,0 +1,12 @@
package com.cameleer3.server.app.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
@Schema(description = "Summary of an agent instance for sidebar display")
public record AgentSummary(
@NotNull String id,
@NotNull String name,
@NotNull String status,
@NotNull double tps
) {}

View File

@@ -0,0 +1,16 @@
package com.cameleer3.server.app.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import java.util.List;
@Schema(description = "Application catalog entry with routes and agents")
public record AppCatalogEntry(
@NotNull String appId,
@NotNull List<RouteSummary> routes,
@NotNull List<AgentSummary> agents,
@NotNull int agentCount,
@NotNull String health,
@NotNull long exchangeCount
) {}

View File

@@ -0,0 +1,19 @@
package com.cameleer3.server.app.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import java.util.List;
@Schema(description = "Aggregated route performance metrics")
public record RouteMetrics(
@NotNull String routeId,
@NotNull String appId,
@NotNull long exchangeCount,
@NotNull double successRate,
@NotNull double avgDurationMs,
@NotNull double p99DurationMs,
@NotNull double errorRate,
@NotNull double throughputPerSec,
@NotNull List<Double> sparkline
) {}

View File

@@ -0,0 +1,13 @@
package com.cameleer3.server.app.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import java.time.Instant;
@Schema(description = "Summary of a route within an application")
public record RouteSummary(
@NotNull String routeId,
@NotNull long exchangeCount,
Instant lastSeen
) {}