Files
nntrivi2001 57dc91585d feat: Claude Code Monitor — lanes, pipelines and a merged workspace
Internal SmartGift build of a Claude Code monitoring dashboard.

Lanes: a durable unit of parallel agent work, one per working directory,
tracked across session restarts. Managed lanes are git worktrees the
dashboard provisions and can reset or remove behind a three-check destroy
guard and a counted preflight; adopted lanes are directories you already
own and are never destroyable.

Pipelines: a lane moves through pipeline stages. A stage the agent declares
with evidence renders green; a stage inferred from the tool-event stream
renders dashed amber and never counts as done. Detection is forward-only
within a 30-minute window, and never writes the declared stage.

Workspace: one page at /run with a lane grid, the selected lane's pipeline,
and a full Claude console behind a disclosure.
2026-07-30 14:39:03 +07:00

921 lines
19 KiB
Markdown

# Deployment Guide
Enterprise deployment strategies for Agent Dashboard across development, staging, and production environments.
---
## Table of Contents
- [Overview](#overview)
- [Deployment Architecture](#deployment-architecture)
- [Local Development](#local-development)
- [Production Deployment](#production-deployment)
- [Docker Deployment](#docker-deployment)
- [Cloud Deployment](#cloud-deployment)
- [Process Management](#process-management)
- [Monitoring & Logging](#monitoring--logging)
- [Backup & Recovery](#backup--recovery)
- [Security Hardening](#security-hardening)
- [Performance Tuning](#performance-tuning)
- [Troubleshooting](#troubleshooting)
---
## Overview
Agent Dashboard supports multiple deployment modes:
- **Local Development** - Hot reload for rapid iteration
- **Docker** - Containerized deployment with Docker/Podman
- **PM2** - Process management for production
- **Systemd** - System service on Linux
- **Cloud** - Deploy to AWS, Azure, GCP, or other cloud providers
```mermaid
graph TB
subgraph "Deployment Modes"
Dev[Local Development<br/>npm run dev]
Docker[Docker Container<br/>docker compose up]
PM2[PM2 Process Manager<br/>pm2 start]
Systemd[Systemd Service<br/>systemctl start]
Cloud[Cloud Platform<br/>Kubernetes, ECS, etc.]
end
subgraph "Environment"
DevEnv[Development<br/>Hot reload, verbose logs]
StagingEnv[Staging<br/>Production build, test data]
ProdEnv[Production<br/>Optimized, monitoring]
end
Dev --> DevEnv
Docker --> DevEnv
Docker --> StagingEnv
PM2 --> ProdEnv
Systemd --> ProdEnv
Cloud --> ProdEnv
style Dev fill:#3B82F6
style PM2 fill:#10B981
style Cloud fill:#F59E0B
```
---
## Deployment Architecture
### Single-Server Architecture
```mermaid
graph TB
subgraph "Server Host"
subgraph "Node.js Process"
Express[Express Server<br/>:4820]
Static[Static File Serving<br/>client/dist/]
API[REST API]
WS[WebSocket Server]
DB[(SQLite DB<br/>data/dashboard.db)]
end
end
subgraph "Clients"
Browser[Web Browsers]
MCP[MCP Clients]
end
subgraph "Claude Code"
Hooks[Hook Events]
end
Browser -->|HTTP/WS| Express
MCP -->|HTTP| API
Hooks -->|HTTP POST| Express
Express --> Static
Express --> API
Express --> WS
API --> DB
Express --> DB
style Express fill:#000000,color:#fff
style DB fill:#003B57,color:#fff
```
### High-Availability Architecture
```mermaid
graph TB
subgraph "Load Balancer"
LB[Nginx/HAProxy]
end
subgraph "Application Servers"
App1[Node.js Server 1<br/>:4820]
App2[Node.js Server 2<br/>:4820]
App3[Node.js Server 3<br/>:4820]
end
subgraph "Data Layer"
Redis[Redis<br/>WebSocket pub/sub]
DB[(PostgreSQL<br/>Shared database)]
end
LB --> App1
LB --> App2
LB --> App3
App1 --> Redis
App2 --> Redis
App3 --> Redis
App1 --> DB
App2 --> DB
App3 --> DB
style LB fill:#10B981
style Redis fill:#DC2626
style DB fill:#2563EB
```
---
## Local Development
### Prerequisites
- Node.js >= 20.0.0
- npm >= 9.0.0
### Setup
```bash
# Clone repository
git clone https://github.com/your-org/agent-dashboard.git
cd agent-dashboard
# Install dependencies
npm run setup
# Start development servers
npm run dev
```
### Development Architecture
```mermaid
sequenceDiagram
participant Dev as Developer
participant Server as Dev Server<br/>:4820 (watch mode)
participant Client as Vite Dev<br/>:5173 (HMR)
participant Browser
Dev->>Server: Edit server/*.js
Server->>Server: Auto-reload
Server-->>Dev: Ready
Dev->>Client: Edit client/src/*
Client->>Client: HMR rebuild
Client->>Browser: Hot update
Browser->>Browser: Re-render
Note over Browser: State preserved!
```
### Running Components Separately
```bash
# Terminal 1: Server only
npm run dev:server
# Terminal 2: Client only
npm run dev:client
# Terminal 3: MCP server (optional)
npm run mcp:dev
```
---
## Production Deployment
### Build Process
```mermaid
graph TB
Source[Source Code] --> Install[Install Dependencies<br/>npm ci --production]
Install --> BuildClient[Build Client<br/>npm run build]
BuildClient --> Bundle[Bundled Assets<br/>client/dist/]
Bundle --> Deploy[Deploy to Server]
Deploy --> Server[Start Server<br/>node server/index.js]
style BuildClient fill:#646CFF
style Server fill:#10B981
```
### Production Checklist
```bash
# 1. Install dependencies (production only)
npm ci --production
cd client && npm ci --production && cd ..
# 2. Build client
npm run build
# 3. Set environment variables
export NODE_ENV=production
export PORT=4820
export DASHBOARD_DB_PATH=/var/lib/agent-dashboard/dashboard.db
# 4. Create data directory
mkdir -p /var/lib/agent-dashboard
# 5. Start server
node server/index.js
```
### Environment Variables
```bash
# Server
DASHBOARD_PORT=4820 # Server port
NODE_ENV=production # Environment mode
# Network exposure (SECURITY — GHSA-gr74-4xfh-6jw9)
# The server binds 127.0.0.1 by default and is NOT network-reachable. It reads
# transcripts, exports all data, and can spawn `claude`, so only widen the bind
# deliberately — and require a token when you do.
DASHBOARD_HOST=127.0.0.1 # set 0.0.0.0 ONLY if you must expose it
DASHBOARD_TOKEN= # required on /api/* + WS when set; use with a non-loopback host
DASHBOARD_ALLOWED_HOSTS= # extra Host names (comma-sep) for a LAN bind
# Database
DASHBOARD_DB_PATH=/var/lib/agent-dashboard/dashboard.db
# Logging
LOG_LEVEL=info # debug | info | warn | error
```
> **Reverse-proxy / Docker exposure:** the app binds loopback, so publish it to a
> network only through a proxy you control that adds TLS + auth, or set
> `DASHBOARD_HOST=0.0.0.0` **with** `DASHBOARD_TOKEN`. A `-p 4820:4820` Docker
> mapping assumes a trusted host network — do not expose it publicly without a
> token and a proxy.
---
## Docker Deployment
### Docker Compose (Recommended)
```yaml
# docker-compose.yml
version: '3.8'
services:
agent-dashboard:
build: .
ports:
- "4820:4820"
volumes:
- ./data:/app/data
environment:
- NODE_ENV=production
- PORT=4820
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:4820/api/sessions"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
```
### Build & Run
```bash
# Build image
docker compose build
# Start container
docker compose up -d
# View logs
docker compose logs -f
# Stop container
docker compose down
```
### Multi-Stage Dockerfile
```dockerfile
# Build stage
FROM node:22-alpine AS builder
WORKDIR /app
# Install dependencies
COPY package*.json ./
COPY client/package*.json ./client/
RUN npm ci && cd client && npm ci
# Build client
COPY client ./client
RUN cd client && npm run build
# Production stage
FROM node:22-alpine
WORKDIR /app
# Copy built artifacts
COPY --from=builder /app/client/dist ./client/dist
COPY --from=builder /app/node_modules ./node_modules
COPY server ./server
COPY package.json ./
# Create data directory
RUN mkdir -p /app/data
EXPOSE 4820
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
CMD node -e "require('http').get('http://localhost:4820/api/sessions', (res) => process.exit(res.statusCode === 200 ? 0 : 1))"
CMD ["node", "server/index.js"]
```
### Container Architecture
```mermaid
graph TB
subgraph "Docker Host"
subgraph "Container"
App[Node.js App<br/>:4820]
Volume[Volume Mount<br/>/app/data]
end
end
Host[Host Filesystem<br/>./data] -->|Bind Mount| Volume
App --> Volume
Client[External Clients] -->|Port 4820| App
style App fill:#2496ED,color:#fff
style Volume fill:#FFA500
```
---
## Cloud Deployment
### AWS (Elastic Beanstalk)
```bash
# Install EB CLI
pip install awsebcli
# Initialize
eb init -p node.js agent-dashboard
# Create environment
eb create production
# Deploy
eb deploy
# Open in browser
eb open
```
### Kubernetes
```yaml
# k8s/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: agent-dashboard
spec:
replicas: 3
selector:
matchLabels:
app: agent-dashboard
template:
metadata:
labels:
app: agent-dashboard
spec:
containers:
- name: agent-dashboard
image: agent-dashboard:latest
ports:
- containerPort: 4820
env:
- name: NODE_ENV
value: "production"
volumeMounts:
- name: data
mountPath: /app/data
volumes:
- name: data
persistentVolumeClaim:
claimName: agent-dashboard-pvc
---
apiVersion: v1
kind: Service
metadata:
name: agent-dashboard
spec:
selector:
app: agent-dashboard
ports:
- protocol: TCP
port: 80
targetPort: 4820
type: LoadBalancer
```
### Kubernetes Architecture
```mermaid
graph TB
subgraph "Kubernetes Cluster"
subgraph "LoadBalancer Service"
LB[Load Balancer<br/>:80]
end
subgraph "Pods"
Pod1[agent-dashboard-1<br/>:4820]
Pod2[agent-dashboard-2<br/>:4820]
Pod3[agent-dashboard-3<br/>:4820]
end
subgraph "Storage"
PVC[PersistentVolumeClaim]
PV[PersistentVolume]
end
end
LB --> Pod1
LB --> Pod2
LB --> Pod3
Pod1 --> PVC
Pod2 --> PVC
Pod3 --> PVC
PVC --> PV
style LB fill:#10B981
style PV fill:#F59E0B
```
---
## Process Management
### PM2 (Production Process Manager)
```bash
# Install PM2
npm install -g pm2
# Start application
pm2 start server/index.js --name agent-dashboard
# Start with environment
pm2 start server/index.js --name agent-dashboard --env production
# View logs
pm2 logs agent-dashboard
# Monitor
pm2 monit
# Restart
pm2 restart agent-dashboard
# Stop
pm2 stop agent-dashboard
# Auto-start on system boot
pm2 startup
pm2 save
```
### PM2 Ecosystem File
```javascript
// ecosystem.config.js
module.exports = {
apps: [{
name: 'agent-dashboard',
script: './server/index.js',
instances: 2,
exec_mode: 'cluster',
env: {
NODE_ENV: 'development',
PORT: 4820
},
env_production: {
NODE_ENV: 'production',
PORT: 4820,
DASHBOARD_DB_PATH: '/var/lib/agent-dashboard/dashboard.db'
},
max_memory_restart: '500M',
error_file: '/var/log/agent-dashboard/error.log',
out_file: '/var/log/agent-dashboard/out.log',
time: true
}]
};
```
```bash
# Start with ecosystem file
pm2 start ecosystem.config.js --env production
```
### Systemd Service (Linux)
```ini
# /etc/systemd/system/agent-dashboard.service
[Unit]
Description=Agent Dashboard
After=network.target
[Service]
Type=simple
User=agent-dashboard
WorkingDirectory=/opt/agent-dashboard
Environment=NODE_ENV=production
Environment=PORT=4820
Environment=DASHBOARD_DB_PATH=/var/lib/agent-dashboard/dashboard.db
ExecStart=/usr/bin/node server/index.js
Restart=on-failure
RestartSec=10
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
```
```bash
# Enable and start service
sudo systemctl enable agent-dashboard
sudo systemctl start agent-dashboard
# Check status
sudo systemctl status agent-dashboard
# View logs
sudo journalctl -u agent-dashboard -f
```
---
## Monitoring & Logging
### Health Checks
```bash
# Server health check
curl http://localhost:4820/api/sessions
# Expected: {"sessions": [...]}
```
### Logging Strategy
```mermaid
graph TB
subgraph "Application Logs"
App[Express Server] --> Console[Console Output]
Console --> Stdout[stdout/stderr]
end
subgraph "Log Aggregation"
Stdout --> PM2[PM2 Logs]
Stdout --> Systemd[Systemd Journal]
Stdout --> Docker[Docker Logs]
end
subgraph "Monitoring Tools"
PM2 --> File[Log Files]
Systemd --> Journalctl[journalctl]
Docker --> DockerLogs[docker logs]
end
subgraph "Analysis"
File --> Splunk[Splunk/ELK]
Journalctl --> Splunk
DockerLogs --> Splunk
end
style App fill:#000000,color:#fff
style Splunk fill:#10B981
```
### Monitoring Metrics
```javascript
// Add to server/index.js for metrics endpoint
app.get('/metrics', (req, res) => {
const metrics = {
uptime: process.uptime(),
memory: process.memoryUsage(),
cpu: process.cpuUsage(),
sessions: db.prepare('SELECT COUNT(*) as count FROM sessions').get(),
agents: db.prepare('SELECT COUNT(*) as count FROM agents').get(),
websocket_clients: wss.clients.size
};
res.json(metrics);
});
```
---
## Backup & Recovery
### Backup Strategy
```mermaid
graph TB
subgraph "Backup Process"
DB[(SQLite DB)] --> Backup[Backup Script]
Backup --> Local[Local Storage<br/>./backups/]
Backup --> S3[AWS S3]
Backup --> Cloud[Cloud Storage]
end
subgraph "Schedule"
Cron[Cron Job<br/>Daily at 2 AM]
end
subgraph "Retention"
Daily[Daily: 7 days]
Weekly[Weekly: 4 weeks]
Monthly[Monthly: 12 months]
end
Cron --> Backup
Local --> Daily
S3 --> Weekly
Cloud --> Monthly
style DB fill:#003B57,color:#fff
style S3 fill:#FF9900
```
### Backup Script
```bash
#!/bin/bash
# scripts/backup.sh
BACKUP_DIR="/var/backups/agent-dashboard"
DB_PATH="/var/lib/agent-dashboard/dashboard.db"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="$BACKUP_DIR/dashboard_$TIMESTAMP.db"
# Create backup directory
mkdir -p "$BACKUP_DIR"
# Create backup (online backup with VACUUM INTO)
sqlite3 "$DB_PATH" "VACUUM INTO '$BACKUP_FILE'"
# Compress backup
gzip "$BACKUP_FILE"
# Upload to S3 (optional)
aws s3 cp "$BACKUP_FILE.gz" s3://my-backups/agent-dashboard/
# Delete old backups (keep last 7 days)
find "$BACKUP_DIR" -name "dashboard_*.db.gz" -mtime +7 -delete
echo "Backup completed: $BACKUP_FILE.gz"
```
### Restore Process
```bash
#!/bin/bash
# scripts/restore.sh
BACKUP_FILE=$1
DB_PATH="/var/lib/agent-dashboard/dashboard.db"
if [ -z "$BACKUP_FILE" ]; then
echo "Usage: ./restore.sh <backup_file.db.gz>"
exit 1
fi
# Stop application
systemctl stop agent-dashboard
# Decompress backup
gunzip -c "$BACKUP_FILE" > /tmp/restore.db
# Restore database
cp /tmp/restore.db "$DB_PATH"
chown agent-dashboard:agent-dashboard "$DB_PATH"
# Start application
systemctl start agent-dashboard
echo "Restore completed from $BACKUP_FILE"
```
---
## Security Hardening
### Security Checklist
```mermaid
graph TB
subgraph "Network Security"
Firewall[Firewall Rules<br/>Allow :4820 only from trusted IPs]
TLS[TLS/SSL<br/>HTTPS + WSS]
CORS[CORS Configuration<br/>Restrict origins]
end
subgraph "Application Security"
Validation[Input Validation]
Prepared[Prepared Statements<br/>SQL injection prevention]
Sanitize[Output Sanitization]
end
subgraph "System Security"
User[Dedicated User<br/>Non-root]
Perms[File Permissions<br/>640 for DB]
SELinux[SELinux/AppArmor]
end
style Firewall fill:#10B981
style Prepared fill:#10B981
style User fill:#10B981
```
### TLS Configuration (Nginx Reverse Proxy)
```nginx
# /etc/nginx/sites-available/agent-dashboard
server {
listen 443 ssl http2;
server_name dashboard.example.com;
ssl_certificate /etc/letsencrypt/live/dashboard.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/dashboard.example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
location / {
proxy_pass http://localhost:4820;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /ws {
proxy_pass http://localhost:4820/ws;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
# Redirect HTTP to HTTPS
server {
listen 80;
server_name dashboard.example.com;
return 301 https://$server_name$request_uri;
}
```
---
## Performance Tuning
### Node.js Optimization
```bash
# Increase memory limit
NODE_OPTIONS="--max-old-space-size=4096" node server/index.js
# Enable V8 optimizations
node --optimize-for-size server/index.js
```
### SQLite Tuning
```javascript
// server/db.js - Add these pragmas
db.pragma('journal_mode = WAL'); // Write-Ahead Logging
db.pragma('synchronous = NORMAL'); // Faster writes
db.pragma('cache_size = -64000'); // 64MB cache
db.pragma('temp_store = MEMORY'); // Temp tables in memory
db.pragma('mmap_size = 30000000000'); // Memory-mapped I/O
db.pragma('page_size = 4096'); // Optimal page size
```
### Nginx Tuning
```nginx
# /etc/nginx/nginx.conf
worker_processes auto;
worker_connections 4096;
http {
# Enable compression
gzip on;
gzip_comp_level 6;
gzip_types text/plain text/css application/json application/javascript;
# Client body buffer
client_body_buffer_size 128k;
# Keepalive
keepalive_timeout 65;
keepalive_requests 100;
# Proxy buffering
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 4k;
}
```
---
## Troubleshooting
### Common Issues
```mermaid
graph TB
subgraph "Issue Categories"
Startup[Startup Failures]
Connection[Connection Errors]
Performance[Performance Issues]
Data[Data Inconsistencies]
end
subgraph "Diagnostics"
Logs[Check Logs]
Health[Health Checks]
Metrics[Monitor Metrics]
DB[Database Integrity]
end
Startup --> Logs
Connection --> Health
Performance --> Metrics
Data --> DB
style Logs fill:#F59E0B
```
### Issue Resolution Guide
| Issue | Symptoms | Solution |
|-------|----------|----------|
| Port already in use | `EADDRINUSE: address already in use :::4820` | `lsof -i :4820` then kill process |
| Database locked | `database is locked` | Check for long-running queries, increase timeout |
| WebSocket connection fails | Clients can't connect | Check firewall, verify WebSocket upgrade headers |
| High memory usage | >500MB RAM | Enable memory limits, check for leaks |
| Slow queries | API responses >100ms | Add indexes, use EXPLAIN QUERY PLAN |
### Debug Mode
```bash
# Enable verbose logging
DEBUG=* node server/index.js
# SQLite query logging
NODE_ENV=development node server/index.js
```
---
## Summary
This deployment guide covers:
-**Multiple deployment modes** - Local, Docker, PM2, Systemd, Cloud
-**Production best practices** - Environment variables, health checks, logging
-**Process management** - PM2, systemd service files
-**Monitoring & logging** - Metrics endpoint, log aggregation
-**Backup & recovery** - Automated backups, restore procedures
-**Security hardening** - TLS, CORS, firewall rules
-**Performance tuning** - Node.js, SQLite, Nginx optimizations
-**Troubleshooting** - Common issues and resolutions
For architecture details, see [ARCHITECTURE.md](../ARCHITECTURE.md).