23 KiB
ТЕХНИЧЕСКОЕ ЗАДАНИЕ (ТЗ) НА ПЛАТФОРМУ 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()] | undefinedbooking— добавлены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. Отзывы и рейтинги
- Пользователи могут оставлять отзывы (рейтинг 1–5 и комментарий) на события или календари.
- Отзыв можно редактировать (сохраняется
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 (разработка)