Files
serverAppConfigs/docs/Infrastructure/Homepage.md
T
Frank cc1f421d27 Homepage: record the completed build in the KB
- Homepage.md: status is now 'built, pending deploy' (all assets + checker +
  deploy are in the repo, 112 tests green). To go live: add CADDY_ADMIN_HASH
  to the target .env, then deploy.sh.
- Homepage Design Grilling.md: the build is complete (all 6 slices, full TDD);
  the only remaining step is the operator adding the admin hash + deploying.
- pi log.md: build-complete entry.
2026-08-23 13:06:58 -07:00

168 lines
7.9 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.
# 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-23: built, pending deploy
The homepage is built and tested (112 tests pass). The assets are in `shared/homepage/` (the pages, the theme, the toggle, `services.json`), the checker is in `scripts/` (`homepage-status.py` + the timer + service), and `deploy.sh` ships it. The render logic is verified with a Node DOM shim.
It is not yet deployed to `/srv/homepage/` on the target. To go live, the operator adds `CADDY_ADMIN_HASH` (the operator-only password, `caddy hash-password`) to the target `.env`, then runs `./scripts/deploy.sh dankclaw`. Until then the admin hash stays a placeholder and the `/admin/` page auth is not live.
## 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 deferred (Q6).
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 two pages. The root page lists the user services. The `/admin/` page lists the admin and infrastructure services. The optional `/how/` page is deferred (Q6).
```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/>(deferred)"]
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. The probe method is per service (`tcp` or `http`). The timeout is 5 s. The page reads `status.json` once on load. It does not auto-refresh.
```mermaid
flowchart TD
A[timer fires] --> B[read service config]
B --> C{for each service}
C -->|wip| D[mark WIP]
C -->|probe| E[probe: tcp or http]
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 # deferred (Q6)
├── style.css # full theme; a toggle strips to bare HTML
├── app.js # loads status.json once, renders the panels
├── 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.
## Rendering
The page renders a **grid of TUI-style panels** — one panel per service. Each panel shows the state badge, the name, the description, and the `Open` and `Docs` links. A summary line at the top counts the states. The footer shows the last master deployment datetime (Q43).
The page reads `status.json` **once on load**. It does not auto-refresh (Q41).
Styling is **toggleable** (Q27). The default is the full terminal theme. A toggle strips the page to bare, unstyled HTML (motherfuckingwebsite.com style). The page does not alter the user's cursor (Q28).
## 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": "/docs/searxng/",
"probe": "127.0.0.1:8081",
"method": "http",
"wip": false,
"showLink": true
}
```
- `category` — `user` or `admin`. Selects the page.
- `url` — the "Open" link (the Caddy site).
- `docs` — the per-service docs page (`/docs/<svc>/`).
- `probe` — the backend `host:port` the checker probes.
- `method` — `tcp` or `http`. The probe type for this service (Q10).
- `wip` — when true, the badge shows WIP and the checker skips the probe.
- `showLink` — when false, the panel shows status only (no "Open" link).
## Deployment and testing
The deploy is **git-driven**. Master always reflects the currently deployed state (Q33). `deploy.sh` copies the assets to `/srv/homepage/`, installs the checker timer, renders the Caddyfile (both hashes), and reloads Caddy. It stamps the deployment datetime the footer shows (Q43).
The build is **full TDD** (Q36–Q38). Tests exist before the code: the checker (a fake up port, a down port, a WIP service, and the JSON schema), the pages and config (the `services.json` schema, `caddy validate`, the `status.json` reference), and the security check (two distinct basicauth hashes).
## Per-service docs (separate workstream)
Each service gets a docs page at `/docs/<svc>/` (Q30). The content is a **how-to for a regular user** — no maintenance details (Q29). The pages are password-protected by the same auth as the homepage section they belong to (Q31). They are built as each service goes active (Q32). The `docs` link on a service points to its page. The existing reference docs in `docs/` are not linked from the homepage. They may contain secrets (Q22).
## See Also
- [[Homepage Design Grilling]] — the decision log
- [[Caddy]] — the proxy that serves it
- [[Dankclaw Stack]], [[Dankserver Stack]] — the services it lists