Телеграм-бот для продажи VPN с inline-сценарием и хранением состояния в PostgreSQL.
- Полностью inline UX с чистыми последовательными экранами.
- Единственная команда пользователя:
/start. Дальше вся навигация только inline-кнопками. - После
/startглавное меню:Купить VPN,Личный кабинет,Сменить язык. Личный кабинет:Инфо и помощь,История покупок,Мои конфиги.- Раздел
Инфо и помощь: документы (ссылки на соглашение/политику) и тикет-система поддержки (создание обращений, история, ответы). - После
Купить VPN3 кнопки:Готовые тарифы,Создать свой тариф,Назад. - Ветка
Готовые тарифы: сначала выбор семейства тарифа, затем длительности, затем оплата. - Ветка
Создать свой тариф: страна -> сервер (с ping) -> протокол -> длительность -> количество подключений -> оплата. - После оплаты бот отправляет задачу на мастер-ноду (
localhost:6767) и опрашивает статус каждые 15 секунд до готовности конфига. - Есть история заказов (из таблицы оплат) и список конфигов с возможностью обновить конфиг без оплаты.
- Мультиязычность:
ru,en,uz,kk,tg,az,be,hy,ky,uk. - Один активный экран: предыдущее сообщение бота удаляется, кроме первого
/startу новых пользователей. - На ключевых экранах используются изображения (старт, кабинет, смена языка).
- Платежные ветки:
SBPкак локальная симуляция (success,failed,cancel).Telegram Starsчерезsend_invoice(валютаXTR).Crypto Botчерез API (createInvoice,getInvoices).
- Python 3.12+
- aiogram 3
- asyncpg
- PostgreSQL 16 (через Docker Compose)
app/
main.py # Точка входа, DI и polling
config.py # Загрузка ENV в Settings
handlers/start.py # /start, кнопки, платежи, back-навигация
keyboards/inline.py # Inline клавиатуры
locales/translations.py # Словари переводов и tr()
db/repository.py # Работа с БД + автосоздание таблиц
services/
catalog.py # Каталог готовых тарифов + формула custom тарифа
cryptobot.py # Клиент Crypto Pay API
master_node.py # Клиент мастер-ноды (create/poll/renew/servers)
ui.py # replace/delete bot message
docker-compose.yml # PostgreSQL
requirements.txt
Создайте .env из шаблона:
cp .env.example .envОбязательные:
BOT_TOKENDATABASE_URL
Опциональные:
DEFAULT_LANGUAGE=ruMASTER_NODE_URL=http://127.0.0.1:6767CONFIG_POLL_INTERVAL_SEC=15STARS_ENABLED=trueCRYPTOBOT_ENABLED=trueCRYPTOBOT_TOKEN=...CRYPTOBOT_ASSET=USDTCRYPTOBOT_API_BASE=https://pay.crypt.bot/apiSUPPORT_ADMIN_IDS=12345,67890(Telegram user id администраторов поддержки, через запятую)
- Поднять PostgreSQL:
docker compose up -d- Создать окружение и поставить зависимости:
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt- Запустить бота:
python3 -m app.mainТаблицы БД создаются автоматически при старте (Repository._migrate()).
- Подготовить
.env:
cp .env.example .env- Запустить PostgreSQL:
docker compose up -d- В отдельном терминале запустить mock мастер-ноду:
python3 -m app.mock_master_node- В отдельном терминале запустить бота:
python3 -m app.main- В Telegram открыть бота и отправить только
/start. - Пройти сценарий:
Купить VPN->Готовые тарифыилиСоздать свой тариф- выбрать оплату (для локального теста проще всего
СБП) - в симуляции нажать
Успешная оплата - дождаться выдачи конфига от mock мастер-ноды
- проверить
История покупокиМои конфигивЛичном кабинете. - открыть
Инфо и помощьи создать тестовый тикет.
- Пользователь:
Инфо и помощь->Создать тикет-> отправляет один текстовый месседж. - Бот создает тикет и отправляет уведомление администраторам из
SUPPORT_ADMIN_IDS. - Администратор:
Инфо и помощь->Открытые тикеты (админ)-> открывает тикет ->Ответить. - Пользователь видит ответы в том же треде тикета (
Инфо и помощь->Мои тикеты). - Доступно закрытие/переоткрытие тикета администратором.
Можно поднять простой mock API мастер-ноды на 127.0.0.1:6767:
python3 -m app.mock_master_nodeОн реализует:
GET /serversPOST /configs/createGET /tasks/{task_id}POST /configs/renew
Полезные env для mock:
MOCK_MASTER_HOST=127.0.0.1MOCK_MASTER_PORT=6767MOCK_TASK_DELAY_SEC=5MOCK_FAIL_RATE=0
Бот поддерживает overrides цен через таблицу config_kv (напрямую в БД, без изменения кода).
Ключи, которые используются:
pricing.usd_to_rubpricing.usd_to_starspricing.plan.<plan_code>.usdpricing.custom.base_usd_per_monthpricing.custom.extra_device_usd_per_month
Примеры plan_code для готовых тарифов:
ready:entry:1ready:standard:3ready:premium:12
Примеры SQL:
-- Курс валюты
INSERT INTO config_kv(key, value) VALUES ('pricing.usd_to_rub', '80')
ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value;
-- Цена конкретного готового тарифа (STANDARD 1 месяц)
INSERT INTO config_kv(key, value) VALUES ('pricing.plan.ready:standard:1.usd', '4.99')
ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value;
-- Формула custom тарифа
INSERT INTO config_kv(key, value) VALUES ('pricing.custom.base_usd_per_month', '3.50')
ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value;
INSERT INTO config_kv(key, value) VALUES ('pricing.custom.extra_device_usd_per_month', '1.10')
ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value;-- Заказы пользователя
SELECT id, tg_id, plan, server, protocol, payment_method, amount_usd_numeric, status, created_at
FROM vpn_orders
ORDER BY id DESC;
-- События оплат
SELECT id, order_id, payment_method, event_type, details, created_at
FROM payment_events
ORDER BY id DESC;
-- Конфиги пользователя
SELECT id, tg_id, server_id, protocol, status, task_id, expiration_date, updated_at
FROM connections
ORDER BY id DESC;
-- Пинг и статус серверов (приходит с мастер-ноды)
SELECT server_id, country, status, ping_ms, updated_at
FROM server_data
ORDER BY country, server_id;/start-> главное меню.Купить VPN->Готовые тарифыилиСоздать свой тариф.Готовые тарифы: семейство тарифа -> длительность -> оплата -> summary.Создать свой тариф: страна -> сервер (node + ping) -> протокол -> длительность -> устройства -> оплата -> summary.pay:startсоздает заказ вvpn_ordersсо статусомpending.- Дальше зависит от платежного метода:
sbp: локальная эмуляция результата.stars: invoice в Telegram, подтверждение черезsuccessful_payment.cryptobot: ссылка на оплату + ручная проверка статуса кнопкой.
- При успехе:
- статус заказа
paid - запись в
payment_events - сброс
draft_orders - создание
connectionи запуск задачи создания конфига на мастер-ноде
users: язык и id последнего сообщения бота.draft_orders: незавершенный выбор пользователя.vpn_orders: финальные заказы и статус оплаты.payment_events: аудит платежных событий.connections: созданные VPN-конфиги и их статус/задача на мастер-ноде.
- Любые команды кроме
/startигнорируются. - Обычные текстовые сообщения игнорируются, кроме режима ввода тикета поддержки (
создание/ответ). - Навигация "Назад" не откатывает состояние
draft_orders, только экран. - Для
customтарифа цена считается формулой-заглушкой вapp/services/catalog.py. - Выдача конфига берется из ответа мастер-ноды, технические детали отправляются в логи.
- Telegram Bot API не поддерживает произвольную раскраску inline-кнопок во всех клиентах.
- В Bot API 9.4 добавлены
style/icon_custom_emoji_id; отображение зависит от клиента Telegram и может отличаться.
# Проверка контейнера БД
docker compose ps
# Логи PostgreSQL
docker compose logs -f postgres
# Остановка окружения
docker compose down