Архивирование с быстрым подключением и серверный рендеринг для веб-клиента #15

Closed
opened 2026-05-02 16:16:19 +03:00 by aleksey · 2 comments
Owner

Этап 3. Архивирование с быстрым подключением и серверный рендеринг для веб-клиента (пункт 4 задачи + решение для веба)

Цель: вынести исторические данные (старше 30 дней) в отдельные архивные узлы с возможностью быстрого доступа по требованию; реализовать серверный рендеринг календаря для минимизации нагрузки на браузеры.

Шаги:

3.1. Модуль архивного контроллера (archive_controller)

  1. Функция переноса данных за день:
    • По расписанию (например, ежедневно в непиковое время) для прошедшего дня D (формат YYYYMMDD):
      • Запустить отдельный Erlang-узел eventhub_archive_D@Host через slave:start/3 или системный вызов erl -sname ....
      • На архивном узле создать свою Mnesia-схему (mnesia:create_schema([node()])).
      • Создать таблицы (event, booking, review и т.д.) как disc_only_copies с теми же индексами, что и в основной базе (вызов обобщённой функции create_indices/0 на архивном узле).
      • В рамках распределённой транзакции скопировать записи из основной базы за день D в архивный узел, затем удалить их из основной.
      • Остановить архивный узел (init:stop/0), сохранив его файлы на диске в каталоге archive_dir/D/.
  2. Обработка ошибок:
    • Если перенос не удался, повторить позже, использовать mnesia:backup/1 основной базы перед удалением.

3.2. Менеджер архивных узлов (archive_manager – gen_server на основном узле)

  1. Запуск архивного узла по требованию:
    • При запросе к архиву определить требуемый день (или диапазон) и имя узла.
    • Проверить, запущен ли узел в пуле; если нет — запустить через slave:start/3 или erl -sname, дождаться инициализации Mnesia.
    • Подключить основной узел к архивному через mnesia:change_config(extra_db_nodes, [ArchiveNode]) (только для чтения).
    • Вернуть {ok, ArchiveNode}.
  2. Остановка неактивных узлов:
    • Для каждого запущенного архивного узла запускать таймер (30 секунд после последнего использования); если новых запросов нет — отключить extra_db_nodes, остановить узел.
  3. Холодное хранение:
    • Очень старые архивы (например, старше года) упаковывать в tar.gz и удалять с диска; при запросе — распаковать и запустить.

3.3. API и серверный рендеринг

  1. Эндпоинт для веб-клиента:
    • GET /calendar/view?month=2026-04&view=month – возвращает готовый HTML.
    • В обработчике запроса:
      • Определить, что месяц холодный (более 30 дней от текущей даты), иначе использовать горячие таблицы.
      • Получить архивный узел через archive_manager.
      • Выполнить запросы к архивным таблицам: mnesia:select(event, [{...}], ArchiveNode) или mnesia:read.
      • Передать данные в функцию рендеринга.
  2. Модуль рендеринга calendar_html_renderer:
    • Функция render_month(Year, Month, Events) -> iolist() генерирует HTML-сетку месяца с событиями.
    • Для оптимизации можно рендерить только «скелет» месяца (дни с индикаторами), а подробности дня подгружать отдельным запросом GET /calendar/day?date=..., возвращающим готовый HTML.
  3. Кеширование:
    • Сохранять готовые HTML-фрагменты в ETS-таблице archive_html_cache на основном узле (ключ – {Year, Month}).
    • Установить HTTP-заголовки: Cache-Control: public, max-age=86400, ETag на основе хеша содержимого.
    • При повторном запросе отдавать из кеша без обращения к архиву.
  4. Тестирование:
    • Перенести тестовые данные за прошлый день, запросить месяц через веб-интерфейс, проверить время ответа и корректность HTML.
    • Проверить, что архивный узел останавливается после таймаута.

Результат: основная база остаётся компактной, веб-клиент мгновенно отображает архивные месяцы без нагрузки на браузер.

