# Homepage Design Grilling The decision log for the homepage design. It records what is settled and the open questions that remain. Answer the open questions in the morning report; the design is built only after they are settled. ## Decided | # | Decision | Value | |---|----------|-------| | Q1 | How the page learns up/down | **Server-side** checker writes `status.json`; the page reads only that file. (Eventual target: client-side probing.) | | Q2 | How the checker runs | **systemd timer**, rewrites `status.json` every **3 minutes**. | | Q3 | Page model | **Single site** on Dankclaw. Root = user services (no host labels). `/admin/` = admin services, separate password. Optional `/how/` tourist page. | | Q4 | (superseded by Q3 restructure) | — | | Q5 | Service split | User: SearXNG, ComfyUI, OpenWebUI, Gitea, Calibre-Web, RomM, Copyparty, Plex, Jellyfin. Admin: Hermes, Grafana, Prometheus, Loki, Caddy, dnsmasq, Gluetun, LLM fleet, low-level backends (status-only). The *arr stack is **excluded** (separate effort, not started). | Styling is settled in principle: terminal TUI, Terminus (monospace fallback), green-on-black, 1995 phosphor palette (green `#33ff66`, red `#ff5555`, amber `#ffcc33`, cyan `#33ccff`, bg `#050805`). ## Open questions Each question carries a recommendation. Answer them in the morning report. ### A. Architecture and structure **Q6 — The optional `/how/` "tourist" page: build now or defer?** Recommendation: **defer** to a later effort. When built, make it **public** (no auth) so a visitor can see the architecture. It can render the mermaid diagrams from this repo. **Q7 — One `status.json` or two (`user-status.json` + `admin-status.json`)?** Recommendation: **one** `status.json`. Each service carries a `category` field. Each page filters client-side. One file, one checker output, one source of truth. **Q8 — One `services.json` or split by page?** Recommendation: **one** `services.json` with all services and a `category` field. The checker reads one file. Simpler to maintain. ### B. The checker **Q9 — What language for the checker script?** Recommendation: **python3** (available on Dankclaw, no dependencies, emits valid JSON cleanly). A bash + `nc` variant works too, but JSON by hand is error-prone. **Q10 — Probe method: TCP connect or HTTP GET?** Recommendation: **TCP connect** to `host:port`. Uniform, works for non-HTTP backends, and "port listening = up" matches the verified ground truth. **Q11 — Probe timeout per service?** Recommendation: **3 seconds**. A dead port refuses fast; a black-holed one times out at 3 s. With ~25 services the worst-case run is well under the 3-minute interval. **Q12 — LLM "loading" state (health returns 503 during model load)?** Recommendation: keep **three** states. A listening port shows **Up**. Optionally probe `/health` and treat 503 as Up (the process is alive). A dedicated "loading" state is a later refinement. **Q13 — Where does the checker live in the repo?** Recommendation: `scripts/homepage-status.py` plus `scripts/homepage-status.service` and `scripts/homepage-status.timer`, all tracked in git like the other units. **Q14 — How does the checker reach the Dankserver backends?** Recommendation: the `probe` field carries a full `host:port`. Dankclaw services use `127.0.0.1:PORT`. Dankserver services use `192.168.0.235:PORT`. The checker (on Dankclaw) connects to each over the LAN. Verified reachable. ### C. The status model **Q15 — How is a service marked WIP?** Recommendation: a static `"wip": true` field. The checker skips the probe and the page shows WIP. Drop the old self-referential "Homepage" entry (a page does not list itself). **Q16 — Staleness: what if the timer fails and `status.json` is old?** Recommendation: write a `generated_at` timestamp into `status.json`. The page shows a "status may be stale" warning when it is older than 10 minutes. **Q17 — Atomic writes?** Recommendation: the checker writes to a temp file, then renames over `status.json`. A crash never leaves a half-written file. The last good status survives. ### D. Auth **Q18 — The admin password: a second `.env` variable?** Recommendation: yes. `CADDY_ADMIN_HASH` in the host `.env` (git-ignored), rendered into the Caddyfile at deploy, operator-only. The root page keeps `CADDY_BASICAUTH_HASH`. **Q19 — Per-path basicauth in Caddy v2?** Recommendation: a `@admin path /admin/*` matcher with a second `basicauth @admin` block. Confirm the exact syntax against the Caddy docs during implementation. ### E. The pages and content **Q20 — Where do the one-line descriptions come from?** Recommendation: hand-written one-liners in `services.json`, drafted from the existing reference docs. **Q21 — The "Open" link target: the Caddy site or the direct backend?** Recommendation: the **Caddy site** URL (what a user actually opens). Status-only backends set `showLink: false` (no Open link). **Q22 — The "docs" link: usage page or the existing reference doc?** Recommendation: link to the **existing** reference doc (`docs/.../X.md`) as a placeholder. Swap to the per-service usage page when that workstream is built. **Q23 — Page layout: cards or a terminal-style list?** Recommendation: a **terminal-style list** (one service per line, like `systemctl list-units`). Columns: `STATUS | NAME | description | (open) (docs)`. Fits the TUI aesthetic better than cards. **Q24 — A summary line at the top?** Recommendation: yes. One line, e.g. `UP 9 DOWN 2 WIP 1`, per page. ### F. Styling **Q25 — Terminus: bundle the font or use a fallback?** Recommendation: **bundle** Terminus (woff2) via `@font-face`, with a monospace fallback stack. Confirm the license (Terminus is freely distributable) and drop the files in `fonts/`. **Q26 — Confirm the palette?** Recommendation: as proposed (green `#33ff66`, red `#ff5555`, amber `#ffcc33`, cyan `#33ccff`, bg `#050805`). Tune for contrast and readability. **Q27 — CRT effects (scanlines + glow)?** Recommendation: subtle scanlines + a soft green `text-shadow`. Make it toggleable (a `?crt=0` param) for those who find it much. **Q28 — Blinking cursor / animation?** Recommendation: a subtle CSS-only blinking block cursor on the header. Respect `prefers-reduced-motion`. ### G. The usage-docs workstream **Q29 — Scope of the per-service usage pages?** Recommendation: concise **how-to** guides (what it is, how to open it, the common tasks). Distinct from the deep reference docs in `docs/`. **Q30 — Where do the usage pages live?** Recommendation: served from the homepage site, same origin, at `/usage//`. Source in the repo under `shared/homepage/usage//`. Same origin keeps the "docs" link working. **Q31 — Are the usage pages password-protected?** Recommendation: yes. User usage pages behind the shared password, admin usage pages behind the operator password. Consistent with the pages they extend. **Q32 — Is the usage-docs workstream a separate effort?** Recommendation: yes, after the core homepage is live. For now the "docs" link points to the existing reference doc (Q22). ### H. Deployment and operations **Q33 — How is the homepage deployed?** Recommendation: extend `deploy.sh` (Dankclaw path): copy `shared/homepage/` to `/srv/homepage/`, install the timer + service, render the Caddyfile (both hashes), reload Caddy. **Q34 — Who creates `/srv/homepage/`?** Recommendation: `deploy.sh` creates it and copies the assets. The checker writes `status.json` there at runtime. **Q35 — Is the timer enabled at boot?** Recommendation: yes. A systemd timer + service, enabled, so it survives reboots and runs every 3 minutes. ### I. Testing **Q36 — Tests for the checker?** Recommendation: yes. A bats test runs the checker against a fake up port, a fake down port, and a WIP service, then validates the `status.json` schema. TDD, per repo rules. **Q37 — Tests for the pages and config?** Recommendation: yes. Validate the `services.json` schema (required fields, valid categories), run `caddy validate` on the Caddyfile, and check the pages reference `status.json`. **Q38 — A security test for the two passwords?** Recommendation: yes. Assert the Caddyfile carries two distinct basicauth hashes (root vs `/admin/`). ### J. Edge cases and robustness **Q39 — A backend moves hosts (e.g. the *arr stack to a new box)?** Recommendation: no code change. The `probe` field is a full `host:port`. A move is a config edit. **Q40 — A slow LAN hop to a Dankserver backend?** Recommendation: the 3 s timeout handles it. A slow-but-alive backend connects (Up); a dead one times out (Down). **Q41 — Client-side auto-refresh?** Recommendation: the page polls `status.json` every **60 s** (the file updates every 3 min; 60 s is responsive without hammering). **Q42 — Mobile responsiveness?** Recommendation: yes. Stack the columns and shrink the font on narrow screens. **Q43 — A "last checked" timestamp on the page?** Recommendation: yes. The footer shows `last checked HH:MM:SS` from `generated_at`. ## How to continue Answer the open questions (Q6–Q43) in the morning report. Group the answers by category. Once settled, the build order is: ```mermaid flowchart LR A[settle Q6-Q43] --> B[write services.json + checker] B --> C[write the pages + theme] C --> D[extend deploy.sh + Caddyfile] D --> E[tests green] E --> F[deploy to Dankclaw] F --> G[verify in browser] ```