# Deployment Dashboard Implementation **Date:** 2026-02-06 19:30 **Project:** nuc-portal **Context:** Implemented Vercel-style deployment detail pages with parallel wave-based execution --- ## Overview Added a comprehensive deployment dashboard to nuc-portal that displays detailed information about individual deployments, including real-time container health, stats, build logs, and quick action buttons. ## Architecture ``` User Flow: Deployments Tab → Click Row → /deployments/[uuid] (Dashboard) → Click Chevron → Expand Logs Inline (preserved) API Flow: Dashboard Page ├── /api/deployments/[uuid] → Deployment details ├── /api/deployments/[uuid]/health → Container health (SWR 10s) ├── /api/deployments/[uuid]/stats → Container stats (SWR 10s) └── /api/deployments/[uuid]/redeploy → Trigger new deployment ``` ## Files Created | File | Purpose | Lines | |------|---------|-------| | `src/app/deployments/[uuid]/page.tsx` | Dynamic route for deployment details | ~150 | | `src/components/DeploymentDashboard.tsx` | Main dashboard component with tabs | ~800 | | `src/components/DeploymentSkeleton.tsx` | Loading, error, empty state components | ~200 | | `src/lib/docker.ts` | Docker API helpers via SSH | ~150 | | `src/app/api/deployments/[uuid]/health/route.ts` | Container health endpoint | ~50 | | `src/app/api/deployments/[uuid]/stats/route.ts` | Container stats endpoint | ~60 | | `src/app/api/deployments/[uuid]/redeploy/route.ts` | Redeploy trigger endpoint | ~50 | ## Files Modified | File | Changes | |------|---------| | `src/components/DeploymentsTable.tsx` | Added expand button, row click navigation | | `src/components/Icons.tsx` | Added missing icons (user, clock, share, etc.) | | `src/components/index.ts` | Exported new components | ## Features ### Dashboard Tabs 1. **Deployment** - Main view with metadata, preview, and collapsible sections 2. **Logs** - Build logs with warning highlighting 3. **Resources** - CPU, Memory, Network I/O, Block I/O 4. **Source** - Git branch, commit, message ### Real-Time Data (SWR) - Health status polling every 10 seconds - Container stats polling every 10 seconds - Auto-refresh with loading states ### Action Cards | Card | Action | URL | |------|--------|-----| | Runtime Logs | Opens Dozzle | `http://192.168.1.3:9999/container/{name}` | | Coolify | Opens Coolify deployment | `http://coolify.nuc.lan:8000/...` | | Visit Site | Opens app FQDN | `{deployment.fqdn}` | | Redeploy | Triggers new deployment | POST `/api/.../redeploy` | ### Edge Cases Handled - `in_progress` - Shows "Building..." with amber banner - `error` - Shows error banner, auto-expands logs - `cancelled` - Shows grey cancelled state - Missing container - Graceful degradation with messages - Missing git info - Shows "—" instead of crashing - Null duration - Shows "In progress..." ### Loading & Error States - `DeploymentSkeleton` - Animated loading skeleton - `DeploymentError` - Error with retry button - `DeploymentEmpty` - Empty state for edge cases ## Docker API Helpers `src/lib/docker.ts` provides: ```typescript // Execute command via SSH to NUC sshExec(command: string): Promise // Get container health status getContainerHealth(containerName: string): Promise<'healthy' | 'unhealthy' | 'starting' | 'none' | null> // Get container resource stats getContainerStats(containerName: string): Promise<{ cpuPercent: number; memoryUsage: string; memoryLimit: string; memoryPercent: number; netIO: { rx: string; tx: string }; blockIO: { read: string; write: string }; } | null> // Get container uptime getContainerUptime(containerName: string): Promise<{ startedAt: string; seconds: number; formatted: string; } | null> // Find container by app name or UUID findContainerByAppName(appName: string): Promise findContainerByUuid(appUuid: string): Promise ``` ## Implementation Method Used parallel wave-based execution with 11 total agents: | Wave | Tasks | Agents | Duration | |------|-------|--------|----------| | Wave 1 | Route, Docker helpers, Table UI | 3 parallel | ~3.5 min | | Wave 2 | Dashboard, Health API, Stats API, Navigation | 4 parallel | ~4.5 min | | Wave 3 | Data integration, Links, Redeploy | 3 parallel | ~5 min | | Wave 4 | Loading states, Edge cases | 2 parallel | ~3 min | **Total implementation time:** ~16 minutes ## Testing ```bash # Start dev server cd /Users/agutierrez/Desktop/nuc/nuc-portal npm run dev # Get a deployment UUID curl http://localhost:3000/api/deployments | jq '.[0].deployment_uuid' # Test dashboard page open http://localhost:3000/deployments/ # Test API endpoints curl http://localhost:3000/api/deployments//health | jq curl http://localhost:3000/api/deployments//stats | jq curl -X POST http://localhost:3000/api/deployments//redeploy | jq ``` ## Dependencies Added ```json { "swr": "^2.x" // For data fetching with auto-refresh } ``` ## URLs Configuration Per user request, Coolify URLs use domain name: - ✅ `http://coolify.nuc.lan:8000` (not IP) - Dozzle still uses IP (no domain configured): `http://192.168.1.3:9999` ## Screenshots Dashboard follows Vercel's deployment page design: - Header with app icon, metadata grid - Collapsible sections (Settings, Build Logs, Container Stats, Summary) - Action cards grid at bottom - Tab navigation (Deployment, Logs, Resources, Source) ## Related - Design doc: `.artifacts/2026-02-06_17-30_deployment-dashboard-design.md` - Implementation plan: `.artifacts/2026-02-06_18-00_deployment-dashboard-implementation-plan.md` - nuc-portal repo: `/Users/agutierrez/Desktop/nuc/nuc-portal/`