488 lines
15 KiB
Markdown
488 lines
15 KiB
Markdown
# 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
|