Event Bus (Apache Kafka)
Событийная модель пока пуста
Topics и события будут добавляться по мере реализации сервисов. Текущий скоуп (TASK-001: авторизация) не требует Kafka.
Конвенции
- Topic naming:
{service_domain}.{entity}.{action}(e.g.catalog.stoplist.updated) - Consumer group:
{consumer_service}-group(e.g.warehouse-group) - Формат: JSON, обязательные поля:
event_id,timestamp,version,payload - Идемпотентность: консьюмеры должны обрабатывать дубли (по
event_id) - Partitioning: по
entity_idдля гарантии порядка в рамках одной сущности
SSE-мост admin → POS
Kafka — серверная инфра, до Tauri-приложения POS Desktop её не дотащить. Решение — мост через pos-bff: Fastify держит Server-Sent Events канал на каждый POS-терминал, Kafka consumer получает события каталога/стора/агрегатора и пушит их подключённым клиентам.
admin (PATCH price/stoplist/table)
│
▼
catalog/store/aggregator-service ──outbox──► Kafka topics
│
consume│ group: pos-bff-sse-${HOSTNAME}
▼
pos-bff (kafkajs)
│ filter by franchise_id/store_id
│ debounce 300ms на batch-update
▼
SSE-hub → POS Desktop (EventSource)
│
▼
menuStore.checkForUpdates / tablesStore.reload / aggregatorStore.reload
Топики на SSE: catalog.product.{upserted,deleted}, catalog.category.{upserted,deleted}, catalog.modifier_group.{upserted,deleted}, catalog.stoplist.updated, store.table.upserted, aggregator.order.received.
SSE-events для клиента: menu.invalidate, table.invalidate, aggregator.invalidate. POS на каждое событие дёргает соответствующий store, дальше сравнение snapshot решает показывать ли «обновите меню».
Per-pod Kafka group. Каждый инстанс pos-bff — отдельная consumer group (с HOSTNAME-суффиксом), чтобы все pod’ы получали все события — иначе SSE-клиенты на pod B не увидели бы события, обработанные pod A.
Auth для EventSource. EventSource в браузере не поддерживает Authorization header — JWT передаём через ?token=. Nginx с access_log off для /pos/api/v1/pos/notifications/stream чтобы токен не оседал в логах.
Nginx настройки. proxy_buffering off (иначе chunked не доезжает до клиента), proxy_read_timeout 3600s (default 30с обрывает idle-канал), Connection "" (keep-alive вместо close). Heartbeat : ping\n\n каждые 30с от pos-bff страхует от idle-kill промежуточных прокси.
Fallback на polling. Polling в POS Desktop (60с/10с/15с) НЕ удалён — работает как страховка при разрыве SSE. EventSource auto-reconnect ≈3с, при работающем SSE snapshot всегда совпадёт и доп. нагрузка минимальна.