diff --git a/settings-site/CLAUDE.md b/settings-site/CLAUDE.md deleted file mode 100644 index 1e85f42..0000000 --- a/settings-site/CLAUDE.md +++ /dev/null @@ -1,76 +0,0 @@ -# CLAUDE.md - -This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. - -## Scope - -This is the **settings-site** subdirectory of the broccolini-bot repo. It is a **separate Express process** that provides an admin web UI for editing the bot's runtime config. It is **not** part of the bot's Node process. - -The parent repo's rules in `/opt/broccolini-bot/CLAUDE.md` still apply here — especially **CommonJS only**, **read before write**, and **no unsolicited refactors**. Read that file alongside this one. - -## Commands - -- `npm start` — run the settings site (`node server.js`). -- `npm run dev` — run with `node --watch` for auto-reload. -- No lint, no test framework, no build step. Frontend is vanilla JS served from `public/` — no bundler. -- Deploy via its own compose file: `docker compose up --build -d` from this directory. Container name `broccolini-settings`, joins external `broccoli-net`. - -## Architecture - -### Two processes, one `.env` -The settings site is a thin HTTPS-oriented proxy in front of the bot's internal API: - -``` -browser ──► settings server.js (:SETTINGS_PORT, default 12752) - │ session auth (SETTINGS_ADMIN_PASSWORD) - ▼ - bot internalApp (broccoli-net only, INTERNAL_API_PORT, default 12753) - │ header auth (x-internal-secret = INTERNAL_API_SECRET) - ▼ - routes/internalApi.js in /opt/broccolini-bot -``` - -`server.js` loads `../.env` (the **bot's** env file) — both processes share it. `docker-compose.yml` also mounts `env_file: ../.env`, not a local one. There is no settings-site-specific env beyond what's in `.env.example`. - -### Proxied endpoints -`server.js` exposes five authenticated endpoints that forward to the bot's `/internal/*` API via `callBot()`: - -| Settings route | Bot route | -|---|---| -| `GET /api/config` | `GET /internal/config` | -| `POST /api/config` | `POST /internal/config` | -| `GET /api/discord/guild` | `GET /internal/discord/guild` | -| `POST /api/restart` | `POST /internal/restart` | -| `GET /api/restart/status` | `GET /internal/restart/status` | -| `GET /api/notifications/alerts` | `GET /internal/notifications/alerts` | -| `GET /api/notifications/state` | `GET /internal/notifications/state` | -| `POST /api/notifications/toggle` | `POST /internal/notifications/toggle` | - -Every response-shape change in the bot's `/internal/*` handlers (`routes/internalApi.js`) is a breaking change here. The bot also gates `POST /internal/config` on an `ALLOWED_CONFIG_KEYS` allowlist — **adding a new field to the UI requires adding the key to that Set in the bot first**, otherwise the save returns 400 for that key. - -### Second admin password -`server.js` accepts an optional `SETTINGS_ADMIN_PASSWORD_2`. If set, the `/login` handler grants the same session for either password; no audit distinction between them. The primary `SETTINGS_ADMIN_PASSWORD` is still required at startup — only the second is optional. Both are redacted by the bot's `GET /internal/config` response. - -### Session cookie requires HTTPS -`server.js:20-26` sets `cookie.secure: true`. Browsers will refuse to persist the session cookie over plain HTTP, so login silently fails when not behind an HTTPS reverse proxy (`SETTINGS_DOMAIN` is the deployed domain). If you're reproducing a login bug, check this first before debugging auth logic. The `session secret` falls back to `'fallback-secret-change-me'` when `INTERNAL_API_SECRET` is unset — don't rely on the fallback in any environment that matters. - -### Client-side routing -`public/js/` is split into focused modules (phase 4 refactor): `app.js` (bootstrap), `router.js`, `fields.js`, `notifications.js`, `discord.js`, `login.js`, `util.js` — no bundler, loaded via `