From 5cc2bcf736b1dfb121bd4c8feb9aa7d9361ecf34 Mon Sep 17 00:00:00 2001 From: Aleksey Sabilin Date: Mon, 20 Jul 2026 22:11:21 +0300 Subject: [PATCH] docs: sync calendar follow API and Front UX. Refs EventHub/EventHubFront#9 --- EventHubBackSpec.md | 15 ++++++++++++++- EventHubFrontSpec.md | 8 +++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/EventHubBackSpec.md b/EventHubBackSpec.md index 9813eec..0e35dc1 100644 --- a/EventHubBackSpec.md +++ b/EventHubBackSpec.md @@ -81,6 +81,8 @@ EventHub — платформа для управления событиями `edited_at :: calendar:datetime() | undefined` - `review_vote` — голос пользователя за отзыв: `id`, `review_id`, `user_id`, `value :: like | dislike`, `created_at`, `updated_at` (уникальность пары review+user) +- `calendar_follow` — follow чужого календаря: `id`, `calendar_id`, `user_id`, `created_at` + (уникальность пары calendar+user; не путать с `calendar_share` и платной `subscription`) #### 2.2.6. Требования к реализации - Все операции с событиями должны быть транзакционными. @@ -88,6 +90,14 @@ EventHub — платформа для управления событиями и кэширование). - При поиске событий для календаря учитывать права доступа пользователя. +### 2.2.7. Follow чужого календаря +- Пользователь может **отслеживать** (follow) чужой календарь, к которому у него есть доступ + (`logic_calendar:can_access/2`) и который ему не принадлежит. +- Follow **не** даёт право на отзыв — gate отзывов остаётся confirmed booking (§2.4). +- Follow **не** связан с платной подпиской (`subscription`) и с `calendar_share` (права invite). +- API: `POST/DELETE /v1/calendars/:id/follow` (идемпотентно), `GET /v1/user/following` + (список active доступных календарей); в `GET /v1/calendars/:id` — поле `following` (boolean). + ### 2.3. Запись участников и подтверждение - Пользователь может отправить заявку на участие в событии. - В зависимости от `confirmation` календаря заявка либо подтверждается автоматически, либо @@ -293,9 +303,12 @@ src/ email/role/status; неизвестные поля → `400`. Ответ — полный профиль как GET. - `GET /v1/user/bookings` — бронирования пользователя. - `GET /v1/user/reviews` — отзывы пользователя. +- `GET /v1/user/following` — календари, которые пользователь отслеживает (follow). - `GET /v1/search` — поиск; пустой запрос (только auth + пагинация/`type`) — discovery tops. - `GET /v1/calendars` — список календарей. -- `GET /v1/calendars/:id` — календарь. +- `GET /v1/calendars/:id` — календарь (поле `following` для текущего пользователя). +- `POST /v1/calendars/:id/follow` — отслеживать чужой календарь. +- `DELETE /v1/calendars/:id/follow` — снять follow. - `GET /v1/calendars/:calendar_id/events` — события календаря. - `GET /v1/events/:id` — событие. - `GET /v1/events/:id/occurrences` — вхождения повторяющегося события. diff --git a/EventHubFrontSpec.md b/EventHubFrontSpec.md index be87abe..de5d36f 100644 --- a/EventHubFrontSpec.md +++ b/EventHubFrontSpec.md @@ -54,7 +54,10 @@ Deep-link на календарь, владельцем которого явл - Выбор события открывает карточку действий: mobile — bottom sheet; desktop — боковая панель. Действия зависят от роли (owner / participant). - Без выбранного события — панель «О календаре» (описание, title/meta, рейтинг, отзывы). Форма отзыва на календарь/событие — только при confirmed booking; жалоба доступна без записи. + На чужом календаре — CTA **«Отслеживать» / Follow** (не путать с платной «Подписка»); + follow не открывает форму отзыва. - На чужом `/c/:id` — CTA «Мой календарь» и таб Calendar не `aria-current` (intent `browse`). +- Список отслеживаемых: `/following` (из «Ещё»). - Открытие события — `navigate` push (не `replace`), чтобы Back возвращал к календарю. - Owner: WS subscribe на активный календарь; `PUT` события из карточки; `PUT` календаря на `/calendars`. - Поиск (`/search`): query/filters в URL params (восстановление при возврате); chip type фильтрует @@ -91,6 +94,7 @@ Deep-link на календарь, владельцем которого явл - `/bookings` — мои бронирования (deep-link в `/c/.../e/...`) - `/calendars` — управление своими календарями (CRUD) - `/more` — вторичное меню + mood switcher +- `/following` — отслеживаемые чужие календари (follow; не платная Подписка) - `/reviews`, `/subscription`, `/tickets`, `/profile` Redirects: `/discover` → `/search`; `/calendars/:id` → `/c/:id`; `/calendars/:id/events/:eventId` → `/c/:id/e/:eventId`. @@ -110,7 +114,9 @@ Redirects: `/discover` → `/search`; `/calendars/:id` → `/c/:id`; `/calendars ### 5.4. Календари - Список своих: `GET /v1/calendars` -- CRUD: `POST/PUT/DELETE /v1/calendars`, `GET /v1/calendars/:id` +- CRUD: `POST/PUT/DELETE /v1/calendars`, `GET /v1/calendars/:id` (поле `following`) +- Follow чужого: `POST/DELETE /v1/calendars/:id/follow`, список `GET /v1/user/following` + (UI: «Отслеживать» в about, страница `/following`; не путать с `/subscription`) - Просмотр коммерческого чужого календаря по id (доступ по правилам бэка) - HTML month view владельца: `GET /v1/calendars/:calendar_id/view?month=YYYY-MM` — при переключении виджета на **прошедший месяц** (owner + вид «Месяц») автоматически подменяет клиентский grid серверным HTML (live/архив, задача #15). Текущий и будущие месяцы — React-виджет по `GET …/events`. - Создание `commercial` требует активной подписки (ответ 402 → экран подписки)