Check off tasks as completed. Each task should result in working, testable code.
- Create
go.modwith modulegithub.com/djedi/caddyshack - Create directory structure:
cmd/caddyshack/,internal/,templates/,static/ - Create minimal
cmd/caddyshack/main.gothat starts an HTTP server on port 8080 - Verify with
go run ./cmd/caddyshack- should respond to requests
- Create
LICENSEfile (MIT) - Create
README.mdwith project description, features, and installation instructions - Create
.gitignorefor Go projects (binaries, .env, *.db, node_modules)
- Create
Dockerfile(multi-stage build: Go build + minimal runtime) - Create
docker-compose.dev.ymlfor local development (caddyshack + caddy container) - Add
Makefilewith common commands (build, run, docker-build, docker-up)
- Create
package.jsonwith tailwindcss as dev dependency - Create
tailwind.config.jsconfigured for Go templates - Create
static/css/input.csswith Tailwind directives - Generate
static/css/output.css - Add npm scripts for watch and build
- Create
templates/layouts/base.htmlwith:- HTML5 boilerplate
- Tailwind CSS link
- HTMX script (CDN)
- Alpine.js script (CDN)
- Sidebar navigation placeholder
- Main content area with
{{ block "content" . }}{{ end }}
- Create
internal/templates/templates.goto load and render templates - Update main.go to serve a test page using the base layout
- Add route to serve
/static/files fromstatic/directory - Embed static files in binary using
embed.FSfor production
- Create
templates/pages/dashboard.htmlextending base layout - Create
internal/handlers/dashboard.gowith handler - Display placeholder cards for: "Sites", "Snippets", "Status"
- Style with Tailwind (clean, minimal admin UI)
- Create
internal/config/config.go - Load config from environment variables (see CLAUDE.md for list)
- Provide sensible defaults for local development
- Pass config to handlers via dependency injection
- Add
modernc.org/sqlitedependency (pure Go SQLite) - Create
internal/store/store.gowith database initialization - Create schema for
config_historytable (id, timestamp, content, comment) - Add migration system (simple version table + SQL files or embedded strings)
- Create
internal/caddy/reader.go - Function to read Caddyfile from configured path
- Return raw content as string
- Handle file not found gracefully
- Create
internal/caddy/parser.go - Define
Sitestruct: Domain, Directives []Directive, Imports []string - Parse site blocks (domain { ... }) from Caddyfile
- Extract domain name and raw content of each site
- Write unit tests with example Caddyfile from prompt.md
- Define
Snippetstruct: Name, Content - Parse snippet definitions
(name) { ... } - Store snippets separately from sites
- Write unit tests
- Define
GlobalOptionsstruct: Email, LogConfig, etc. - Parse the global options block
{ ... }at start of file - Write unit tests
- Create
templates/pages/sites.html - Create
internal/handlers/sites.gowith List handler - Display all parsed sites as cards showing domain and basic info
- Add navigation link to sidebar
- Create
templates/partials/site-card.html - Display: domain, reverse proxy target (if applicable), imported snippets
- Add Edit and Delete buttons (non-functional for now)
- Style with Tailwind
- Create
templates/pages/site-detail.html - Show full configuration for a single site
- Display raw Caddyfile block with syntax highlighting (optional)
- Link from site card to detail view
- Create
internal/caddy/writer.go - Function to generate Caddyfile site block from Site struct
- Maintain proper indentation and formatting
- Write unit tests (parse -> write -> compare)
- Function to generate complete Caddyfile from all components
- Order: global options, snippets, sites
- Preserve comments where possible
- Create
internal/caddy/validator.go - Shell out to
caddy validate --config /pathor use Admin API - Return validation errors in structured format
- Write integration test
- Create
templates/partials/site-form.html - Form fields: domain, type (reverse_proxy/static/redirect), target
- Use Alpine.js to show/hide fields based on type selection
- HTMX form submission to POST /sites
- Add POST /sites handler
- Validate input
- Add site to parsed config
- Regenerate and validate Caddyfile
- Save to file
- Return updated site list (HTMX swap)
- Create edit form (reuse site-form partial)
- GET /sites/{domain}/edit returns form with current values
- PUT /sites/{domain} updates the site
- Validate and save
- Add DELETE /sites/{domain} handler
- Confirmation modal using Alpine.js
- Remove site from config
- Regenerate Caddyfile
- Return updated site list
- Create
internal/caddy/admin.go - Function to reload config: POST to /load endpoint
- Function to get current config: GET /config/
- Function to check Caddy status
- Handle connection errors gracefully
- After successful Caddyfile save, trigger reload
- Display reload status in UI (success/failure)
- Show error details if reload fails
- Add Caddy status to dashboard
- Show: running/stopped, uptime, version
- Auto-refresh with HTMX polling (every 30s)
- Before each Caddyfile change, save current version to SQLite
- Store: timestamp, full content, change description
- Limit history to last 50 versions (configurable)
- Create
templates/pages/history.html - List recent config changes with timestamps
- Show diff between versions (simple text diff)
- Add "Restore" button to history entries
- Restore selected version as current Caddyfile
- Validate before applying
- Reload Caddy
- Create
internal/middleware/auth.go - Implement HTTP Basic Auth
- Read credentials from config
- Apply to all routes except /health
- Create login form as alternative to browser basic auth prompt
- Session-based auth with secure cookie
- Logout functionality
- Create error page template
- Consistent error responses for HTMX (swap error message)
- Log errors appropriately
- Add HTMX loading indicators
- Disable buttons during form submission
- Skeleton loaders for async content
- Embed templates and static files in binary
- Optimize Tailwind for production (purge unused)
- Add health check endpoint
- Document deployment process in README
- Unit tests for parser and writer (80%+ coverage)
- Integration tests for handlers
- End-to-end test with real Caddy container
- Create
templates/pages/snippets.html - Create
internal/handlers/snippets.gowith List handler - Display all parsed snippets as cards showing name and preview
- Add navigation link to sidebar
- Wire up routes in main.go
- Create
templates/partials/snippet-card.html - Display: name, content preview (first few lines), usage count
- Add Edit and Delete buttons
- Style with Tailwind consistent with site cards
- Create
templates/pages/snippet-detail.html - Show full snippet content with syntax highlighting
- List sites that use this snippet (via import)
- Link from snippet card to detail view
- Create
templates/partials/snippet-form.html - Form fields: name (identifier), content (textarea)
- Syntax validation on submit
- HTMX form submission to POST /snippets
- Add POST /snippets handler (create)
- Add GET /snippets/{name}/edit handler (edit form)
- Add PUT /snippets/{name} handler (update)
- Add DELETE /snippets/{name} handler
- Validate snippet syntax before saving
- Regenerate Caddyfile and reload Caddy
- Unit tests for snippet CRUD handlers
- Integration tests for snippet routes
- Test snippet creation, editing, deletion flow
- Create
internal/handlers/export.gowith export handler - Add
GET /exportroute that downloads current Caddyfile as file - Add
GET /export/jsonroute that returns config as JSON (using Caddy Admin API) - Create export button in dashboard or settings area
- Include timestamp in filename (e.g.,
caddyfile-2024-01-15.txt)
- Create
templates/pages/import.htmlwith file upload form - Create
internal/handlers/import.gowith import handler - Add navigation link to sidebar (under settings or tools section)
- Support file upload or paste text content
- Preview parsed config before applying
- Parse uploaded/pasted Caddyfile using existing parser
- Validate syntax using
caddy validateor Admin API - Show validation errors with line numbers
- Show preview of sites and snippets that will be imported
- Create "Apply Import" action that saves and reloads
- Create handler to export full backup (Caddyfile + history)
- Package as downloadable JSON or ZIP file
- Include: current Caddyfile, config history, timestamps
- Add backup button to history page or dashboard
- Extend
internal/caddy/admin.gowith certificate methods - GET
/pki/ca/localfor CA info (if using internal CA) - Parse certificate info from Caddy's config JSON
- Handle cases where ACME/certificates aren't configured
- Create
templates/pages/certificates.html - Create
internal/handlers/certificates.gowith handler - Display: domain, issuer, expiry date, status (valid/expiring/expired)
- Add navigation link to sidebar
- Color code by status (green=valid, yellow=expiring soon, red=expired)
- Add certificate summary to dashboard
- Show count of valid, expiring, and expired certificates
- Link to full certificates page
- Auto-refresh with HTMX polling
- Highlight certificates expiring within 30 days
- Add warning banner when certificates need attention
- Show in site detail view if that site's cert is expiring
- Create
templates/pages/global-options.html - Create
internal/handlers/global.gowith handler - Display current global options (email, logging, admin, debug, etc.)
- Add navigation link to sidebar
- Create form to edit common global options
- Fields: email, admin address, debug mode, log format
- Advanced section for raw block editing
- Validate and save changes
- UI to configure global logging settings
- Log output path, format (json/console), roll settings
- Preview generated Caddyfile block
- Save and reload
- Create
internal/handlers/logs.gowith log handler - Read last N lines from configured Caddy log file
- Support configurable log path (from config or auto-detect from Caddyfile)
- Handle log file not found gracefully
- Create
templates/pages/logs.html - Display recent log entries in scrollable view
- Parse JSON log format for readable display
- Show: timestamp, level, message, domain (if applicable)
- Add navigation link to sidebar
- Filter logs by level (error, warn, info)
- Filter by domain/site
- Search within log entries
- HTMX partial refresh for filters
- Add auto-refresh toggle (poll every 5 seconds)
- Scroll to bottom on new entries (optional)
- Pause auto-refresh when user scrolls up
- Show "new entries" indicator
- Create
internal/docker/client.gowith Docker client - Connect to Docker socket (configurable path)
- Function to list running containers
- Function to get container status by name or ID
- Handle Docker not available gracefully (optional feature)
- Create
templates/pages/containers.html - Create
internal/handlers/containers.gowith handler - Display: container name, status (running/stopped), image, ports
- Add navigation link to sidebar
- Color code by status (green=running, red=stopped)
- Parse reverse_proxy targets to identify potential container hosts
- Match container ports to proxy targets
- Show container status in site detail view
- Add indicator on site cards for container health (moved to Task 21.4)
- Add container summary to dashboard
- Show count of running, stopped, and unhealthy containers
- Link to full containers page
- Auto-refresh with HTMX polling
- Add start/stop/restart buttons for containers
- Confirmation modal for container actions
- Log output for container actions
- Require admin permissions for container control
- Create
internal/notifications/notification.gowith notification types and interfaces - Define Notification struct: Type, Severity, Title, Message, Timestamp, Acknowledged
- Create notification storage in SQLite (notifications table with type, severity, data, created_at, ack_at)
- Add notification service for creating, listing, and acknowledging notifications
- Create
templates/pages/notifications.htmlfor notification center - Create
internal/handlers/notifications.gowith handlers - Add notification bell icon to header with unread count badge
- Create notification dropdown/panel showing recent notifications
- Add "Mark as read" and "Mark all as read" functionality
- Add navigation link to full notification history
- Create background job to check certificate expiry daily
- Generate notification when certificate expires within 30 days (warning)
- Generate notification when certificate expires within 7 days (critical)
- Generate notification when certificate has expired (error)
- Link notification to certificate details page
- Avoid duplicate notifications for same certificate/threshold
- Create
internal/notifications/email.gowith SMTP client - Add email configuration to config.go (SMTP host, port, user, password, from address)
- Create email templates for notifications
- Add email preferences per notification type (UI setting)
- Send email for critical notifications (configurable)
- Create
internal/notifications/webhook.gofor webhook delivery - Add webhook URL configuration (supports multiple endpoints)
- POST notification data as JSON to configured webhooks
- Support webhook headers for authentication
- Retry failed webhook deliveries with exponential backoff
- Create domains table in SQLite (domain, registrar, expiry_date, notes, created_at)
- Create
internal/handlers/domains.gowith CRUD handlers - Create
templates/pages/domains.htmlfor domain list - Auto-detect domains from Caddyfile sites
- Allow manual domain entry with registrar and expiry info
- Add expiry tracking for registered domains
- Background job to check domain expiry dates
- Generate notification when domain expires within 60 days (warning)
- Generate notification when domain expires within 14 days (critical)
- Link notification to domain details
- Create
internal/domains/whois.gofor WHOIS lookups - Lookup domain expiry date automatically
- Cache WHOIS results to avoid rate limiting
- Button to refresh WHOIS data manually
- Parse registrar and nameserver info
- Create users table in SQLite (id, username, email, password_hash, role, created_at, last_login)
- Create
internal/auth/user.gowith User model and password hashing (bcrypt) - Define roles: admin, editor, viewer
- Role permissions: admin (all), editor (CRUD sites/snippets), viewer (read-only)
- Migrate from basic auth to session-based auth
- Create
templates/pages/users.htmlfor user list (admin only) - Create
internal/handlers/users.gowith CRUD handlers - Add user creation form with role selection
- Add user edit form (change password, role)
- Add user deletion with confirmation
- Only admins can manage users
- Create
internal/middleware/rbac.gofor role checking - Protect routes based on required role
- Hide UI elements based on user role
- Viewer role: read-only access, no edit/delete buttons
- Editor role: can edit sites/snippets, cannot manage users or global settings
- Admin role: full access
- Create
templates/pages/profile.htmlfor current user settings - Allow users to change their own password
- Notification preferences per user
- Theme preference (if dark mode is implemented) - skipped, dark mode not yet implemented
- Session management (list active sessions, logout other sessions)
- Create audit_log table (user_id, action, resource_type, resource_id, details, timestamp)
- Log all configuration changes with user attribution
- Create
templates/pages/audit.htmlto view audit log (admin only) - Filter by user, action type, date range
- Link audit entries to relevant resources
- Add dark mode CSS variants with Tailwind dark: modifier
- Add theme toggle in header (light/dark/system)
- Store preference in localStorage or user profile
- Respect system preference by default
- Allow reordering of dashboard widgets
- Allow hiding/showing widgets
- Collapsible widget sections
- Store layout preference per user
- Add keyboard shortcuts for common actions
-
?to show shortcuts help modal -
nfor new site,g sfor sites,g dfor dashboard -
Escapeto close modals - Use Alpine.js for shortcut handling
- Add global search in header
- Search across sites, snippets, logs
- Quick navigation results (cmd+k style)
- Recent searches history
- Create api_tokens table (id, user_id, token_hash, name, permissions, created_at, expires_at, last_used)
- Create
internal/auth/token.gowith token generation and validation - Add API token management UI (create, revoke, list tokens)
- Create middleware to authenticate API requests via Bearer token
- Define API scopes/permissions (read, write, admin)
- Create
internal/middleware/ratelimit.gofor rate limiting - Rate limit login attempts (5 attempts per 15 minutes per IP)
- Rate limit API requests (configurable per token/user)
- Add lockout notification when rate limit exceeded
- Store rate limit data in memory with configurable backend
- Add TOTP support with
pquerna/otplibrary - Create
internal/auth/totp.gofor TOTP handling - Add 2FA setup flow in user profile (QR code generation)
- Add 2FA verification step in login flow
- Add backup codes for account recovery
- Allow admins to disable 2FA for users
- Add container health check to site card partial
- Display small status indicator (dot) on site cards for linked containers
- Color code: green=running, red=stopped, yellow=unhealthy
- Tooltip showing container name and status
- Handle case where Docker integration is disabled
- Create
internal/handlers/metrics.gowith Prometheus handler - Export Caddy status metrics (uptime, config reloads)
- Export certificate metrics (valid count, expiring count, expired count)
- Export container metrics if Docker enabled
- Add /metrics endpoint (optionally protected)
- Add request rate and latency charts to dashboard
- Display error rate trends
- Show bandwidth usage per site (from Caddy logs)
- Add time range selector (1h, 24h, 7d, 30d)
- Store aggregated metrics in SQLite
- Create comprehensive /health endpoint with component status
- Check Caddy connectivity
- Check database connectivity
- Check Docker connectivity (if enabled)
- Return structured JSON with component statuses
- Create
internal/git/git.gofor git operations - Initialize git repo for Caddyfile directory (optional)
- Auto-commit on Caddyfile changes with meaningful messages
- View git history in UI
- Diff between commits
- Add backup schedule configuration (daily, weekly)
- Create
internal/backup/scheduler.gofor scheduled tasks - Store backups in configurable location
- Auto-cleanup old backups (configurable retention)
- Add backup status to dashboard
- Create
internal/caddy/nginx.gofor nginx config parsing - Parse nginx.conf server blocks
- Convert to equivalent Caddyfile configuration
- Preview conversion before applying
- Handle common nginx directives (proxy_pass, location, rewrite)
Ideas for future development:
- Traefik configuration import
- Mobile-responsive improvements
- Caddy plugin management
- Multi-server management (manage multiple Caddy instances)
- Configuration templates/presets
- API documentation (OpenAPI/Swagger)
- WebSocket support for real-time log streaming
- Site analytics integration