Kiến trúc Sự kiện
Các service BANA được tách rời qua bốn seam. Redis không phải một trong số đó - nó chỉ là cache, fan-out WebSocket giữa các instance, và storage cho BullMQ.
| Seam | Mang gì | Nguồn-sự-thật |
|---|---|---|
Kafka event / command (nx.bana.evt.* · nx.bana.cmd.*) | sự kiện ứng dụng liên-service | packages/core/src/common/kafka/registry.ts (ServiceTopicDefs) |
Debezium CDC (nx.bana.cdc.<schema>.<Table>) | thay đổi dòng → read-model (Typesense, projection) | cùng registry (CDC_TABLE_SCHEMA, CDCTopicDefs) |
| HTTP webhook | hai chặng service-to-service (payment→sale, commerce→invoice) | cấu hình webhook từng service |
WebSocket (ws:…) | đẩy real-time tới client (fan-out giữa instance qua Redis) | websocket.ts từng service |
Code cũ / chết - không phải xương sống messaging
IEventBus + RedisPubSubAdapter của @nx/core và các hằng PaymentEventChannels / CommerceEventChannels không bao giờ được khởi tạo cho eventing liên-service. Seam payment thật là topic Kafka nx.bana.evt.payment.succeeded, không phải chuỗi payment.order.success. Redis pub/sub chuyển frame WebSocket giữa các replica - nó không chuyển sự kiện ứng dụng giữa các service.
Kafka event & command
Quy ước tên topic: nx.bana.<evt|cmd>.<domain>[.<entity>].<event> - chữ thường, ngăn bằng ., dùng - cho từ ghép, quá khứ cho evt, mệnh lệnh cho cmd. Registry ServiceTopicDefs là danh sách đầy đủ:
| Topic | Loại | Producer | Consumer |
|---|---|---|---|
nx.bana.evt.payment.succeeded | evt | sale | finance, inventory, invoice |
nx.bana.evt.inventory.purchase-order.received | evt | inventory | finance |
nx.bana.evt.inventory.stock.issued-for-sale | evt | inventory | finance |
nx.bana.evt.inventory.stock.adjusted | evt | inventory | finance |
nx.bana.evt.kitchen.ticket-item.status-changed | evt | sale | inventory |
nx.bana.evt.inventory.material.transferred | evt | inventory | inventory (chuyển kho) |
nx.bana.evt.inventory.material.stock-changed | evt | inventory | (chưa có consumer) |
nx.bana.evt.signal.activity.notified | evt | (chưa có producer) | signal → WebSocket |
nx.bana.cmd.ledger.generate | cmd | ledger | ledger (queue → worker nội bộ) |
Các hằng
KafkaTopics.*phân giải ra các tên trên.signal.activity.notifiedđã có consumer nhưng chưa có producer trong repo;material.stock-changedđược phát nhưng hiện chưa có consumer - cả hai đã đấu nối sẵn cho việc sắp tới.cmd.ledger.generatelà nội bộ ledger (tách queue→worker), không phải seam liên-service.
Consumer group
| Service | Subscribe |
|---|---|
| finance | payment.succeeded, inventory.purchase-order.received, inventory.stock.issued-for-sale, inventory.stock.adjusted, CDC public.Merchant |
| inventory | payment.succeeded, kitchen.ticket-item.status-changed, inventory.material.transferred, CDC public.Merchant, CDC public.ProductVariant |
| invoice | payment.succeeded, CDC public.Merchant |
| signal | signal.activity.notified |
| search | toàn bộ 27 CDC topic |
| ledger | cmd.ledger.generate (nội bộ) |
Debezium CDC
Connector Debezium đặt topic.prefix = nx.bana.cdc, phát nx.bana.cdc.<schema>.<Table> đúng nguyên theo từng bảng Postgres (CDC_TABLE_SCHEMA, đồng bộ với table.include.list của connector). 27 bảng được capture và đưa vào read-model:
| Consumer | CDC topic | Projection |
|---|---|---|
| search | toàn bộ 27 (SearchCollections.ALL_CDC_TOPICS) | collection Typesense (products, merchants, categories, organizers, devices, sale-channels) |
| invoice | nx.bana.cdc.public.Merchant | TaxInfo (hồ sơ thuế merchant chuẩn) |
| finance | nx.bana.cdc.public.Merchant | ví Cash mặc định khi có merchant mới |
| inventory | nx.bana.cdc.public.Merchant, …public.ProductVariant | seed InventoryItem |
Bảng capture theo schema: public (Organizer, Merchant, Category, Device, SaleChannel, Product, ProductInfo, ProductVariant, ProductCategory, ProductIdentifier, MetaLink, ProductBundler, ProductOption, ProductOptionValue, ProductVariantOption), pricing (FareSet, Fare), sale (SaleOrder), inventory (InventoryStock, InventoryItem, InventoryLocation, InventoryIdentifier, Material), identity (User, UserProfile, UserIdentifier, PolicyDefinition).
Topic nội bộ connector (không phải dữ liệu ứng dụng):
nx_bana_connect_configs/_offsets/_statuses,__debezium-heartbeat.nx.bana.cdc,nx.bana.cdc.public.debezium_signal, và các topic DLQ.
WebSocket topic
Topic WebSocket theo ws:{namespace}.{domain}.{entity}; room theo wr:{namespace}/{path}. Dựng bởi WebSocketTopics / WebSocketRooms trong packages/core/src/common/events/websocket-events.ts. Giao giữa các instance được fan-out qua Redis (signal, sale, payment, helpdesk, outreach gắn một Redis emitter adapter).
Sale (packages/sale/src/common/websocket.ts):
| Topic | Mục đích |
|---|---|
ws:observation.sale.sale-order | Đơn được tạo/cập nhật |
ws:observation.sale.sale-order-item | Thay đổi mục đơn hàng |
ws:observation.sale.sale-check | Thay đổi trạng thái check |
ws:observation.sale.kitchen-ticket | Phiếu bếp được gửi |
ws:observation.sale.kitchen-ticket-item | Cập nhật mục phiếu bếp |
ws:observation.allocation.allocation-usage | Thay đổi sử dụng chỗ/allocation |
Payment (packages/payment/src/common/websocket.ts):
| Topic | Mục đích |
|---|---|
ws:observation.payment.transaction | Cập nhật trạng thái giao dịch thanh toán |
ws:observation.payment.payment-attempt | Sự kiện từng lần thử thanh toán |
Outreach (packages/outreach/src/components/websocket/topics.ts):
| Topic | Mục đích |
|---|---|
ws:observation.outreach.inquiry.submitted | Có inquiry mới (thông báo admin real-time) |
HTTP webhook
payment → sale
Service sale nhận sự kiện thanh toán từ MQ-Pay qua HTTP, định tuyến theo header X-Webhook-Event-Type (packages/sale/src/common/webhook-types.ts):
| Event type | Mục đích |
|---|---|
mq-pay:attempt.success | Lần thử thanh toán thành công |
mq-pay:attempt.failed | Lần thử thanh toán thất bại |
mq-pay:attempt.expired | Lần thử thanh toán hết hạn |
mq-pay:attempt.cancelled | Người dùng hủy lần thử |
mq-pay:transaction.settled | Giao dịch tất toán (đã trả hết) |
mq-pay:transaction.cancelled | Giao dịch bị hủy |
Khi đơn tất toán, sale phát topic Kafka nx.bana.evt.payment.succeeded. Bên trong thư viện MQ-Pay các sự kiện này trước hết phát trên một EventEmitter của Node.js (mq-pay:transaction.*, mq-pay:attempt.*, mq-pay:refund.*) và được bắc cầu sang sale qua MQPaySaleEventAdapter → SaleEventMapperService → SalePaymentEventHandlerService.
commerce → invoice
commerce phát commerce:organizer.hq_changed như một HTTP webhook (WebhookDispatcherService + WebhookConfig); invoice nhận qua CommerceWebhookService.handleEvent để làm mới hồ sơ phát hành.
Luồng
Onboarding merchant mới (qua CDC)
Thanh toán
Thay đổi sản phẩm → read-model (CDC)
Trang Liên quan
| Trang | Mô tả |
|---|---|
| Kiến trúc | Danh mục dịch vụ, chuỗi phụ thuộc, ma trận component |
| Platform Facts | Tóm tắt messaging seam, số liệu chuẩn |
| Hạ tầng - Kafka | Thiết lập cluster Kafka KRaft |
| Hạ tầng - CDC | Cấu hình pipeline Debezium CDC |