ADR-0002. Chạy song song calculator v1 (/simulation) và v2 (/simulation-v2); v2 là chuẩn
| Trường | Giá trị |
|---|---|
| Trạng thái | Accepted |
| Ngày | 2026-04 |
| Người quyết định | Phat Nguyen |
| Thay thế | - |
Bối cảnh
- Pipeline v1 ban đầu (
src/services/core/) trả về response giá + thuế dạng phẳng theo từng dòng. Nó vẫn chạy được nhưng không thể diễn đạt ai chịu mỗi khoản tiền (người mua / người bán / nền tảng / nhà nước), cũng không mang theo một dấu vết kiểm toán khép kín. - Các nhu cầu phía hạ nguồn (hoàn tiền, kê khai thuế, đối soát nền tảng, biên lai bất biến) đòi hỏi một snapshot có nguồn gốc của rule đã áp dụng và một ledger theo từng role (
byBearer). - Sale đã lưu snapshot v2 trên
SaleOrder.priceMetadatalàm nguồn dữ liệu chuẩn cho kiểm toán/hoàn tiền. - v1 và v2 dùng chung khoảng 90% logic fare/thuế, nên chuyển đổi dứt khoát một lần có nguy cơ làm hỏng đường phẳng vẫn đang được dùng.
Quyết định
Giữ cả hai pipeline cùng hoạt động sau các route riêng: v1 tại POST /simulation/calculate (phẳng) và v2 tại POST /simulation-v2/calculate (snapshot - OrderPricingSnapshot + LineItemPricingSnapshot[]). v2 là chuẩn cho mọi việc mới. Trong giai đoạn chuyển tiếp, sale gọi cả hai lúc checkout; v2 là nguồn dữ liệu chuẩn được lưu lại.
Hệ quả
| Ưu điểm | Nhược điểm |
|---|---|
| Bên tiêu thụ mới nhận đầy đủ nguồn gốc rule + ledger theo người chịu | Trùng lặp ~90% logic nghĩa là sửa lỗi thường phải áp cho cả hai pipeline |
| Không có nguy cơ hỏng hóc cho bên tiêu thụ giá phẳng hiện có | Phải bảo trì hai luồng code cho tới khi v1 ngừng dùng |
Cấu trúc snapshot được đánh version độc lập (v: 1 theo từng lớp) | Độ trễ tính giá tăng gấp đôi lúc checkout vì gọi cả hai |
Các phương án đã cân nhắc
| Phương án | Ưu điểm | Nhược điểm | Vì sao loại |
|---|---|---|---|
| Chuyển dứt khoát v1 → v2 | Một luồng code | Nguy cơ hỏng hóc cao; mọi bên gọi phải migrate cùng lúc | Quá xáo trộn khi đang vận hành |
| Mở rộng response v1 tại chỗ | Không cần route mới | Phá vỡ contract phẳng; không thể thêm byBearer mà không gây biến động | Không tương thích ngược |
| Chỉ tính v2, rồi suy ra dạng phẳng từ đó | Một engine duy nhất | Bên gọi v1 sẽ cần một lớp rút gọn cấu trúc; chưa được xây | Hoãn lại tới khi v1 ngừng dùng |
Tham chiếu
pricing/src/services/core/(v1)pricing/src/services/core-v2/(v2 +pricing-snapshot/)pricing/src/controllers/simulation/,pricing/src/controllers/simulation-v2/