v2.0
This commit is contained in:
848
README.md
848
README.md
@@ -1,115 +1,785 @@
|
||||
# OreolRP Subscription Bot
|
||||
# OREOL VPN Bot
|
||||
|
||||
Telegram-бот для продажи подписок на **aiogram 3.x** с поддержкой нескольких языков.
|
||||
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`
|
||||
- форматирование дат
|
||||
- форматирование трафика
|
||||
- форматирование карточек доступа
|
||||
|
||||
## Структура проекта
|
||||
|
||||
```
|
||||
botyobshik/
|
||||
├── main.py # Точка входа
|
||||
├── requirements.txt # Зависимости
|
||||
├── .env # Конфигурация (не в git)
|
||||
├── .env.example # Пример конфигурации
|
||||
├── README.md # Документация
|
||||
├── config/
|
||||
│ └── __init__.py # Загрузка настроек из .env
|
||||
├── core/
|
||||
│ └── __init__.py # Работа с БД (авто-создание)
|
||||
├── handlers/
|
||||
│ └── __init__.py # Обработчики команд
|
||||
├── keyboards/
|
||||
│ └── __init__.py # Клавиатуры
|
||||
└── locales/
|
||||
├── __init__.py # Локализация
|
||||
├── ru.json # Русский
|
||||
├── en.json # English
|
||||
└── kz.json # Қазақша
|
||||
```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
|
||||
|
||||
1. **Установите зависимости:**
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
docker compose up --build
|
||||
```
|
||||
|
||||
2. **Создайте `.env` файл:**
|
||||
Это полный запуск вместе с 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
|
||||
```
|
||||
|
||||
3. **Настройте `.env`:**
|
||||
```ini
|
||||
BOT_TOKEN=1234567890:AAH...
|
||||
DB_HOST=localhost
|
||||
DB_USER=root
|
||||
DB_PASSWORD=ваш_пароль
|
||||
DB_NAME=botyobshik
|
||||
SUPPORT_USERNAME=@support_username
|
||||
На Windows PowerShell:
|
||||
|
||||
```powershell
|
||||
Copy-Item .env.example .env
|
||||
```
|
||||
|
||||
4. **Запустите бота:**
|
||||
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` можно не менять вручную.
|
||||
|
||||
MariaDB в текущем `docker-compose.yml` не публикуется наружу на хост, чтобы база не торчала во внешний интернет по `3306`. Бот подключается к ней по внутренней Docker-сети через hostname `db`.
|
||||
|
||||
#### Первый запуск
|
||||
|
||||
Запустите сборку и контейнеры:
|
||||
|
||||
```bash
|
||||
python main.py
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
🎉 База данных и таблицы создадутся **автоматически**!
|
||||
Будут подняты два сервиса:
|
||||
|
||||
## Возможности
|
||||
- `db` — MariaDB 11.7
|
||||
- `bot` — приложение на Python
|
||||
|
||||
- ✅ Авто-создание БД и таблиц
|
||||
- ✅ Команда `/start` с меню
|
||||
- ✅ Проверка статуса подписки
|
||||
- ✅ Покупка подписки (тарифы)
|
||||
- ✅ Техподдержка
|
||||
- ✅ Правила сервиса
|
||||
- ✅ Смена языка (RU/EN/KZ)
|
||||
- ✅ Асинхронная работа с БД
|
||||
- ✅ Конфигурация через `.env`
|
||||
Полный сценарий для Ubuntu Server обычно выглядит так:
|
||||
|
||||
## Редактирование
|
||||
|
||||
### Переменные окружения (`.env`)
|
||||
| Переменная | Описание |
|
||||
|------------|----------|
|
||||
| `BOT_TOKEN` | Токен от @BotFather |
|
||||
| `DB_HOST` | Хост MySQL |
|
||||
| `DB_USER` | Пользователь MySQL |
|
||||
| `DB_PASSWORD` | Пароль MySQL |
|
||||
| `DB_NAME` | Имя базы данных |
|
||||
| `SUPPORT_USERNAME` | Контакт поддержки |
|
||||
|
||||
### Тексты и кнопки
|
||||
Все тексты редактируются в `locales/*.json`:
|
||||
|
||||
| Ключ | Описание |
|
||||
|------|----------|
|
||||
| `welcome` | Приветствие |
|
||||
| `subscription_active/inactive` | Статусы подписки |
|
||||
| `buttons.*` | Текст кнопок (buy, support, rules, language, back) |
|
||||
| `messages.rules_title` | Заголовок правил |
|
||||
| `messages.rules_text` | Текст правил (многострочный) |
|
||||
| `messages.support` | Сообщение поддержки |
|
||||
| `messages.select_tariff` | Выбор тарифа |
|
||||
| `tariffs.*` | Названия тарифов |
|
||||
| `languages.*` | Названия языков |
|
||||
|
||||
### Пример редактирования правил
|
||||
|
||||
Откройте `locales/ru.json` и измените:
|
||||
|
||||
```json
|
||||
"messages": {
|
||||
"rules_title": "📜 Правила сервиса",
|
||||
"rules_text": "1. Первое правило\n2. Второе правило\n3. Третье правило"
|
||||
}
|
||||
```bash
|
||||
git clone <URL_репозитория> telegabot
|
||||
cd telegabot
|
||||
cp .env.example .env
|
||||
nano .env
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
Используйте `\n` для переноса строки.
|
||||
#### Как проверить, что всё поднялось
|
||||
|
||||
## База данных
|
||||
Посмотреть список контейнеров:
|
||||
|
||||
При запуске бот автоматически создаёт:
|
||||
- Базу данных `botyobshik`
|
||||
- Таблицу `subscriptions` (подписки)
|
||||
- Таблицу `user_languages` (языки пользователей)
|
||||
```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`
|
||||
|
||||
Если хотите открыть 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`
|
||||
- открытие раздела подписки через кнопку в панели
|
||||
- ввод реферального кода
|
||||
- отправку чека
|
||||
- подтверждение оплаты модератором
|
||||
- выдачу ссылки пользователю
|
||||
- поддержку через тикет
|
||||
|
||||
Reference in New Issue
Block a user