25 KiB
Интеграция веб-админки
Этот документ описывает запуск встроенного административного веб-API бота и типовой сценарий интеграции c внешней веб-админкой. API разворачивается вместе с ботом, использует FastAPI и защищено токенами доступа.
1. Обзор архитектуры
- Веб-API запускается в том же процессе, что и бот, через встроенный
uvicornсервер. - Авторизация выполняется по токену:
X-API-KeyилиAuthorization: Bearer <token>. - Все эндпоинты работают поверх HTTPS/HTTP и возвращают структуры в формате JSON.
- Встроенный механизм миграций создаёт таблицу
web_api_tokensи бутстрап-токен, если указан в конфигурации.
2. Настройка окружения
Добавьте переменные в .env (или другую систему конфигурации):
| Переменная | Назначение | Значение по умолчанию / пример |
|---|---|---|
WEB_API_ENABLED |
Включает веб-API. | true |
WEB_API_HOST |
IP/hostname, на котором слушает API. | 0.0.0.0 |
WEB_API_PORT |
Порт веб-API. | 8080 |
WEB_API_ALLOWED_ORIGINS |
Список доменов для CORS, через запятую. * разрешит всё. |
https://admin.example.com |
WEB_API_DOCS_ENABLED |
Включить /docs, /doc (редирект), /redoc и /openapi.json. В проде лучше false. |
false |
WEB_API_WORKERS |
Количество воркеров uvicorn. В embed-режиме всегда приводится к 1. |
1 |
WEB_API_REQUEST_LOGGING |
Логировать каждый запрос API. | true |
WEB_API_DEFAULT_TOKEN |
Бутстрап-токен, который будет создан при миграции. | super-secret-token |
WEB_API_DEFAULT_TOKEN_NAME |
Отображаемое имя созданного токена. | Bootstrap Token |
WEB_API_TOKEN_HASH_ALGORITHM |
Алгоритм хеширования токенов (sha256, sha512, ...). |
sha256 |
⚠️ Если вы храните конфигурацию в Kubernetes/Ansible/других системах — не забудьте обновить секреты, чтобы бот видел эти переменные.
Включение Swagger (интерактивной документации)
Чтобы открыть интерфейс Swagger UI на /docs, убедитесь, что одновременно заданы две переменные окружения:
WEB_API_ENABLED=true— включает само веб-API.WEB_API_DOCS_ENABLED=true— публикует/docs,/doc(редирект для старых ссылок),/redocи/openapi.json.
После изменения значений перезапустите бота. Интерфейс будет доступен по адресу http://<WEB_API_HOST>:<WEB_API_PORT>/docs.
3. Подготовка базы данных
- Убедитесь, что настройки БД верны (
DATABASE_URLили параметры PostgreSQL/SQLite). - При старте бота автоматически запускается универсальная миграция
run_universal_migration, которая:- создаёт таблицу
web_api_tokens, если её нет; - активирует токен из
WEB_API_DEFAULT_TOKEN, если он задан.
- создаёт таблицу
- Если нужно запустить миграцию вручную, выполните:
python -c "import asyncio; from app.database.universal_migration import run_universal_migration; asyncio.run(run_universal_migration())"
Или просто запустите python main.py — бот выполнит ту же процедуру автоматически.
4. Запуск веб-API
# Создаём .env и включаем веб-API
cp .env.example .env
nano .env # проставьте WEB_API_* переменные и BOT_TOKEN
# Запускаем бота (локально)
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
python main.py
В Docker достаточно пробросить порт WEB_API_PORT из контейнера бота. После запуска API будет доступно по адресу http://<WEB_API_HOST>:<WEB_API_PORT>.
5. Аутентификация и токены
- Первый токен удобно задать через
WEB_API_DEFAULT_TOKEN. Он появится в таблице при запуске миграции и будет автоматически пересоздан/активирован после изменения значения через интерфейс настроек. - Для управления токенами используйте эндпоинты
/tokens:GET /tokens— список токенов.POST /tokens— создать новый токен. Возвращает открытое значение один раз.POST /tokens/{id}/revokeи/activate— управление статусом.DELETE /tokens/{id}— удаление.
- Заголовок авторизации можно передавать двумя способами:
X-API-Key: <ваш_токен>
# или
Authorization: Bearer <ваш_токен>
Пример запроса на создание токена:
curl -X POST "http://127.0.0.1:8080/tokens" \
-H "X-API-Key: super-secret-token" \
-H "Content-Type: application/json" \
-d '{"name": "Web admin", "description": "UI token"}'
6. Основные эндпоинты
| Метод | Путь | Назначение |
|---|---|---|
GET |
/health |
Статус API, версия бота, флаги включённых сервисов. |
GET |
/stats/overview |
Сводная статистика по пользователям, подпискам, платежам и тикетам. |
GET |
/settings/categories |
Категории системных настроек. |
GET |
/settings |
Полный список настроек (с текущими и дефолтными значениями). |
GET |
/settings/{key} |
Получить одну настройку. |
PUT |
/settings/{key} |
Обновить значение настройки. |
DELETE |
/settings/{key} |
Сбросить настройку к значению по умолчанию. |
GET |
/users |
Список пользователей с фильтрами и пагинацией. |
GET |
/users/{id} |
Детали пользователя. ID может быть как внутренним (user.id), так и Telegram ID (user.telegram_id). |
POST |
/users |
Создать пользователя (например, для ручной выдачи доступа). |
PATCH |
/users/{id} |
Обновить профиль пользователя или статус. ID может быть как внутренним (user.id), так и Telegram ID (user.telegram_id). |
POST |
/users/{id}/balance |
Корректировка баланса с созданием транзакции. ID может быть как внутренним (user.id), так и Telegram ID (user.telegram_id). |
GET |
/subscriptions |
Список подписок с фильтрами. |
POST |
/subscriptions |
Создать триальную или платную подписку. |
POST |
/subscriptions/{id}/extend |
Продлить подписку на N дней. |
POST |
/subscriptions/{id}/traffic |
Добавить трафик (ГБ). |
POST |
/subscriptions/{id}/devices |
Добавить устройства. |
POST |
/subscriptions/{id}/squads |
Привязать сквад. |
DELETE |
/subscriptions/{id}/squads/{uuid} |
Удалить сквад. |
GET |
/transactions |
История транзакций. |
GET |
/tickets |
Список тикетов поддержки. |
GET |
/tickets/{id} |
Тикет с перепиской. |
POST |
/tickets/{id}/status |
Изменить статус тикета. |
POST |
/tickets/{id}/priority |
Изменить приоритет. |
POST |
/tickets/{id}/reply-block |
Заблокировать ответы пользователя. |
DELETE |
/tickets/{id}/reply-block |
Снять блокировку. |
GET |
/promo-groups |
Список промо-групп с количеством участников. |
POST |
/promo-groups |
Создать промо-группу. |
PATCH |
/promo-groups/{id} |
Обновить промо-группу. |
DELETE |
/promo-groups/{id} |
Удалить промо-группу. |
GET |
/promo-offers |
Список промо-предложений с фильтрами по пользователю, статусу и типу уведомления. |
POST |
/promo-offers |
Создать или обновить персональное промо-предложение пользователю. ID может быть как внутренним (user.id), так и Telegram ID (user.telegram_id). |
GET |
/promo-offers/{id} |
Детали конкретного промо-предложения. |
GET |
/promo-offers/templates |
Список шаблонов промо-предложений. |
GET |
/promo-offers/templates/{id} |
Получить данные шаблона промо-предложения. |
PATCH |
/promo-offers/templates/{id} |
Обновить текст, кнопки и параметры шаблона. |
GET |
/promo-offers/logs |
Журнал операций с промо-предложениями (активации, списания, выключения). |
GET |
/tokens |
Управление токенами доступа. |
GET |
/polls |
Список опросов с постраничной навигацией. |
GET |
/polls/{id} |
Детали опроса с вопросами и вариантами ответов. |
POST |
/polls |
Создать опрос: заголовок, описание, вопросы и варианты. |
DELETE |
/polls/{id} |
Удалить опрос целиком. |
GET |
/polls/{id}/stats |
Сводная статистика по ответам и начисленным наградам. |
GET |
/polls/{id}/responses |
Ответы пользователей с детализацией по вопросам. |
GET |
/logs/monitoring |
Логи мониторинга бота с пагинацией и фильтрами по типу события. |
GET |
/logs/monitoring/event-types |
Справочник доступных типов событий мониторинга. |
GET |
/logs/support |
Журнал действий модераторов поддержки (блокировки, закрытия тикетов). |
GET |
/logs/support/actions |
Справочник возможных действий в аудите поддержки. |
GET |
/logs/system |
Предпросмотр системного лог-файла бота с метаданными. |
GET |
/logs/system/download |
Скачивание полного лог-файла бота (text/plain). |
Раздел promo-offers в Swagger объединяет работу с персональными предложениями: выдачу скидок/бонусов пользователям, настройку текстов шаблонов и просмотр журнала операций (активации, автосписания, отключения просроченных акций).
Логи бота
В административном API появился раздел logs. Он позволяет:
- Просматривать общие логи мониторинга (
GET /logs/monitoring) с поддержкой пагинации (limit,offset) и фильтра по типу события (event_type). - Получать справочник доступных типов событий (
GET /logs/monitoring/event-types). Это удобно для построения фильтров во внешней админке. - Отслеживать действия модераторов поддержки (
GET /logs/support) с пагинацией и возможностью фильтровать по конкретному действию (action). - Запрашивать список возможных действий для UI (
GET /logs/support/actions). - Просматривать системный лог-файл бота (
GET /logs/system). Endpoint возвращает метаданные (путь, время изменения, размер в байтах/символах) и фрагмент конца файла, размер которого можно регулировать параметромpreview_limit(от 500 до 20 000 символов). - Скачивать полный системный лог в текстовом формате (
GET /logs/system/download).
Все эндпоинты защищены токеном API и возвращают структуру с общим количеством записей, текущим limit/offset и массивом объектов. Это упрощает реализацию таблиц и постраничной навигации во внешних административных интерфейсах.
Управление опросами
Раздел polls в административном API позволяет создавать и анализировать опросы, которые бот рассылает пользователям.
Список и детали
GET /polls— возвращает массив объектов с базовой информацией: название, описание, флаги награды, количество вопросов и ответов.GET /polls/{id}— раскрывает структуру конкретного опроса, включая упорядоченные вопросы и варианты ответов. Подходит для предпросмотра перед публикацией.
Создание опроса
Для создания опроса отправьте JSON, соответствующий схеме:
{
"title": "Оценка нового тарифа",
"description": "Помогите улучшить продукт — ответ займет до 2 минут",
"reward_enabled": true,
"reward_amount_kopeks": 1000,
"questions": [
{
"text": "Насколько вы довольны скоростью соединения?",
"options": [
{ "text": "Очень доволен" },
{ "text": "Скорее доволен" },
{ "text": "Нейтрально" },
{ "text": "Скорее недоволен" },
{ "text": "Очень недоволен" }
]
},
{
"text": "Какие улучшения вы ждёте?",
"options": [
{ "text": "Стабильность" },
{ "text": "Скорость" },
{ "text": "Поддержка" }
]
}
]
}
Требования валидации:
- Заголовок (
title) — от 1 до 255 символов, не пустой после обрезки пробелов. - Описание (
description) — до 4000 символов, пробелы по краям удаляются. - Если
reward_enabled=true, сумма вознаграждения (reward_amount_kopeks) должна быть положительной. Приfalseзначение автоматически сбрасывается в0. - Каждый вопрос содержит минимум два уникальных варианта ответа.
В ответ API вернёт созданный опрос с назначенными идентификаторами и полем reward_amount_rubles, которое удобно показывать в интерфейсе.
Удаление и статистика
DELETE /polls/{id}— удаляет опрос и связанные с ним вопросы/ответы. Используйте с осторожностью, операция необратима.GET /polls/{id}/stats— агрегированная статистика: общее количество ответов, завершённых прохождений и сумма выданных наград. Для каждого вопроса возвращается количество выборов по вариантам.GET /polls/{id}/responses— список ответов пользователей с пагинацией (limit,offset). Каждый элемент содержит временные метки (sent_at,started_at,completed_at), данные пользователя (ID, username, Telegram ID), информацию о выданной награде и массив ответов с текстами вопросов/вариантов.
Такой формат позволяет без дополнительного запроса показать детализацию на фронтенде или выгрузить данные в CSV.
RemnaWave интеграция
После включения веб-API в Swagger (WEB_API_DOCS_ENABLED=true) появится раздел remnawave. Он объединяет эндпоинты для управления панелью RemnaWave и синхронизации данных бота:
| Метод | Путь | Назначение |
|---|---|---|
GET |
/remnawave/status |
Проверка конфигурации и доступности RemnaWave API. |
GET |
/remnawave/system |
Агрегированная статистика по пользователям, нодам и трафику. |
GET |
/remnawave/nodes |
Список нод и их текущее состояние. |
GET |
/remnawave/nodes/realtime |
Текущая загрузка нод (realtime-метрики RemnaWave). |
GET |
/remnawave/nodes/{uuid} |
Детальная информация по конкретной ноде. |
GET |
/remnawave/nodes/{uuid}/statistics |
Агрегированная статистика и история нагрузок по ноде. |
GET |
/remnawave/nodes/{uuid}/usage |
История использования ноды пользователями за выбранный период. |
POST |
/remnawave/nodes/{uuid}/actions |
Включение, отключение или перезапуск ноды. |
POST |
/remnawave/nodes/restart |
Массовый перезапуск всех нод в RemnaWave. |
GET |
/remnawave/squads |
Список внутренних сквадов с составом и статистикой. |
GET |
/remnawave/squads/{uuid} |
Детали выбранного сквада. |
POST |
/remnawave/squads |
Создание нового сквада и привязка inbounds. |
PATCH |
/remnawave/squads/{uuid} |
Обновление имени или состава inbounds сквада. |
POST |
/remnawave/squads/{uuid}/actions |
Массовые операции: добавить/удалить всех, переименовать, обновить inbounds, удалить. |
GET |
/remnawave/inbounds |
Список доступных inbounds в панели RemnaWave. |
GET |
/remnawave/users/{telegram_id}/traffic |
Использование трафика конкретного пользователя RemnaWave. |
POST |
/remnawave/sync/from-panel |
Синхронизация пользователей и подписок из панели в бота. |
POST |
/remnawave/sync/to-panel |
Обратная синхронизация данных бота в панель. |
POST |
/remnawave/sync/subscriptions/validate |
Проверка и восстановление подписок в RemnaWave. |
POST |
/remnawave/sync/subscriptions/cleanup |
Очистка «осиротевших» подписок и пользователей в RemnaWave. |
POST |
/remnawave/sync/subscriptions/statuses |
Приведение статусов подписок в боте и панели к единому виду. |
GET |
/remnawave/sync/recommendations |
Рекомендации по синхронизации: что добавить, обновить или удалить. |
Все списковые эндпоинты поддерживают пагинацию (
limit,offset) и фильтры, описанные в OpenAPI спецификации. ЕслиWEB_API_DOCS_ENABLED=true, документация доступна по/docs. В ответах/settingsполеchoicesвсегда массив: пустой список означает отсутствие предопределённых значений.
7. Сценарий интеграции веб-админки
- Health-check — перед авторизацией UI вызывает
GET /health, чтобы отобразить статус и версию бота. - Настройки UI — подгружает категории через
GET /settings/categories, далее выводит форму со значениями изGET /settings. - Статистика дашборда —
GET /stats/overviewдля карточек с показателями. - Раздел пользователи —
GET /usersс поиском (search), фильтрами по статусу или промо-группе. Для детальной карточки использоватьGET /users/{id}(в качестве ID можно использовать как внутренний user.id, так и telegram_id пользователя). - Операции с подпиской — использовать
POST /subscriptions/{id}/...эндпоинты для продления, выдачи трафика и устройств. - Поддержка — список тикетов (
GET /tickets), изменение статуса (POST /tickets/{id}/status), блокировка ответов (POST /tickets/{id}/reply-block). - История операций —
GET /transactionsс фильтрами по пользователю, типу и периоду.
8. CORS, безопасность и логирование
- Разрешённые домены указываются в
WEB_API_ALLOWED_ORIGINS. Для нескольких доменов перечислите их через запятую. - Для продакшена рекомендуется отключить публичную документацию (
WEB_API_DOCS_ENABLED=false). WEB_API_REQUEST_LOGGING=trueдобавляет middleware, которое логирует метод, путь и статус ответа. Используйте его для аудита или отключите в продакшене, если хватает reverse-proxy логов.- Все токены хранятся в базе в хешированном виде. Не храните открытые значения в коде.
9. Диагностика проблем
| Симптом | Возможная причина | Что проверить |
|---|---|---|
| 401 Unauthorized | Неверный или просроченный токен. | Пересоздайте токен через /tokens и обновите UI. |
| 403/404 при работе с настройками | Неверный ключ настройки. | Получите список доступных ключей через GET /settings. |
| 422 Unprocessable Entity | Неверный тип данных в теле запроса. | Проверьте типы (числа, булевы, строки) и формат JSON. |
| API не стартует | Порт занят или неверные переменные окружения. | Проверьте логи контейнера бота и значения WEB_API_HOST/PORT. |
10. Рекомендации по эксплуатации
- Регулярно ревизируйте список активных токенов и отключайте неиспользуемые.
- Для внешних админок размещайте API за reverse-proxy (nginx, Caddy, Traefik) с TLS.
- Включите мониторинг доступности (например, curl на
/health) в систему наблюдения. - Обновляйте бота и админку синхронно, чтобы использовать новые поля API.