diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 25a48b0..9eb5c2d 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -28,8 +28,8 @@ DASH_DEV=1 go run ./cmd/dash # API on :8080
and `-- +goose Down`.
- Board renderers share state, drag-drop, and popover primitives. Never
reimplement them per renderer.
-- No auth, no YAML-as-source-of-truth, no external database. These are
- non-goals for v1.
+- Auth is opt-in and local-only: no OIDC/SSO, no multi-user RBAC. No
+ YAML-as-source-of-truth, no external database. These are non-goals.
- Standard library before dependencies; existing helpers before new ones.
- User-visible strings go through `t("key")` from `src/i18n` — add the key to
`en.ts` rather than inlining literals in new UI.
diff --git a/README.md b/README.md
index 98998e9..22b01ad 100644
--- a/README.md
+++ b/README.md
@@ -1,53 +1,106 @@
-# Dash
+
+
+
-A self-hosted homelab dashboard. CasaOS-grade ease of use, Vercel-grade design.
-Single container, UI-managed, no YAML. Optional auth.
+Dash
-
+
+ Self-hosted homelab dashboard.
+ Service boards, uptime monitors, domain watch, and system metrics in one container.
+
+
+
+ Quick Start ·
+ Documentation ·
+ Releases ·
+ Contributing
+
+
+
+
+
+
+
+
+## What is Dash?
+
+Dash is a self-hosted homelab dashboard: service boards with drag-and-drop,
+uptime monitors, domain intelligence, push-based system metrics, incidents,
+and public status pages — one static Go binary serving an embedded React UI.
+No YAML, no external database; auth is optional and off by default.
+
+## Screenshots
+
+| Board | Monitors | Systems |
+|:-:|:-:|:-:|
+|  |  |  |
+
+
+More screenshots
+
+| Domains | Status page |
+|:-:|:-:|
+|  |  |
+
+
## Features
-- **Service board** — multiple boards, sections, drag-and-drop, multi-URL
- services, icon upload, four renderers (Bento, Cards, Index, Console),
- dark/light themes, custom accent/wallpaper/CSS
-- **Uptime monitors** — HTTP, TCP, ping, DNS, keyword, JSON-path, and push
- checks on a schedule, heartbeat history, uptime graphs, per-monitor alert
- rules
-- **Domain watch** — WHOIS/RDAP, DNS records, TLS certificate expiry,
- registrar and provider detection, CT-log subdomain discovery
-- **System monitoring** — lightweight `dash-agent` pushes CPU, memory, disk,
- network, load, temperatures, per-container stats, and SMART/ZFS/GPU when
- available
-- **Incidents & status pages** — manual and automatic incidents, maintenance
- windows, public `/status/:slug` pages, SVG badges
-- **Alerts** — webhook, Slack, Discord, Telegram, Gotify, ntfy, and SMTP
- transports
-- **Observability** — Prometheus `/api/metrics`, JSON export, CSV bulk import,
- importers for Homepage, Homarr, and Dashy configs
-- **Optional auth** — local username/password with bcrypt + session cookies,
- off by default; public status pages stay open either way
-- **i18n + PWA** — English and Czech UI, installable manifest/service worker
+- **Service boards** — multiple boards, sections, drag-and-drop, multi-URL services, icon upload, four renderers (Bento, Cards, Index, Console), dark/light themes, custom accent/wallpaper/CSS.
+- **Uptime monitors** — HTTP, TCP, ping, DNS, keyword, JSON-path, and push checks on a schedule; heartbeat history, uptime graphs, per-monitor alert rules.
+- **Domain watch** — WHOIS/RDAP, DNS records, TLS certificate expiry, registrar and provider detection, CT-log subdomain discovery.
+- **System monitoring** — lightweight `dash-agent` pushes CPU, memory, disk, network, load, temperatures, per-container stats, and SMART/ZFS/GPU when available.
+- **Incidents & status pages** — automatic incidents on monitor down, maintenance windows, public `/status/:slug` pages, SVG badges.
+- **Alerts** — webhook, Slack, Discord, Telegram, Gotify, ntfy, and SMTP transports.
+- **Observability** — Prometheus `/api/metrics`, JSON export, CSV bulk import, importers for Homepage, Homarr, and Dashy configs.
+- **Optional auth** — local username/password, bcrypt + SQLite sessions, off by default; public status pages stay open either way.
+- **i18n + PWA** — English and Czech UI, installable manifest/service worker.
-## Run
+## Architecture
+
+```
+Browser ──▶ dash (single static Go binary)
+ ├── Embedded React UI (embed.FS)
+ ├── REST API (Gin) ──▶ SQLite
+ └── Schedulers ──▶ monitors, domain refresh, alerts, retention
+ │
+ ▼ outbound
+ HTTP/TCP/ICMP/DNS, WHOIS/RDAP, TLS, SMTP
+
+dash-agent (one binary per host) ──push JSON──▶ POST /api/systems/ingest
+```
+
+## Quick Start
+
+Prerequisites: Docker.
+
+```bash
+curl -fsSL https://raw.githubusercontent.com/Dvorinka/Dash/main/install.sh | sh
+```
+
+Installs into `./dash` and starts the stack on port 3000. Or from a clone:
+
+```bash
+git clone https://github.com/Dvorinka/Dash.git && cd Dash
+./scripts/setup.sh # builds the image and starts the stack
+```
+
+Or plain `docker run`, no script needed:
```sh
docker run -d -v ./data:/data -p 3000:3000 ghcr.io/dvorinka/dash:latest
```
-or with compose:
+Then open `http://localhost:3000` — everything is configured from the UI.
+For the system agent, binary installs, reverse proxies, and upgrades see
+[docs/installation.md](docs/installation.md).
-```yaml
-services:
- dash:
- image: ghcr.io/dvorinka/dash:latest
- ports:
- - "3000:3000"
- volumes:
- - ./data:/data
- restart: unless-stopped
-```
+## Configuration
-Then open http://localhost:3000. Everything is configured from the UI.
+Dash is configured from the UI; the server reads three environment
+variables (`DASH_PORT`, `DASH_DATA_DIR`, `DASH_DEV`). All state lives in one
+directory — a SQLite database plus uploaded icons. See
+[docs/configuration.md](docs/configuration.md).
## System agent
@@ -57,22 +110,16 @@ Monitor a Linux host: create a system in the UI, copy the token, then:
dash-agent -url http://dash:3000 -token
```
-One static binary, no dependencies. See
-[docs/installation.md](docs/installation.md) for systemd and Docker setups.
+One static binary, no dependencies. systemd unit and container image covered
+in [docs/installation.md](docs/installation.md#dash-agent-system-monitoring).
-## Screenshots
+## Documentation
-| | |
-|---|---|
-|  |  |
-|  |  |
-
-## Docs
-
-- [Installation](docs/installation.md)
-- [Configuration](docs/configuration.md)
-- [Widget development](docs/widgets.md)
-- [Roadmap](ROADMAP.md) · [Changelog](CHANGELOG.md) · [Contributing](CONTRIBUTING.md)
+- [docs/installation.md](docs/installation.md) — Docker, binary, agent, reverse proxy, upgrades
+- [docs/configuration.md](docs/configuration.md) — env vars, notifications, auth, boards, operations
+- [docs/widgets.md](docs/widgets.md) — widget development guide
+- `openapi.yaml` — API contract (generated TS client in `packages/api-client`)
+- [ROADMAP.md](ROADMAP.md) — design decisions and release history
## Develop
@@ -80,21 +127,21 @@ Requires Go 1.24+ and Node 20+.
```sh
npm install # workspaces: frontend + api-client
-npm run generate # regenerate TS client from openapi.yaml
npm run dev # vite dev on :5173, proxies /api to :8080
```
-In another shell:
-
```sh
cd apps/backend
DASH_DEV=1 go run ./cmd/dash # API on :8080 (DASH_DEV skips embedded UI)
```
-## Stack
+## Contributing
-Go + Gin + SQLite (single static binary, embeds the frontend) · React 18 +
-Vite + TS strict + Tailwind + shadcn/ui + dnd-kit · OpenAPI-generated client.
+See [CONTRIBUTING.md](CONTRIBUTING.md) for the development workflow.
+
+## Security
+
+See [SECURITY.md](SECURITY.md) for reporting vulnerabilities.
## License
diff --git a/SECURITY.md b/SECURITY.md
index 8196235..3cbd37d 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -7,7 +7,7 @@
| latest release | yes |
| older releases | no |
-Dash is pre-1.0; only the latest release receives fixes.
+Only the latest release receives fixes.
## Reporting a vulnerability
diff --git a/dash.svg b/dash.svg
new file mode 100644
index 0000000..804cb76
--- /dev/null
+++ b/dash.svg
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/docs/installation.md b/docs/installation.md
index c4ee3f9..c543cc1 100644
--- a/docs/installation.md
+++ b/docs/installation.md
@@ -3,7 +3,16 @@
Dash ships as a single container image or a single static binary. All state
lives in one directory: a SQLite database and uploaded icons.
-## Docker (recommended)
+## One-line install
+
+```sh
+curl -fsSL https://raw.githubusercontent.com/Dvorinka/Dash/main/install.sh | sh
+```
+
+Creates `./dash`, pulls the image, and starts on port 3000. Override with
+`DASH_DIR` / `DASH_PORT` environment variables.
+
+## Docker (manual)
```sh
docker run -d --name dash \
diff --git a/install.sh b/install.sh
new file mode 100755
index 0000000..5a98451
--- /dev/null
+++ b/install.sh
@@ -0,0 +1,80 @@
+#!/bin/sh
+# Dash installer — curl -fsSL https://raw.githubusercontent.com/Dvorinka/Dash/main/install.sh | sh
+# Creates ./dash, writes a compose file, pulls the image, starts on :3000.
+set -eu
+
+DIR="${DASH_DIR:-dash}"
+PORT="${DASH_PORT:-3000}"
+IMAGE="ghcr.io/dvorinka/dash:latest"
+DATA_HINT=""
+
+info() { printf ' %s\n' "$1"; }
+fail() { printf 'error: %s\n' "$1" >&2; exit 1; }
+
+command -v docker >/dev/null 2>&1 || fail "docker not found — install Docker first: https://docs.docker.com/engine/install"
+docker info >/dev/null 2>&1 || fail "docker daemon not reachable — start it, or run with sudo/root"
+
+mkdir -p "$DIR/data"
+cd "$DIR"
+
+# compose.yml with a bind mount (data dir visible next to the file) or, when
+# Docker Desktop file sharing forbids it, a named volume.
+write_compose() {
+ if [ "$1" = "named" ]; then
+ cat > compose.yml < compose.yml </dev/null 2>&1; then
+ write_compose bind
+ docker compose pull
+ if up_out=$(docker compose up -d --remove-orphans 2>&1); then
+ DATA_HINT="$(pwd)/data"
+ elif printf '%s' "$up_out" | grep -qi "not shared\|mounts denied"; then
+ info "Host path not shareable - retrying with a named volume"
+ write_compose named
+ docker compose up -d --remove-orphans
+ DATA_HINT="the 'dash-data' docker volume (docker volume ls | grep dash-data)"
+ else
+ printf '%s\n' "$up_out" >&2
+ exit 1
+ fi
+else
+ # No compose plugin — named volume keeps docker run free of host-path rules.
+ info "Compose plugin absent; using docker run"
+ docker rm -f dash >/dev/null 2>&1 || true
+ docker pull "$IMAGE"
+ docker run -d --name dash --restart unless-stopped \
+ -p "$PORT:3000" -v dash-data:/data "$IMAGE"
+ DATA_HINT="docker volume 'dash-data'"
+fi
+
+info ""
+info "Dash is up: http://localhost:$PORT"
+info "Data lives in $DATA_HINT — back it up to back up everything."
+info "Upgrade later: docker compose pull && docker compose up -d (or: docker pull $IMAGE && docker restart dash)"
diff --git a/scripts/setup.sh b/scripts/setup.sh
new file mode 100755
index 0000000..1ae536f
--- /dev/null
+++ b/scripts/setup.sh
@@ -0,0 +1,19 @@
+#!/bin/sh
+# Dash setup from a clone — builds the image locally and starts the stack.
+# For the prebuilt image path, use ../install.sh instead.
+set -eu
+
+cd "$(dirname "$0")/.."
+
+command -v docker >/dev/null 2>&1 || { echo "error: docker not found" >&2; exit 1; }
+docker compose version >/dev/null 2>&1 || { echo "error: docker compose plugin not found" >&2; exit 1; }
+
+docker compose up -d --build
+
+echo ""
+echo "Dash is up: http://localhost:3000"
+echo "Logs: docker compose logs -f"
+echo ""
+echo "For development instead:"
+echo " npm install && npm run dev # vite on :5173"
+echo " cd apps/backend && DASH_DEV=1 go run ./cmd/dash # API on :8080"