Operate from the dashboard.
The Cordum dashboard is an optional Vite + React UI for approvals, run timelines, pack lifecycle, policy operations, and real-time event monitoring. It connects to the API gateway over REST and WebSocket.
- Approvals inbox with bulk approve/reject and SLA tracking
- Run timelines with DAG visualization and Gantt charts
- Jobs list with multi-filter search and cursor pagination
- Pack install, verify, marketplace, and uninstall
- Policy studio with simulate, publish, rollback, and audit
- Real-time event stream with auto-reconnect
In a default Docker Compose setup the dashboard is exposed locally. It connects to the API gateway using a pre-configured key.
http://localhost:8082 /config.json
Approvals Inbox
Every job that receives a REQUIRE_APPROVAL decision from the Safety Kernel appears in the approvals inbox. Each card shows urgency, a live wait timer, SLA status, presence indicators, and the matched policy rule. Approvals are bound to the policy snapshot hash and job hash at the time of request — if policy changes later, existing approvals remain valid for their snapshot.
| Field | Description |
|---|---|
| Urgency Badge | Fresh / Aging / Critical / SLA Breach — color-coded left border |
| Wait Timer | Live-updating duration since approval was requested |
| SLA Status | Remaining time or pulsing red breach indicator |
| Presence | Shows who is currently reviewing the approval |
| Summary | Human-readable description (capability on topic fallback) |
| Policy Rule | Matched rule name and reason text |
| Risk Tags | Color-coded badges for risk classification |
| Workflow Link | Workflow ID, step number, and step name |
Approve / Reject Flow
- Click Approve or Reject on a card
- Inline confirmation expands — add an optional comment (approve) or required reason (reject)
- Mutation calls
POST /approvals/{id}/approveor/reject - Card animates out; queue counter updates
Bulk Operations
- Select multiple approvals via checkboxes; "Select All" respects high-risk filtering
- Bulk bar appears at bottom with approve/reject actions and shared comment
- Progress bar shows real-time count with 200ms delay between requests
- High-risk tags (
financial,destructive,compliance,production) force individual review
Queue Filters
The inbox has two tabs: Queue (pending approvals) and History (resolved approvals from the policy audit endpoint, filterable by date range).
Run Timeline View
Click any run to open a detail page with three visualization modes: an interactive DAG graph showing step dependencies, a Gantt timeline showing parallel execution across time, and an expandable step list with full I/O inspection.
DAG Visualization
Directed acyclic graph rendering of workflow steps. Nodes are color-coded by status. Edges show depends_on relationships. Zoom and pan supported.
Gantt Timeline
Horizontal timeline with step bars colored by status. Shows parallel execution lanes and helps identify bottlenecks. Duration labels on each bar.
Step Details
Expandable accordion rows per step. Shows type, ID, timestamps, dependencies, safety decision, error messages, and output JSON in a scrollable pre-formatted block.
Jobs List
| Column | Description |
|---|---|
| ID | Shortened job ID (8 chars, monospace) |
| Topic | Job topic — sortable |
| Status | Color-coded badge (pending, running, succeeded, failed, …) |
| Safety Decision | Allow / Deny / Approval / Throttle badge |
| Pool | Worker pool name — sortable |
| Duration | Formatted execution time — sortable |
| Updated | Relative timestamp — sortable |
Filters
- State — multi-select: pending, scheduled, dispatched, running, succeeded, failed, cancelled, approval_required, denied, timeout
- Decision — allow / deny / require_approval / throttle
- Topic — text input (debounced 400ms)
- Pool — text input (debounced 400ms)
- Tenant — text input (debounced 400ms)
- Time — presets (1h, 24h, 7d, 30d) or custom date picker
Pagination & Sorting
- Cursor-based pagination with "Newer" / "Older" buttons
- Rows per page: 10, 25, 50, or 100
- Default sort: updatedAt (descending)
- Click row to open job detail with full metadata, timeline, and result
Pack Lifecycle
The Packs page has two tabs: Installed shows currently registered packs as cards, and Marketplace lets you browse and install packs from configured catalogs.
Pack Card
- Name, version, and status badge (active / installing / error / failed)
- Pool assignment and capability badges
- Click card to open detail drawer with metadata, capabilities, and install history
- Uninstall button with confirmation dialog →
DELETE /packs/{id}
Marketplace
- Browse available packs from configured catalog URLs
- Pack title, version, author, description, and install button
- Filter by catalog and search by name
- Install triggers the same pipeline as
cordumctl pack install
Policy Studio
The Policy Studio provides a complete lifecycle for safety policies: create and edit rules visually or in YAML, simulate decisions, publish bundles, rollback to previous snapshots, and review a full audit timeline. Write operations require the secops role in config.json.
Visual Rule Builder
Add, edit, and toggle rules with a structured editor — match criteria, decision type, and reason fields.
YAML Editor
Edit raw policy YAML with syntax highlighting, inline validation, and a publish button.
Simulator
Test policy decisions against job attributes. Single-request, batch CSV/JSON, or replay against historical jobs.
Publish & Rollback
Publish bundles with author and message. Rollback to any previous snapshot via the policy timeline.
Audit Timeline
Filterable history of publishes, rollbacks, rule changes, and config changes with actor and timestamp.
Snapshot Diff
Side-by-side YAML comparison of bundle versions with rollback action on any historical snapshot.
POST /api/v1/policy/publish
{
"bundle_ids": ["default"],
"author": "platform-team",
"message": "Add remediation constraints for prod"
}
POST /api/v1/policy/rollback
{
"snapshot_id": "snap_a3f8c1e2"
}Real-Time Updates
The dashboard maintains a persistent WebSocket connection to /api/v1/stream for live updates. Authentication uses a subprotocol header with base64url-encoded API key. Events invalidate React Query caches to keep all views current without polling.
| Event | Source | Description |
|---|---|---|
| job.submit | jobRequest | New job submitted (topic, labels, tenant) |
| job.result.* | jobResult | Job completed (status, error, execution time) |
| job.progress | jobProgress | Job progress update (percent, message) |
| job.cancel | jobCancel | Job cancelled (reason) |
| worker.heartbeat | heartbeat | Worker health (pool, active jobs, capacity) |
| system.alert | alert | System alert (generic payload) |
job.*→ jobs listapproval.*→ approvals list + nav badgepolicy.*→ policy bundles + rulespack.*→ packs listAuto-reconnect with exponential backoff (1s → 30s max, 2× factor).
// Connection URL ws://localhost:8081/api/v1/stream // Subprotocol header Sec-WebSocket-Protocol: cordum-api-key.<base64url(apiKey)> // base64url encoding btoa(apiKey) .replace(/\+/g, "-") .replace(/\//g, "_") .replace(/=+$/, "")
Configuration
The dashboard reads /config.json at startup (2-second timeout, graceful fallback). Fields are validated: URLs must be relative or http/https, traceUrlTemplate blocks javascript: and data: protocols for XSS prevention.
| Field | Type | Description | Example |
|---|---|---|---|
| apiBaseUrl | string | API gateway URL. Relative or absolute (http/https). | http://localhost:8081 |
| apiKey | string | API key for authentication (X-API-Key header). | sk-... |
| tenantId | string | Tenant isolation scope (X-Tenant-ID header). | default |
| principalId | string | Identity of the dashboard user for audit logs. | user@example.com |
| principalRole | string | Role for RBAC. Set to secops for policy write access. | secops |
| traceUrlTemplate | string? | URL template for trace links. {traceId} is replaced at runtime. | https://dd.example.com/apm/traces/{traceId} |
{
"apiBaseUrl": "http://localhost:8081",
"apiKey": "sk-cordum-...",
"tenantId": "default",
"principalId": "platform-team@example.com",
"principalRole": "secops",
"traceUrlTemplate": "https://dd.example.com/apm/traces/{traceId}"
}VITE_API_URLVITE_WS_URLVITE_POLICY_CONFIG_SUPPORTEDVITE_POLICY_STATS_SUPPORTEDCORDUM_CORS_ORIGINS- Dashboard sends
X-API-KeyandX-Tenant-IDheaders on every request - WebSocket uses subprotocol auth (no headers on WS upgrade)
- Separate-domain deployment: add dashboard origin to
CORDUM_CORS_ORIGINSon the gateway - Policy write operations restricted to
secopsrole
