diff --git a/docs/specs/2026-09-16-dash-design.md b/docs/specs/2026-09-16-dash-design.md new file mode 100644 index 0000000..c8b4067 --- /dev/null +++ b/docs/specs/2026-09-16-dash-design.md @@ -0,0 +1,141 @@ +# Dash — Design Spec & Roadmap + +Date: 2026-09-16 +Status: proposed — pending UI direction pick (see `mockups/`) + +## 1. Product + +Self-hosted homelab dashboard. A visual launchpad for services (local + external) with live widgets. CasaOS-grade ease of use, Vercel-grade design. Single Docker container, no auth in v1. + +Differentiator: UI-first management (no YAML) + modern design. Homepage requires YAML, Homarr forces auth and complexity, Dashy is overloaded, CasaOS is an OS not a dashboard. + +## 2. Requirements (from prompt.md) + +| Req | Notes | +|---|---| +| Service cards | name, icon (URL or uploaded file), status indicator | +| Multi-URL services | each URL tagged `local` / `external` / custom label; 1 URL = direct nav, 2+ = popover chooser | +| Sections | named groups; collapse/expand; reorder sections and items via drag-drop; items move between sections | +| Add service | `+` button, dialog: name, URLs, icon | +| Widgets | live on the grid; v1: clock/timezones, Pi-hole, AdGuard Home, Immich; extensible registry | +| Themes | dark + light | +| No auth | v1; optional auth is post-1.0 | +| Lightweight | single container, single binary, <50 MB image target | + +## 3. Architecture + +``` +/apps/frontend React 18 + Vite + TS strict + Tailwind + shadcn/ui + dnd-kit +/apps/backend Go + Gin + zap, CGO-free +/packages/api-client generated from OpenAPI (single source of truth) +/infra Dockerfile multi-stage → ONE image; docker-compose.yml (1 service) +/data SQLite file + uploaded icons (bind-mounted) +``` + +### Approved deviations from locked stack + +- **SQLite** (`modernc.org/sqlite`, CGO-free) instead of Postgres. Approved 2026-09-16. Reason: ~100 rows of state, single-binary deployment is the product's core install feature. goose migrations still apply. +- **No DragonflyDB.** Widget responses cached in-process with a small TTL map. Add a real cache only if profiling demands it. + +Everything else per `tdvorak-fullstack` locked stack. + +### Key decisions + +- **Go embeds the frontend** via `embed.FS` → `docker run -v ./data:/data -p 3000:3000 dash` is the entire install. +- **Widget proxy server-side.** Pi-hole/AdGuard/etc. APIs need secrets and are not CORS-safe. Backend exposes `GET /api/widgets/:id/data`; a registry maps widget type → fetcher. New integration = one Go file + one React component. +- **Ordering** via fractional position column (`position REAL`) — drag-drop writes one row, not a renumber of the set. +- **Icons** stored in `data/icons/`; dashboard-icons pack integration for auto-suggest in Phase 3. + +## 4. Data model (SQLite) + +```sql +sections(id TEXT PK, name TEXT, position REAL, collapsed INT, created_at) +items(id TEXT PK, section_id FK, kind TEXT, -- 'service' | 'widget' + name TEXT, icon TEXT, -- icon: path or URL + position REAL, config JSON, created_at) -- widget cfg or null +urls(id TEXT PK, item_id FK, url TEXT, label TEXT, position REAL) +settings(key TEXT PK, value JSON) -- theme, wallpaper, widget secrets ref +``` + +Widget secrets (API keys) live in `config JSON` for v1; encrypted-at-rest only if auth lands later. + +## 5. API (OpenAPI contract — sketch) + +``` +GET/POST/PATCH/DELETE /api/sections +POST /api/sections/reorder +GET/POST/PATCH/DELETE /api/items +POST /api/items/reorder +POST /api/items/:id/icon (upload) +GET /api/widgets/types (registry metadata for UI) +GET /api/widgets/:id/data (live fetch, cached ~30s) +GET/PUT /api/settings +GET /api/export (full JSON backup) +POST /api/import +GET /api/healthz +``` + +Frontend never hand-writes API types — generated client from `openapi.yaml`. + +## 6. Frontend structure + +- `ServiceCard` — icon, name, host, status dot, multi-URL badge → `UrlPopover` +- `Section` — header (label, count, collapse chevron, drag handle) + `SortableContext` grid +- `WidgetHost` — renders widget component by `config.type`, polls `/api/widgets/:id/data` +- `AddServiceDialog`, `EditServiceDialog` (shadcn Dialog + Form) +- `CommandPalette` (⌘K) — Phase 3 +- dnd-kit `DndContext` at board level; sections and items both sortable + +## 7. UI direction — pending + +Three static mockups in `mockups/` — open each, compare: + +| File | Direction | Character | +|---|---|---| +| `a-vercel-mono.html` | Flat monochrome | Geist, hairlines, no shadows, quietest | +| `b-command-bento.html` | Bento grid | mixed tile sizes, widgets inline, densest | +| `c-casa-glass.html` | Glass + wallpaper | homescreen tiles, warmest, most motion | + +Decision recorded here once picked. A and C share card anatomy — hybrid (mono base + optional wallpaper) is cheap later. + +## 8. Roadmap + +### Phase 0 — Foundation +- [ ] Monorepo scaffold, LICENSE (MIT), README, .gitignore, AGENTS.md +- [ ] `openapi.yaml` stub → generated TS client pipeline +- [ ] CI: `go build`, `go vet`, `tsc --noEmit`, oxlint + vendored anti-slop rules +- [ ] `docker compose up` runs the app + +### Phase 1 — MVP +- [ ] Schema + goose migrations; section/item/URL CRUD +- [ ] Board UI: sections, cards, collapse, drag-drop ordering (persist position) +- [ ] Multi-URL popover; icon URL + upload +- [ ] Add/Edit dialogs; delete with confirm +- [ ] Dark/light; responsive to phone width +- [ ] Single-image Dockerfile; JSON export/import + +### Phase 2 — Widgets +- [ ] Widget registry (Go) + `WidgetHost` (React) +- [ ] Clock/timezone widget (frontend-only) +- [ ] Pi-hole, AdGuard Home, Immich fetchers + per-widget config UI +- [ ] Service up/down ping (server-side HEAD, cached) + +### Phase 3 — Open-source readiness +- [ ] Docs (install, config, widget dev guide), screenshots, demo GIF +- [ ] dashboard-icons auto-suggest in icon picker +- [ ] Importers: Homepage `services.yml`, Homarr JSON, Dashy `conf.yml` +- [ ] ⌘K search palette; i18n scaffolding +- [ ] goreleaser (binaries) + GHCR image + semver tags + CHANGELOG +- [ ] Issue/PR templates, CONTRIBUTING.md, code of conduct + +### Phase 4 — Post-1.0 (demand-driven only) +- Optional auth (local + OIDC), health-history graphs, custom CSS/themes, iframe widgets, PWA, wallpaper support for direction A + +### Explicit non-goals for v1 +Auth, Postgres, multi-user, mobile app, container management, YAML-as-source-of-truth. + +## 9. Testing + +- Go: table-driven tests for widget fetchers + reorder logic (`go test ./...`) +- TS: `tsc --noEmit` + oxlint gate; dnd reducer unit tests only if ordering logic grows +- Smoke: `docker compose up` → create section → add service → drag → export JSON diff --git a/mockups/a-vercel-mono.html b/mockups/a-vercel-mono.html new file mode 100644 index 0000000..3fe87a5 --- /dev/null +++ b/mockups/a-vercel-mono.html @@ -0,0 +1,441 @@ + + + + + +Dash — A · Vercel Mono + + + + + +
+
+ + Dash +
+ + + +
+ +
+
+

