# EventHub Admin UI — Техническое задание (актуальная версия) ## 1. Роли и права доступа | Роль | Идентификатор | Права | |---------------|---------------|---------------------------------------------------------------------------------------------------------| | Суперадмин | `superadmin` | Полный доступ ко всем модулям, включая изменение ролей других админов, просмотр аудита, системные настройки, управление администраторами. | | Администратор | `admin` | Управление пользователями, событиями, жалобами, отзывами, бан-словами, тикетами, подписками. Нет доступа к аудиту и управлению администраторами. | | Модератор | `moderator` | Работа с жалобами и отзывами. Остальные разделы недоступны. | | Поддержка | `support` | Работа с тикетами (баг-трекер). Остальные разделы недоступны. | Права проверяются на уровне фронтенда: пункты меню и маршруты (`RoleGuard` в `App.tsx`, конфиг `src/config/adminAccess.ts`) ограничены по роли из `GET /v1/admin/me`; при прямом URL без прав — страница 403. ## 2. Аутентификация и авторизация Эндпоинты: - `POST /v1/admin/login` — вход (email, пароль). Возвращает `{ token, refresh_token, user }`. - `POST /v1/refresh` — обновление access-токена по refresh-токену. - `GET /v1/admin/me` — данные текущего администратора, включая роль. Реализация: - JWT-токены сохраняются в `localStorage`. - Axios-интерсептор добавляет `Authorization: Bearer ` ко всем запросам. - При получении 401 автоматически пытается обновить токен через `/v1/refresh`. Если обновление не удалось — редирект на страницу входа. - При перезагрузке страницы токен проверяется через `GET /v1/admin/me`. Если токен валиден, сессия восстанавливается без повторного входа. ## 3. Технологический стек - Язык: TypeScript - Сборщик: Vite - UI-фреймворк: React 18 + Ant Design 5 - Управление состоянием: Zustand (аутентификация), TanStack React Query v5 (серверное состояние) - HTTP-клиент: Axios с интерсепторами - Формы и валидация: React Hook Form + Zod - Графики: Recharts - Дата и время: dayjs с русской локалью - Интернационализация: react-i18next (русский, английский) - Роутинг: React Router v6 - WebSocket: нативное WebSocket API с автоматическим переподключением - Контейнеризация: Docker, Nginx, Traefik ## 4. Модули панели ### 4.1. Дашборд (Dashboard) Эндпоинт: `GET /v1/admin/stats` Виджеты: - Карточки с метриками: пользователи, события, отзывы, календари, жалобы, тикеты (всего и открытых), среднее время решения. - Мини-графики (спарклайны) в карточках «Пользователи» и «События» — динамика по дням с плавной заливкой. - Графики «События по дням» и «Регистрации по дням» на основе данных `events_by_day` и `registrations_by_day`. - Таблица «Активность администраторов» с сортировкой по убыванию числа действий, раскрашенными ролями, форматированной датой последнего входа, заменой пустых значений на прочерк. ### 4.2. Управление пользователями Эндпоинты: `GET /v1/admin/users`, `GET /v1/admin/users/:id`, `PUT /v1/admin/users/:id`, `DELETE /v1/admin/users/:id` Функциональность: - Список с серверной пагинацией и сортировкой по всем столбцам. - Первая колонка — иконка для перехода на детальную страницу. - Роли и статусы раскрашены (user — синий, bot — фиолетовый; active — зелёный, frozen — оранжевый, deleted — красный). - Модальное окно редактирования: email, ник, роль, статус, причина. Обязательные поля подсвечиваются, кнопка «Сохранить» неактивна при пустых обязательных полях. Пустые строки не отправляются на сервер. - Кнопка «Заморозить/Разморозить» открывает модальное окно с обязательной причиной при заморозке. Подгружается текущая причина, если она была. - Кнопка «Удалить» открывает диалог подтверждения. - Для удалённых пользователей (status=deleted) кнопки «Заморозить/Разморозить» и «Удалить» неактивны, кнопка «Редактировать» активна. - Детальная страница пользователя: все поля из API, включая телефон, язык, часовой пояс, аватар URL, соцсети, настройки, даты создания/обновления. Пустые значения заменены на прочерк. Даты отформатированы. ### 4.3. Управление событиями Эндпоинты: `GET /v1/admin/events`, `GET /v1/admin/events/:id`, `PUT /v1/admin/events/:id`, `DELETE /v1/admin/events/:id` Функциональность: - Список с серверной пагинацией и сортировкой. - Первая колонка — иконка для перехода на детальную страницу. - Типы событий раскрашены (single — синий, recurring — фиолетовый). - Статусы раскрашены (active — зелёный, cancelled — красный, completed — серый). - Модальное окно редактирования: название, описание, тип, статус, дата и время начала (DatePicker), продолжительность, вместимость, специалист ID, календарь ID, ссылка онлайн, теги. Валидация обязательных полей. - Кнопки «Редактировать» и «Удалить» с иконками. - Детальная страница события: все поля из API (название, описание, тип, статус, причина, дата начала, продолжительность, вместимость, специалист, календарь, мастер-событие, онлайн-ссылка, теги, рейтинг, вложения, история изменений, повторение, локация, является экземпляром, даты создания/обновления). ID-поля (специалист → пользователь, мастер → событие) оформлены как кликабельные ссылки. Статус и тип раскрашены. ### 4.4. Жалобы (Reports) Эндпоинты: `GET /v1/admin/reports`, `GET /v1/admin/reports/:id`, `PUT /v1/admin/reports/:id` Функциональность: - Список с серверной пагинацией и сортировкой. - Первая колонка — иконка для перехода на детальную страницу. - Резолвинг отправителя: если нет ника — показывается email (ссылка на профиль пользователя). - Колонка «Тип» раскрашена (event — синий, calendar — зелёный, review — фиолетовый). - Колонка «Цель» — кликабельная ссылка с названием (для событий) или ID. - Быстрый просмотр в модальном окне: ID, отправитель (ссылка с ником/email), тип цели, цель (ссылка с названием для событий), причина, статус, дата создания, дата решения, кем решено (ссылка на админа с ником/email). В модалке кнопки «Рассмотрено» и «Отклонено» для жалоб в статусе pending. - Детальная страница жалобы: все поля с возможностью принять решение (кнопки «Рассмотрено» и «Отклонено»). ### 4.5. Отзывы (Reviews) Эндпоинты: `GET /v1/admin/reviews`, `GET /v1/admin/reviews/:id`, `PUT /v1/admin/reviews/:id`, `PATCH /v1/admin/reviews` Функциональность: - Список с серверной пагинацией и сортировкой. - Возможность выбора нескольких отзывов для массового изменения статуса (скрыть, показать, удалить) с обязательной причиной при скрытии/удалении. - Первая колонка — иконка для перехода на детальную страницу. - Резолвинг пользователя (никнейм → email → ID) и цели (название события). - Оценка отображается звёздами. - Статусы раскрашены (visible — зелёный, hidden — оранжевый, deleted — красный). - Тип цели раскрашен (event — синий, calendar — зелёный). - Модальное окно редактирования: оценка, комментарий, статус, причина (обязательна при скрытии/удалении). - Детальная страница отзыва: все поля, кнопки изменения статуса с причиной. ### 4.6. Бан-слова (Banned Words) Эндпоинты: `GET /v1/admin/banned-words`, `POST /v1/admin/banned-words`, `DELETE /v1/admin/banned-words/:word` Функциональность: - Список с серверной пагинацией, сортировкой и поиском. - Резолвинг поля «Кем добавлено» (ссылка на администратора с ником/email). - Дата добавления отформатирована. - Форма добавления нового слова и кнопка удаления с подтверждением. ### 4.7. Тикеты (баг-трекер) Эндпоинты: `GET /v1/admin/tickets`, `GET /v1/admin/tickets/stats`, `GET /v1/admin/tickets/:id`, `PUT /v1/admin/tickets/:id`, `DELETE /v1/admin/tickets/:id` Функциональность: - Статистика вверху: открыто, в работе, решено, закрыто. - Список с серверной пагинацией и сортировкой. - Первая колонка — иконка для перехода на детальную страницу. - Резолвинг назначенного администратора (ссылка с ником/email). - Статусы раскрашены (open — красный, in_progress — синий, resolved — зелёный, closed — серый). - Детальная страница: все поля тикета, отправитель как ссылка на пользователя, назначенный администратор как ссылка, форма изменения статуса с выбором администратора из списка (email — ник). - Кнопка удаления с подтверждением. ### 4.8. Подписки (Subscriptions) Эндпоинты: `GET /v1/admin/subscriptions`, `GET /v1/admin/subscriptions/:id`, `PUT /v1/admin/subscriptions/:id`, `DELETE /v1/admin/subscriptions/:id` Функциональность: - Список с серверной пагинацией и сортировкой. - Резолвинг пользователя (никнейм → email → ID) со ссылкой. - Планы раскрашены (trial — голубой, monthly — синий, quarterly — зелёный, biannual — фиолетовый, annual — оранжевый). - Статусы раскрашены (active — зелёный, expired — оранжевый, cancelled — красный). - Даты отформатированы. - Модальное окно редактирования: план, статус, пробный период, дата окончания (DatePicker). Данные подгружаются с сервера. ### 4.9. Управление администраторами Эндпоинты: `GET /v1/admin/admins`, `GET /v1/admin/admins/:id`, `POST /v1/admin/admins`, `PUT /v1/admin/admins/:id`, `DELETE /v1/admin/admins/:id` Функциональность: - Список с серверной пагинацией и сортировкой. - Первая колонка — иконка для перехода на детальную страницу. - Роли раскрашены (superadmin — красный, admin — синий, moderator — фиолетовый, support — голубой). - Статусы раскрашены (active — зелёный, blocked — красный). - Модальное окно создания: email, пароль, роль. - Модальное окно редактирования: ник, email, роль, статус, часовой пояс (выпадающий список), язык (русский/английский), телефон. - Кнопки «Редактировать» и «Удалить» с иконками. - Детальная страница администратора: все поля с раскрашенными ролью и статусом. ### 4.10. Аудит (Audit) Эндпоинт: `GET /v1/admin/audit` Функциональность: - Список с серверной пагинацией и сортировкой. - Резолвинг администратора (ссылка с ником/email). - Роль раскрашена. - Действие раскрашено (create, update, delete, freeze, unfreeze, block, unblock, hide, unhide, login, logout и др.). - Тип сущности раскрашен (user, event, calendar, review, report, ticket, subscription, admin). - Наименование сущности: для user — ник/email (ссылка), для event — название (ссылка), для review — ссылка на отзыв, для остальных — ID. - Фильтры: администратор (выпадающий список с поиском), действие (выпадающий список уникальных действий), диапазон дат. - Дата отформатирована. ### 4.11. Профиль текущего администратора Эндпоинты: использует данные из `useAuthStore().user`, редактирование через `PUT /v1/admin/admins/:id` Функциональность: - Просмотр всех полей профиля: email, ник, роль, статус, часовой пояс, язык, телефон, аватар URL, настройки (JSON), последний вход. - Пустые значения заменены на прочерк, дата отформатирована. - Кнопка «Редактировать» доступна только для superadmin. При редактировании можно изменить ник, часовой пояс, язык, телефон, URL аватара, настройки (с валидацией JSON). - Доступен всем ролям, страница открывается из виджета профиля в боковом меню. ## 5. Real-time уведомления (WebSocket) Эндпоинт: `wss://<домен>/admin/ws?token=` Функциональность: - При входе устанавливается WebSocket-соединение; при logout или смене `accessToken` сокет явно закрывается, reconnect отменяется, метрики в store сбрасываются. - Подписка на каналы `reports` и `tickets`. - При получении сообщения `{ type: "report_created" }` или `{ type: "ticket_created" }` показывается уведомление со ссылкой на соответствующую страницу. - Автоматическое переподключение при разрыве соединения. - Защита от дубликатов по `timestamp`. ## 6. Интерфейс - Боковое меню (сайдбар) с пунктами, доступными в соответствии с ролью. - В нижней части сайдбара — виджет профиля текущего администратора с аватаром и именем (ник или email). При клике открывается меню «Мой профиль» и «Выйти». Кнопка сворачивания сайдбара находится в этой же панели. - Верхняя панель содержит моки оперативной статистики (онлайн, заказов сегодня, тикетов) — в будущем будут заменены на реальные данные. - В меню профиля (аватар в header): «Мой профиль», язык UI, **Admin `MAJOR.MINOR (sha)`** и **API `MAJOR.MINOR (sha)`** (API — из `GET /v1/admin/health`), «Выйти». - Все даты в интерфейсе русифицированы (dayjs с русской локалью; i18n ru/en). - Единая нормализация данных: пустые значения (`null`, `undefined`, `"undefined"`, `"-"`) заменяются на прочерк, даты приводятся к читаемому формату. Нормализация применяется централизованно в хуках списков; для форм редактирования используются сырые данные. - Все таблицы имеют серверную пагинацию и сортировку через заголовок `X-Total-Count`. ## 7. Развёртывание - Product version: файл `VERSION` (`MAJOR.MINOR`); в CI bake как `VITE_APP_*`. Образы: `sha-<12>` + floating `:ift` / `:stage` (см. `EventHubSpec/WORKFLOW.md` §6). - Production-сборка: `npm run build` → папка `dist/`. - Docker-образ на основе Nginx Alpine. - Контейнер подключается к сети `eventhub_network`. - Traefik маршрутизирует домен `admin-ui.stage.eventhub.local` на контейнер. - Nginx внутри контейнера раздаёт статику и проксирует API-запросы (`/v1/` → `http://eventhub:8445`, `/admin/ws` → `http://eventhub:8446`), что позволяет избежать проблем с CORS и самоподписанными сертификатами. - WebSocket также проксируется через Nginx. - Makefile автоматизирует установку, сборку, запуск и очистку проекта. ## 8. E2E (Playwright) - Каркас: `playwright.config.ts`, каталог `e2e/`. - Контракт селекторов: `e2e/TESTIDS.md` (`data-testid` + a11y). - **Mock-suite** (`npm run test:e2e`): в CI после lint/build; route-моки `**/v1/admin/**`. - **IFT smoke** (`npm run test:e2e:ift`): login → shell → logout против IFT; учётки `SMOKE_ADMIN_*` / `ADMIN_SUPER_*` из `EventHubDevOps/ift/.env`; workflow `e2e-ift.yml` после Deploy IFT. - Coverage (mock): auth/roles, shell, inbox reports/tickets, reports/reviews CRUD-пути, explore users/calendars/events/subscriptions, banned-words, admins/audit/monitoring/profile, i18n.