Production-структура проекта на Aiogram 3: handlers, services и конфигурация
Как разложить Telegram-бота на Aiogram 3 по слоям, чтобы добавлять FSM, платежи и интеграции без единого огромного файла.
Надёжная структура Aiogram 3 отделяет Telegram-слой от бизнес-логики: handlers принимают обновление, services выполняют действие, repositories работают с данными, а config отвечает за окружение. Это не архитектура «ради папок»: границы помогают менять хранение, тестировать правила без Telegram и не переплетать оплату с FSM и уведомлениями.
Минимальная структура
app/
bot.py
config.py
handlers/
start.py
orders.py
services/
orders.py
repositories/
orders.py
keyboards/
middlewares/
tests/
bot.py — composition root: здесь создаются конфигурация, хранилища и Dispatcher, после чего подключаются роутеры. В handler не нужно помещать SQL-запросы и сложные расчёты. Он проверяет формат входа, вызывает нужное действие и переводит его результат в ответ Telegram.
Не создавайте папку на каждый класс. На маленьком боте достаточно одного модуля для заявок; разделяйте код по предметной области, когда у неё появились свои сценарии, данные и тесты. Названия services и repositories не важны сами по себе — важно, чтобы направление зависимостей оставалось понятным.
Конфигурация через окружение
Токен и ключи интеграций не должны попадать в код или репозиторий. Установите зависимости и храните только пример переменных в Git:
python -m pip install aiogram pydantic-settings
# .env.example; реальный .env добавьте в .gitignore
BOT_TOKEN=
Минимальная конфигурация проверяет обязательные значения на старте:
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
model_config = SettingsConfigDict(env_file=".env", extra="ignore")
bot_token: str
BaseSettings сопоставит bot_token с BOT_TOKEN. Если появится база, добавьте её URL вместе с выбранным драйвером и проверьте соединение при старте. Реальный .env добавляется на сервере или переменные размещаются в secret storage CI.
Роутеры вместо большого handler-файла
Группируйте обработчики по предметной области: заявки, каталог, профиль, платежи. Роутер не должен знать, где физически хранится заявка. Это позволяет заменить SQLite на PostgreSQL без переписывания Telegram-слоя.
# app/handlers/orders.py
from aiogram import Router
from aiogram.filters import Command
from aiogram.types import Message
router = Router(name="orders")
@router.message(Command("request"))
async def start_request(message: Message) -> None:
await message.answer("Опишите, что нужно сделать.")
Подключите вложенные роутеры один раз при старте и следите за порядком широких фильтров. Универсальный handler «на любой текст» может перехватить сообщение, которое ожидал FSM. Для последовательной формы с проверками, отменой и несколькими состояниями есть отдельный разбор FSM в Aiogram 3.
Services и repositories
Сервис отвечает на вопрос «что сделать», repository — «как прочитать или сохранить данные». Например, orders.create() проверяет бизнес-правила, а orders_repository.insert() выполняет запрос. Решите, где начинается и завершается транзакция, и не возвращайте ORM-объекты напрямую в Telegram-слой.
Внешние API вызываются из отдельного клиента или gateway с timeout, понятной обработкой ошибок и ограниченными повторными попытками. Повторять безопасно только операции, которые идемпотентны или имеют idempotency key. Для логов используйте request/update ID и технический статус, но не токен, полный текст переписки или платёжные секреты.
Такой разнос особенно важен для оплаты. Webhook может прийти повторно, поэтому обработчик проверяет подпись и внешний ID события, атомарно фиксирует заказ и только после подтверждённого перехода выдаёт доступ. Нельзя считать callback-кнопку или сообщение клиента доказательством оплаты.
Сборка приложения и запуск
Создавайте сетевые ресурсы один раз на время жизни процесса, а не на каждое обновление. При завершении polling закройте HTTP-сессию бота и пул базы данных. Не запускайте два polling-процесса с одним токеном; для webhook отдельно настройте публичный endpoint и проверку секрета.
import asyncio
from aiogram import Bot, Dispatcher
from app.config import Settings
from app.handlers import orders, start
async def main() -> None:
settings = Settings()
bot = Bot(token=settings.bot_token)
dispatcher = Dispatcher()
dispatcher.include_routers(start.router, orders.router)
try:
await dispatcher.start_polling(bot, close_bot_session=False)
finally:
await bot.session.close()
if __name__ == "__main__":
asyncio.run(main())
Экспортируйте BOT_TOKEN в окружение или используйте локальный .env, который исключён из Git. Если добавите async database engine, его dispose() тоже вызывается в finally или lifespan-обработчике.
Что проверить перед деплоем
- приложение стартует из инструкции на чистом окружении, а не только из IDE;
.env.exampleсовпадает с конфигурацией и не содержит действующих секретов;- polling и webhook не запущены одновременно для одного бота;
- ошибки внешних API не скрываются пустым
exceptи безопасно видны в логах; - повторный update или webhook не создаёт дубликат заявки, заказа или выдачи;
- роли и права проверяются сервером, а callback нельзя подделать сменой ID;
- есть проверка доступности процесса и резервная копия хранилища;
- критические правила сервисов покрыты тестами без реального Telegram API;
- для новой версии есть понятные команды миграции и отката.
Не начинайте с микросервисов, очереди и сложного контейнерного окружения, если один процесс и одна база решают текущую задачу. Добавляйте инфраструктуру, когда появляется измеримое требование к нагрузке, отказоустойчивости или независимому масштабированию.
Для первого проекта можно начать с бесплатного практикума Aiogram 3, а затем перейти к полному курсу по Telegram-ботам, где разбираются платежи, Mini App, webhook, Docker и production-проверки.
Если нужна такая архитектура для реального продукта, опиши задачу в заявке: достаточно указать основной сценарий, интеграции и предполагаемую нагрузку.
по теме
следующий шаг
Собрать production-бота целиком
В полном курсе есть PostgreSQL, платежи, Mini App, тесты и Docker. Начать можно с бесплатного первого урока.
поделиться
Нужна разработка Telegram-бота?
Разрабатываю ботов, Mini Apps, платежи и автоматизацию под ключ.