# Taps, Business Attributes & Enhanced Replay — UI Design

## Context

The Cameleer agent now supports camel-native data extraction taps, business attributes on executions, enhanced replay with editable payloads, per-route recording toggles, and success compression. The agent-side implementation is deployed and live.

The shared models (`TapDefinition`, extended `ApplicationConfig` with `taps`, `tapVersion`, `routeRecording`, `compressSuccess`) exist in `cameleer-common` (agent repo). The server already depends on this library and persists `ApplicationConfig` as JSONB in the `application_config` table. However, the server-side execution DTOs (`ExecutionDetail`, `ExecutionSummary`, `ProcessorNode`) do not yet carry `attributes` fields, and the `CommandType` enum lacks `TEST_EXPRESSION`.

This spec covers all UI surfaces and the backend changes needed to support them.

## Design Decisions

| Decision | Choice | Rationale |
|----------|--------|-----------|
| Tap management location | RouteDetail contextual + AppConfigDetail overview | Taps target processors; processor list is contextual to a route. Admin overview for cross-route visibility. |
| Business attributes display | Header badges + per-processor + dashboard table | Primary value of taps — must be front-and-center for quick identification |
| Replay trigger | Button in ExchangeDetail header | Route-level action, clear and discoverable |
| Route recording location | RouteDetail toggle + AppConfigDetail bulk table | Contextual single-route control + centralized bulk management |
| Compress success | Badge in AppConfigDetail Settings section | Simple boolean toggle, admin-level concern |
| Expression testing | Agent-side evaluation via TEST_EXPRESSION command | Only the agent has the Camel expression engine; works for all languages |
| AppConfigDetail layout | 3 sections: Settings, Traces & Taps, Route Recording | Collapsed from 4 sections; Logging+Observability merged, TracedProcessors+Taps merged |

## Prerequisites

Before UI work can begin, the following backend changes are required:

1. **Update `cameleer-common` dependency** — ensure the server pulls a version that includes `TapDefinition`, and `ApplicationConfig` with `taps`, `tapVersion`, `routeRecording`, `compressSuccess` fields.
2. **Add `attributes` to execution DTOs** — `ExecutionDetail`, `ProcessorNode`, and `ExecutionSummary` need a `Map<String, String> attributes` field. This requires changes to the PostgreSQL ingestion pipeline (store attributes from agent-submitted `RouteExecution`/`ProcessorExecution`), the detail service (reconstruct attributes), and the OpenSearch indexing (index attributes for search results).
3. **Add `TEST_EXPRESSION` to `CommandType`** enum.
4. **Enhance `CommandAckRequest`** — add an optional `data` field (`String`, JSON) to carry structured results (currently only `status` + `message`). The test-expression endpoint needs the result value from the ACK.
5. **Regenerate `openapi.json`** after all backend REST API changes.

## Page Changes

### 1. ExchangeDetail

**Business attributes strip** between header info and stat boxes:
- Route-level attributes as auto-colored badges (`key: value`, monospace)
- Wraps on overflow
- Empty state: section not rendered when no attributes exist

**Per-processor attributes** in processor detail panel:
- Badges below processor info, before message IN/OUT sections
- Shows attributes extracted at that specific processor

**Replay button** in header action area (top-right), primary blue. Requires OPERATOR or ADMIN role:
- Opens large Modal with:
  - Warning banner ("This will re-execute the exchange on the selected agent")
  - Target Agent select — uses `useAgents(application, 'LIVE')` to populate. Disabled with message when no LIVE agents available.
  - Tabs: Headers (editable key-value table with add/remove) | Body (editable monospace textarea, JSON indicator)
  - Pre-populated from original exchange's `inputHeaders` and `inputBody` (already available on `ExecutionDetail`)
  - Cancel / Replay footer
- Sends REPLAY command via `POST /api/v1/agents/{agentId}/commands`
- Payload: `{ "type": "replay", "payload": { "headers": {...}, "body": "..." } }`
- Success: toast with confirmation message from ACK
- Failure: toast with error message
- Loading state: Replay button shows spinner while awaiting ACK

### 2. Dashboard Exchanges Table

**New "Attributes" column** between App and Exchange ID:
- First 2 attribute values as compact auto-colored badges (value only; key shown via native `title` attribute on hover)
- "+N" overflow indicator when more than 2
- Em-dash when no attributes

