feat(ui): add type filter toggles
This commit is contained in:
487
SPEC.md
Normal file
487
SPEC.md
Normal file
@@ -0,0 +1,487 @@
|
||||
# Homelab Topology Visualizer - Specification
|
||||
|
||||
## 1. Project Overview
|
||||
|
||||
**Project Name:** Homelab Topology Visualizer (HomelabTV)
|
||||
**Type:** Interactive Web Application
|
||||
**Core Functionality:** A visual, interactive graph-based UI that displays the complete topology of a homelab - from network infrastructure (UniFi gateway, VLANs) through hosts, Docker containers/services, to filesystem paths and files.
|
||||
**Target Users:** Homelab administrators, DevOps engineers, home network enthusiasts
|
||||
|
||||
---
|
||||
|
||||
## 2. UI/UX Specification
|
||||
|
||||
### Layout Structure
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ HEADER: Logo + Title + View Mode Selector + Refresh Button │
|
||||
├─────────────┬───────────────────────────────────────────────────┬───────────────┤
|
||||
│ │ │ │
|
||||
│ LEFT │ MAIN GRAPH CANVAS │ RIGHT │
|
||||
│ PANEL │ (React Flow / D3.js) │ PANEL │
|
||||
│ │ │ │
|
||||
│ Subnodes │ Nodes connected by edges showing │ Details │
|
||||
│ of │ relationships: │ Tabs: │
|
||||
│ selected │ Gateway → VLAN → Host → Service → Volume │ │
|
||||
│ node │ │ - Details │
|
||||
│ │ [Interactive: click to select, │ - Config │
|
||||
│ - List │ drag to pan, scroll to zoom] │ - Files │
|
||||
│ - Click │ │ - Usage │
|
||||
│ to │ │ - Importance │
|
||||
│ select │ │ │
|
||||
│ │ │ │
|
||||
├─────────────┴───────────────────────────────────────────────────┴───────────────┤
|
||||
│ FOOTER: Status bar (last refresh, node count, connection status) │
|
||||
└─────────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
- **Header:** Fixed, 56px height
|
||||
- **Left Panel:** 280px width, collapsible
|
||||
- **Right Panel:** 360px width, collapsible
|
||||
- **Graph Canvas:** Flexible, fills remaining space
|
||||
- **Footer:** Fixed, 32px height
|
||||
|
||||
### Responsive Breakpoints
|
||||
|
||||
- **Desktop (≥1200px):** Full 3-column layout
|
||||
- **Tablet (768px-1199px):** Left panel hidden, right panel 300px
|
||||
- **Mobile (<768px):** Panels as overlays/drawers
|
||||
|
||||
### Visual Design
|
||||
|
||||
#### Color Palette
|
||||
|
||||
```css
|
||||
/* Network Layer */
|
||||
--network-gateway: #6366F1; /* Indigo - UniFi gateway */
|
||||
--network-vlan: #8B5CF6; /* Purple - VLANs */
|
||||
--network-wifi: #EC4899; /* Pink - Access points */
|
||||
|
||||
/* Host Layer */
|
||||
--host-physical: #10B981; /* Emerald - Physical servers */
|
||||
--host-vm: #14B8A6; /* Teal - Virtual machines */
|
||||
--host-container: #F59E0B; /* Amber - LXC containers */
|
||||
|
||||
/* Service Layer */
|
||||
--service-media: #EF4444; /* Red - Jellyfin, Radarr, etc */
|
||||
--service-infra: #3B82F6; /* Blue - Traefik, Authentik */
|
||||
--service-monitoring: #22C55E; /* Green - Prometheus, Grafana */
|
||||
--service-ai: #F97316; /* Orange - Ollama, Litellm */
|
||||
--service-storage: #06B6D4; /* Cyan - Storage services */
|
||||
|
||||
/* Filesystem Layer */
|
||||
--filesystem-nfs: #84CC16; /* Lime - NFS mounts */
|
||||
--filesystem-volume: #A855F7; /* Purple - Docker volumes */
|
||||
--filesystem-path: #EAB308; /* Yellow - File paths */
|
||||
|
||||
/* UI Colors */
|
||||
--bg-primary: #0F172A; /* Slate 900 */
|
||||
--bg-secondary: #1E293B; /* Slate 800 */
|
||||
--bg-tertiary: #334155; /* Slate 700 */
|
||||
--text-primary: #F8FAFC; /* Slate 50 */
|
||||
--text-secondary: #94A3B8; /* Slate 400 */
|
||||
--border: #475569; /* Slate 600 */
|
||||
--accent: #38BDF8; /* Sky 400 */
|
||||
--success: #22C55E;
|
||||
--warning: #F59E0B;
|
||||
--error: #EF4444;
|
||||
```
|
||||
|
||||
#### Typography
|
||||
|
||||
- **Font Family:** `"JetBrains Mono", "Fira Code", monospace` for data; `"Inter", system-ui` for UI
|
||||
- **Sizes:**
|
||||
- H1 (Title): 24px, weight 700
|
||||
- H2 (Section): 18px, weight 600
|
||||
- H3 (Node name): 14px, weight 600
|
||||
- Body: 13px, weight 400
|
||||
- Caption: 11px, weight 400
|
||||
|
||||
#### Spacing System
|
||||
|
||||
- Base unit: 4px
|
||||
- Padding: 8px (sm), 12px (md), 16px (lg), 24px (xl)
|
||||
- Margins: 4px (xs), 8px (sm), 16px (md), 24px (lg)
|
||||
- Border radius: 4px (sm), 8px (md), 12px (lg)
|
||||
|
||||
#### Visual Effects
|
||||
|
||||
- **Node shadows:** `0 2px 8px rgba(0,0,0,0.3)`
|
||||
- **Panel shadows:** `0 4px 24px rgba(0,0,0,0.4)`
|
||||
- **Glow on hover:** `0 0 12px var(--node-color)`
|
||||
- **Transitions:** 200ms ease-out for all interactive elements
|
||||
- **Graph edges:** Animated dashed lines for active connections
|
||||
|
||||
### Components
|
||||
|
||||
#### Node Component
|
||||
|
||||
- **Shape:** Rounded rectangle (120x48px) or circle (48x48px) for endpoints
|
||||
- **Content:** Icon + Label + Status indicator
|
||||
- **States:**
|
||||
- Default: bg-secondary, border solid
|
||||
- Hover: Glow effect, scale 1.02
|
||||
- Selected: Border 2px accent, elevated shadow
|
||||
- Running: Green status dot
|
||||
- Stopped: Red status dot
|
||||
- Warning: Yellow status dot
|
||||
|
||||
#### Edge Component
|
||||
|
||||
- **Style:** Curved bezier lines with arrows
|
||||
- **States:**
|
||||
- Default: border 1px text-secondary
|
||||
- Active/Selected: border 2px accent, animated dash
|
||||
|
||||
#### Left Panel - Subnodes
|
||||
|
||||
- **Header:** "CHILD NODES" with count badge
|
||||
- **List Items:** Icon + Name + Type badge
|
||||
- **Interaction:** Click to focus/select in graph
|
||||
- **Empty state:** "No child nodes"
|
||||
|
||||
#### Right Panel - Details Tabs
|
||||
|
||||
- **Tab Bar:** Details | Config | Files | Usage | Importance
|
||||
- **Details Tab:** IP, MAC, Status, Uptime, Type, Description
|
||||
- **Config Tab:** YAML/JSON view of configuration
|
||||
- **Files Tab:** Tree view of relevant file paths
|
||||
- **Usage Tab:** CPU, Memory, Network graphs
|
||||
- **Importance Tab:** Critical / High / Medium / Low with reasoning
|
||||
|
||||
#### View Mode Selector
|
||||
|
||||
- **Options:**
|
||||
- 🌐 Network: Shows gateway, VLANs, WiFi, hosts
|
||||
- 🖥️ Hosts: Shows hosts and their services
|
||||
- 📦 Services: Shows all services and their dependencies
|
||||
- 💾 Filesystem: Shows volumes, mounts, paths
|
||||
- 🔗 Full: Complete topology (default)
|
||||
|
||||
---
|
||||
|
||||
## 3. Functionality Specification
|
||||
|
||||
### Core Features
|
||||
|
||||
#### F1: Interactive Graph Visualization
|
||||
- Render infrastructure as directed graph
|
||||
- Pan, zoom, fit-to-view controls
|
||||
- Click node to select (shows details)
|
||||
- Double-click to focus/center
|
||||
- Drag nodes to rearrange
|
||||
- Minimap for navigation
|
||||
|
||||
#### F2: Node Selection & Navigation
|
||||
- Single click: Select node, show details in right panel
|
||||
- Double click: Zoom to node, expand children
|
||||
- Right click: Context menu (copy IP, open URL, etc.)
|
||||
- Keyboard: Arrow keys to navigate, Enter to select
|
||||
|
||||
#### F3: Multi-View Modes
|
||||
- **Network View:** UniFi → VLANs → Subnets → Hosts
|
||||
- **Host View:** Hosts → VMs/LXCs → Containers
|
||||
- **Service View:** Services → Dependencies → Volumes
|
||||
- **Filesystem View:** TrueNAS → NFS → Volumes → Paths
|
||||
- **Full View:** Everything connected
|
||||
|
||||
#### F4: Detail Panels
|
||||
|
||||
**Left Panel (Subnodes):**
|
||||
- Shows children of selected node
|
||||
- Click to select in graph
|
||||
- Shows node count per type
|
||||
|
||||
**Right Panel (Details):**
|
||||
- 5 tabs with content
|
||||
- Details: Basic info (IP, type, status)
|
||||
- Config: Docker compose, YAML configs
|
||||
- Files: Related file paths (clickable)
|
||||
- Usage: Resource consumption
|
||||
- Importance: 1-5 stars with why
|
||||
|
||||
#### F5: Data Discovery (Hybrid Approach)
|
||||
|
||||
**Static Config (JSON/YAML):**
|
||||
```json
|
||||
{
|
||||
"network": {
|
||||
"gateway": { "model": "UniFi Dream Machine Pro", "ip": "192.168.1.1" },
|
||||
"vlans": [
|
||||
{ "id": 10, "name": "Family", "subnet": "192.168.10.0/24" },
|
||||
{ "id": 30, "name": "IoT", "subnet": "192.168.30.0/24" },
|
||||
{ "id": 50, "name": "Production", "subnet": "192.168.50.0/24" }
|
||||
],
|
||||
"wifi": [
|
||||
{ "ssid": "Will of D.", "vlan": "default" },
|
||||
{ "ssid": "Will of D. IoT", "vlan": 30 }
|
||||
]
|
||||
},
|
||||
"hosts": [
|
||||
{
|
||||
"name": "ubuntu",
|
||||
"ip": "192.168.50.61",
|
||||
"type": "vm",
|
||||
"role": "Primary Docker Host",
|
||||
"containers": ["traefik", "jellyfin", "authentik", ...]
|
||||
},
|
||||
{
|
||||
"name": "grizzley",
|
||||
"ip": "192.168.50.84",
|
||||
"type": "rpi5",
|
||||
"role": "Edge Services",
|
||||
"containers": ["frigate", "traefik"]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Auto-Discovery (SSH):**
|
||||
- SSH to hosts and run commands
|
||||
- `docker ps --format json` for containers
|
||||
- `docker network inspect` for network topology
|
||||
- `ls /mnt/truenas/` for NFS mounts
|
||||
- `cat /proc/cpuinfo` for hardware info
|
||||
|
||||
#### F6: Search & Filter
|
||||
- Search bar: Filter nodes by name
|
||||
- Type filter: Show/hide node types
|
||||
- Status filter: Running/Stopped/All
|
||||
- Quick jump: Cmd+K to open command palette
|
||||
|
||||
#### F7: Real-time Updates
|
||||
- Poll intervals: 30s (configurable)
|
||||
- WebSocket option for live updates
|
||||
- Visual indicator for stale data
|
||||
|
||||
### User Interactions & Flows
|
||||
|
||||
1. **Initial Load:**
|
||||
- Load static config
|
||||
- Run auto-discovery in background
|
||||
- Render graph with all nodes
|
||||
- Fit to view
|
||||
|
||||
2. **Select Node:**
|
||||
- Click node → Highlight path to root
|
||||
- Left panel shows children
|
||||
- Right panel shows details (Details tab)
|
||||
|
||||
3. **Change View:**
|
||||
- Click view mode → Re-render graph with filter
|
||||
- Preserve selected node if visible
|
||||
|
||||
4. **View Service Config:**
|
||||
- Select service node
|
||||
- Click "Config" tab
|
||||
- Shows docker-compose.yml content
|
||||
- Clickable file paths
|
||||
|
||||
5. **Refresh Data:**
|
||||
- Click refresh → Show loading state
|
||||
- Run discovery commands
|
||||
- Update graph
|
||||
- Show "Last updated: X seconds ago"
|
||||
|
||||
### Data Handling
|
||||
|
||||
- **State Management:** React Context + useReducer
|
||||
- **Persistence:** LocalStorage for user preferences (view mode, panel states)
|
||||
- **Caching:** In-memory cache with 30s TTL
|
||||
- **Error Handling:** Show stale data with warning banner if discovery fails
|
||||
|
||||
### Edge Cases
|
||||
|
||||
- Host unreachable: Show node with "Offline" status, gray out
|
||||
- Container stopped: Show with red indicator, allow config view
|
||||
- Empty discovery: Use static config as fallback
|
||||
- Large graphs (100+ nodes): Enable clustering, lazy render
|
||||
- Mobile: Simplified single-panel view with drawer navigation
|
||||
|
||||
---
|
||||
|
||||
## 4. Technical Architecture
|
||||
|
||||
### Tech Stack
|
||||
|
||||
- **Framework:** React 18 + TypeScript
|
||||
- **Build Tool:** Vite
|
||||
- **Graph Library:** React Flow (@xyflow/react)
|
||||
- **Styling:** Tailwind CSS
|
||||
- **State:** Zustand (lightweight)
|
||||
- **HTTP Client:** Axios
|
||||
- **SSH:** Node-SSH (backend) or jsch (frontend via proxy)
|
||||
- **Icons:** Lucide React
|
||||
- **Charts:** Recharts (for usage graphs)
|
||||
|
||||
### Project Structure
|
||||
|
||||
```
|
||||
homelab-topology/
|
||||
├── src/
|
||||
│ ├── components/
|
||||
│ │ ├── Graph/
|
||||
│ │ │ ├── TopologyGraph.tsx
|
||||
│ │ │ ├── NodeComponent.tsx
|
||||
│ │ │ ├── EdgeComponent.tsx
|
||||
│ │ │ └── controls.tsx
|
||||
│ │ ├── Panels/
|
||||
│ │ │ ├── LeftPanel.tsx
|
||||
│ │ │ ├── RightPanel.tsx
|
||||
│ │ │ └── DetailTabs/
|
||||
│ │ ├── Header/
|
||||
│ │ │ └── Header.tsx
|
||||
│ │ └── common/
|
||||
│ │ ├── Button.tsx
|
||||
│ │ ├── Badge.tsx
|
||||
│ │ └── Tabs.tsx
|
||||
│ ├── hooks/
|
||||
│ │ ├── useTopology.ts
|
||||
│ │ ├── useDiscovery.ts
|
||||
│ │ └── useSelection.ts
|
||||
│ ├── store/
|
||||
│ │ └── topologyStore.ts
|
||||
│ ├── types/
|
||||
│ │ └── index.ts
|
||||
│ ├── utils/
|
||||
│ │ ├── graphLayout.ts
|
||||
│ │ └── formatters.ts
|
||||
│ ├── data/
|
||||
│ │ └── staticConfig.ts
|
||||
│ ├── services/
|
||||
│ │ └── discovery.ts
|
||||
│ ├── App.tsx
|
||||
│ ├── main.tsx
|
||||
│ └── index.css
|
||||
├── public/
|
||||
├── docker/
|
||||
│ └── Dockerfile
|
||||
├── package.json
|
||||
├── tsconfig.json
|
||||
├── vite.config.ts
|
||||
├── tailwind.config.js
|
||||
└── README.md
|
||||
```
|
||||
|
||||
### Backend/API (Optional)
|
||||
|
||||
If running auto-discovery, need a small backend:
|
||||
- **Technology:** Node.js + Express
|
||||
- **Purpose:** Proxy SSH commands to homelab hosts
|
||||
- **Endpoints:**
|
||||
- `GET /api/discover/:host` - Run discovery on specific host
|
||||
- `GET /api/containers` - Get all containers across hosts
|
||||
- `GET /api/volumes` - Get all Docker volumes
|
||||
|
||||
---
|
||||
|
||||
## 5. Acceptance Criteria
|
||||
|
||||
### Visual Checkpoints
|
||||
|
||||
- [ ] Graph renders with nodes and edges
|
||||
- [ ] Nodes are color-coded by type
|
||||
- [ ] Clicking a node highlights it and shows details
|
||||
- [ ] Left panel shows child nodes of selected
|
||||
- [ ] Right panel shows 5 tabs with content
|
||||
- [ ] View mode selector changes graph content
|
||||
- [ ] Panels can be collapsed/expanded
|
||||
- [ ] Search filters nodes in real-time
|
||||
|
||||
### Functional Checkpoints
|
||||
|
||||
- [ ] Initial data loads from static config
|
||||
- [ ] Auto-discovery populates missing data
|
||||
- [ ] Graph is pannable and zoomable
|
||||
- [ ] Node selection is persistent across view changes
|
||||
- [ ] Config tab shows Docker compose content
|
||||
- [ ] Files tab shows relevant file paths
|
||||
- [ ] Refresh button updates data
|
||||
|
||||
### Performance Checkpoints
|
||||
|
||||
- [ ] Initial load < 2 seconds
|
||||
- [ ] Graph renders 100+ nodes smoothly
|
||||
- [ ] Interactions feel responsive (< 100ms)
|
||||
|
||||
### Deployment Checkpoints
|
||||
|
||||
- [ ] Builds successfully with `npm run build`
|
||||
- [ ] Docker image builds and runs
|
||||
- [ ] Accessible at localhost:3000
|
||||
- [ ] Works in browser via local network
|
||||
|
||||
---
|
||||
|
||||
## 6. Data Model
|
||||
|
||||
### Node Types
|
||||
|
||||
```typescript
|
||||
type NodeType =
|
||||
| 'gateway'
|
||||
| 'vlan'
|
||||
| 'wifi'
|
||||
| 'host_physical'
|
||||
| 'host_vm'
|
||||
| 'host_container'
|
||||
| 'service'
|
||||
| 'volume'
|
||||
| 'mount'
|
||||
| 'path';
|
||||
|
||||
interface TopologyNode {
|
||||
id: string;
|
||||
type: NodeType;
|
||||
name: string;
|
||||
data: {
|
||||
ip?: string;
|
||||
mac?: string;
|
||||
status: 'running' | 'stopped' | 'unknown';
|
||||
metadata: Record<string, any>;
|
||||
config?: string;
|
||||
files?: string[];
|
||||
importance: 1 | 2 | 3 | 4 | 5;
|
||||
};
|
||||
position?: { x: number; y: number };
|
||||
}
|
||||
|
||||
interface TopologyEdge {
|
||||
id: string;
|
||||
source: string;
|
||||
target: string;
|
||||
type?: string;
|
||||
label?: string;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Implementation Priority
|
||||
|
||||
### Phase 1 (MVP - Week 1)
|
||||
1. Set up React + React Flow project
|
||||
2. Create static config with hardcoded topology
|
||||
3. Render basic graph with nodes and edges
|
||||
4. Implement node selection
|
||||
5. Build right panel with Details tab
|
||||
6. Add view mode selector
|
||||
|
||||
### Phase 2 (Week 2)
|
||||
1. Complete right panel tabs (Config, Files, Usage, Importance)
|
||||
2. Build left panel with child nodes
|
||||
3. Add search and filters
|
||||
4. Implement basic auto-discovery (Docker)
|
||||
|
||||
### Phase 3 (Week 3)
|
||||
1. Add SSH-based discovery
|
||||
2. Implement real-time updates
|
||||
3. Add animations and polish
|
||||
4. Create Docker build
|
||||
|
||||
### Phase 4 (Ongoing)
|
||||
1. Add more node types
|
||||
2. Improve auto-discovery coverage
|
||||
3. Add mobile optimizations
|
||||
4. Add saved layouts
|
||||
Reference in New Issue
Block a user