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>
8.6 KiB
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.yamlstub → generated TS client (packages/api-client)- Backend skeleton: Gin router,
zaplogging,/api/healthz, SQLite open + goose migrations runner - Frontend skeleton: Vite + TS strict + Tailwind + shadcn/ui, theme tokens matching
d-bento-mono.htmlCSS 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.FSserves UI) - SPA fallback routing in embedded server (
/+ client-side paths →index.html,/apiisolated) docker-compose.yml— one service,./data:/datavolume
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(fractionalposition REALordering) - REST API: CRUD for sections/items/urls,
reorderendpoints, icon upload,settings,export/importJSON - Renderer contract: shared board store +
BoardView/SectionView/ItemView/WidgetViewseam, 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/downchip - Parallel probing: per-item
sync.WaitGroupfan-out, 4s client timeout - URL scheme allowlist (
http/httpsonly —file://etc. rejected on create + probe) - Post-drag click suppression (
lastDropAtwindow — 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:
Widgetinterface (Type(),Fetch(cfg)),GET /api/widgets/:id/datawith ~30s in-process TTL cache GET /api/widgets/types→ registry metadata drives the add-widget dialogWidgetHostcomponent: mapsconfig.type→ React component, polls with backoff- Widgets as grid items (same
itemstable,kind = 'widget',config JSON) - Clock/timezone widget (frontend-only)
- Pi-hole fetcher (blocked %, queries today) — per-day bar series deferred: v5
api.phplacks 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) localtype flag: frontend-only widgets (clock) register in/api/widgets/typeswithout 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
indexprop → 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-visiblemoved 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, Dashyconf.yml→ sections/items/urls README.mdhero: screenshots (4 themes), demo GIF,docker runone-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.