sequenceDiagram
autonumber
actor Partner as REST-клиент Торговой Сети
participant Nginx as Nginx Proxy
participant GW as FastAPI Gateway (backend-api)
participant Store as store-service (INVENTORY)
participant Auth as auth-service (SECURITY/IAD)
participant K as Apache Kafka Cluster
participant Fridge as fridge-service (INVENTORY)
Partner->>Nginx: Шаг 1: POST /api/v1/webhooks/stores/receipt (Headers: X-Shop-Token)
activate Nginx
Nginx->>GW: Шаг 2: Внутренний прокси сырого JSON вебхука
activate GW
GW->>Store: Шаг 3: gRPC: ProcessB2BReceipt(ReceiptRequest)
activate Store
Store->>Auth: Шаг 4: gRPC: ResolveLoyaltyCard(CardRequest)
activate Auth
Auth-->>Store: Возврат user_id, home_group_id и статуса X-Shop-Token
deactivate Auth
alt Сценарий А: Токен НЕ валиден / Карта лояльности не найдена
Store-->>GW: gRPC Error: UNAUTHENTICATED / NOT_FOUND
GW-->>Partner: HTTP 401 Unauthorized / 404 Not Found
else Сценарий Б: Успешная валидация и маппинг
Store-->>GW: gRPC Response: ACCEPTED (OK)
deactivate Store
GW-->>Partner: Шаг 5: HTTP 200 OK (Контракт исполнен, Fire-and-Forget)
deactivate GW
deactivate Nginx
%% АСИНХРОННЫЙ ХВОСТ ПРЯМОГО ЗАЧИСЛЕНИЯ
Store->>K: Шаг 6: Пуш события в топик: store.inventory.in.receipt.imported
activate K
K->>Fridge: Шаг 7: Handler: ProcessTrustedB2BReceipt()
deactivate K
activate Fridge
Note over Fridge: Шаг 8: Прямой транзакционный INSERT<br/>в PostgreSQL Fridge DB на баланс home_group_id
deactivate Fridge
end
[DRAFT] Метод POST /api/v1/webhooks/stores/receipt
Документация B2B API: Автоматическое добавление продуктов через вебхук для торговой сети Магазин
- INV-BACKEND-024 Backlog — Реализация обработчика ReceivePartnerReceipt для добавления продуктов по внешнему методу.
В открытом доступе представлена демонстрационная версия метода. В настоящей публичной документации отображены не все шаги, технические сценарии и приватные эндпоинты для системы цифровых симуляторов бизнес-процессов.
- Полная спецификация метода: Будет доступна только во внутреннем контуре разработки (Confluence / Swagger Enterprise).
Functional Purpose / Функциональное назначение
This documentation section is currently under development and may contain incomplete data. Some technical descriptions, parameters, and system operation scenarios for the digital business process simulator are subject to change.
- Stable documentation version: Will be published upon final completion and validation of the method code.
Метод представляет собой открытый B2B-эндпоинт (вебхук), предназначенный для автоматического пополнения холодильника пользователя товарами, приобретенными в розничной сети или магазине или у продавца с настроенной интеграцией.
Метод решает следующие задачи:
- Синхронный Direct-Inflow (Прямой импорт): В отличие от пользовательского контура (метод/ы распознавания OCR из мобильного приложения), “Вендор” передает серверу строго типизированный, подготовленный JSON-датасет. Это позволяет системе добавлять продукты в цифровой холодильник не используя промежуточные таблицы например:
pending_receipts. - Сквозная B2B-авторизация: Метод защищен протоколом
OAuth2 Client Credentialsлибо выделенным статическим API-ключом, так как запрос инициируется сервером торговой сети, а не мобильным приложением. - Связывание аккаунтов (User Mapping): Идентификация целевого холодильника (
home_group_id) происходит по переданному в теле запросаloyalty_card_token(токен карты лояльности сетиМагазин, которую пользователь привязал в своем профиле в приложении FoodLifeCycleApp).
Протокол взаимодействия (HTTP Контракт)
- Метод:
POST - Маршрут:
/api/v1/webhooks/stores/receipt - Формат данных:
application/json
Спецификация заголовков (HTTP Headers)
| Заголовок | Обязательный | Описание | Пример значения |
|---|---|---|---|
Content-Type |
Да | Указывает на передачу строго типизированного JSON-пакета | application/json |
X-Shop-Token |
Да | Секретный статический ключ авторизации партнера (B2B API Key) | shop_live_secret_abc123... |
X-Request-ID |
Да | Сквозной ID запроса, генерируемый шиной Магазина для трассировки |
shop-tr-44bb-99ff |
Спецификация тела запроса (Request Body)
Структура данных повторяет фискальный срез чека Магазин. Поля количества товара (quantity) поддерживают тип float/double для корректного зачисления весовых позиций (например, бананов весом 1.695 кг).
| Поле | Тип | Обязательный | Описание | Пример значения |
|---|---|---|---|---|
loyalty_card_token |
String | Да | Уникальный токен карты, по которому бэкенд находит user_id и home_group_id |
shop-card-8822-fa |
receipt_number |
String | Да | Фискальный номер чека для предотвращения дублирования | CH-20260701-09 |
items |
Array | Да | Список приобретенных товарных позиций | [..._name: "БАНАН", qty: 1.695] |
Пример JSON-запроса (Payload):
{
"loyalty_card_token": "shop-card-8822-fa",
"receipt_number": "CH-20260701-09",
"purchase_timestamp": "2026-07-01T23:10:00Z",
"store_id": "shop-almaty-05",
"items": [
{
"product_id": "2110310",
"product_name": "БАНАН ЭКВАДОР КГ",
"quantity": 1.6950,
"price": 595.00,
"unit": "кг"
},
{
"product_id": "4001020",
"product_name": "ХЛЕБ АКСАЙ БОРОДИНСКИЙ",
"quantity": 1.0000,
"price": 180.00,
"unit": "шт"
}
]
}Диаграмма последовательности (Mermaid)
This documentation section is currently under development and may contain incomplete data. Some technical descriptions, parameters, and system operation scenarios for the digital business process simulator are subject to change.
- Stable documentation version: Will be published upon final completion and validation of the method code.
На диаграмме представлена логика сквозной интеграции через B2B-вебхук: бэкенд идентифицирует пользователя по карте лояльности, проверяет чек на дубликаты и добавляет продукты напрямую в цифровой холодильник автоматически.
Расшифровка шагов
This documentation section is currently under development and may contain incomplete data. Some technical descriptions, parameters, and system operation scenarios for the digital business process simulator are subject to change.
- Stable documentation version: Will be published upon final completion and validation of the method code.
| Шаг | Действие | Параметры / Запросы | Ошибки (Исключения / Статусы) и JSON Ответы |
|---|---|---|---|
1 (Partner -> Nginx) |
Внешний сервер торговой сети отправляет JSON-датасет фискального чека на B2B-эндпоинт интеграции. | HTTP POST /api/v1/webhooks/stores/receipt Headers: X-Shop-Token |
Входная точка запроса партнера. Транспортный уровень. |
2 (Nginx -> GW) |
Прокси-сервер осуществляет добавление X-Request-ID и перенаправляет запрос вебхука на API-шлюз. |
HTTP POST /backend-api/... Headers: X-Request-ID |
Внутренняя маршрутизация шлюза. |
3 (GW -> Store) |
Шлюз валидирует структуру чека и транслирует запрос в микросервис. | Протокол: gRPC Метод: ProcessB2BReceipt |
Проверка синтаксиса контракта JSON шлюзом. |
4 (Store -> Auth) |
Метод сервиса запрашивает у компонента безопасности проверку B2B-токена и конвертацию карты лояльности в ID пространства. | Протокол: gRPC Метод: ResolveLoyaltyCard |
Сквозная B2B авторизация. |
5.1 (Сценарий А) (Store -> Partner) |
Компонент безопасности отклоняет запрос. Сервис возвращает партнеру финальный статус отказа из-за сработавшей идемпотентности. | Ответ по цепочке через GW и Nginx: HTTP 409 Conflict |
Бизнес-ошибка метода (Idempotency Trigger): json\n{\n "error_code": "ERR-RECEIPT-DUPLICATE",\n "message": "Данный фискальный документ уже был успешно обработан и зачислен ранее.",\n "details": {\n "rejected_receipt_number": "CH-20260701-09",\n "partner_code": "MAGNUM",\n "action": "Idempotency trigger activated. No duplicate database writes executed."\n }\n}\n |
5.1 (Сценарий Б) (Store -> Partner) |
Сервис фиксирует успешное прохождение проверок, закрывает транзакцию СУБД и возвращает успешный статус. | Ответ по цепочке через GW и Nginx: HTTP 200 OK |
Успешный ответ (Success Response): json\n{\n "status": "PROCESSED",\n "receipt_number": "CH-20260701-09",\n "loyalty_card_token": "shop-card-8822-fa",\n "metrics": {\n "items_processed_count": 2,\n "db_transaction_status": "COMMITTED"\n },\n "timestamp": "2026-07-01T23:10:02Z"\n}\n |
6 (Store -> KAFKA) |
Инвентарный сервис асинхронно публикует событие успешного импорта B2B-чека в брокер сообщений для изоляции транзакционной нагрузки. | Топик: store.inventory.in.receipt.imported |
Асинхронная публикация события в шину. |
7 (KAFKA -> Fridge) |
Фоновый воркер сервиса холодильника вычитывает доверенное B2B-сообщение из топика и запускает процедуру зачисления позиций. | Handler: ProcessTrustedB2BReceipt() |
Асинхронное чтение события воркером. |
8 (Fridge -> DB_Fridge) |
Сервис проверяет фискальный номер чека в реестре обработанных документов для соблюдения идемпотентности на уровне БД. | SQL: SELECT 1 FROM processed_b2b_receipts... |
Проверка дубликатов на уровне СУБД. |
8.1 (Fridge -> DB_Fridge) |
В рамках единой транзакции воркер регистрирует факт обработки чека и выполняет bulk-insert весовой матрицы товаров на баланс группы. | SQL: INSERT INTO processed_b2b_receipts... INSERT INTO fridge_inventory... |
Атомарная фиксация остатков. |
8.2 (DB_Fridge -> Fridge) |
СУБД фиксирует транзакцию, обновляет складские остатки Multi-Tenancy контура и возвращает статус успешной записи. | Статус: COMMIT |
Успешное завершение транзакции БД. |
8.3 (Fridge -> KAFKA) |
Сервис отправляет системное бизнес-событие в шину данных для уведомления зависимых доменов бэкенда (аналитика, умные рецепты). | Топик: fridge.inventory.events.stock_replenished |
Обогащение бизнес-событиями. |
9 (Fridge -> App) |
Шлюз по сигналу воркера находит активный WebSocket-стрим семьи по home_group_id и отправляет пуш-ивент для реалтайм обновления UI. |
Эндпоинт: /ws/push-stream/{id} |
Смена стейта UI на клиенте. |
Спецификация ответов (Response Body)
This documentation section is currently under development and may contain incomplete data. Some technical descriptions, parameters, and system operation scenarios for the digital business process simulator are subject to change.
- Stable documentation version: Will be published upon final completion and validation of the method code.
Успешный ответ (Success Response)
HTTP 200 OK
Возвращается шине данных партнерской торговой сети Магазин в качестве успешного подтверждения запроса приема, и авторизации.
- Заголовки ответа (Response Headers):
Content-Type: application/json
- Тело ответа (Response Body):
{
"status": "PROCESSED",
"receipt_number": "CH-20260701-09",
"loyalty_card_token": "shop-card-8822-fa",
"metrics": {
"items_processed_count": 2,
"db_transaction_status": "COMMITTED"
},
"timestamp": "2026-07-01T23:10:02Z"
}Спецификация ошибок (Error Responses)
Ошибка дублирования чека (HTTP 409 Conflict)
Вызывается, если переданный receipt_number уже присутствует в таблице. Это предотвращает повторное начисление веса продуктов при сбоях и ретраях на стороне Магазина.
{
"error_code": "ERR-RECEIPT-DUPLICATE",
"message": "Данный фискальный документ уже был успешно обработан и зачислен ранее.",
"details": {
"rejected_receipt_number": "CH-20260701-09",
"partner_code": "MAGNUM",
"action": "Idempotency trigger activated. No duplicate database writes executed."
}
}Ошибка: Карта лояльности не привязана к профилю (HTTP 422 Unprocessable Entity)
Вызывается, если loyalty_card_token верный по структуре, но отсутствует в таблице маппинга user_loyalty_cards. Система не может определить, в чей именно цифровой холодильник нужно положить продукты.
{
"error_code": "ERR-LOYALTY-CARD-NOT-MAPPED",
"message": "Карта лояльности партнера не связана ни с одним активным аккаунтом в экосистеме .",
"details": {
"unmapped_token": "mag-card-8822-fa",
"action": "The user must physically link their Magnum card inside the Flutter mobile app profile."
}
}