- Homepage.md: rewritten to the settled design (single site, user + /admin/ pages, server-side status.json via a 3-min systemd-timer checker, terminal TUI theme). Added mermaid diagrams: site structure, status states, checker flow. Recorded the classification (user vs admin; *arr excluded; LLM admin; backends status-only) and the documented future shift to client-side probing. - Homepage Design Grilling.md (new): the decision log — settled Q1-Q5 plus 38 open questions (Q6-Q43) across 10 categories, each with a recommendation. - docs/index.md: link the grilling page (satisfies the index-links-every-page test). - report/homepage-grilling-2026-08-22.html: self-contained terminal-TUI progress report (settled decisions, verified stack baseline, overnight processing, work threads, the open questions, and how to continue). Baseline recorded: Dankclaw fully up (10/10); the Dankserver media stack is down (only Calibre-Web + the LLM are up; no .env on the target) — a separate thread. No homepage code built yet; the design is pending the operator's answers to Q6-Q43.
148 lines
5.9 KiB
Markdown
148 lines
5.9 KiB
Markdown
# Homepage
|
|
|
|
A password-protected web site on Dankclaw lists the services that are up, with a short description of each and a link to both the service and its usage documentation.
|
|
|
|
**Served by:** Caddy, `file_server` + `basicauth` — **Docs:** this page
|
|
|
|
## Status — 2026-08-22: work in progress
|
|
|
|
The homepage is not finished. The static assets exist in `shared/homepage/`. They are not yet copied to `/srv/homepage/` on the target. Caddy serves the `basicauth` challenge (HTTP 401) and the `:80` redirect (HTTP 302). The page content is absent.
|
|
|
|
Do not treat the missing page as an outage. The Caddy site block and the redirect are live. Only the content and the deploy step remain.
|
|
|
|
## Design decision — 2026-08-22
|
|
|
|
The live up/down check runs server-side. A checker on Dankclaw probes each backend and writes a same-origin `status.json`. The page fetches only that file and renders the badges. The browser never calls a backend directly. The checker runs as a systemd timer every 3 minutes.
|
|
|
|
The site has two pages. The root lists user-facing services only, with no host labels. An `/admin/` subpage lists the admin and infrastructure services behind a separate password for the operator. Gitea is a user service. Hermes is an admin service. A "how it is built" page for visitors is optional and undecided.
|
|
|
|
The client-side probe design is blocked in this topology. The page origin is `https://dankclaw.franksdank.cloud`. The service URLs are `http://<name>.franksdank.cloud`. That is cross-origin, mixed content, and auth-gated (HTTP 401). All three fail a browser `fetch`.
|
|
|
|
Intended direction: move to client-side probing. Serve every service as a same-origin `https` path under `dankclaw.franksdank.cloud`. Add a health endpoint and CORS headers to each backend. Then the page probes each service directly. Keep this note until that shift is complete.
|
|
|
|
## Structure
|
|
|
|
The site has three pages. The root page lists the user services. The `/admin/` page lists the admin and infrastructure services. The `/how/` page (optional) shows the architecture to visitors.
|
|
|
|
```mermaid
|
|
graph TD
|
|
subgraph site["dankclaw.franksdank.cloud (Caddy)"]
|
|
ROOT["/ user services<br/>(shared password)"]
|
|
ADMIN["/admin/ admin services<br/>(operator password)"]
|
|
HOW["/how/ how it is built<br/>(optional)"]
|
|
STATUS["/status.json"]
|
|
end
|
|
TIMER["systemd timer<br/>every 3 minutes"]
|
|
CHECKER["checker script<br/>probes each backend"]
|
|
BACKENDS["backends on both hosts"]
|
|
TIMER --> CHECKER
|
|
CHECKER -->|writes| STATUS
|
|
STATUS -->|polled| ROOT
|
|
STATUS -->|polled| ADMIN
|
|
CHECKER -->|probes| BACKENDS
|
|
```
|
|
|
|
## Status model
|
|
|
|
Each service shows one of three states.
|
|
|
|
```mermaid
|
|
stateDiagram-v2
|
|
[*] --> Up
|
|
[*] --> Down
|
|
[*] --> WIP
|
|
Up --> Down: probe fails
|
|
Down --> Up: probe succeeds
|
|
WIP --> Up: work completes
|
|
```
|
|
|
|
- **Up** — the probe reached the backend.
|
|
- **Down** — the probe failed (connection refused or timeout).
|
|
- **WIP** — a static override. The service is intentionally not finished. The checker does not probe it.
|
|
|
|
## Checker
|
|
|
|
The checker runs on Dankclaw as a systemd timer. Every run probes each backend directly, then writes `status.json`. It probes the backend `host:port`, not the Caddy site. A Caddy `502` or `401` cannot tell up from down.
|
|
|
|
```mermaid
|
|
flowchart TD
|
|
A[timer fires] --> B[read service config]
|
|
B --> C{for each service}
|
|
C -->|wip| D[mark WIP]
|
|
C -->|probe| E[TCP connect to host:port]
|
|
E -->|connected| F[mark Up]
|
|
E -->|refused / timeout| G[mark Down]
|
|
D --> H[write status.json]
|
|
F --> H
|
|
G --> H
|
|
```
|
|
|
|
## Service classification
|
|
|
|
**User services** (root page): SearXNG, ComfyUI, OpenWebUI, Gitea, Calibre-Web, RomM, Copyparty, Plex, Jellyfin.
|
|
|
|
**Admin services** (`/admin/`): Hermes, Grafana, Prometheus, Loki, Caddy, dnsmasq, Gluetun, the LLM fleet, and the low-level backends (mariadb, redis, Postgres, node-exporter, alloy). The backends show status only. They get a link only where a UI is meaningful.
|
|
|
|
**Excluded for now:** the *arr stack (Radarr, Sonarr, Lidarr, Readarr, Prowlarr, qBittorrent). It is not started. It is a separate effort, possibly on a different host.
|
|
|
|
## Layout
|
|
|
|
```
|
|
shared/homepage/
|
|
├── index.html # root page (user services)
|
|
├── admin.html # admin + infrastructure services
|
|
├── how.html # optional architecture page
|
|
├── style.css # terminal TUI theme
|
|
├── app.js # loads status.json, renders the badges
|
|
├── services.json # service config (user + admin)
|
|
└── fonts/ # Terminus (woff2) for @font-face
|
|
```
|
|
|
|
`status.json` is generated at runtime in `/srv/homepage/`. It is not committed.
|
|
|
|
## Auth
|
|
|
|
Caddy wraps the site with HTTP basic auth. The root page uses the shared password. The `/admin/` page uses a second, operator-only password. The hashes come from the host `.env` (git-ignored). Do not commit the hash or the password.
|
|
|
|
```
|
|
dankclaw.franksdank.cloud {
|
|
@admin path /admin/*
|
|
basicauth {
|
|
dank {env.CADDY_BASICAUTH_HASH}
|
|
}
|
|
basicauth @admin {
|
|
frank {env.CADDY_ADMIN_HASH}
|
|
}
|
|
root * /srv/homepage
|
|
file_server
|
|
}
|
|
```
|
|
|
|
## Service entry format
|
|
|
|
```json
|
|
{
|
|
"name": "SearXNG",
|
|
"category": "user",
|
|
"description": "Privacy-respecting metasearch engine.",
|
|
"url": "http://search.franksdank.cloud",
|
|
"docs": "/usage/searxng/",
|
|
"probe": "127.0.0.1:8081",
|
|
"wip": false,
|
|
"showLink": true
|
|
}
|
|
```
|
|
|
|
- `category` — `user` or `admin`. Selects the page.
|
|
- `url` — the "Open" link (the Caddy site).
|
|
- `docs` — the per-service usage page.
|
|
- `probe` — the backend `host:port` the checker probes.
|
|
- `wip` — when true, the badge shows WIP and the checker skips the probe.
|
|
- `showLink` — when false, the card shows status only (no "Open" link).
|
|
|
|
## See Also
|
|
|
|
- [[Homepage Design Grilling]] — the decision log and open questions
|
|
- [[Caddy]] — the proxy that serves it
|
|
- [[Dankclaw Stack]], [[Dankserver Stack]] — the services it lists
|