StackTrading Docs

SRS: BPS — Manual Payout Hold (UC 10.4.6)

FieldValue
BA in ChargeAnh Hoang
Date Created2026-11-04
Versionv1.9
Document ReferencesZapier Integration V7.pdf (Break-Glass Operations — Manual Payout Holds ("Do Not Pay" list) · Operational Security Requirement · §Flow 5, Flow 9, Flow 17, Flow 36)ADMIN BPS OPERATIONS.xlsx (tab "QnA (Lily)" — Manual Payout Hold: RBAC, Input, Output, Logic Requirements)QnA_BPS_AnhHoang_UC_10.2-10.4.md (AH-HOLD-01 → AH-HOLD-19)

UC_10.4.6 — Manual Payout Hold

🇻🇳 Section này viết bằng tiếng Việt để BA review. Mọi ID, anchor, tên field/API và text trả về giữ nguyên tiếng Anh.

1. Overview

FieldContent
IDUC_10.4.6
Use CaseManual Payout Hold
DescriptionOperations / Compliance dùng endpoint này để chặn ngay mọi khoản tiền trả ra cho một trader, cả lúc vận hành bình thường (VD đang điều tra nghi gian lận hoặc vi phạm rule) và khi có sự cố (break-glass).
Phạm viEndpoint thêm / gỡ hold, và quy tắc các luồng trả tiền phải kiểm tra hold. Không gồm: khoá tài khoản trading (Admin làm riêng nếu cần), lương cơ bản W-2 (US) định kỳ, vì khoản này chạy trực tiếp trong Rippling và do HR quản lý trong Rippling; UI trên Trader Dashboard, màn hình BPS Admin.
Zapier FlowKhông có Zap riêng. Hold được kiểm tra trong Flow 5, Flow 9, Flow 17 và cron International Retainer (Flow 36)
Zapier Table— (đọc / ghi bảng PostgreSQL Users, BPS_Audit_Log)
APIBPS endpoint Manual Payout Hold (POST)
Cron Job taskKhông có
3rd PartySlack (hold chặn lệnh gọi Dots, Rippling)

2. Trigger

  • Operations / Compliance cần chặn tiền trả ra cho 1 trader (VD đang điều tra nghi gian lận). Level 2 Admin thêm hold trên BPS Admin console (màn hình quản trị nội bộ của Stack Trading, do team Stack Trading tự làm. Admin đăng nhập màn này để tìm trader và bấm các thao tác hỗ trợ; mỗi thao tác gọi tới endpoint do Sotatek làm).
  • Điều tra xong, Level 2 Admin gỡ hold.

3. Pre-conditions

  • Admin đã đăng nhập BPS Admin console với role Level 2 Admin hoặc System Admin (BR_10.4.6.1).
  • Trader đã có trong Users.

4. Post-conditions

  • Thêm hold: Users.payout_hold = TRUE. Từ lúc này, mọi khoản payout tự động chưa gửi đi của trader đều bị giữ lại.
  • Gỡ hold: Users.payout_hold = FALSE. Các khoản đang giữ được trả lại theo BR_10.4.6.7.
  • Trạng thái tài khoản trading không đổi. Trader không nhận email, Dashboard không đổi gì.
  • BPS_Audit_Log có 1 dòng; #ops-general có tin báo.

5. Basic Flow

5.1 Add/remove a trader from a payout hold list (Logic Requirement 1)

Stage 1 — Nhận request

  1. BPS Admin console gọi Manual Payout Hold (POST, path do BE xác định) với header Authorization: Bearer <access-token> (mã đăng nhập của Admin, cách hoạt động xem BR_10.4.6.1) và input. Nguồn ghi Input là "None"; input dưới đây theo câu trả lời của khách:

    InputBắt buộcValue
    user_id✅UUID của trader
    action✅'HOLD' (thêm hold) hoặc 'RELEASE' (gỡ hold)
    reason✅Lý do Admin nhập (xem §5.3)
    transcript_url✅URL tới Freshdesk ticket

    admin_id lấy từ JWT (hoặc payload).

    OutputKhi nào
    200 OKThêm / gỡ hold thành công
  2. Endpoint xác thực token, kiểm tra role trong JWT phải là Level_2 hoặc System_Admin, và kiểm tra input theo BR_10.4.6.1. Không đạt thì xem E_10.4.6.1, E_10.4.6.2, E_10.4.6.3.

