Summary

Мне понадобился Telegram-бот, который сам выдаёт клиентам VPN-конфиги и принимает оплату. Я поставил задачу агенту Codex и посмотрел, что получится. Рабочий бот с оплатой, базой и Docker-деплоем появился за один день. Но самое интересное в этой истории - не скорость, а то, как трижды менялось ТЗ прямо по ходу и что упало при самом первом запуске.

Как менялось ТЗ бота, стек и ошибка первого запуска

Что нужно было сделать

VPN у меня уже работал: серверы на AmneziaWG и веб-панель WGDashboard, через которую выдаются конфиги. Чего не хватало - автоматизации. Каждому новому клиенту конфиг приходилось выдавать руками, отслеживать оплату - тоже руками.

Идея простая: бот в Telegram.

  • пользователь нажимает кнопку и получает конфиг;
  • платит прямо в боте;
  • когда деньги кончаются, доступ приостанавливается;
  • после оплаты включается обратно, без моего участия.

Шаг 0. Посмотреть, как делают другие

Писать с пустого листа я не стал. Нашёл открытый репозиторий похожего бота и попросил агента разобрать его отдельным субагентом: что там есть, чего нет.

Вывод оказался поучительным. У референса нет настоящего биллинга: тарифы зашиты прямо в код, транзакций в базе нет. Как отправная точка - хорошо, как основа для платного сервиса - нет. Поэтому я взял у него только структуру бота, а платёжную часть решил делать с нуля.

Главное решение: бот не лезет в базу панели

Первое архитектурное правило, которое я поставил: бот общается с WGDashboard только через его REST API. Никакого прямого доступа к файлам или SQLite панели.

Почему это важно: у панели своя внутренняя логика и свои миграции. Залезешь в базу - сломаешь при первом же обновлении. А через API панель сама решает, что и как записать. Бот лишь вызывает три действия: создать пира, скачать его конфиг, ограничить доступ.

Как менялось ТЗ

Вот тут началась настоящая работа. Я формулировал задачу итерациями, и каждая итерация что-то ломала в предыдущих решениях.

Версия 1: тарифы и подписки. Классика: месячный, квартальный, годовой. Агент реализовал, я посмотрел и понял, что не нравится.

Версия 2: один тариф, посуточная оплата. Вместо подписок - баланс. Деньги списываются по дням, пока на счёте есть средства. Это куда честнее для пользователя: никаких «купил на год и забыл».

Версия 3: плюс бонусный баланс. Отдельный счёт для бонусов, которые тратятся первыми. Удобно для промо.

Параллельно поменялась и база данных: сначала SQLite, потом PostgreSQL. А вместо самодельных фоновых задач я попросил взять менеджер задач и docker-compose из моего же старого бота, который уже проверен в бою.

ЧтоНачалиЗакончили
Модель оплатыПодпискиБаланс + посуточное списание + бонусы
БазаSQLitePostgreSQL
Фоновые задачиС нуляПроверенный менеджер из старого проекта
Доступ к панелиДумали про прямойТолько REST API

Главный урок: агент отлично переписывает код, когда ты чётко говоришь «нет, не так». Беда начинается, когда ты сам ещё не знаешь, как «так».

Что внутри

  • aiogram 3 - сам бот;
  • SQLAlchemy + PostgreSQL - пользователи, балансы, транзакции;
  • YooKassa и Telegram Stars - два способа оплаты; для Stars используется счёт в валюте XTR;
  • WGDashboard REST API - выдача конфигов и ограничение доступа;
  • Docker Compose - упаковка для деплоя;
  • pytest - несколько тестов на самые важные сценарии.

Что сломалось сразу

Я запустил контейнер, и бот упал прямо на старте. Polling даже не успел начаться.

Причина - смена API в aiogram 3. Обработчики запуска и остановки (on_startup и on_shutdown) теперь вызываются без позиционного аргумента. А код, написанный по привычке к старой версии, ждал его на входе.

# было (aiogram 2)
async def on_startup(dp):
    ...
 
# стало (aiogram 3)
async def on_startup():
    ...

Мелочь? Да. Но из таких мелочей и состоит первый день любого бота. Агент нашёл и исправил ошибку за пару минут, потому что я просто вставил ему в чат traceback из контейнера.

Порядок работы, который сработал

  1. Сначала разведка. Субагент разобрал референс, прежде чем я начал писать.
  2. Контракт с внешней системой. Выбрали REST API панели и не отступали.
  3. Правки на ходу. ТЗ менялось три раза, и это нормально.
  4. Тесты на критичное. Баланс, списания, выдача конфига.
  5. Git-дисциплина. Приватный репозиторий создан через gh, работа шла в отдельной ветке.

Что я вынес

Ощущение «бот собрался за один день» слегка обманчиво. Собрался каркас. Дальше начинается то, чего в чате не видно: реальные платежи, возвраты, обработка ошибок платёжных систем, поддержка пользователей.

Но для меня ценность была в другом. Раньше идея «нужен бот» превращалась в неделю рутины. Теперь это вечер, а остальное время остаётся на то, что требует головы: как устроена оплата, что делать с просрочкой, как не обидеть пользователя.

Warning

Если вы принимаете реальные деньги, не доверяйте сгенерированной платёжной логике «на слово». Проверьте сами, что происходит при повторных уведомлениях, отмене платежа и двойном нажатии кнопки.