Summary
Мне понадобился Telegram-бот, который сам выдаёт клиентам VPN-конфиги и принимает оплату. Я поставил задачу агенту Codex и посмотрел, что получится. Рабочий бот с оплатой, базой и Docker-деплоем появился за один день. Но самое интересное в этой истории - не скорость, а то, как трижды менялось ТЗ прямо по ходу и что упало при самом первом запуске.
Что нужно было сделать
VPN у меня уже работал: серверы на AmneziaWG и веб-панель WGDashboard, через которую выдаются конфиги. Чего не хватало - автоматизации. Каждому новому клиенту конфиг приходилось выдавать руками, отслеживать оплату - тоже руками.
Идея простая: бот в Telegram.
- пользователь нажимает кнопку и получает конфиг;
- платит прямо в боте;
- когда деньги кончаются, доступ приостанавливается;
- после оплаты включается обратно, без моего участия.
Шаг 0. Посмотреть, как делают другие
Писать с пустого листа я не стал. Нашёл открытый репозиторий похожего бота и попросил агента разобрать его отдельным субагентом: что там есть, чего нет.
Вывод оказался поучительным. У референса нет настоящего биллинга: тарифы зашиты прямо в код, транзакций в базе нет. Как отправная точка - хорошо, как основа для платного сервиса - нет. Поэтому я взял у него только структуру бота, а платёжную часть решил делать с нуля.
Главное решение: бот не лезет в базу панели
Первое архитектурное правило, которое я поставил: бот общается с WGDashboard только через его REST API. Никакого прямого доступа к файлам или SQLite панели.
Почему это важно: у панели своя внутренняя логика и свои миграции. Залезешь в базу - сломаешь при первом же обновлении. А через API панель сама решает, что и как записать. Бот лишь вызывает три действия: создать пира, скачать его конфиг, ограничить доступ.
Как менялось ТЗ
Вот тут началась настоящая работа. Я формулировал задачу итерациями, и каждая итерация что-то ломала в предыдущих решениях.
Версия 1: тарифы и подписки. Классика: месячный, квартальный, годовой. Агент реализовал, я посмотрел и понял, что не нравится.
Версия 2: один тариф, посуточная оплата. Вместо подписок - баланс. Деньги списываются по дням, пока на счёте есть средства. Это куда честнее для пользователя: никаких «купил на год и забыл».
Версия 3: плюс бонусный баланс. Отдельный счёт для бонусов, которые тратятся первыми. Удобно для промо.
Параллельно поменялась и база данных: сначала SQLite, потом PostgreSQL. А вместо самодельных фоновых задач я попросил взять менеджер задач и docker-compose из моего же старого бота, который уже проверен в бою.
| Что | Начали | Закончили |
|---|---|---|
| Модель оплаты | Подписки | Баланс + посуточное списание + бонусы |
| База | SQLite | PostgreSQL |
| Фоновые задачи | С нуля | Проверенный менеджер из старого проекта |
| Доступ к панели | Думали про прямой | Только 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 из контейнера.
Порядок работы, который сработал
- Сначала разведка. Субагент разобрал референс, прежде чем я начал писать.
- Контракт с внешней системой. Выбрали REST API панели и не отступали.
- Правки на ходу. ТЗ менялось три раза, и это нормально.
- Тесты на критичное. Баланс, списания, выдача конфига.
- Git-дисциплина. Приватный репозиторий создан через
gh, работа шла в отдельной ветке.
Что я вынес
Ощущение «бот собрался за один день» слегка обманчиво. Собрался каркас. Дальше начинается то, чего в чате не видно: реальные платежи, возвраты, обработка ошибок платёжных систем, поддержка пользователей.
Но для меня ценность была в другом. Раньше идея «нужен бот» превращалась в неделю рутины. Теперь это вечер, а остальное время остаётся на то, что требует головы: как устроена оплата, что делать с просрочкой, как не обидеть пользователя.
Warning
Если вы принимаете реальные деньги, не доверяйте сгенерированной платёжной логике «на слово». Проверьте сами, что происходит при повторных уведомлениях, отмене платежа и двойном нажатии кнопки.