Files
design-system/ui-mocks/mock-v3-exchange-detail.html

1946 lines
67 KiB
HTML
Raw Normal View History

<!--
============================================================================
CAMELEER3 v3 — Exchange / Message Inspector (Light Theme)
============================================================================
DESIGN NOTES
============
PURPOSE:
This is the deepest drill-down view in Cameleer3 — the Exchange Inspector.
A developer arrives here after clicking a failed execution row in the
Operations Dashboard (mock-v2). The page answers the #1 question:
"What happened to my message as it flowed through the route?"
LAYOUT:
Two-region layout inside the standard sidebar + main shell:
1. Exchange Header Card — identity, status, timing at a glance
2. Processor Timeline — Gantt-style horizontal bars showing where time was spent
3. Processor Detail Panel — split IN / OUT columns with headers, body, diffs
4. Properties & Correlation — collapsible bottom section
DATA SCENARIO:
Order OP-88421 entered via direct:order-intake, passed validation, DB insert,
priority check, then FAILED at http:payment-api/charge with a 503 timeout
after 2m 18s. The payment-api processor consumed 94% of total wall time.
DESIGN SYSTEM:
Inherits 100% from mock-v2-light.html — same CSS variables, fonts, sidebar,
topbar. No new colors or typefaces introduced.
OPTIMIZED FOR: 1920x1080, Chrome/Firefox/Edge
============================================================================
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=1920">
<title>Cameleer3 — Exchange OP-88421</title>
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,300;0,9..40,400;0,9..40,500;0,9..40,600;0,9..40,700&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
/* ==========================================================================
RESET & FOUNDATIONS (identical to mock-v2)
========================================================================== */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
/* Surface palette (warm parchment) */
--bg-body: #F5F2ED;
--bg-surface: #FFFFFF;
--bg-raised: #FAF8F5;
--bg-inset: #F0EDE8;
--bg-hover: #F5F0EA;
/* Sidebar (warm charcoal) */
--sidebar-bg: #2C2520;
--sidebar-hover: #3A322C;
--sidebar-active: #4A3F38;
--sidebar-text: #BFB5A8;
--sidebar-muted: #7A6F63;
/* Text */
--text-primary: #1A1612;
--text-secondary: #5C5347;
--text-muted: #9C9184;
--text-faint: #C4BAB0;
/* Borders */
--border: #E4DFD8;
--border-subtle: #EDE9E3;
/* Brand accent (amber-gold) */
--amber: #C6820E;
--amber-light: #F0D9A8;
--amber-bg: #FDF6E9;
--amber-deep: #8B5A06;
/* Status colors (warm) */
--success: #3D7C47;
--success-bg: #EFF7F0;
--success-border: #C2DFC6;
--warning: #C27516;
--warning-bg: #FEF5E7;
--warning-border: #F0D9A8;
--error: #C0392B;
--error-bg: #FDF0EE;
--error-border: #F0C4BE;
--running: #1A7F8E;
--running-bg: #E8F5F7;
--running-border: #B0DDE4;
/* Typography */
--font-body: 'DM Sans', system-ui, -apple-system, sans-serif;
--font-mono: 'JetBrains Mono', 'Fira Code', monospace;
/* Spacing & Radii */
--radius-sm: 5px;
--radius-md: 8px;
--radius-lg: 12px;
/* Shadows */
--shadow-sm: 0 1px 2px rgba(44, 37, 32, 0.06);
--shadow-md: 0 2px 8px rgba(44, 37, 32, 0.08);
--shadow-lg: 0 4px 16px rgba(44, 37, 32, 0.10);
--shadow-card: 0 1px 3px rgba(44, 37, 32, 0.04), 0 0 0 1px rgba(44, 37, 32, 0.04);
}
html { font-size: 14px; }
body {
font-family: var(--font-body);
background: var(--bg-body);
color: var(--text-primary);
line-height: 1.5;
min-height: 100vh;
-webkit-font-smoothing: antialiased;
}
::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }
::-webkit-scrollbar-thumb:hover { background: var(--text-faint); }
/* ==========================================================================
ANIMATIONS
========================================================================== */
@keyframes fadeIn {
from { opacity: 0; transform: translateY(6px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes errorPulse {
0%, 100% { box-shadow: 0 0 0 0 rgba(192, 57, 43, 0.2); }
50% { box-shadow: 0 0 0 4px rgba(192, 57, 43, 0); }
}
.animate-in { animation: fadeIn 0.3s ease-out both; }
.delay-1 { animation-delay: 0.04s; }
.delay-2 { animation-delay: 0.08s; }
.delay-3 { animation-delay: 0.12s; }
.delay-4 { animation-delay: 0.16s; }
.delay-5 { animation-delay: 0.20s; }
/* ==========================================================================
LAYOUT
========================================================================== */
.app {
display: flex;
height: 100vh;
overflow: hidden;
}
/* ==========================================================================
SIDEBAR (220px, warm charcoal — identical to mock-v2)
========================================================================== */
.sidebar {
width: 220px;
flex-shrink: 0;
background: var(--sidebar-bg);
display: flex;
flex-direction: column;
overflow: hidden;
}
.sidebar-logo {
padding: 16px 18px;
display: flex;
align-items: center;
gap: 10px;
border-bottom: 1px solid rgba(255,255,255,0.06);
}
.sidebar-logo .brand {
font-family: var(--font-mono);
font-weight: 600;
font-size: 15px;
color: var(--amber-light);
letter-spacing: -0.3px;
}
.sidebar-logo .version {
font-family: var(--font-mono);
font-size: 10px;
color: var(--sidebar-muted);
margin-left: 2px;
}
.sidebar-search { padding: 10px 12px; }
.sidebar-search input {
width: 100%;
background: rgba(255,255,255,0.06);
border: 1px solid rgba(255,255,255,0.08);
border-radius: var(--radius-sm);
padding: 6px 10px 6px 28px;
color: var(--sidebar-text);
font-family: var(--font-body);
font-size: 12px;
outline: none;
transition: border-color 0.15s;
}
.sidebar-search input::placeholder { color: var(--sidebar-muted); }
.sidebar-search input:focus { border-color: rgba(198, 130, 14, 0.4); }
.sidebar-search-wrap { position: relative; }
.sidebar-search-wrap .search-icon {
position: absolute;
left: 9px;
top: 50%;
transform: translateY(-50%);
color: var(--sidebar-muted);
font-size: 12px;
}
.sidebar-section {
padding: 14px 12px 5px;
font-size: 10px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 1.2px;
color: var(--sidebar-muted);
}
.sidebar-items {
flex: 1;
overflow-y: auto;
padding: 0 6px;
}
.sidebar-item {
display: flex;
align-items: center;
gap: 10px;
padding: 7px 12px;
border-radius: var(--radius-sm);
color: var(--sidebar-text);
font-size: 13px;
cursor: pointer;
transition: all 0.12s;
text-decoration: none;
border-left: 3px solid transparent;
margin-bottom: 1px;
}
.sidebar-item:hover { background: var(--sidebar-hover); color: #E8DFD4; }
.sidebar-item.active { background: var(--sidebar-active); color: var(--amber-light); border-left-color: var(--amber); }
.sidebar-item .health { width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0; }
.health-live { background: #5DB866; box-shadow: 0 0 6px rgba(93, 184, 102, 0.4); }
.health-stale { background: var(--warning); }
.sidebar-item .item-info { flex: 1; min-width: 0; }
.sidebar-item .item-name { font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sidebar-item .item-meta { font-size: 11px; color: var(--sidebar-muted); font-family: var(--font-mono); }
.sidebar-item .item-count {
font-family: var(--font-mono);
font-size: 11px;
color: var(--sidebar-muted);
background: rgba(255,255,255,0.06);
padding: 1px 6px;
border-radius: 10px;
}
.sidebar-item.active .item-count { background: rgba(198, 130, 14, 0.2); color: var(--amber-light); }
.sidebar-divider {
height: 1px;
background: rgba(255,255,255,0.06);
margin: 6px 12px;
}
.sidebar-agents-header {
padding: 14px 12px 6px;
font-size: 10px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 1.2px;
color: var(--sidebar-muted);
display: flex;
align-items: center;
justify-content: space-between;
}
.sidebar-agent-badge {
font-family: var(--font-mono);
font-size: 10px;
padding: 1px 6px;
border-radius: 10px;
background: rgba(93, 184, 102, 0.15);
color: #5DB866;
}
.agent-item {
display: flex;
align-items: center;
gap: 8px;
padding: 6px 12px;
margin: 0 6px 2px;
border-radius: var(--radius-sm);
font-size: 11px;
color: var(--sidebar-text);
transition: background 0.1s;
}
.agent-item:hover { background: var(--sidebar-hover); }
.agent-dot { width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0; }
.agent-info { flex: 1; min-width: 0; }
.agent-name { font-family: var(--font-mono); font-size: 11px; font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.agent-detail { font-size: 10px; color: var(--sidebar-muted); }
.agent-stats-col { text-align: right; font-family: var(--font-mono); font-size: 10px; color: var(--sidebar-muted); }
.agent-tps { color: var(--sidebar-text); }
.sidebar-bottom {
border-top: 1px solid rgba(255,255,255,0.06);
padding: 6px;
}
.sidebar-bottom .sidebar-item { font-size: 12px; color: var(--sidebar-muted); border-left: 3px solid transparent; }
.sidebar-bottom .sidebar-item:hover { color: var(--sidebar-text); }
/* ==========================================================================
MAIN CONTENT AREA
========================================================================== */
.main {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
min-width: 0;
}
/* Top bar */
.topbar {
display: flex;
align-items: center;
gap: 12px;
padding: 0 24px;
height: 48px;
flex-shrink: 0;
background: var(--bg-surface);
border-bottom: 1px solid var(--border);
}
.topbar-breadcrumb {
display: flex;
align-items: center;
gap: 6px;
font-size: 13px;
color: var(--text-muted);
}
.topbar-breadcrumb .crumb-link {
color: var(--text-muted);
text-decoration: none;
cursor: pointer;
transition: color 0.12s;
}
.topbar-breadcrumb .crumb-link:hover { color: var(--amber); }
.topbar-breadcrumb .crumb-active { color: var(--text-primary); font-weight: 600; }
.topbar-breadcrumb .crumb-sep { color: var(--text-faint); font-size: 11px; }
.topbar-right {
margin-left: auto;
display: flex;
align-items: center;
gap: 12px;
}
.topbar-env {
font-family: var(--font-mono);
font-size: 10px;
font-weight: 600;
padding: 3px 10px;
border-radius: 10px;
background: var(--success-bg);
color: var(--success);
border: 1px solid var(--success-border);
text-transform: uppercase;
letter-spacing: 0.5px;
}
.topbar-user {
display: flex;
align-items: center;
gap: 8px;
font-size: 12px;
color: var(--text-secondary);
}
.topbar-avatar {
width: 28px;
height: 28px;
border-radius: 50%;
background: var(--amber-bg);
color: var(--amber);
font-weight: 600;
font-size: 11px;
display: flex;
align-items: center;
justify-content: center;
border: 1px solid var(--amber-light);
}
/* Content scroll container */
.content {
flex: 1;
overflow-y: auto;
padding: 20px 24px 40px;
min-width: 0;
}
/* ==========================================================================
STATUS BADGES (reused from mock-v2)
========================================================================== */
.status-badge {
display: inline-flex;
align-items: center;
gap: 5px;
padding: 2px 10px;
border-radius: 12px;
font-size: 11px;
font-weight: 600;
letter-spacing: 0.2px;
}
.status-success { background: var(--success-bg); color: var(--success); border: 1px solid var(--success-border); }
.status-error { background: var(--error-bg); color: var(--error); border: 1px solid var(--error-border); }
.status-dot { width: 5px; height: 5px; border-radius: 50%; background: currentColor; }
/* ==========================================================================
EXCHANGE HEADER CARD
========================================================================== */
.exchange-header {
background: var(--bg-surface);
border: 1px solid var(--border-subtle);
border-radius: var(--radius-lg);
padding: 18px 22px;
box-shadow: var(--shadow-card);
margin-bottom: 16px;
border-left: 4px solid var(--error);
}
.exchange-header-top {
display: flex;
align-items: flex-start;
justify-content: space-between;
margin-bottom: 14px;
}
.exchange-title-area {
display: flex;
align-items: center;
gap: 12px;
}
.exchange-route {
font-size: 18px;
font-weight: 700;
color: var(--text-primary);
}
.exchange-status-lg {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 4px 14px;
border-radius: 16px;
font-size: 12px;
font-weight: 700;
letter-spacing: 0.3px;
text-transform: uppercase;
background: var(--error-bg);
color: var(--error);
border: 1px solid var(--error-border);
animation: errorPulse 2.5s ease-in-out infinite;
}
.exchange-status-lg .status-dot { width: 6px; height: 6px; }
.exchange-actions {
display: flex;
gap: 6px;
}
.action-btn {
display: inline-flex;
align-items: center;
gap: 5px;
padding: 5px 12px;
border: 1px solid var(--border);
border-radius: var(--radius-sm);
background: var(--bg-surface);
color: var(--text-secondary);
font-family: var(--font-body);
font-size: 11px;
font-weight: 500;
cursor: pointer;
transition: all 0.12s;
}
.action-btn:hover {
border-color: var(--text-faint);
background: var(--bg-raised);
color: var(--text-primary);
}
.action-btn.primary {
background: var(--amber-bg);
border-color: var(--amber-light);
color: var(--amber-deep);
}
.action-btn.primary:hover {
background: var(--amber-light);
}
.exchange-meta-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 0;
border-top: 1px solid var(--border-subtle);
padding-top: 14px;
}
.meta-item {
padding: 0 16px;
border-right: 1px solid var(--border-subtle);
}
.meta-item:first-child { padding-left: 0; }
.meta-item:last-child { border-right: none; }
.meta-label {
font-size: 10px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.6px;
color: var(--text-muted);
margin-bottom: 3px;
}
.meta-value {
font-family: var(--font-mono);
font-size: 12px;
font-weight: 500;
color: var(--text-primary);
}
.meta-value.mono-sm {
font-size: 11px;
color: var(--text-secondary);
word-break: break-all;
}
.meta-value .biz-tag {
display: inline-flex;
align-items: center;
gap: 4px;
padding: 1px 8px;
border-radius: 10px;
font-size: 11px;
font-weight: 500;
margin-right: 6px;
}
.biz-tag.order { background: var(--running-bg); color: var(--running); border: 1px solid var(--running-border); }
.biz-tag.customer { background: var(--amber-bg); color: var(--amber-deep); border: 1px solid var(--amber-light); }
.meta-value .duration-lg {
font-size: 16px;
font-weight: 700;
color: var(--error);
}
.meta-value .duration-label {
font-size: 11px;
color: var(--text-muted);
font-weight: 400;
margin-left: 4px;
}
.meta-sub {
font-size: 10px;
color: var(--text-muted);
font-family: var(--font-mono);
margin-top: 2px;
}
/* ==========================================================================
PROCESSOR TIMELINE (Gantt-style)
========================================================================== */
.timeline-section {
background: var(--bg-surface);
border: 1px solid var(--border-subtle);
border-radius: var(--radius-lg);
box-shadow: var(--shadow-card);
margin-bottom: 16px;
overflow: hidden;
}
.timeline-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px 18px;
border-bottom: 1px solid var(--border-subtle);
}
.timeline-title {
font-size: 13px;
font-weight: 600;
color: var(--text-primary);
display: flex;
align-items: center;
gap: 8px;
}
.timeline-title .proc-count {
font-family: var(--font-mono);
font-size: 10px;
padding: 1px 8px;
border-radius: 10px;
background: var(--bg-inset);
color: var(--text-muted);
}
.timeline-legend {
display: flex;
gap: 14px;
font-size: 11px;
color: var(--text-muted);
}
.legend-item {
display: flex;
align-items: center;
gap: 5px;
}
.legend-dot {
width: 8px;
height: 8px;
border-radius: 2px;
}
.legend-dot.l-success { background: var(--success); }
.legend-dot.l-error { background: var(--error); }
.legend-dot.l-slow { background: var(--warning); }
.timeline-body {
padding: 6px 0;
}
.timeline-row {
display: grid;
grid-template-columns: 260px 1fr 80px 32px;
align-items: center;
padding: 6px 18px;
gap: 12px;
cursor: pointer;
transition: background 0.08s;
border-left: 3px solid transparent;
}
.timeline-row:hover { background: var(--bg-hover); }
.timeline-row.selected { background: var(--amber-bg); border-left-color: var(--amber); }
.timeline-row.row-error { border-left-color: var(--error); }
.timeline-row.row-error.selected { border-left-color: var(--error); background: var(--error-bg); }
.proc-label {
display: flex;
align-items: center;
gap: 8px;
font-size: 12px;
min-width: 0;
}
.proc-index {
font-family: var(--font-mono);
font-size: 10px;
font-weight: 600;
color: var(--text-faint);
width: 18px;
text-align: right;
flex-shrink: 0;
}
.proc-type {
font-family: var(--font-mono);
font-size: 10px;
font-weight: 500;
padding: 1px 6px;
border-radius: 3px;
background: var(--bg-inset);
color: var(--text-muted);
flex-shrink: 0;
}
.proc-type.type-from { background: var(--running-bg); color: var(--running); }
.proc-type.type-to { background: var(--amber-bg); color: var(--amber-deep); }
.proc-type.type-process { background: var(--success-bg); color: var(--success); }
.proc-type.type-choice { background: #F3EFF8; color: #6B4FA0; }
.proc-name {
font-weight: 500;
color: var(--text-primary);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.proc-bar-area {
position: relative;
height: 20px;
background: var(--bg-inset);
border-radius: 3px;
overflow: hidden;
}
.proc-bar {
height: 100%;
border-radius: 3px;
min-width: 3px;
transition: width 0.3s ease;
position: relative;
}
.proc-bar.bar-success { background: linear-gradient(90deg, var(--success), #5DB866); }
.proc-bar.bar-error { background: linear-gradient(90deg, var(--error), #E74C3C); }
.proc-bar.bar-slow { background: linear-gradient(90deg, var(--warning), #E8A838); }
.proc-bar .bar-pct {
position: absolute;
right: 6px;
top: 50%;
transform: translateY(-50%);
font-family: var(--font-mono);
font-size: 9px;
font-weight: 600;
color: white;
text-shadow: 0 1px 2px rgba(0,0,0,0.3);
}
.proc-duration {
font-family: var(--font-mono);
font-size: 11px;
font-weight: 500;
color: var(--text-secondary);
text-align: right;
}
.proc-duration.dur-error { color: var(--error); font-weight: 600; }
.proc-status-icon {
font-size: 14px;
text-align: center;
}
.proc-status-icon.icon-ok { color: var(--success); }
.proc-status-icon.icon-fail { color: var(--error); }
/* Bottleneck callout */
.bottleneck-callout {
display: flex;
align-items: center;
gap: 8px;
margin: 4px 18px 10px;
padding: 8px 14px;
background: var(--error-bg);
border: 1px solid var(--error-border);
border-left: 3px solid var(--error);
border-radius: var(--radius-sm);
font-size: 12px;
color: var(--error);
}
.bottleneck-callout strong { font-weight: 700; }
.bottleneck-pct {
font-family: var(--font-mono);
font-weight: 700;
font-size: 14px;
}
/* ==========================================================================
PROCESSOR DETAIL PANEL (split IN / OUT)
========================================================================== */
.detail-split {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 16px;
margin-bottom: 16px;
}
.detail-panel {
background: var(--bg-surface);
border: 1px solid var(--border-subtle);
border-radius: var(--radius-lg);
box-shadow: var(--shadow-card);
overflow: hidden;
}
.detail-panel.panel-error {
border-color: var(--error-border);
}
.detail-panel-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 10px 16px;
border-bottom: 1px solid var(--border-subtle);
background: var(--bg-raised);
}
.detail-panel.panel-error .detail-panel-header {
background: var(--error-bg);
border-bottom-color: var(--error-border);
}
.panel-title {
font-size: 12px;
font-weight: 600;
color: var(--text-primary);
display: flex;
align-items: center;
gap: 6px;
}
.panel-title .arrow-in { color: var(--success); }
.panel-title .arrow-out { color: var(--error); }
.panel-tag {
font-family: var(--font-mono);
font-size: 10px;
padding: 1px 6px;
border-radius: 8px;
background: var(--bg-inset);
color: var(--text-muted);
font-weight: 500;
}
.detail-panel-body {
padding: 14px 16px;
}
/* Headers section */
.headers-section { margin-bottom: 16px; }
.section-label {
font-size: 10px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.6px;
color: var(--text-muted);
margin-bottom: 8px;
display: flex;
align-items: center;
gap: 6px;
}
.section-label .count {
font-family: var(--font-mono);
font-size: 10px;
padding: 0 5px;
border-radius: 8px;
background: var(--bg-inset);
color: var(--text-faint);
}
.header-list {
display: flex;
flex-direction: column;
gap: 3px;
}
.header-row {
display: grid;
grid-template-columns: 180px 1fr;
gap: 8px;
padding: 3px 8px;
border-radius: 3px;
font-family: var(--font-mono);
font-size: 11px;
transition: background 0.08s;
}
.header-row:hover { background: var(--bg-hover); }
.header-row.h-added { background: var(--success-bg); }
.header-row.h-removed { background: var(--error-bg); text-decoration: line-through; }
.header-key {
color: var(--text-secondary);
font-weight: 500;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.header-value {
color: var(--text-primary);
word-break: break-all;
}
.header-row.h-added .header-key { color: var(--success); }
.header-row.h-added .header-value { color: var(--success); }
.header-row.h-removed .header-key { color: var(--error); opacity: 0.7; }
.header-row.h-removed .header-value { color: var(--error); opacity: 0.7; }
.diff-badge {
font-family: var(--font-mono);
font-size: 9px;
font-weight: 600;
padding: 0 5px;
border-radius: 8px;
margin-left: 4px;
}
.diff-badge.added { background: var(--success-bg); color: var(--success); border: 1px solid var(--success-border); }
.diff-badge.removed { background: var(--error-bg); color: var(--error); border: 1px solid var(--error-border); }
/* Body section */
.body-section { margin-bottom: 0; }
.body-toolbar {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 8px;
}
.body-size {
font-family: var(--font-mono);
font-size: 10px;
color: var(--text-muted);
}
.body-format-tag {
font-family: var(--font-mono);
font-size: 10px;
font-weight: 600;
padding: 1px 6px;
border-radius: 8px;
background: var(--running-bg);
color: var(--running);
border: 1px solid var(--running-border);
}
.body-toggle {
font-size: 10px;
font-weight: 500;
padding: 2px 8px;
border: 1px solid var(--border);
border-radius: var(--radius-sm);
background: var(--bg-surface);
color: var(--text-muted);
cursor: pointer;
transition: all 0.12s;
margin-left: auto;
}
.body-toggle:hover { border-color: var(--text-faint); color: var(--text-secondary); }
.body-toggle.active { background: var(--amber-bg); border-color: var(--amber-light); color: var(--amber-deep); }
.body-content {
background: var(--bg-inset);
border: 1px solid var(--border-subtle);
border-radius: var(--radius-sm);
padding: 12px;
overflow-x: auto;
max-height: 280px;
overflow-y: auto;
}
.body-content pre {
font-family: var(--font-mono);
font-size: 11px;
line-height: 1.6;
color: var(--text-primary);
margin: 0;
white-space: pre;
}
/* JSON syntax highlighting */
.json-key { color: #6B4FA0; }
.json-str { color: var(--success); }
.json-num { color: var(--amber-deep); }
.json-bool { color: var(--running); }
.json-null { color: var(--text-muted); }
.json-brace { color: var(--text-secondary); }
/* ==========================================================================
ERROR DISPLAY
========================================================================== */
.error-section {
margin-top: 0;
}
.error-badge-row {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 12px;
}
.error-class {
font-family: var(--font-mono);
font-size: 12px;
font-weight: 600;
color: var(--error);
}
.error-http-badge {
font-family: var(--font-mono);
font-size: 11px;
font-weight: 700;
padding: 2px 10px;
border-radius: 10px;
background: var(--error-bg);
color: var(--error);
border: 1px solid var(--error-border);
}
.error-message-box {
background: var(--error-bg);
border: 1px solid var(--error-border);
border-left: 3px solid var(--error);
border-radius: var(--radius-sm);
padding: 10px 14px;
margin-bottom: 12px;
font-family: var(--font-mono);
font-size: 12px;
color: var(--error);
line-height: 1.6;
}
.error-detail-grid {
display: grid;
grid-template-columns: 100px 1fr;
gap: 4px 12px;
margin-bottom: 14px;
font-size: 12px;
}
.error-detail-key {
font-weight: 600;
color: var(--text-muted);
text-align: right;
}
.error-detail-val {
font-family: var(--font-mono);
font-size: 11px;
color: var(--text-primary);
word-break: break-all;
}
.stack-section { }
.stack-toggle {
display: flex;
align-items: center;
gap: 6px;
font-size: 11px;
font-weight: 600;
color: var(--text-secondary);
cursor: pointer;
padding: 4px 0;
margin-bottom: 6px;
background: none;
border: none;
font-family: var(--font-body);
}
.stack-toggle:hover { color: var(--text-primary); }
.stack-content {
background: var(--sidebar-bg);
border-radius: var(--radius-sm);
padding: 12px 14px;
overflow-x: auto;
max-height: 220px;
overflow-y: auto;
}
.stack-content pre {
font-family: var(--font-mono);
font-size: 10px;
line-height: 1.7;
color: #D4C8B8;
margin: 0;
white-space: pre;
}
.stack-content .stack-highlight {
color: #F0C4BE;
font-weight: 600;
}
.stack-content .stack-cause {
color: #E8A838;
font-weight: 600;
}
.stack-content .stack-at {
color: #8B9DAF;
}
/* ==========================================================================
PROPERTIES & CORRELATION
========================================================================== */
.props-section {
background: var(--bg-surface);
border: 1px solid var(--border-subtle);
border-radius: var(--radius-lg);
box-shadow: var(--shadow-card);
overflow: hidden;
margin-bottom: 16px;
}
.props-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 10px 18px;
border-bottom: 1px solid var(--border-subtle);
cursor: pointer;
transition: background 0.08s;
}
.props-header:hover { background: var(--bg-hover); }
.props-title {
font-size: 13px;
font-weight: 600;
color: var(--text-primary);
}
.props-chevron {
color: var(--text-faint);
font-size: 12px;
transition: transform 0.2s;
}
.props-body {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 0;
padding: 16px 18px;
}
.props-column {
padding: 0 16px;
border-right: 1px solid var(--border-subtle);
}
.props-column:first-child { padding-left: 0; }
.props-column:last-child { border-right: none; }
.props-col-title {
font-size: 10px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.6px;
color: var(--text-muted);
margin-bottom: 10px;
}
.prop-row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 4px;
padding: 3px 0;
border-bottom: 1px solid var(--border-subtle);
font-size: 11px;
}
.prop-row:last-child { border-bottom: none; }
.prop-key {
font-weight: 500;
color: var(--text-muted);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.prop-val {
font-family: var(--font-mono);
font-size: 11px;
color: var(--text-primary);
word-break: break-all;
}
/* Correlation chain */
.correlation-chain {
display: flex;
align-items: center;
gap: 0;
margin-top: 16px;
padding: 12px 18px;
border-top: 1px solid var(--border-subtle);
}
.chain-label {
font-size: 10px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.6px;
color: var(--text-muted);
margin-right: 14px;
white-space: nowrap;
}
.chain-node {
display: inline-flex;
align-items: center;
gap: 5px;
padding: 4px 12px;
border: 1px solid var(--border);
border-radius: var(--radius-sm);
font-family: var(--font-mono);
font-size: 11px;
font-weight: 500;
color: var(--text-secondary);
cursor: pointer;
transition: all 0.12s;
background: var(--bg-surface);
}
.chain-node:hover { border-color: var(--amber); color: var(--amber); }
.chain-node.current { background: var(--amber-bg); border-color: var(--amber-light); color: var(--amber-deep); font-weight: 600; }
.chain-node.chain-error { border-color: var(--error-border); color: var(--error); }
.chain-arrow {
color: var(--text-faint);
font-size: 14px;
margin: 0 6px;
}
/* ==========================================================================
KEYBOARD HINTS
========================================================================== */
.keyboard-bar {
position: fixed;
bottom: 0;
left: 220px;
right: 0;
display: flex;
align-items: center;
gap: 16px;
padding: 6px 24px;
background: var(--sidebar-bg);
border-top: 1px solid rgba(255,255,255,0.06);
z-index: 100;
}
.kb-hint {
display: flex;
align-items: center;
gap: 5px;
font-size: 11px;
color: var(--sidebar-muted);
}
.kb-key {
font-family: var(--font-mono);
font-size: 10px;
padding: 1px 5px;
border-radius: 3px;
background: rgba(255,255,255,0.08);
color: var(--sidebar-text);
border: 1px solid rgba(255,255,255,0.1);
}
</style>
</head>
<body>
<div class="app">
<!-- ====================================================================
SIDEBAR (identical structure to mock-v2)
==================================================================== -->
<aside class="sidebar">
<div class="sidebar-logo">
<svg width="24" height="26" viewBox="940 300 900 1000" fill="none" xmlns="http://www.w3.org/2000/svg">
<path style="fill:#C6820E" d="M 1385.2768,1205.0273 c -1.7727,-1.0809 -3.4419,-2.9917 -3.7093,-4.2463 -0.2674,-1.2545 -0.6851,-23.881 -0.9282,-50.281 -0.4544,-49.3389 -1.4003,-65.7355 -5.6645,-98.1921 -10.4552,-79.57719 -28.3441,-125.96796 -62.5438,-162.19311 -9.2529,-9.80096 -19.9748,-18.38696 -33.931,-27.17162 -12.6119,-7.93853 -24.8581,-13.73088 -49.5,-23.41316 -41.7081,-16.38789 -67.8677,-32.29827 -89.0588,-54.16599 -34.7586,-35.86827 -54.3653,-83.30392 -59.0504,-142.86402 -0.8357,-10.6245 -0.92,-22.5842 -0.2891,-41 0.4899,-14.3 0.8164,-35.225 0.7255,-46.5 -0.1983,-24.59199 -2.0251,-34.76973 -8.4617,-47.14159 -6.2021,-11.92135 -10.364,-15.10789 -36.2345,-27.74305 -25.4032,-12.40694 -27.7701,-13.30168 -35.4717,-13.40961 -4.63013,-0.0649 -7.47783,0.72754 -15.6593,4.35747 -9.86218,4.37563 -10.15161,4.43672 -21,4.43267 -10.86566,-0.004 -11.08917,-0.0517 -18.30169,-3.90103 -17.43524,-9.3052 -21.50075,-23.5772 -13.55784,-47.59486 2.73631,-8.27402 10.00732,-22.43593 14.69263,-28.61719 5.4984,-7.25394 10.89014,-11.83885 20.83968,-17.72117 15.06768,-8.90827 29.60254,-11.98884 63.90372,-13.54403 l 16.5765,-0.75156 14.9235,-7.05735 c 8.2079,-3.88154 17.1735,-7.76831 19.9235,-8.63727 7.7052,-2.43474 21.059,-4.67186 27.8605,-4.66741 8.0518,0.005 22.643,2.41202 30.0139,4.95066 l 5.8744,2.02321 4.8856,-4.09041 c 10.341,-8.65797 18.6496,-12.95738 28.96,-14.98583 6.9966,-1.37649 26.3532,-0.64631 32.1116,1.21134 4.5531,1.46885 5.4951,3.7902 6.3689,15.69592 1.5167,20.66426 -5.0112,40.44987 -18.1772,55.09363 -4.3065,4.78983 -4.5016,5.25488 -3.4977,8.33516 4.5184,13.86447 5.3154,38.07517 2.1537,65.42564 -5.169,44.71349 -5.0411,70.7797 0.5404,110.15637 6.8135,48.06863 22.3335,73.51874 48.2051,79.04779 24.1748,5.16643 45.2921,-5.78181 66.8353,-34.65077 4.809,-6.4442 11.1363,-14.93006 14.0608,-18.85747 7.3865,-9.91943 25.6102,-27.11708 35.952,-33.92766 12.5235,-8.24739 26.8808,-14.74833 42.8527,-19.40354 15.4108,-4.49168 26.7091,-9.74984 36.2432,-16.86731 3.4338,-2.56341 13.3338,-12.03104 22,-21.03916 26.2356,-27.27067 44.5755,-40.32368 66.9928,-47.68062 19.1052,-6.26998 35.4927,-7.73718 50.8681,-4.55427 37.0856,7.67726 63.5507,26.77589 100.2888,72.37362 16.6011,20.60463 29.9711,32.07977 51.6071,44.29313 39.3131,22.19195 50.1228,30.50985 68.8076,52.94655 5.4963,6.6 12.9187,14.91604 16.4941,18.4801 33.6796,33.57259 54.1965,72.51092 61.6587,117.0199 2.7315,16.29242 3.3374,26.62538 3.1861,54.33713 l -0.1465,26.83714 -2.7975,2.40572 c -3.9132,3.36522 -7.2806,3.99163 -11.2591,2.09442 -6.4731,-3.08682 -6.5715,-3.57833 -6.878,-34.36929 -0.2908,-29.2175 -2.0265,-46.13705 -6.6479,-64.80512 -3.2997,-13.32891 -12.2529,-34.61943 -17.0313,-40.5 l -2.0314,-2.5 0.5698,3.5 c 5.8574,35.97875 4.2855,72.40287 -5.3946,125 -8.4016,45.65054 -4.3665,69.39588 20.7318,122 11.4175,23.93009 12.5452,27.25907 12.4212,36.6684 -0.1018,7.7227 -2.5346,19.5162 -13.1674,63.8316 -1.0558,4.4 -3.5336,14.975 -5.5063,23.5 -1.9727,8.525 -4.2259,18.2 -5.0072,21.5 -0.7812,3.3 -3.4495,15.225 -5.9296,26.5 -9.1636,41.6596 -13.4372,59.8787 -14.5204,61.9027 -2.4994,4.6702 -5.2312,5.0973 -32.6024,5.0973 H 1765.8 l -3.4,-3.4 c -2.3518,-2.3518 -3.4,-4.3226 -3.4,-6.3925 0,-1.6458 2.2347,-12.1533 4.966,-23.35 8.6906,-35.6259 11.6969,-54.778 12.6921,-80.8575 1.3475,-35.3073 -4.6406,-62.7687 -18.7825,-86.137 -7.6672,-12.66954 -11.9163,-17.84148 -29.8756,-36.36415 -22.9362,-23.65574 -34.6222,-39.72583 -47.9268,-65.90697 -5.7294,-11.27448 -13.6061,-31.99995 -15.5051,-40.79778 -0.3212,-1.48824 -1.0176,-3.84619 -1.5475,-5.2399 l -0.9634,-2.534 -11.7786,7.15145 c -38.634,23.45687 -74.5513,34.71091 -124.1895,38.91257 -14.5402,1.23075 -58.2359,0.66344 -71.9142,-0.93369 -5.4419,-0.63542 -6.4542,-0.49723 -7.25,0.98972 -0.5545,1.03621 -0.9249,60.63835 -0.9249,148.84365 0,161.6262 0.4025,151.2052 -5.9673,154.4992 -2.3865,1.2341 -7.4633,1.5162 -27.233,1.5132 -22.3926,-0 -24.5527,-0.158 -27.5229,-1.969 z M 1424,1045.6452 c 0,-87.21053 0.3878,-144.17994 1.0365,-152.24998 1.8115,-22.53829 7.2373,-44.8067 16.1142,-66.13567 20.7842,-49.93942 66.8961,-95.01414 129.8493,-126.92865 14.9469,-7.57742 29.283
</svg>
<div>
<span class="brand">cameleer</span><span class="version">v3</span>
</div>
</div>
<div class="sidebar-search">
<div class="sidebar-search-wrap">
<span class="search-icon">&#9671;</span>
<input type="text" placeholder="Filter applications...">
</div>
</div>
<div class="sidebar-section">Applications</div>
<div class="sidebar-items">
<div class="sidebar-item">
<span class="health health-live"></span>
<div class="item-info"><div class="item-name">All Applications</div></div>
<span class="item-count">4</span>
</div>
<div class="sidebar-divider"></div>
<div class="sidebar-item active">
<span class="health health-live"></span>
<div class="item-info">
<div class="item-name">order-service</div>
<div class="item-meta">2 agents</div>
</div>
<span class="item-count">1,847</span>
</div>
<div class="sidebar-item">
<span class="health health-live"></span>
<div class="item-info">
<div class="item-name">payment-gateway</div>
<div class="item-meta">2 agents</div>
</div>
<span class="item-count">923</span>
</div>
<div class="sidebar-item">
<span class="health health-live"></span>
<div class="item-info">
<div class="item-name">shipment-tracker</div>
<div class="item-meta">2 agents</div>
</div>
<span class="item-count">471</span>
</div>
<div class="sidebar-item">
<span class="health health-stale"></span>
<div class="item-info">
<div class="item-name">notification-hub</div>
<div class="item-meta">1 agent</div>
</div>
<span class="item-count">128</span>
</div>
<div class="sidebar-divider"></div>
<div class="sidebar-section">Routes</div>
<div class="sidebar-item" style="padding-left: 22px;">
<span style="color: var(--sidebar-muted); font-size: 10px;">&#9656;</span>
<div class="item-info"><div class="item-name">order-intake</div></div>
<span class="item-count">892</span>
</div>
<div class="sidebar-item" style="padding-left: 22px;">
<span style="color: var(--sidebar-muted); font-size: 10px;">&#9656;</span>
<div class="item-info"><div class="item-name">order-enrichment</div></div>
<span class="item-count">541</span>
</div>
<div class="sidebar-item" style="padding-left: 22px;">
<span style="color: var(--sidebar-muted); font-size: 10px;">&#9656;</span>
<div class="item-info"><div class="item-name">payment-process</div></div>
<span class="item-count">414</span>
</div>
</div>
<!-- Agent health -->
<div class="sidebar-agents-header">
<span>Agents</span>
<span class="sidebar-agent-badge">4/4 live</span>
</div>
<div style="padding: 0 0 6px; overflow-y: auto; max-height: 180px;">
<div class="agent-item">
<span class="agent-dot health-live"></span>
<div class="agent-info">
<div class="agent-name">prod-node-01</div>
<div class="agent-detail">order-service v3.2.1</div>
</div>
<div class="agent-stats-col">
<div class="agent-tps">14.2/s</div>
<div>12s ago</div>
</div>
</div>
<div class="agent-item">
<span class="agent-dot health-live"></span>
<div class="agent-info">
<div class="agent-name">prod-node-02</div>
<div class="agent-detail">order-service v3.2.1</div>
</div>
<div class="agent-stats-col">
<div class="agent-tps">11.8/s</div>
<div style="color: var(--error);">3 err/h</div>
</div>
</div>
<div class="agent-item">
<span class="agent-dot health-live"></span>
<div class="agent-info">
<div class="agent-name">prod-node-03</div>
<div class="agent-detail">payment-svc v3.2.1</div>
</div>
<div class="agent-stats-col">
<div class="agent-tps">12.1/s</div>
<div>5s ago</div>
</div>
</div>
<div class="agent-item">
<span class="agent-dot health-live"></span>
<div class="agent-info">
<div class="agent-name">prod-node-04</div>
<div class="agent-detail">shipment-svc v3.2.0</div>
</div>
<div class="agent-stats-col">
<div class="agent-tps">9.1/s</div>
<div>3s ago</div>
</div>
</div>
</div>
<div class="sidebar-bottom">
<div class="sidebar-item"><span style="font-size: 13px; width: 18px; text-align: center;">&#9881;</span><div class="item-info"><div class="item-name">Admin</div></div></div>
<div class="sidebar-item"><span style="font-size: 13px; width: 18px; text-align: center;">&#9776;</span><div class="item-info"><div class="item-name">API Docs</div></div></div>
</div>
</aside>
<!-- ====================================================================
MAIN CONTENT — Exchange Detail
==================================================================== -->
<div class="main">
<!-- Top bar -->
<div class="topbar">
<div class="topbar-breadcrumb">
<span class="crumb-link">order-service</span>
<span class="crumb-sep">/</span>
<span class="crumb-link">order-processing</span>
<span class="crumb-sep">/</span>
<span class="crumb-active">Exchange OP-88421</span>
</div>
<div class="topbar-right">
<span class="topbar-env">PRODUCTION</span>
<div class="topbar-user">
<span>hendrik</span>
<div class="topbar-avatar">H</div>
</div>
</div>
</div>
<!-- Scrollable content -->
<div class="content" style="padding-bottom: 60px;">
<!-- ============================================================
1. EXCHANGE HEADER CARD
============================================================ -->
<div class="exchange-header animate-in">
<div class="exchange-header-top">
<div class="exchange-title-area">
<span class="exchange-route">order-processing</span>
<span class="exchange-status-lg">
<span class="status-dot"></span>
FAILED
</span>
</div>
<div class="exchange-actions">
<button class="action-btn" title="Copy Exchange ID">&#128203; Copy ID</button>
<button class="action-btn" title="Copy full trace as JSON">&#128196; Export JSON</button>
<button class="action-btn primary" title="Retry this exchange">&#8635; Retry</button>
</div>
</div>
<div class="exchange-meta-grid">
<div class="meta-item">
<div class="meta-label">Business IDs</div>
<div class="meta-value">
<span class="biz-tag order">Order: OP-88421</span>
<span class="biz-tag customer">Customer: DE-40912</span>
</div>
</div>
<div class="meta-item">
<div class="meta-label">Duration</div>
<div class="meta-value">
<span class="duration-lg">2m 33s</span>
<span class="duration-label">total</span>
</div>
<div class="meta-sub">Started 09:14:22 (2 min ago)</div>
</div>
<div class="meta-item">
<div class="meta-label">Exchange ID</div>
<div class="meta-value mono-sm">ID-20260317-091422-prod02-88421</div>
<div class="meta-sub">Breadcrumb: BC-88421-001</div>
</div>
<div class="meta-item">
<div class="meta-label">Agent</div>
<div class="meta-value" style="display: flex; align-items: center; gap: 6px;">
<span style="width: 6px; height: 6px; border-radius: 50%; background: #5DB866; display: inline-block;"></span>
prod-node-02
</div>
<div class="meta-sub">order-service v3.2.1</div>
</div>
</div>
</div>
<!-- ============================================================
2. PROCESSOR TIMELINE (Gantt-style)
============================================================ -->
<div class="timeline-section animate-in delay-1">
<div class="timeline-header">
<div class="timeline-title">
Processor Timeline
<span class="proc-count">5 processors</span>
</div>
<div class="timeline-legend">
<div class="legend-item"><span class="legend-dot l-success"></span> Success</div>
<div class="legend-item"><span class="legend-dot l-error"></span> Failed</div>
<div class="legend-item"><span class="legend-dot l-slow"></span> Slow (&gt; SLA)</div>
</div>
</div>
<div class="timeline-body">
<!-- Row 1: from(direct:order-intake) — 12ms -->
<div class="timeline-row" onclick="selectRow(this, 0)">
<div class="proc-label">
<span class="proc-index">1</span>
<span class="proc-type type-from">from</span>
<span class="proc-name">direct:order-intake</span>
</div>
<div class="proc-bar-area">
<div class="proc-bar bar-success" style="width: 0.8%;"></div>
</div>
<div class="proc-duration">12ms</div>
<div class="proc-status-icon icon-ok">&#10003;</div>
</div>
<!-- Row 2: process(OrderValidator) — 45ms -->
<div class="timeline-row" onclick="selectRow(this, 1)">
<div class="proc-label">
<span class="proc-index">2</span>
<span class="proc-type type-process">process</span>
<span class="proc-name">OrderValidator</span>
</div>
<div class="proc-bar-area">
<div class="proc-bar bar-success" style="width: 2.9%;"></div>
</div>
<div class="proc-duration">45ms</div>
<div class="proc-status-icon icon-ok">&#10003;</div>
</div>
<!-- Row 3: to(sql:INSERT INTO orders) — 89ms -->
<div class="timeline-row" onclick="selectRow(this, 2)">
<div class="proc-label">
<span class="proc-index">3</span>
<span class="proc-type type-to">to</span>
<span class="proc-name">sql:INSERT INTO orders</span>
</div>
<div class="proc-bar-area">
<div class="proc-bar bar-success" style="width: 5.8%;"></div>
</div>
<div class="proc-duration">89ms</div>
<div class="proc-status-icon icon-ok">&#10003;</div>
</div>
<!-- Row 4: choice(priority check) — 2ms -->
<div class="timeline-row" onclick="selectRow(this, 3)">
<div class="proc-label">
<span class="proc-index">4</span>
<span class="proc-type type-choice">choice</span>
<span class="proc-name">priority-check</span>
</div>
<div class="proc-bar-area">
<div class="proc-bar bar-success" style="width: 0.3%;"></div>
</div>
<div class="proc-duration">2ms</div>
<div class="proc-status-icon icon-ok">&#10003;</div>
</div>
<!-- Row 5: to(http:payment-api/charge) — 2m 18s — FAILED -->
<div class="timeline-row row-error selected" onclick="selectRow(this, 4)">
<div class="proc-label">
<span class="proc-index">5</span>
<span class="proc-type type-to">to</span>
<span class="proc-name" style="color: var(--error); font-weight: 600;">http:payment-api/charge</span>
</div>
<div class="proc-bar-area">
<div class="proc-bar bar-error" style="width: 94%;">
<span class="bar-pct">94%</span>
</div>
</div>
<div class="proc-duration dur-error">2m 18s</div>
<div class="proc-status-icon icon-fail">&#10007;</div>
</div>
</div>
<!-- Bottleneck callout -->
<div class="bottleneck-callout">
<span style="font-size: 16px;">&#9888;</span>
<span><strong>Bottleneck detected:</strong> Processor #5 <code style="font-family: var(--font-mono); font-size: 11px; background: rgba(192,57,43,0.1); padding: 1px 4px; border-radius: 3px;">http:payment-api/charge</code> consumed</span>
<span class="bottleneck-pct">94%</span>
<span>of total execution time (2m 18s of 2m 33s). 503 Service Unavailable after 30s timeout with 4 retries.</span>
</div>
</div>
<!-- ============================================================
3. PROCESSOR DETAIL PANEL (split IN / OUT)
Selected: #5 http:payment-api/charge (FAILED)
============================================================ -->
<div class="detail-split animate-in delay-2">
<!-- LEFT: Message IN (at entry to this processor) -->
<div class="detail-panel">
<div class="detail-panel-header">
<div class="panel-title">
<span class="arrow-in" style="font-size: 16px;">&#8594;</span>
Message IN
<span class="panel-tag">at processor #5 entry</span>
</div>
</div>
<div class="detail-panel-body">
<!-- Headers at entry -->
<div class="headers-section">
<div class="section-label">
Headers <span class="count">9</span>
</div>
<div class="header-list">
<div class="header-row">
<span class="header-key">breadcrumbId</span>
<span class="header-value">BC-88421-001</span>
</div>
<div class="header-row">
<span class="header-key">CamelHttpMethod</span>
<span class="header-value">POST</span>
</div>
<div class="header-row">
<span class="header-key">Content-Type</span>
<span class="header-value">application/json</span>
</div>
<div class="header-row">
<span class="header-key">orderId</span>
<span class="header-value">OP-88421</span>
</div>
<div class="header-row">
<span class="header-key">customerId</span>
<span class="header-value">DE-40912</span>
</div>
<div class="header-row">
<span class="header-key">correlationId</span>
<span class="header-value">corr-a7f3e9d1-88421</span>
</div>
<div class="header-row">
<span class="header-key">orderPriority</span>
<span class="header-value">HIGH</span>
</div>
<div class="header-row h-added">
<span class="header-key">orderDbId <span class="diff-badge added">+added</span></span>
<span class="header-value">48291</span>
</div>
<div class="header-row h-added">
<span class="header-key">priorityTier <span class="diff-badge added">+added</span></span>
<span class="header-value">express</span>
</div>
</div>
</div>
<!-- Body at entry -->
<div class="body-section">
<div class="section-label">Body</div>
<div class="body-toolbar">
<span class="body-format-tag">JSON</span>
<span class="body-size">1.2 KB</span>
<button class="body-toggle">Show diff from #4</button>
</div>
<div class="body-content">
<pre><span class="json-brace">{</span>
<span class="json-key">"orderId"</span>: <span class="json-str">"OP-88421"</span>,
<span class="json-key">"customerId"</span>: <span class="json-str">"DE-40912"</span>,
<span class="json-key">"timestamp"</span>: <span class="json-str">"2026-03-17T09:14:22.184Z"</span>,
<span class="json-key">"items"</span>: <span class="json-brace">[</span>
<span class="json-brace">{</span>
<span class="json-key">"sku"</span>: <span class="json-str">"WDG-4420-BLK"</span>,
<span class="json-key">"name"</span>: <span class="json-str">"Industrial Pressure Valve DN50"</span>,
<span class="json-key">"quantity"</span>: <span class="json-num">12</span>,
<span class="json-key">"unitPrice"</span>: <span class="json-num">284.50</span>,
<span class="json-key">"currency"</span>: <span class="json-str">"EUR"</span>
<span class="json-brace">}</span>,
<span class="json-brace">{</span>
<span class="json-key">"sku"</span>: <span class="json-str">"FLG-1180-SS"</span>,
<span class="json-key">"name"</span>: <span class="json-str">"Stainless Steel Flange PN16"</span>,
<span class="json-key">"quantity"</span>: <span class="json-num">24</span>,
<span class="json-key">"unitPrice"</span>: <span class="json-num">67.90</span>,
<span class="json-key">"currency"</span>: <span class="json-str">"EUR"</span>
<span class="json-brace">}</span>
<span class="json-brace">]</span>,
<span class="json-key">"totalAmount"</span>: <span class="json-num">5043.60</span>,
<span class="json-key">"shippingAddress"</span>: <span class="json-brace">{</span>
<span class="json-key">"street"</span>: <span class="json-str">"Industriestr. 42"</span>,
<span class="json-key">"city"</span>: <span class="json-str">"Stuttgart"</span>,
<span class="json-key">"zip"</span>: <span class="json-str">"70178"</span>,
<span class="json-key">"country"</span>: <span class="json-str">"DE"</span>
<span class="json-brace">}</span>,
<span class="json-key">"priority"</span>: <span class="json-str">"HIGH"</span>,
<span class="json-key">"paymentMethod"</span>: <span class="json-str">"invoice_30d"</span>
<span class="json-brace">}</span></pre>
</div>
</div>
</div>
</div>
<!-- RIGHT: Message OUT / Error -->
<div class="detail-panel panel-error">
<div class="detail-panel-header">
<div class="panel-title">
<span class="arrow-out" style="font-size: 16px;">&#10007;</span>
Error at Processor #5
<span class="panel-tag" style="background: var(--error-bg); color: var(--error); border: 1px solid var(--error-border);">FAILED</span>
</div>
</div>
<div class="detail-panel-body">
<!-- Error info -->
<div class="error-section">
<div class="error-badge-row">
<span class="error-http-badge">503</span>
<span class="error-class">java.net.http.HttpTimeoutException</span>
</div>
<div class="error-message-box">
request timed out after 30000ms &mdash; HTTP POST http://payment-api:8080/v2/charge returned 503 Service Unavailable after 4 retry attempts (backoff: 1s, 2s, 4s, 8s)
</div>
<div class="error-detail-grid">
<span class="error-detail-key">Endpoint</span>
<span class="error-detail-val">http://payment-api:8080/v2/charge</span>
<span class="error-detail-key">HTTP Method</span>
<span class="error-detail-val">POST</span>
<span class="error-detail-key">HTTP Status</span>
<span class="error-detail-val" style="color: var(--error); font-weight: 600;">503 Service Unavailable</span>
<span class="error-detail-key">Timeout</span>
<span class="error-detail-val">30,000ms (configured)</span>
<span class="error-detail-key">Retries</span>
<span class="error-detail-val">4 of 4 (exhausted)</span>
<span class="error-detail-key">Last Attempt</span>
<span class="error-detail-val">09:16:55.412 (after 8s backoff)</span>
</div>
<!-- Stack trace -->
<div class="stack-section">
<button class="stack-toggle">
<span style="font-size: 9px;">&#9660;</span>
Stack Trace (42 frames)
</button>
<div class="stack-content">
<pre><span class="stack-highlight">java.net.http.HttpTimeoutException: request timed out after 30000ms</span>
<span class="stack-at"> at java.net.http/jdk.internal.net.http.HttpClientImpl.send(HttpClientImpl.java:586)</span>
<span class="stack-at"> at java.net.http/jdk.internal.net.http.HttpClientImpl.send(HttpClientImpl.java:538)</span>
<span class="stack-at"> at org.apache.camel.component.http.HttpProducer.executeMethod(HttpProducer.java:347)</span>
<span class="stack-at"> at org.apache.camel.component.http.HttpProducer.process(HttpProducer.java:198)</span>
<span class="stack-at"> at org.apache.camel.processor.SendProcessor.process(SendProcessor.java:172)</span>
<span class="stack-at"> at org.apache.camel.processor.errorhandler.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:614)</span>
<span class="stack-at"> at org.apache.camel.processor.errorhandler.RedeliveryErrorHandler.processErrorHandler(RedeliveryErrorHandler.java:258)</span>
<span class="stack-at"> at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:399)</span>
<span class="stack-at"> at org.apache.camel.processor.Pipeline.process(Pipeline.java:184)</span>
<span class="stack-at"> at org.apache.camel.processor.Pipeline.process(Pipeline.java:74)</span>
<span class="stack-at"> at org.apache.camel.impl.engine.DefaultReactiveExecutor$Worker.run(DefaultReactiveExecutor.java:182)</span>
<span class="stack-at"> at org.apache.camel.impl.engine.DefaultReactiveExecutor.scheduleMain(DefaultReactiveExecutor.java:64)</span>
<span class="stack-at"> at org.apache.camel.processor.Pipeline.process(Pipeline.java:184)</span>
<span class="stack-at"> at org.apache.camel.spring.boot.SpringBootRoutesCollector.process(SpringBootRoutesCollector.java:89)</span>
<span class="stack-cause">Caused by: java.net.ConnectException: Connection refused: payment-api:8080</span>
<span class="stack-at"> at java.base/sun.nio.ch.Net.connect0(Native Method)</span>
<span class="stack-at"> at java.base/sun.nio.ch.Net.connect(Net.java:579)</span>
<span class="stack-at"> at java.base/sun.nio.ch.SocketChannelImpl.connect(SocketChannelImpl.java:726)</span>
<span class="stack-at"> at java.net.http/jdk.internal.net.http.PlainHttpConnection.connectAsync(PlainHttpConnection.java:198)</span>
<span class="stack-at"> ... 8 more</span></pre>
</div>
</div>
</div>
<!-- Response headers (from the 503) -->
<div class="headers-section" style="margin-top: 16px;">
<div class="section-label">
Response Headers <span class="count">4</span>
</div>
<div class="header-list">
<div class="header-row">
<span class="header-key">Date</span>
<span class="header-value">Mon, 17 Mar 2026 09:16:55 GMT</span>
</div>
<div class="header-row">
<span class="header-key">Content-Length</span>
<span class="header-value">0</span>
</div>
<div class="header-row">
<span class="header-key">Retry-After</span>
<span class="header-value">60</span>
</div>
<div class="header-row">
<span class="header-key">X-Request-Id</span>
<span class="header-value">pay-req-f42a8c91</span>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- ============================================================
4. PROPERTIES & CORRELATION
============================================================ -->
<div class="props-section animate-in delay-3">
<div class="props-header">
<span class="props-title">Exchange Properties &amp; Context</span>
<span class="props-chevron">&#9660;</span>
</div>
<div class="props-body">
<!-- Column 1: Exchange Properties -->
<div class="props-column">
<div class="props-col-title">Exchange Properties</div>
<div class="prop-row">
<span class="prop-key">CamelCreatedTimestamp</span>
<span class="prop-val">2026-03-17T09:14:22.184Z</span>
</div>
<div class="prop-row">
<span class="prop-key">CamelExternalRedelivered</span>
<span class="prop-val">false</span>
</div>
<div class="prop-row">
<span class="prop-key">CamelToEndpoint</span>
<span class="prop-val">http://payment-api:8080/v2/charge</span>
</div>
<div class="prop-row">
<span class="prop-key">CamelFailureEndpoint</span>
<span class="prop-val">http://payment-api:8080/v2/charge</span>
</div>
<div class="prop-row">
<span class="prop-key">CamelRedeliveryCounter</span>
<span class="prop-val">4</span>
</div>
<div class="prop-row">
<span class="prop-key">CamelRedelivered</span>
<span class="prop-val">true</span>
</div>
</div>
<!-- Column 2: Route Context -->
<div class="props-column">
<div class="props-col-title">Route Context</div>
<div class="prop-row">
<span class="prop-key">CamelContext</span>
<span class="prop-val">order-service-ctx</span>
</div>
<div class="prop-row">
<span class="prop-key">Route ID</span>
<span class="prop-val">order-processing</span>
</div>
<div class="prop-row">
<span class="prop-key">Route Version</span>
<span class="prop-val">3.2.1-20260315</span>
</div>
<div class="prop-row">
<span class="prop-key">From Endpoint</span>
<span class="prop-val">direct:order-intake</span>
</div>
<div class="prop-row">
<span class="prop-key">Error Handler</span>
<span class="prop-val">DefaultErrorHandler</span>
</div>
</div>
<!-- Column 3: Environment -->
<div class="props-column">
<div class="props-col-title">Environment</div>
<div class="prop-row">
<span class="prop-key">Agent ID</span>
<span class="prop-val">prod-node-02</span>
</div>
<div class="prop-row">
<span class="prop-key">Hostname</span>
<span class="prop-val">order-svc-6f8d4b-xk2p9</span>
</div>
<div class="prop-row">
<span class="prop-key">JVM</span>
<span class="prop-val">Eclipse Temurin 17.0.10</span>
</div>
<div class="prop-row">
<span class="prop-key">Camel Version</span>
<span class="prop-val">4.4.1</span>
</div>
<div class="prop-row">
<span class="prop-key">Heap Used</span>
<span class="prop-val">412 MB / 1024 MB</span>
</div>
</div>
</div>
<!-- Correlation chain -->
<div class="correlation-chain">
<span class="chain-label">Correlation Chain</span>
<span class="chain-node current chain-error">
<span style="width: 5px; height: 5px; border-radius: 50; background: var(--error); display: inline-block;"></span>
order-processing
</span>
<span class="chain-arrow">&#8594;</span>
<span class="chain-node">
payment-flow
</span>
<span class="chain-arrow">&#8594;</span>
<span class="chain-node">
notification-sender
</span>
</div>
</div>
</div><!-- /content -->
<!-- Keyboard hints bar -->
<div class="keyboard-bar">
<div class="kb-hint"><span class="kb-key">&#8593;&#8595;</span> Navigate processors</div>
<div class="kb-hint"><span class="kb-key">Enter</span> Select processor</div>
<div class="kb-hint"><span class="kb-key">D</span> Toggle diff</div>
<div class="kb-hint"><span class="kb-key">J</span> View raw JSON</div>
<div class="kb-hint"><span class="kb-key">R</span> Retry exchange</div>
<div class="kb-hint"><span class="kb-key">Esc</span> Back to list</div>
</div>
</div><!-- /main -->
</div><!-- /app -->
<script>
// Simple row selection for the timeline
function selectRow(el, index) {
document.querySelectorAll('.timeline-row').forEach(function(row) {
row.classList.remove('selected');
});
el.classList.add('selected');
}
</script>
</body>
</html>