## Этап 3. Архивирование с быстрым подключением и серверный рендеринг для веб-клиента (пункт 4 задачи + решение для веба) **Цель**: вынести исторические данные (старше 30 дней) в отдельные архивные узлы с возможностью быстрого доступа по требованию; реализовать серверный рендеринг календаря для минимизации нагрузки на браузеры. **Шаги**: ### 3.1. Модуль архивного контроллера (`archive_controller`) 1. **Функция переноса данных за день**: - По расписанию (например, ежедневно в непиковое время) для прошедшего дня `D` (формат `YYYYMMDD`): - Запустить отдельный Erlang-узел `eventhub_archive_D@Host` через `slave:start/3` или системный вызов `erl -sname ...`. - На архивном узле создать свою Mnesia-схему (`mnesia:create_schema([node()])`). - Создать таблицы (`event`, `booking`, `review` и т.д.) как `disc_only_copies` с теми же индексами, что и в основной базе (вызов обобщённой функции `create_indices/0` на архивном узле). - В рамках распределённой транзакции скопировать записи из основной базы за день `D` в архивный узел, затем удалить их из основной. - Остановить архивный узел (`init:stop/0`), сохранив его файлы на диске в каталоге `archive_dir/D/`. 2. **Обработка ошибок**: - Если перенос не удался, повторить позже, использовать `mnesia:backup/1` основной базы перед удалением. ### 3.2. Менеджер архивных узлов (`archive_manager` – gen_server на основном узле) 1. **Запуск архивного узла по требованию**: - При запросе к архиву определить требуемый день (или диапазон) и имя узла. - Проверить, запущен ли узел в пуле; если нет — запустить через `slave:start/3` или `erl -sname`, дождаться инициализации Mnesia. - Подключить основной узел к архивному через `mnesia:change_config(extra_db_nodes, [ArchiveNode])` (только для чтения). - Вернуть `{ok, ArchiveNode}`. 2. **Остановка неактивных узлов**: - Для каждого запущенного архивного узла запускать таймер (30 секунд после последнего использования); если новых запросов нет — отключить `extra_db_nodes`, остановить узел. 3. **Холодное хранение**: - Очень старые архивы (например, старше года) упаковывать в `tar.gz` и удалять с диска; при запросе — распаковать и запустить. ### 3.3. API и серверный рендеринг 1. **Эндпоинт для веб-клиента**: - `GET /calendar/view?month=2026-04&view=month` – возвращает готовый HTML. - В обработчике запроса: - Определить, что месяц холодный (более 30 дней от текущей даты), иначе использовать горячие таблицы. - Получить архивный узел через `archive_manager`. - Выполнить запросы к архивным таблицам: `mnesia:select(event, [{...}], ArchiveNode)` или `mnesia:read`. - Передать данные в функцию рендеринга. 2. **Модуль рендеринга `calendar_html_renderer`**: - Функция `render_month(Year, Month, Events) -> iolist()` генерирует HTML-сетку месяца с событиями. - Для оптимизации можно рендерить только «скелет» месяца (дни с индикаторами), а подробности дня подгружать отдельным запросом `GET /calendar/day?date=...`, возвращающим готовый HTML. 3. **Кеширование**: - Сохранять готовые HTML-фрагменты в ETS-таблице `archive_html_cache` на основном узле (ключ – `{Year, Month}`). - Установить HTTP-заголовки: `Cache-Control: public, max-age=86400`, `ETag` на основе хеша содержимого. - При повторном запросе отдавать из кеша без обращения к архиву. 4. **Тестирование**: - Перенести тестовые данные за прошлый день, запросить месяц через веб-интерфейс, проверить время ответа и корректность HTML. - Проверить, что архивный узел останавливается после таймаута. **Результат**: основная база остаётся компактной, веб-клиент мгновенно отображает архивные месяцы без нагрузки на браузер.
aleksey added the Future label 2026-05-02 16:16:19 +03:00
Author
Owner

План выполнения Задачи #15 – Архивирование и серверный рендеринг

1. Анализ и цели

