DetailPanel is a flex sibling that slides in from the right — it must
be rendered at the AppShell level via the detail prop, not inside the
page content. Add DetailPanelContext so pages can push their panel
content up to LayoutShell, which passes it to AppShell.detail.
Applied to Dashboard (exchange detail) and AgentHealth (instance detail).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Upgrade @cameleer/design-system to ^0.1.3 which adds LIVE/PAUSED
toggle to TopBar backed by autoRefresh state in GlobalFilterProvider.
Add useRefreshInterval() hook that returns the polling interval when
auto-refresh is on, or false when paused. Wire it into all query
hooks that use refetchInterval (executions, catalog, agents, metrics,
admin database/opensearch).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
OpenSearch dynamically maps string fields as text with a .keyword
subfield. Sorting on text fields throws an error; only .keyword,
date, and numeric fields support sorting. Add .keyword suffix to
all string sort columns (status, routeId, agentId, executionId,
correlationId, applicationName) while keeping start_time and
duration_ms as-is.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add application_name filter to OpenSearch query builder — sidebar
app selection now correctly filters the exchange list. The
application field was being resolved to agentIds in the controller
but never applied as a query filter in OpenSearch.
Also restore snake_case sort column mapping since the OpenSearch
toMap() serializer uses snake_case field names (start_time, route_id,
etc.), not camelCase.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add executionId and applicationName to allowed sort fields. Fix sort
column mapping to use camelCase field names matching the OpenSearch
ExecutionDocument fields instead of snake_case DB column names. This
was causing sorts on most columns to either silently fall back to
startTime or return empty results from OpenSearch.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Upgrade @cameleer/design-system to v0.1.1 which adds onSortChange
callback to DataTable. Wire it up in Dashboard (exchanges), AuditLog,
and RouteDetail (recent executions) so sorting triggers a new API
request with sortField/sortDir instead of only sorting the current page.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace inline styles with CSS module matching the design system's
LoginForm visual patterns. Uses proper DS class structure (divider,
social section, form fields) while keeping username-based auth
instead of the DS component's email validation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Migrate all page components from the @cameleer/design-system v0.0.3
example UI, replacing mock data with real backend API hooks. This brings
richer visuals (KpiStrip, GroupCard, RouteFlow, ProcessorTimeline,
DateRangePicker, expandable rows) while preserving all existing API
integration, auth, and routing infrastructure.
Pages migrated: Dashboard, RoutesMetrics, RouteDetail, ExchangeDetail,
AgentHealth, AgentInstance, OidcConfig, AuditLog, RBAC (Users/Groups/Roles).
Also enhanced LayoutShell CommandPalette with real search data from catalog.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add engine_level, input_body, output_body, input_headers, output_headers
to the executions INSERT/SELECT/UPSERT and row mapper. Required for
REGULAR mode where route-level payloads exist but no processor records.
Note: requires ALTER TABLE migration to add the new columns.
Extract inputBody/outputBody/inputHeaders/outputHeaders from RouteExecution
snapshots and pass to ExecutionRecord. Maps engineLevel field. Critical for
REGULAR mode where no processor records exist but route-level payloads do.
Adds engineLevel (NONE/MINIMAL/REGULAR/COMPLETE) and inputBody/outputBody/
inputHeaders/outputHeaders to ExecutionRecord so REGULAR mode route-level
payloads are persisted (previously only processor-level records had payloads).
- Add @RequestBody(required=false) CommandAckRequest to ack endpoint for
receiving agent command results (backward compat with old agents)
- Record command results in agent event log via AgentEventService
- Add set-traced-processors to mapCommandType switch
- Inject AgentEventService dependency
Complete the group→application terminology rename in the agent
registry subsystem:
- AgentInfo: field group → application, all wither methods updated
- AgentRegistryService: findByGroup → findByApplication
- AgentInstanceResponse: field group → application (API response)
- AgentRegistrationRequest: field group → application (API request)
- JwtServiceImpl: parameter names group → application (JWT claim
string "group" preserved for token backward compatibility)
- All controllers, lifecycle monitor, command controller updated
- Integration tests: JSON request bodies "group" → "application"
- Frontend: schema.d.ts, openapi.json, agent queries, AgentHealth
RBAC group references (groups table, GroupAdminController, etc.)
are NOT affected — they are a separate domain concept.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The stats endpoint was calling statsForRoute(null, agentIds) when
only application was set — this filtered by route_id=null, returning
zero results. Now correctly routes to statsForApp/timeseriesForApp
which queries the stats_1m_app continuous aggregate by application_name.
Also reverts the group parameter alias workaround — the deployed
backend correctly accepts 'application'.
Three code paths now:
- No filters → stats_1m_all (global)
- application only → stats_1m_app (per-app)
- routeId (±application) → stats_1m_route (per-route)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The backend was renamed from group→application but Docker build cache
may serve old code. Accept 'group' as a fallback alias so the UI works
with both old and new backends. Applies to GET /search/executions,
/search/stats, and /search/stats/timeseries.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Split pane: card layout with border, border-radius, box-shadow
matching mock's bordered panel look
- List pane: bg-surface background, padded header with border-bottom
- Entity items: border-bottom separators instead of gap spacing,
flex-start alignment for multi-line content
- Detail pane: bg-surface background, 20px padding, right border-radius
- User meta line: show email + group path (like mock's "email · group")
- Create form: raised background with bottom border
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add AdminLayout wrapper with Tabs component for navigating between
admin sections: User Management, Audit Log, OIDC, Database, OpenSearch.
Nest all /admin/* routes under AdminLayout using React Router's
Outlet pattern so the tab bar persists across admin page navigation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Loading fonts from fonts.googleapis.com sends user IP addresses to
Google on every page load — a GDPR violation. Self-host DM Sans and
JetBrains Mono as woff2 files bundled with the UI.
- Download DM Sans (400/500/600/700 + 400 italic) woff2 files
- Download JetBrains Mono (400/500/600) woff2 files
- Replace @import url(googleapis) with local @font-face declarations
- Both fonts are OFL-licensed (free to self-host)
- Total size: ~135KB for all 8 font files
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Two places in Dashboard used toISOString() for display, which always
renders UTC. Changed to toLocaleString() for the user's local timezone.
- Exchanges table "Started" column
- Detail panel "Timestamp" field
API query parameters correctly continue using toISOString() (UTC).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
PostgreSQL JDBC driver can't infer SQL type for java.time.Instant.
Convert from/to parameters to java.sql.Timestamp before binding.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- DetailPanel: switch from tabs to flat children layout (fixes stale
tab state bug), add position:fixed override, key on agent id
- Stat strip: colored status breakdown (live/stale/dead), msg/s detail
on TPS, "requires attention" on dead count
- Scope trail: simplified to "X/Y live" label
- Event card header: rename "Event Log" to "Timeline" with count badge
- Remove unused Breadcrumb, scopeItems, groupHealth
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use browser default locale instead of hardcoded 'en-US' and 'en-GB'
for number and time formatting.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
TimescaleDB add_continuous_aggregate_policy and add_compression_policy
cannot run inside a transaction block. Move all policy calls to V2
with flyway:executeInTransaction=false directive.
Also fix stats_1m_processor_detail: add WITH NO DATA and
materialized_only = false.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The render endpoint returns a union type (SVG string | JSON object).
Cast to DiagramLayout interface so .nodes is accessible. Also rename
useDiagramByRoute parameter from group to application.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Consolidate V1-V7 Flyway migrations into single V1__init.sql with
all columns renamed from group_name to application_name. Requires
fresh database (wipe flyway_schema_history, all data).
- DB columns: executions.group_name → application_name,
processor_executions.group_name → application_name
- Continuous aggregates: all views updated to use application_name
- OpenSearch field: group_name → application_name in index/query
- All Java SQL strings updated to match new column names
- Delete V2-V7 migration files (folded into V1)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The execution-related "group" concept actually represents the
application name. Rename all Java fields, API parameters, and frontend
types from groupName→applicationName and group→application for clarity.
- Java records: ExecutionSummary, ExecutionDetail, ExecutionDocument,
ExecutionRecord, ProcessorRecord
- API params: SearchRequest.group→application, SearchController
@RequestParam group→application
- Services: IngestionService, DetailService, SearchIndexer, StatsStore
- Frontend: schema.d.ts, Dashboard, ExchangeDetail, RouteDetail,
executions query hooks
Database column names (group_name) and OpenSearch field names are
unchanged — only the API-facing Java/TS field names are renamed.
RBAC group references (groups table, GroupRepository, GroupsTab) are
a separate domain concept and are NOT affected by this change.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The deployed backend doesn't return groupName on ExecutionDetail or
ExecutionSummary (Docker build cache issue). Switch diagram lookup to
use diagramContentHash which is always available in the detail response.
- Dashboard: useDiagramLayout(detail.diagramContentHash) instead of
useDiagramByRoute(groupName, routeId)
- ExchangeDetail: same change
Route Flow now renders correctly in both the slide-in panel and the
full exchange detail page.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The Java record was updated but the OpenAPI schema was not regenerated,
causing a TypeScript build error in CI.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add groupName field to ExecutionDetail record and DetailService
- Dashboard: fix TDZ error (rows referenced before definition), add
selectedRow fallback for diagram groupName lookup
- ExchangeDetail: rewrite to match mock layout — auto-select first
processor, Message IN/OUT split panels with header key-value rows,
error panel for failed processors, Timeline/Flow toggle buttons
- Track diagram-mapping utility (was untracked, caused CI build failure)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Only render DetailPanel when detail data is loaded (key={selectedId} forces remount
so internal activeTab state resets correctly)
- Override DetailPanel CSS with position:fixed to overlay on right side
(AppShell layout doesn't support detail prop from child pages)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Added groupName field to ExecutionSummary Java record and OpenSearch mapper
- Dashboard stat cards use locale-formatted numbers (en-US)
- Added inspect column (↗) linking directly to exchange detail page
- Fixed duplicate React key warning from two columns sharing executionId key
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Dashboard: correct stat card labels (Exchanges/Success Rate/Errors/Throughput/Latency p99),
add detail text, trends, sparklines on all cards, Agent column, LIVE badge,
expanded detail panel with Agent/Correlation/Timestamp, "Open full details" link.
Agent Health: per-group meta (TPS/routes) in GroupCard header, proper HTML table
with column headers for instance list.
Agent Instance: stat card detail props (heap info, start date), scope trail with
inline status/version/routes badges.
Routes: 5th In-Flight stat card, enriched stat card props (detail/trend/sparkline),
SLA threshold line on latency chart.
Exchange Detail: Agent stat box in header.
Also: vite proxy CORS fix, cross-env dev scripts.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>