83 lines
11 KiB
Markdown
83 lines
11 KiB
Markdown
# Админ-панель 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 сейчас входят:
|
||
|
||
- общие параметры: язык, валюта, ссылки поддержки, документы, обязательный канал и поведение `/start`;
|
||
- внешний вид и доступность Web App: название, цвет, логотип, emoji-логотип и `WEBAPP_ENABLED`;
|
||
- legacy-цены без JSON-каталога: периоды подписки, RUB/Stars цены и пакеты трафика;
|
||
- платежные провайдеры: включение методов, порядок кнопок, публичные параметры и секреты YooKassa, FreeKassa, Platega, SeverPay, Wata, CryptoPay и 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`) через модалку в админке.
|
||
|
||
## Внешний вид
|
||
|
||
Раздел **Внешний вид** объединяет настройки бренда и темы 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](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`.
|