### 3. RouteDetail

**Recording toggle** in route header (top-right):
- Toggle in pill container with "Recording" label
- Updates `routeRecording` map in ApplicationConfig via PUT
- Requires OPERATOR or ADMIN role

**"Active Taps" KPI card** added to KPI strip.

**New "Taps" tab** (fourth tab alongside Performance, Recent Executions, Error Patterns):
- Header: "Data Extraction Taps" + "Add Tap" button (OPERATOR or ADMIN only)
- DataTable columns: Attribute, Processor, Expression, Language, Target, Type, Enabled (toggle), Actions (edit/delete)
- Add/edit opens tap modal
- Empty state: "No taps configured for this route. Add a tap to extract business attributes from exchange data."

**Add/Edit Tap modal** (Modal size="md"):
- Fields: Attribute Name (input), Processor (select from route diagram via `useDiagramLayout`), Language + Target (side-by-side selects), Expression (monospace textarea), Attribute Type (pill selector: BUSINESS_OBJECT / CORRELATION / EVENT / CUSTOM), Enabled toggle
- **Test Expression section** (collapsible, default expanded):
  - Tabs: "Recent Exchange" | "Custom Payload"
  - Recent Exchange: auto-selects most recent exchange with captured data at selected processor. Dropdown to change. Test button sends expression to live agent. Result display.
  - Custom Payload: editable textarea pre-populated from most recent exchange body. Switching from Recent Exchange carries the payload over. Test button → result display.
  - Result: green success box with extracted value, or red error box with message
  - Loading state: spinner on Test button while awaiting agent response
  - No agents state: "No LIVE agents available to test expression" with Test button disabled
  - Note showing which agent evaluated and which language was used
- Save / Cancel footer
- Save writes the tap to the `taps` array in ApplicationConfig via existing `PUT /api/v1/config/{application}`

### 4. AppConfigDetailPage

Restructured to **3 sections** (from 4):

**Section 1 — Settings:** Merged Logging + Observability. All settings as badges in flex row: Log Forwarding, Engine Level, Payload Capture, Metrics, Sampling Rate, Compress Success (new). Edit mode: badges become dropdowns/toggles.

**Section 2 — Traces & Taps:** Merged Traced Processors + Data Extraction Taps. Table columns: Route, Processor, Capture (badge or em-dash), Taps (attribute name badges with enabled/disabled indicator). Sorted by route. Capture editable in edit mode; taps read-only with "manage taps on route pages" hint. Summary: "N traced · M taps".

Processor-to-route mapping: Taps carry a `processorId` that belongs to a specific route. The route association is derived by cross-referencing with route diagram data (via `useDiagramLayout` per route from the route catalog). If a processor cannot be mapped to a route (e.g., route no longer active), show "unknown" in the Route column.

**Section 3 — Route Recording:** Table: Route + Recording toggle. Summary: "N of M routes recording". Toggles editable in edit mode. Route list from `useRouteCatalog` filtered by application. Routes not present in the `routeRecording` map default to recording enabled (consistent with agent behavior where absence = enabled).

### 5. AgentHealth Config Bar

No changes. New features managed at AppConfig level, not per-agent.

## RBAC Permissions

| Action | Minimum Role |
|--------|-------------|
| View business attributes | VIEWER |
| View taps / traces / recording state | VIEWER |
| Create / edit / delete taps | OPERATOR |
| Toggle route recording | OPERATOR |
| Edit app config settings | OPERATOR |
| Replay exchange | OPERATOR |
| Test expression | OPERATOR |

These align with the existing pattern where VIEWER sees data and OPERATOR can modify configuration.

## TypeScript Interface Changes

```typescript
// Add to ApplicationConfig in commands.ts
interface ApplicationConfig {
  // ... existing fields ...
  taps: TapDefinition[]
  tapVersion: number
  routeRecording: Record<string, boolean>
  compressSuccess: boolean
}

interface TapDefinition {
  tapId: string
  processorId: string
  target: 'INPUT' | 'OUTPUT' | 'BOTH'
  expression: string
  language: string
  attributeName: string
  attributeType: 'BUSINESS_OBJECT' | 'CORRELATION' | 'EVENT' | 'CUSTOM'
  enabled: boolean
  version: number
}
```

