Telegram bot for stalls at the Karlsruhe Unifest to order supplies (change money, cups, beer, cocktail materials, helpers, ...). Includes a small live dashboard for the orga groups handling tickets.
- aiogram v3 (async Telegram bot)
- SQLModel + SQLite (single file,
create_allat startup, no migrations) - FastAPI + SSE for the dashboard (no MQTT broker)
- uv for dependency management
# 1. Install uv
curl -LsSf https://astral.sh/uv/install.sh | sh
# 2. Install dependencies
uv sync
# 3. Configure secrets
cp .env.example .env # then edit
cp config.yaml.example config.yaml # then edit for the year's structure
# 4. Run
uv run unifestbestellbotThe bot polls Telegram and serves the dashboard at http://0.0.0.0:8000.
Open http://<host>:8000/?group=Finanz (or ?group=BiMi, etc.) on a TV to
see live tickets for one orga group.
uv run pytest
uv run ruff check
uv run ty checkThe suite covers: config validation, repo CRUD + audit (including
rejected-transition immutability and the atomic WIP claim), the /register
flow, the full /request FSM end-to-end per category, all orga commands +
inline pickers and their permission gating, the notify fan-out (mute,
flood-control retry, block-then-unregister), the dashboard event bus
(including orga lifecycle publishing), Engelsystem summary rendering, and
the dashboard endpoints. Run uv run pytest for the live count.
Every commit bumps the package's patch version in pyproject.toml and
uv.lock. The hook is tracked in .githooks; enable it once after cloning:
git config core.hooksPath .githooksThe version bump also runs for empty commits, amend, merge, and revert. As with
all pre-commit hooks, git commit --no-verify bypasses it. The hook aborts if
pyproject.toml or uv.lock contains unstaged edits, so it cannot silently
include those edits in the commit.
docs/REWRITE_PLAN.md— the architecture and why each decision was madedocs/IMPLEMENTATION.md— detailed module layout, schemas, and code sketchesdocs/OPERATIONS.md— deploy, backup, restore, common fixesdocs/MIGRATION.md— observable behaviour and config differences vs. the legacy bot