222 lines
22 KiB
Markdown
222 lines
22 KiB
Markdown
# 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 <token>` ко всем запросам.
|
||
- При получении 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` (фильтры `status`, `source`, `assigned_to`, `q`), `GET /v1/admin/tickets/stats`, `GET /v1/admin/tickets/:id`, `PUT /v1/admin/tickets/:id`, `DELETE /v1/admin/tickets/:id`; создание/авто-репорт: `POST /v1/tickets` (user/admin JWT).
|
||
|
||
Функциональность:
|
||
- Статистика вверху: открыто, в работе, решено, закрыто.
|
||
- Список с серверной пагинацией и сортировкой; колонка и фильтр `source` (`backend` / `frontend` / `manual`).
|
||
- Первая колонка — иконка для перехода на детальную страницу.
|
||
- Резолвинг назначенного администратора (ссылка с ником/email).
|
||
- Статусы раскрашены (open — красный, in_progress — синий, resolved — зелёный, closed — серый).
|
||
- Детальная страница: все поля тикета (включая `source`), отправитель как ссылка на пользователя, назначенный администратор как ссылка, форма изменения статуса с выбором администратора из списка (email — ник).
|
||
- Кнопка удаления с подтверждением.
|
||
- Авто-capture ошибок самой Admin SPA: `window.onerror`, `unhandledrejection`, `ErrorBoundary` → `POST /v1/tickets` (`source=frontend`) с throttle.
|
||
- Ручной баг-репорт (`source=manual`) — клиентский сценарий end-user приложений через `POST /v1/tickets`, не UI Control Center.
|
||
|
||
### 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=<jwt>`
|
||
|
||
Функциональность:
|
||
- При входе устанавливается 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. |