Appearance
Type Deep Dive — Transaction Request Engine
1. Engine này nằm ở đâu?
transaction_request là request engine trung tâm của wallet. FE không có “wallet module” riêng, nhưng nhiều màn hình cùng ghi vào engine này:
ecommerce/pages/WithdrawRequestCreate.tsxecommerce/pages/WithdrawRequestDetail.tsxuser/components/customer/Collaborators.tsxaffiliate/components/core/WithdrawAffiliateForm.tsx
Các màn hình này dùng chung:
- mutation tạo request,
- action đổi status,
- query balance/stats để validate amount,
- read models để hiển thị commission/refund liên quan.
2. Create path
2.1 FE create request
Request mới thường đi qua mutation RefundRequestCreate.
Các bước phổ biến:
- FE lấy
wallet_balancehoặcwallet_stats. - FE build payload
transaction_request. - FE insert
transaction_request_usersender/receiver tương ứng. - Request thường được tạo ở status
R.
Write surfaces chính:
| Surface | Use case |
|---|---|
WithdrawRequestCreate.tsx | Tạo request hoàn/rút theo route ecommerce |
Collaborators.tsx | Tạo request payout cho collaborator trong user module |
WithdrawAffiliateForm.tsx | Tạo payout request cho affiliate/collaborator |
2.2 Insert event
Khi request được insert, wallet-api/event/transaction_request_insert.go xử lý:
- mirror sang
hrm_transaction_request, - sync
transaction_refund_log, - set
order.is_refunded_ordercho family refund, - build keywords,
- có thể auto-sinh child request
refund_commission.
Điểm quan trọng:
- insert event đã gây side effects nghiệp vụ, không phải chỉ “ghi request thô”,
- vì vậy nhiều cờ ở ecommerce có thể đổi trước khi request thực sự thành công.
3. Approve / Reject / Cancel path
3.1 Action changeStatusTransaction
FE gọi action này khi người dùng approve/reject/cancel.
Action backend:
- load request,
- check reviewer chain,
- validate transition theo status hiện tại,
- ghi
transaction_request_log, - tăng
num_approvedkhi approve, - update status cuối cùng sang
S,ChoặcReject.
Điểm cần nhớ:
- family refund/withdraw thực tế đang chạy nhiều ở
R -> S/C/Reject, - không phải mọi case đều đi qua
P.
3.2 Update event
Khi transaction_request.status hoặc success_at đổi, transaction_request_update xử lý:
- sync refund log,
- gửi notification approve/success,
- insert wallet credit nếu refund về ví,
- sync
hrm_transaction_request.success_at, - sync
ecommerce_transaction, - generate commission refund con ở vài nhánh.
Kết luận:
- action chỉ là gate transition,
- side effects business nặng nằm ở event update.
4. Ledger materialization
DB trigger trong migration khởi tạo sẽ materialize transaction từ transaction_request_user khi request sang S.
Mental model đúng:
text
transaction_request = workflow
transaction_request_user = requested legs
transaction = realized ledgerĐiều này giải thích vì sao:
- có request tồn tại nhưng chưa có
transaction, - có view/report phải đọc từ request thay vì transaction,
- reconciliation cần tách rõ requested amount và realized amount.
5. FE coupling và drift
5.1 Permission drift
| Case | Drift |
|---|---|
| IT/accounting transfer action | UI và route config đang không đồng nhất role thực sự được vào màn hình |
| Customer collaborator payout | Nút payout chủ yếu check host context thay vì module wallet permission rõ ràng |
| Approve guard | canApprove ở detail page có dấu hiệu so approver với created_by thay vì current user |
5.2 Data lookup drift
| Case | Drift |
|---|---|
WithdrawRequestSelectStatus | Dựa vào walletBalance[0] / [1] thay vì lookup theo wallet_type_id |
| Fallback amount | Có fallback cứng 40000000 nếu không đọc được balance |
| Withdraw history state | Dùng key state chung với tab collaborator root, dễ bleed filter/paging |
6. Permission / visibility map
| Flow | Runtime gate nổi bật |
|---|---|
| POS withdraw | refund_request_management + BranchPOS |
| Admin/accounting withdraw | fund_request_management |
| Affiliate commission edit | affiliate_management và không phải BranchPOS |
| Employee/customer wallet read | Chủ yếu qua module host user và role hiện tại |
Kết luận:
- permission của wallet request engine là permission phân tán,
- không có một wallet permission matrix FE duy nhất.
7. Rủi ro / Findings kỹ thuật
| ID | Mức | Finding |
|---|---|---|
| TE-F01 | P1 | canApprove ở FE có dấu hiệu check sai actor tại detail page. |
| TE-F02 | P1 | changeStatusTransaction có guard reject dựa trên allReviewer, có thể cho reviewer step cũ reject ở step sau. |
| TE-F03 | P1 | Sau khi bỏ trigger cấm update transaction_request_user, ledger có nguy cơ drift nếu request user bị sửa sau này. |
| TE-F04 | P1 | reference_id overload làm refund log và downstream sync phải fallback nhiều tầng. |
| TE-F05 | P2 | Request engine bị host bởi nhiều module FE khác nhau nên UX và validation rất dễ lệch nhau theo từng surface. |