Files
EventHubSpec/EventHubBackSpec.md
2026-05-05 13:45:45 +03:00

315 lines
23 KiB
Markdown
Raw Permalink 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.
# ТЕХНИЧЕСКОЕ ЗАДАНИЕ (ТЗ) НА ПЛАТФОРМУ EVENTHUB
Версия: 1.5 (актуальная реализация: выполнены задачи #12#17)
## 1. ЦЕЛИ И НАЗНАЧЕНИЕ
EventHub — платформа для управления событиями с поддержкой календарей, записи участников
(включая специалистов), гибкого подтверждения, рейтингов, отзывов, модерации,
встроенного баг-трекера и платной подписки.
Целевая аудитория: владельцы календарей (бизнес), участники (клиенты), администраторы.
## 2. ФУНКЦИОНАЛЬНЫЕ ТРЕБОВАНИЯ
### 2.1. Календари
- CRUD календаря (название, описание, теги, владелец)
- Расшаривание по ссылке (публичная/приватная)
- Приглашение пользователей с правами "запись" или "администрирование"
- Типы календарей: personal (бесплатный, без записи), commercial (платный, запись клиентов,
специалисты)
- Гибкое подтверждение заявок: auto (автоматически), manual (вручную), timeout (авто через N
секунд)
- Теги календаря, рейтинг (средняя оценка, количество голосов)
**Новые поля (задача #12):**
- `short_name` — короткое уникальное имя для API и поиска
- `category` — категория (enum)
- `color` — цвет отображения
- `image_url` — изображение календаря
- `settings` — дополнительные настройки (map)
### 2.1.1. Специалисты календаря (задача #12)
Реализована отдельная таблица `calendar_specialist`, связывающая пользователя (специалиста) с
календарём. Специалист может иметь отображаемое имя (`name`) и список специализаций
(`specialization`). Статус специалиста: `active` | `inactive`.
### 2.2. События (расширенная версия с повторяющимися событиями)
#### 2.2.1. Типы событий и модель хранения
События могут быть одиночными (`event_type = single`) или повторяющимися (`event_type = recurring`).
Для повторяющихся событий:
- Мастер-событие содержит правило повторения (`recurrence_rule`) и является шаблоном.
- При создании повторяющегося события генерируются экземпляры (instances) на определённый
период (например, на месяц вперёд), которые хранятся как отдельные записи с полем
`is_instance = true` и ссылкой на мастер (`master_id`).
- При изменении мастера можно выбрать обновление всех будущих экземпляров или только мастер-записи.
- При удалении мастера удаляются все связанные экземпляры.
- Для поддержки исключений (отмена отдельного вхождения) используется таблица
`recurrence_exception`.
#### 2.2.2. Правила генерации вхождений при поиске
При поиске событий на заданный диапазон дат система должна:
- Включать все одиночные события, попадающие в диапазон.
- Для повторяющихся событий генерировать виртуальные вхождения на основе `recurrence_rule`,
исключая те, что помечены как исключения.
- Возвращать как одиночные, так и сгенерированные вхождения в едином списке.
#### 2.2.3. Материализация при записи участника
При записи участника на конкретное вхождение повторяющегося события:
- Система материализует (создаёт) физическую запись события для этого вхождения, если оно ещё
не было материализовано (например, для хранения количества записавшихся).
- Материализованное событие имеет `is_instance = true` и ссылается на `master_id`.
- Запись участника (`booking`) всегда привязывается к конкретному экземпляру (материализованному
или одиночному событию).
#### 2.2.4. Изменение и удаление серий
- При редактировании мастера можно применить изменения ко всем будущим экземплярам или создать
новый мастер с отдельной серией.
- При удалении мастера удаляются все связанные экземпляры, если на них нет активных записей.
Если есть активные записи, мастер-событие помечается как `cancelled`, а существующие записи
остаются.
#### 2.2.5. Структура записей (records.hrl)
Актуальная структура записей включает дополнительные поля, добавленные в рамках задачи #12:
- `event` — добавлены `attachments :: [binary()] | undefined`, `edit_history :: [map()] | undefined`
- `booking` — добавлены `notes :: binary() | undefined`, `reminder_sent :: boolean()`
- `review` — добавлены `likes :: non_neg_integer()`, `dislikes :: non_neg_integer()`,
`edited_at :: calendar:datetime() | undefined`
#### 2.2.6. Требования к реализации
- Все операции с событиями должны быть транзакционными.
- Генерация вхождений должна быть эффективной (использовать `calendar:datetime_to_gregorian_seconds`
и кэширование).
- При поиске событий для календаря учитывать права доступа пользователя.
### 2.3. Запись участников и подтверждение
- Пользователь может отправить заявку на участие в событии.
- В зависимости от `confirmation` календаря заявка либо подтверждается автоматически, либо
ожидает ручного подтверждения владельцем, либо подтверждается по таймауту.
- Бронирование имеет статусы: `pending`, `confirmed`, `cancelled`.
- Пользователь может отменить свою запись.
- Владелец календаря может подтвердить или отклонить заявку.
- При подтверждении фиксируется время (`confirmed_at`).
- Вместимость события (`capacity`) ограничивает количество подтверждённых записей.
### 2.4. Отзывы и рейтинги
- Пользователи могут оставлять отзывы (рейтинг 15 и комментарий) на события или календари.
- Отзыв можно редактировать (сохраняется `edited_at`).
- Отзывы могут быть скрыты модератором.
- При добавлении/изменении/удалении отзыва пересчитывается средний рейтинг события
(`rating_avg`, `rating_count`).
- Реализованы лайки/дизлайки отзывов (`likes`, `dislikes`).
- Возможность пожаловаться на отзыв (создание `report`).
### 2.5. Поиск и фильтрация
- Полнотекстовый поиск по названиям событий, календарей, тегам.
- Фильтрация по дате, категории, местоположению, рейтингу.
- Пагинация результатов.
- Поиск должен учитывать права доступа (не показывать скрытые/заблокированные календари).
### 2.6. Расширенные возможности
- Локация события (`location` запись с адресом, широтой, долготой).
- Онлайн-ссылка (`online_link`).
- Вложения к событию (`attachments`).
- История изменений события (`edit_history`).
- Заметки пользователя к бронированию (`notes`).
- Напоминания о событии (поле `reminder_sent` в бронировании, логика отправки не реализована).
### 2.7. Модерация и безопасность
- Пользователи могут отправлять жалобы (`report`) на календари, события, отзывы.
- Модераторы могут просматривать жалобы и принимать меры (скрывать контент, блокировать).
- Список запрещённых слов (`banned_word`) для фильтрации контента.
- Аудит действий администраторов (`admin_audit`).
### 2.8. Баг-трекер (автоматический)
- При возникновении ошибок сервер автоматически создаёт тикет (`ticket`).
- Тикет содержит хеш ошибки, сообщение, стектрейс, контекст, количество повторений.
- Администраторы могут просматривать тикеты, назначать ответственных, менять статус.
### 2.9. Платная подписка
- Пользователи могут оформить подписку (`subscription`) с разными планами: monthly, quarterly,
biannual, annual.
- Статус подписки: `active`, `expired`, `cancelled`.
- Отслеживание использования пробного периода (`trial_used`).
### 2.10. Административная панель
- Управление пользователями (просмотр, блокировка, изменение ролей).
- Просмотр статистики платформы.
- Управление жалобами и тикетами.
- Управление подписками.
- Аудит действий администраторов.
#### 2.10.1. Ролевая модель администраторов
- `superadmin` — полный доступ, может управлять другими администраторами.
- `admin` — управление пользователями, контентом, подписками.
- `moderator` — модерация контента (жалобы, отзывы).
- `support` — работа с тикетами.
#### 2.10.2. Эндпоинты для управления ролями и аудитом
- `GET /v1/admin/me` — информация о текущем администраторе.
- `GET /v1/admin/admins` — список администраторов (только для superadmin).
- `POST /v1/admin/admins/:id` — изменение роли администратора (superadmin).
- `GET /v1/admin/audit` — просмотр аудита.
#### 2.10.3. Статистика для дашборда с учётом ролей
- `GET /v1/admin/stats` — базовая статистика (количество пользователей, событий, бронирований).
- В будущем планируется расширенная аналитика на основе данных из таблицы `stats`.
### 2.11. Real-time уведомления (WebSocket)
- Пользовательский WebSocket (порт 8081): подписка на обновления событий календаря.
- Административный WebSocket (порт 8446): подписка на новые жалобы и тикеты.
- Создана таблица `notification` для хранения уведомлений (тип, заголовок, тело, флаг прочитано).
Полноценная логика доставки уведомлений будет реализована позже.
### 2.12. Инфраструктура развертывания (Docker Compose)
- Docker Swarm с тремя репликами `eventhub-node{1..3}`.
- Traefik в качестве reverse-прокси и балансировщика.
- Prometheus для сбора метрик, Grafana для визуализации.
- Observer Web для мониторинга Erlang-узлов.
- Автоматическая ротация логов.
## 3. НЕФУНКЦИОНАЛЬНЫЕ ТРЕБОВАНИЯ
### 3.1. Производительность и масштабирование
- Поддержка 100 000+ пользователей.
- Горизонтальное масштабирование добавлением новых узлов.
- Все персистентные таблицы хранятся в `disc_copies` на каждом узле (задача #13).
- Сессионные таблицы (`session`, `admin_session`) оставлены в `ram_copies` для скорости.
- Индексы созданы для часто запрашиваемых полей (calendar_id, start_time, event_type, status и др.) (задача #13).
- Полная репликация горячих таблиц между всеми узлами кластера (задача #14).
- Автоматическое обнаружение узлов через DNS-имя `eventhub-node` или статический список (задача #14).
- Периодическая очистка «мёртвых» узлов из схемы Mnesia (каждые 30 секунд) (задача #14).
- Архивирование исторических данных (старше 30 дней) в отдельные Mnesia-узлы с `disc_only_copies` (задача #15).
- Пагинация всех списков.
### 3.2. Надёжность
- Супервизорное дерево OTP.
- Философия "let it crash" — быстрый перезапуск упавших процессов.
- Автоматическое восстановление после падения ноды (Mnesia).
- Валидация входных данных и единый формат ошибок.
- Механизм миграций схемы данных: миграции компилируются вместе с проектом и автоматически применяются при старте, поддерживается откат (задача #17).
### 3.3. Безопасность
- JWT-аутентификация с разделением ролей (user, admin, superadmin, moderator, support).
- Проверка прав доступа к календарям и событиям.
- Пароли хэшируются с использованием Argon2.
- Защита от несанкционированного просмотра архивных данных (только владелец календаря) (задача #15).
### 3.4. Наблюдаемость
- Логирование в JSON-формате.
- Экспорт метрик для Prometheus (HTTP-эндпоинт `/metrics`).
- Встроенный Observer Web для мониторинга Erlang-системы.
- Сбор статистики использования (события, бронирования, отзывы) через триггеры Mnesia с сохранением в таблице `stats` (задача #16).
### 3.5. CI/CD
- Контейнеризация (Docker).
- Makefile для автоматизации задач.
- Возможность развёртывания в Kubernetes (в будущем).
## 4. СТЕК ТЕХНОЛОГИЙ (С ВЕРСИЯМИ)
- Erlang/OTP 28
- Mnesia (встроенная БД)
- Cowboy 2.12 (HTTP-сервер)
- JWT (jose 1.11.10)
- Prometheus (prometheus 4.11.0, prometheus_cowboy 2.1.0)
- Docker Compose v3.8
- Traefik v3.1
- Grafana 11.2
- Prometheus 2.55
- Observer Web
- Logrotate
## 5. ИЕРАРХИЧЕСКАЯ СТРУКТУРА КОДА
```
src/
├── core/ — бизнес-логика (core_user, core_event, core_booking, core_review, ...)
├── handlers/ — обработчики HTTP (handler_login, handler_calendar_view, ...)
├── infra/ — инфраструктура (infra_mnesia, infra_sup, cluster_discovery,
│ archive_manager, archive_controller, stats_collector,
│ migration_engine, ...)
├── archive/ — архивирование и рендеринг (archive_controller, archive_manager,
│ calendar_html_renderer, archive_fetcher)
├── migrations/ — файлы миграций
└── eventhub_app.erl — точка входа приложения
```
## 6. ОСНОВНЫЕ API (КРАТКО)
### Пользовательские (порт 8080)
- `POST /v1/register` — регистрация.
- `POST /v1/login` — вход.
- `POST /v1/refresh` — обновление токена.
- `GET /v1/user/me` — профиль пользователя.
- `GET /v1/user/bookings` — бронирования пользователя.
- `GET /v1/user/reviews` — отзывы пользователя.
- `GET /v1/search` — поиск.
- `GET /v1/calendars` — список календарей.
- `GET /v1/calendars/:id` — календарь.
- `GET /v1/calendars/:calendar_id/events` — события календаря.
- `GET /v1/events/:id` — событие.
- `GET /v1/events/:id/occurrences` — вхождения повторяющегося события.
- `POST /v1/events/:id/bookings` — запись на событие.
- `GET /v1/bookings/:id` — статус бронирования.
- `POST /v1/reviews` — создать отзыв.
- `GET /v1/reviews` — список отзывов.
- `PUT /v1/reviews/:id` — обновить отзыв.
- `POST /v1/reports` — пожаловаться.
- `GET /v1/tickets` — тикеты пользователя.
- `POST /v1/tickets` — создать тикет.
- `GET /v1/tickets/:id` — статус тикета.
- `GET /v1/subscription` — подписка пользователя.
- `GET /v1/calendars/:calendar_id/view?month=YYYY-MM` — HTML-календарь (владелец), включая архив.
### Административные (порт 8445)
- `GET /v1/admin/health` — состояние сервера.
- `GET /v1/admin/stats` — статистика.
- `POST /v1/admin/login` — вход администратора.
- `GET /v1/admin/users`, `GET /v1/admin/users/:id` — пользователи.
- `GET /v1/admin/reports`, `GET /v1/admin/reports/:id` — жалобы.
- `DELETE /v1/admin/reviews/:id` — удалить отзыв.
- `GET /v1/admin/banned-words`, `POST /v1/admin/banned-words` — запрещённые слова.
- `GET /v1/admin/tickets/stats` — статистика тикетов.
- `GET /v1/admin/tickets`, `GET /v1/admin/tickets/:id` — управление тикетами.
- `GET /v1/admin/subscriptions`, `POST /v1/admin/subscriptions/:id` — подписки.
- `PUT /v1/admin/:target_type/:id` — модерация.
- `GET /v1/admin/me` — профиль администратора.
- `GET /v1/admin/admins`, `POST /v1/admin/admins/:id` — управление администраторами.
- `GET /v1/admin/audit` — аудит.
## 6.1. Аутентификация и авторизация
- Пользователи и администраторы используют разные эндпоинты и JWT-токены.
- Access-токен имеет срок жизни 1 час, refresh-токен — 30 дней.
- Все защищённые эндпоинты требуют заголовок `Authorization: Bearer <token>`.
## 7. ВЕРСИОНИРОВАНИЕ И СТАТУС
Текущая версия: 1.5 (MVP, альфа). Включает:
- Гибридную модель повторяющихся событий
- Раздельную JWT-аутентификацию (пользователи/администраторы)
- Полноценную ролевую модель администрирования
- Версионированное админ-API (/v1/admin/...)
- Расширенную инфраструктуру (Traefik, WAF, мониторинг, failover)
- Аудит действий администраторов
- Расширенную статистику для дашборда
- Улучшенную обработку ошибок и валидацию
**Новое в версии 1.5:**
- Расширенная структура данных (новые поля и таблицы, задача #12)
- Дисковое хранение и индексы (задача #13)
- Репликация между узлами кластера с автоочисткой (задача #14)
- Архивирование исторических данных и серверный рендеринг календаря (задача #15)
- Сбор статистики через триггеры Mnesia (задача #16)
- Механизм миграций схемы данных (задача #17)
## 8. ОГРАНИЧЕНИЯ И ДОПУЩЕНИЯ
- Система не поддерживает транзакционную целостность между несколькими таблицами на уровне
приложения (полагаемся на Mnesia).
- В текущей версии отсутствует полноценная система уведомлений (только таблица).
- Загрузка файлов (вложения) пока не реализована.
- Серверный рендеринг календаря работает только для владельца календаря.
- Автоматическое архивирование через `archive_controller` в локальном режиме использует
`slave:start`, который устарел; в production планируется `peer`.
## 9. ТРЕБОВАНИЯ К ОКРУЖЕНИЮ
- Erlang/OTP 28
- Docker Engine 27.3.1+
- Docker Compose v3.8
- Linux (продакшен) или WSL2 (разработка)