Mangrullo Web UI Design Document
Overview
This document outlines the design and implementation plan for Mangrullo's web interface. The web UI provides a modern, responsive dashboard for monitoring and managing Docker container updates through a browser interface.
Goals
- Visual Monitoring: Provide a dashboard view of all running containers and their update status
- Interactive Management: Allow users to check for updates, update containers, and view logs
- Real-time Updates: Show live status updates and notifications
- Bulk Operations: Enable updating multiple containers at once
- Mobile Responsive: Work well on both desktop and mobile devices
Current Status
The web interface is fully implemented with comprehensive functionality:
✅ Completed Features
- Basic Web Server: Kemal-based HTTP server running on port 3000 (configurable via
MANGRULLO_WEB_PORT/MANGRULLO_WEB_HOST) - Dashboard Page: Overview of all running containers and their update status
- Container List: Display of containers with update status indicators
- Update Checking: Web-based update detection functionality
- Container Updates: Web-triggered container recreation and updates
- HTML Templates: ECR template with a token-driven "Mission Control" theme
- Error Handling: Graceful error handling and user-friendly messages
- Real-time Updates: Auto-refresh (every 30 seconds) plus live Server-Sent Events
- Bulk Operations: Multi-container updates queued through the job queue, with dry run support
- Embedded Static Assets: All CSS, JavaScript, and images baked into binary
- Theme Toggle: Dark (default) and light modes, persisted in
localStorage - State Management: Shared state between web requests and background operations
- Custom Branding: Cell tower icons and favicons throughout interface
- Typography: Chivo, Chivo Mono and Space Grotesk Google Fonts
- Dry Run Modal: Comprehensive results display with CLI-like output
- Modal Improvements: Proper close button positioning and responsive design
- Bulk Update Modal: Dry run checkbox and major version upgrade controls
- Button State Management: Proper onclick attribute handling during operations
- Notification System: Token-colored toast notifications for user feedback
- Container Restart: Direct container restart via the API
- Optional HTTP Basic Auth: Enabled via
MANGRULLO_WEB_USER/MANGRULLO_WEB_PASSWORD
🚧 In Progress
- Log Viewing: Container log viewing
📋 Planned Features
- Metrics: Performance and usage metrics
- Scheduling: Web-based update scheduling
- Notifications: Email/webhook notifications
- API Documentation: Swagger/OpenAPI documentation
Technology Stack
Backend
- Kemal: Fast, lightweight web framework for Crystal
- ECR: Crystal's built-in template engine for HTML rendering
- Crystal: High-performance programming language
- Baked File System: Embedded static assets for easy deployment
- Server-Sent Events: Live update progress pushed to connected dashboards
- Job Queue: Bulk updates are enqueued and polled instead of blocking requests
- State Manager: Shared state management for web operations
- Existing Mangrullo modules: Docker client, image checker, update manager
Frontend
- Pico.css v2 (self-hosted): reskinned through
--pico-*custom properties - Token-driven theme:
data-theme="dark|light"selects a CSS custom property set (Mission Control palette: dark navy panels, teal accent) - Vanilla JavaScript: served as a baked
/js/dashboard.jsasset; only the pre-paint theme bootstrap stays inline - HTML5: Modern, semantic markup
- Auto-refresh: Periodic status updates (every 30 seconds)
- Server-Sent Events:
EventSourceconnection to/api/events
Architecture
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Browser │ │ Kemal Server │ │ Docker API │
│ │ │ │ │ │
│ ┌─────────────┐ │ │ ┌─────────────┐ │ │ ┌─────────────┐ │
│ │ Pico.css │ │◄──►│ │ Web Server │ │◄──►│ │ Containers │ │
│ │ Templates │ │ │ │ Routes │ │ │ │ Images │ │
│ │ JavaScript │ │ │ │ API │ │ │ │ Networks │ │
│ └─────────────┘ │ │ └─────────────┘ │ │ └─────────────┘ │
└─────────────────┘ └─────────────────┘ └─────────────────┘
Features
1. Dashboard (Main Page)
URL: /
Purpose: Overview of all running containers and their update status
Components:
- Header with app title and navigation
- Summary statistics (total containers, updates available)
- Container list with:
- Container name and ID
- Current image tag
- Update status indicator
- Last checked timestamp
- Quick actions (Check Update, Update)
- Action bar for bulk operations
- Real-time status indicators
Status Indicators:
- 🟢 Up to date
- 🟡 Update available
- 🔴 Unknown/error
- ⚪ Latest tag (always check)
2. Container Details Page
Status: Not implemented (planned). The dashboard is a single page;
per-container actions (check, update) live in the container table, and
restart is available through the API (POST /containers/:id/restart).
3. API Endpoints
Pages
GET /- DashboardGET /health- Health check (kept open when Basic auth is enabled)
Container Management
POST /containers/:id/check-update- Force an update check for one containerPOST /containers/:id/update- Queue an update job for one containerPOST /containers/:id/restart- Restart container
Bulk Operations
GET /api/updates- Update info for all containersPOST /api/updates- Dry runs execute synchronously; real updates enqueue one job per container and answer202with{queued, count, job_ids}
Job Status
GET /api/jobs/:job_id- Job status (retained ~10 minutes after finishing)GET /api/containers/:container_id/jobs- Jobs for one container
System
GET /api/status- State manager status (includesupdate_in_progress)GET /api/containers- All containers with update infoPOST /api/refresh- Force a refresh of all containers (409 if in progress)GET /api/events- SSE stream of live update events
All routes are protected by HTTP Basic auth when MANGRULLO_WEB_USER and
MANGRULLO_WEB_PASSWORD are set (/health excepted).
4. Real-time Features (Implemented)
Server-Sent Events
The dashboard opens an EventSource on /api/events. The endpoint registers
the client, streams keep-alive comments, and the update flow broadcasts
events: image_pull_start, image_pull_complete, container_stop,
container_remove, container_create, container_start, update_complete,
update_error, status_update.
Auto-refresh
- Periodic status checks every 30 seconds (paused while the tab is hidden)
- SSE events trigger targeted UI updates and refreshes
User Interface Design
Color Scheme
Token-driven, selected by <html data-theme="dark|light"> (Mission Control
palette, grafito-style):
| Token | Dark | Light |
|---|---|---|
--bg |
#101418 |
#f2f5f4 |
--panel |
#161b22 |
#ffffff |
--line |
#29313c |
#d3dcda |
--txt |
#dfe6ee |
#1d2530 |
--accent |
#4cc2a9 (teal) |
#178f77 |
--ok |
#7ec9a1 |
#3e7d5c |
--warn |
#e9a23b |
#b07414 |
--err |
#f0635a |
#c73e34 |
--info |
#58a6ff |
#2b6cb0 |
Pico.css v2 is reskinned through its --pico-* custom properties, and
container status is conveyed with severity-colored left borders on table rows.
Layout Structure
The dashboard is a single ECR template (src/templates/dashboard.ecr) with a
sticky topbar (brand, auto-refresh indicator, theme toggle, Check/Update
actions), two stat cards, a sortable container table, dialogs for update and
dry-run confirmations, and a footer. JavaScript lives in
public/js/dashboard.js (baked into the binary); only a small pre-paint
theme bootstrap remains inline in <head>.
Component Templates
Container Table Row
<tr class="status-update-available" data-container-id="abc123">
<td title="my-app">my-app</td>
<td title="nginx:1.2.3"><code>nginx:1.2.3</code></td>
<td>
<div class="actions-cell">
<button onclick="showUpdateModal('abc123')" class="primary btn-sm">Update</button>
</div>
</td>
</tr>
Row status (status-up-to-date, status-update-available, status-latest,
status-error) drives a severity-colored left border on the first cell.
Update Modal
<dialog id="updateModal">
<article>
<header>
<h3>Update Container</h3>
<button aria-label="Close" class="close" onclick="closeModal()"></button>
</header>
<p>Are you sure you want to update this container?</p>
<label>
<input type="checkbox" id="allowMajor" name="allow_major" />
Allow major version upgrades
</label>
<footer>
<button onclick="confirmUpdate()" class="primary">Update Container</button>
<button onclick="closeModal()" aria-label="Close" class="secondary">Cancel</button>
</footer>
</article>
</dialog>
Implementation Plan
Phase 1: Basic Web Interface ✓
- [x] Add Kemal dependency
- [x] Create basic web server structure
- [x] Implement HTML templates with Pico.css
- [x] Create dashboard page
- [x] Add container list view
Phase 2: Core Functionality ✓
- [x] Implement container details page
- [x] Add update checking functionality
- [x] Implement container updates
- [x] Add error handling and validation
Phase 3: Advanced Features ✅
- [x] Add bulk operations (queued through the job queue)
- [x] Implement real-time updates (auto-refresh every 30 seconds + SSE)
- [x] Add container restart functionality
- [ ] Add log viewing
Phase 4: Polish and Documentation ✅
- [x] Responsive design improvements
- [x] Loading states and spinners
- [x] Better error messages
- [x] Update documentation
- [x] Custom branding with cell tower icons
- [x] Typography improvements with Chivo fonts
- [x] Comprehensive dry run modal
- [x] Favicon integration
Security Considerations
- Authentication: Implemented as optional HTTP Basic auth (
MANGRULLO_WEB_USER/MANGRULLO_WEB_PASSWORD), constant-time credential comparison,/healthexempt - Authorization: Container operations require appropriate permissions
- Input Validation: All user input should be validated
- CSRF Protection: Use tokens for state-changing operations
- Rate Limiting: Prevent abuse of API endpoints
Performance Considerations
- Caching: Cache Docker API responses where appropriate
- Pagination: For large numbers of containers
- Lazy Loading: Load container details on demand
- Connection Pooling: Reuse Docker client connections
Testing Strategy
- Unit Tests: Test individual components and utilities
- Integration Tests: Test API endpoints and Docker integration
- End-to-End Tests: Test complete user workflows
- Browser Testing: Test across different browsers and devices
File Structure
src/
├── web.cr # Web server entry point (Kemal.run)
├── web_server.cr # Routes, auth middleware, SSE endpoint, error handlers
├── web_views.cr # Dashboard rendering (ECR)
├── templates/
│ └── dashboard.ecr # Dashboard template
├── static_assets.cr # Bakes public/ into the binary
├── sse.cr # Server-Sent Events registry and broadcast
├── web_auth.cr # Optional HTTP Basic authentication
├── update_job_queue.cr # Background update jobs with status retention
├── state_manager.cr # Shared state management
├── container_state.cr # Container state data structures
└── public/ # Source static assets (baked into binary)
├── css/
│ ├── pico.min.css # Pico v2, self-hosted
│ └── dashboard.css # Token-driven theme
├── js/
│ └── dashboard.js # Dashboard behavior
├── favicon.svg
└── favicon.ico
Note: Static assets are now baked directly into the binary using the baked_file_system and baked_file_handler libraries, eliminating the need for separate static file deployment.
Success Metrics
- Functionality: All core container operations work via web interface
- Performance: Page loads in < 2 seconds with 50 containers
- Usability: Intuitive interface requiring no documentation
- Reliability: Graceful error handling and recovery
- Mobile: Responsive design works on mobile devices
Future Enhancements
- Scheduled Updates: Web-based scheduling configuration
- Notifications: Email/webhook notifications
- Container Metrics: Resource usage graphs
- Image History: View image update history
- Export/Import: Configuration backup and restore
- Log Viewing: Container log viewer
- API Documentation: Swagger/OpenAPI documentation
Conclusion
The web UI will make Mangrullo more accessible and user-friendly while maintaining the reliability and performance of the core CLI tool. The modular design allows for incremental development and easy extension.