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

23 KiB
Raw Blame History

ТЕХНИЧЕСКОЕ ЗАДАНИЕ (ТЗ) НА ПЛАТФОРМУ 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 (разработка)