Bot hosting: releases are self-contained CI bundles, and the bot serves its own web UI

The image no longer installs the bot's dependencies: its CI builds one tar.gz holding the app plus a
vendor/ directory of prebuilt wheels, and PYTHONPATH=/app/vendor makes the code import them. A new
dependency therefore needs no image rebuild and the server contacts no package index.

- deployBotBundle.sh: install / --latest / --status / --rollback, verifies every file against BUILD.json
  and keeps the previous release beside the live one.
- compose: mount ${BOT_APP_DIR:-/srv/bot/app} at /app, set DB_BACKEND, DATA_DIR, WEB_ALLOWED_GROUPS,
  WEB_SERVE_UI and PYTHONPATH. bot/app placeholder untracked; install.sh creates /srv/bot/app.
- The placeholder requirements would have crashed the bot on import (no sqlglot), which is why the
  image now ships none of them.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-11-02 21:18:15 -06:00
parent 855651c5a4
commit 223458550a
14 changed files with 226 additions and 55 deletions

View File

@@ -236,21 +236,33 @@ Phase 4 is the Vanguard Metadata Jellyfin plugin; Phase 5 puts copyparty, /sync
## 5d. MariaDB + Discord bot (for the bot dev)
`mariadb` (public on 3306, host network, root local-only, 32-char generated passwords) with a database/user
for the bot, and `discord-bot`, a Python 3.12 container that runs `bot/app/main.py` and idles until that file
exists. Credentials live in `.env` (generated by `configure.py`; bot token + guild ID are asked in `--full`
for the bot, and `discord-bot`, a Python 3.12 container that runs `/app/main.py` and idles until a release is
installed. Credentials live in `.env` (generated by `configure.py`; bot token + guild ID are asked in `--full`
or the `[d]` menu item; `./configure.py --show` prints them).
The bot also serves a web UI on 127.0.0.1:8000, published as `https://bot.HOST/` behind **Authentik
forward-auth**: Caddy asks Authentik, then injects `X-Authentik-Username/-Groups/-Email`. Create the matching
Proxy Provider in Authentik (forward auth, single application, external host `https://bot.HOST`), add it to
the embedded outpost, and bind a group policy. Until then the site returns an error, never an open page.
**Releases are self-contained bundles, not loose files.** The bot repo's Gitea Actions workflow runs its tests
and then builds one tar.gz holding `main.py`, `app/`, `website/`, `BUILD.json` **and `vendor/`** — its own
dependencies, as prebuilt wheels for this image's Python. `./deployBotBundle.sh <bundle.tar.gz>` verifies it
against `BUILD.json`, swaps it into `/srv/bot/app` (bind-mounted at `/app`, previous release kept beside it)
and restarts the container. `PYTHONPATH=/app/vendor` is how the code finds its dependencies, so **a new
dependency never needs an image rebuild** and the server never contacts a package index.
./deployBotBundle.sh vanguard-bot-bundle.tar.gz # install a release (downloaded from the ci workflow)
./deployBotBundle.sh --latest # fetch the newest main build first (needs BOT_REPO_TOKEN in .env)
./deployBotBundle.sh --status # version, commit, package list, container state
./deployBotBundle.sh --rollback # back to the previous bundle
docker compose logs -f discord-bot # watch it
The bot serves **both** its API and its web pages on 127.0.0.1:8000, published as `https://bot.HOST/` behind
**Authentik forward-auth**: Caddy asks Authentik, then injects `X-Authentik-Username/-Groups/-Email`, and the
bot authorises per request from those headers (`WEB_ALLOWED_GROUPS=bot-users,admins`; `WEB_SERVE_UI=true`
turns the pages on). Create the matching Proxy Provider in Authentik (forward auth, single application,
external host `https://bot.HOST`), add it to the embedded outpost, and bind a group policy. Until then the
site returns an error, never an open page. Caddy's own gate is `BOT_REQUIRE_GROUP` (`bot-users` by default),
so **admins need the `bot-users` role too** — or set `BOT_REQUIRE_GROUP=` and let the bot's group list decide.
The build brief for whoever writes the bot is `bot/AGENT.md`; `bot/README.md` is the ops cheat-sheet.
docker compose logs -f discord-bot # watch it
docker compose restart discord-bot # after code changes
docker compose build discord-bot && docker compose up -d discord-bot # after requirements.txt changes
## 5e. Gitea + Actions runner
`gitea` (MariaDB-backed, `git.HOST` via Caddy, git-over-ssh on **2222**, registration closed) and