06 — UI & Reporting Architecture
Scope: Web UI for SecurityV0 — page specifications, component architecture, data fetching patterns, evidence pack rendering, and export. This document consumes the API contract from 04-api-layer.md and the entity/finding types from 01-data-model.md.
Graph visualization rationale: The @xyflow/react + Dagre decision, layout configuration, and alternatives analysis are documented in 00-overview.md §9. This document references that section — it does not repeat it.
Implementation status:
- Core pages (Dashboard, Graph Explorer, Findings, Entities, Automations, Syncs, Temporal): [Implemented]
- Execution chains page, new entity type colors/edges in graph: [Planned]
- Entity model updated to 9 types per ADR-006.
1. Tech Stack
| Layer | Technology | Version | Purpose |
|---|---|---|---|
| Framework | React | 19.x | Component model, hooks |
| Language | TypeScript | 5.9.x | Type safety |
| Build | Vite | 7.x | Dev server, bundling |
| Graph | @xyflow/react | 12.x | Canvas, pan/zoom, node interaction |
| Layout | Dagre | 0.8.x | Hierarchical Sugiyama layout |
| Data Fetching | TanStack Query | 5.x | Caching, refetch, optimistic updates |
| Data Tables | @tanstack/react-table | 8.x | Server-side filtering, sorting, pagination |
| Routing | React Router | 7.x | Client-side navigation |
| Styling | Tailwind CSS | 4.x | Utility-first CSS |
| Icons | lucide-react | 0.5.x | Consistent icon set |
For the rationale behind @xyflow/react + Dagre over alternatives (force-graph-2d, Cytoscape.js, ELK.js), see 00-overview.md §9.
2. Route Structure & Navigation
2.1 Routes
| Path | Page | Primary API Endpoints | Status |
|---|---|---|---|
/ | Dashboard | GET /findings, GET /syncs?limit=1 | [Implemented] |
/automations | Automations List | GET /entities?entity_type=identity&identity_subtype={automation_subtypes} | [Implemented] — see note below |
/automations/:id | Automation Detail | GET /entities/{id}, GET /graph/subgraph | [Implemented] |
/findings | Findings List | GET /findings | [Implemented] |
/findings/:id | Finding Detail | GET /findings/{id}, GET /findings/{id}/evidence-pack | [Implemented] |
/graph | Graph Explorer | GET /entities, GET /graph/subgraph | [Implemented] |
/entities | Entities List | GET /entities | [Implemented] |
/entities/:id | Entity Detail | GET /entities/{id}, /timeline, /blast-radius | [Implemented] |
/syncs | Sync Management | GET /syncs, GET /syncs/{id} | [Implemented] — manual trigger (POST /syncs) is [Planned] |
/temporal | Temporal Comparison | GET /entities/{id}/diff | [Implemented] |
/execution-chains | Execution Chains | GET /execution-chains | [Planned] |
Automations query note: The platform does not yet have a dedicated
automationentity type (ADR-006 is not yet implemented in code). The current UI queries automations viaentity_type=identitywithidentity_subtypeset to automation subtypes (business_rule,flow_designer_flow,scheduled_job,system_execution) and applies a defaultsecurity_relevance=active_external,dormant_authorityfilter. When entity type reclassification is implemented, this will change toentity_type=automation.
2.2 Layout
+---------------------------------------------------+
| Navbar (h-16) |
| Logo - SecurityV0 - [tenant context] - search |
+----------+----------------------------------------+
| Sidebar | |
| (w-64) | Main Content Area |
| | |
| Dashboard| (page-specific content) |
| Automatio| |
| Graph | |
| Findings | |
| Entities | |
| Syncs | |
| Temporal | |
| | |
+----------+----------------------------------------+
- Navbar: Fixed top. Displays tenant context (tenant name from auth token), global search input.
- Sidebar: Fixed left, sticky. Navigation links with active-state highlighting. Icons from lucide-react.
- Breadcrumbs: Rendered in main content area for drill-down paths (e.g., Findings > Finding Detail > Evidence Pack).
3. Dashboard Page (/)
Purpose: At-a-glance security posture — active findings, entity statistics, sync health.
3.1 KPI Cards
Four severity cards in a 4-column grid:
| Card | Source | Color |
|---|---|---|
| Critical Findings | GET /findings?status=active&severity=critical | Red border |
| High Findings | GET /findings?status=active&severity=high | Orange border |
| Medium Findings | GET /findings?status=active&severity=medium | Yellow border |
| Low Findings | GET /findings?status=active&severity=low | Blue border |
Each card displays the count and a 30-day sparkline trend (derived from detected_at timestamps in the findings response).
3.2 Entity Statistics
Summary panel showing entity counts by type (9-type model per ADR-006):
| Entity Type | Source | Status |
|---|---|---|
| Identities | GET /entities?entity_type=identity -> meta.total_count | [Implemented] |
| Automations | GET /entities?entity_type=identity&identity_subtype=... -> meta.total_count | [Implemented] — uses identity subtype workaround (see §2.1 note) |
| Connections | GET /entities?entity_type=connection -> meta.total_count | [Planned] |
| Credentials | GET /entities?entity_type=credential -> meta.total_count | [Implemented] |
| Owners | GET /entities?entity_type=owner -> meta.total_count | [Implemented] |
| Roles | GET /entities?entity_type=role -> meta.total_count | [Implemented] |
| Permissions | GET /entities?entity_type=permission -> meta.total_count | [Implemented] |
| Resources | GET /entities?entity_type=resource -> meta.total_count | [Implemented] |
| Execution Evidence | GET /entities?entity_type=execution_evidence -> meta.total_count | [Planned] |
3.3 Recent Findings Feed
Last 10 active findings sorted by detected_at descending. Each row shows:
- Finding type badge (color-coded)
- Entity name (link to entity detail)
- Severity badge
- Time ago (relative timestamp)
API: GET /findings?status=active&sort=-detected_at&limit=10
3.4 Sync Status
Last sync indicator: time since last completed sync, next scheduled sync (if configured), pass/fail status.
API: GET /syncs?sort=-completed_at&limit=1
4. Graph Explorer Page (/graph)
Purpose: Interactive hierarchical graph visualization of the entity-relationship graph. Primary tool for exploring execution paths and identifying structural anomalies.
4.1 Layout
3:9 column grid — filter sidebar (left) + graph canvas (right).
4.2 Filter Sidebar
Sticky sidebar with filter controls:
| Filter | Type | Values |
|---|---|---|
| Entity Types | Checkboxes | identity, automation, connection, credential, owner, role, permission, resource, execution_evidence |
| Status | Checkboxes | active, disabled, deleted, departed (owners only) |
| Source System | Dropdown | Dynamic from entities in graph |
| Has Findings | Toggle | Show finding badge overlay |
| Finding Type | Multi-select | orphaned_ownership, scope_drift, dormant_authority, privilege_justification_gap, ownership_degraded |
Filters apply client-side against the loaded graph data. Entity type and status filters remove nodes and their connected edges. Finding filters toggle badge visibility without removing nodes.
4.3 Graph Canvas
@xyflow/react canvas with Dagre hierarchical layout (see 00-overview.md §9 for layout rationale and configuration).
Node rendering: Custom EntityNode component.
| Entity Type | Color | Node Size | Status |
|---|---|---|---|
identity | #3B82F6 (blue) | 140x60 | [Implemented] |
automation | #F97316 (orange-500) | 140x60 | [Planned] |
connection | #06B6D4 (cyan-500) | 120x50 | [Planned] |
credential | #6B7280 (gray) | 120x50 | [Implemented] |
owner | #10B981 (green) | 120x50 | [Implemented] |
role | #8B5CF6 (purple) | 120x50 | [Implemented] |
permission | #F59E0B (amber) | 120x50 | [Implemented] |
resource | #EF4444 (red) | 140x60 | [Implemented] |
execution_evidence | #A855F7 (purple-400) | 100x40 | [Planned] |
Node status overlays:
deleted: 50% opacity with "DELETED" overlay textdecayed: Red dashed border
Finding badge: Red circle positioned top-right of node, showing finding count or alert icon.
Edge styling:
| Relationship Type | Color | Style | Status |
|---|---|---|---|
| OWNED_BY | Green | Solid | [Implemented] |
| HAS_ROLE | Purple | Solid | [Implemented] |
| GRANTS | Orange | Solid | [Implemented] |
| AUTHENTICATES_TO | Blue | Solid | [Implemented] |
| APPLIES_TO | Gray | Dotted | [Implemented] |
| BELONGS_TO | Green | Dashed | [Implemented] |
| CALLS | Orange | Dashed | [Planned] |
| INVOKES | Cyan | Solid | [Planned] |
| USES | Gray | Dashed | [Planned] |
| AUTHENTICATES_AS | Blue | Dashed | [Planned] |
| RUNS_AS | Teal | Solid | [Implemented] |
| TRIGGERS_ON | Yellow | Dotted | [Planned] |
| EXECUTES_ON | Red | Solid | [Implemented] (narrowed: automation->resource only per ADR-007) |
| AUTHENTICATES_VIA | Gray | Dashed | (deprecated -- legacy only, see ADR-007) |
| Default | Gray | Solid | [Implemented] |
Dagre layout configuration:
rankdir: 'LR' // Left-to-right flow
nodesep: 80 // Vertical spacing between nodes in same rank
ranksep: 200 // Horizontal spacing between ranks
align: 'UL' // Upper-left alignment
Rank assignment: Entity types map to column positions — execution_evidence (-1), automation (0), identity (1), connection (2), credential (3), owner (4), role (5), permission (6), resource (7).
4.4 Node Interaction
- Click: Selects node, highlights direct neighbors (1-hop), opens detail panel below canvas.
- Detail panel: Shows entity label, type, status, source system, finding types (if any). Links to Entity Detail page.
- Double-click: Navigates to
/entities/:id.
4.5 Path Highlighting
When an identity node is selected, its execution paths are highlighted:
- Execution path edges glow with increased stroke width
- Non-path nodes dim to 40% opacity
- Path tooltip shows auth chain depth for cross-system paths
API: GET /identities/{id}/blast-radius on identity selection.
4.6 Legend & Controls
- Legend panel: Color swatches for all 9 entity types (identity, automation, connection, credential, owner, role, permission, resource, execution_evidence), positioned bottom-left.
- Node count panel: Total visible nodes, positioned top-right.
- Zoom controls: @xyflow/react built-in (+/- buttons, fit-view).
5. Findings List Page (/findings)
Purpose: Filterable, sortable table of all findings.
5.1 Filters
Three filter controls in a horizontal bar above the table:
| Filter | Type | Options |
|---|---|---|
| Finding Type | Dropdown | All / orphaned_ownership / scope_drift / dormant_authority / privilege_justification_gap / ownership_degraded |
| Severity | Dropdown | All / critical / high / medium / low |
| Status | Dropdown | All / active / acknowledged / remediated / false_positive |
Filters are applied as query parameters: GET /findings?finding_type=scope_drift&severity=high&status=active.
5.2 Table
| Column | Source Field | Sortable |
|---|---|---|
| Type | finding_type | Yes |
| Severity | severity (badge) | Yes |
| Entity | entity_name (link) | Yes |
| Detected | detected_at (relative time) | Yes (default: desc) |
| Status | status (badge) | Yes |
| Affected Resources | derived from evidence | No |
Row click navigates to /findings/:id.
5.3 Bulk Actions
Checkbox selection on rows enables bulk actions:
- Acknowledge —
PATCH /findings/{id}/statuswith{ status: "acknowledged" } - Mark False Positive —
PATCH /findings/{id}/statuswith{ status: "false_positive", reason: "..." }
5.4 Pagination
Cursor-based pagination matching the API contract. Footer shows: "Showing 1-25 of {total_count}" with Next/Previous buttons.
6. Finding Detail Page (/findings/:id)
Purpose: Full finding context with evidence pack rendering and status workflow.
6.1 Header
- Finding type badge (color-coded by type)
- Severity badge (color-coded: critical=red, high=orange, medium=yellow, low=blue)
- Status badge with transition dropdown
- Entity name as link to
/entities/:id - Detection timestamps: first detected, last updated
6.2 Deterministic Explanation
Full-width panel displaying deterministic_explanation text. This is the human-readable, no-inference explanation of the finding.
6.3 Evidence Completeness Report
Visual indicator for each evidence category:
| Category | Available | Unavailable | Partial |
|---|---|---|---|
| current_roles | Green dot | Red dot + reason | Yellow dot + note |
| role_history | Green dot | Red dot + reason | Yellow dot + note |
| execution_evidence | Green dot | Red dot + reason | Yellow dot + note |
| ownership_records | Green dot | Red dot + reason | Yellow dot + note |
| approval_records | Green dot | Red dot + reason | Yellow dot + note |
| credential_state | Green dot | Red dot + reason | Yellow dot + note |
Source: evidence_completeness field on the finding (see 01-data-model.md).
Each category shows its EvidenceAvailability status and the corresponding note from evidence_completeness.notes.
Example rendering:
Evidence Completeness
* current_roles Available
* role_history Unavailable -- sys_audit_role not enabled in target instance
* execution_evidence Partial -- syslog_transaction accessible, retention window: 30d
* ownership_records Available
* approval_records Unavailable -- no approval system configured
* credential_state Available
6.4 Evidence Pack Viewer
Rendered from GET /findings/{id}/evidence-pack. The evidence pack contains structured sections:
| Section | Content |
|---|---|
| Identity Summary | Entity properties, source system, creation date, status |
| Authority Snapshot | Current roles, permissions, execution paths |
| Ownership Timeline | Owner chain with status (active/decayed/departed), assignment dates |
| Blast Radius | Materialized execution paths as a mini-graph (@xyflow/react subgraph) |
| Remediation | Recommended actions from recommended_actions[] |
Integrity badge: If the evidence pack includes a hash, display a verification indicator (checkmark if hash matches, warning if mismatch).
6.5 Status Workflow
Finding status transitions via PATCH /findings/{id}/status:
active -> acknowledged -> remediated
active -> false_positive
acknowledged -> active (reopen)
acknowledged -> remediated
acknowledged -> false_positive
Each transition requires:
acknowledged: optionalacknowledged_byremediated: requiredresolved_by, optionalresolution_notesfalse_positive: requiredreason
6.6 Actions
- Export JSON: Download evidence pack as JSON file
- Export Markdown:
GET /findings/{id}/evidence-pack?format=markdown - Export PDF (Optional, post-MVP): Added as a separate phased enhancement using Markdown/HTML-to-PDF conversion
7. Entity Detail Page (/entities/:id)
Purpose: Complete view of a single entity — properties, graph context, timeline, ownership chain.
7.1 Tabs
| Tab | Content | API Endpoint |
|---|---|---|
| Properties | Key-value display of entity fields | GET /entities/{id} |
| Graph | Mini @xyflow/react showing 1-hop neighborhood | GET /entities/{id} (relationships) |
| Timeline | Chronological events | GET /entities/{id}/timeline |
| Ownership | Owner chain with status indicators | GET /entities/{id} (ownership edges) |
| Findings | Findings referencing this entity | GET /findings?entity_id={id} |
7.2 Properties Tab
Key-value table from entity properties object. Includes:
source_metadatafields (allowlisted subset — see 01-data-model.md Source Metadata Policy)source_metadata_hashdisplayed as truncated hash with copy button- Credential summary (if entity is identity with credentials): credential type, status, expiry
7.3 Graph Tab
Mini @xyflow/react canvas (400px height) centered on the current entity. Shows:
- The entity node (highlighted)
- All directly connected nodes (1-hop)
- Edges between them
Same Dagre layout, entity colors, and edge styles as the full Graph Explorer. Click on neighbor node navigates to that entity's detail page.
7.4 Timeline Tab
Chronological event list from GET /entities/{id}/timeline:
2026-02-07 14:30:22 role_assigned HAS_ROLE -> admin_role (sync: abc-123)
2026-02-06 09:15:00 entity_created sp-hr-onboarding (sync: abc-122)
Each event shows: timestamp, event type badge, description, sync reference link.
7.5 Ownership Tab
Owner chain visualization:
Primary Owners
* Alex Johnson (active) assigned 2025-11-01
o Sam Wilson (departed) decayed 2026-01-15, reason: "user disabled in IdP"
Secondary Owners
* Maria Garcia (active) assigned 2025-12-01
Inherited Owners
* IT Security Team (active) via: BELONGS_TO -> Engineering Dept
Status indicators: filled circle = active, empty circle = decayed/departed.
8. Temporal Comparison Page (/temporal)
Purpose: Side-by-side diff of an entity's state at two points in time.
8.1 Controls
- Entity selector (search/autocomplete against
GET /entities) - Two date pickers: "Before" (t1) and "After" (t2)
- Compare button triggers
GET /entities/{id}/diff?from={t1}&to={t2}
8.2 Diff Display
Side-by-side panels showing:
| Change Type | Visual |
|---|---|
| Added relationship | Green highlight, "+" prefix |
| Removed relationship | Red highlight, "-" prefix |
| Changed property | Yellow highlight, old -> new |
| Added execution path | Green path in graph |
| Removed execution path | Red (dashed) path in graph |
8.3 Graph Diff
Mini @xyflow/react canvas showing the union of both states:
- Nodes present in both: normal rendering
- Nodes added in t2: green border
- Nodes removed in t2: red dashed border
- Edges follow same added/removed coloring
9. Sync Management Page (/syncs)
Purpose: Monitor and trigger connector sync operations.
9.1 Sync List
Table of recent syncs from GET /syncs:
| Column | Source |
|---|---|
| Connector Type | connector_type |
| Status | status (badge: completed/running/failed) |
| Started | started_at |
| Duration | computed from started_at / completed_at |
| Entities Affected | metrics.entities_affected |
| Events Created | metrics.events_created |
9.2 Sync Detail
Drill into GET /syncs/{id} for:
- Sync metrics (audit_records_fetched, events_created, entities_affected, paths_recomputed)
- Error log (if failed)
- Evidence completeness report from the connector health check
9.3 Manual Trigger [Planned]
"Trigger Sync" button -> POST /syncs with source system selector. Confirmation dialog before executing. Requires the POST /syncs endpoint (see 04-api-layer.md).
9A. Execution Chains Page (/execution-chains) -- [Planned]
Purpose: List, filter, and explore execution chains — the typed paths from automation entry points through connections and credentials to destination identities and their authorized resources.
Status: [Planned] — This page is designed in ADR-008 but not yet implemented. The
execution_chainscollection and API endpoints are pending.
9A.1 Chain List
Table of execution chains from GET /api/v1/execution-chains:
| Column | Source Field | Sortable |
|---|---|---|
| Name | name | Yes |
| Trigger | summary.trigger | Yes |
| Destination | summary.destination | Yes |
| Egress Category | summary.egress_category (badge) | Yes |
| Ownership | summary.ownership_status (badge) | Yes |
| Max Sensitivity | summary.max_sensitivity (badge) | Yes (default: desc) |
| Entities | entity_refs.length | Yes |
| Last Seen | last_seen_at | Yes |
9A.2 Chain Filters
| Filter | Type | Values |
|---|---|---|
| Egress Category | Dropdown | identity_provider, itsm, monitoring, unknown |
| Ownership Status | Dropdown | owned, orphaned, degraded |
| Max Sensitivity | Dropdown | public, internal, confidential, restricted |
| Blast Radius Domain | Multi-select | Dynamic from summary.blast_radius_domains |
9A.3 Chain Detail
Drill into GET /api/v1/execution-chains/{id}:
- Chain summary panel: trigger, destination, egress_category, ownership_status, total_roles, canonical_permissions
- Entity chain graph: Mini @xyflow/react showing the chain's
entity_refsas a linear graph with role labels on each node - Blast radius panel: Domains reachable via this chain with sensitivity levels
- Composition hash: Displayed for change tracking (SHA256 fingerprint)
- Temporal info: first_detected_at, last_seen_at, sync_version
10. Data Fetching Patterns
10.1 TanStack Query Hooks
All API calls wrapped in custom hooks using TanStack Query:
| Hook | Query Key | Endpoint | Status |
|---|---|---|---|
useEntity(id) | ['entities', id] | GET /entities/{id} | [Implemented] |
useEntities(filters) | ['entities', filters] | GET /entities | [Implemented] |
useEntityTimeline(id) | ['entities', id, 'timeline'] | GET /entities/{id}/timeline | [Implemented] |
useBlastRadius(id) | ['blast-radius', id] | GET /identities/{id}/blast-radius | [Implemented] |
useAccessibleBy(id) | ['accessible-by', id] | GET /resources/{id}/accessible-by | [Implemented] |
useCrossSystemPaths(id) | ['cross-system-paths', id] | GET /identities/{id}/cross-system-paths | [Implemented] |
useFinding(id) | ['findings', id] | GET /findings/{id} | [Implemented] |
useFindings(filters) | ['findings', filters] | GET /findings | [Implemented] |
useEvidencePack(id) | ['evidence-pack', id] | GET /findings/{id}/evidence-pack | [Implemented] |
useEntityDiff(id, t1, t2) | ['entities', id, 'diff', t1, t2] | GET /entities/{id}/diff | [Implemented] |
useSyncs(filters) | ['syncs', filters] | GET /syncs | [Implemented] |
useSync(id) | ['syncs', id] | GET /syncs/{id} | [Implemented] |
useSubgraph(seedId, mode, depth) | ['subgraph', seedId, mode, depth] | GET /graph/subgraph | [Implemented] |
useExecutionChains(filters) | ['execution-chains', filters] | GET /execution-chains | [Planned] |
useExecutionChain(id) | ['execution-chains', id] | GET /execution-chains/{id} | [Planned] |
10.2 Cache Strategy
- Stale time: 30 seconds for entity/finding data (refreshed frequently during active use)
- Cache time: 5 minutes (keep cached data for quick back-navigation)
- Refetch on window focus: Enabled for findings and sync status
10.3 Cache Invalidation
Sync completion invalidates dependent queries:
On sync completed (detected via polling GET /syncs/{id}):
-> invalidate ['entities']
-> invalidate ['findings']
-> invalidate ['blast-radius']
-> invalidate ['accessible-by']
-> invalidate ['cross-system-paths']
-> invalidate ['subgraph']
-> invalidate ['execution-chains']
Finding status mutations invalidate:
On PATCH /findings/{id}/status:
-> invalidate ['findings', id]
-> invalidate ['findings'] (list may change)
10.4 Loading & Error States
Every data-fetching component handles three states:
- Loading: Spinner with contextual message (e.g., "Loading graph data...")
- Error: Red error panel with message and retry button
- Empty: Contextual empty state (e.g., "No findings match your filters")
10.5 Pagination Integration
For paginated endpoints, hooks accept cursor parameters and expose navigation:
const { data, fetchNextPage, hasNextPage } = useFindings({
status: 'active',
limit: 25,
});
// data.cursor.next used for fetchNextPage
// data.cursor.has_more controls hasNextPage
11. Component Architecture
11.1 Shared Components
| Component | Purpose | Used By | Status |
|---|---|---|---|
EntityBadge | Entity type label with color | Graph, Findings, Entity Detail | [Implemented] |
FindingSeverityBadge | Severity label (critical/high/medium/low) | Findings List, Finding Detail, Dashboard | [Implemented] |
FindingTypeBadge | Finding type label with icon | Findings List, Finding Detail | [Implemented] |
StatusIndicator | Status dot + label | Entity Detail, Findings, Syncs | [Implemented] |
EvidenceCompletenessBar | Category availability visual | Finding Detail | [Implemented] |
EntityNode | Custom @xyflow/react node | Graph Explorer, Entity Detail graph tab, Finding blast radius | [Implemented] |
MiniGraph | Small @xyflow/react canvas (1-hop) | Entity Detail, Finding Detail | [Implemented] |
TimelineEvent | Single event row | Entity Timeline, Dashboard recent activity | [Implemented] |
CursorPagination | Next/Prev with count display | Findings List, Entity List, Syncs | [Implemented] |
DataTable | Enterprise data table with server-side features | Entities, Findings, Chains | [Implemented] |
AutomationNode | Custom node for automation entities | Graph Explorer, Chain Detail | [Planned] |
ConnectionNode | Custom node for connection entities | Graph Explorer, Chain Detail | [Planned] |
ChainCard | Execution chain summary card | Chain List, Dashboard | [Planned] |
11.2 File Structure
src/ui/
├── App.tsx # Router setup
├── Layout.tsx # Navbar + sidebar + outlet
├── api.ts # API client functions
├── hooks/ # TanStack Query hooks
│ ├── useEntity.ts
│ ├── useFindings.ts
│ ├── useBlastRadius.ts
│ ├── useSyncs.ts
│ └── ...
├── pages/
│ ├── DashboardPage.tsx
│ ├── GraphExplorerPage.tsx
│ ├── FindingsPage.tsx
│ ├── FindingDetailPage.tsx
│ ├── EntityDetailPage.tsx
│ ├── EntitiesListPage.tsx # [Implemented]
│ ├── AutomationsPage.tsx # [Implemented]
│ ├── AutomationDetailPage.tsx # [Implemented]
│ ├── TemporalComparePage.tsx
│ ├── SyncsPage.tsx
│ └── ExecutionChainsPage.tsx # [Planned]
├── components/
│ ├── graph/
│ │ ├── GraphCanvas.tsx
│ │ ├── EntityNode.tsx
│ │ ├── MiniGraph.tsx
│ │ ├── GraphLegend.tsx
│ │ ├── GraphFilterSidebar.tsx
│ │ ├── GraphNodeDetailsDrawer.tsx
│ │ ├── AutomationNode.tsx # [Planned]
│ │ ├── ConnectionNode.tsx # [Planned]
│ │ └── layout.ts # Dagre layout config
│ ├── findings/
│ │ ├── EvidenceCompletenessBar.tsx
│ │ ├── EvidencePackViewer.tsx
│ │ └── StatusWorkflow.tsx
│ ├── chains/ # [Planned]
│ │ ├── ChainCard.tsx
│ │ ├── ChainGraph.tsx
│ │ └── ChainFilters.tsx
│ ├── shared/
│ │ ├── EntityBadge.tsx
│ │ ├── FindingSeverityBadge.tsx
│ │ ├── StatusIndicator.tsx
│ │ ├── CursorPagination.tsx
│ │ └── TimelineEvent.tsx
│ ├── table/
│ │ ├── DataTable.tsx # [Implemented]
│ │ ├── DataTableFilters.tsx # [Implemented]
│ │ └── DataTablePagination.tsx # [Implemented]
│ └── temporal/
│ ├── DiffDisplay.tsx
│ └── GraphDiff.tsx
└── types/
└── api.ts # Response type definitions
12. Export & Reporting
12.1 Evidence Pack Export
Evidence packs are the primary reporting artifact. Export formats:
| Format | Method | Use Case |
|---|---|---|
| JSON | GET /findings/{id}/evidence-pack | Machine-readable, API consumers |
| Markdown | GET /findings/{id}/evidence-pack?format=markdown | Human-readable, email-friendly |
| PDF (post-MVP optional) | Separate phased add-on (Markdown/HTML-to-PDF conversion) | Formal reports, compliance attachments |
MVP priority is JSON and Markdown export. PDF is not required for v0.2; if enabled later, it should be generated from Markdown/HTML via a dedicated conversion step.
12.2 Entity List Export
CSV export from the findings list or entity queries:
- User applies filters on findings or entity list page
- "Export CSV" button serializes current result set
- Client-side CSV generation (no server endpoint needed for MVP)
- Columns match the visible table columns
12.3 Graph Snapshot
PNG export of the current graph view:
- "Export PNG" button on Graph Explorer toolbar
- Client-side capture via
html2canvasor @xyflow/react's built-intoImage()method - Captures current viewport (zoom level, filters applied)
13. MVP Exclusions
The following are explicitly out of scope for MVP:
| Feature | Rationale |
|---|---|
| Reporting templates | Custom report builder adds complexity without MVP value |
| Mobile responsiveness | Desktop-first for security analysts |
| Real-time WebSocket updates | Polling sync status is sufficient at MVP scale |
| Admin / settings pages | Configuration via environment variables for MVP |
| User role management UI | Single-tenant, single-role for MVP |
| Dark mode | Cosmetic, not functional |
| Custom dashboards | Fixed dashboard layout sufficient for MVP |
| Scheduled report delivery | Manual export covers MVP needs |
| Native PDF evidence-pack export | Deferred. Optional post-MVP phase using Markdown/HTML-to-PDF conversion |
| GraphQL | REST API covers all MVP query patterns |
| Webhooks / subscriptions | Polling is sufficient at MVP sync frequency |
14. Cross-Reference Summary
| This Document | References |
|---|---|
| §4 Graph Explorer layout rationale | 00-overview.md §9 |
| §2-§9A All API endpoints | 04-api-layer.md |
| §3.2 Entity statistics (9-type model) | ADR-006 |
| §4.3 Edge styling (typed execution edges) | ADR-007 |
| §9A Execution chains page | ADR-008 |
| §6.3 Evidence completeness categories | 01-data-model.md EvidenceAvailability |
| §6.4 Evidence pack structure | 01-data-model.md Finding schema |
| §7.2 Source metadata policy | 01-data-model.md Source Metadata Policy |
| §4.3 Entity type colors, node sizes | Implemented in src/ui/components/graph/EntityNode.tsx |
| §4.3 Dagre config | Implemented in src/ui/components/graph/layout.ts |