Files
PnvPanel/docs/frontend.md
T

120 lines
9.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Frontend
SPA на **React 19 + Vite + TypeScript**. Общается с бэком по REST (JWT Bearer) и получает
живые обновления по SignalR. Типы API генерируются из OpenAPI-схемы бэкенда.
> **Раздача из единого контейнера.** В проде собранный фронт (`dist/`) кладётся в `wwwroot`
> ASP.NET Core и раздаётся тем же приложением (SPA-fallback на `index.html`). Фронт и бек — один
> origin, база API — относительный `/api`, SignalR — `/hubs/panel`. В dev Vite-сервер проксирует
> `/api` и `/hubs` на бэкенд. Детали упаковки — [architecture.md](architecture.md#развёртывание-единый-контейнер-приложения).
## Стек
| Задача | Выбор |
| ----------------- | --------------------------------------- |
| Сборка/dev | Vite |
| Язык | TypeScript (strict) |
| Данные с сервера | TanStack Query |
| Роутинг | TanStack Router (типобезопасный) |
| UI-компоненты | shadcn/ui + Tailwind CSS v4 |
| Иконки | lucide-react |
| Клиентский стейт | Zustand (auth, тема) |
| Формы | react-hook-form + zod |
| Realtime | @microsoft/signalr |
| Графики | Recharts |
| QR-коды | qrcode.react |
| Типы API | openapi-typescript / orval (codegen) |
| i18n | react-i18next (RU + EN) |
| Пакетный менеджер | pnpm |
## Структура
```
frontend/
src/
app/ # провайдеры (Query, Router, Auth, Theme), корневой layout
routes/ # маршруты TanStack Router (login, dashboard, configs, instructions, admin/*)
features/
auth/ # формы, хуки useLogin/useRegister, стор авторизации
configs/ # список/создание/редактирование/детали конфигов, QR, подписка
instructions/ # страница инструкций + каталог приложений по ОС
nodes/ # (admin) управление нодами
apps/ # (admin) CRUD каталога приложений
admin/ # пользователи, роли, аудит, статистика
theme/ # провайдер темы (light/dark/system) + переключатель
shared/
api/ # http-клиент (fetch + JWT/refresh), сгенерированные типы, query-хуки
realtime/ # инициализация SignalR, подписки → инвалидация Query-кэша
ui/ # обёртки над shadcn/ui, общие компоненты
lib/ # утилиты, форматирование (байты, даты)
config/ # env, константы
styles/ # tailwind, темы
index.html
vite.config.ts
package.json
```
## Дизайн / UX
- **Тема оформления**: светлая и тёмная (переключатель в шапке; вариант «системная»). Реализация —
Tailwind `dark` (класс на `html`) + shadcn/ui; выбор сохраняется (localStorage).
- **Современный и чистый вид**: shadcn/ui + Tailwind, адаптивность, аккуратная типографика.
- **Дашборд пользователя**: карточки конфигов (протокол, локация, трафик прогресс-баром, срок, статус),
быстрые действия (копировать ссылку, показать QR, перевыпустить, отозвать) + карточка «Общая подписка»
(агрегированная ссылка/QR со всеми конфигами). Для неактивированного — экран «запросить активацию».
- **Создание конфига**: выбор локации/inbound (по `DisplayName`) + метка + лимит устройств →
мгновенная выдача ссылки + QR + ссылка на страницу инструкций.
- **Страница инструкций** (`/instructions`): общие шаги «как импортировать ссылку/QR» + каталог
приложений (`GET /api/apps`), **сгруппированный по ОС**; клик по приложению открывает ссылку на
скачивание. Данные ведёт админ (каталог `ClientApp`).
- **Редактирование конфига**: изменить метку и лимит устройств.
- **Настройки аккаунта**: смена пароля, привязка/отвязка Telegram, **удаление аккаунта** (с подтверждением).
- **Админка**: таблицы (TanStack Table) с пагинацией/фильтрами для нод, пользователей, конфигов, ролей,
каталога приложений, журнала аудита; очередь запросов активации; графики трафика (Recharts).
Блокировка пользователя — с подтверждением (гасит VPN). Управление приложениями (название, ссылка, ОС, вкл/выкл).
- **Состояния**: скелетоны при загрузке, аккуратные пустые состояния и toasts на ошибки/успех.
## Работа с API
- HTTP-клиент оборачивает `fetch`: подставляет access-token, при 401 — прозрачно обновляет через
refresh-cookie и повторяет запрос; при неуспехе — разлогин.
- Все запросы/мутации — через TanStack Query (ключи по фичам, инвалидация после мутаций).
- Типы ответов/запросов — из codegen по OpenAPI (никакого ручного дублирования DTO).
## Авторизация на клиенте
- **Access-token** — в памяти (не в localStorage), кладётся в `Authorization: Bearer`.
- **Refresh-token** — httpOnly Secure cookie (JS не читает), ротация на сервере.
- Стор авторизации (Zustand) хранит профиль/роли/`isActivated`; guard-маршруты по роли (`admin` vs обычный)
и по активации (неактивированного ведём на экран «запросить активацию»).
- **Вход — по username** (email не используется). «Забыли пароль?» ведёт: при привязанном
Telegram — восстановление через бота; иначе — подсказка обратиться к админу.
- **Баннер привязки Telegram**: пока Telegram не привязан, показываем настойчивый, но не блокирующий
баннер/напоминание — это единственный self-service способ восстановить доступ. Настройки: смена пароля.
### Вход и привязка через Telegram
- **«Войти через Telegram»**: `POST /api/auth/telegram/login-request` → показать deep-link/QR на
бота, затем ждать подтверждения (поллинг `GET …/login-request/{id}` или событие SignalR). При
`Approved` — сохранить access, refresh уже в cookie, редирект в панель.
- **«Привязать Telegram»** (в настройках, для вошедшего): `POST /api/auth/telegram/link-token`
показать deep-link/QR; статус привязки обновить по факту (поллинг/SignalR). Отвязка — `unlink`.
- QR для deep-link — `qrcode.react`.
## Realtime
- Одно SignalR-подключение к `/hubs/panel` с JWT; реконнект с бэкоффом.
- Обработчики событий (`configTrafficUpdated`, `configStatusChanged`, `nodeStatusChanged`) точечно
обновляют/инвалидируют кэш TanStack Query — UI обновляется без перезагрузки.
## Скрипты (ожидаемые)
```bash
pnpm dev # dev-сервер Vite
pnpm build # прод-сборка
pnpm preview # предпросмотр сборки
pnpm lint # ESLint
pnpm typecheck # tsc --noEmit
pnpm gen:api # генерация типов из OpenAPI-схемы бэкенда
```