Stage 2 — Kiểm tra điều kiện hợp lệ để Admin thêm / gỡ hold

  1. Endpoint tìm trader theo user_id. Không thấy → E_10.4.6.4.
  2. Endpoint đọc Users.payout_hold (BR_10.4.6.4):
    • action = 'HOLD' mà trader đang bị hold → E_10.4.6.5.
    • action = 'RELEASE' mà trader không bị hold → E_10.4.6.6.

Stage 3 — Thêm / gỡ hold

  1. HOLD → Users.payout_hold = TRUE. RELEASE → Users.payout_hold = FALSE, các khoản đang giữ được trả lại theo BR_10.4.6.7. Trạng thái tài khoản trading không đổi (BR_10.4.6.8).

Stage 4 — Ghi log và trả kết quả

  1. Endpoint ghi BPS_Audit_Log với action = 'PAYOUT_HOLD' hoặc 'PAYOUT_RELEASE' (BR_10.4.6.2).
  2. Endpoint trả 200 OK.
  3. Endpoint gửi tin ✅ OPERATIONS ACTION PERFORMED vào #ops-general (BR_10.4.6.3). Không gửi email cho trader.

5.2 Halt payout triggers and prevent payout execution even if prior events replay (Logic Requirement 2)

Stage 5 — Các luồng trả tiền kiểm tra hold

  1. Trước khi gửi một khoản payout sang Dots API hoặc Rippling Off-Cycle API, luồng trả tiền kiểm tra trader có đang bị hold không (Users.payout_hold). Đang bị hold thì không gửi khoản đó (BR_10.4.6.5). Vì kiểm tra ngay lúc sắp gửi tiền, nên dù một sự kiện trả tiền cũ bị chạy lại, khoản đó vẫn bị chặn (E_10.4.6.8). Các luồng có bước kiểm tra này:

    LuồngChỗ kiểm tra
    Flow 5 — thưởng lên cấp, Data Refund, hoàn phí Sierra ChartStep 2 Compliance Check
    Flow 9 — SeveranceTrước lệnh trả tiền
    Flow 17 — Pod Leader Carry VestingTrong POST /process-pod-vesting (UC_8.2.12)
    Flow 36 — Dots retainer hằng tháng của International ContractorTrong cron International Retainer (UC_8.3.1)

Stage 6 — Giữ khoản tiền đến hạn

  1. payout_hold = TRUE → luồng bỏ qua khoản của trader này và giữ khoản đó ở trạng thái chờ (BR_10.4.6.6):
    • Flow 17: bỏ qua leader này (giống leader bị lỗi routing Dots), giữ nguyên Pending_Carry_Balance, không đưa về 0.
    • Flow 5, Flow 9, Flow 36: bản ghi payout giữ status = 'pending' / 'held' trong bảng payouts, không huỷ, không xoá.
    • ⚠️ Dev kiểm tra: schema Zapier V7 §3.1 chưa có bảng payouts; nơi lưu payout đang chờ khách trả lời ở STAGE5-039.
    • Gửi cảnh báo vào #ops-treasury cho mỗi khoản bị bỏ qua do hold.
  2. Khoản đã gửi sang Dots / Rippling trước lúc thêm hold thì không chặn được nữa; hệ thống không huỷ hay đảo lại khoản đó, Stack Trading tự chấp nhận (E_10.4.6.7).

5.3 Require a reason code and supervisor approval policy (if applicable) (Logic Requirement 3)

Stage 7 — Lý do và phê duyệt

  1. Không có danh sách reason code cố định: reason là text tự do, bắt buộc, đã kiểm ở bước 2. Không có quy trình duyệt của người thứ 2 (supervisor): 1 lần gọi của Level 2 Admin / System Admin là có hiệu lực ngay (BR_10.4.6.1).

6. Exceptional Flows

Mọi trường hợp thất bại ở §5.1 đều ghi BPS_Audit_Log (BR_10.4.6.2) và báo #ops-general (BR_10.4.6.3).

