# DiunDashboard ## What This Is A web-based dashboard that receives DIUN webhook events and presents a persistent, visual overview of which Docker services have available updates. Built for self-hosters who use DIUN to monitor container images but need something better than dismissable push notifications — a place that nags you until you actually update. ## Core Value Reliable, persistent visibility into which services need updating — data never disappears, and the dashboard is the one place you trust to show the full picture. ## Requirements ### Validated - ✓ Receive and store DIUN webhook events — existing - ✓ Display all tracked images with update status — existing - ✓ Acknowledge/dismiss individual updates — existing - ✓ Manual tag/group organization via drag-and-drop — existing - ✓ Tag CRUD (create, delete, assign, unassign) — existing - ✓ Optional webhook authentication via WEBHOOK_SECRET — existing - ✓ Docker deployment with volume-mounted SQLite — existing - ✓ Auto-polling for new updates (5s interval) — existing - ✓ Service icon detection from image names — existing - ✓ SQLite foreign key enforcement (PRAGMA foreign_keys = ON) — Phase 1 - ✓ Proper UPSERT preserving tag assignments on re-webhook — Phase 1 - ✓ Request body size limits (1MB) on webhook and API endpoints — Phase 1 - ✓ Test error handling uses t.Fatalf (no silent failures) — Phase 1 - ✓ Store interface abstracts all persistence operations (9 methods) — Phase 2 - ✓ Server struct replaces package-level globals (db, mu, webhookSecret) — Phase 2 - ✓ Schema migrations via golang-migrate with embedded SQL files — Phase 2 - ✓ Per-test in-memory databases for isolated, parallel-safe testing — Phase 2 - ✓ PostgreSQL support via pgx/v5 with DATABASE_URL env var selection — Phase 3 - ✓ Separate PostgreSQL migration directory with baseline schema — Phase 3 - ✓ Docker Compose profiles for optional PostgreSQL service — Phase 3 - ✓ Cross-dialect UNIQUE constraint detection (case-insensitive) — Phase 3 ### Active - [ ] Bulk acknowledge (dismiss all, dismiss by group) - [ ] Bulk acknowledge (dismiss all, dismiss by group) - [ ] Filtering and search across updates - [ ] In-dashboard new-update indicators (badge/counter/toast) - [ ] Data persistence resilience (survive container restarts reliably) ### Out of Scope - DIUN bundling / unified deployment — future milestone, requires deeper DIUN integration research - Auto-grouping by Docker stack/compose project — future milestone, requires Docker socket or DIUN metadata research - Visual DIUN config management UI — future milestone, depends on DIUN bundling - Notification channel management UI — DIUN already handles this; visual config deferred to DIUN integration milestone - OAuth / user accounts — single-user self-hosted tool, auth beyond webhook secret not needed now - Mobile app — web-first, responsive design sufficient ## Context - User hosts services on a VPS using Coolify (Docker-based PaaS) - DIUN monitors container images for new versions and sends webhooks - Previous approach (Gotify push notifications) failed because notifications were easy to dismiss and forget - Dashboard was a daily driver but data loss (likely volume misconfiguration + SQLite bugs) eroded trust - Coolify doesn't show available updates — this fills that gap - Target audience: self-hosters using DIUN, not limited to Coolify users - Existing codebase: Go 1.26 backend, React 19 + Tailwind + shadcn/ui frontend, SQLite via modernc.org/sqlite ## Constraints - **Tech stack**: Go backend + React frontend — established, no migration - **Database**: Must support both SQLite (simple deploys) and PostgreSQL (robust deploys) - **Deployment**: Docker-first, single-container with optional compose - **No CGO**: Pure Go SQLite driver (modernc.org/sqlite) — must maintain this for easy cross-compilation - **Backward compatible**: Existing users with SQLite databases should be able to upgrade without data loss ## Key Decisions | Decision | Rationale | Outcome | |----------|-----------|---------| | Dual DB (SQLite + PostgreSQL) | SQLite is fine for simple setups, Postgres for users who want robustness | ✓ Phase 3 | | DATABASE_URL as DB selector | Presence of DATABASE_URL activates PostgreSQL; absence falls back to SQLite with DB_PATH | ✓ Phase 3 | | pgx/v5/stdlib over native pgx | Keeps both stores on database/sql for identical constructor signatures | ✓ Phase 3 | | Fix SQLite bugs before adding features | Data trust is the #1 priority; features on a broken foundation waste effort | ✓ Phase 1 | | Store interface as persistence abstraction | 9 methods, no SQL in handlers; enables PostgreSQL swap without touching HTTP layer | ✓ Phase 2 | | Server struct over package globals | Dependency injection via constructor; enables per-test isolated databases | ✓ Phase 2 | | Defer auto-grouping to future milestone | Requires research into Docker socket / DIUN metadata; don't want to slow down stability fixes | — Pending | | Defer DIUN bundling to future milestone | Significant scope; need stability and UX improvements first | — Pending | ## Evolution This document evolves at phase transitions and milestone boundaries. **After each phase transition** (via `/gsd:transition`): 1. Requirements invalidated? → Move to Out of Scope with reason 2. Requirements validated? → Move to Validated with phase reference 3. New requirements emerged? → Add to Active 4. Decisions to log? → Add to Key Decisions 5. "What This Is" still accurate? → Update if drifted **After each milestone** (via `/gsd:complete-milestone`): 1. Full review of all sections 2. Core Value check — still the right priority? 3. Audit Out of Scope — reasons still valid? 4. Update Context with current state --- *Last updated: 2026-03-24 after Phase 3 completion*