Универсальный Discord-бот для проектов Space Station 14: руководство проекта выдаёт волонтёрам баллы, волонтёры тратят их в магазине на временные донат-роли. Бот сам выдаёт роль на N дней и сам её снимает, когда срок истечёт.
Раньше бот назывался fish-bot. Название сменилось на Spesobot (
spesos- единица из эсперантского проекта международной валюты начала 20 века)
📖 Если вы участник команды (куратор, ревизор, админ, волонтёр) и просто хотите понять как пользоваться ботом - смотрите docs/TEAM_GUIDE.md. Этот README - для тех, кто разворачивает бот на сервере.
Бот мульти-серверный: один процесс обслуживает любое число Discord-серверов.
Каждый сервер настраивается прямо из Discord через /setup (есть готовый
пресет «Рыбья Станция» и режим ручной настройки, а в будущем будут пресеты для каждого проекта SunRise Network) Каждый сервер делится на
департаменты (Модерация, Медиа и т.п.) - у волонтёра отдельный баланс в
каждом, и магазин у каждого свой. Баллы Модерации нельзя потратить в магазине
Медиа - это исключает приколы вида «накопил в одном отделе, а купил по дешёвке
в другом».
- Per-department currency. Каждый сервер делится на департаменты (Модерация, Медиа, Караульные, …). У волонтёра - отдельный баланс в каждом, и баллы Модерации можно потратить только в магазине Модерации.
- Slash-команды для всех действий - без префиксов, без чатовых команд.
- Мастер
/setupс дропдауном пресетов или ручной настройкой черезRoleSelect/ChannelSelect- никаких ID руками. Пресет может заранее объявить список департаментов, и/setupсоздаст их одним кликом. - Выдача баллов с обязательной причиной (модалка), всё в канал-лог.
- Магазин конфигурируется на лету и per-department (
/shop_set department:<…>). - Автоматическое снятие роли по истечении срока + лог в канал.
- Покупка той же роли продлевает существующий срок, а не сбрасывает его.
- SQLite (один файл, бэкап =
cp). - Полная история транзакций (с фильтром по департаменту) и leaderboard каждого департамента.
| Команда | Кто может | Что делает |
|---|---|---|
/give <user> <amount> <department> |
Куратор этого департамента | Открывает модалку с причиной и выдаёт баллы департамента. |
/take <user> <amount> <reason> <department> |
Админы | Списывает баллы из департамента. |
/balance [user] |
Все (свой), админы (чужой) | Балансы по всем департаментам сервера. |
/history [user] [department] [limit] |
Все (свою), админы (чужую) | Последние транзакции (опц. фильтр). |
/leaderboard <department> [limit] |
Все | Топ по баллам конкретного департамента. |
/shop [department] |
Все | Список товаров (опц. фильтр по департаменту). |
/buy <role> |
Все | Покупка роли — списывает баллы её департамента. |
/inventory [user] |
Все (свой), админы (чужой) | Активные купленные роли и срок. |
/department_view |
Админы | Все департаменты сервера и их роли. |
/department_create <name> |
Админы | Создать новый департамент. |
/department_remove <name> |
Админы | Удалить департамент (с балансами и магазином). |
/department_curators <name> <roles> |
Админы | Назначить кураторские роли департамента. |
/department_donator <name> <roles> |
Админы | Привязать донат-роли к департаменту. |
/shop_set <department> <role> <price> <duration_days> [description] |
Админы | Добавить/обновить роль в магазине департамента. |
/shop_remove <role> |
Админы | Убрать роль из магазина. |
/shop_view |
Админы | Сырая выкладка магазина с role_id. |
/admin_grant <user> <delta> <reason> <department> |
Админы | Корректировка баланса (любой знак) в департаменте. |
/awarn <user> <department> <warn_type> <reason> [quantity] |
Админ / ревизор / куратор департамента | Выдать административный варн (вес: обычный 1.0, замечание 0.5, устный 0.25, устный без веса 0.0). |
/unawarn <user> <department> <warn_type> <reason> [quantity] |
Админ / ревизор / куратор департамента | Снять варн (списывается из общего веса). |
/get_awarns [user] [department] |
Все | Текущий вес варнов и история. |
/set_awarns <user> <department> <amount> [reason] |
Админы | Установить вес варнов напрямую. |
/setup |
Владелец / «Manage Server» | Мастер настройки сервера (пресет или вручную). |
/setup_status |
Все | Показать текущую настройку этого сервера. |
/setup_auditors <roles> |
Админы | Назначить роли ревизоров (могут варнить любой департамент). |
/setup_public_warn_channel [channel] |
Админы | Публичный канал для всех варнов сервера (виден всем). |
/setup_reset |
Только владелец сервера | Сбросить настройки этого сервера. |
/ping |
Все | Проверка работоспособности (latency Discord ↔ бот). |
- Создайте приложение и бота в Discord Developer Portal.
- В разделе Bot включите Server Members Intent.
- Скопируйте токен - он пойдёт в
.env.
- На странице OAuth2 - URL Generator выберите scope
botиapplications.commands, права бота:Manage Roles,Send Messages,Read Message History,View Channels. - Добавьте бота на сервер по сгенерированной ссылке.
- Иерархия ролей. Поднимите роль бота выше всех донат-ролей, которыми он будет управлять, иначе Discord не даст их выдавать.
- На сервере выполните
/setup:- Если у этого сервера есть готовый пресет (например, «Рыбья Станция») - выберите его в дропдауне; всё применится одним кликом.
- Иначе выберите «Свой (вручную)» и через
RoleSelect/ChannelSelectукажите канал-лог, кураторские/админские/донат-роли.
- После
/setupадмин настраивает магазин:/shop_set role:<...> price:<...> duration_days:<...>.
Для проверки текущей конфигурации используйте /setup_status.
Для полного сброса - /setup_reset (только владелец сервера).
В .env нужны только глобальные настройки бота - всё остальное живёт в БД.
DISCORD_TOKEN=...
DATABASE_PATH=data/spesobot.db
EXPIRY_CHECK_INTERVAL=60Переменные GUILD_ID, LOG_CHANNEL_ID, *_ROLE_IDS в .env.example помечены
«легаси» - они нужны только при апгрейде с предыдущей single-guild версии,
чтобы автоматически перенести существующую конфигурацию в новую схему.
После первого запуска и /setup их можно удалить.
Готовые пресеты лежат в presets/*.json и привязаны к конкретному
guild_id. Когда админ запускает /setup на сервере, бот показывает в
дропдауне те пресеты, чей guild_id совпадает с текущим сервером.
Чтобы добавить пресет для нового SS14-проекта — создайте новый JSON-файл по
образцу presets/fish_station.json и откройте PR.
git clone https://github.com/Perl404/fish-bot.git spesobot
cd spesobot
cp .env.example .env # отредактируйте
docker compose up -d --build
docker compose logs -fБаза лежит в ./data/spesobot.db и переживёт пересборку контейнера.
sudo useradd -r -s /usr/sbin/nologin spesobot
sudo mkdir -p /opt/spesobot && sudo chown spesobot:spesobot /opt/spesobot
sudo -u spesobot git clone https://github.com/Perl404/fish-bot.git /opt/spesobot
cd /opt/spesobot
sudo -u spesobot python3 -m venv .venv
sudo -u spesobot .venv/bin/pip install --upgrade pip
sudo -u spesobot .venv/bin/pip install .
sudo -u spesobot cp .env.example .env
sudo -u spesobot $EDITOR .env
sudo -u spesobot mkdir -p data
sudo cp deploy/spesobot.service /etc/systemd/system/spesobot.service
sudo systemctl daemon-reload
sudo systemctl enable --now spesobot
sudo journalctl -u spesobot -fpython3 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
cp .env.example .env # заполнить токен и т.д.
spesobotПосле /setup (с пресетом или вручную) - настройте каждый департамент:
/department_curators name:Модерация roles:@Mod1 @Mod2
/department_donator name:Модерация roles:@Донат-неделя @Донат-месяц
/shop_set department:Модерация role:@Донат-неделя price:100 duration_days:7
/shop_set department:Модерация role:@Донат-месяц price:300 duration_days:30
Если пресет не объявил департаменты - создайте их сами:
/department_create name:Модерация
/department_create name:Медиа
…
Донат-роли whitelist'a (заданные в /setup) - это единственные роли, которые
/shop_set разрешает выставить в магазин. Если whitelist пуст - допускается
любая роль (на свой страх и риск).
# Простой бэкап (бот может писать в этот момент — WAL-режим разруливает):
cp data/spesobot.db backups/spesobot-$(date +%F).dbDocker:
cd /opt/spesobot
docker compose down
git pull
docker compose up -d --buildЕсли бэкап нужен на всякий случай: cp data/spesobot.db data/spesobot.db.v2-backup
до апгрейда.
pip install -e ".[dev]"
ruff check .
ruff format --check .
pytest -vCI на GitHub Actions запускает то же самое на каждый PR и push в main.
MIT.