После завершения задач #12, #13 и #14 основная база EventHub надёжна и реплицирована, но с ростом исторических данных производительность может снижаться.

Цели:

  • Вынести «холодные» данные (события, бронирования, отзывы старше 30 дней) в отдельные архивные Mnesia‑узлы.
  • Обеспечить быстрый доступ к архиву только по требованию, без постоянного потребления ресурсов.
  • Реализовать серверный рендеринг календаря для веб‑клиента, чтобы снять нагрузку с браузера при просмотре больших исторических периодов.

2. Архитектура решения

Вводятся три новых модуля и один HTTP‑эндпоинт:

Компонент Назначение
archive_controller Периодический перенос данных из основной БД в архивные узлы.
archive_manager gen_server, управляющий пулом запущенных архивных узлов (старт, стоп, таймаут неактивности).
calendar_html_renderer Генерация HTML‑представления календаря по данным из архива / основной БД.
GET /calendar/view?... Точка входа для веб‑клиента.

3. Детальный план реализации

Шаг 3.1. Модуль archive_controller

Ответственность: Перенос данных за указанный день в новый архивный узел.

  • Функция archive_day(Day) (где Day – строка "YYYYMMDD"):
    1. Запустить архивный узел через slave:start/3.
    2. На архивном узле:
      • Создать схему mnesia:create_schema([Node]).
      • Запустить Mnesia.
      • Создать таблицы для архивируемых сущностей (event, recurrence_exception, booking, review, report) как disc_only_copies с теми же индексами, что в основной БД.
    3. В распределённой транзакции:
      • Прочитать из основной БД все записи за день D (фильтр по start_time для событий, created_at для остальных).
      • Записать их в архивный узел.
      • Удалить эти записи из основной БД.
    4. Остановить архивный узел, сохранив его файлы в archive_dir/<Day>/.
    5. При ошибке – сделать повтор позже, перед удалением данных выполнять mnesia:backup/1.

Шаг 3.2. Модуль archive_manager

Ответственность: Управление жизненным циклом архивных узлов.

  • Тип: gen_server.
  • Состояние: map() с ключом Node :: atom()#{pid => pid(), last_access => integer()}.
  • API:
    • get_archive_node(Day) -> {ok, Node} | {error, term()}:
      1. Проверить пул – если узел для дня уже запущен, обновить last_access и вернуть его.
      2. Иначе запустить архивный узел (через slave:start или erl -sname).
      3. Дождаться готовности Mnesia на архивном узле.
      4. Подключить основной узел к архивному через mnesia:change_config(extra_db_nodes, [ArchiveNode]).
      5. Добавить узел в пул и вернуть.
  • Остановка неактивных узлов:
    • Для каждого узла запускается таймер (30 с).
    • Если до истечения таймера не было новых обращений – узел отключается и останавливается.
  • Холодное хранение (опционально): Для очень старых архивов – упаковка в tar.gz и удаление исходных файлов; при запросе – распаковка и запуск.

Шаг 3.3. Серверный рендеринг (calendar_html_renderer)

Ответственность: Генерация готового HTML для отображения календаря в браузере.

  • Функция render_month(Year, Month, Events):
    • Принимает список событий, год и месяц.
    • Строит HTML‑сетку месяца (таблица или div‑сетка).
    • Для каждого дня выводит краткую информацию о событиях (название, время, специалист).
  • Оптимизация: Сначала отрисовывается «скелет» месяца (дни с индикаторами наличия событий), а детали дня подгружаются отдельным запросом GET /calendar/day?date=....
  • Кеширование:
    • ETS‑таблица archive_html_cache, ключ {Year, Month}.
    • При первом запросе – сохранить сгенерированный HTML.
    • При повторном – отдать из кеша, минуя архивный узел.
    • HTTP‑заголовки: Cache-Control: public, max-age=86400, ETag.

