docs(journey): phase 7 — the installation path and administration
All checks were successful
PR checks / checks (pull_request) Successful in 9m25s
All checks were successful
PR checks / checks (pull_request) Successful in 9m25s
Twenty documentation pages: Getting started (7) and Administration (13), the journey no existing document owns end to end because the repositories are organised by component and an operator is not. Four decisions of record, taken before anything was written (D34–D37, PLAN.md §10 "How phase 7 built the documentation journey"): - D34 one PR for all twenty pages. - D35 the install page is SELF-CONTAINED: it prints a complete Compose file and a complete .env that an operator copies without visiting another repository. That is a copy of somebody else's file, so it is checked rather than trusted — scripts/checkQuickstart.mjs re-reads website main:docker-compose.yml and main:.env.example over the Gitea API and fails on any disagreement, in both directions: a value that drifts fails, and a service or variable that appears upstream fails until it is either included or recorded as deliberately omitted with a reason. Its first run found two stale entries. - D36 every Administration screen was walked on a real deployment before it was described — the rig being the quickstart itself, against the published image, so one run proved the install page and produced the detail the admin pages needed. - D37 a thirteenth Administration page, Content, so that every admin nav row has a home without organising the docs by the app's menu. What the live deployment disproved, all three now documented: - The documented Compose deploy does not boot. SECRET_ENC_KEY is required in production (utils/secretBox.js throws at require time) and is missing from website's ROOT .env.example — the file Compose reads. It is present in server/.env.example, which is why dev never hits it. The quickstart carries it, declared as an upstream omission so the check fails the day it is fixed. - The installer points operators at a screen that no longer exists: it prints <site>/admin/shard, and INSTALL.md §5 repeats it, but since the module cutover the screen is /admin/uo/link. Both the binary and the guide are stale. - The admin Restart button opens a window.confirm whose text is the honest warning that a deployment with no supervisor does not come back — which is why `restart: unless-stopped` is called out as load-bearing rather than left as boilerplate. And the defect only a look found, three phases running: the .env block's prose promised that every highlighted line must be changed, while `mark` given the variable names highlighted the names alone and left the values unmarked. Every check passed on a page that was wrong about its own highlighting. verify green: 890 internal links, 52 branch links, 19 facts, 59 quickstart checks, 0 astro-check errors. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
160
src/data/quickstart.mjs
Normal file
160
src/data/quickstart.mjs
Normal file
@@ -0,0 +1,160 @@
|
||||
/**
|
||||
* quickstart.mjs — the self-contained site deployment (D35, PLAN.md §10).
|
||||
*
|
||||
* The org lead chose a quickstart an operator can copy without leaving the page: the
|
||||
* Compose file and the environment file below are complete enough to boot a site, and
|
||||
* `/docs/getting-started/install-the-site/` renders them verbatim.
|
||||
*
|
||||
* That decision creates the artifact §1 spends its whole length warning about — a second
|
||||
* copy of somebody else's file, free to drift. `scripts/checkQuickstart.mjs` is the price
|
||||
* of it: every service, image, port, mount and variable below is re-read from `website`'s
|
||||
* own `docker-compose.yml` and `.env.example` on `main`, over the Gitea API, and any
|
||||
* disagreement fails the build. Same mechanism and same intent as `checkFacts.mjs`.
|
||||
*
|
||||
* WHAT THIS FILE IS NOT. It is not a smaller compose file that the project supports as an
|
||||
* alternative. It is the shipped one with the parts an operator does not need on day one
|
||||
* left out, and the page says so: `bot` and `ntfy` are real services, documented where
|
||||
* they are configured, and the reader is pointed at the full file for them.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Services the quickstart ships, and — for the check — what each one must still agree with
|
||||
* upstream about. `omitted` records the services deliberately left out, because a NEW
|
||||
* service appearing upstream should make someone decide, rather than pass silently.
|
||||
*/
|
||||
export const services = ['db', 'app'];
|
||||
export const omittedServices = {
|
||||
ntfy: 'Push notifications for the Android app. Nothing needs it to boot, and it wants a public URL a first install does not have yet.',
|
||||
bot: 'The Discord bot. It is configured from the admin panel once the site is up, so it is introduced on the integrations page rather than here.',
|
||||
};
|
||||
|
||||
/**
|
||||
* The Compose file, exactly as the page prints it.
|
||||
*
|
||||
* Three differences from upstream's, all deliberate and all asserted by the check:
|
||||
* - `bot` and `ntfy` are absent (above).
|
||||
* - `db` does not bind-mount `./server/db/schema.sql`. That mount is a checkout-relative
|
||||
* path, and this quickstart has no checkout; the server ensures its own schema on boot,
|
||||
* which is what actually creates the tables in every deployment.
|
||||
* - the `MODULES` comment block is reduced to one line pointing at the module page.
|
||||
*/
|
||||
export const compose = `services:
|
||||
db:
|
||||
image: mariadb:11
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
MARIADB_DATABASE: \${DB_NAME}
|
||||
MARIADB_USER: \${DB_USER}
|
||||
MARIADB_PASSWORD: \${DB_PASSWORD}
|
||||
MARIADB_ROOT_PASSWORD: \${DB_ROOT_PASSWORD}
|
||||
volumes:
|
||||
- dbdata:/var/lib/mysql
|
||||
healthcheck:
|
||||
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
|
||||
app:
|
||||
image: gitea.whitlocktech.com/runicgateway/website-app:\${IMAGE_TAG:-latest}
|
||||
restart: unless-stopped
|
||||
env_file: .env
|
||||
environment:
|
||||
DB_HOST: db
|
||||
UPLOAD_DIR: /app/uploads
|
||||
LOG_DIR: /app/logs
|
||||
MODULES_DIR: /app/modules
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
volumes:
|
||||
- uploads:/app/uploads
|
||||
- ./logs:/app/logs
|
||||
- ./brand:/app/brand:ro
|
||||
- ./modules:/app/modules
|
||||
ports:
|
||||
- "3000:3000"
|
||||
|
||||
volumes:
|
||||
dbdata:
|
||||
uploads:
|
||||
`;
|
||||
|
||||
/**
|
||||
* The environment file, as the page prints it. `fill` marks the lines an operator must
|
||||
* change before this is a real deployment — the page highlights exactly these.
|
||||
*/
|
||||
export const env = [
|
||||
{ key: 'IMAGE_TAG', value: 'latest' },
|
||||
|
||||
{ key: 'NODE_ENV', value: 'production' },
|
||||
{ key: 'PORT', value: '3000' },
|
||||
{ key: 'INTERNAL_PORT', value: '3001' },
|
||||
|
||||
{ key: 'DB_HOST', value: 'db' },
|
||||
{ key: 'DB_PORT', value: '3306' },
|
||||
{ key: 'DB_NAME', value: 'runic_gateway' },
|
||||
{ key: 'DB_USER', value: 'runic' },
|
||||
{ key: 'DB_PASSWORD', value: 'change-me-db-password', fill: true },
|
||||
{ key: 'DB_ROOT_PASSWORD', value: 'change-me-root-password', fill: true },
|
||||
|
||||
{ key: 'JWT_SECRET', value: 'change-me-to-a-long-random-string', fill: true },
|
||||
{ key: 'SECRET_ENC_KEY', value: 'change-me-to-another-long-random-string', fill: true },
|
||||
{ key: 'COOKIE_SECURE', value: 'auto' },
|
||||
{ key: 'TRUST_PROXY', value: '1' },
|
||||
|
||||
{ key: 'ADMIN_USERNAME', value: 'admin', fill: true },
|
||||
{ key: 'ADMIN_PASSWORD', value: 'change-me-before-first-boot', fill: true },
|
||||
|
||||
{ key: 'BOT_INTERNAL_KEY', value: 'change-me-to-a-third-long-random-string', fill: true },
|
||||
];
|
||||
|
||||
/**
|
||||
* `SECRET_ENC_KEY` is in this quickstart and NOT in upstream's `.env.example`, which is why
|
||||
* it needs a declaration rather than passing quietly.
|
||||
*
|
||||
* Found by booting this exact file against the published image (phase 7): the server calls
|
||||
* `resolveKey()` in `utils/secretBox.js` at require time and throws
|
||||
* `SECRET_ENC_KEY must be set in production`, so the container crash-loops before it ever
|
||||
* listens. It is documented in `server/.env.example` — the file local development copies —
|
||||
* and missing from the root `.env.example` that Compose actually reads.
|
||||
*
|
||||
* The check treats the omission as upstream's bug, not as licence: it fails the moment the
|
||||
* variable appears in `.env.example`, so this note cannot outlive the defect it describes.
|
||||
*/
|
||||
export const notInUpstreamEnvExample = {
|
||||
SECRET_ENC_KEY:
|
||||
"the app refuses to start in production without it (utils/secretBox.js), but website's root .env.example does not list it",
|
||||
};
|
||||
|
||||
/**
|
||||
* Variables upstream's `.env.example` carries that the quickstart leaves out, each with the
|
||||
* reason. The check requires this list plus the keys above to account for EVERY key in
|
||||
* `.env.example`: when website adds a variable, this repo goes red and someone decides
|
||||
* whether a first install needs it. That failure is the feature.
|
||||
*/
|
||||
export const envOmitted = {
|
||||
UPLOAD_DIR: 'set in the Compose file, where the volume that makes it meaningful is',
|
||||
LOG_LEVEL: 'logging defaults are fine until there is something to debug',
|
||||
FILE_LOG_LEVEL: 'as above',
|
||||
LOG_TO_FILE: 'as above',
|
||||
LOG_DIR: 'set in the Compose file, beside its bind mount',
|
||||
LOG_FILE: 'as above',
|
||||
BRAND_NAME: 'branding is its own admin screen and its own page',
|
||||
BRAND_SHORT_NAME: 'as above',
|
||||
BRAND_TAGLINE: 'as above',
|
||||
BRAND_DESCRIPTION: 'as above',
|
||||
BRAND_CONTACT_EMAIL: 'as above',
|
||||
BRAND_URL: 'as above',
|
||||
BRAND_ACCENT_COLOR: 'as above',
|
||||
BRAND_LOGO: 'as above',
|
||||
BRAND_HERO: 'as above',
|
||||
BRAND_FAVICON: 'as above',
|
||||
JWT_EXPIRES_IN: 'the default session length is a decision for later, not for boot',
|
||||
COOKIE_NAME: 'changing it logs everyone out; not a first-install decision',
|
||||
DEBUG_TRUST_PROXY: 'a diagnostic, and a noisy one',
|
||||
TOTP_CHALLENGE_TTL: 'the default is right',
|
||||
CLIENT_ORIGIN: 'only needed when the client is served from a different origin, which a Compose deployment does not do',
|
||||
BOT_INTERNAL_URL: 'points at the bot service, which this quickstart does not run',
|
||||
NTFY_BASE_URL: 'push notifications need the ntfy service, which this quickstart does not run',
|
||||
};
|
||||
Reference in New Issue
Block a user