Architecture
1. Bối cảnh hệ thống (C4 L1)
Pricing thuần đồng bộ trên đường read/calculate (sale gọi nó inline lúc checkout). Input async duy nhất là luồng CDC
ProductVarianttự seed fare.
2. Góc nhìn Container (C4 L2)
3. Góc nhìn Component (C4 L3) — Phân lớp nội bộ
| Lớp | Trách nhiệm |
|---|---|
| Routes | 12 base path trong RestPaths (một — pricing-configurations — khai báo, không controller mount) |
| Controllers | Cổng auth (jwt, basic), permission theo resource, ánh xạ DTO |
| Calculation services | Toán fare/tax stateless; v1 flat, v2 snapshot |
| Management services | CRUD + transaction aggregate |
| Repositories | Truy vấn Drizzle, soft-delete, denormalize counter |
| Worker | Nạp CDC, seed fare idempotent |
4. Chỉ mục máy trạng thái
| Entity | Trạng thái | Sơ đồ |
|---|---|---|
FareSet | ACTIVATED, DEACTIVATED | → |
Fare | ACTIVATED, DEACTIVATED, ARCHIVED | → |
Tax / TaxSet / TaxType | ACTIVATED, DEACTIVATED, ARCHIVED | → |
Promotion | DRAFT, ACTIVATED, DEACTIVATED, ARCHIVED | → |
FareSet
FareSetStatuses.canDeactivate()luôn trảfalse— một FareSet đã activated là terminal-active. Đúng một FareSet ACTIVATED mỗi variant là bất biến chọn lựa.
Fare
Tax / TaxSet / TaxType
Cả ba chia sẻ IGNIS
Statuses.{ACTIVATED, DEACTIVATED, ARCHIVED}. Tax calculator chỉ đọc hàng ACTIVATED trong cửa sổ hiệu lực.
Promotion
Promotion hiện chỉ CRUD — không calculator nào tiêu thụ chúng, nên trạng thái chưa có hiệu ứng định giá.
5. Kịch bản runtime
5.1 Định giá Checkout (v2 snapshot)
| Bước | Chi tiết |
|---|---|
| 2–7 | Theo dòng: chọn fare (DEFAULT/OVERRIDE/POLICY), rồi thuế kép gom theo priority |
| 8 | Order snapshot tổng hợp ledger byBearer theo dòng + rule cấp order |
| 9–10 | Sale lưu snapshot bất biến; pricing không giữ trạng thái order |
5.2 ProductVariant CDC → Seed Fare
| Bước | Chi tiết |
|---|---|
| 4 | Chỉ xử lý CREATE/RETRIEVE; UPDATE/DELETE là no-op |
| 5 | Bỏ qua khi đã có FareSet cho variant (idempotent) |
| 6 | FBT bundlers seed một OVERRIDE child mang orderProductVariantIds CONTAINS leadVariantId |
5.3 Variant đồng bộ — Deep Copy FareSet
Khi một variant mang
metadata.referenceId, worker deep-copy toàn bộ cấu trúc fare của variant tham chiếu trong một transaction thay vì seed một default tươi.
6. Mối quan tâm xuyên suốt
| Mối quan tâm | Cách service này xử lý |
|---|---|
| AuthN | JWT (ES256, JWKS từ identity); BASIC cho service-to-service (sale dùng BASIC) |
| AuthZ | Casbin qua PolicyDefinition; theo resource mỗi controller; permission cache trong Redis |
| i18n | jsonb { default, en, vi } trên cột name / description |
| Logging | IGNIS có cấu trúc (key: %s); decorator @logged(); marker SKIP/DONE trong worker |
| Money | float(x, 4) khắp nơi; số tiền lưu decimal(15,4), serialize thành chuỗi (MoneySchema) |
| Idempotency | CDC worker bỏ qua khi FareSet/FBT override đã seed; endpoint calculate không side-effect |
| Statelessness | Pricing không lưu order/snapshot; snapshot nó trả về thuộc về caller |
| Soft-delete | SoftDeletableRepository (deletedAt); filter mặc định deletedAt IS NULL |
| IDs | Snowflake qua IdGenerator, worker 7 |