12 KiB
Админ-панель Web App
Админ-панель доступна пользователям, чей Telegram ID указан в ADMIN_IDS. В Web App такие пользователи видят раздел администрирования; все API /api/admin/* дополнительно проверяют сессию и ADMIN_IDS на сервере. Доступ проверяется по Telegram ID, сохранённому у записи пользователя в базе: аккаунт только с email без привязки Telegram не получит права администратора, даже если его идентификатор ошибочно указан в ADMIN_IDS.
Возможности
- дашборд со статистикой пользователей, платежей и синхронизации с Remnawave;
- список пользователей с поиском, фильтрами и колонкой premium-трафика; карточка пользователя с активной подпиской, обычным и premium-трафиком, платежами и действиями (подробнее в разделе «Пользователи» ниже);
- блокировка пользователей, входящий список тикетов поддержки, рассылки, промокоды и просмотр логов;
- ручная синхронизация с Remnawave;
- редактор разрешенных настроек приложения из manifest-файла;
- раздел Внешний вид для логотипа, emoji-логотипа, выбора темы, accent-цвета, масштаба логотипа и предпросмотра тем;
- редактор JSON-каталога тарифов;
- загрузка Internal Squads из Remnawave для выбора в тарифах.
Пользователи
Раздел Пользователи — таблица с пагинацией по 25 записей. Строка поиска ищет по внутреннему числовому ID, Telegram ID, фрагменту @username, имени или email; применение — кнопка «Найти» или клавиша Enter в поле поиска.
Фильтры:
- состояние аккаунта: все / не забанены / забанены;
- наличие Telegram или email;
- связь с панелью Remnawave (
panel_user_uuid); - статус подписки в панели для активной подписки в базе бота: active, expired, limited;
- premium-трафик: все; без лимита premium в тарифе; безлимитный оверрайд; норма (ниже 85% квоты); предупреждение (от 85% до 100%); исчерпана квота.
Сортировка: по дате регистрации, имени, ID, а также по доле использования premium-квоты (если у активной подписки есть конечный premium-лимит).
В колонке premium для конечной квоты показывается израсходовано относительно лимита; лимит складывается из базовой premium-квоты тарифа, докупок и бонусов. Отображение не опирается на служебный флаг «limited» в базе как на признак «есть premium-трафик» — он отражает другую семантику на стороне панели.
Карточка пользователя по переходу из списка объединяет просмотр подписки, трафика, платежей и действий (блокировка, сообщения, продление, оверрайды и т.д.) в соответствии с доступными эндпоинтами /api/admin/users/*.
Настройки
Раздел Система -> Настройки позволяет менять приложение без редактирования .env, но только в пределах allowlist из backend/bot/app/web/admin_settings_manifest.py. Даже администратор не может менять через UI произвольные атрибуты Settings.
Изменения сохраняются как overrides в базе данных и применяются поверх .env без перезапуска. Если значение сброшено, снова используется значение из .env. После сохранения публичный кеш настроек Web App сбрасывается, поэтому пользователи видят изменения при следующих запросах.
В manifest сейчас входят:
- общие параметры: язык, валюта, ссылки поддержки, документы, обязательный канал, Remnawave-доступы и поведение
/start; - внешний вид и доступность Web App: название, цвет, логотип, emoji-логотип и
WEBAPP_ENABLED; - legacy-цены без JSON-каталога: периоды подписки, RUB/Stars цены и пакеты трафика;
- платежные провайдеры: включение методов, порядок кнопок, публичные параметры и секреты YooKassa, FreeKassa, Platega, SeverPay, Wata, CryptoPay, Heleket и Stars, а также текст и иконки кнопок оплаты;
- пробный период, реферальные бонусы, уведомления, логирование, поддержка, раздел устройств, лимит устройств и legacy-лимиты трафика.
Секретные поля помечены как secret и не должны использоваться для произвольного просмотра старых значений. Настройки, которых нет в manifest, остаются только в .env или коде.
Для каждого платежного метода в разделе провайдера доступны presentation-настройки PAYMENT_<METHOD>_WEBAPP_LABEL_RU, PAYMENT_<METHOD>_WEBAPP_LABEL_EN, PAYMENT_<METHOD>_WEBAPP_ICON, PAYMENT_<METHOD>_TELEGRAM_LABEL_RU, PAYMENT_<METHOD>_TELEGRAM_LABEL_EN и PAYMENT_<METHOD>_TELEGRAM_EMOJI. Пустое значение возвращает мультиязычный дефолт из модуля платежного провайдера. Иконка Web App выбирается из уже подключённых lucide-иконок (frontend/src/lib/components/ui/icons.js) через модалку в админке.
Поддержка
Раздел Коммуникации -> Поддержка показывает входящий список тикетов из Mini App. В списке доступны фильтры по статусу, приоритету, категории и назначенному администратору, поиск по теме и пользователю, сортировка по обновлению, созданию или важности.
В карточке тикета администратор видит диалог, пользовательский контекст и действия: ответить пользователю, оставить внутреннюю заметку, изменить статус, приоритет, категорию или исполнителя, закрыть тикет и перейти в карточку пользователя. Внутренние заметки не показываются пользователю.
Счетчик непрочитанных обращений отображается в навигации админки. Уведомления о новых тикетах и ответах пользователя настраиваются через LOG_SUPPORT, LOG_SUPPORT_THREAD_ID и параметры SUPPORT_*. Подробности: support.md.
Внешний вид
Раздел Внешний вид объединяет настройки бренда и темы Web App. Логотип можно загрузить файлом или по HTTPS-ссылке; backend сохраняет файл в data/webapp-logo/uploads и подставляет локальный URL. Если включен emoji-логотип, картинка скрывается, а для emoji можно выбрать системный, Twemoji, Noto Color, animated Noto и другие варианты отрисовки.
В блоке тем админка читает каталог из WEBAPP_THEMES_DIR, показывает встроенные и кастомные темы, позволяет выбрать текущую тему, изменить accent, включить или выключить тему для админки и настроить масштаб логотипа на главной и экране входа. Кнопка предпросмотра открывает /home?theme_preview=<key> и не меняет глобальную тему до сохранения.
Подробный формат theme.json, CSS/asset-роуты и пошаговый пайплайн создания новой темы описаны в webapp-themes.md.
Тарифы
Раздел Система -> Тарифы работает с файлом TARIFFS_CONFIG_PATH (по умолчанию data/tariffs.json). При сохранении backend валидирует payload через TariffsConfig, пишет JSON в UTF-8 и сбрасывает кеш публичных данных Web App.
Если файла еще нет, админка открывает пустой каталог. Перед сохранением должен быть хотя бы один включенный тариф, а default_tariff должен ссылаться на включенный тариф.
Редактор тарифа разделен на вкладки:
- Основное: ключ, модель
period/traffic, видимость, названия и описания RU/EN, базовые Internal Squads, HWID-лимит, месячный лимит или курс конвертации; - Цены: периоды и цены для
period, пакеты GB и цены дляtraffic; - Докупки: обычные пакеты докупки трафика для
period; дляtrafficотдельные докупки не нужны, пользователь повторно покупает пакеты изtraffic_packages; - Premium: названия premium-раздела RU/EN, premium Internal Squads, месячный premium-лимит и RUB/Stars пакеты premium-докупки;
- Устройства: RUB/Stars пакеты докупки HWID-устройств.
Базовые и premium Internal Squads выбираются из Remnawave через /api/admin/panel/internal-squads. Если панель недоступна, можно сохранить уже существующие UUID в JSON, но выпадающий список не загрузится.
Практические замечания
Не меняйте key опубликованного тарифа без миграции активных подписок: подписки, платежи и смена тарифа ссылаются на этот ключ.
Отключенный тариф исчезает с витрины, но активные подписки с его tariff_key продолжают существовать. Удаление тарифа безопасно только если не осталось активных подписок, которым нужна докупка, продление или смена с этого тарифа.
Для Docker важно, чтобы путь TARIFFS_CONFIG_PATH был доступен на запись контейнеру. Если каталог ./data смонтирован в /app/data, админка может сохранять data/tariffs.json.