Files
remnawave-bedolaga-telegram…/docs/web-admin-integration.md
2025-12-05 09:56:03 +03:00

25 KiB
Raw Permalink Blame History

Интеграция веб-админки

Этот документ описывает запуск встроенного административного веб-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, убедитесь, что одновременно заданы две переменные окружения:

  1. WEB_API_ENABLED=true — включает само веб-API.
  2. WEB_API_DOCS_ENABLED=true — публикует /docs, /doc (редирект для старых ссылок), /redoc и /openapi.json.

После изменения значений перезапустите бота. Интерфейс будет доступен по адресу http://<WEB_API_HOST>:<WEB_API_PORT>/docs.

3. Подготовка базы данных

  1. Убедитесь, что настройки БД верны (DATABASE_URL или параметры PostgreSQL/SQLite).
  2. При старте бота автоматически запускается универсальная миграция run_universal_migration, которая:
    • создаёт таблицу web_api_tokens, если её нет;
    • активирует токен из WEB_API_DEFAULT_TOKEN, если он задан.
  3. Если нужно запустить миграцию вручную, выполните:
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. Сценарий интеграции веб-админки

  1. Health-check — перед авторизацией UI вызывает GET /health, чтобы отобразить статус и версию бота.
  2. Настройки UI — подгружает категории через GET /settings/categories, далее выводит форму со значениями из GET /settings.
  3. Статистика дашбордаGET /stats/overview для карточек с показателями.
  4. Раздел пользователиGET /users с поиском (search), фильтрами по статусу или промо-группе. Для детальной карточки использовать GET /users/{id} (в качестве ID можно использовать как внутренний user.id, так и telegram_id пользователя).
  5. Операции с подпиской — использовать POST /subscriptions/{id}/... эндпоинты для продления, выдачи трафика и устройств.
  6. Поддержка — список тикетов (GET /tickets), изменение статуса (POST /tickets/{id}/status), блокировка ответов (POST /tickets/{id}/reply-block).
  7. История операций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.