Exception IDExceptionConditionSystem Handling / Fallback
E_10.4.6.1Token không hợp lệKhông có token, hoặc token không xác thực được.Từ chối, không thực thi.
E_10.4.6.2Không đủ quyềnJWT có role Level_1.Trả 403 Forbidden.
E_10.4.6.3Input không hợp lệThiếu reason hoặc transcript_url, hoặc action khác 'HOLD' / 'RELEASE'.Trả 400 Bad Request. Không kiểm tra nội dung reason.
E_10.4.6.4Không tìm thấy traderuser_id không có trong Users.Trả 404.
E_10.4.6.5Thêm hold khi đang holdaction = 'HOLD' và payout_hold = TRUE.Trả 409 "Trader is already on payout hold".
E_10.4.6.6Gỡ hold khi chưa holdaction = 'RELEASE' và payout_hold = FALSE.Trả 409 "Trader is not on payout hold".
E_10.4.6.7Thêm hold sau khi tiền đã gửi điVD trader lên cấp lúc 10:00, hệ thống đã gửi lệnh trả thưởng sang Dots; 10:05 Admin mới thêm hold.Hold chỉ chặn khoản chưa gửi. Khoản đã gửi sang Dots / Rippling không bị huỷ hay đảo lại; Stack Trading tự chấp nhận khoản đó.
E_10.4.6.8Sự kiện cũ chạy lạiWebhook trả tiền cũ chạy lại (replay) trong lúc trader đang bị hold.Bị chặn, vì hold được kiểm tra ngay trước lệnh gọi Dots / Rippling, không phải lúc nhận sự kiện (BR_10.4.6.5).
E_10.4.6.9Ghi BPS_Audit_Log lỗiInsert vào BPS_Audit_Log không thành công.Ghi lỗi vào server log (CloudWatch), không chặn response.

7. Business Rules