Overview

+ ● 17 services · +
+ +
+
+ +

Network

4 + +
+
+
+
+
Pi-hole
10.0.0.2
+ 2 +
+
+
+
+
AdGuard Home
10.0.0.3:3000
+ +
+
+
+
Nginx Proxy Mgr
10.0.0.2:81
+ 2 +
+
+
+
+
Uptime Kuma
status.tdvorak.dev
+ 2 +
+
+
+
+ +
+
+ +

Media

6 + +
+
+
+
+
Jellyfin
watch.tdvorak.dev
+ 2 +
+
+
+
+
Immich
photos.tdvorak.dev
+ 2 +
+
+
+
+
Navidrome
10.0.0.10:4533
+ +
+
+
+
qBittorrent
10.0.0.10:8080
+ +
+
+
+
Sonarr
10.0.0.10:8989
+ +
+
+
+
Radarr
10.0.0.10:7878
+ +
+
+
+ +
+
+ +

Infrastructure

7 + +
+
+
+
+
Proxmox
10.0.0.4:8006
+ +
+
+
+
Portainer
10.0.0.4:9000
+ +
+
+
+
TrueNAS
nas.tdvorak.dev
+ 2 +
+
+
+
+
Grafana
10.0.0.4:3100
+ +
+
+
+
Vaultwarden
vault.tdvorak.dev
+ +
+
+
+
Home Assistant
home.tdvorak.dev
+ 2 +
+
+
+
+
Nextcloud
cloud.tdvorak.dev
+ +
+
+
+ +
+
+ +

