Skip to content

Стандарт создания Telegram‑ботов

Этот документ описывает, как строить Telegram‑боты в рамках экосистемы DETai с учётом философии мозаичного подхода. (см. Мозаический подход)

Info

Мозаичный подход в контексте ботов означает, что бот должен состоять из независимых, легко заменяемых модулей и придерживаться чётких правил организации.

Базовые принципы мозаики — независимость, инкрементальность, гибкость и гармония: каждый этап должен разрабатываться изолированно, новые этапы добавляются без нарушения работы остальных, любой модуль можно заменить без переписывания всей системы, а итоговая конструкция собирается как мозаика из проверенных компонентов.
Эти же принципы лежат в основе стандарта для Telegram‑ботов.

Мозаичный подход, адаптированный для Telegram‑ботов

Независимость модулей

  • Один бот — один каталог. Для каждого бота создаётся собственная папка. Внутри лежат его исходники (bot.py, routers/, states/, services/, keyboards/ и т. д.), конфигурация и документация. Это соответствует принципу независимости: бот можно развернуть, обновить или удалить, не затронув другие сервисы.

  • Изоляция компонентов. Каждый логический блок (роутер, FSM‑группа, клавиатура, сервис) находится в отдельном модуле. Это позволяет разрабатывать и тестировать их независимо, как отдельные «плитки» мозаики.

Инкрементальность

  • Пошаговое наращивание функциональности. Новые ветки роутера, состояния FSM, сервисы и клавиатуры добавляются постепенно. Благодаря независимости модулей новое поведение не ломает уже работающие части.

Гибкость

  • Заменяемость. Любую FSM‑группу, сервис или роутер можно заменить новой реализацией, не трогая остальные модули. Это возможно благодаря чистым интерфейсам и централизованной конфигурации.

  • Конфигурация через config_bot.toml Все токены, chat‑ID, URL‑ы и параметры ботов хранятся в едином конфигурационном файле. Бот считывает только свои параметры, что позволяет безболезненно менять окружение.

Гармония

  • Целостность структуры. Несмотря на независимость, модули подчиняются общей архитектуре: все роутеры регистрируются в одном bot.py, общие клавиатуры располагаются в core/keyboards/common.py, а FSM‑группы хранятся в каталоге states/. Эта согласованность обеспечивает гармоничную интеграцию частей в единую систему.
  • Единые стандарты. Общие утилиты помещаются в common/, а общие правила (DI, Builder, systemd‑юнит) одинаковы для всех ботов. Это позволяет легко понимать и сопровождать код.

Архитектурные правила

1. Независимые каталоги и конфигурация

  1. Общие утилиты. Функции, используемые несколькими ботами (генерация клавиатур, работа с БД, таймауты), выносятся в common/ или tools/telegram_bots/common/ и импортируются в нужных модулях.

2. DI и Builder (правило Telegram‑интеграции)

По аналогии с мозаичным подходом каждый бот реализует два уровня взаимодействия:

  1. Контекстный уровень (DI). Используется при тесной интеграции бота с ядром DET (runner, orchestrator). Все зависимости (пути, токены, состояния, параметры) передаются через ApplicationContext или context.py. Хендлеры получают нужные данные автоматически. Это подходит для диалоговых ботов и управляющих команд (/start, /pause, /stats) и обеспечивает единый источник правды.

  2. Чистый уровень (Builder). Применяется для формирования сообщений или отчётов без привязки к контексту. Функции принимают сырой лог или данные, возвращают готовый текст (HTML/Markdown) и не используют глобальные состояния. Такой подход подходит для уведомляющих сервисов, CLI‑скриптов и fallback‑сценариев. Стандартный интерфейс:

Если бот выполняет простую уведомляющую задачу, DI‑контейнер можно не подключать и ограничиться Builder + Notifier.

3. Менеджмент состояний и FSM

  1. Когда использовать FSM. Aiogram 3.x предоставляет встроенный механизм FSM для управления сценарием взаимодействия Используйте FSM‑группы, если нужно удерживать контекст диалога между несколькими сообщениями (формы, опросы, пошаговые процессы). Для простых команд и callback‑хендлеров FSM не требуется.

  2. Размещение FSM‑групп. Каждая ветка (router) может иметь собственную группу состояний, размещённую в states/<module_name>_states.py. Это обеспечивает независимость сценариев.

  3. Хранение состояния. В демо‑ботах состояние хранят в памяти (словаре), но для production это ненадёжно. Для устойчивых ботов нужно использовать внешнее хранилище. Статья о «robust Telegram bots» рекомендует Redis как быстрое хранилище для сохранения пользовательского состояния Такое решение обеспечивает:

    • Персистентность: данные переживают перезапуск бота;
    • Масштабируемость: несколько инстансов бота могут обслуживать запросы, сохраняя состояние централизованно
    • Отделение логики от хранения: функции get_user_state и set_user_state абстрагируют доступ к Redis, поэтому при необходимости можно заменить хранилище

