Админ-панель 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/*.
Блок Ссылки карточки (и в Web App, и в карточке пользователя Telegram-админки) показывает ссылку подписки из панели, публичную ссылку инструкции установки /s/<token> (если включены встроенные инструкции и у пользователя есть активная подписка) и реферальные ссылки — их удобно копировать, когда нужно помочь пользователю с подключением.
Настройки
Заголовок раздела «Настройки»Раздел Система -> Настройки позволяет менять приложение без редактирования .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, PayKilla, LAVA, Pally, CloudPayments, Stripe и Stars, а также текст и иконки кнопок оплаты;
- пробный период, приветственный реферальный бонус, уведомления, логирование, Telegram антифлуд, поддержка, раздел устройств, лимит устройств и legacy-лимиты трафика.
Секретные поля помечены как secret и не должны использоваться для произвольного просмотра старых значений. Настройки, которых нет в manifest, остаются только в .env или коде.
Переключатель Регистрация только по приглашению находится в Система -> Настройки -> Общие. Когда он включён, новые пользователи создаются только после перехода по валидной реферальной ссылке Telegram/Web App; существующие Telegram, WebApp/OAuth, email-code, magic-link и password пользователи продолжают входить без реферального параметра.
Для каждого платежного метода в разделе провайдера доступны настройки отображения 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.ts) через модалку в админке.
Раздел Система -> Бэкапы показывает архивы из data/backups, принимает upload ZIP-файла и запускает восстановление БД/compose-папки с предварительной проверкой архива. Подробная эксплуатационная инструкция: бэкапы и восстановление.
Промокоды
Заголовок раздела «Промокоды»Раздел Промокоды управляет кодами для мгновенных бонусов и checkout-скидок. В Web App админке доступны новые режимы промокодов: скидка в процентах, множитель срока подписки, множитель выдаваемого трафика, бонусные дни сразу или после оплаты, область применения, минимальный срок/объем покупки и история активаций.
Админка показывает Telegram/Web App ссылки для каждого кода и вкладку активаций с платежом, суммой скидки и фактически выданными днями или GB. Массовое создание в Telegram-админке остается быстрым legacy-сценарием для бонусных дней; расширенные эффекты настраиваются здесь.
Подробности по режимам и ограничениям: промокоды.
Переводы
Заголовок раздела «Переводы»Раздел Система -> Переводы позволяет переопределять отдельные строки из 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-файл есть, но его нельзя перезаписать, сохранение отклоняется, чтобы БД не разъехалась с главным файлом.
Формат файла:
Инструкции подключения
Заголовок раздела «Инструкции подключения»Секция Система -> Настройки -> Инструкции подключения управляет встроенным экраном установки. 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_*. Подробности: поддержка пользователей / тикеты.
Внешний вид
Заголовок раздела «Внешний вид»Раздел Внешний вид объединяет настройки бренда и темы 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.
Раздел Система -> Тарифы работает с файлом 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и переключатель «Докупка доступна всегда» (topup_always_available); по умолчанию докупка появляется у пользователя после 80% расхода лимита. Дляtrafficотдельные докупки не нужны, пользователь повторно покупает пакеты изtraffic_packages; - Premium: названия premium-раздела RU/EN, premium Internal Squads, месячный premium-лимит, RUB/Stars пакеты premium-докупки и отдельный переключатель «Докупка доступна всегда» (
premium_topup_always_available) для 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.