Шаг 3.4. HTTP‑эндпоинт

  • GET /calendar/view?month=2026-05 (или from/to) – вход для веб‑клиента.
  • Логика:
    1. Определить, является ли запрошенный период «холодным» (старше 30 дней от текущей даты).
    2. Если холодный – получить узел через archive_manager:get_archive_node(Day).
    3. Прочитать события через mnesia:select / mnesia:read с нужного узла.
    4. Передать данные в calendar_html_renderer.
    5. Вернуть HTML‑ответ с заголовками кеширования.

4. Тестирование

  • Перенос данных: Создать тестовые события за прошлый день, запустить archive_controller:archive_day(...). Проверить, что данные удалены из основной БД и доступны на архивном узле.
  • Быстрое подключение: Остановить архивный узел, запросить данные через archive_manager. Узел должен запуститься и вернуть данные.
  • Серверный рендеринг: Запросить /calendar/view?month=2026-05. Ответ должен быть валидным HTML с архивными событиями. Проверить работу кеша и автоматическую остановку архивного узла после таймаута.

5. Документация

Добавить в README.md раздел «Архивирование данных»:

  • Как запустить архивирование вручную/автоматически.
  • Как получить доступ к архивным данным через API.
  • Настройки конфигурации (archive_dir, пороговый срок хранения в днях).
  • Особенности развёртывания в Docker Swarm (если применимо).

Этот план полностью согласован с выполненными задачами #12, #13, #14 и готов к реализации.