BR_IDRule Description
BR_10.4.6.1Xác thực, quyền và input: Endpoint chỉ nhận request từ BPS Admin có token trong header Authorization: Bearer <access-token>. Cách hoạt động:1. Admin đăng nhập BPS Admin console, Auth0 (dịch vụ đăng nhập) trả về một mã đăng nhập (token).2. Admin bấm thao tác, BPS gửi yêu cầu sang endpoint, kèm mã đăng nhập đó.3. Endpoint kiểm tra mã: mã đúng thì biết ai đang thao tác (VD adam@stacktrading.com) và làm tiếp; mã sai hoặc hết hạn thì từ chối.admin_id lấy từ JWT (hoặc payload).Quyền gọi theo role:- Level 1 Admin: ❌ không được gọi, endpoint trả 403 Forbidden.- Level 2 Admin: ✅ được gọi.- System Admin: ✅ được gọi.Endpoint tự kiểm tra role trong JWT (RBAC Gate). Không có quy trình duyệt 2 người: 1 lần gọi của Level 2 / System Admin là có hiệu lực ngay. user_id, action, reason, transcript_url bắt buộc; reason là text tự do.
BR_10.4.6.2Audit log: Mỗi request, thành công hay thất bại, ghi 1 dòng vào BPS_Audit_Log (PostgreSQL) và server log (CloudWatch) với đủ 6 field: admin_id, user_id, action ('PAYOUT_HOLD' hoặc 'PAYOUT_RELEASE'), timestamp, reason, transcript_url, kèm kết quả success / failure. BPS_Audit_Log cũng là lịch sử thêm / gỡ hold của trader.⚠️ Dev kiểm tra: bảng bps_audit_logs chưa có cột transcript_url và kết quả.Insert lỗi thì không chặn luồng (E_10.4.6.9).
BR_10.4.6.3Slack: Mỗi request từ BPS Admin báo kết quả vào #ops-general (Ref: slack_channel_usage.md) theo mẫu Slack BPS, gồm 2 loại tin:- Thành công: dòng đầu ✅ OPERATIONS ACTION PERFORMED.- Thất bại (bất kỳ bước nào không thực hiện được): dòng đầu 🚨 FAILED OPERATION ACTION.Các dòng sau giống nhau ở cả 2 loại:- WHEN: thời điểm thực hiện, dạng ISO timestamp- BY WHO: email của admin, lấy từ token- ACTION: Manual Payout Hold- ACCOUNT: email của trader- CHANGE: payout_hold trước và sau: thêm hold FALSE to TRUE, gỡ hold TRUE to FALSE- REASON: giá trị reason; không có thì ghi NULL- TICKET: mã ticket kèm link Freshdesk (transcript_url); không có thì ghi NULLVD tin thành công:✅ OPERATIONS ACTION PERFORMEDWHEN: 2026-11-04T09:30:00ZBY WHO: adam@stacktrading.comACTION: Manual Payout HoldACCOUNT: hana@sotatek.comCHANGE: FALSE to TRUEREASON: Fraud investigationTICKET: 12345 https://stacktrading.freshdesk.com/a/tickets/12345Tin thất bại có cùng các dòng, chỉ đổi dòng đầu. BPS_Audit_Log ghi đúng kết quả thành công / thất bại tương ứng. Khoản payout bị bỏ qua do hold thì báo riêng vào #ops-treasury (§5.2 bước 10).
BR_10.4.6.4Nơi lưu hold: Cột boolean Users.payout_hold (mặc định FALSE). Không tạo bảng riêng; lịch sử thêm / gỡ lấy từ BPS_Audit_Log. Hold không tự hết hạn, không có cron nhắc: còn hiệu lực tới khi admin gọi action = 'RELEASE'.
BR_10.4.6.5Hold chặn những khoản nào, kiểm tra ở đâu: Chặn mọi payout tự động do backend / Zapier kích hoạt:- Flow 5: thưởng lên cấp (Promotion Bonuses), Data Refund, hoàn phí Sierra Chart.- Flow 9: Severance.- Flow 17: Pod Leader Carry Vesting.- Dots retainer định kỳ của International Contractor (Flow 36).Lương cơ bản W-2 (US) định kỳ chạy trực tiếp trong Rippling và do HR quản lý trong Rippling, không do backend / Zapier kích hoạt.Cách chặn: ngay trước khi gửi khoản tiền sang Dots API hoặc Rippling Off-Cycle API, luồng kiểm tra Users.payout_hold; đang hold thì không gửi. Khoản đã gửi sang Dots / Rippling trước đó thì không chặn được, Stack Trading tự chấp nhận. Vì kiểm tra ngay lúc sắp gửi tiền nên sự kiện trả tiền cũ chạy lại cũng bị chặn.
BR_10.4.6.6Khoản đến hạn trong lúc hold: Giữ lại, không huỷ, không xoá. Flow 17 giữ nguyên Pending_Carry_Balance; các luồng còn lại giữ bản ghi payout ở status = 'pending' / 'held'. Hold chỉ chặn khoản chưa gửi đi; khoản đã gửi sang Dots / Rippling thì không đảo lại.
BR_10.4.6.7Sau khi gỡ hold: Day 1 không làm cơ chế trả gộp mới.- Carry của Pod Leader được trả ở kỳ Flow 17 tiếp theo (ngày 1 hằng tháng).- Bản ghi payout đang treo trong bảng payouts: cách trả lại đang chờ chốt (§8 Open Items #1).
BR_10.4.6.8Những gì hold không động tới: Trạng thái tài khoản trading (trader vẫn trade bình thường); email cho trader; UI Trader Dashboard (tab Billing, Career & HR); ledger công khai Polygon (chỉ ghi khi payout thực sự đã được trả, không ghi sự kiện hold).

8. Open Items

#Hạng mụcTrạng thái
1Trả lại khoản payout đang treo sau khi gỡ hold. Adrian: chạy lại Flow 5 cho bản ghi đó, hoặc để Operations xử lý tay.⏳ Cần BA chốt

9. Phân chia trách nhiệm

Hạng mụcSotatek buildStack Trading OpsBên thứ 3
Endpoint Manual Payout Hold: RBAC gate, kiểm tra, cập nhật Users.payout_hold, audit log, Slack✅——
Kiểm tra hold trước lệnh trả tiền ở Flow 5, Flow 9, Flow 17, Flow 36; giữ khoản ở trạng thái chờ; cảnh báo #ops-treasury✅——
Quyết định thêm / gỡ hold, điều tra—✅ (Operations / Compliance)—
Lương cơ bản W-2 (US) định kỳ—✅ (HR)Rippling

Changelog

DateVersionUpdated itemBeforeAfterNotes
2026-11-04v1.9§5 tên Stage kiểm tra"Kiểm tra""Kiểm tra" → "Kiểm tra điều kiện hợp lệ để Admin thêm / gỡ hold"BA review 2026-11-04: tên Stage kiểm tra ghi rõ là kiểm tra điều kiện hợp lệ cho thao tác của Admin
2026-11-04v1.8§1 Phạm vi, §5 bước 9 và 11, E_10.4.6.7, BR_10.4.6.5, §9Bước 9 viết khó hiểu ("đọc Users.payout_hold ngay trước khi gọi…"); ghi "Không chặn lương W-2 US chạy trong Rippling"Bước 9 viết lại: trước khi gửi khoản payout sang Dots / Rippling thì kiểm tra hold, đang hold thì không gửi; khoản đã gửi trước đó thì Stack Trading tự chấp nhận. Phần W-2 ghi đúng ý khách: lương cơ bản W-2 (US) định kỳ chạy trực tiếp trong Rippling, do HR quản lý, không do backend / Zapier kích hoạtBA review 2026-11-04; AH-HOLD-08, AH-HOLD-11
2026-11-04v1.7§5 bước 1Ghi header Authorization: Bearer <access-token> nhưng không trỏ tới phần giải nghĩaThêm "(mã đăng nhập của Admin, cách hoạt động xem BR_10.4.6.1)" ngay sau headerBA review 2026-11-04
2026-11-04v1.6§1 Overview (thêm dòng Cron Job task), §3 Pre-conditions, §5 Basic Flow, BR phân quyền, toàn file§5 chia Stage theo cách BA tự đặt (Nhận request / Kiểm tra / Thực hiện), không theo Logic Requirements của nguồn; người thực hiện ghi là "Ops"; quyền ghi chung chung§5 chia mục 5.x theo đúng Logic Requirements ở cột B của tab "QnA (Lily)", mỗi mục có Stage và bước đánh số liên tục; phần khách trả lời thêm ghi ngay trong bước tương ứng; người thực hiện ghi là "Admin"; quyền ghi theo từng role (Level 1 Admin, Level 2 Admin, System Admin)BA duyệt khuôn UC_10.2.4, 2026-11-04
2026-11-04v1.5BR_10.4.6.1Giải nghĩa token viết liền 1 đoạn, còn chữ "header", "Bearer"Viết lại thành 3 bước dễ hiểu: Admin đăng nhập → Auth0 trả mã đăng nhập (token); BPS gửi yêu cầu kèm mã; endpoint kiểm tra mã, đúng thì biết ai thao tác và làm tiếp, sai / hết hạn thì từ chốiBA review 2026-11-04
2026-11-04v1.4BR_10.4.6.1Ghi header Authorization: Bearer ..., không giải nghĩaThêm giải nghĩa: token Auth0 cấp khi Admin đăng nhập BPS, BPS gửi kèm mỗi request, endpoint kiểm tra token và đọc ra Admin nào đang gọiBA review 2026-11-04; nguồn: câu trả lời của Adam (tab "QnA (Lily)", cột D dòng 3)
2026-11-04v1.3§2 TriggerGhi "BPS Admin console", không giải nghĩaThêm giải nghĩa trong ngoặc ở lần nhắc đầu tiên: màn hình quản trị nội bộ của Stack Trading do team Stack Trading tự làm, Admin dùng để tìm trader và bấm thao tác, mỗi thao tác gọi endpoint do Sotatek làmBA review 2026-11-04
2026-11-04v1.2§1 Overview — DescriptionBA tự tóm tắt luồng xử lý của endpointGhi đúng câu trả lời của khách cho câu hỏi Purpose (AH-HOLD-01)BA yêu cầu: Description = câu trả lời Purpose trong file Q&A
2026-11-04v1.1BR_10.4.6.3 (Slack), §8 Open ItemsChỉ ghi gửi #ops-general theo mẫu Slack BPS chung; mẫu chưa có (Open Item)Ghi đủ mẫu tin thành công (✅ OPERATIONS ACTION PERFORMED) và thất bại (🚨 FAILED OPERATION ACTION): WHEN, BY WHO, ACTION Manual Payout Hold, ACCOUNT, CHANGE, REASON, TICKET (không có thì NULL). Đóng Open Item mẫu SlackMẫu Slack BPS của BA Chloe, BA cung cấp 2026-11-04
2026-11-04v1.0Toàn bộ file—Tạo mới UC_10.4.6 theo khuôn UC_1.8.7, dựa trên runbook Manual Payout Holds của Zapier V7 và câu trả lời của kháchQnA_BPS_AnhHoang_UC_10.2-10.4.md (AH-HOLD-01 → 19)

On this page