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>
58 lines
3.7 KiB
Markdown
58 lines
3.7 KiB
Markdown
# discord-bot — for the bot dev
|
|
|
|
Start with **AGENT.md** in this folder: the stack, the rules, the layout, the web-UI auth contract.
|
|
|
|
## How code reaches the server
|
|
|
|
Your repo's Gitea Actions workflow builds a **release bundle**: one tar.gz holding `main.py`, `app/`,
|
|
`website/`, `version.json`, `BUILD.json` and `vendor/` (your dependencies as prebuilt wheels). The admin
|
|
installs it with `./deployBotBundle.sh <bundle.tar.gz>` from the stack root; it lands in `/srv/bot/app`,
|
|
which is bind-mounted into the container at `/app`, and the previous release is kept for `--rollback`.
|
|
|
|
The image contains **no** bot dependencies: the container imports yours from `/app/vendor`
|
|
(`PYTHONPATH=/app/vendor`). Adding a dependency means editing `app/requirements.txt` and pushing — no image
|
|
rebuild, no package index on the server. The image only changes if you need a new system package (ffmpeg and
|
|
curl are already there); ask the admin for that.
|
|
|
|
## Day to day (on the server, in ~/vanguard-stream)
|
|
./deployBotBundle.sh vanguard-bot-bundle.tar.gz # install a release
|
|
./deployBotBundle.sh --status # what is installed; container state
|
|
./deployBotBundle.sh --rollback # previous release
|
|
docker compose logs -f discord-bot # live log
|
|
docker compose restart discord-bot # restart without changing code
|
|
docker compose exec discord-bot python # a REPL inside the container (your vendor/ is on sys.path)
|
|
|
|
## Environment the container gives you
|
|
| var | value |
|
|
|-----|-------|
|
|
| `DISCORD_BOT_TOKEN` | from `.env` (stack root) — the Bot added to the existing Authentik Discord application |
|
|
| `DISCORD_GUILD_ID` | the server |
|
|
| `DB_BACKEND` | `mariadb` |
|
|
| `DB_HOST` / `DB_PORT` | `host.docker.internal` / `3306` (MariaDB runs on the host network) |
|
|
| `DB_NAME` / `DB_USER` / `DB_PASSWORD` | your own database + user (`vanguardbot` / `bot` / generated) |
|
|
| `DATA_DIR` | `/data` — persistent, owned by you |
|
|
| `MEDIA_CLIPS` | `/media/clips` — rw mount of `/srv/media/clips` (folder per user, for clip submissions) |
|
|
| `WEB_HOST` / `WEB_PORT` | `0.0.0.0` / `8000` — published as `https://bot.<domain>/` via Caddy + Authentik |
|
|
| `WEB_PUBLIC_URL` | `https://bot.<domain>` for absolute links |
|
|
| `WEB_SERVE_UI` | `true` — serve your pages at `/` on the same port as `/api` |
|
|
| `WEB_ALLOWED_GROUPS` | `bot-users,admins` — the groups your own code must accept |
|
|
| `AUTH_HEADER_USER` / `_GROUPS` / `_EMAIL` | `X-Authentik-Username` / `X-Authentik-Groups` / `X-Authentik-Email` — identity injected by Caddy, trust these, implement no login |
|
|
| `PYTHONPATH` | `/app/vendor` |
|
|
| `TZ` | America/New_York |
|
|
|
|
SQLAlchemy URL: `mysql+pymysql://{DB_USER}:{DB_PASSWORD}@{DB_HOST}:{DB_PORT}/{DB_NAME}`
|
|
async: `mysql+aiomysql://...`
|
|
|
|
## Database from your own machine
|
|
MariaDB is reachable directly: `media.dumpstervigilantes.rip:3306`, user `bot`, database `vanguardbot`,
|
|
password from the admin (`./configure.py --show` on the server). Root is local-only. New connections are
|
|
rate limited at the firewall; if yours get dropped, ask the admin to add your IP to `db_allow`.
|
|
|
|
## Conventions
|
|
- Run as uid 1000 (files you write under `/media/clips` are owned like everything else there).
|
|
- `/app` holds a released bundle; treat it as read-only and write to `/data` instead.
|
|
- If you write clips: `/media/clips/<discord-username>/<name>.mp4` plus `<name>.json` with
|
|
`{"timestamp": "<UTC ISO-8601>", "source": "medal", "source_url": "...", "uploader": "...", "title": "..."}`
|
|
— the Jellyfin plugin reads that sidecar for the exact recording time.
|
|
- Log to stdout; the container captures it. One event per line, `key=value`, keeps it searchable (`LOGGING.md`).
|