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

143 lines
8.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.
- [x] Monorepo scaffold (`apps/frontend`, `apps/backend`, `packages/api-client`, `infra/`, `data/`)
- [x] MIT `LICENSE`, `README.md`, `.gitignore`, `AGENTS.md`
- [x] `openapi.yaml` stub → generated TS client (`packages/api-client`)
- [x] Backend skeleton: Gin router, `zap` logging, `/api/healthz`, SQLite open + goose migrations runner
- [x] Frontend skeleton: Vite + TS strict + Tailwind + shadcn/ui, theme tokens matching `d-bento-mono.html` CSS vars
- [x] CI (GitHub Actions): `go build ./...`, `go vet ./...`, `go test ./...`, `tsc --noEmit`, `oxlint` + vendored anti-slop rules, `npm run build`
- [x] Multi-stage `Dockerfile` (frontend build → Go build → distroless, `embed.FS` serves UI)
- [x] SPA fallback routing in embedded server (`/` + client-side paths → `index.html`, `/api` isolated)
- [x] `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.
- [x] Schema: `sections`, `items`, `urls`, `settings` (fractional `position REAL` ordering)
- [x] REST API: CRUD for sections/items/urls, `reorder` endpoints, icon upload, `settings`, `export`/`import` JSON
- [x] Renderer contract: shared board store + `BoardView`/`SectionView`/`ItemView`/`WidgetView` seam, dnd + popover as shared primitives
- [x] **Bento** renderer (default): mixed-size grid, hairline section headers, tiles with status chips
- [x] **Cards** renderer: uniform compact grid — second renderer proves the seam while code is small
- [x] dnd-kit: reorder items in a section, move items between sections, reorder sections; persist on drop
- [x] Collapse/expand sections (persisted)
- [x] `UrlPopover`: 1 URL → direct open, 2+ → chooser (`local`/`external`/custom tags)
- [x] `ServiceDialog` — one dialog for add + edit (name, URLs+labels, icon URL or file upload)
- [x] Icon handling: upload to `data/icons/`, remote URL passthrough, letter-tile fallback
- [x] Dark/light toggle (persisted), renderer picker in settings, responsive to ~360px
- [x] Pre-paint theme bootstrap in `index.html` (no wrong-theme flash on load)
- [x] Status ping: server-side HEAD request per service URL, cached ~60s → `up`/`down` chip
- [x] Parallel probing: per-item `sync.WaitGroup` fan-out, 4s client timeout
- [x] URL scheme allowlist (`http`/`https` only — `file://` etc. rejected on create + probe)
- [x] Post-drag click suppression (`lastDropAt` window — drops no longer fire tile activation)
- [x] Mobile polish: status chip collapses to dot-only below 620px
- [x] `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
- [x] Go widget registry: `Widget` interface (`Type()`, `Fetch(cfg)`), `GET /api/widgets/:id/data` with ~30s in-process TTL cache
- [x] `GET /api/widgets/types` → registry metadata drives the add-widget dialog
- [x] `WidgetHost` component: maps `config.type` → React component, polls with backoff
- [x] Widgets as grid items (same `items` table, `kind = 'widget'`, `config JSON`)
- [x] Clock/timezone widget (frontend-only)
- [x] Pi-hole fetcher (blocked %, queries today) — per-day bar series deferred: v5 `api.php` lacks it, needs Pi-hole v6 `/api/history`
- [x] AdGuard Home fetcher (blocked %, queries, avg processing ms)
- [x] Immich fetcher (photo/video count, library size)
- [x] Per-widget config UI (endpoint URL, API key — stored in `config`, never logged)
- [x] `local` type flag: frontend-only widgets (clock) register in `/api/widgets/types` without a fetcher
- [x] Widget tile error/loading states (graceful upstream 502 rendering)
- [x] 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
- [x] **Index** renderer: serif section headers, full-width rows, masthead stat strip
- [x] **Console** renderer: bordered panels/tables, JetBrains Mono, `[ up ]` tags
- [x] Renderer switcher polished (2×2 radio grid with per-renderer descriptions)
- [x] ⌘K command palette: jump to service, add service, toggle theme, switch renderer (⌘K / Ctrl+K / `/`)
- [x] dashboard-icons auto-suggest in icon picker (name → slug → CDN URL chip + live preview)
- [x] Renderer contract `index` prop → row/section numbering without re-deriving position
- [x] Icon URL live preview in service dialog (dead URLs degrade to dashed tile)
- [x] Palette `/` shortcut + header search button for discoverability
- [x] Fonts: Instrument Serif + JetBrains Mono via fontsource (bundled, no CDN dep)
- [x] 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.