Files
PnvPanel/docs/frontend.md
T

9.3 KiB
Raw Blame History

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.

Стек

Задача Выбор
Сборка/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 обновляется без перезагрузки.

Скрипты (ожидаемые)

pnpm dev            # dev-сервер Vite
pnpm build          # прод-сборка
pnpm preview        # предпросмотр сборки
pnpm lint           # ESLint
pnpm typecheck      # tsc --noEmit
pnpm gen:api        # генерация типов из OpenAPI-схемы бэкенда