Skip to content

Системная архитектура

┌─────────────────────────────────┐
│ Пользователь │
└────────────┬────────────────────┘
│ HTTPS
┌────────────▼────────────────────┐
│ Traefik (TLS) │
└──┬──────────────────────────┬───┘
│ │
┌────────────▼───────────┐ ┌──────────▼──────────┐
│ Frontend (React SPA) │ │ Backend API (Go) │
│ / │ │ /api/v1/... │
│ /dashboard │ │ │
│ /admin │ │ Fiber HTTP Server │
└───────────────────────┘ │ JWT Auth │
│ WebSocket (metrics) │
└──┬───────────────────┘
┌─────────────────┼─────────────────┐
│ │ │
┌────────▼──────┐ ┌───────▼───────┐ ┌─────▼──────┐
│ PostgreSQL │ │ Redis │ │ Asynq │
│ (основная │ │ (кэш, │ │ Worker │
│ БД) │ │ pub/sub) │ │ │
└───────────────┘ └───────────────┘ └─────┬──────┘
│ gRPC
┌───────────────────┼──────────────┐
│ │ │
┌────────▼──────┐ ┌─────────▼─────┐ │
│ Node 1 │ │ Node 2 │ ... │
│ (NL / DE) │ │ (US / NYC) │ │
│ │ │ │ │
│ Xray-core │ │ Xray-core │ │
│ Агент (Go) │ │ Агент (Go) │ │
└───────────────┘ └───────────────┘ │

Статические файлы, отдаются Traefik / nginx. Три зоны:

  • Лендинг (/) — публичная, описание сервиса, тарифы, FAQ
  • Личный кабинет (/dashboard) — статус подписки, subscription link, устройства
  • Админ-панель (/admin) — управление нодами, пользователями, тарифами, статистика

Единый сервис. Отвечает за:

  • REST API для фронтенда
  • WebSocket endpoint для realtime-метрик в админке
  • HTTP endpoint для subscription link (отдаёт конфиг для VPN-клиентов)
  • Запуск Asynq воркеров

Запускается внутри того же Go-процесса (отдельная горутина). Обрабатывает задачи:

  • sync:user — синхронизировать пользователя на все его ноды через gRPC
  • sync:node — синхронизировать всех активных пользователей на новую ноду
  • check:expired — крон, проверяет истёкшие подписки и отзывает доступ

Лёгкий gRPC-сервер на каждой ноде. Умеет:

  • Добавить / удалить / изменить клиента в Xray inbound
  • Вернуть статистику трафика по тегу
  • Вернуть метрики системы (CPU, RAM, connections)
  • Применить новый конфиг инбаунда

Регистрация + первый вход

Section titled “Регистрация + первый вход”
Пользователь → POST /api/v1/auth/register
→ Создаётся users + user_credentials (генерируется UUID)
→ Создаётся subscription_links токен
→ Если есть активная подписка (промокод/триал) → enqueue sync:user
→ Агент на нодах получает gRPC вызов → Xray добавляет UUID в inbound
Крон check:expired (каждые 5 минут)
→ Находит subscriptions WHERE expires_at < NOW() AND status = 'active'
→ UPDATE status = 'expired'
→ enqueue sync:user для каждого
→ Агент удаляет UUID из всех inbound-ов → трафик блокируется

Сбор статистики трафика

Section titled “Сбор статистики трафика”
Крон collect:traffic (каждые 5 минут)
→ gRPC GetStats к каждой ноде
→ INSERT INTO traffic_snapshots
→ UPSERT daily_traffic (UPDATE bytes += delta)
→ UPDATE subscriptions SET traffic_used_bytes

На начальном этапе всё работает в одном docker-compose на одном VPS. При росте:

  • Бэкенд горизонтально масштабируется (stateless, сессии в Redis)
  • Воркеры можно вынести в отдельный процесс
  • PostgreSQL → managed (RDS, Supabase) или read replica
  • Ноды добавляются через админку без downtime