Перейти к основному содержимому

Фронтенд

Веб-приложение frontend/ — Next.js 16 (App Router) + React 19 + TypeScript + Tailwind CSS v4 + shadcn/ui + TanStack Query, менеджер пакетов npm. Работает на app.optimawb.ru и ходит только в API api.optimawb.ru. Решения — ADR-0008 (стек) и ADR-0012 (app shell и навигация); публичный лендинг — отдельное приложение landing/, а не часть frontend/.

Маршруты (App Router)​

frontend/src/app/
(marketing)/ редирект `/` на лендинг optimawb.ru (NEXT_PUBLIC_LANDING_URL)
(auth)/ /login, /register
(app)/app/ аутентифицированная оболочка (AppShell)
settings/ кабинеты WB, профиль — не привязаны к кабинету
admin/ пользователи, доступы к брендам, аудит — только admin
wb/[accountId]/ дашборд и модули ТЗ 5.x — привязаны к кабинету

Ключевое решение ADR-0012 — кабинет в URL: /app/wb/:accountId/<модуль>. Ссылку можно отправить коллеге, обновление страницы не теряет контекст, а уведомления и диплинки (Уведомления) ведут сразу на нужный экран кабинета. Фильтр по бренду — глобальный, в шапке (BrandScopeProvider).

Маршруты в app/ тонкие: страница модуля только выбирает компонент из features/ через module-page-router.

App shell и реестр навигации​

  • components/shell/ — AppShell, боковое меню, шапка, PageHeader; features/shell/ — провайдеры оболочки, командная палитра, гейты (AdminGate — страницы администратора).
  • Navigation registry — src/config/navigation.ts — единственный источник бокового меню. Элемент описывает id, подпись (из локали ru), иконку, группу (overview, sales, pricing, advertising, communications, operations, ai, other, settings, admin), статус (live | soon | hidden), признак accountScoped, функцию href(ctx) и допустимые роли. Меню и командная палитра строятся из него; элементы для недоступной роли не показываются.
  • Новый модуль ТЗ = запись в реестре + папка features/<slug>/ + тонкий route.

Структура features/​

features/<slug>/
index.ts публичный API (страница + типы)
model/ типы, query keys, константы (KPI, подписи)
adapters/ DTO бэкенда → модели UI, параметры запросов
api/ функции запросов и TanStack Query
components/ страница, секции, таблицы, формы
hooks/ use-*-queries.ts (связки useQuery/useMutation)
lib/ форматтеры, экспорт

Правила: фичи не импортируют друг друга (общее — через features/shared и composition root features/modules); бизнес-UI живёт в features/, а не в app/. Страницы модулей используют общий каркас AccountModulePageShell (шапка «название · модуль · кабинет · статус», тулбар, алерт для неактивного кабинета, KPI-сетка, кнопка «Обновить»). Эталоны — digitization, dashboard, prices, repricer, autobidder, auto-replies. Фичи соответствуют модулям бэкенда: rnp, ai-agent, content-generation, knowledge-base, notifications и др. (Обзор архитектуры).

Данные: TanStack Query и типизированный клиент​

  • TanStack Query — серверное состояние. Глобальные настройки (components/providers.tsx): staleTime 60 с, один повтор запроса; ошибки запросов и мутаций показываются тостом (если не отключено в meta), а успех мутации — сообщением из meta.successMessage; 401 тостом не дублируется. Фоновые данные обновляются опросом (например, счётчик уведомлений — раз в 60 с).
  • Клиент OpenAPI — src/lib/api: openapi-fetch + schema.d.ts, сгенерированный из backend/openapi.json командой npm run api:generate. Любое изменение контракта бэкенда видно компилятором (npm run typecheck).
  • getApiClient() добавляет Authorization: Bearer, при 401 один раз обновляет токены и повторяет запрос, ошибки приводит к ApiError с кодом и сообщением бэкенда.

Аутентификация и сессия​

  • src/proxy.ts (Next.js proxy, бывший middleware) защищает /app/*, /login, /register: по наличию cookie-флага optima_session перенаправляет неавторизованных на вход. Cookie — только флаг, самих токенов в нём нет.
  • Access-токен — в памяти вкладки, refresh — в localStorage (общий источник истины между вкладками: другая вкладка могла уже ротировать токен). Обновление — POST /auth/refresh; при обнаружении повторного использования токена бэкенд завершает всю сессию (Безопасность).
  • AuthGate на клиенте дополнительно проверяет сессию для /app/*; страницы администратора закрыты AdminGate по роли. Серверная проверка прав — всегда на бэкенде, интерфейс только скрывает недоступное.

Окружение и сборка​

ПеременнаяНазначение
NEXT_PUBLIC_API_URLадрес бэкенда (dev: http://localhost:3000)
NEXT_PUBLIC_LANDING_URLадрес лендинга для редиректа с / (dev: http://localhost:3002)

Production-сборка — next build в режиме output: "standalone", образ собирает frontend/Dockerfile и публикует GitHub Actions в GHCR optima-frontend (Развёртывание, CI/CD). Локальный запуск — Локальная разработка. Gate 1 для фронтенда: lint + typecheck + unit (Vitest) + build + e2e (Playwright). Подписи интерфейса — в src/locales/ru.