Архитектура Экосистемы BPDS: Топология Шины Данных
Спецификация топиков Apache Kafka (KRaft)
Событийно-Ориентированная Топология Broker Kafka
Взаимодействие между доменами системы BPDS реализовано на базе распределенной шины данных Apache Kafka (11 топиков, архитектура KRaft). Для маршрутизации пакетов и обеспечения безопасности на уровне ACL применяется строго типизированный паттерн разделения топиков через точку, поддерживающий концепцию CQRS (разделение команд и событий):
\[\text{Паттерн: } \text{bpds}.\langle\text{домен}\rangle.\langle\text{направление}\rangle.\langle\text{ресурс}\rangle.\langle\text{действие}\rangle\]
Где: * bpds — неизменный префикс проекта. * направление — принимает значение in (Входящая команда/тяжелый стрим) или out (Исходящий подтвержденный факт/событие).
Маппинг и Спецификация Топиков (11 Production Topics)
| № | Название топика Kafka | Направление потока данных | Продюсер (Producer) | Потребитель (Consumer) |
|---|---|---|---|---|
| 1 | bpds.inventory.in.receipt.upload |
IN (Команда на разбор чека) | shop-engine (1. Shop) |
ai-vision-worker (EasyOCR) |
| 2 | bpds.inventory.out.receipt.parsed |
OUT (Факт: чек успешно разобран) | ai-vision-worker (EasyOCR) |
shop-engine \(\rightarrow\) fridge-ops |
| 3 | bpds.inventory.in.voice.stream |
IN (Потоковое аудио голоса) | shop-engine / 3. Cook |
ai-speech-worker (Whisper) |
| 4 | bpds.inventory.out.voice.transcribed |
OUT (Факт: голос переведен в текст) | ai-speech-worker (Whisper) |
shop-engine / cookbook |
| 5 | bpds.mdm.in.product.process |
IN (Запрос на карточку продукта) | API Gateway (при Cache miss) | ollama-llm-proxy (Structured) |
| 6 | bpds.mdm.out.product.templated |
OUT (Факт: сгенерирован шаблон) | ollama-llm-proxy |
product-registry-service |
| 7 | bpds.mdm.in.recipe.synthesize |
IN (Команда на парсинг текста) | Веб-парсер / Админка | ollama-llm-proxy |
| 8 | bpds.inventory.in.fridge_item.deduct |
IN (Команда на FIFO списание) | recipe-cookbook (3. Cook) |
warehouse-fridge-ops (Склад) |
| 9 | bpds.inventory.out.meal_item.create |
OUT (Факт: готовое блюдо создано) | warehouse-fridge-ops (Склад) |
bupar-audit / affinity-core |
| 10 | bpds.inventory.out.fridge_item.consume |
OUT (Факт: продукт утилизирован/съеден) | warehouse-fridge-ops (4. Cons) |
affinity-prediction-core (+) |
| 11 | bpds.inventory.out.fridge_item.waste |
OUT (Факт: продукт выброшен в мусор) | warehouse-fridge-ops (5. Waste) |
affinity-prediction-core (-) |
| 12 | bpds.iad.out.group.change |
OUT (Факт: изменение прав группы) | auth-identity-service |
Все базы (Сброс кэша прав) |
| 13 | bpds.aid.out.profanity.violate |
OUT (Факт: лимит мата исчерпан) | redis-profanity-censor |
auth-identity-service (Бан) |
| 14 | bpds.pma.out.process.event |
OUT (Сквозной бизнес-лог шага) | Все микросервисы экосистемы | bupar-audit-service \(\rightarrow\) UI |
Маппинг и Спецификация Топиков (14 Production Topics)
| № | Название топика Kafka | Направление потока данных | Продюсер (Producer) | Потребитель (Consumer) |
|---|---|---|---|---|
| 1 | bpds.inventory.in.receipt.upload |
IN (Команда на разбор чека) | shop-engine (1. Shop) | ai-vision-worker (EasyOCR) |
| 2 | bpds.inventory.out.receipt.parsed |
OUT (Факт: чек успешно разобран) | ai-vision-worker (EasyOCR) | shop-engine \(\rightarrow\) fridge-ops |
| 3 | bpds.inventory.in.voice.stream |
IN (Потоковое аудио голоса) | shop-engine / 3. Cook | ai-speech-worker (Whisper) |
| 4 | bpds.inventory.out.voice.transcribed |
OUT (Факт: голос переведен в текст) | ai-speech-worker (Whisper) | shop-engine / cookbook |
| 5 | bpds.mdm.in.product.process |
IN (Запрос на карточку продукта) | API Gateway (при Cache miss) | ollama-llm-proxy (Structured) |
| 6 | bpds.mdm.out.product.templated |
OUT (Факт: сгенерирован шаблон) | ollama-llm-proxy | product-registry-service |
| 7 | bpds.mdm.in.recipe.synthesize |
IN (Команда на парсинг текста рецепта) | Веб-парсер / Админка | ollama-llm-proxy |
| 8 | bpds.inventory.in.fridge_item.deduct |
IN (Команда на каскадное FIFO списание весов) | fridge-service (3. Cook) | fridge-service (FIFO-движок) |
| 9 | bpds.inventory.out.meal_item.create |
OUT (Факт: готовое составное блюдо создано) | fridge-service | bupar-audit-service / affinity-prediction-core |
| 10 | bpds.inventory.out.fridge_item.consume |
OUT (Факт: продукт съеден) | fridge-service (4. Consume) | affinity-prediction-core |
| 11 | bpds.inventory.out.fridge_item.waste |
OUT (Факт: продукт выброшен в мусор) | fridge-service (5. Waste) | affinity-prediction-core |
| 12 | bpds.iad.out.group.change |
OUT (Факт: изменение состава группы / тарифа) | auth-identity-service | billing-service / fridge-service / affinity-prediction-core |
| 13 | bpds.aid.out.profanity.violate |
OUT (Факт: превышен лимит мата, бан сессии) | censorship-control-worker | auth-identity-service |
| 14 | bpds.pma.out.process.event |
OUT (Сквозной технический маркер шага процесса) | Все микросервисы экосистемы | bupar-audit-service |
Мультитентовое Разделение Данных (Multi-Tenancy)
Разделение арендаторов (HOME / OFFICE) инкапсулировано внутри мета-заголовков каждого сообщения и поддерживается стратегией секционирования брокера. Partition Key строго равен meta.tenant.home_group_id. Это гарантирует, что все события по одной семье или офису попадают в одну и ту же партицию Kafka, обеспечивая строгую последовательность FIFO.
Архитектура Сообщения (Payload Blueprint)
Ниже представлен эталонный контракт сообщения для топика команды на списание bpds.inventory.in.fridge_item.deduct (Генерируется во Flutter при клике на кнопку 3. Cook):
{
"meta": {
"event_id": "evt-8830-bf-2026",
"timestamp": "2026-07-13T06:05:00Z",
"trace_id": "X-Request-ID-Dio-Client-77755",
"direction": "IN",
"tenant": {
"home_group_id": "group-office-corporate-4",
"account_type": "OFFICE",
"user_id": "usr-991"
}
},
"payload": {
"command": "EXECUTE_FIFO_DEDUCTION",
"context": {
"case_id": "case-food-lifecycle-loop-4412",
"recipe_id": 2085,
"target_meal_name": "Компот Ягодный"
},
"ingredients": [
{
"element_id": "mdm-prod-102",
"element_symbol": "St",
"requested_weight_g": 500.0000
},
{
"element_id": "mdm-prod-005",
"element_symbol": "Wt",
"requested_weight_g": 2500.0000
}
]
}
}Назначение ключевых полей структуры:
meta.trace_id: Сюда пробрасываетсяX-Request-IDот Flutter-клиента. Позволяет Promtail агрегировать логи обработки сообщения в Grafana Loki и отображать их наObservabilityScreen.meta.tenant.account_type: Контурный флаг (OFFICE). Сигнализирует сервисуwarehouse-fridge-ops: в случае нехватки остатков при каскадном FIFO-списании, транзакцию необходимо жестко заблокировать по gRPC с кодом ошибки 422.payload.context.case_id: Сквозной маркер цепочки процессов. Перехватываетсяbupar-audit-serviceдля отрисовки карт жизненного цикла продуктов (Process Mining).