docs: design for the documentation site
This commit is contained in:
@@ -0,0 +1,150 @@
|
||||
# Documentation site — design
|
||||
|
||||
**Date:** 2026-07-28
|
||||
**Status:** approved
|
||||
|
||||
## Problem
|
||||
|
||||
Vantage has no user-facing documentation. Everything an operator needs — how to
|
||||
install self-hosted, how to enrol an agent, what a workflow step is, how a
|
||||
licence gets issued — lives either in `CLAUDE.md` (written for contributors, not
|
||||
users) or in the code. The marketing site sells the product and the control
|
||||
plane runs it; neither explains it.
|
||||
|
||||
## Solution
|
||||
|
||||
A fourth Next-adjacent frontend, `docsite/`, built with Docusaurus v3 and shipped
|
||||
alongside the marketing site.
|
||||
|
||||
### Placement and deployment
|
||||
|
||||
- Lives at repo root as `docsite/`.
|
||||
- Served at **`docs.hostxtra.co.uk`**, deliberately outside
|
||||
`*.vantage.hostxtra.co.uk` — that namespace is per-tenant instance subdomains
|
||||
and `APP_ROOT_LABEL` resolves an org from the label before `vantage`. Same
|
||||
reasoning that puts `adminsite/` on `vantage-hq.hostxtra.co.uk`.
|
||||
- Added to **`deploy/docker-compose.site.yml` only**, published as `3005`.
|
||||
`deploy/docker-compose.yml` (the self-hosted install) must never mention it,
|
||||
exactly as it never mentions `site`, `sitesvc`, `admin` or `adminsite`.
|
||||
- Added to `.gitea/workflows/server-deploy.yml` as a seventh image, rebuilding
|
||||
on `^docsite/` only, build context `docsite/`.
|
||||
|
||||
### Runtime
|
||||
|
||||
Docusaurus emits a fully static site, so unlike `site/`, `web/` and
|
||||
`adminsite/` there is no Node server at runtime. Two stages:
|
||||
|
||||
1. `node:26-alpine` builder — `npm ci && npm run build` → `/app/build`.
|
||||
2. `nginx:alpine-slim` runner — copies `build/` to `/usr/share/nginx/html`,
|
||||
plus a small `nginx.conf` giving `try_files` a 404 fallback to Docusaurus's
|
||||
`404.html` and long cache headers on `/assets/`.
|
||||
|
||||
`nginx:alpine-slim` is roughly 12MB against `caddy:alpine`'s ~50MB, and nothing
|
||||
here needs Caddy's automatic TLS — the host proxy already terminates it.
|
||||
|
||||
Build args, baked at build time the same way `site/`'s are:
|
||||
|
||||
| Arg | Purpose |
|
||||
| --- | --- |
|
||||
| `DOCS_URL` | site `url`; defaults to `https://docs.hostxtra.co.uk` |
|
||||
| `APP_URL` | navbar link to the control plane |
|
||||
| `HQ_URL` | navbar link to the HQ portal |
|
||||
|
||||
### Theme
|
||||
|
||||
`docsite/src/css/custom.css` carries `site/app/globals.css`'s token blocks
|
||||
**copied verbatim** — same names, same values — and maps Docusaurus's `--ifm-*`
|
||||
variables onto them. Docusaurus stamps `data-theme="light|dark"` on `<html>`,
|
||||
which is the same selector `site/`'s dark block already keys on, so the built-in
|
||||
toggle works with no extra wiring. Light is the default, matching `site/` and
|
||||
`adminsite/`.
|
||||
|
||||
This makes a **fifth** copy of the token block (`site/`, `adminsite/`, `web/`
|
||||
dark-only, `shared/mail/templates/layout.html.tmpl` as literal hex, and now
|
||||
`docsite/`). Nothing enforces the match; `CLAUDE.md`'s Frontend section is
|
||||
updated to say so. No component in `docsite/` may carry a hex value.
|
||||
|
||||
Search is `@easyops-cn/docusaurus-search-local` — index built at compile time,
|
||||
served from the same origin. No Algolia account, no external host, nothing to
|
||||
key or rotate.
|
||||
|
||||
Docs-only mode: `routeBasePath: "/"`, blog disabled, no tutorial scaffolding.
|
||||
|
||||
## Content
|
||||
|
||||
Sidebar is authored explicitly in `sidebars.ts` rather than autogenerated, so
|
||||
ordering is a decision rather than a filename accident.
|
||||
|
||||
### Getting Started
|
||||
|
||||
| Page | Covers |
|
||||
| --- | --- |
|
||||
| `what-is-vantage` | The control plane, the agent, what problem each solves |
|
||||
| `cloud-vs-self-hosted` | The two deployments, what differs (licensing, HQ-managed users, reaping) |
|
||||
| `self-hosted-install` | Prereqs (Docker, external MongoDB, DNS, TLS), `docker-compose.yml`, required env, `docker compose up -d` |
|
||||
| `first-login` | `/setup` bootstrap, first org and owner |
|
||||
| `first-server` | `POST /servers/new`, the install one-liner, Linux and Windows, watching it flip to `active` |
|
||||
| `claim-free-licence` | Linking the install to an HQ account, `claim-free` |
|
||||
|
||||
`self-hosted-install` is the page the section exists for; it names every
|
||||
required environment variable with its consequence-of-omission, in particular
|
||||
`GRPC_HOST` (boot fails, no default is safe) and `KEY_ENCRYPTION_KEY`.
|
||||
|
||||
### Vantage (the application)
|
||||
|
||||
`servers` (agent install Linux/Windows, inventory, OS updates, agent
|
||||
self-update) · `ssh-keys` (upload, generate-on-server, assign, revoke, what the
|
||||
agent writes and when) · `workflows` (step library, default steps and why they
|
||||
are read-only, the designer, running, live logs, `on_failure`, `output_env`,
|
||||
workspaces, log retention) · `monitors` (the four check types, server vs agent
|
||||
runner, retries, incidents, uptime rollups) · `notification-channels` (five
|
||||
types, testing) · `secrets` (vault, `secret_refs` in steps, the ESO read path
|
||||
and its bearer token) · `browser-console` (SSH/RDP/VNC, one-time tokens) ·
|
||||
`audit-log` · `settings` (members and roles, OIDC per org, retention, ESO token,
|
||||
licence).
|
||||
|
||||
### Vantage HQ (the portal)
|
||||
|
||||
`accounts-and-signup` (account-first signup, email verification, an account is
|
||||
a team) · `people-and-roles` (owner/admin/member, invitations, accepting) ·
|
||||
`cloud-instances` (create, overview, granting members and what a grant actually
|
||||
is) · `self-hosted-instances` (purchase creates a placeholder, claim-link binds
|
||||
the real UUID, relink) · `licensing-and-entitlements` (tiers, metered server
|
||||
count, feature toggles, desired vs granted) · `billing` (Paddle as merchant of
|
||||
record, checkout, the customer portal, changing configuration) · `free-tier`
|
||||
(limits, the renewal window, reaping on cloud).
|
||||
|
||||
### Reference
|
||||
|
||||
`environment-variables` (server, sitesvc, admin, agent) · `rest-api` (the route
|
||||
tables, grouped as in `CLAUDE.md`) · `grpc-api` (the eight RPCs, the command
|
||||
stream) · `agent-config` (config.yaml, paths, permissions) ·
|
||||
`ports-and-networking` (which ports, which direction, what needs to be
|
||||
reachable) · `troubleshooting`.
|
||||
|
||||
### Operations
|
||||
|
||||
`upgrading` (pull and recreate) · `backups` (MongoDB is the durable state; Redis
|
||||
is sessions only) · `agent-updates` · `ci-cd` (which image rebuilds when, and
|
||||
the repo-variable gap that pushes no commit).
|
||||
|
||||
## Writing rules
|
||||
|
||||
- Every guide is task-shaped: numbered steps, real paths and commands taken from
|
||||
the repository, never invented UI.
|
||||
- Behaviour that is a hard refusal gets an admonition, not a paragraph: default
|
||||
steps are read-only (409 `ErrDefaultStep`), `POST /license` answers 409
|
||||
`cloud_managed` on cloud, HQ-sourced users cannot have their role changed
|
||||
locally (409 `ErrHQManaged`).
|
||||
- Where the UI enforces something, say that the API is the boundary and the UI
|
||||
is the courtesy — the same phrasing the codebase uses.
|
||||
- No screenshots in this pass. They rot faster than prose and there is no
|
||||
capture pipeline.
|
||||
|
||||
## Out of scope
|
||||
|
||||
- Versioned documentation. One version, tracking `main`. Docusaurus versioning
|
||||
can be switched on later without restructuring.
|
||||
- Internationalisation.
|
||||
- Screenshots and diagrams beyond what Mermaid renders inline.
|
||||
- A docs search backed by an external service.
|
||||
Reference in New Issue
Block a user