POS BFF — API Contract

POS BFF — это BFF (Backend-for-Frontend) для POS Desktop

Большая часть эндпоинтов — прокси к микросервисам. Здесь описываются собственные агрегирующие эндпоинты и контракты SSE-канала. Полные контракты лежащих за прокси сервисов — в соответствующих документах (Order, Catalog, Store и др.).

Содержание

REST (Bearer JWT кассира)

  • GET /marketing/active (BR 6.1 — собственный агрегирующий)
  • (proxy) Authentication, Cashier roster, Shift, Order, Catalog, Tables, Aggregator, PayKeeper — см. соответствующие сервисы

SSE


GET /marketing/active

(BR 6.1)

Активные маркетинговые слайды текущей ТТ кассира + конфиг standby-режима. Используется POS Desktop при входе в /standby и при получении SSE marketing.invalidate.

ПараметрЗначение
AuthBearer JWT (любая роль с pos.access; store_id берётся из scope кассира — см. Ролевая модель)
Base path/pos/api/v1

Query Parameters

Нет. store_id определяется по JWT кассира — кассир видит только свою ТТ.

Response 200

{
  "data": {
    "slides": [
      {
        "id": "uuid",
        "image_url": "string — public URL картинки",
        "order": "integer"
      }
    ],
    "standby_idle_minutes": "integer — для idle-timer (default 5)",
    "standby_transition_seconds": "integer — для transition (default 9)"
  }
}

Слайды отсортированы по order ASC, фильтрация — только active = true AND deleted_at IS NULL.

Errors

CodeHTTPКогда
UNAUTHORIZED401Невалидный JWT
FORBIDDEN403Нет pos.access permission
NO_STORE_IN_SCOPE400У кассира пустой store-scope (логическая ошибка — кассир не привязан к ТТ)

Реализация в pos-bff

Прокси к Store Service: GET /internal/stores/{store_id}/marketing-slides/active (см. Store Service).

store_id берётся из req.user.scope.store_ids[0] (предполагается, что кассир имеет ровно одну ТТ; в противном случае — 400 MULTI_STORE_NOT_SUPPORTED).


GET /pos/notifications/stream

(BR SSE-3, расширено BR 6.1)

Server-Sent Events канал для realtime-обновлений POS Desktop. Один канал на терминал, удерживается долго (до 1 часа), Connection: keep-alive.

ПараметрЗначение
AuthJWT через ?token= query параметр (EventSource не поддерживает Authorization header)
Content-Typetext/event-stream
Nginxaccess_log off, proxy_buffering off, proxy_read_timeout 3600s

События

Каждое сообщение — стандартный SSE event: <name>\ndata: <json>\n\n.

EventPayloadИсточник Kafka
menu.invalidate{ "category": "product|category|modifier|stoplist" }catalog.* топики
table.invalidate{ "table_id": "uuid", "status": "..." }store.table.upserted
aggregator.invalidate{ "order_id": "uuid" }aggregator.order.received
marketing.invalidate{ "store_id": "uuid", "action": "..." } (BR 6.1)marketing.slide.changed
(heartbeat): ping каждые 30 сексинтетический

POS Desktop слушает события через useSSE hook и вызывает соответствующие store reloads.

Routing внутри pos-bff

При получении Kafka-сообщения с payload.store_id pos-bff делает broadcastToStore(store_id, eventName, data) — рассылает SSE-event всем подключённым клиентам этой ТТ. Клиенты других ТТ событие не получают.

Errors

CodeHTTPКогда
UNAUTHORIZED401Невалидный ?token=
NO_STORE_IN_SCOPE400JWT без store_ids

Общий формат ошибок

См. REST Conventions — единый формат { error: { code, message, details } }.