- FastAPI REST API with JWT auth - aiogram 3 Telegram bot with admin middleware - APScheduler daily tasks (expiry, reminders, revoke, sync) - SQLAlchemy 2 async ORM with Alembic migrations - Jinja2 admin panel (Dashboard, Users, Payments, Servers, Tariffs) - VPN provider abstraction with MockProvider - Stats service with revenue/subscription analytics - Docker Compose (PostgreSQL + Redis + app) - Healthcheck endpoint
277 lines
8.0 KiB
Markdown
277 lines
8.0 KiB
Markdown
# VPN Control Panel
|
||
|
||
Система управления VPN-подписками: регистрация пользователей, тарифы, платежи,
|
||
Telegram-бот, административная панель и фоновые задачи.
|
||
|
||
## Стек
|
||
|
||
- **Python 3.13** / **FastAPI** + Uvicorn
|
||
- **SQLAlchemy 2** (async) + asyncpg
|
||
- **PostgreSQL 16** / **Redis 7**
|
||
- **Alembic** — миграции БД
|
||
- **aiogram 3** — Telegram-бот
|
||
- **APScheduler** — фоновые задачи
|
||
- **Jinja2** — админ-панель
|
||
- **Docker** / **Docker Compose**
|
||
|
||
## Структура
|
||
|
||
```
|
||
├── app/
|
||
│ ├── api/v1/ # REST API endpoints (users, payments, tariffs, servers, auth, stats)
|
||
│ ├── admin/ # Административная панель (Jinja2)
|
||
│ ├── bot/ # Telegram bot (handlers, middleware, dispatcher)
|
||
│ ├── models/ # SQLAlchemy ORM модели
|
||
│ ├── providers/ # VPN-провайдеры (абстракция + Mock)
|
||
│ ├── repositories/ # Слой доступа к данным (CRUD)
|
||
│ ├── scheduler/ # Фоновые задачи (APScheduler)
|
||
│ ├── schemas/ # Pydantic схемы запросов/ответов
|
||
│ ├── services/ # Бизнес-логика
|
||
│ └── utils/ # Вспомогательные функции
|
||
├── docker/
|
||
│ ├── Dockerfile # Production-сборка
|
||
│ ├── Dockerfile.dev # Dev-сборка
|
||
│ └── entrypoint.sh # Точка входа (миграции + uvicorn)
|
||
├── migrations/ # Alembic миграции
|
||
├── tests/ # Тесты
|
||
├── .env.example
|
||
├── docker-compose.yml
|
||
└── docker-compose.dev.yml
|
||
```
|
||
|
||
## Быстрый старт
|
||
|
||
### 1. Запуск через Docker (рекомендуется)
|
||
|
||
```bash
|
||
cp .env.example .env
|
||
# Отредактируйте .env (BOT_TOKEN, JWT_SECRET и т.д.)
|
||
docker compose up -d
|
||
```
|
||
|
||
Приложение будет доступно на `http://localhost:8000`.
|
||
|
||
### 2. Локальный запуск для разработки
|
||
|
||
```bash
|
||
# Только БД и Redis
|
||
docker compose -f docker-compose.dev.yml up -d
|
||
|
||
# Python окружение
|
||
python -m venv .venv
|
||
source .venv/bin/activate
|
||
pip install -r requirements.dev.txt
|
||
|
||
# Миграции
|
||
alembic upgrade head
|
||
|
||
# Запуск
|
||
uvicorn app.main:app --reload --port 8000
|
||
```
|
||
|
||
## Миграции
|
||
|
||
Создание новой миграции:
|
||
|
||
```bash
|
||
alembic revision --autogenerate -m "description"
|
||
```
|
||
|
||
Применение миграций:
|
||
|
||
```bash
|
||
alembic upgrade head
|
||
```
|
||
|
||
Откат на одну:
|
||
|
||
```bash
|
||
alembic downgrade -1
|
||
```
|
||
|
||
## Создание администратора
|
||
|
||
Администратор создаётся напрямую в БД. Telegram ID — ваш числовой ID в Telegram.
|
||
|
||
```bash
|
||
docker compose exec app python -c "
|
||
import asyncio
|
||
from app.database import async_session_factory
|
||
from app.repositories.admin import AdminRepository
|
||
from app.models.admin import AdminRole
|
||
|
||
async def create():
|
||
async with async_session_factory() as session:
|
||
repo = AdminRepository(session)
|
||
admin = await repo.create(
|
||
telegram_id=123456789, # Ваш Telegram ID
|
||
username='admin',
|
||
role=AdminRole.SUPERADMIN,
|
||
is_active=True,
|
||
)
|
||
print(f'Admin created: id={admin.id} tg={admin.telegram_id}')
|
||
|
||
asyncio.run(create())
|
||
"
|
||
```
|
||
|
||
## Настройка Telegram
|
||
|
||
1. Создайте бота через [@BotFather](https://t.me/BotFather), получите токен.
|
||
2. Укажите токен в `.env`: `BOT_TOKEN=ваш_токен`.
|
||
3. Узнайте свой Telegram ID (например, через @userinfobot).
|
||
4. Добавьте его в БД через скрипт выше.
|
||
5. Запустите — бот ответит на команды только администраторам из БД.
|
||
|
||
Команды бота:
|
||
|
||
```
|
||
/start — приветствие
|
||
/help — список команд
|
||
/users — список активных пользователей
|
||
/user <id> — информация о пользователе
|
||
/delete <id> — деактивация пользователя
|
||
/renew <id> — статус подписки
|
||
/expired — список просроченных подписок
|
||
/expiring [N] — истекают в ближайшие N дней (по умолч. 3)
|
||
/stats — статистика системы
|
||
```
|
||
|
||
## Пример .env
|
||
|
||
```env
|
||
APP_NAME=VPN Control Panel
|
||
DEBUG=false
|
||
PORT=8000
|
||
|
||
POSTGRES_USER=vpn
|
||
POSTGRES_PASSWORD=vpn_secret
|
||
POSTGRES_DB=vpn_control
|
||
POSTGRES_HOST=db
|
||
POSTGRES_PORT=5432
|
||
|
||
REDIS_URL=redis://redis:6379/0
|
||
|
||
BOT_TOKEN=123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11
|
||
ADMIN_IDS=[123456789]
|
||
ADMIN_GROUP_ID=-1001234567890
|
||
ADMIN_GROUP_THREAD_ID=
|
||
|
||
JWT_SECRET=случайная_строка_32_символа
|
||
JWT_ACCESS_EXPIRE_MINUTES=30
|
||
JWT_REFRESH_EXPIRE_DAYS=30
|
||
|
||
OUTLINE_API_PREFIX=https://example.com:1234/abc123
|
||
OUTLINE_CERT_SHA256=sha256hash...
|
||
```
|
||
|
||
## Пример API
|
||
|
||
Авторизация:
|
||
|
||
```bash
|
||
# Логин (secret_key = JWT_SECRET из .env)
|
||
curl -X POST http://localhost:8000/api/v1/auth/login \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"telegram_id": 123456789, "secret_key": "change_me_to_random_string"}'
|
||
|
||
# Ответ:
|
||
# {"access_token": "...", "refresh_token": "...", "token_type": "bearer"}
|
||
```
|
||
|
||
Пользователи:
|
||
|
||
```bash
|
||
# Список (требуется Bearer token)
|
||
curl http://localhost:8000/api/v1/users \
|
||
-H "Authorization: Bearer <access_token>"
|
||
|
||
# Создать
|
||
curl -X POST http://localhost:8000/api/v1/users \
|
||
-H "Authorization: Bearer <access_token>" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"telegram_id": 987654321, "username": "user", "full_name": "User Name"}'
|
||
```
|
||
|
||
Тарифы:
|
||
|
||
```bash
|
||
curl http://localhost:8000/api/v1/tariffs
|
||
# [{"id":1,"name":"Basic","duration_days":30,"price":500.0,"currency":"RUB",...}]
|
||
```
|
||
|
||
Платежи:
|
||
|
||
```bash
|
||
curl -X POST http://localhost:8000/api/v1/payments \
|
||
-H "Authorization: Bearer <access_token>" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"user_id": 1, "tariff_id": 1, "amount": 500, "provider": "manual"}'
|
||
|
||
# Подтвердить платёж (активирует подписку)
|
||
curl -X PATCH http://localhost:8000/api/v1/payments/1/confirm \
|
||
-H "Authorization: Bearer <access_token>"
|
||
```
|
||
|
||
Статистика:
|
||
|
||
```bash
|
||
curl http://localhost:8000/api/v1/stats
|
||
# {"total_users":5,"active_users":3,"total_revenue":2500.0,...}
|
||
```
|
||
|
||
Административная панель:
|
||
|
||
```
|
||
http://localhost:8000/admin/ — Dashboard
|
||
http://localhost:8000/admin/users — Пользователи
|
||
http://localhost:8000/admin/payments — Платежи
|
||
http://localhost:8000/admin/servers — Серверы
|
||
http://localhost:8000/admin/tariffs — Тарифы
|
||
```
|
||
|
||
Healthcheck:
|
||
|
||
```bash
|
||
curl http://localhost:8000/health
|
||
# {"status":"ok","database":"connected"}
|
||
```
|
||
|
||
Документация API (Swagger):
|
||
|
||
```
|
||
http://localhost:8000/docs
|
||
http://localhost:8000/redoc
|
||
```
|
||
|
||
## Архитектура
|
||
|
||
```
|
||
Client → FastAPI (REST / Admin)
|
||
↓
|
||
Service Layer
|
||
↓
|
||
Repository Layer
|
||
↓
|
||
PostgreSQL / Redis
|
||
↓
|
||
Telegram Bot ← aiogram ← APScheduler (daily tasks)
|
||
```
|
||
|
||
- **Service Layer** — бизнес-логика, не содержит SQL.
|
||
- **Repository Layer** — только CRUD, без логики.
|
||
- Сервисы не вызывают друг друга — оркестрация на уровне handler.
|
||
- Telegram-бот не содержит бизнес-логики — только отображение.
|
||
- Scheduler не содержит Telegram-кода — только вызовы сервисов.
|
||
|
||
## Планы
|
||
|
||
- WireGuard / Outline / XRay провайдеры
|
||
- Онлайн-оплата (ЮKassa, Stripe)
|
||
- Рассылка уведомлений
|
||
- Dashboard с графиками
|
||
|
||
## Лицензия
|
||
|
||
MIT
|