## Backend Changes

### New Endpoint: Test Expression

`POST /api/v1/config/{application}/test-expression`

Request:
```json
{
  "expression": "${body.orderId}",
  "language": "simple",
  "body": "{\"orderId\": \"ORD-123\"}",
  "target": "OUTPUT"
}
```

Response (success):
```json
{ "result": "ORD-123" }
```

Response (failure):
```json
{ "error": "Expression evaluation timed out (50ms limit)" }
```

**Request-reply mechanism:** The server selects a LIVE agent for the application, sends a `TEST_EXPRESSION` command via SSE, then awaits the ACK with a `CompletableFuture` (timeout 5s). The `CommandAckRequest` record is extended with an optional `data` field (JSON string) to carry the evaluation result. The controller completes the future when the ACK arrives, returning the result to the HTTP caller. If no LIVE agent is available or the timeout expires, the endpoint returns an appropriate error response.

### Replay Command Payload

The REPLAY command (already exists in `CommandType`) is sent via `POST /api/v1/agents/{agentId}/commands`:

```json
{
  "type": "replay",
  "payload": {
    "headers": {
      "Content-Type": "application/json",
      "X-Correlation-Id": "corr-abc123"
    },
    "body": "{\"orderId\": \"ORD-2024-78542\", ...}"
  }
}
```

The agent uses `ProducerTemplate.send()` to replay the exchange on the original route with the provided headers and body.

### Execution DTO Changes

**`ExecutionDetail`** — add `Map<String, String> attributes` (route-level aggregated)
**`ProcessorNode`** — add `Map<String, String> attributes` (per-processor)
**`ExecutionSummary`** — add `Map<String, String> attributes` (route-level, for dashboard table)

These require:
- PostgreSQL ingestion: store attributes from incoming `RouteExecution` and `ProcessorExecution` (the agent already sends them)
- Detail service: include attributes when reconstructing the execution tree
- OpenSearch indexing: index route-level attributes for search result enrichment

### CommandType Addition

Add `TEST_EXPRESSION` to the `CommandType` enum.

### CommandAckRequest Enhancement

Extend from `(String status, String message)` to `(String status, String message, String data)` where `data` is an optional JSON string for structured results.

## Design System Impact

No new components required. Uses existing: Modal, DataTable, Badge, Toggle, Select, Input, Textarea, FormField, Tabs, Button, CodeBlock, Collapsible.

## Files Touched

### Frontend (ui/src/)
- `api/queries/commands.ts` — TapDefinition interface, extend ApplicationConfig, add test-expression mutation, add replay mutation
- `pages/ExchangeDetail/ExchangeDetail.tsx` — attributes strip, per-processor attributes, replay button + modal
- `pages/ExchangeDetail/ExchangeDetail.module.css` — attributes strip styles, replay modal styles
- `pages/Dashboard/Dashboard.tsx` — attributes column in exchanges table
- `pages/Routes/RouteDetail.tsx` — recording toggle, active taps KPI, taps tab, tap modal with test section
- `pages/Routes/RouteDetail.module.css` — taps tab, recording toggle, tap modal styles
- `pages/Admin/AppConfigDetailPage.tsx` — restructure to 3 sections, traces & taps merged table, route recording table, compress success badge
- `pages/Admin/AppConfigDetailPage.module.css` — updated section styles

### Backend (cameleer-server-app/)
- `controller/ApplicationConfigController.java` — add test-expression endpoint
- `dto/CommandAckRequest.java` — add optional `data` field
- `controller/AgentCommandController.java` — support CompletableFuture-based ACK for test-expression

### Backend (cameleer-server-core/)
- `agent/CommandType.java` — add TEST_EXPRESSION
- `detail/ExecutionDetail.java` — add attributes field
- `detail/ProcessorNode.java` — add attributes field
- `search/ExecutionSummary.java` — add attributes field
- `detail/DetailService.java` — include attributes in reconstruction
- `storage/` — store attributes from ingested executions
- `search/SearchService.java` — include attributes in search results

### Generated
- `ui/src/api/schema.d.ts` — regenerate from openapi.json
- `openapi.json` — regenerate after backend changes