4. Клавиатуры и интерфейсы

  1. Общие клавиатуры. Повторяющиеся элементы интерфейса (кнопки «🏠 В меню», «↩️ Назад», «💬 Поддержка») выносятся в core/keyboards/common.py. Это облегчает поддержку и обеспечивает единый стиль.

  2. Локальные клавиатуры. Каждая функциональная ветка (router) хранит свои уникальные клавиатуры в routers/<module>_keyboards.py или в keyboards.py.

  3. Масштабирование. Если файл keyboards.py превысил ~300–350 строк, его следует разбить на подмодули и соединить через __init__.py. Общие элементы оставляются в core/keyboards/common.py.

  4. Inline‑клавиатуры и фильтры. Aiogram позволяет создавать inline‑клавиатуры и обрабатывать их через фильтры `F.data. Это обеспечивает чистую маршрутизацию callback‑запросов.

5. Управление сообщениями

  1. Удаление сообщений. По умолчанию бот должен удалять устаревшие сообщения после выбора пользователем действия, чтобы интерфейс оставался чистым. Используйте message.delete() внутри callback‑хендлеров при показе нового меню или переходе в новое состояние.
  2. Показывать результаты. Не удаляйте сообщения, содержащие уведомления, результаты действия или справочную информацию.
  3. Автоудаление в FSM. Для пошаговых сценариев можно включать автоудаление предыдущего шага через middleware, чтобы экран пользователя не загромождался.

6. Асинхронность и планирование задач

  1. Асинхронные вызовы. Все API‑вызовы должны быть асинхронными. Aiogram 3.x полностью основан на asyncio, поэтому избегайте блокирующих операций. В примере из руководства по Aiogram обработчик start_polling запускается как асинхронная функция

  2. Фоновые задачи. Тяжёлые операции (обращение к медленным API, генерация отчётов) нельзя выполнять внутри хендлера, потому что они блокируют event loop. Рекомендация — выносить такие задачи в фоновый поток или использовать asyncio.gather для конкурентного выполнения Для длительных CPU‑операций используйте брокер и очередь задач (например, Celery)

  3. Периодические задачи. Для периодических уведомлений используйте планировщик apscheduler, как показано в руководстве Планировщик запускается в обработчике startup и выполняет задания независимо от основного цикла.

8. Обработка ошибок и логирование

  1. Глобальный обработчик ошибок. Необработанное исключение может привести к падению всего бота. Используйте глобальный middleware/handler, который перехватывает исключения, логирует их и уведомляет разработчика. Пример из руководства показывает, как логировать исключение и отправлять его разработчику, не прерывая работу бота
  2. Структурированное логирование. Настройте формат логов (timestamp, имя модуля, уровень), сохраняйте их в файл и отправляйте критические ошибки в чат разработчика.
  3. Мониторинг. Регулярно проверяйте логи на наличие ошибок и тестируйте бота под нагрузкой для выявления узких мест

9. Паттерн цепочки ответственности и роутинг

Телеграм‑боты получают все обновления на единую точку входа (webhook или polling). Для маршрутизации запросов к нужной логике используется паттерн цепочки ответственности (Chain of Responsibility). Его суть:

  1. Обработчики как независимые звенья цепочки. Логику бота нужно разделять на маленькие обработчики (функции или классы), каждый из которых самостоятельно решает, обрабатывать ли конкретное обновление. Обработчик может обработать обновление или передать его дальше. По сути, это модульная реализация роутинга
  2. Параллельность и контроль. Обработчики можно запускать последовательно или параллельно, но важно гарантировать, что каждый запрос будет обработан не более чем одним обработчиком, иначе возможны дублирование ответов
  3. Комбинация с FSM. Цепочку удобно сочетать с FSM: сначала определяется, какой обработчик обслуживает текущее состояние, затем обновление передаётся в этот обработчик, после чего состояние сохраняется и цикл повторяется

10. Развёртывание и systemd

  • Юнит‑файлы systemd. Каждый бот разворачивается как сервис systemd.
  • Расположение юнитов. Юнит‑файлы хранятся в axiom/systemd_units/system/. После обновления юнита в README конкретного бота добавляется блок с командами для ручного развёртывания.

Добавление новых веток и функций

  1. Следуйте мозаичной парадигме: добавляйте новые функции как отдельные модули (новые роутеры, FSM‑группы, сервисы). Каждый модуль должен быть независим и тестироваться отдельно.

  2. Инкрементальные изменения. При добавлении функций не изменяйте существующие модули, пока это не критично. Лучше расширить возможности через новые обработчики или состояния.

  3. Дробление больших файлов. Если файл превышает ~300–350 строк, выделите его части в отдельные модули.

  4. Модульные тесты. Добавляйте юнит‑тесты для новых функций и интеграционные тесты для проверки связей между модулями.

  5. Используйте цепочку ответственности. Добавляя новую ветку, вставьте новый обработчик в цепочку маршрутизации. Он сам решает, принимать ли обновление, что исключает конфликт с другими обработчиками

Масштабирование производительности

  1. Внешнее состояние. Храните состояние в Redis или другом ключ‑значение хранилище. Это позволит запускать несколько экземпляров бота и балансировать нагрузк
  2. Асинхронные задачи и очереди. Разделяйте I/O‑задачи (выполняйте их асинхронно и параллельно через asyncio.gather) и CPU‑задачи (переносите в очередь задач). Это повышает отзывчивость бота
  3. Monitoring & Logging. Настраивайте мониторинг (Prometheus, Grafana) и централизованное логирование для отслеживания метрик. Выявляйте узкие места и оптимизируйте код.

➕ см. README для Telegram‑бота

♻️ Метаданные Документ создан по стандарту U.L.I. v1.0 и соответствует мозаичному подходу к разработке. Обновляйте этот раздел при изменении версии бота или стандарта.

`