P1: Истечение past-pending bookings #60

Closed
opened 2026-07-27 16:39:55 +03:00 by cursor-ai · 2 comments
Owner

Проблема

Pending-бронирования с уже прошедшим event.start_time остаются pending: занимают слот capacity, попадают в inbox booking-requests, Confirm/Decline формально возможны после старта события.

Влияние

Путаница у владельца/специалиста и участника; past-pending удерживает capacity.

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

Option B: при event.start_time < now статус pendingexpired (воркер + on-read в list/get/confirm). Confirm/Decline для ещё будущих pending не ломаются.

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

  • Past-pending переходит в expired (background и при чтении списков)
  • Past-pending не попадает в booking-requests
  • Confirm/Decline будущего pending работает как раньше
  • Confirm/Decline past-pending отклоняется после expire
  • eunit зелёный

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

  • src/logic/logic_booking.erl
  • include/records.hrl
  • handlers booking schemas

Приоритет

P1

## Проблема Pending-бронирования с уже прошедшим `event.start_time` остаются `pending`: занимают слот capacity, попадают в inbox `booking-requests`, Confirm/Decline формально возможны после старта события. ## Влияние Путаница у владельца/специалиста и участника; past-pending удерживает capacity. ## Ожидаемый результат Option B: при `event.start_time < now` статус `pending` → `expired` (воркер + on-read в list/get/confirm). Confirm/Decline для ещё будущих pending не ломаются. ## Критерии приёмки - [ ] Past-pending переходит в `expired` (background и при чтении списков) - [ ] Past-pending не попадает в `booking-requests` - [ ] Confirm/Decline будущего pending работает как раньше - [ ] Confirm/Decline past-pending отклоняется после expire - [ ] eunit зелёный ## Файлы (подсказка) - `src/logic/logic_booking.erl` - `include/records.hrl` - handlers booking schemas ## Приоритет P1
cursor-ai added the Task label 2026-07-27 16:39:55 +03:00
cursor-ai self-assigned this 2026-07-27 16:39:55 +03:00
Author
Owner

Беру в работу.

Вариант: Option B — переход pendingexpired, если event.start_time < now (воркер process_timeout_bookings + on-read в list/get/confirm). Confirm/Decline будущих pending без изменений.

Беру в работу. **Вариант:** Option B — переход `pending` → `expired`, если `event.start_time < now` (воркер `process_timeout_bookings` + on-read в list/get/confirm). Confirm/Decline будущих pending без изменений.
Author
Owner

Готово

SHA: edb7c20f701bd8b54186fdea06f16914e258389a

Подход (Option B)

При event.start_time <= now статус pendingexpired:

  1. Воркер subscription_workerprocess_timeout_bookings/0 (каждые 15с)
  2. On-read: list_user_bookings, list_event_bookings, list_bookings, get_booking, admin list
  3. booking-requests — past-pending expires и не попадает в inbox
  4. Confirm/Decline past-pending → {error, expired} → HTTP 409 Booking expired
  5. Confirm/Decline будущего pending — без изменений

API для Front

  • Новый статус в JSON: "expired" (рядом с pending / confirmed / cancelled)
  • Эндпоинты: GET /v1/user/bookings, GET /v1/events/:id/bookings, GET /v1/bookings/:id, admin lists
  • GET /v1/user/booking-requests — только ещё актуальные pending
  • PUT /v1/bookings/:id confirm/decline на истёкшем → 409
  • expired не занимает capacity и не блокирует повторную бронь (active_booking считает только pending|confirmed)

Тесты

rebar3 eunit --module=logic_booking_tests29 tests, 0 failures
(в т.ч. expire on list / exclude from requests / confirm denied / future still confirmable / worker)

Спека

Контракт статуса изменился — обновить EventHubBackSpec.md агентом Spec отдельно.

## Готово **SHA:** `edb7c20f701bd8b54186fdea06f16914e258389a` ### Подход (Option B) При `event.start_time <= now` статус `pending` → **`expired`**: 1. Воркер `subscription_worker` → `process_timeout_bookings/0` (каждые 15с) 2. On-read: `list_user_bookings`, `list_event_bookings`, `list_bookings`, `get_booking`, admin list 3. `booking-requests` — past-pending expires и **не попадает** в inbox 4. Confirm/Decline past-pending → `{error, expired}` → HTTP **409** `Booking expired` 5. Confirm/Decline будущего pending — без изменений ### API для Front - Новый статус в JSON: `"expired"` (рядом с `pending` / `confirmed` / `cancelled`) - Эндпоинты: `GET /v1/user/bookings`, `GET /v1/events/:id/bookings`, `GET /v1/bookings/:id`, admin lists - `GET /v1/user/booking-requests` — только ещё актуальные pending - `PUT /v1/bookings/:id` confirm/decline на истёкшем → **409** - `expired` не занимает capacity и не блокирует повторную бронь (`active_booking` считает только pending|confirmed) ### Тесты `rebar3 eunit --module=logic_booking_tests` — **29 tests, 0 failures** (в т.ч. expire on list / exclude from requests / confirm denied / future still confirmable / worker) ### Спека Контракт статуса изменился — обновить `EventHubBackSpec.md` агентом Spec отдельно.
Sign in to join this conversation.