# План выполнения Задачи #15 – Архивирование и серверный рендеринг ## 1. Анализ и цели После завершения задач #12, #13 и #14 основная база EventHub надёжна и реплицирована, но с ростом исторических данных производительность может снижаться. **Цели:** - Вынести «холодные» данные (события, бронирования, отзывы старше 30 дней) в отдельные архивные Mnesia‑узлы. - Обеспечить быстрый доступ к архиву только по требованию, без постоянного потребления ресурсов. - Реализовать серверный рендеринг календаря для веб‑клиента, чтобы снять нагрузку с браузера при просмотре больших исторических периодов. ## 2. Архитектура решения Вводятся три новых модуля и один HTTP‑эндпоинт: | Компонент | Назначение | |----------------------------|------------| | `archive_controller` | Периодический перенос данных из основной БД в архивные узлы. | | `archive_manager` | `gen_server`, управляющий пулом запущенных архивных узлов (старт, стоп, таймаут неактивности). | | `calendar_html_renderer` | Генерация HTML‑представления календаря по данным из архива / основной БД. | | `GET /calendar/view?...` | Точка входа для веб‑клиента. | ## 3. Детальный план реализации ### Шаг 3.1. Модуль `archive_controller` **Ответственность:** Перенос данных за указанный день в новый архивный узел. - **Функция `archive_day(Day)` (где `Day` – строка `"YYYYMMDD"`):** 1. Запустить архивный узел через `slave:start/3`. 2. На архивном узле: - Создать схему `mnesia:create_schema([Node])`. - Запустить Mnesia. - Создать таблицы для архивируемых сущностей (`event`, `recurrence_exception`, `booking`, `review`, `report`) как `disc_only_copies` с теми же индексами, что в основной БД. 3. В распределённой транзакции: - Прочитать из основной БД все записи за день `D` (фильтр по `start_time` для событий, `created_at` для остальных). - Записать их в архивный узел. - Удалить эти записи из основной БД. 4. Остановить архивный узел, сохранив его файлы в `archive_dir/<Day>/`. 5. При ошибке – сделать повтор позже, перед удалением данных выполнять `mnesia:backup/1`. ### Шаг 3.2. Модуль `archive_manager` **Ответственность:** Управление жизненным циклом архивных узлов. - **Тип:** `gen_server`. - **Состояние:** `map()` с ключом `Node :: atom()` → `#{pid => pid(), last_access => integer()}`. - **API:** - `get_archive_node(Day) -> {ok, Node} | {error, term()}`: 1. Проверить пул – если узел для дня уже запущен, обновить `last_access` и вернуть его. 2. Иначе запустить архивный узел (через `slave:start` или `erl -sname`). 3. Дождаться готовности Mnesia на архивном узле. 4. Подключить основной узел к архивному через `mnesia:change_config(extra_db_nodes, [ArchiveNode])`. 5. Добавить узел в пул и вернуть. - **Остановка неактивных узлов:** - Для каждого узла запускается таймер (30 с). - Если до истечения таймера не было новых обращений – узел отключается и останавливается. - **Холодное хранение (опционально):** Для очень старых архивов – упаковка в `tar.gz` и удаление исходных файлов; при запросе – распаковка и запуск. ### Шаг 3.3. Серверный рендеринг (`calendar_html_renderer`) **Ответственность:** Генерация готового HTML для отображения календаря в браузере. - **Функция `render_month(Year, Month, Events)`:** - Принимает список событий, год и месяц. - Строит HTML‑сетку месяца (таблица или div‑сетка). - Для каждого дня выводит краткую информацию о событиях (название, время, специалист). - **Оптимизация:** Сначала отрисовывается «скелет» месяца (дни с индикаторами наличия событий), а детали дня подгружаются отдельным запросом `GET /calendar/day?date=...`. - **Кеширование:** - ETS‑таблица `archive_html_cache`, ключ `{Year, Month}`. - При первом запросе – сохранить сгенерированный HTML. - При повторном – отдать из кеша, минуя архивный узел. - HTTP‑заголовки: `Cache-Control: public, max-age=86400`, `ETag`. ### Шаг 3.4. HTTP‑эндпоинт - `GET /calendar/view?month=2026-05` (или `from/to`) – вход для веб‑клиента. - **Логика:** 1. Определить, является ли запрошенный период «холодным» (старше 30 дней от текущей даты). 2. Если холодный – получить узел через `archive_manager:get_archive_node(Day)`. 3. Прочитать события через `mnesia:select` / `mnesia:read` с нужного узла. 4. Передать данные в `calendar_html_renderer`. 5. Вернуть HTML‑ответ с заголовками кеширования. ## 4. Тестирование - **Перенос данных:** Создать тестовые события за прошлый день, запустить `archive_controller:archive_day(...)`. Проверить, что данные удалены из основной БД и доступны на архивном узле. - **Быстрое подключение:** Остановить архивный узел, запросить данные через `archive_manager`. Узел должен запуститься и вернуть данные. - **Серверный рендеринг:** Запросить `/calendar/view?month=2026-05`. Ответ должен быть валидным HTML с архивными событиями. Проверить работу кеша и автоматическую остановку архивного узла после таймаута. ## 5. Документация Добавить в `README.md` раздел «Архивирование данных»: - Как запустить архивирование вручную/автоматически. - Как получить доступ к архивным данным через API. - Настройки конфигурации (`archive_dir`, пороговый срок хранения в днях). - Особенности развёртывания в Docker Swarm (если применимо). --- Этот план полностью согласован с выполненными задачами #12, #13, #14 и готов к реализации.
Author
Owner

Финальная проверка задачи #15 – Архивирование и серверный рендеринг

Шаг 1. Подготовка окружения и загрузка записей

Очистите старые данные Mnesia и запустите приложение. Дождитесь приглашения (eventhub@DESKTOP-SIR8B3R)1> и сообщения Booted eventhub.

Код для терминала (bash):

rm -rf Mnesia.*
make shell

Код для Erlang-консоли после запуска:

rr("include/records.hrl").

Ожидаемый результат – список загруженных записей.

Шаг 2. Создание тестового пользователя

Сгенерируйте хеш пароля и создайте запись пользователя, который будет владельцем календаря.

{ok, Hash} = argon2:hash(<<"123456">>).
UserId = list_to_binary(io_lib:format("~p~p", [os:system_time(millisecond), rand:uniform(100000)])).
mnesia:dirty_write(#user{
    id = UserId,
    email = <<"owner@test.com">>,
    password_hash = Hash,
    role = user,
    status = active,
    created_at = calendar:universal_time(),
    updated_at = calendar:universal_time(),
    nickname = <<"owner">>
}).

