P0: specialist_id на create event + 402 gate на commercial create #61

Closed
opened 2026-07-27 21:15:47 +03:00 by cursor-ai · 3 comments
Owner

Проблема

P0 с stage UX-прогона (FULL-STAGE-UX-JOURNEY):

  1. POST /v1/calendars/:id/events игнорировал specialist_id — в ответе всегда ""; PUT сохранял. Ломало event-specialist-card и specialist Confirm (403).
  2. Создание commercial-календаря без активной подписки/trial возвращало 201 вместо 402: can_create_commercial_calendar/1 автозапускал trial, а handler создавал personal и ставил type через core_calendar:update в обход gate.

Ожидаемый результат

  • Create event персистит specialist_id так же, как update (валидация: active specialist на commercial-календаре).
  • Без active подписки/trial: create commercial → 402; personal проходит; trial — явно через POST /v1/subscription (start_trial).

Критерии приёмки

  • POST .../events с валидным specialist_id → 201 и поле в ответе
  • Невалидный specialist → 400; событие не остаётся «битым»
  • POST /v1/calendars type=commercial без sub → 402
  • Personal create без sub → 201
  • После start_trial commercial create → 201
  • eunit зелёный

Файлы (подсказка)

  • src/handlers/handler_events.erl
  • src/handlers/handler_calendars.erl
  • src/logic/logic_subscription.erl
  • src/logic/logic_calendar.erl

Приоритет

P0

## Проблема P0 с stage UX-прогона (FULL-STAGE-UX-JOURNEY): 1. `POST /v1/calendars/:id/events` игнорировал `specialist_id` — в ответе всегда `""`; `PUT` сохранял. Ломало `event-specialist-card` и specialist Confirm (403). 2. Создание commercial-календаря без активной подписки/trial возвращало **201** вместо **402**: `can_create_commercial_calendar/1` автозапускал trial, а handler создавал personal и ставил type через `core_calendar:update` в обход gate. ## Ожидаемый результат - Create event персистит `specialist_id` так же, как update (валидация: active specialist на commercial-календаре). - Без active подписки/trial: create commercial → **402**; personal проходит; trial — явно через `POST /v1/subscription` (`start_trial`). ## Критерии приёмки - [ ] `POST .../events` с валидным `specialist_id` → 201 и поле в ответе - [ ] Невалидный specialist → 400; событие не остаётся «битым» - [ ] `POST /v1/calendars` type=commercial без sub → 402 - [ ] Personal create без sub → 201 - [ ] После `start_trial` commercial create → 201 - [ ] eunit зелёный ## Файлы (подсказка) - `src/handlers/handler_events.erl` - `src/handlers/handler_calendars.erl` - `src/logic/logic_subscription.erl` - `src/logic/logic_calendar.erl` ## Приоритет P0
cursor-ai added the Bug label 2026-07-27 21:15:47 +03:00
cursor-ai self-assigned this 2026-07-27 21:15:47 +03:00
Author
Owner

Готово

SHA: 8172830 (master)

Что было сломано

  1. POST /v1/calendars/:id/events не прокидывал specialist_id в update_event_fields → в ответе всегда "".
  2. can_create_commercial_calendar/1 автоматически стартовал trial, поэтому free-пользователь получал 201 на commercial create; плюс handler создавал personal и ставил type через core_calendar:update в обход gate.

Как починили

  1. Create event: specialist_id в POST-схеме и в update_event_fields; при invalid_specialist — удаляем созданное событие и 400; PUT тоже отдаёт 400.
  2. Subscription gate: can_create только при уже active sub/trial (без auto-start); create идёт через logic_calendar:create_calendar/5 с Type; {error, subscription_required}402.

Тесты

  • rebar3 eunit --module=logic_subscription_tests,logic_calendar_tests,logic_event_tests — 32 tests, 0 failures
  • расширенный набор (booking/specialist/automod) — 93 tests, 0 failures

Проверить на stage после деплоя

  1. Новый user, status=free: POST /v1/calendars {type:commercial}402; personal → 201.
  2. POST /v1/subscription start_trial → commercial create → 201.
  3. Active specialist на commercial: POST .../events с specialist_id → 201 и поле в JSON; specialist Confirm без предварительного PUT.
## Готово **SHA:** `8172830` (master) ### Что было сломано 1. `POST /v1/calendars/:id/events` не прокидывал `specialist_id` в `update_event_fields` → в ответе всегда `""`. 2. `can_create_commercial_calendar/1` **автоматически стартовал trial**, поэтому free-пользователь получал 201 на commercial create; плюс handler создавал personal и ставил `type` через `core_calendar:update` в обход gate. ### Как починили 1. Create event: `specialist_id` в POST-схеме и в `update_event_fields`; при `invalid_specialist` — удаляем созданное событие и **400**; PUT тоже отдаёт 400. 2. Subscription gate: `can_create` только при **уже active** sub/trial (без auto-start); create идёт через `logic_calendar:create_calendar/5` с Type; `{error, subscription_required}` → **402**. ### Тесты - `rebar3 eunit --module=logic_subscription_tests,logic_calendar_tests,logic_event_tests` — 32 tests, 0 failures - расширенный набор (booking/specialist/automod) — 93 tests, 0 failures ### Проверить на stage после деплоя 1. Новый user, `status=free`: `POST /v1/calendars` `{type:commercial}` → **402**; personal → **201**. 2. `POST /v1/subscription` `start_trial` → commercial create → **201**. 3. Active specialist на commercial: `POST .../events` с `specialist_id` → 201 и поле в JSON; specialist Confirm без предварительного PUT.
Author
Owner

CI run 420 / job 885 упал на CT: admin_test_websocketPOST /v1/calendars commercial без trial → 402 после гейта из #61.

Фикс: admin_websocket_tests переведён на create_calendar/create_event (как user WS), SHA cd619db. Push в master — новый CI run.

CI run 420 / job 885 упал на CT: `admin_test_websocket` — `POST /v1/calendars` commercial без trial → **402** после гейта из #61. Фикс: `admin_websocket_tests` переведён на `create_calendar`/`create_event` (как user WS), SHA `cd619db`. Push в master — новый CI run.
Author
Owner

CI run 420 / job 885 упал на CT: admin_test_websocketPOST /v1/calendars commercial без trial → 402 после гейта из #61.

Фикс: admin_websocket_tests переведён на create_calendar/create_event (как user WS), SHA cd619db. Push в master — новый CI run.

CI run 420 / job 885 упал на CT: `admin_test_websocket` — `POST /v1/calendars` commercial без trial → **402** после гейта из #61. Фикс: `admin_websocket_tests` переведён на `create_calendar`/`create_event` (как user WS), SHA `cd619db`. Push в master — новый CI run.
Sign in to join this conversation.