diff --git a/README.md b/README.md index 4df1591..f430941 100644 --- a/README.md +++ b/README.md @@ -18,25 +18,38 @@ Remnawave Minishop - Telegram-бот и Web App (Mini App) для продажи Для администраторов: -- админ-панель для пользователей из `ADMIN_IDS`; +- админ-панель для пользователей из `ADMIN_IDS` (только при входе через Telegram, не для аккаунтов только с email); - статистика пользователей, подписок, платежей и синхронизации с Remnawave; +- список пользователей с поиском, фильтрами и колонкой premium-трафика; - блокировка пользователей, рассылки, промокоды, логи действий и настройка разрешенных параметров приложения поверх `.env`; - редактор JSON-каталога тарифов с period/traffic-моделями, Internal Squads, premium-сквадами и HWID-пакетами; - ручная синхронизация пользователей и подписок с панелью. ## Документация -- [Настройка окружения](docs/configuration.md) - основные переменные `.env`, платежи, Remnawave, пробный период и секреты. +- [Настройка окружения](docs/configuration.md) - основные переменные `.env`, платежи, Remnawave, пробный период, SMTP для email-входа и секреты. - [Тарифы](docs/tariffs.md) - каталог тарифов, period- и traffic-модели, обычные и premium-докупки, premium-сквады, смена тарифа, HWID-лимиты и обработка трафика. - [Админ-панель](docs/admin.md) - права доступа, настройки, редактор тарифов, premium-сквады и сохранение JSON-каталога. - [Web App / Mini App](docs/webapp.md) - отдельный порт, домен, Telegram OAuth, email-вход и реферальные ссылки. -- [Развертывание](docs/deployment.md) - Docker Compose, reverse proxy, Nginx, Caddy, вебхуки и запуск из образа. +- [Развертывание](docs/deployment.md) - Docker Compose, reverse proxy, Nginx, Caddy, вебхуки, запуск из образа и обновление версии (`IMAGE_TAG`). - [Миграция с remnawave-tg-shop](docs/migration-to-minishop.md) - перенос данных из прежнего стека. ## Совместимость Интеграция с API панели Remnawave (вебхуки, пользователи, подписки, статистика в админке и т.д.) **протестирована** на панели Remnawave версии **`> 2.7.0`**. Более старые версии могут работать частично или не работать из‑за изменений в API. +## Стек + +Сборка и runtime задаются **Dockerfile** и **docker-compose.yml**; точные версии пакетов — в **requirements.txt** и **package.json**. + +| Слой | Технологии | +| --- | --- | +| Backend | Python **3.12**, [aiogram](https://docs.aiogram.dev/) 3.x (Telegram), **aiohttp** (HTTP и Web App), **SQLAlchemy** 2 async, **asyncpg**, **Pydantic** / pydantic-settings, **httpx**, платёжные SDK (в т.ч. YooKassa, aiocryptopay), **PyJWT** | +| Данные | **PostgreSQL** **17** (сервис `remnawave-minishop-db` в Compose) | +| Сборка Web App | **Node.js** **22**, **Svelte** **5**, **Vite**, **Tailwind CSS** 4; артефакты попадают в шаблоны `bot/app/web/templates/` | + +Локальная разработка без Docker возможна при установленных Python 3.12, PostgreSQL и (для пересборки фронта) Node 22; типичный сценарий — всё через Compose. + ## Быстрый старт Требования: diff --git a/docs/admin.md b/docs/admin.md index 272d711..6e24843 100644 --- a/docs/admin.md +++ b/docs/admin.md @@ -1,17 +1,35 @@ # Админ-панель Web App -Админ-панель доступна пользователям, чей Telegram ID указан в `ADMIN_IDS`. В Web App такие пользователи видят раздел администрирования; все API `/api/admin/*` дополнительно проверяют сессию и `ADMIN_IDS` на сервере. +Админ-панель доступна пользователям, чей Telegram ID указан в `ADMIN_IDS`. В Web App такие пользователи видят раздел администрирования; все API `/api/admin/*` дополнительно проверяют сессию и `ADMIN_IDS` на сервере. Доступ проверяется по **Telegram ID**, сохранённому у записи пользователя в базе: аккаунт только с email без привязки Telegram не получит права администратора, даже если его идентификатор ошибочно указан в `ADMIN_IDS`. ## Возможности - дашборд со статистикой пользователей, платежей и синхронизации с Remnawave; -- список пользователей, карточка активной подписки, обычный и premium-трафик, платежи и действия; +- список пользователей с поиском, фильтрами и колонкой premium-трафика; карточка пользователя с активной подпиской, обычным и premium-трафиком, платежами и действиями (подробнее в разделе «Пользователи» ниже); - блокировка пользователей, рассылки, промокоды и просмотр логов; - ручная синхронизация с Remnawave; - редактор разрешенных настроек приложения из manifest-файла; - редактор 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 из `bot/app/web/admin_settings_manifest.py`. Даже администратор не может менять через UI произвольные атрибуты `Settings`. diff --git a/docs/configuration.md b/docs/configuration.md index 6dbb6c0..af299c2 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -102,9 +102,11 @@ docker compose -f docker-compose-dev.yml up -d --build --force-recreate | `WEBAPP_SESSION_SECRET` | HMAC-секрет сессий Web App. | | `TELEGRAM_OAUTH_CLIENT_ID` / `TELEGRAM_OAUTH_CLIENT_SECRET` | Данные Telegram OAuth / OpenID Connect из BotFather. | | `TELEGRAM_OAUTH_REQUEST_ACCESS` | Дополнительные разрешения Telegram Login, например `write`. | -| `SMTP_HOST`, `SMTP_PORT`, `SMTP_FALLBACK_PORTS` | SMTP-подключение для email-кодов. | +| `SMTP_HOST`, `SMTP_PORT`, `SMTP_FALLBACK_PORTS` | SMTP-подключение для email-кодов; резервные порты перебираются при ошибке основного. | +| `SMTP_TIMEOUT_SECONDS` | Таймаут одной попытки подключения и отправки. | +| `SMTP_STARTTLS` / `SMTP_USE_SSL` | STARTTLS на обычном порту (например 587) и SSL-обёртка (часто порт 465). | | `SMTP_USERNAME` / `SMTP_PASSWORD` | Логин и пароль или SMTP key. | -| `SMTP_FROM_EMAIL` / `SMTP_FROM_NAME` | Отправитель писем с кодом. | +| `SMTP_FROM_EMAIL` / `SMTP_FROM_NAME` | Отправитель писем с кодом; адрес из `SMTP_FROM_EMAIL` должен быть разрешён у провайдера. | | `EMAIL_CODE_TTL_SECONDS` | Срок действия email-кода. | | `EMAIL_CODE_RESEND_SECONDS` | Пауза перед повторной отправкой кода. | | `EMAIL_CODE_MAX_ATTEMPTS` | Максимум попыток ввода одного кода. | @@ -115,6 +117,23 @@ docker compose -f docker-compose-dev.yml up -d --build --force-recreate Настройка домена, BotFather и callback URL описана в [webapp.md](webapp.md). +### SMTP и вход по email + +Вход по email в Web App включается только если заполнены все обязательные поля SMTP: **`SMTP_HOST`**, **`SMTP_PORT`**, **`SMTP_USERNAME`**, **`SMTP_PASSWORD`**, **`SMTP_FROM_EMAIL`**. Имя отправителя **`SMTP_FROM_NAME`** необязательно. Пока конфигурация неполная, интерфейс входа по email не показывается. + +Рекомендуемый типичный вариант — **порт 587** с **STARTTLS** (`SMTP_STARTTLS=True`, `SMTP_USE_SSL=False`), как в примере для Brevo в `.env.example`. Для **порта 465** обычно используют обёртку SSL: выставьте `SMTP_USE_SSL=True` и при необходимости `SMTP_STARTTLS=False`; приложение также считает порт 465 SSL-режимом автоматически при отправке. + +Если основной порт недоступен, перебираются порты из **`SMTP_FALLBACK_PORTS`** (список через запятую, после `SMTP_PORT`). Таймаут одной попытки подключения и отправки задаёт **`SMTP_TIMEOUT_SECONDS`**. + +Порядок действий при подключении нового SMTP: + +1. В панели почтового провайдера создайте SMTP-доступ и подтвердите адрес отправителя (**from**), совпадающий с `SMTP_FROM_EMAIL`. +2. Перенесите хост, порт, логин и пароль (или API-ключ SMTP) в `.env`. +3. Перезапустите контейнер приложения, чтобы подхватить переменные. +4. Проверьте вход: на странице Web App запросите код на почту; при ошибках смотрите логи контейнера. + +Для ограничений по частоте отправки кодов см. `EMAIL_CODE_*` и `BRUTE_FORCE_*` в таблице выше. + ## Пробный период | Переменная | Назначение | diff --git a/docs/deployment.md b/docs/deployment.md index 8e7bf9b..0f84dd9 100644 --- a/docs/deployment.md +++ b/docs/deployment.md @@ -19,6 +19,85 @@ IMAGE_TAG=3.1.0 docker compose -f docker-compose-remote-server.yml up -d `docker-compose-remote-server.yml` можно использовать как шаблон и заменить `image:` на нужный образ. По умолчанию используется `ghcr.io/3252a8/remnawave-minishop:latest`. +## Обновление версии + +Образ приложения: `ghcr.io/3252a8/remnawave-minishop`. Тег задаётся переменной окружения **`IMAGE_TAG`** (в Compose подставляется как `${IMAGE_TAG:-latest}`). Для продакшена разумно закрепить **конкретный тег релиза** вместо `latest`, чтобы обновляться осознанно и иметь откат. + +**Запуск из готового образа** (`docker-compose-remote-server.yml` или свой файл с тем же шаблоном): + +1. Сделайте резервную копию базы (особенно перед крупными обновлениями) — см. раздел «Резервная копия и восстановление PostgreSQL» ниже на этой странице. +2. Укажите нужный тег, например в `.env`: `IMAGE_TAG=3.2.0` (или экспортируйте переменную перед командой). +3. Подтяните образ и пересоздайте контейнер приложения (БД при этом не удаляется, том данных сохраняется): + +```bash +docker compose -f docker-compose-remote-server.yml pull remnawave-minishop +docker compose -f docker-compose-remote-server.yml up -d --no-deps remnawave-minishop +``` + +При необходимости перезапустите оба сервиса: `docker compose -f docker-compose-remote-server.yml up -d`. Флаг `--force-recreate` добавляют, если нужно гарантированно пересоздать контейнер при неизменённом образе. + +**Локальная сборка из репозитория** (ваш `Dockerfile`): + +```bash +git pull +docker compose up -d --build +``` + +После обновления проверьте логи (`docker compose logs -f remnawave-minishop`), работу бота, вебхуков и Web App. Совместимость с панелью Remnawave — см. раздел «Совместимость» в [README.md](../README.md). + +## Резервная копия и восстановление PostgreSQL + +Имя контейнера БД в типичном Compose — `remnawave-minishop-db`. Подставьте значения **`POSTGRES_USER`** и **`POSTGRES_DB`** из `.env` (на хосте можно выполнить `set -a && source .env && set +a` перед командами или подставить вручную). + +### Резервная копия (текстовый SQL) + +Логическое дампирование в один файл: + +```bash +docker exec remnawave-minishop-db pg_dump -U "$POSTGRES_USER" "$POSTGRES_DB" > backup.sql +``` + +Такой файл удобно хранить вне сервера. При необходимости добавьте к `pg_dump` параметры сжатия или расписание через cron. + +### Восстановление из `backup.sql` + +Дамп выше — **обычный текст SQL** без удаления существующих объектов. Чтобы накатить его на **чистую** базу с тем же именем: + +1. Остановите приложение, чтобы не было записей в БД: + +```bash +docker compose -f docker-compose-remote-server.yml stop remnawave-minishop +``` + +(или ваш файл Compose без `-f`, если работаете из каталога проекта.) + +2. Удалите базу и создайте пустую с тем же именем — пользователь из `.env` в официальном образе PostgreSQL обычно суперпользователь и может это сделать: + +```bash +docker exec remnawave-minishop-db dropdb -U "$POSTGRES_USER" "$POSTGRES_DB" --if-exists +docker exec remnawave-minishop-db createdb -U "$POSTGRES_USER" "$POSTGRES_DB" +``` + +Если `dropdb` сообщает, что база занята, убедитесь, что остановлен сервис `remnawave-minishop` и к базе нет других подключений. + +3. Восстановите данные из файла на хосте: + +```bash +docker exec -i remnawave-minishop-db psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" < backup.sql +``` + +4. Запустите приложение снова: + +```bash +docker compose -f docker-compose-remote-server.yml start remnawave-minishop +``` + +Проверьте логи и работу бота. При ошибках импорта убедитесь, что версия приложения совместима со схемой в дампе (после обновлений бота иногда нужны шаги из changelog релиза). + +### Замечание про «накат поверх» без пересоздания БД + +Если нужно применить дамп к уже заполненной базе без `dropdb`, создавайте резервные копии с **`pg_dump --clean --if-exists`** — в файл попадут команды `DROP` перед `CREATE`, и `psql` сможет перезаписать объекты. Это разрушительно для текущих данных; перед таким сценарием сделайте отдельный свежий бэкап. + ## Порты | Порт | Назначение | diff --git a/docs/webapp.md b/docs/webapp.md index 6a5146c..4ba384f 100644 --- a/docs/webapp.md +++ b/docs/webapp.md @@ -14,7 +14,7 @@ Web App запускается в том же контейнере, что и б - реферальную ссылку и статистику приглашений; - привязку email и Telegram к одному аккаунту. -Для администраторов из `ADMIN_IDS` Web App также показывает админ-панель: статистику, пользователей, рассылки, промокоды, логи, настройки и редактор тарифов. Подробности: [admin.md](admin.md). +Для администраторов из `ADMIN_IDS` Web App также показывает админ-панель: статистику, **пользователей** (поиск, фильтры, premium-трафик), рассылки, промокоды, логи, настройки и редактор тарифов. Подробности: [admin.md](admin.md). ## Настройки `.env` @@ -74,6 +74,8 @@ Email-вход работает через одноразовый код: Для Brevo обычно подходит порт `587` с STARTTLS. Если основной порт недоступен, приложение пробует порты из `SMTP_FALLBACK_PORTS`; порт `465` используется через SSL. +Полный список переменных, обязательные поля для включения email-входа и типичные ошибки подключения описаны в разделе **SMTP и вход по email** в [configuration.md](configuration.md). + ## Проксирование Web App должен проксироваться отдельно от вебхуков: