Skip to content

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.tsx
  • ecommerce/pages/WithdrawRequestDetail.tsx
  • user/components/customer/Collaborators.tsx
  • affiliate/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:

  1. FE lấy wallet_balance hoặc wallet_stats.
  2. FE build payload transaction_request.
  3. FE insert transaction_request_user sender/receiver tương ứng.
  4. Request thường được tạo ở status R.

Write surfaces chính:

SurfaceUse case
WithdrawRequestCreate.tsxTạo request hoàn/rút theo route ecommerce
Collaborators.tsxTạo request payout cho collaborator trong user module
WithdrawAffiliateForm.tsxTạ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_order cho 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_approved khi approve,
  • update status cuối cùng sang S, C hoặc Reject.

Đ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

CaseDrift
IT/accounting transfer actionUI và route config đang không đồng nhất role thực sự được vào màn hình
Customer collaborator payoutNút payout chủ yếu check host context thay vì module wallet permission rõ ràng
Approve guardcanApprove ở detail page có dấu hiệu so approver với created_by thay vì current user

5.2 Data lookup drift

CaseDrift
WithdrawRequestSelectStatusDựa vào walletBalance[0] / [1] thay vì lookup theo wallet_type_id
Fallback amountCó fallback cứng 40000000 nếu không đọc được balance
Withdraw history stateDùng key state chung với tab collaborator root, dễ bleed filter/paging

6. Permission / visibility map

FlowRuntime gate nổi bật
POS withdrawrefund_request_management + BranchPOS
Admin/accounting withdrawfund_request_management
Affiliate commission editaffiliate_management và không phải BranchPOS
Employee/customer wallet readChủ 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

IDMứcFinding
TE-F01P1canApprove ở FE có dấu hiệu check sai actor tại detail page.
TE-F02P1changeStatusTransaction có guard reject dựa trên allReviewer, có thể cho reviewer step cũ reject ở step sau.
TE-F03P1Sau 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-F04P1reference_id overload làm refund log và downstream sync phải fallback nhiều tầng.
TE-F05P2Request 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.