Describe LAVA Business configuration: env keys, webhook URL and signature scheme, RUB-only invoices, and the include-services filter. Mention LAVA in the provider lists of the README, admin panel page, and tariff currency matrix.
138 lines
19 KiB
Markdown
138 lines
19 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-файла;
|
||
- раздел **Внешний вид** для логотипа, выбора темы, accent-цвета, масштаба логотипа и предпросмотра тем;
|
||
- раздел **Инструкции подключения** для встроенной страницы установки, поведения кнопок бота и Remnawave Subscription Page config;
|
||
- раздел **Бэкапы** для просмотра локальных ZIP-архивов, загрузки архива и восстановления БД/compose-папки;
|
||
- редактор JSON-каталога тарифов;
|
||
- загрузка Internal Squads из Remnawave для выбора в тарифах.
|
||
|
||
## Пользователи
|
||
|
||
Раздел **Пользователи** — таблица с **пагинацией по 25 записей**. Строка поиска ищет по внутреннему числовому ID, Telegram ID, фрагменту `@username`, имени или email; применение — кнопка «Найти» или клавиша Enter в поле поиска.
|
||
|
||
Из этого же раздела администратор управляет основными пользовательскими операциями:
|
||
|
||
- просматривает подписку, статус, трафик, premium-лимиты, платежи и служебные события;
|
||
- блокирует пользователя;
|
||
- запускает ручную синхронизацию с Remnawave Panel;
|
||
- открывает тикеты поддержки и отвечает пользователю.
|
||
|
||
**Фильтры:**
|
||
|
||
- состояние аккаунта: все / не забанены / забанены;
|
||
- наличие 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: название, цвет, логотип и `WEBAPP_ENABLED`;
|
||
- инструкции подключения: `SUBSCRIPTION_GUIDES_ENABLED`, `SUBSCRIPTION_GUIDES_BOT_MENU_ENABLED`, чтение конфига из Remnawave Panel, JSON-переопределение и резервный путь к файлу;
|
||
- legacy-тарифы без JSON-каталога: периоды подписки, RUB/Stars цены, реферальные бонусы и пакеты трафика;
|
||
- платежные провайдеры: включение методов, порядок кнопок, публичные параметры и секреты YooKassa, FreeKassa, Platega, SeverPay, Wata, CryptoPay, Heleket, LAVA и Stars, а также текст и иконки кнопок оплаты;
|
||
- пробный период, приветственный реферальный бонус, уведомления, логирование, Telegram антифлуд, поддержка, раздел устройств, лимит устройств и legacy-лимиты трафика.
|
||
|
||
Секретные поля помечены как secret и не должны использоваться для произвольного просмотра старых значений. Настройки, которых нет в manifest, остаются только в `.env` или коде.
|
||
|
||
Для каждого платежного метода в разделе провайдера доступны настройки отображения `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`) через модалку в админке.
|
||
|
||
## Бэкапы
|
||
|
||
Раздел **Система -> Бэкапы** показывает архивы из `data/backups`, принимает upload ZIP-файла и запускает восстановление БД/compose-папки с предварительной проверкой архива. Подробная эксплуатационная инструкция: [бэкапы и восстановление](backups.md).
|
||
|
||
## Переводы
|
||
|
||
Раздел **Система -> Переводы** позволяет переопределять отдельные строки из `locales/ru.json` и `locales/en.json` без монтирования полного файла локализации. Строки сгруппированы по месту применения: админка, Mini App, Telegram-бот, платежи, подписки, поддержка и другие группы.
|
||
|
||
В разделе строки разделены по аудитории: пользовательские тексты Mini App/бота/платежей и внутренние тексты админки, логов и синхронизации. Дополнительные языки можно добавлять прямо в интерфейсе по коду локали, например `uk`, `de` или `pt-BR`; для таких языков оверрайды хранятся без отдельного базового файла локали, а отсутствующие строки берутся из языка по умолчанию.
|
||
|
||
Файл `data/locales-overrides.json` считается источником правды, а таблица `locale_overrides` хранит его DB-зеркало. Если валидный JSON-файл есть, при старте backend и worker полностью синхронизируют БД с файлом, включая удаления строк. Если файл отсутствует, но каталог доступен для записи, он автоматически создается из текущих DB-оверрайдов или как пустой `{}`. Если файл не примонтирован, недоступен или временно сломан по JSON, используется fallback из БД. Сохранение из админки записывает полный итоговый снапшот и в JSON-файл, и в БД; если активный JSON-файл есть, но его нельзя перезаписать, сохранение отклоняется, чтобы БД не разъехалась с главным файлом.
|
||
|
||
Формат файла:
|
||
|
||
```json
|
||
{
|
||
"ru": {
|
||
"menu_personal_account_button": "Личный кабинет"
|
||
},
|
||
"en": {
|
||
"menu_personal_account_button": "Account"
|
||
}
|
||
}
|
||
```
|
||
|
||
## Инструкции подключения
|
||
|
||
Секция **Система -> Настройки -> Инструкции подключения** управляет встроенным экраном установки. `SUBSCRIPTION_GUIDES_ENABLED` включает `/install` в личном кабинете, а `SUBSCRIPTION_GUIDES_BOT_MENU_ENABLED` заставляет кнопки подключения в Telegram-боте открывать Mini App вместо финальной Remnawave Subscription Page. Оба переключателя включены по умолчанию.
|
||
|
||
По умолчанию Minishop читает конфиг Remnawave Subscription Page из панели (`SUBSCRIPTION_PAGE_CONFIG_PANEL_ENABLED=True`). Это основной режим, потому что один и тот же конфиг используется и в панели, и во встроенной инструкции. JSON-поле `SUBSCRIPTION_PAGE_CONFIG_JSON` применяется только когда явно включен `SUBSCRIPTION_PAGE_CONFIG_JSON_OVERRIDE_ENABLED`; иначе оно может храниться в админке, но не влияет на пользователей. `SUBSCRIPTION_PAGE_CONFIG_PATH` остается резервным путем к локальному v1 JSON-файлу, если конфиг панели отключен или недоступен.
|
||
|
||
При сохранении backend валидирует JSON-переопределение как конфиг Remnawave Subscription Page v1. Ошибки показываются как обычные ошибки валидации настроек, а если рабочий конфиг недоступен, пользовательская кнопка подключения откатывается к старой финальной ссылке подписки.
|
||
|
||
## Поддержка
|
||
|
||
Раздел **Коммуникации -> Поддержка** показывает входящий список тикетов из Mini App. В списке доступны фильтры по статусу, приоритету, категории и назначенному администратору, поиск по теме и пользователю, сортировка по обновлению, созданию или важности.
|
||
|
||
В карточке тикета администратор видит диалог, пользовательский контекст и действия: ответить пользователю, оставить внутреннюю заметку, изменить статус, приоритет, категорию или исполнителя, закрыть тикет и перейти в карточку пользователя. Внутренние заметки не показываются пользователю.
|
||
|
||
Счетчик непрочитанных обращений отображается в навигации админки. Уведомления о новых тикетах и ответах пользователя настраиваются через `LOG_SUPPORT`, `LOG_SUPPORT_THREAD_ID` и параметры `SUPPORT_*`. Подробности: [поддержка пользователей / тикеты](support.md).
|
||
|
||
## Внешний вид
|
||
|
||
Раздел **Внешний вид** объединяет настройки бренда и темы Web App. Логотип можно загрузить файлом или по HTTPS-ссылке; backend сохраняет файл в `data/webapp-logo/uploads` и подставляет локальный URL. Если логотип не задан, показывается логотип проекта по умолчанию. Favicon генерируется из логотипа или загружается отдельно.
|
||
|
||
Этот же бренд используется в HTML-письмах. Загруженный локальный логотип встраивается в письмо как inline image (`cid:webapp-logo`), поэтому email-клиенту не нужен прямой доступ к `/webapp-uploaded-logo/...`. Логотип по публичной HTTPS-ссылке остается внешней картинкой в письме.
|
||
|
||
В блоке тем админка читает каталог из `WEBAPP_THEMES_DIR`, показывает встроенные и кастомные темы, позволяет выбрать текущую тему, изменить accent, включить или выключить тему для админки и настроить отдельный масштаб логотипа для desktop и mobile layout. Кнопка предпросмотра открывает `/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-устройств.
|
||
|
||
Порядок периодов, traffic-пакетов, обычных докупок, premium-докупок и HWID-пакетов меняется перетаскиванием строк в редакторе. Этот порядок сохраняется в JSON и используется на витрине Web App и в Telegram-боте.
|
||
|
||
Базовые и premium Internal Squads выбираются из Remnawave через `/api/admin/panel/internal-squads`. Если панель недоступна, можно сохранить уже существующие UUID в JSON, но выпадающий список не загрузится.
|
||
|
||
## Практические замечания
|
||
|
||
Не меняйте `key` опубликованного тарифа без миграции активных подписок: подписки, платежи и смена тарифа ссылаются на этот ключ.
|
||
|
||
Отключенный тариф исчезает с витрины, но активные подписки с его `tariff_key` продолжают существовать. Удаление тарифа безопасно только если не осталось активных подписок, которым нужна докупка, продление или смена с этого тарифа.
|
||
|
||
Для Docker важно, чтобы путь `TARIFFS_CONFIG_PATH` был доступен на запись контейнеру. Если каталог `./data` смонтирован в `/app/data`, админка может сохранять `data/tariffs.json`.
|