* feat(dashboard): redesign as DevOps command center Transform the dashboard from a basic stats viewer into a high-signal operational command center with 5 composable sections: - Health status bar with system health derivation (Healthy/Degraded/Critical) - Resource gauges with visual progress bars and threshold coloring - Paginated stack health table with per-stack UP/DN, CPU, memory, and click-to-navigate (8 per page) - Enhanced historical CPU/RAM charts with skeleton empty states - Recent alerts feed with severity-coded notifications Extract monolithic HomeDashboard.tsx (447 lines) into composable sub-components under dashboard/ directory. Remove Docker Run to Compose converter from the landing surface. Add defensive .ok check on container status fallback in EditorLayout. * feat(dashboard): add Clear All Notifications button to Recent Alerts Add a destructive ghost button below the alerts feed that calls DELETE /api/notifications to clear all notifications, then refreshes the list. Button only appears when there are alerts to clear. * feat(dashboard): add pagination to Recent Alerts section Same pattern as Stack Health table: 8 items per page with prev/next chevron controls and page indicator in the card header. Pagination auto-hides when there are 8 or fewer alerts. Page resets on clear all. * fix(dashboard): resolve container count oscillation and add cursor hover detail Fix container stats flickering between 0 and correct values by moving state resets to the top of each useEffect body (runs once per node switch, not on every poll tick). Add animate-ui cursor primitive and wire it to the active containers number in ResourceGauges to show managed/external breakdown on hover. Silence noisy Docker socket errors when engine is unreachable. * feat(dashboard): add cursor hover to health status with reason breakdown Wrap the health badge (pulsing dot + label) in a CursorFollow tooltip that explains why the node is Critical, Degraded, or Healthy. Shows specific metrics (e.g. "RAM at 97.9%", "Disk at 96.4%") when hovered. Displays "All systems nominal" for healthy nodes. * fix(dashboard): resolve OOM from unbounded Docker stats polling Three root causes addressed: 1. updateGlobalDockerNetwork had no overlap guard. When Docker was slow, 3-second interval ticks stacked up, creating dozens of concurrent container.stats() calls that exhausted the heap. Added isUpdatingNetwork flag and increased interval from 3s to 5s. 2. Historical metrics query returned ~20K rows (1-minute buckets x 14 containers x 24h). Downsampled to 5-minute buckets, reducing response size by ~5x. 3. Dashboard polling continued when the browser tab was hidden, creating phantom load. Replaced setInterval with visibilityInterval helper that pauses polling on tab hide and resumes with an immediate fetch on focus. * fix(dashboard): use loadFile for stack navigation from Stack Health table The onNavigateToStack callback was only calling setSelectedFile and setActiveView, skipping the full load flow (YAML content, env files, containers, backup info). This caused the editor to show stale state with a "Start" button for running stacks and empty YAML. Now calls loadFile() which is the same path the sidebar uses. * refactor(dashboard): simplify Containers card layout Replace 2-column grid with vertical layout matching other gauge cards. Active count uses text-2xl hero number, exited count sits in subtitle position. Removed redundant total count row. * fix(dashboard): unify notification types and fix multi-node clear - Replace duplicate Notification interface in EditorLayout with shared NotificationItem from dashboard/types.ts - Tighten is_read type from number | boolean to number (matches SQLite) - Pass notifications from EditorLayout (which aggregates all nodes) to HomeDashboard as props, removing duplicate local-only polling from useDashboardData - Fix Clear All to use clearAllNotifications (deletes from all nodes) instead of fetchNotifications (which was just a re-fetch, causing remote notifications to reappear immediately after clearing) - Delegate DELETE responsibility from RecentAlerts to parent handler * fix(dashboard): handle optional nodeId in notification operations Guard against undefined nodeId when calling fetchForNode for mark-read, delete, and clear-all notification operations. The shared NotificationItem type has nodeId as optional since the API response doesn't include it; EditorLayout enriches it but TypeScript correctly flags the possibility.
Sencho
A self-hosted Docker Compose management dashboard. Manage your stacks, containers, images, volumes, and networks through a modern web UI.
Features
- Stack Management - Create, edit, start, stop, and remove Docker Compose stacks with a built-in Monaco code editor
- Multi-Node Support - Manage remote Sencho instances through a transparent HTTP/WebSocket proxy (Distributed API model)
- App Store - One-click deployment from LinuxServer.io templates with editable ports, volumes, and environment variables
- Resource Hub - Browse and manage images, volumes, and networks with managed/external/unused classification
- Live Logs - Aggregated real-time log streaming across all containers with search and filtering
- Dashboard - Container stats, CPU/RAM metrics, health checks, and image update notifications
- Alerts - Configurable threshold alerts for CPU, RAM, and disk usage
- Terminal - In-browser host console and container exec via WebSocket
Quick Start
services:
sencho:
image: saelix/sencho:latest
container_name: sencho
restart: unless-stopped
ports:
- "3000:3000"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./data:/app/data
# 1:1 Compose Path Rule: host path MUST match container path
- /opt/docker:/opt/docker
environment:
- COMPOSE_DIR=/opt/docker
- DATA_DIR=/app/data
docker compose up -d
Then open http://your-server:3000 and create your admin account.
See the full documentation for configuration details, multi-node setup, and more.
Development
# Backend (Express + TypeScript)
cd backend && npm install && npm run dev
# Frontend (React + Vite)
cd frontend && npm install && npm run dev
The frontend dev server proxies /api requests to the backend on port 3000.
Contributing
See CONTRIBUTING.md for development setup and PR guidelines.
Security
See SECURITY.md for vulnerability reporting. Do not open public issues for security vulnerabilities.
License
Sencho is licensed under the Business Source License 1.1. You may use, modify, and redistribute the code freely, including for production use. The only restriction is offering Sencho as a competing hosted or managed service. On 2030-03-25, the license automatically converts to Apache 2.0.
