Appearance
Type Deep Dive — Commission Lifecycle
1. Commission có phải subsystem riêng không?
Không. Trong code hiện tại, commission là một family request chạy trên cùng wallet request engine.
Điểm khác biệt chỉ là:
behavior_id,- wallet đích hoặc wallet nguồn,
- upstream creator,
- rule idempotency,
- refund/clawback path.
2. Commission create path chuẩn
2.1 Trigger nghiệp vụ
Các nguồn tạo commission phổ biến:
- invoice approved,
- membership / prepaid flow,
- referral / affiliate flow,
- event bonus.
Nguồn backend quan trọng nhất:
ecommerce-api/event/invoice_insert_update.gopkg/commission_util/add_commission.go
2.2 AddCommission(...)
Utility này thường:
- build checksum,
- tạo
transaction_request, - set
behavior_id = transaction_commission, - set
type = D, - chọn wallet đích
COMMISSIONhoặcVND_PROMOTION, - tạo request ở trạng thái
S, - để DB trigger materialize
transaction.
Kết quả:
- commission chuẩn là “auto-success request”,
- không cần đi qua màn hình duyệt như family refund/withdraw.
3. Customer / affiliate commission variants
3.1 AddCommissionCustomer(...)
Variant này dùng cho customer/affiliate-oriented flows nhưng vẫn giữ pattern:
- create request,
- create receiver leg,
- materialize ledger,
- đồng bộ read models/reporting.
3.2 Temp commission rồi mới approve
Một số flow affiliate dùng mô hình:
AddTempCustomerCommission(...)tạo request statusR,- affiliate/status change approval xảy ra,
AddAffiliateCommission(...)chuyển request sangS.
Đây là khác biệt quan trọng so với commission chuẩn từ invoice:
- commission không phải lúc nào cũng auto-success,
- cùng family commission nhưng state machine có thể khác nhau theo upstream business flow.
4. Commission refund / clawback
4.1 Refund order sinh child refund_commission
Khi refund order:
- FE đọc
order_commission_refund, - approver chọn amount truy thu theo user,
- FE hoặc backend tạo child
transaction_request, - child request có
behavior_id = refund_commission, - sender thường là ví
COMMISSIONcủa user bị truy thu.
4.2 Commission percent / affiliate config change
Một số thay đổi affiliate không tạo child request từ refund cha mà:
- update request hiện hữu, hoặc
- insert sender request mới để clawback phần commission không còn hợp lệ.
Điều này làm commission clawback có ít nhất 2 hình thái:
- child refund request gắn vào refund cha,
- standalone sender request do change config/business state.
5. Read models liên quan
| Object | Vai trò |
|---|---|
order_commission_refund | Aggregate commission/refund theo order + user |
ecommerce_transaction | Theo dõi side effect transaction phía ecommerce |
CommissionReport* | Báo cáo read-only phía report |
EmployeeProfileCommission | Lịch sử commission phía user module |
Điểm cần nhớ:
- đây là read models hoặc reporting surfaces,
- source-of-truth của lifecycle vẫn là
transaction_request+transaction.
6. Idempotency và duplicate risk
Checksum hiện tại là lớp anti-duplicate chính cho commission create.
Vấn đề:
- checksum mang tính time-window,
- chưa phản ánh đầy đủ business key bền vững như invoice/order/user/behavior/source,
- retry sau window có thể tạo duplicate hợp lệ về mặt kỹ thuật nhưng sai về business,
- hai thao tác hợp lệ quá gần nhau có thể bị chặn nhầm.
Kết luận:
- commission idempotency hiện là “best effort”,
- chưa phải contract mạnh để QA hoặc integration dựa vào hoàn toàn.
7. Rủi ro / Findings kỹ thuật
| ID | Mức | Finding |
|---|---|---|
| CL-F01 | P1 | Commission chuẩn và temp commission dùng hai state model khác nhau nhưng cùng family, dễ làm docs/QA nhầm là một flow duy nhất. |
| CL-F02 | P1 | refund_commission có thể được tạo theo child request hoặc sender request standalone, nên reconciliation phải phân biệt nguồn gốc. |
| CL-F03 | P1 | Idempotency checksum hiện dựa trên time-window, không đủ mạnh như business key. |
| CL-F04 | P2 | Reporting surfaces commission không luôn đọc ledger trực tiếp, nên số liệu có thể lệch khi read-model sync trễ hoặc source field bị overload. |