| status | Proposed | |||
|---|---|---|---|---|
| date | 2025-11-18 | |||
| deciders |
|
|||
| related |
|
The web application started as a graph visualization tool—click around, explore concepts, view relationships. But as the platform evolved, we added job management, OAuth configuration, ingestion workflows, and published query endpoints. These features live in the operator container and CLI, forcing users to jump between interfaces for routine tasks.
The disconnect creates friction. You visualize a concept in the web app, decide to ingest more documents, drop to terminal, run CLI commands, return to browser, refresh to see results. Want to manage jobs? Back to terminal. Need to configure OAuth? Operator container. The web app shows you the knowledge but doesn't let you create or manage it.
This ADR restructures the web application from a single-purpose visualization tool into a multi-function workstation. The left sidebar transforms from "pick a visualization type" to "pick a workflow category": Explorers for visualization, Ingest for uploading content, Jobs for queue management, Admin for platform configuration. Same plugin architecture as explorers, now extended to entire functional areas. The result: one interface for exploring, creating, and managing knowledge graphs.
The web application evolved from a visualization tool with a single focus:
┌─────────────────────────────────────┐
│ Visualization Explorer │
│ │
│ ┌─────────┐ ┌────────────────────┐ │
│ │Explorers│ │ Main Content │ │
│ │• 2D │ │ • Query tabs │ │
│ │• 3D │ │ • Graph canvas │ │
│ └─────────┘ └────────────────────┘ │
└─────────────────────────────────────┘
This served well for exploring knowledge graphs, but the platform has grown capabilities that don't fit this model:
- Ingestion - Currently CLI/MCP only, no web interface
- Job management - No visibility into job queue from web
- Graph editing - No manual CRUD operations
- OAuth/security - Configuration via operator container only
- Published endpoints - ADR-066 introduces flow publishing with no management UI
- Reporting - No tabular/export views
Users need a knowledge graph workstation - a unified interface for:
- Exploring - Visualizing and querying (current strength)
- Creating - Ingesting content, editing graph
- Managing - Jobs, security, published flows
- Reporting - Tabular views, exports
Transform the left sidebar from "Explorer selector" to "Workstation navigation" with multiple functional categories.
┌─────────────────────────────┐
│ Knowledge Graph │
├─────────────────────────────┤
│ ▼ Explorers │
│ • 2D Force Graph │
│ • 3D Force Graph │
│ • [Future visualizations] │
│ │
│ ▸ Block Editor │
│ │
│ ▸ Ingest │
│ │
│ ▸ Jobs │
│ │
│ ▸ Report │
│ │
│ ▸ Edit │
│ │
│ ▸ Admin │
└─────────────────────────────┘
Interactive graph visualizations with embedded query tools.
Each explorer includes:
- Query mode tabs: Smart Search | Block Builder | openCypher
- Graph canvas (2D/3D/Sankey/Heatmap/etc.)
- Node info panel
- Results list
Pattern: Build query → visualize → iterate → save
Focused flow management environment.
Features:
- Saved diagrams list (left panel)
- Full block canvas (main area)
- Properties panel (right):
- Name, description, tags
- Execution mode toggle (Interactive ↔ Published)
- Output format (Visualization/JSON/CSV)
- Permissions (for published flows)
Pattern: Organize flows → configure → publish
Web-based content ingestion.
Features:
- Drag-and-drop file upload
- URL input field
- Batch directory selection
- Ontology selector
- Job preview with cost estimate
- Submit to job queue
Pattern: Drop files → configure → approve → monitor
Job queue visibility and management.
Features:
- Queue view (pending, running)
- History view (completed, failed)
- Job details (progress, logs, results)
- Approve/cancel actions
- Filter by status, ontology, date
Pattern: Monitor → approve → investigate
Tabular and export views.
Features:
- Saved queries list
- Tabular result view
- Export formats (JSON, CSV, Markdown)
- Column selection
- Sort/filter
- Pagination
Pattern: Query → view table → export
Manual graph editing.
Features:
- Node browser/search
- Create/update/delete nodes
- Create/update/delete edges
- Bypass upsert (direct graph manipulation)
- LLM-mediated quality suggestions (optional)
- Audit trail for manual edits
Pattern: Find node → edit properties → save
Platform administration.
Features:
- OAuth client management
- Register clients
- View/revoke tokens
- Configure scopes
- User management
- Create/edit users
- Assign roles
- Published flow management
- View all published flows
- Revoke access
- Usage analytics
- System status
- Database stats
- Embedding status
- AI provider status
Pattern: Configure → monitor → secure
The Block Builder appears in two contexts with shared state:
┌─────────────────────────────────────────────────┐
│ blockDiagramStore (Zustand) │
│ • workingNodes/Edges (current canvas) │
│ • savedDiagrams list │
│ • currentDiagramId │
│ • hasUnsavedChanges │
└─────────────────────────────────────────────────┘
▲ ▲
│ │
┌──────────┴──────┐ ┌───────┴────────┐
│ Embedded Mode │ │ Standalone Mode │
│ (in Explorers) │ │ (sidebar item) │
│ │ │ │
│ • Query tabs │ │ • Diagram list │
│ • Compact UI │ │ • Full canvas │
│ • Quick save │ │ • Properties │
│ • See results │ │ • Publish config│
└─────────────────┘ └─────────────────┘
Behavior:
- Save in embedded → appears in standalone list
- Create in standalone → loadable in any explorer
- Switch views → same working diagram stays loaded
- Unsaved changes persist across view switches
// App.tsx routes
<Routes>
<Route path="/" element={<Navigate to="/explore/2d" />} />
{/* Explorers */}
<Route path="/explore/2d" element={<ForceGraph2DExplorer />} />
<Route path="/explore/3d" element={<ForceGraph3DExplorer />} />
<Route path="/explore/sankey" element={<SankeyExplorer />} />
{/* Block Editor */}
<Route path="/blocks" element={<BlockEditorWorkspace />} />
<Route path="/blocks/:diagramId" element={<BlockEditorWorkspace />} />
{/* Ingest */}
<Route path="/ingest" element={<IngestWorkspace />} />
{/* Jobs */}
<Route path="/jobs" element={<JobsWorkspace />} />
<Route path="/jobs/:jobId" element={<JobDetail />} />
{/* Report */}
<Route path="/report" element={<ReportWorkspace />} />
{/* Edit */}
<Route path="/edit" element={<GraphEditor />} />
<Route path="/edit/node/:nodeId" element={<NodeEditor />} />
{/* Admin */}
<Route path="/admin" element={<AdminDashboard />} />
<Route path="/admin/clients" element={<OAuthClientManager />} />
<Route path="/admin/users" element={<UserManager />} />
<Route path="/admin/flows" element={<PublishedFlowManager />} />
</Routes>src/
├── components/
│ ├── layout/
│ │ ├── Sidebar.tsx # Main navigation
│ │ ├── SidebarCategory.tsx # Collapsible category
│ │ └── MainLayout.tsx # Shell with sidebar
│ │
│ ├── explorers/ # Existing + enhanced
│ │ ├── ForceGraph2D/
│ │ ├── ForceGraph3D/
│ │ └── common/
│ │ └── QueryTabs.tsx # Shared query mode tabs
│ │
│ ├── blocks/ # Block Builder
│ │ ├── BlockBuilder.tsx # Canvas component
│ │ ├── BlockEditorWorkspace.tsx # Standalone view
│ │ └── ...
│ │
│ ├── ingest/ # New
│ │ ├── IngestWorkspace.tsx
│ │ ├── FileDropZone.tsx
│ │ └── IngestionForm.tsx
│ │
│ ├── jobs/ # New
│ │ ├── JobsWorkspace.tsx
│ │ ├── JobQueue.tsx
│ │ ├── JobHistory.tsx
│ │ └── JobDetail.tsx
│ │
│ ├── report/ # New
│ │ ├── ReportWorkspace.tsx
│ │ ├── TabularView.tsx
│ │ └── ExportPanel.tsx
│ │
│ ├── edit/ # New
│ │ ├── GraphEditor.tsx
│ │ ├── NodeEditor.tsx
│ │ └── EdgeEditor.tsx
│ │
│ └── admin/ # New
│ ├── AdminDashboard.tsx
│ ├── OAuthClientManager.tsx
│ ├── UserManager.tsx
│ └── PublishedFlowManager.tsx
│
└── store/
├── graphStore.ts
├── blockDiagramStore.ts
├── jobStore.ts # New
└── adminStore.ts # New
Existing:
/api/v1/queries/*- Graph queries/api/v1/ontology/*- Ontology management/api/v1/jobs/*- Job operations
New or Enhanced:
# Ingest (enhanced for web)
POST /api/v1/ingest/upload # Multipart file upload
POST /api/v1/ingest/url # URL ingestion
# Jobs (enhanced for web)
GET /api/v1/jobs # List with filters
GET /api/v1/jobs/{id}/logs # Stream job logs
# Admin
GET /api/v1/admin/clients # List OAuth clients
POST /api/v1/admin/clients # Register client
DELETE /api/v1/admin/clients/{id}
GET /api/v1/admin/users # List users
POST /api/v1/admin/users # Create user
PATCH /api/v1/admin/users/{id} # Update user
GET /api/v1/admin/flows # List all published flows
DELETE /api/v1/admin/flows/{id} # Unpublish flow
# Graph editing
POST /api/v1/graph/nodes # Create node
PATCH /api/v1/graph/nodes/{id} # Update node
DELETE /api/v1/graph/nodes/{id} # Delete node
POST /api/v1/graph/edges # Create edge
DELETE /api/v1/graph/edges/{id} # Delete edgeCommon UI patterns across workspaces warrant a shared component library:
web/src/components/shared/
├── data-display/
│ ├── DataTable.tsx # Sortable, filterable, paginated tables
│ ├── StatusBadge.tsx # Running/Pending/Failed/Completed
│ ├── MetricCard.tsx # Stats with label
│ └── EmptyState.tsx # "No results" with action
│
├── layout/
│ ├── ListDetailLayout.tsx # Left list, right detail pattern
│ ├── ActionToolbar.tsx # Icon buttons with tooltips
│ └── PanelHeader.tsx # Title + actions
│
├── input/
│ ├── SearchFilterBar.tsx # Text + filters + sort
│ ├── FileDropZone.tsx # Drag-drop with preview
│ ├── FormField.tsx # Label + input + validation
│ └── OntologySelector.tsx # Reusable ontology picker
│
├── feedback/
│ ├── ConfirmDialog.tsx # Destructive action confirmation
│ ├── Toast.tsx # Success/error/info notifications
│ ├── LoadingSkeleton.tsx # Consistent loading states
│ └── ProgressBar.tsx # Job/upload progress
│
└── index.ts # Barrel export
Design tokens (colors, spacing, typography) should be centralized in Tailwind config or CSS variables for consistent theming across all workspaces.
The explorer codebase already has patterns that should be extracted for workstation-wide use:
From explorers/common/:
// PanelStack - auto-positioning panels with collapse support
<PanelStack side="right" gap={16}>
<NodeInfoBox />
<Legend />
</PanelStack>
// Collapsible sections pattern (NodeInfoBox, GraphSettingsPanel)
const [expanded, setExpanded] = useState(true);
<button onClick={() => setExpanded(!expanded)}>
{expanded ? <ChevronDown /> : <ChevronRight />}
Section Title
</button>
{expanded && <SectionContent />}
// Formatted metrics (utils.ts)
formatGrounding(0.73) // "+73%"
formatDiversity(0.42) // "42%"
formatAuthenticatedDiversity // "✓ 42%"From components/shared/:
// ModeDial - radio selection with icons
<ModeDial
options={[
{ id: 'smart', label: 'Smart', icon: Search },
{ id: 'blocks', label: 'Blocks', icon: Blocks },
]}
selected={mode}
onChange={setMode}
/>
// Debounced input pattern (SearchBar)
const [query, setQuery] = useState('');
const debouncedQuery = useDebouncedValue(query, 300);
// Use debouncedQuery for API calls
// Results dropdown pattern
<SearchResultsDropdown
results={results}
onSelect={handleSelect}
loading={isLoading}
/>Extraction priorities:
- CollapsibleSection - wrap the expand/collapse pattern
- DetailPanel - header + scrollable content + actions
- MetricDisplay - formatted number with label and indicator
- SearchableDropdown - debounced input + results list
- SettingsForm - labeled fields with validation
Pattern usage by workspace:
| Component | Explorers | Blocks | Ingest | Jobs | Report | Edit | Admin |
|---|---|---|---|---|---|---|---|
| DataTable | ✓ | ✓ | ✓ | ✓ | ✓ | ||
| ListDetailLayout | ✓ | ✓ | ✓ | ✓ | |||
| SearchFilterBar | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | |
| FileDropZone | ✓ | ✓ | |||||
| StatusBadge | ✓ | ✓ | ✓ | ||||
| ConfirmDialog | ✓ | ✓ | ✓ | ✓ | |||
| Toast | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| EmptyState | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
The cli/ directory contains substantial TypeScript code shared with MCP server that can be reused:
cli/src/
├── api/client.ts # API client - reuse directly
├── cli/
│ ├── jobs.ts # Job listing, approval, cancel
│ ├── ingest.ts # File/URL ingestion logic
│ ├── oauth.ts # OAuth client management
│ ├── admin.ts # Admin operations
│ ├── search.ts # Search operations
│ └── vocabulary.ts # Vocabulary operations
└── lib/auth/
├── auth-client.ts # Auth state management
├── device-flow.ts # Device authorization
└── oauth-types.ts # Type definitions
Reuse strategy:
- Extract shared types/interfaces to common package
- API client methods directly portable to web
- Auth library adapts to browser storage (localStorage vs file)
- Business logic (validation, formatting) reusable as-is
Benefits:
- Consistent API interactions across CLI, MCP, and web
- Type safety shared across all clients
- Bug fixes propagate to all consumers
- Reduced development time for web workspaces
- Refactor Sidebar to support categories
- Add routing for all workspaces
- Create placeholder components for new areas
- Block Editor standalone view (using existing BlockBuilder)
- Job list view with filters
- Job detail view with logs
- Approve/cancel actions
- Real-time status updates
- File drop zone component
- Upload API integration
- Ontology selector
- Job preview and submission
- OAuth client management
- User management
- Published flow overview
- System status dashboard
- Tabular result view
- Export functionality
- Saved query integration
- Node browser/search
- Node/edge CRUD forms
- Audit trail display
- Unified Interface: All platform capabilities accessible from one place
- Reduced CLI Dependency: Web-first workflow for common operations
- Better Discoverability: Users see full platform capabilities in sidebar
- Consistent UX: Same patterns across all workspaces
- Enables ADR-066: UI for publishing/managing query flows
- Increased Complexity: More routes, components, state management
- API Surface Growth: Many new endpoints needed
- Auth Complexity: Different capabilities need different permissions
- Testing Burden: More UI to test across workspaces
- Bundle Size: More code to ship (can mitigate with code splitting)
- Migration: Existing explorer functionality unchanged
- Documentation: Each workspace needs user guide
- Mobile: Sidebar navigation works but some workspaces need responsive design
Option: Build separate apps for admin, ingest, reporting.
Rejected because:
- Users must switch between apps
- Duplicate auth flows
- No unified state (e.g., can't jump from job to results)
Option: Top tabs instead of sidebar categories.
Rejected because:
- Limited space for 7+ categories
- Doesn't scale with ADR-064 explorer additions
- Sidebar pattern already established
Option: Keep single explorer view, use modals for other functions.
Rejected because:
- Modals are disruptive for complex workflows
- Can't see job progress while editing
- No persistent state for lengthy operations
Adoption:
- % of users accessing non-explorer workspaces
- Web vs CLI usage for ingestion
- Time spent in each workspace category
Efficiency:
- Time to complete common workflows (ingest file, manage job, edit node)
- Reduction in CLI usage for routine tasks
Discovery:
- Users trying new workspaces after initial exposure
- Feature awareness in user surveys
- ADR-034: Graph Visualization Architecture
- ADR-066: Published Query Endpoints
- React Router documentation
- Zustand state management patterns