Шаг 3. Создание календаря

Создайте календарь, принадлежащий этому пользователю. Запомните полученный CalendarId – он понадобится для HTTP-запросов.

CalendarId = list_to_binary(io_lib:format("~p~p", [os:system_time(millisecond)+1, rand:uniform(100000)])).
mnesia:dirty_write(#calendar{
    id = CalendarId,
    owner_id = UserId,
    title = <<"Test Calendar">>,
    type = personal,
    status = active,
    created_at = calendar:universal_time(),
    updated_at = calendar:universal_time()
}).

Шаг 4. Создание события за вчерашний день

Предположим, что сегодня 4 мая 2026, вчера – 3 мая. Создайте событие в прошлом.

Yesterday = {{2026,5,3},{10,0,0}}.
mnesia:dirty_write(#event{
    id = list_to_binary(io_lib:format("~p~p", [os:system_time(millisecond)+2, rand:uniform(100000)])),
    calendar_id = CalendarId,
    start_time = Yesterday,
    duration = 60,
    event_type = single,
    title = <<"Yesterday's event">>,
    description = <<"To be archived">>,
    status = active,
    created_at = Yesterday,
    updated_at = Yesterday
}).

Проверьте, что запись видна:

length(mnesia:dirty_match_object(#event{calendar_id = CalendarId, _ = '_'})).
% должно вернуть 1

Шаг 5. Получение JWT-токена владельца

В новом терминале (bash) выполните логин:

curl -s -X POST http://localhost:8080/v1/login \
  -H "Content-Type: application/json" \
  -d '{"email":"owner@test.com","password":"123456"}'

Из ответа извлеките access_token и сохраните в переменную:

TOKEN="скопированный access_token"

Шаг 6. Проверка отображения горячего события

Запросите календарь за май 2026 (горячий месяц):

curl -s -o /tmp/calendar_hot.html -w "%{http_code}" \
  -H "Authorization: Bearer $TOKEN" \
  "http://localhost:8080/v1/calendars/$CALENDAR_ID/view?month=2026-05"

Должен вернуться HTTP 200. Проверьте содержимое:

grep "Yesterday's event" /tmp/calendar_hot.html

Если событие найдено – горячий режим работает.

Шаг 7. Архивирование за вчерашний день

В Erlang-консоли выполните:

archive_controller:archive_day("20260503").

Дождитесь сообщения Archived day 20260503 successfully.

Проверьте, что событие удалено из основной базы:

mnesia:dirty_match_object(#event{calendar_id = CalendarId, _ = '_'}).
% должно вернуть []

Шаг 8. Проверка отображения архивного события

Снова запросите календарь за май:

curl -s -o /tmp/calendar_archived.html -w "%{http_code}" \
  -H "Authorization: Bearer $TOKEN" \
  "http://localhost:8080/v1/calendars/$CALENDAR_ID/view?month=2026-05"

Убедитесь, что событие по-прежнему видно (теперь оно берётся из архива):

grep "Yesterday's event" /tmp/calendar_archived.html

Шаг 9. Проверка защиты от не-владельца

Создайте второго пользователя и получите его токен. Попробуйте запросить календарь с этим токеном – должен вернуться HTTP 403.

Шаг 10. Сброс кеша и повторный запрос

В Erlang-консоли удалите кеш:

ets:delete(archive_html_cache).

Повторите запрос календаря – он должен выполниться без ошибок и вернуть тот же HTML.

Заключение

Если все шаги выполнены успешно, задача #15 полностью готова.

# Финальная проверка задачи #15 – Архивирование и серверный рендеринг ## Шаг 1. Подготовка окружения и загрузка записей Очистите старые данные Mnesia и запустите приложение. Дождитесь приглашения `(eventhub@DESKTOP-SIR8B3R)1>` и сообщения `Booted eventhub`. Код для терминала (bash): rm -rf Mnesia.* make shell Код для Erlang-консоли после запуска: rr("include/records.hrl"). Ожидаемый результат – список загруженных записей. ## Шаг 2. Создание тестового пользователя Сгенерируйте хеш пароля и создайте запись пользователя, который будет владельцем календаря. {ok, Hash} = argon2:hash(<<"123456">>). UserId = list_to_binary(io_lib:format("~p~p", [os:system_time(millisecond), rand:uniform(100000)])). mnesia:dirty_write(#user{ id = UserId, email = <<"owner@test.com">>, password_hash = Hash, role = user, status = active, created_at = calendar:universal_time(), updated_at = calendar:universal_time(), nickname = <<"owner">> }). ## Шаг 3. Создание календаря Создайте календарь, принадлежащий этому пользователю. Запомните полученный `CalendarId` – он понадобится для HTTP-запросов. CalendarId = list_to_binary(io_lib:format("~p~p", [os:system_time(millisecond)+1, rand:uniform(100000)])). mnesia:dirty_write(#calendar{ id = CalendarId, owner_id = UserId, title = <<"Test Calendar">>, type = personal, status = active, created_at = calendar:universal_time(), updated_at = calendar:universal_time() }). ## Шаг 4. Создание события за вчерашний день Предположим, что сегодня 4 мая 2026, вчера – 3 мая. Создайте событие в прошлом. Yesterday = {{2026,5,3},{10,0,0}}. mnesia:dirty_write(#event{ id = list_to_binary(io_lib:format("~p~p", [os:system_time(millisecond)+2, rand:uniform(100000)])), calendar_id = CalendarId, start_time = Yesterday, duration = 60, event_type = single, title = <<"Yesterday's event">>, description = <<"To be archived">>, status = active, created_at = Yesterday, updated_at = Yesterday }). Проверьте, что запись видна: length(mnesia:dirty_match_object(#event{calendar_id = CalendarId, _ = '_'})). % должно вернуть 1 ## Шаг 5. Получение JWT-токена владельца В новом терминале (bash) выполните логин: curl -s -X POST http://localhost:8080/v1/login \ -H "Content-Type: application/json" \ -d '{"email":"owner@test.com","password":"123456"}' Из ответа извлеките `access_token` и сохраните в переменную: TOKEN="скопированный access_token" ## Шаг 6. Проверка отображения горячего события Запросите календарь за май 2026 (горячий месяц): curl -s -o /tmp/calendar_hot.html -w "%{http_code}" \ -H "Authorization: Bearer $TOKEN" \ "http://localhost:8080/v1/calendars/$CALENDAR_ID/view?month=2026-05" Должен вернуться HTTP 200. Проверьте содержимое: grep "Yesterday's event" /tmp/calendar_hot.html Если событие найдено – горячий режим работает. ## Шаг 7. Архивирование за вчерашний день В Erlang-консоли выполните: archive_controller:archive_day("20260503"). Дождитесь сообщения `Archived day 20260503 successfully.` Проверьте, что событие удалено из основной базы: mnesia:dirty_match_object(#event{calendar_id = CalendarId, _ = '_'}). % должно вернуть [] ## Шаг 8. Проверка отображения архивного события Снова запросите календарь за май: curl -s -o /tmp/calendar_archived.html -w "%{http_code}" \ -H "Authorization: Bearer $TOKEN" \ "http://localhost:8080/v1/calendars/$CALENDAR_ID/view?month=2026-05" Убедитесь, что событие по-прежнему видно (теперь оно берётся из архива): grep "Yesterday's event" /tmp/calendar_archived.html ## Шаг 9. Проверка защиты от не-владельца Создайте второго пользователя и получите его токен. Попробуйте запросить календарь с этим токеном – должен вернуться HTTP 403. ## Шаг 10. Сброс кеша и повторный запрос В Erlang-консоли удалите кеш: ets:delete(archive_html_cache). Повторите запрос календаря – он должен выполниться без ошибок и вернуть тот же HTML. ## Заключение Если все шаги выполнены успешно, задача #15 полностью готова.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Reference: EventHub/EventHubBack#15