Widgets

4 + +
+
+
+
Time
+
--:--
+
PRG NYC TYO
+
+
+
Pi-hole
+
24.6%
+
ads blocked · 84,213 queries
+
+
+
AdGuard
+
11.2%
+
blocked · 31 clients
+
+
+
Immich
+
12,483
+
photos · 96.4 GB
+
+
+
+ +

Mockup A — Vercel Mono. Drag cards to reorder. Click a card with a “2” badge to see the URL chooser.

+
+ + + + diff --git a/mockups/b-command-bento.html b/mockups/b-command-bento.html new file mode 100644 index 0000000..77bdb4c --- /dev/null +++ b/mockups/b-command-bento.html @@ -0,0 +1,449 @@ + + + + + +Dash — B · Command Bento + + + + + + +
+
+ + Dash +
+ home / main board + + + +
+ +
+
+ + + + +
+
Local time ● LIVE
+
--:--:--
+
PRG NYC TYO
+
+
+
Pi-hole · today
+
24.6%
+
20,721 ads blocked · 84,213 queries
+
+
+
+
AdGuard
+
11.2%
+
blocked · 31 clients
+
+
+
Immich
+
12,483
+
photos · 96.4 GB
+
+
+
Uptime · 30d
+
99.7%
+
1 incident · Radarr
+
+
+
Storage
+
61%
+
14.2 / 23.2 TB
+
+ + + + +
+
+
Pi-hole
10.0.0.2
+ UP +
+
+
+
+
AdGuard Home
10.0.0.3:3000
+ UP +
+
+
+
Nginx Proxy Mgr
10.0.0.2:81
+ UP +
+
+
+
+
Uptime Kuma
status.tdvorak.dev
+ UP +
+
+ + + + +
+
+
Jellyfin
watch.tdvorak.dev
+ UP +
+
+
+
+
Immich
photos.tdvorak.dev
+ UP +
+
+
+
+
Navidrome
10.0.0.10:4533
+ UP +
+
+
+
qBittorrent
10.0.0.10:8080
+ UP +
+
+
+
Sonarr
10.0.0.10:8989
+ UP +
+
+
+
Radarr
10.0.0.10:7878
+ DOWN +
+ + + + +
+
+
Proxmox
10.0.0.4:8006
+ UP +
+
+
+
Portainer
10.0.0.4:9000
+ UP +
+
+
+
TrueNAS
nas.tdvorak.dev
+ UP +
+
+
+
+
Grafana
10.0.0.4:3100
+ UP +
+
+
+
Vaultwarden
vault.tdvorak.dev
+ UP +
+
+
+
Home Assistant
home.tdvorak.dev
+ UP +
+
+
+
+
Nextcloud
cloud.tdvorak.dev
+ UP +
+ +
+ +

Mockup B — Command Bento. Widgets and services share one grid. Click a multi-URL tile (Jellyfin, Immich…) for the chooser. Section headers collapse.

