Store Service — Events

Публикует

store.table.upserted

Публикуется при любом изменении состояния стола: create / update / soft-delete / occupy / release / reserve / cancel-reservation / waiter assignment. Используется pos-bff для realtime-инвалидации плана зала на POS-терминалах (Kafka → SSE → EventSource в pos-desktop).

Topic: store.table.upserted

Ключ Kafka: store_id

Доставка: fire-and-forget без outbox. Для UI-инвалидации потеря единичного события приемлема — на POS есть 10с polling fallback. При недоступности Kafka в момент изменения транзакция всё равно коммитится (KafkaTemplate возвращает CompletableFuture, exception логируется но не пробрасывается).

{
  "event_id": "uuid",
  "timestamp": "datetime",
  "version": 1,
  "payload": {
    "franchise_id": "uuid",
    "store_id": "uuid",
    "table_id": "uuid",
    "number": "integer",
    "status": "free | occupied | reserved",
    "current_order_id": "uuid | null",
    "current_waiter_id": "uuid | null",
    "change_type": "created | updated | deleted | occupied | released | reserved | waiter_assigned",
    "deleted_at": "datetime | null"
  }
}

Консьюмеры:

  • pos-bff (group pos-bff-sse-${HOSTNAME}) — broadcastToStore(store_id, table.invalidate) → POS Desktop вызывает tablesStore.reload()

marketing.slide.changed

(BR 6.1)

Публикуется при любом CRUD-изменении маркетинговых слайдов: create / update / soft-delete / reorder / активация-деактивация. Используется pos-bff для realtime-обновления standby-карусели на POS Desktop (Kafka → SSE → EventSource в pos-desktop).

Topic: marketing.slide.changed

Ключ Kafka: store_id (партиционирование по ТТ — все события одной ТТ идут в одну партицию, упорядоченно)

Доставка: через outbox (как store.table.upserted? — нет, table — fire-and-forget; здесь — outbox для гарантии at-least-once, потому что reorder влияет на порядок отображения; потеря единичного события создаст рассинхрон между админкой и кассой). Запись в outbox-таблицу в той же транзакции что и marketing_slides, отдельный publisher-poller вычитывает и публикует, по успешной публикации помечает processed_at.

{
  "event_id": "uuid",
  "timestamp": "datetime",
  "version": 1,
  "payload": {
    "franchise_id": "uuid",
    "store_id": "uuid",
    "slide_id": "uuid | null — null для action=reordered (затронуты все слайды ТТ)",
    "action": "created | updated | deleted | reordered | activated | deactivated"
  }
}

Минимальный payload

Не кладём image_url, title, order — потребитель (pos-bff) использует событие только как trigger для broadcast. POS Desktop по SSE event дёргает GET /pos/api/v1/marketing/active и забирает свежий список.

Консьюмеры:

  • pos-bff (group pos-bff-sse-${HOSTNAME}) — broadcastToStore(store_id, marketing.invalidate) → POS Desktop в standby-режиме перезагружает активные слайды

Потребляет

EventTopicConsumer groupЗачем
order.status.changedorder.status.changedstore-service-tablesOrderStatusConsumer синхронизирует статус столов zal_tables с жизненным циклом заказа (освобождение стола при закрытии/отмене)

Side-эффекты приостановки ЮЛ — синхронно

Приостановка ЮЛ → снятие ТТ с публикации реализована через синхронный вызов User Service → Store Service POST /internal/stores/unpublish-by-legal-entity. Kafka не используется.

Будущие события (Phase 2)

EventОписаниеКогда понадобится
store.createdТТ созданаCustomer BFF (обновление каталога)
store.publishedТТ опубликованаCustomer BFF, Order Service
store.unpublishedТТ снята с публикацииCustomer BFF, Order Service
store.updatedТТ обновлена (адрес, график)Customer BFF
store.deletedТТ удаленаCustomer BFF, Order Service

Ссылки

  • Event Bus — общая шина и SSE-мост admin → POS

Переход на Kafka

При появлении нескольких консьюмеров (Customer BFF, Order Service) — переводим side-эффекты на Kafka, убираем синхронные вызовы.