Files
Dash/ROADMAP.md
T
Tomas Dvorak 331721cca5 docs: roadmap fully reconciled with shipped work
Adds shipped-but-unlisted items under each phase: parallel status probing,
URL scheme allowlist, post-drag click suppression, mobile status-dot
fallback, api_test.go coverage, widget local flag + error states + endpoint
tests, renderer index prop, icon preview, / shortcut, bundled fonts,
@layer base fix, SPA fallback, pre-paint theme bootstrap. Releases table
gates marked verified through v0.3.0.

Generated with [Devin](https://devin.ai)

Authored By: TDvorak <[email protected]>
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-17 20:29:22 +02:00

8.6 KiB
Raw Blame History

Dash — Roadmap

A self-hosted homelab dashboard. CasaOS-grade ease of use, Vercel-grade design. Single container, UI-managed, no YAML, no auth required.

Stack: Go + Gin + SQLite (single static binary, embeds frontend) · React 18 + Vite + TS strict + Tailwind + shadcn/ui + dnd-kit · OpenAPI-generated client.


Design system

Multiple board styles are a core feature: same system, same functionality, different UI structure per style. A renderer supplies the layout; board state, drag-drop, popovers, and dialogs are shared primitives underneath.

Renderer Source mockup Ships
Bento (default) d-bento-mono.html v0.1.0 — mixed-size grid, widgets inline
Cards a-vercel-mono.html v0.1.0 — uniform compact grid; validates the seam early
Index e-editorial.html v0.3.0 — serif headers, list rows, stat strip
Console f-console.html v0.3.0 — terminal panels, [ up ] tags

Contract: renderers/<name>/{BoardView, SectionView, ItemView, WidgetView}. Tokens (--bg, --surface, --border, …) shared; dark/light is orthogonal. User picks renderer in settings; persisted. Renderers never reimplement dnd or popover logic.


Releases

Version Contents Gate
v0.1.0 Phase 0 + 1 — working MVP, single image manual smoke test ✅
v0.2.0 Phase 2 — widget layer + first integrations Pi-hole widget live ✅
v0.3.0 Phase 3 — four renderers, ⌘K palette, icon suggest palette + switcher live ✅
v1.0.0 Phase 4 — OSS polish, docs, importers, CI releases public repo launch
v1.x Phase 5 — demand-driven extras only per-feature

Phase 0 — Foundation → part of v0.1.0 ✅ done 2026-09-17

Repo hygiene and pipelines before features.

  • Monorepo scaffold (apps/frontend, apps/backend, packages/api-client, infra/, data/)
  • MIT LICENSE, README.md, .gitignore, AGENTS.md
  • openapi.yaml stub → generated TS client (packages/api-client)
  • Backend skeleton: Gin router, zap logging, /api/healthz, SQLite open + goose migrations runner
  • Frontend skeleton: Vite + TS strict + Tailwind + shadcn/ui, theme tokens matching d-bento-mono.html CSS vars
  • CI (GitHub Actions): go build ./..., go vet ./..., go test ./..., tsc --noEmit, oxlint + vendored anti-slop rules, npm run build
  • Multi-stage Dockerfile (frontend build → Go build → distroless, embed.FS serves UI)
  • SPA fallback routing in embedded server (/ + client-side paths → index.html, /api isolated)
  • docker-compose.yml — one service, ./data:/data volume

Exit: docker compose up serves a blank board — verified locally (33.6 MB image). CI green on main — pending first push.

Phase 1 — MVP → v0.1.0 ✅ done 2026-09-17

The product's spine: sections, services, drag-drop, multi-URL.

  • Schema: sections, items, urls, settings (fractional position REAL ordering)
  • REST API: CRUD for sections/items/urls, reorder endpoints, icon upload, settings, export/import JSON
  • Renderer contract: shared board store + BoardView/SectionView/ItemView/WidgetView seam, dnd + popover as shared primitives
  • Bento renderer (default): mixed-size grid, hairline section headers, tiles with status chips
  • Cards renderer: uniform compact grid — second renderer proves the seam while code is small
  • dnd-kit: reorder items in a section, move items between sections, reorder sections; persist on drop
  • Collapse/expand sections (persisted)
  • UrlPopover: 1 URL → direct open, 2+ → chooser (local/external/custom tags)
  • ServiceDialog — one dialog for add + edit (name, URLs+labels, icon URL or file upload)
  • Icon handling: upload to data/icons/, remote URL passthrough, letter-tile fallback
  • Dark/light toggle (persisted), renderer picker in settings, responsive to ~360px
  • Pre-paint theme bootstrap in index.html (no wrong-theme flash on load)
  • Status ping: server-side HEAD request per service URL, cached ~60s → up/down chip
  • Parallel probing: per-item sync.WaitGroup fan-out, 4s client timeout
  • URL scheme allowlist (http/https only — file:// etc. rejected on create + probe)
  • Post-drag click suppression (lastDropAt window — drops no longer fire tile activation)
  • Mobile polish: status chip collapses to dot-only below 620px
  • api_test.go: reorder positions, URL scheme rejection, settings round-trip

Exit: create sections, add services with icons and dual URLs, drag everything, reload — state persists. docker run single image works. Export/import round-trips. — verified: full API + browser smoke (dnd, popover, upload, collapse, themes, both renderers, 360px), api_test.go covers reorder/URL-validation/settings.

Phase 2 — Widgets → v0.2.0 ✅ done 2026-09-17

  • Go widget registry: Widget interface (Type(), Fetch(cfg)), GET /api/widgets/:id/data with ~30s in-process TTL cache
  • GET /api/widgets/types → registry metadata drives the add-widget dialog
  • WidgetHost component: maps config.type → React component, polls with backoff
  • Widgets as grid items (same items table, kind = 'widget', config JSON)
  • Clock/timezone widget (frontend-only)
  • Pi-hole fetcher (blocked %, queries today) — per-day bar series deferred: v5 api.php lacks it, needs Pi-hole v6 /api/history
  • AdGuard Home fetcher (blocked %, queries, avg processing ms)
  • Immich fetcher (photo/video count, library size)
  • Per-widget config UI (endpoint URL, API key — stored in config, never logged)
  • local type flag: frontend-only widgets (clock) register in /api/widgets/types without a fetcher
  • Widget tile error/loading states (graceful upstream 502 rendering)
  • Widget endpoint tests: type registry, 404 on missing item, 502 on dead upstream, TTL cache hit

Exit: Pi-hole widget shows real data; adding a new integration = one Go file + one React component. — verified: registry, cache, 502 path, generic config dialog, clock live in-browser, Pi-hole fetcher against stubbed v5 API.

Phase 3 — Renderers & ergonomics → v0.3.0 ✅ done 2026-09-17

  • Index renderer: serif section headers, full-width rows, masthead stat strip
  • Console renderer: bordered panels/tables, JetBrains Mono, [ up ] tags
  • Renderer switcher polished (2×2 radio grid with per-renderer descriptions)
  • ⌘K command palette: jump to service, add service, toggle theme, switch renderer (⌘K / Ctrl+K / /)
  • dashboard-icons auto-suggest in icon picker (name → slug → CDN URL chip + live preview)
  • Renderer contract index prop → row/section numbering without re-deriving position
  • Icon URL live preview in service dialog (dead URLs degrade to dashed tile)
  • Palette / shortcut + header search button for discoverability
  • Fonts: Instrument Serif + JetBrains Mono via fontsource (bundled, no CDN dep)
  • Fix: global :focus-visible moved into @layer base (was silently overriding all utility overrides)
  • User services list → prioritized widget backlog (owner-supplied list pending)

Exit: all four renderers work off the same board state; palette navigates everything. — verified: both new renderers render/persist/dnd/collapse, palette filters and executes, icon suggest resolves real CDN assets, 360px + light theme, docker image 43.9 MB.

Phase 4 — Open-source launch → v1.0.0

  • Docs: install, configuration, widget development guide (docs/)
  • Importers: Homepage services.yml, Homarr JSON, Dashy conf.yml → sections/items/urls
  • README.md hero: screenshots (4 themes), demo GIF, docker run one-liner
  • goreleaser → binaries; GHCR image on tag; semver + CHANGELOG.md
  • CONTRIBUTING.md, issue/PR templates, code of conduct, security policy
  • i18n scaffolding (en default)
  • Public repo flip + announcement assets

Exit: a stranger can docker run, import their Homepage config, and have a working board in under two minutes.

Phase 5 — Post-1.0 (demand-driven only)

Build only what users actually ask for. Candidates, unordered:

  • Optional auth (local password + OIDC) — most-requested, likely first
  • Health-check history + uptime graphs
  • Custom CSS / accent color / wallpaper
  • Iframe/embed widgets, API-status widgets (generic JSON path)
  • PWA install, mobile layout polish
  • Multiple boards

Non-goals (v1)

Auth, Postgres/external DB, multi-user, mobile app, container lifecycle management, YAML-as-source-of-truth. Revisit only with evidence of demand.