818 lines
28 KiB
Markdown
818 lines
28 KiB
Markdown
# OREOL VPN Bot
|
||
|
||
Telegram-бот на `aiogram 3` с интеграцией в `Remnawave API`, локальным кэшем в `MariaDB`, пользовательской панелью, тикетами поддержки, реферальной системой и ручной оплатой с подтверждением админом.
|
||
|
||
Этот README написан как рабочий handoff-документ: по нему можно поднять проект, понять текущую архитектуру и продолжить разработку в новой сессии без восстановления контекста по кускам.
|
||
|
||
## Что умеет бот
|
||
|
||
- Показывает стартовую панель пользователя через `/start`
|
||
- Подтягивает аккаунты Remnawave по `telegramId`
|
||
- Хранит локальный кэш пользователей и истории подписок в MariaDB
|
||
- Поддерживает привязку существующего аккаунта Remnawave по `short_uuid`
|
||
- Показывает профиль, статус подписки, срок и трафик
|
||
- Работает с реферальными кодами и скидкой перед оплатой
|
||
- Поддерживает ручную оплату переводом с отправкой чека в бот
|
||
- Отправляет чек в отдельный Telegram-канал/топик на проверку
|
||
- Даёт админу или модератору подтвердить или отклонить оплату
|
||
- После подтверждения создаёт или продлевает доступ в Remnawave
|
||
- Поддерживает тикеты в отдельный канал и ответы только от админа/модератора
|
||
- Показывает админам отдельную Telegram-панель с метриками и быстрыми действиями
|
||
|
||
## Текущий сценарий оплаты
|
||
|
||
Сейчас в проекте не используется Telegram Stars. Оплата работает вручную:
|
||
|
||
1. Пользователь нажимает `Купить подписку`
|
||
2. Бот показывает список тарифов из `PAYMENT_PLANS`
|
||
3. Если у пользователя применён реферальный код, скидка учитывается до выбора тарифа
|
||
4. После выбора тарифа бот показывает реквизиты из `PAYMENT_TRANSFER_TEXT`
|
||
5. Пользователь отправляет чек следующим сообщением в бота
|
||
6. Бот пересылает чек в review-чат оплаты
|
||
7. Админ или модератор нажимает `Подтвердить` или `Отклонить`
|
||
8. При подтверждении бот создаёт или продлевает доступ в Remnawave и отправляет пользователю подписку
|
||
|
||
### Тарифы
|
||
|
||
Тарифы задаются одной переменной:
|
||
|
||
```env
|
||
PAYMENT_PLANS=30:250,180:600,365:1000
|
||
```
|
||
|
||
Формат:
|
||
|
||
- `дни:цена_в_рублях`
|
||
- элементы разделяются запятой
|
||
|
||
Пример выше означает:
|
||
|
||
- 30 дней = 250 ₽
|
||
- 180 дней = 600 ₽
|
||
- 365 дней = 1000 ₽
|
||
|
||
### Логин в Remnawave
|
||
|
||
Логин создаётся в формате:
|
||
|
||
```text
|
||
Oreol-<telegram_id>-<username>
|
||
```
|
||
|
||
Пример:
|
||
|
||
```text
|
||
Oreol-591220249-slkes
|
||
```
|
||
|
||
Если username отсутствует, используется `first_name`, а если и его нет, то `user`.
|
||
|
||
Важно:
|
||
|
||
- логин обрезается до 36 символов, чтобы соответствовать ограничениям Remnawave
|
||
- повторная покупка у того же пользователя не должна создавать новый логин, а должна продлевать уже существующий доступ
|
||
|
||
## Важное замечание по базе
|
||
|
||
Если таблица `payment_orders` уже была создана старой версией проекта, в ней мог остаться `UNIQUE` на `provision_username`.
|
||
|
||
Для текущей логики это неверно, потому что один и тот же логин может использоваться в нескольких заказах одного пользователя при продлении.
|
||
|
||
Правильное состояние:
|
||
|
||
- в ORM `provision_username` обычный индекс без `UNIQUE`
|
||
- в `sql/schema.sql` тоже без `UNIQUE`
|
||
|
||
Если таблица уже существует в MariaDB, может потребоваться вручную убрать старое уникальное ограничение.
|
||
|
||
## Архитектура
|
||
|
||
### Основные слои
|
||
|
||
- `app/main.py`
|
||
- инициализация приложения
|
||
- подключение к БД
|
||
- создание клиента Remnawave
|
||
- создание `SyncService`, `SupportTicketService`, `PaymentService`
|
||
- запуск aiogram
|
||
|
||
- `app/config.py`
|
||
- все настройки из `.env`
|
||
- парсинг ID админов и модераторов
|
||
- парсинг ссылок Telegram вида `https://t.me/c/.../.../...`
|
||
- парсинг тарифов оплаты
|
||
|
||
- `app/services/remnawave_client.py`
|
||
- прямой HTTP-клиент к Remnawave API через `httpx`
|
||
- `GET /users/by-telegram-id/{telegramId}`
|
||
- `GET /users/{uuid}`
|
||
- `GET /users/by-short-uuid/{shortUuid}`
|
||
- `GET /users/by-username/{username}`
|
||
- `POST /users`
|
||
- `PATCH /users`
|
||
- `POST /users/resolve`
|
||
- `GET /users`
|
||
- `GET /users/{uuid}/subscription-request-history`
|
||
|
||
- `app/services/sync_service.py`
|
||
- регистрация Telegram-пользователей
|
||
- синхронизация пользователей из Remnawave в MariaDB
|
||
- привязка аккаунтов по `short_uuid`
|
||
- реферальные коды и приглашения
|
||
|
||
- `app/services/payment_service.py`
|
||
- список доступных тарифов
|
||
- создание ручного заказа
|
||
- расчёт скидки по реферальному коду
|
||
- хранение статусов заказа
|
||
- создание нового доступа в Remnawave
|
||
- продление существующего доступа в Remnawave
|
||
|
||
- `app/services/support_ticket_service.py`
|
||
- создание тикетов
|
||
- поиск тикета по support message ID
|
||
- отметка, что тикет обработан
|
||
|
||
- `app/bot/handlers/main.py`
|
||
- все команды и callback-и
|
||
- стартовая панель
|
||
- меню оплаты
|
||
- FSM для тикетов, рефкодов и чека оплаты
|
||
- приём ответа модератора на тикет
|
||
- приём кнопок `Подтвердить / Отклонить` в review-канале оплаты
|
||
|
||
- `app/bot/ui/panel.py`
|
||
- рендер панели пользователя
|
||
- инлайн-кнопки разделов
|
||
- тексты профиля, подписки, рефералки, правил и поддержки
|
||
|
||
- `app/utils/formatters.py`
|
||
- форматирование дат
|
||
- форматирование трафика
|
||
- форматирование карточек доступа
|
||
|
||
## Структура проекта
|
||
|
||
```text
|
||
telegabot/
|
||
├── app/
|
||
│ ├── bot/
|
||
│ │ ├── handlers/
|
||
│ │ │ └── main.py
|
||
│ │ └── ui/
|
||
│ │ └── panel.py
|
||
│ ├── db/
|
||
│ │ ├── base.py
|
||
│ │ ├── models.py
|
||
│ │ └── session.py
|
||
│ ├── schemas/
|
||
│ │ └── remnawave.py
|
||
│ ├── services/
|
||
│ │ ├── payment_service.py
|
||
│ │ ├── remnawave_client.py
|
||
│ │ ├── support_ticket_service.py
|
||
│ │ └── sync_service.py
|
||
│ ├── utils/
|
||
│ │ └── formatters.py
|
||
│ ├── config.py
|
||
│ └── main.py
|
||
├── assets/
|
||
│ └── main.png
|
||
├── sql/
|
||
│ └── schema.sql
|
||
├── tests/
|
||
│ ├── test_config.py
|
||
│ ├── test_formatters.py
|
||
│ ├── test_panel_ui.py
|
||
│ └── test_remnawave_client.py
|
||
├── .env.example
|
||
├── docker-compose.yml
|
||
├── Dockerfile
|
||
├── main.py
|
||
├── pyproject.toml
|
||
├── README.md
|
||
└── run.bat
|
||
```
|
||
|
||
## Команды бота
|
||
|
||
### Пользовательские
|
||
|
||
- `/start` — открыть стартовую панель
|
||
|
||
### Админские
|
||
|
||
- `Админ-панель` в UI — сводка по боту, поиск пользователя, полная синхронизация, быстрые переходы в рабочие чаты
|
||
- `/lookup <uuid|id|username|short_uuid>` — найти и синхронизировать пользователя
|
||
- `/sync_all` — массовая синхронизация пользователей Remnawave в MariaDB
|
||
|
||
## База данных
|
||
|
||
### Основные таблицы
|
||
|
||
- `telegram_users`
|
||
- Telegram-пользователи, взаимодействовавшие с ботом
|
||
|
||
- `remnawave_users`
|
||
- локальный кэш пользователей Remnawave
|
||
|
||
- `internal_squads`
|
||
- справочник внутренних групп
|
||
|
||
- `remnawave_user_internal_squads`
|
||
- связь many-to-many пользователей и групп
|
||
|
||
- `subscription_request_logs`
|
||
- история запросов подписки
|
||
|
||
- `support_tickets`
|
||
- тикеты поддержки
|
||
|
||
- `referral_codes`
|
||
- персональные коды пользователей
|
||
|
||
- `referral_invites`
|
||
- кто кого пригласил
|
||
|
||
- `referral_bonuses`
|
||
- начисленные и ожидающие применения бонусы реферерам
|
||
|
||
- `payment_orders`
|
||
- ручные платежи, статусы и выданные доступы
|
||
|
||
### Статусы заказов оплаты
|
||
|
||
Сейчас используются:
|
||
|
||
- `PENDING` — заказ создан, чек ещё не отправлен
|
||
- `REVIEW` — чек отправлен на проверку
|
||
- `REJECTED` — платёж отклонён модератором
|
||
- `FULFILLED` — доступ выдан или продлён
|
||
|
||
## Реферальная система
|
||
|
||
Что реализовано:
|
||
|
||
- каждому пользователю создаётся персональный код
|
||
- можно сгенерировать ссылку вида `https://t.me/<bot_username>?start=ref_<CODE>`
|
||
- сам переход по ссылке скидку не активирует
|
||
- чтобы получить скидку, пользователь должен вручную ввести код до оплаты
|
||
- размер скидки задаётся в `REFERRAL_DISCOUNT_PERCENT`
|
||
- за каждую подтверждённую оплату по рефкоду реферер получает бонус в днях
|
||
- размер бонуса задаётся в `REFERRAL_BONUS_DAYS`
|
||
|
||
## Тикеты поддержки
|
||
|
||
Сценарий:
|
||
|
||
1. Пользователь открывает раздел `Поддержка`
|
||
2. Нажимает `Создать тикет`
|
||
3. Отправляет следующим сообщением вопрос или описание проблемы
|
||
4. Бот отправляет тикет в support-чат
|
||
5. Админ или модератор отвечает реплаем на сообщение с тикетом
|
||
6. Бот доставляет ответ пользователю в личный чат
|
||
|
||
Доступ к ответу на тикет есть только у:
|
||
|
||
- пользователей из `BOT_ADMIN_IDS`
|
||
- пользователей из `BOT_MODERATOR_IDS`
|
||
|
||
## Переменные окружения
|
||
|
||
Полный шаблон лежит в `.env.example`.
|
||
|
||
Критический минимум для запуска:
|
||
|
||
- `BOT_TOKEN`
|
||
- `REMNAWAVE_BASE_URL`
|
||
- `REMNAWAVE_API_TOKEN`
|
||
- `DB_HOST`
|
||
- `DB_PORT`
|
||
- `DB_NAME`
|
||
- `DB_USER`
|
||
- `DB_PASSWORD`
|
||
- `PAYMENT_INTERNAL_SQUAD_UUIDS`
|
||
|
||
Для полного сценария поддержки и оплаты также нужны:
|
||
|
||
- `BOT_PUBLIC_USERNAME`
|
||
- `BOT_SUPPORT_TICKET_LINK` или `BOT_SUPPORT_TICKET_CHAT_ID`
|
||
- `PAYMENT_TRANSFER_TEXT`
|
||
- `PAYMENT_REVIEW_LINK` или `PAYMENT_REVIEW_CHAT_ID`
|
||
|
||
## Как настроить `.env`
|
||
|
||
1. Скопировать шаблон:
|
||
|
||
```bat
|
||
copy .env.example .env
|
||
```
|
||
|
||
2. Заполнить обязательные значения
|
||
|
||
3. Проверить:
|
||
|
||
- корректен ли `BOT_TOKEN`
|
||
- доступен ли `REMNAWAVE_BASE_URL`
|
||
- валиден ли `REMNAWAVE_API_TOKEN`
|
||
- существует ли MariaDB и есть ли права на создание БД, если `CREATE_DATABASE_ON_START=true`
|
||
- указаны ли реальные UUID групп в `PAYMENT_INTERNAL_SQUAD_UUIDS`
|
||
- указаны ли реальные реквизиты в `PAYMENT_TRANSFER_TEXT`
|
||
|
||
## Пример важных настроек
|
||
|
||
```env
|
||
BOT_BRAND_NAME=OREOL VPN
|
||
BOT_PUBLIC_USERNAME=oreol_vpn_bot
|
||
|
||
DB_HOST=127.0.0.1
|
||
DB_PORT=3306
|
||
DB_NAME=oreolvpn
|
||
DB_USER=oreolvpn
|
||
DB_PASSWORD=strong_password
|
||
|
||
PAYMENT_PLANS=30:250,180:600,365:1000
|
||
PAYMENT_TRANSFER_TEXT=Карта 0000 0000 0000 0000; банк OREOL; получатель OREOL VPN
|
||
PAYMENT_REVIEW_LINK=https://t.me/c/3646494169/56/57
|
||
PAYMENT_INTERNAL_SQUAD_UUIDS=11111111-1111-1111-1111-111111111111
|
||
REFERRAL_DISCOUNT_PERCENT=5
|
||
PAYMENT_USERNAME_PREFIX=Oreol
|
||
```
|
||
|
||
## Поддержка Telegram-ссылок `t.me/c/...`
|
||
|
||
Проект умеет разбирать приватные ссылки Telegram вида:
|
||
|
||
```text
|
||
https://t.me/c/3646494169/56/57
|
||
```
|
||
|
||
Разбор происходит так:
|
||
|
||
- chat id = `-1003646494169`
|
||
- thread id = `56`
|
||
- последний сегмент `57` — это message id, для маршрутизации топика он не нужен
|
||
|
||
Это используется для:
|
||
|
||
- `BOT_SUPPORT_TICKET_LINK`
|
||
- `PAYMENT_REVIEW_LINK`
|
||
|
||
## Как запускать
|
||
|
||
### Вариант 1. Windows через `run.bat`
|
||
|
||
```bat
|
||
run.bat
|
||
```
|
||
|
||
Что делает батник:
|
||
|
||
- переходит в папку проекта
|
||
- проверяет `.env`
|
||
- создаёт `.venv`, если его нет
|
||
- ставит зависимости
|
||
- запускает `main.py`
|
||
|
||
### Вариант 2. Ручной локальный запуск
|
||
|
||
```bat
|
||
py -3 -m venv .venv
|
||
.venv\Scripts\python -m pip install -e .[dev]
|
||
.venv\Scripts\python main.py
|
||
```
|
||
|
||
### Вариант 3. Docker
|
||
|
||
```bash
|
||
docker compose up --build
|
||
```
|
||
|
||
Это полный запуск вместе с MariaDB. База данных уже есть в проекте: сервис `db` описан в `docker-compose.yml`, данные сохраняются в volume `mariadb_data`.
|
||
|
||
#### Что нужно установить заранее
|
||
|
||
- Docker Desktop на Windows/macOS
|
||
- или Docker Engine + Docker Compose plugin на Linux
|
||
|
||
Проверьте, что команды доступны:
|
||
|
||
```bash
|
||
docker --version
|
||
docker compose version
|
||
```
|
||
|
||
#### Ubuntu Server 24.04: установка Docker Engine
|
||
|
||
Для `Ubuntu Server 24.04` рекомендуется ставить Docker Engine из официального Docker-репозитория.
|
||
|
||
1. Обновить пакеты и поставить базовые утилиты:
|
||
|
||
```bash
|
||
sudo apt update
|
||
sudo apt install -y ca-certificates curl git
|
||
```
|
||
|
||
2. Добавить официальный GPG-ключ Docker:
|
||
|
||
```bash
|
||
sudo install -m 0755 -d /etc/apt/keyrings
|
||
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
|
||
sudo chmod a+r /etc/apt/keyrings/docker.asc
|
||
```
|
||
|
||
3. Подключить Docker repository:
|
||
|
||
```bash
|
||
sudo tee /etc/apt/sources.list.d/docker.sources > /dev/null <<EOF
|
||
Types: deb
|
||
URIs: https://download.docker.com/linux/ubuntu
|
||
Suites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}")
|
||
Components: stable
|
||
Architectures: $(dpkg --print-architecture)
|
||
Signed-By: /etc/apt/keyrings/docker.asc
|
||
EOF
|
||
```
|
||
|
||
4. Установить Docker Engine и Compose plugin:
|
||
|
||
```bash
|
||
sudo apt update
|
||
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
||
```
|
||
|
||
5. Включить Docker после перезагрузки:
|
||
|
||
```bash
|
||
sudo systemctl enable docker --now
|
||
```
|
||
|
||
6. Разрешить запуск Docker без `sudo`:
|
||
|
||
```bash
|
||
sudo usermod -aG docker $USER
|
||
```
|
||
|
||
После этого выйдите из SSH-сессии и зайдите снова, либо выполните:
|
||
|
||
```bash
|
||
newgrp docker
|
||
```
|
||
|
||
7. Проверить установку:
|
||
|
||
```bash
|
||
docker --version
|
||
docker compose version
|
||
docker ps
|
||
```
|
||
|
||
Если проект будет стоять на VPS или выделенном сервере, этого достаточно: отдельный Docker Desktop на Linux Server не нужен.
|
||
|
||
#### Что нужно подготовить перед первым запуском
|
||
|
||
1. Скопировать пример конфига:
|
||
|
||
```bash
|
||
cp .env.example .env
|
||
```
|
||
|
||
На Windows PowerShell:
|
||
|
||
```powershell
|
||
Copy-Item .env.example .env
|
||
```
|
||
|
||
2. Открыть `.env` и заполнить обязательные значения:
|
||
|
||
- `BOT_TOKEN`
|
||
- `BOT_ADMIN_IDS`
|
||
- `REMNAWAVE_BASE_URL`
|
||
- `REMNAWAVE_API_TOKEN`
|
||
- `DB_NAME`
|
||
- `DB_USER`
|
||
- `DB_PASSWORD`
|
||
- `DB_ROOT_PASSWORD`
|
||
- `PAYMENT_INTERNAL_SQUAD_UUIDS`
|
||
|
||
Обычно ещё сразу настраивают:
|
||
|
||
- `BOT_PUBLIC_USERNAME`
|
||
- `BOT_SUPPORT_URL`
|
||
- `BOT_SUPPORT_TICKET_LINK` или `BOT_SUPPORT_TICKET_CHAT_ID`
|
||
- `PAYMENT_TRANSFER_TEXT`
|
||
- `PAYMENT_REVIEW_LINK` или `PAYMENT_REVIEW_CHAT_ID`
|
||
|
||
#### Важный момент по базе данных в Docker
|
||
|
||
При запуске через `docker compose` контейнер бота сам получает:
|
||
|
||
```env
|
||
DB_HOST=db
|
||
DB_PORT=3306
|
||
```
|
||
|
||
Это уже задано в `docker-compose.yml`. В `.env` для Docker главное задать:
|
||
|
||
- `DB_NAME`
|
||
- `DB_USER`
|
||
- `DB_PASSWORD`
|
||
- `DB_ROOT_PASSWORD`
|
||
|
||
Если вы запускаете проект только в Docker, `DB_HOST` и `DB_PORT` можно не менять вручную.
|
||
|
||
`DB_ROOT_PASSWORD` нужен только контейнеру MariaDB. Сам бот подключается к базе исключительно через:
|
||
|
||
- `DB_USER`
|
||
- `DB_PASSWORD`
|
||
|
||
Это важно:
|
||
|
||
- `DB_ROOT_PASSWORD` не используется приложением для SQLAlchemy-подключения
|
||
- если в `.env` указать `DB_USER=root`, но оставить `DB_PASSWORD` пустым, бот попытается зайти как `root` без пароля и упадёт с `Access denied`
|
||
|
||
Для production рекомендуется не использовать `root` для бота, а создать отдельного пользователя БД через:
|
||
|
||
- `DB_USER`
|
||
- `DB_PASSWORD`
|
||
|
||
MariaDB в текущем `docker-compose.yml` не публикуется наружу на хост, чтобы база не торчала во внешний интернет по `3306`. Бот подключается к ней по внутренней Docker-сети через hostname `db`.
|
||
|
||
#### Первый запуск
|
||
|
||
Запустите сборку и контейнеры:
|
||
|
||
```bash
|
||
docker compose up -d --build
|
||
```
|
||
|
||
Будут подняты два сервиса:
|
||
|
||
- `db` — MariaDB 11.7
|
||
- `bot` — приложение на Python
|
||
|
||
Полный сценарий для Ubuntu Server обычно выглядит так:
|
||
|
||
```bash
|
||
git clone <URL_репозитория> telegabot
|
||
cd telegabot
|
||
cp .env.example .env
|
||
nano .env
|
||
docker compose up -d --build
|
||
```
|
||
|
||
#### Как проверить, что всё поднялось
|
||
|
||
Посмотреть список контейнеров:
|
||
|
||
```bash
|
||
docker compose ps
|
||
```
|
||
|
||
Посмотреть логи бота:
|
||
|
||
```bash
|
||
docker compose logs -f bot
|
||
```
|
||
|
||
Посмотреть логи базы:
|
||
|
||
```bash
|
||
docker compose logs -f db
|
||
```
|
||
|
||
Проверить, что бот видит базу и база отвечает:
|
||
|
||
```bash
|
||
docker compose exec db mariadb -u"$DB_USER" -p"$DB_PASSWORD" -e "SHOW DATABASES;"
|
||
```
|
||
|
||
Если нужно зайти в MariaDB вручную:
|
||
|
||
```bash
|
||
docker compose exec db mariadb -u"$DB_USER" -p"$DB_PASSWORD" "$DB_NAME"
|
||
```
|
||
|
||
Если всё настроено правильно, сценарий такой:
|
||
|
||
1. поднимается `db`
|
||
2. healthcheck MariaDB становится `healthy`
|
||
3. стартует `bot`
|
||
4. бот при старте создаёт БД и таблицы, если включены:
|
||
- `CREATE_DATABASE_ON_START=true`
|
||
- `CREATE_TABLES_ON_START=true`
|
||
|
||
#### Остановка и повторный запуск
|
||
|
||
Остановить контейнеры:
|
||
|
||
```bash
|
||
docker compose down
|
||
```
|
||
|
||
Запустить снова без пересборки:
|
||
|
||
```bash
|
||
docker compose up -d
|
||
```
|
||
|
||
Пересобрать после изменения кода:
|
||
|
||
```bash
|
||
docker compose up -d --build
|
||
```
|
||
|
||
#### Как удалить всё вместе с базой
|
||
|
||
Если нужен полный сброс, включая MariaDB volume:
|
||
|
||
```bash
|
||
docker compose down -v
|
||
```
|
||
|
||
После этого база будет создана заново при следующем запуске.
|
||
|
||
#### Обновление на Ubuntu Server
|
||
|
||
Если вы обновили код проекта:
|
||
|
||
```bash
|
||
git pull
|
||
docker compose up -d --build
|
||
```
|
||
|
||
Если меняли только `.env`, обычно достаточно:
|
||
|
||
```bash
|
||
docker compose up -d
|
||
```
|
||
|
||
#### Если бот не стартует
|
||
|
||
Проверьте по пунктам:
|
||
|
||
- заполнен ли `BOT_TOKEN`
|
||
- доступен ли `REMNAWAVE_BASE_URL`
|
||
- корректен ли `REMNAWAVE_API_TOKEN`
|
||
- заполнен ли `PAYMENT_INTERNAL_SQUAD_UUIDS`
|
||
- не пустые ли `DB_PASSWORD` и `DB_ROOT_PASSWORD`
|
||
- есть ли у сервиса `db` статус `healthy` в `docker compose ps`
|
||
|
||
Если видите ошибку вида:
|
||
|
||
```text
|
||
Access denied for user 'root' ... (using password: NO)
|
||
```
|
||
|
||
проверьте:
|
||
|
||
- не стоит ли в `.env` `DB_USER=root`
|
||
- не пустой ли `DB_PASSWORD`
|
||
- совпадают ли `DB_USER` и `DB_PASSWORD` с пользователем MariaDB, который был создан при первом старте контейнера
|
||
|
||
Если контейнер `db` уже один раз поднимался с неправильными DB-переменными, volume MariaDB мог сохранить старого пользователя и старый пароль. Тогда есть два варианта:
|
||
|
||
- если данных ещё не жалко: `docker compose down -v` и затем `docker compose up -d --build`
|
||
- если данные нужно сохранить: зайти в MariaDB и вручную создать/выдать права нужному пользователю
|
||
|
||
Если хотите открыть MariaDB наружу для внешнего клиента, это нужно делать осознанно: добавьте `ports` обратно в сервис `db` и отдельно ограничьте доступ через firewall или private network.
|
||
|
||
#### Минимальный сценарий запуска в Docker
|
||
|
||
1. Скопировать `.env.example` в `.env`
|
||
2. Заполнить Telegram, Remnawave и DB-переменные
|
||
3. Выполнить `docker compose up -d --build`
|
||
4. Проверить `docker compose logs -f bot`
|
||
|
||
## Проверка проекта
|
||
|
||
### Синтаксис
|
||
|
||
```bat
|
||
py -3 -m compileall app main.py tests
|
||
```
|
||
|
||
### Тесты
|
||
|
||
```bat
|
||
.venv\Scripts\python -m pytest
|
||
```
|
||
|
||
Если основная `.venv` невалидна из-за переезда проекта между машинами, пересоздай её.
|
||
|
||
## Что уже протестировано
|
||
|
||
Покрыто тестами:
|
||
|
||
- парсинг конфигурации
|
||
- разбор support/review ссылок Telegram
|
||
- парсинг тарифов
|
||
- форматтеры текста
|
||
- UI панели
|
||
- базовые методы `RemnawaveApiClient`
|
||
|
||
Последняя локальная проверка в этой сетевой копии:
|
||
|
||
- `py -3 -m compileall app main.py tests` — успешно
|
||
- `pytest` — `26 passed`
|
||
|
||
## Известные нюансы
|
||
|
||
### 1. Перенос `.venv` между машинами
|
||
|
||
Если скопировать проект вместе с уже готовой `.venv` в другую папку, на другой компьютер или на сетевой диск, окружение может ссылаться на старый путь Python.
|
||
|
||
Типичная ошибка:
|
||
|
||
```text
|
||
did not find executable at ...python.exe
|
||
```
|
||
|
||
Решение:
|
||
|
||
1. удалить `.venv`
|
||
2. создать её заново
|
||
3. снова установить зависимости
|
||
|
||
### 2. Ошибка `Unknown database`
|
||
|
||
Если MariaDB доступна, но самой базы из `DB_NAME` ещё нет, можно увидеть:
|
||
|
||
```text
|
||
OperationalError: (1049, "Unknown database '...'" )
|
||
```
|
||
|
||
Что делать:
|
||
|
||
- оставить `CREATE_DATABASE_ON_START=true`, если у пользователя есть права на создание БД
|
||
- либо создать БД вручную
|
||
|
||
### 3. Прокси Telegram
|
||
|
||
Для `TELEGRAM_PROXY_URL` подходят обычные proxy URL:
|
||
|
||
- `http://user:pass@host:port`
|
||
- `socks5://host:port`
|
||
|
||
Не подходят клиентские ссылки вроде:
|
||
|
||
- `vless://...`
|
||
- `vmess://...`
|
||
- `trojan://...`
|
||
- `tg://proxy?...` для aiogram напрямую
|
||
|
||
### 4. Review-чат оплаты должен быть настроен
|
||
|
||
Если `PAYMENT_REVIEW_LINK` и `PAYMENT_REVIEW_CHAT_ID` пустые, пользователь сможет выбрать тариф, но бот не сможет отправить чек на модерацию.
|
||
|
||
### 5. Internal squads обязательны для выдачи доступа
|
||
|
||
Если `PAYMENT_INTERNAL_SQUAD_UUIDS` пустой, бот не сможет корректно создать доступ в Remnawave.
|
||
|
||
## Безопасность
|
||
|
||
Нельзя публиковать:
|
||
|
||
- реальный `.env`
|
||
- `BOT_TOKEN`
|
||
- `REMNAWAVE_API_TOKEN`
|
||
- `REMNAWAVE_CADDY_API_KEY`
|
||
- банковские реквизиты из рабочего `PAYMENT_TRANSFER_TEXT`
|
||
|
||
Передавать между сессиями безопасно:
|
||
|
||
- код проекта
|
||
- `README.md`
|
||
- `.env.example`
|
||
|
||
## Что логично делать дальше
|
||
|
||
Следующие разумные шаги по проекту:
|
||
|
||
- добавить миграции через Alembic
|
||
- хранить отдельный audit log по модерации оплат
|
||
- сделать уведомление модераторам о новых чеках
|
||
- добавить историю заказов пользователя в панели
|
||
- сделать админ-панель со списком платежей
|
||
- добавить продление конкретного существующего аккаунта по выбору, если у пользователя их несколько
|
||
- добавить отдельный статус `APPROVED_BUT_NOT_DELIVERED`, если бот не смог отправить результат пользователю
|
||
- покрыть тестами `PaymentService` и FSM оплаты
|
||
|
||
## Быстрый handoff
|
||
|
||
Если проект открывает новая сессия, порядок такой:
|
||
|
||
1. Прочитать этот README
|
||
2. Проверить `.env`
|
||
3. Проверить, рабочая ли `.venv`
|
||
4. Убедиться, что доступны MariaDB и Remnawave
|
||
5. Запустить `run.bat` или `python main.py`
|
||
6. Проверить руками:
|
||
- `/start`
|
||
- открытие раздела подписки через кнопку в панели
|
||
- ввод реферального кода
|
||
- отправку чека
|
||
- подтверждение оплаты модератором
|
||
- выдачу ссылки пользователю
|
||
- поддержку через тикет
|