Skip to content

Структура фронтенда

frontend/
├── public/
│ └── locales/ # JSON файлы переводов (i18next)
│ ├── en/
│ └── ru/
├── src/
│ ├── app/ # Инициализация приложения
│ │ ├── main.tsx
│ │ ├── router.tsx # TanStack Router — все маршруты
│ │ └── providers.tsx # QueryClient, i18n, Toaster и т.д.
│ │
│ ├── pages/ # Страницы (один файл = один маршрут)
│ │ ├── landing/
│ │ │ ├── index.tsx
│ │ │ ├── sections/
│ │ │ │ ├── Hero.tsx
│ │ │ │ ├── Features.tsx
│ │ │ │ ├── Pricing.tsx
│ │ │ │ └── FAQ.tsx
│ │ │ └── components/
│ │ ├── auth/
│ │ │ ├── login.tsx
│ │ │ └── register.tsx
│ │ ├── dashboard/
│ │ │ ├── index.tsx # Обзор подписки
│ │ │ ├── subscription.tsx # Детали + subscription link
│ │ │ └── devices.tsx # Список устройств / сессий
│ │ └── admin/
│ │ ├── index.tsx # Dashboard с метриками
│ │ ├── users/
│ │ │ ├── index.tsx # Таблица пользователей
│ │ │ └── [id].tsx # Детальная страница
│ │ ├── nodes/
│ │ │ ├── index.tsx
│ │ │ └── [id].tsx
│ │ ├── plans/
│ │ │ └── index.tsx
│ │ └── settings/
│ │ └── index.tsx
│ │
│ ├── components/ # Переиспользуемые компоненты
│ │ ├── ui/ # shadcn/ui компоненты (auto-generated)
│ │ ├── layout/
│ │ │ ├── DashboardLayout.tsx
│ │ │ ├── AdminLayout.tsx
│ │ │ └── LandingLayout.tsx
│ │ └── shared/
│ │ ├── TrafficChart.tsx
│ │ ├── NodeStatusBadge.tsx
│ │ ├── SubscriptionLinkCard.tsx
│ │ └── DataTable.tsx # Переиспользуемая таблица с сортировкой
│ │
│ ├── api/ # API слой
│ │ ├── client.ts # Axios instance + interceptors (refresh token)
│ │ ├── auth.ts
│ │ ├── users.ts
│ │ ├── nodes.ts
│ │ ├── plans.ts
│ │ └── stats.ts
│ │
│ ├── hooks/ # Кастомные хуки (TanStack Query)
│ │ ├── useAuth.ts
│ │ ├── useNodes.ts
│ │ ├── useSubscription.ts
│ │ └── useRealtimeStats.ts # WebSocket хук
│ │
│ ├── store/ # Zustand stores
│ │ ├── auth.store.ts
│ │ └── ui.store.ts
│ │
│ ├── lib/ # Утилиты
│ │ ├── utils.ts # cn(), formatBytes(), formatDate()
│ │ └── constants.ts
│ │
│ └── types/ # TypeScript типы
│ ├── api.ts # Типы ответов API
│ └── models.ts # User, Node, Plan, Subscription...
├── index.html
├── vite.config.ts
├── tailwind.config.ts
├── tsconfig.json
└── package.json

TanStack Router с файловой структурой маршрутов. Защищённые маршруты через beforeLoad:

// Все /dashboard/* и /admin/* маршруты проверяют токен
// /admin/* дополнительно проверяют role === 'admin'
Путь Компонент Доступ
/ LandingPage Публичный
/login LoginPage Гость
/register RegisterPage Гость
/dashboard DashboardOverview Auth
/dashboard/subscription SubscriptionPage Auth
/admin AdminDashboard Admin
/admin/users UsersPage Admin
/admin/users/:id UserDetailPage Admin
/admin/nodes NodesPage Admin
/admin/nodes/:id NodeDetailPage Admin
/admin/plans PlansPage Admin
/sub/:token Публичный (subscription endpoint)
1. POST /api/v1/auth/login → { access_token, refresh_token }
2. access_token хранится в памяти (Zustand)
3. refresh_token — в httpOnly cookie
4. Axios interceptor: если 401 → POST /api/v1/auth/refresh → повторяет запрос
5. При выходе → DELETE /api/v1/auth/logout (инвалидирует refresh в БД)

В AdminDashboard и NodeDetailPage подключается WebSocket:

ws://api/admin/ws/stats

Сервер пушит каждые 5 секунд JSON с текущими метриками по всем нодам. Хук useRealtimeStats обновляет локальный стейт, графики перерисовываются автоматически.

Пользователь получает ссылку вида:

https://your-domain.com/sub/TOKEN

При GET-запросе бэкенд генерирует и отдаёт application/x-www-form-urlencoded или base64 YAML — формат, который понимают все популярные VPN-клиенты.