Skip to content

Kiến trúc

1. System Context (C4 L1)

2. Container View (C4 L2)

3. Component View (C4 L3) — Phân lớp nội bộ

LớpTrách nhiệm
Routes/inventory-stocks, /purchase-orders, … (15 trong RestPaths)
ControllersCổng auth (JWT / BASIC), kiểm tra permission, mapping DTO
ServicesLogic nghiệp vụ, transaction, phát sự kiện, guard idempotency
WorkersInventoryWorkerService, MaterialWorkerService — Kafka handler stateless
RepositoriesDrizzle queries, soft-delete, atomic adjuster (adjustStock)
ComponentsKafka producer/consumer, WebSocket, Redis cache

4. State Machines Index

EntityTrạng tháiSơ đồ
PurchaseOrderDRAFT, PROCESSING, RECEIVED, COMPLETED, CLOSED, CANCELLED
MaterialRecipeDRAFT, ACTIVATED, DEACTIVATED
Vendor / VendorItemACTIVATED, DEACTIVATED, ARCHIVED
InventoryLocationNEW, ACTIVATED, DEACTIVATED, ARCHIVED
InventoryTicketDRAFT, SUBMITTED, APPROVED, IN_PROGRESS, COMPLETED, CANCELLED

PurchaseOrder

TừSự kiệnĐếnGuards
DRAFTconfirmPROCESSINGitems length ≥ 1
PROCESSINGreceive(items)RECEIVEDnhận một phần
PROCESSINGreceive(items)COMPLETEDtất cả items có receivedQuantity ≥ quantity
RECEIVEDreceive(items)RECEIVED / COMPLETEDnhận tiếp phần còn lại
RECEIVED / COMPLETEDcompleteCOMPLETEDidempotent
RECEIVED / COMPLETEDcloseCLOSEDterminal
PROCESSINGrevertDRAFTchưa nhận item nào
any non-terminalcancelCANCELLEDterminal

MaterialRecipe

Vendor / VendorItem

InventoryLocation

InventoryTicket

5. Kịch bản Runtime

5.1 Sale Payment → Trừ Stock

5.2 Kitchen Ticket Item READY → Tiêu thụ Material

5.3 PO Confirm → Receive → Complete

5.4 Merchant CDC → Seed Default Location

5.5 ProductVariant CDC seed — COMBO tự bị skip

InventoryWorkerService.handleProductVariantCDC chỉ seed InventoryItem cho các variant type stockable. ProductVariantTypes.COMBO không nằm trong STOCKABLE_SET, nên guard có sẵn

ts
if (!ProductVariantTypes.isStockable(productVariant.type)) return;

đã loại combo variant — không cần category lookup, không cần branch thêm. Combo variant là ảo; component giữ stock.

Combo deduction chảy qua path per-item hiện có tại payment-success vì cart-add layer (@nx/sale) đã insert các leaf component thành SaleOrderItem con với leadItemId. Worker xem chúng như item PRODUCT_VARIANT thường và trừ kho bình thường.

ADR: ./decisions/0006-combo-explosion-at-cart-add.

6. Crosscutting Concerns

ConcernCách service xử lý
AuthNJWT (ES256, JWKS lấy từ identity); fallback sang BASIC cho service-to-service
AuthZCasbin qua PolicyDefinitionService (cache ở Redis) — code <Resource>.<action> từ controllers/permissions.ts
i18nCột jsonb dạng { en, vi }; locale resolve từ Accept-Language
LoggingStructured logger của IGNIS; định dạng key: %s; topic/partition/offset cho Kafka
IdempotencyLookup theo (referenceType, referenceId, inventoryStockId) trong InventoryTracking trước khi ghi
AtomicityInventoryStockRepository.adjustStock — một SQL UPDATE duy nhất với forceNonNegative tùy chọn
Soft-deleteSoftDeletableRepository (deletedAt); audit trail (InventoryTracking) KHÔNG soft-delete
IDsSnowflake qua IdGenerator, worker 5
TransactionsPhương thức service nhận tham số transaction tùy chọn; aggregate ops scope qua helper _withTransaction
Merchant scopingMerchantScopedService chèn filter merchantId cho mọi read/write với role không phải system

7. Trang liên quan

Proprietary and Confidential. Unauthorized copying, distribution, or use of this software is strictly prohibited.