- Add displayName field to AuthTokenResponse so the UI shows human-readable
names instead of internal JWT subjects (e.g. user:oidc:<hash>)
- Add displayNameClaim to OIDC config (default: "name") allowing admins to
configure which ID token claim contains the user's display name
- Support dot-separated claim paths (e.g. profile.display_name) like rolesClaim
- Add admin UI field for Display Name Claim on the OIDC config page
- ClickHouse migration: ALTER TABLE adds display_name_claim column
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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>
Backend: add autoSignup field to OidcConfig, ClickHouse schema, repository,
and admin controller. Gate OIDC login when auto-signup is disabled and user
is not pre-created (returns 403).
Frontend: add OIDC admin page with full CRUD (save/test/delete), role-gated
Admin nav link parsed from JWT, and matching design system styles.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
OIDC provider settings (issuer, client ID/secret, roles claim) are
now stored in ClickHouse and managed via admin REST API at
/api/v1/admin/oidc. This allows runtime configuration from the UI
without server restarts.
- New oidc_config table (ReplacingMergeTree, singleton row)
- OidcConfig record + OidcConfigRepository interface in core
- ClickHouseOidcConfigRepository implementation
- OidcConfigAdminController: GET/PUT/DELETE config, POST test
connectivity, client_secret masked in responses
- OidcTokenExchanger: reads config from DB, invalidateCache()
on config change
- OidcAuthController: always registered (no @ConditionalOnProperty),
returns 404 when OIDC not configured
- Startup seeder: env vars seed DB on first boot only, then admin
API takes over
- HOWTO.md updated with admin OIDC config API examples
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Implement three-phase security upgrade:
Phase 1 - RBAC: Extend JWT with roles claim, populate Spring
GrantedAuthority in filter, enforce role-based access (AGENT for
data/heartbeat/SSE, VIEWER+ for search/diagrams, OPERATOR+ for
commands, ADMIN for user management). Configurable JWT secret via
CAMELEER_JWT_SECRET env var for token persistence across restarts.
Phase 2 - User persistence: ClickHouse users table with
ReplacingMergeTree, UserRepository interface + ClickHouse impl,
UserAdminController for CRUD at /api/v1/admin/users. Local login
upserts user on each authentication.
Phase 3 - OIDC: Token exchange flow where SPA sends auth code,
server exchanges it server-side (keeping client_secret secure),
validates id_token via JWKS, resolves roles (DB override > OIDC
claim > default), issues internal JWT. Conditional on
CAMELEER_OIDC_ENABLED=true. Uses oauth2-oidc-sdk for standards
compliance.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
P99 latency and active count now use the same from/to parameters as the
timeseries sparklines, so all stat cards are consistent with the user's
selected time range.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New /search/stats/timeseries endpoint returns bucketed counts/metrics
over a time window using ClickHouse toStartOfInterval(). Frontend
Sparkline component renders SVG polyline + gradient fill on each
stat card, driven by a useStatsTimeseries query hook.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Status filter now parses comma-separated values into SQL IN clause
instead of exact match, so filtering by multiple statuses works.
Added GET /api/v1/search/stats returning P99 latency (last hour) and
active execution count, wired into the UI stat cards with 10s polling.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Propagate authenticated agent identity through write buffers via
TaggedExecution/TaggedDiagram wrappers so ClickHouse rows get real
agent IDs instead of empty strings
- Add execution_id to text search LIKE clause so selecting an execution
by ID in the palette actually finds it
- Clear status filter to all three statuses on palette selection so the
chosen execution/agent isn't filtered out
- Add disabled Routes and Exchanges scope tabs with "coming soon" state
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Backend: add routeId, agentId, processorType filter fields to SearchRequest
and ClickHouseSearchEngine. Expand global text search to match route_id and
agent_id columns.
Frontend: new command palette component (portal overlay, Zustand store,
TanStack Query search hook with 300ms debounce, filter chip parsing,
keyboard navigation, scope tabs). Search bar in SearchFilters and TopNav
now open the palette. Selecting a result writes filters to the execution
search store to drive the results table.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- SseConnectionManager with per-agent SseEmitter, ping keepalive, event delivery
- AgentSseController GET /{id}/events SSE endpoint with Last-Event-ID support
- AgentCommandController with single/group/broadcast command targeting + ack
- WebConfig excludes SSE events path from protocol version interceptor
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Implement findRawById and findProcessorSnapshot in ClickHouseExecutionRepository
- DetailController with GET /executions/{id} returning nested processor tree
- GET /executions/{id}/processors/{index}/snapshot for per-processor exchange data
- 5 unit tests for tree reconstruction (linear, branching, multiple roots, empty)
- 6 integration tests for detail endpoint, snapshot, and 404 handling
- Added assertj and mockito test dependencies to core module
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- ClickHouseSearchEngine with dynamic WHERE clause building and LIKE escape
- SearchController with GET (basic filters) and POST (advanced JSON body)
- SearchBeanConfig wiring SearchEngine, SearchService, DetailService beans
- 13 integration tests covering all filter types, combinations, pagination, empty results
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- ExecutionController: POST /api/v1/data/executions (single or array)
- DiagramController: POST /api/v1/data/diagrams (single or array)
- MetricsController: POST /api/v1/data/metrics (array)
- All return 202 Accepted or 503 with Retry-After when buffer full
- Fix duplicate IngestionConfig bean (remove @Configuration, use @EnableConfigurationProperties)
- Fix BackpressureIT timing by using batch POST and 60s flush interval
- All 11 integration tests green
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>