+
+ + + + diff --git a/mockups/c-casa-glass.html b/mockups/c-casa-glass.html new file mode 100644 index 0000000..61b0d34 --- /dev/null +++ b/mockups/c-casa-glass.html @@ -0,0 +1,466 @@ + + + + + +Dash — C · Casa Glass + + + + +
+ +
+
+ + Dash +
+ + + +
+ +
+
+
+
Good evening
+
--:--
+
+
+
+
Prague
--:--
+
New York
--:--
+
Tokyo
--:--
+
+
+ +
+

Widgets

4 + +
+
+
+
+
Pi-hole
+
24.6%
+
ads blocked today · 84,213 queries
+
+
+
AdGuard Home
+
11.2%
+
blocked · 31 clients online
+
+
+
Immich
+
12,483
+
photos · 96.4 GB library
+
+
+
Storage
+
61%
+
14.2 of 23.2 TB used
+
+
+
+
+ +
+

Network

4 + +
+
+
+
+
Pi-hole
+
2 URLs
+
+
+
+
+
AdGuard Home
+
+
+
+
+
Nginx Proxy Mgr
+
2 URLs
+
+
+
+
+
Uptime Kuma
+
2 URLs
+
+
+
+
+ +
+

Media

6 + +
+
+
+
+
Jellyfin
+
2 URLs
+
+
+
+
+
Immich
+
2 URLs
+
+
+
+
+
Navidrome
+
+
+
+
+
qBittorrent
+
+
+
+
+
Sonarr
+
+
+
+
+
Radarr
+
+
+
+
+ +
+

Infrastructure

7 + +
+
+
+
+
Proxmox
+
+
+
+
+
Portainer
+
+
+
+
+
TrueNAS
+
2 URLs
+
+
+
+
+
Grafana
+
+
+
+
+
Vaultwarden
+
+
+
+
+
Home Assistant
+
2 URLs
+
+
+
+
+
Nextcloud
+
+
+
+
+ +

Mockup C — Casa Glass. Wallpaper + glass trays + homescreen tiles. Click a “2 URLs” tile for the chooser. Trays collapse.

+
+ + + + diff --git a/prompt.md b/prompt.md new file mode 100644 index 0000000..dea7648 --- /dev/null +++ b/prompt.md @@ -0,0 +1 @@ +Okay, I have another simple, quick, easy project that I want to create. I always use some kind of dashboard to manage my home lab and visualize all the stuff that I am running and also what stuff I am running externally. But most of the dashboards seem like they are stuck in the past, which I don't really like. So currently, what I use is CasaOS, which isn't really used for this, but you know, I managed to make it work because when I deploy services, I, let's say, I mostly deploy on CasaOS or Dockploy, but that's not the main point. It's just the CasaOS management and the visualization is so good and easy to use that I like it really much. So here is what I want from the project. I want it stylized and simple, looking like Vercel, in the Vercel style, so ChatCN, styling, GoBackEnd and SolidJS or React frontend, really easy, modern, dark and white mode, nice to look at and easy to manage. I want drag and drop, no authentication, easy plus button to add service. At external service, so you provide the URL, the name, and the link or the file of the image. So you add these to that, it then visualizes it easily from it. Also, when we add the URL for the service, let's allow insertion of multiple URLs. So, for example, the user has local URL for when they are on the local network. Another they have, for example, external, so their domain if they are externally. Then they can save both of these, then mark it as local or external. And then when I click on the dashboard on the service, it shows a pop-up of these two and they can choose, and it takes them to the proper website. So easy like that. Make sure it's really drag and drop, reorient. Also another feature that I'm missing from QOS is grouping, so let's say I have four services, I group them into one section, it then visualizes it, I can close it, open it, reorient the whole section, make it really nice, really easy, really nice visually and the UI, UX. Also, what I want from the app, I just want it to be a lightweight. I open it, see date, time, for example, time zones, and... Let's add some random widget the user can add. For example, let's add Pi-hole, which would be great for the user. AdGuard, Image, for example, if the user are using Image. And I will later send a list of what services exactly I am using, so we can prepare a proper widget structure for other stuff that have APIs and so on. So this should be all of it. Use react and other stuff from @tdvorak-fullstack skills. Drag and drop nice things.. \ No newline at end of file