Docs: sync booking-requests + Bookings IA + image_url after Back#59/Front#30. Fixes EventHub/EventHubSpec#12
This commit is contained in:
@@ -0,0 +1,33 @@
|
|||||||
|
---
|
||||||
|
description: EventHub — локальные сборки/тесты только через WSL (Windows toolchain сломан)
|
||||||
|
alwaysApply: true
|
||||||
|
---
|
||||||
|
|
||||||
|
# EventHub: рабочее окружение агента
|
||||||
|
|
||||||
|
На этой машине **не использовать** нативный Windows для:
|
||||||
|
|
||||||
|
| Стек | Нельзя (Windows) | Нужно |
|
||||||
|
|------|------------------|--------|
|
||||||
|
| Front / FrontAdmin | `npm`, `npx`, Playwright | **WSL** `npm` |
|
||||||
|
| Back (Erlang) | Windows `erl` / `rebar3` | **WSL** + `scripts/wsl-dev-env.sh` |
|
||||||
|
|
||||||
|
## Front (EventHubFront)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
wsl -e bash -lc 'cd /mnt/c/Users/alexc/IdeaProjects/eventHub/EventHubFront && npm run lint && npm run build && npm run test:e2e'
|
||||||
|
```
|
||||||
|
|
||||||
|
## FrontAdmin
|
||||||
|
|
||||||
|
```bash
|
||||||
|
wsl -e bash -lc 'cd /mnt/c/Users/alexc/IdeaProjects/eventHub/EventHubFrontAdmin && npm run lint && npm run build'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Back
|
||||||
|
|
||||||
|
```bash
|
||||||
|
wsl -e bash -lc 'cd /mnt/c/Users/alexc/IdeaProjects/eventHub/EventHubBack && source scripts/wsl-dev-env.sh && rebar3 eunit'
|
||||||
|
```
|
||||||
|
|
||||||
|
Подробности: `EventHubFront/.cursor/rules/npm-wsl.mdc`, `EventHubBack/.cursor/rules/otp-rebar-wsl.mdc`.
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
---
|
||||||
|
description: Один агент — один репозиторий; не смешивать Front и Back
|
||||||
|
alwaysApply: true
|
||||||
|
---
|
||||||
|
|
||||||
|
# EventHub: отдельные агенты по репозиториям
|
||||||
|
|
||||||
|
## Правило
|
||||||
|
При работе с **несколькими репозиториями** EventHub запускай **отдельного агента на каждый репо**. Не смешивай Front и Back (и Spec/FrontAdmin) в одном агенте.
|
||||||
|
|
||||||
|
| Репо | Зона |
|
||||||
|
|------|------|
|
||||||
|
| `EventHubFront` | клиентский SPA |
|
||||||
|
| `EventHubBack` | Erlang API |
|
||||||
|
| `EventHubSpec` | спеки, UI-PARITY, контракты |
|
||||||
|
| `EventHubFrontAdmin` | admin SPA |
|
||||||
|
|
||||||
|
## Запрещено
|
||||||
|
- Один агент правит и Front, и Back в одной сессии
|
||||||
|
- Коммиты/`Refs`/`Fixes` не в тот репо (Front-код → issue Back, и наоборот)
|
||||||
|
- Закрывать/комментировать issue чужого репо «заодно»
|
||||||
|
|
||||||
|
## Как делать
|
||||||
|
1. Спека/issue → агент **Spec** (или короткий foreground), если только доки.
|
||||||
|
2. API → отдельный агент **Back** (`Back#N`, eunit, push Back).
|
||||||
|
3. UI → отдельный агент **Front** (`Front#N`, lint/IFT, push Front).
|
||||||
|
4. Родитель-координатор только маршрутизирует; не пишет код сразу в два репо.
|
||||||
|
|
||||||
|
Кросс-репо фича (например Bookings inbox): **сначала Back**, потом **Front** (или параллельно двумя агентами), Spec — третьим или после стабилизации API.
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
---
|
||||||
|
description: Shell — только WSL/bash; PowerShell-экранирование запрещено для сложного
|
||||||
|
alwaysApply: true
|
||||||
|
---
|
||||||
|
|
||||||
|
# Shell: WSL, не PowerShell
|
||||||
|
|
||||||
|
Агенты **не должны** гонять сложные one-liner’ы в PowerShell (ломается экранирование).
|
||||||
|
|
||||||
|
Канон: файл `.sh` + `wsl -e bash /mnt/c/.../script.sh`, либо
|
||||||
|
`wsl -e bash -lc 'простая команда без вложенных двойных кавычек'`.
|
||||||
|
|
||||||
|
Полный текст: `EventHubBack/.cursor/rules/shell-wsl-not-powershell.mdc`.
|
||||||
+13
-2
@@ -171,6 +171,8 @@ Legacy: прямой `POST /v1/calendars/:id/specialists` **не использ
|
|||||||
(иначе `400`).
|
(иначе `400`).
|
||||||
- **Confirm/decline booking:** владелец — любые booking календаря; `active` specialist — только
|
- **Confirm/decline booking:** владелец — любые booking календаря; `active` specialist — только
|
||||||
booking на событиях, где `event.specialist_id` = его `user_id`.
|
booking на событиях, где `event.specialist_id` = его `user_id`.
|
||||||
|
- **Inbox к подтверждению:** `GET /v1/user/booking-requests` агрегирует pending по тем же
|
||||||
|
правилам (owner — все события своих календарей; specialist — только свои слоты).
|
||||||
|
|
||||||
#### Фаза 2 (вне текущего контракта реализации)
|
#### Фаза 2 (вне текущего контракта реализации)
|
||||||
- `calendar_share` (`read` | `write` | `admin`): не путать с follow, specialist_invite и платной subscription.
|
- `calendar_share` (`read` | `write` | `admin`): не путать с follow, specialist_invite и платной subscription.
|
||||||
@@ -453,10 +455,18 @@ src/
|
|||||||
`nickname`, `timezone`, `phone`, `avatar_url`, `preferences`; смена пароля —
|
`nickname`, `timezone`, `phone`, `avatar_url`, `preferences`; смена пароля —
|
||||||
пара `current_password` + `password` (неверный текущий → `403`). Нельзя менять
|
пара `current_password` + `password` (неверный текущий → `403`). Нельзя менять
|
||||||
email/role/status; неизвестные поля → `400`. Ответ — полный профиль как GET.
|
email/role/status; неизвестные поля → `400`. Ответ — полный профиль как GET.
|
||||||
- `GET /v1/user/bookings` — бронирования пользователя.
|
- `GET /v1/user/bookings` — бронирования пользователя **как участника**.
|
||||||
|
- `GET /v1/user/booking-requests` — pending-заявки к подтверждению, где текущий
|
||||||
|
пользователь — **owner** календаря события или **assigned specialist**
|
||||||
|
(`event.specialist_id` = user и specialist active). Ответ — массив объектов
|
||||||
|
booking + `role` (`owner`|`specialist`) + вложенный `event`
|
||||||
|
(`id`, `calendar_id`, `calendar_title`, `title`, `start_time`, `duration`,
|
||||||
|
`specialist_id`). Confirm/decline — существующий `PUT /v1/bookings/:id`.
|
||||||
- `GET /v1/user/reviews` — отзывы пользователя.
|
- `GET /v1/user/reviews` — отзывы пользователя.
|
||||||
- `GET /v1/user/following` — календари, которые пользователь отслеживает (follow).
|
- `GET /v1/user/following` — календари, которые пользователь отслеживает (follow).
|
||||||
- `GET /v1/search` — поиск; пустой запрос (только auth + пагинация/`type`) — discovery tops.
|
- `GET /v1/search` — поиск; пустой запрос (только auth + пагинация/`type`) — discovery tops.
|
||||||
|
В calendar-результатах — `image_url` (если задан на календаре). Upload/multipart
|
||||||
|
**не** входит в контракт: поле URL.
|
||||||
- `GET /v1/calendars` — список календарей.
|
- `GET /v1/calendars` — список календарей.
|
||||||
- `POST /v1/calendars` — создать календарь (`commercial` → подписка/trial; иначе `402`).
|
- `POST /v1/calendars` — создать календарь (`commercial` → подписка/trial; иначе `402`).
|
||||||
- `GET /v1/calendars/:id` — календарь (`following`, `booking_open` для текущего контекста).
|
- `GET /v1/calendars/:id` — календарь (`following`, `booking_open` для текущего контекста).
|
||||||
@@ -482,7 +492,8 @@ src/
|
|||||||
- `POST /v1/events/:id/bookings` — запись на событие.
|
- `POST /v1/events/:id/bookings` — запись на событие.
|
||||||
- `GET /v1/events/:id/bookings` — список бронирований события (владелец).
|
- `GET /v1/events/:id/bookings` — список бронирований события (владелец).
|
||||||
- `GET /v1/bookings/:id` — статус бронирования.
|
- `GET /v1/bookings/:id` — статус бронирования.
|
||||||
- `PUT /v1/bookings/:id` — подтвердить/отклонить бронирование (владелец).
|
- `PUT /v1/bookings/:id` — подтвердить/отклонить (`confirm`|`decline`); владелец —
|
||||||
|
любые booking календаря; active specialist — только события со своим `specialist_id`.
|
||||||
- `DELETE /v1/bookings/:id` — отменить бронирование (участник).
|
- `DELETE /v1/bookings/:id` — отменить бронирование (участник).
|
||||||
- `POST /v1/reviews` — создать отзыв.
|
- `POST /v1/reviews` — создать отзыв.
|
||||||
- `GET /v1/reviews` — список отзывов (поле `my_vote` для текущего пользователя).
|
- `GET /v1/reviews` — список отзывов (поле `my_vote` для текущего пользователя).
|
||||||
|
|||||||
+19
-5
@@ -51,6 +51,9 @@ Deep-link на календарь, владельцем которого явл
|
|||||||
|
|
||||||
- Главная сущность — **календарь**. Центр UI — виджет с видами **месяц** (default) / **неделя** / **день**.
|
- Главная сущность — **календарь**. Центр UI — виджет с видами **месяц** (default) / **неделя** / **день**.
|
||||||
- Главные вкладки: **Календарь** (`/`, `/c/:id`), **Найти** (`/search`), **Записи** (`/bookings`), **Ещё** (`/more`).
|
- Главные вкладки: **Календарь** (`/`, `/c/:id`), **Найти** (`/search`), **Записи** (`/bookings`), **Ещё** (`/more`).
|
||||||
|
- **Записи** (`/bookings`) — grouped inbox: «К подтверждению» (owner/specialist pending + Confirm/Decline)
|
||||||
|
и «Мои записи» (participant); пустые группы скрывать. Confirm на карточке события остаётся.
|
||||||
|
- В **Ещё**: пункт входящих specialist invites скрыт при `pending=0` (deep-link `/invites` работает).
|
||||||
- Контекст виджета: свой календарь (селектор) или чужой (browse после поиска). Чужой `personal` —
|
- Контекст виджета: свой календарь (селектор) или чужой (browse после поиска). Чужой `personal` —
|
||||||
только просмотр; чужой `commercial` с `booking_open=true` — запись; при `booking_open=false`
|
только просмотр; чужой `commercial` с `booking_open=true` — запись; при `booking_open=false`
|
||||||
(restricted / нет подписки владельца) — просмотр + сообщение «Запись временно недоступна».
|
(restricted / нет подписки владельца) — просмотр + сообщение «Запись временно недоступна».
|
||||||
@@ -96,9 +99,12 @@ Deep-link на календарь, владельцем которого явл
|
|||||||
- `/c/:calendarId` — workspace с календарём
|
- `/c/:calendarId` — workspace с календарём
|
||||||
- `/c/:calendarId/e/:eventId` — workspace + карточка события
|
- `/c/:calendarId/e/:eventId` — workspace + карточка события
|
||||||
- `/search` — поиск календарей/событий
|
- `/search` — поиск календарей/событий
|
||||||
- `/bookings` — мои бронирования (deep-link в `/c/.../e/...`)
|
- `/bookings` — grouped inbox: (A) к подтверждению (owner/specialist pending) +
|
||||||
|
(B) мои записи участника; deep-link в `/c/.../e/...`
|
||||||
- `/calendars` — управление своими календарями (CRUD)
|
- `/calendars` — управление своими календарями (CRUD)
|
||||||
- `/more` — вторичное меню + mood switcher
|
- `/more` — вторичное меню + mood switcher; пункт specialist invites **скрыт**,
|
||||||
|
если входящих pending = 0 (deep-link `/invites?token=` работает)
|
||||||
|
- `/invites` — inbox входящих specialist invites (не смешивать с `/bookings`)
|
||||||
- `/following` — отслеживаемые чужие календари (follow; не платная Подписка)
|
- `/following` — отслеживаемые чужие календари (follow; не платная Подписка)
|
||||||
- `/reviews`, `/subscription`, `/tickets`, `/profile`
|
- `/reviews`, `/subscription`, `/tickets`, `/profile`
|
||||||
|
|
||||||
@@ -116,6 +122,7 @@ Redirects: `/discover` → `/search`; `/calendars/:id` → `/c/:id`; `/calendars
|
|||||||
|
|
||||||
### 5.3. Поиск (участник)
|
### 5.3. Поиск (участник)
|
||||||
`GET /v1/search` — фильтры (`type`, `q`, `tags`, даты, `lat`/`lon`/`radius`, sort, order, пагинация). Без `q`/дат/tags/geo/sort — топы календарей и событий; иначе — поиск. В списке бейдж типа — `calendar`|`event` (не `personal`/`commercial`). Даты, теги, geo и сортировка свёрнуты по умолчанию. Переход к `/c/:id` или `/c/:id/e/:eventId`.
|
`GET /v1/search` — фильтры (`type`, `q`, `tags`, даты, `lat`/`lon`/`radius`, sort, order, пагинация). Без `q`/дат/tags/geo/sort — топы календарей и событий; иначе — поиск. В списке бейдж типа — `calendar`|`event` (не `personal`/`commercial`). Даты, теги, geo и сортировка свёрнуты по умолчанию. Переход к `/c/:id` или `/c/:id/e/:eventId`.
|
||||||
|
В результатах calendar (и event, если Back отдаёт) может быть `image_url` — Discover показывает cover; иначе mood wash + initials. **Upload API нет** — поле URL (seed / ручная установка).
|
||||||
|
|
||||||
### 5.4. Календари
|
### 5.4. Календари
|
||||||
- Список своих: `GET /v1/calendars`
|
- Список своих: `GET /v1/calendars`
|
||||||
@@ -132,8 +139,10 @@ Redirects: `/discover` → `/search`; `/calendars/:id` → `/c/:id`; `/calendars
|
|||||||
список active + исходящие pending; deactivate/remove принятых.
|
список active + исходящие pending; deactivate/remove принятых.
|
||||||
Выбор `specialist_id` в форме события (только `active`).
|
Выбор `specialist_id` в форме события (только `active`).
|
||||||
Баннер «подписка истекла / истекает» при `booking_open=false`.
|
Баннер «подписка истекла / истекает» при `booking_open=false`.
|
||||||
- Invitee: inbox входящих `GET /v1/user/specialist-invites` (More / уведомления) —
|
- Invitee: inbox входящих `GET /v1/user/specialist-invites` на `/invites` —
|
||||||
принять / отклонить; deep-link из email → accept по `token` после логина.
|
принять / отклонить; deep-link из email → accept по `token` после логина.
|
||||||
|
В More пункт «Приглашения» показывается **только** при `pending > 0`
|
||||||
|
(не путать с booking-заявками на `/bookings`).
|
||||||
|
|
||||||
### 5.5. События
|
### 5.5. События
|
||||||
- Список: `GET /v1/calendars/:calendar_id/events`
|
- Список: `GET /v1/calendars/:calendar_id/events`
|
||||||
@@ -145,8 +154,13 @@ Redirects: `/discover` → `/search`; `/calendars/:id` → `/c/:id`; `/calendars
|
|||||||
### 5.6. Запись (bookings)
|
### 5.6. Запись (bookings)
|
||||||
- Участник: `POST /v1/events/:id/bookings` только при `booking_open`; иначе UI-сообщение /
|
- Участник: `POST /v1/events/:id/bookings` только при `booking_open`; иначе UI-сообщение /
|
||||||
ответ `403`; `GET /v1/user/bookings`, `DELETE /v1/bookings/:id`, `GET /v1/bookings/:id`
|
ответ `403`; `GET /v1/user/bookings`, `DELETE /v1/bookings/:id`, `GET /v1/bookings/:id`
|
||||||
- Владелец и specialist: `GET /v1/events/:id/bookings`, `PUT /v1/bookings/:id`
|
- Владелец и specialist:
|
||||||
`{ action: confirm | decline }` (specialist — только свои события, см. BackSpec §2.1.2)
|
- на карточке события: `GET /v1/events/:id/bookings` + Confirm/Decline (**обязательно**)
|
||||||
|
- inbox `/bookings` группа «К подтверждению»: `GET /v1/user/booking-requests`
|
||||||
|
(pending, где user — owner календаря или `event.specialist_id`); те же
|
||||||
|
`PUT /v1/bookings/:id` `{ action: confirm | decline }`
|
||||||
|
- UI `/bookings`: две группы (пустые скрывать): **К подтверждению** + **Мои записи**
|
||||||
|
(upcoming/past participant). `specialist_invite` сюда **не** попадает.
|
||||||
- Статусы: `pending` | `confirmed` | `cancelled`; confirmation: `auto` | `manual` | timeout
|
- Статусы: `pending` | `confirmed` | `cancelled`; confirmation: `auto` | `manual` | timeout
|
||||||
- Pending резервирует capacity (как на бэке)
|
- Pending резервирует capacity (как на бэке)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# Stage Popular cleanup notes
|
||||||
|
|
||||||
|
Popular / Discover empty-search feed = ratings tops (`GET /v1/search` without `q`/filters).
|
||||||
|
E2E и smoke иногда оставляют commercial-календари с рейтингами, из‑за чего лента засоряется.
|
||||||
|
|
||||||
|
## Правила
|
||||||
|
|
||||||
|
1. **Не** удалять «живые» smoke-календари пилота без явного фильтра.
|
||||||
|
2. Чистить только по безопасным маркерам (название/тег/описание содержат `e2e`, `E2E`, `playwright`, `ift-litter`, или owner = известный e2e user).
|
||||||
|
3. Soft-delete через API (`DELETE /v1/calendars/:id` владельцем / admin), не ручной wipe Mnesia.
|
||||||
|
4. Front already tracks calendars created in-session via `e2e/helpers/standCleanup.ts` — предпочитать это для новых тестов.
|
||||||
|
|
||||||
|
## Suggested filter (admin / ops)
|
||||||
|
|
||||||
|
- title/tags match: `(?i)e2e|playwright|ift-litter|tmp-`
|
||||||
|
- created recently + zero real bookings, if policy allows
|
||||||
|
- exclude calendars used by documented stage smoke accounts
|
||||||
|
|
||||||
|
## Upload / cover images
|
||||||
|
|
||||||
|
`image_url` на календаре отдаётся в search. **Upload API нет** — seed URL вручную или через admin/update поля. Discover показывает cover если URL непустой, иначе mood wash + initials.
|
||||||
|
|
||||||
|
Refs: EventHubSpec#12, EventHubBack#59, EventHubFront#30.
|
||||||
@@ -362,6 +362,7 @@ error rate > 1% **или** mean request > 500 ms (hold ≥2 мин в фазе)
|
|||||||
- После успешных тестов — обновить спеку, если менялся внешний контракт.
|
- После успешных тестов — обновить спеку, если менялся внешний контракт.
|
||||||
- Одна задача — один логический объём работы.
|
- Одна задача — один логический объём работы.
|
||||||
- Код фичи — в репозитории-владельце; `EventHubSpec` — для документации и процесса.
|
- Код фичи — в репозитории-владельце; `EventHubSpec` — для документации и процесса.
|
||||||
|
- **Один агент — один репо** (не смешивать Front/Back/Spec/FrontAdmin в одной сессии): `.cursor/rules/one-repo-per-agent.mdc`.
|
||||||
- Метки во всех репозиториях держать одинаковыми (`sync-labels.ps1`).
|
- Метки во всех репозиториях держать одинаковыми (`sync-labels.ps1`).
|
||||||
- Секреты и токены не коммитить; Gitea token — только в env / `~/.cursor/secrets/`.
|
- Секреты и токены не коммитить; Gitea token — только в env / `~/.cursor/secrets/`.
|
||||||
- **Git commit/push — через WSL** (`~/.cursor/eventhub/git-commit.sh`, `git-push.sh`); **push — только после подтверждения пользователя** (см. §2.1).
|
- **Git commit/push — через WSL** (`~/.cursor/eventhub/git-commit.sh`, `git-push.sh`); **push — только после подтверждения пользователя** (см. §2.1).
|
||||||
@@ -377,6 +378,7 @@ error rate > 1% **или** mean request > 500 ms (hold ≥2 мин в фазе)
|
|||||||
|
|
||||||
| Дата | Изменение |
|
| Дата | Изменение |
|
||||||
|------|-----------|
|
|------|-----------|
|
||||||
|
| 2026-07-27 | Spec#12: booking-requests + Bookings IA + image_url; правило one-repo-per-agent |
|
||||||
| 2026-07-27 | §6 / STAGE-BROWSER: канон — прямой HTTPS `*.calentiq.com`; proxy `:8787` только DNS-fallback |
|
| 2026-07-27 | §6 / STAGE-BROWSER: канон — прямой HTTPS `*.calentiq.com`; proxy `:8787` только DNS-fallback |
|
||||||
| 2026-07-22 | §6: Stage UI в Cursor Browser — `STAGE-BROWSER.md` + alias proxy |
|
| 2026-07-22 | §6: Stage UI в Cursor Browser — `STAGE-BROWSER.md` + alias proxy |
|
||||||
| 2026-07-22 | §2.1: Agent shell — не PowerShell для сложного; `.sh` + WSL; Front push только после lint/build/IFT |
|
| 2026-07-22 | §2.1: Agent shell — не PowerShell для сложного; `.sh` + WSL; Front push только после lint/build/IFT |
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ SoT: [`boards/calentiq-ui-board-final.png`](boards/calentiq-ui-board-final.png).
|
|||||||
| Pixel-perfect calendar | denser board mock + Today/Upcoming rail | Agenda rail (§B): title-case Сегодня/Предстоящие + count, time-first rows; month chips/cell wash (§B/D) по mood; не 1:1 Figma |
|
| Pixel-perfect calendar | denser board mock + Today/Upcoming rail | Agenda rail (§B): title-case Сегодня/Предстоящие + count, time-first rows; month chips/cell wash (§B/D) по mood; не 1:1 Figma |
|
||||||
| Discover cards | soft cards + media thumb + CTA | mood media plane (wash/initials + `image_url` when present) + soft-card rhythm + CTA; без full photo-hero grid |
|
| Discover cards | soft cards + media thumb + CTA | mood media plane (wash/initials + `image_url` when present) + soft-card rhythm + CTA; без full photo-hero grid |
|
||||||
| CONTROL booking §E | отдельные mock-карточки «слот/специалист» | `EventActionCard` / specialists / bookings: steel rail (усилен), avatar, available label, Confirm/Decline; не pixel-perfect board mocks |
|
| CONTROL booking §E | отдельные mock-карточки «слот/специалист» | `EventActionCard` / specialists / bookings: steel rail (усилен), avatar, available label, Confirm/Decline; не pixel-perfect board mocks |
|
||||||
| Bookings list §D | список заявок с Confirm/Decline на `/bookings` | `/bookings` = заявки **участника** (Отменить); owner Confirm/Decline — в карточке события (`EventActionCard` / Заявки) |
|
| Bookings list §D | список заявок с Confirm/Decline на `/bookings` | `/bookings` = **grouped inbox**: (A) К подтверждению — pending owner/specialist + Confirm/Decline; (B) Мои записи — participant upcoming/past + Cancel; empty groups hidden. Event card Confirm/Decline **остаётся** обязательным |
|
||||||
| Login §D phone chrome | три phone frames + (на борде) Google CTA | brand-first hero + mood `--auth-*`; email/password only; mood switcher на login (иконки); taglines mood cards — на `/more`; **без** Google OAuth |
|
| Login §D phone chrome | три phone frames + (на борде) Google CTA | brand-first hero + mood `--auth-*`; email/password only; mood switcher на login (иконки); taglines mood cards — на `/more`; **без** Google OAuth |
|
||||||
| Favicon set | 3 отдельных favicon файла на борде | mood appicon через `applyMood` |
|
| Favicon set | 3 отдельных favicon файла на борде | mood appicon через `applyMood` |
|
||||||
| Desktop nav | phone bottom tabs на борде | desktop: top tabs (Календарь / Найти / Записи / Ещё); bottom nav — mobile |
|
| Desktop nav | phone bottom tabs на борде | desktop: top tabs (Календарь / Найти / Записи / Ещё); bottom nav — mobile |
|
||||||
@@ -32,7 +32,30 @@ IA без sidebar / без Creator mood — совпадает с non-goals (п
|
|||||||
|
|
||||||
**Polish in this pass:** agenda copy/casing/counts + time-first rows; CONTROL steel rail emphasis; neutral Discover cover in mock (не flow-appicon во всех moods).
|
**Polish in this pass:** agenda copy/casing/counts + time-first rows; CONTROL steel rail emphasis; neutral Discover cover in mock (не flow-appicon во всех moods).
|
||||||
|
|
||||||
**Remaining intentional:** no pixel-perfect phone chrome; Discover без photo-hero grid; owner Confirm/Decline не на `/bookings` list.
|
**Remaining intentional:** no pixel-perfect phone chrome; Discover без photo-hero grid (cover via `image_url` when API returns it); §E specialist schedule card vs panel — не pixel-perfect board mocks (follow-up).
|
||||||
|
|
||||||
|
### Bookings inbox + More invites (locked 2026-07-27)
|
||||||
|
|
||||||
|
Продуктовые решения (не deviation — канон):
|
||||||
|
|
||||||
|
1. **Event card Confirm/Decline** остаётся обязательным (quick approve на слоте).
|
||||||
|
2. **`/bookings`** — grouped inbox, не только participant:
|
||||||
|
- **Группа A — К подтверждению:** pending bookings, где пользователь calendar **owner** или **assigned specialist** (`event.specialist_id` = user). Confirm/Decline те же, что на `EventActionCard`.
|
||||||
|
- **Группа B — Мои записи:** participant bookings (upcoming/past + Cancel) как раньше.
|
||||||
|
- Пустые группы скрывать (`count=0`).
|
||||||
|
- Опционально подпись owner vs specialist внутри A; иначе одна секция «К подтверждению».
|
||||||
|
3. **`specialist_invite` в More:** скрывать пункт меню, если **0 pending** входящих. Deep-link `/invites?token=` работает. Исходящие invite остаются в `SpecialistsPanel`.
|
||||||
|
4. **Не** класть строки `specialist_invite` в `/bookings`.
|
||||||
|
|
||||||
|
API: `GET /v1/user/booking-requests` (Back) + существующий `PUT /v1/bookings/:id`.
|
||||||
|
|
||||||
|
### Follow-ups (вне этого fix-pass или частично)
|
||||||
|
|
||||||
|
| Тема | Статус |
|
||||||
|
|------|--------|
|
||||||
|
| Discover `image_url` в search serialization | Back отдаёт поле; upload API **нет** — только URL field / seed |
|
||||||
|
| Stage Popular clutter (e2e calendars) | filter notes: см. `EventHubSpec/STAGE-POPULAR-CLEANUP.md`; не трогать реальные smoke данные без фильтра по e2e-паттернам |
|
||||||
|
| §E specialist schedule card vs panel | deviation: EventActionCard + SpecialistsPanel; отдельный pixel mock — Future |
|
||||||
|
|
||||||
## Mood concept = product surface
|
## Mood concept = product surface
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user