StackTrading Docs

Bản dịch: UC_9.2 → UC_9.17 (Background Mechanisms & Cron Jobs)

Bản dịch: UC_9.2 → UC_9.17 (BACKGROUND MECHANISMS & CRON JOBS)

Tổng hợp bản dịch tiếng Việt cho 11 use case thuộc nhóm BACKGROUND MECHANISMS & CRON JOBS đã có tài liệu SRS. File gốc tiếng Anh không bị thay đổi — khi có mâu thuẫn, file gốc là bản chuẩn. Mọi mã UC, field name, API endpoint, business rule ID, status value, code block và nội dung tin nhắn/email gửi cho user giữ nguyên tiếng Anh. UC_9.1, UC_9.4–UC_9.7, UC_9.10 chưa có tài liệu SRS nên chưa có trong bản dịch này. Ngày dịch: 2026-10-27. Cập nhật 2026-10-27: UC_9.2 (v2.0) và UC_9.12 (v1.1) theo CR-20261027-001 (Flow 13 hybrid); UC_9.2 (v2.1) và UC_9.17 (v1.3) đồng bộ account_status = 'Active_DMA'. Cập nhật 2026-10-28: UC_9.3 (v1.1) theo spec Flow 18. Cập nhật 2026-11-05: đồng bộ UC_9.2 (v2.5), UC_9.3 (v1.3), UC_9.11 (v1.1), UC_9.12 (v1.2), UC_9.14 (v1.1), UC_9.15 (v1.1), UC_9.16 (v1.1) theo câu trả lời của khách 2026-10-30 / 2026-11-04; mọi link .md đổi sang đường dẫn tuyệt đối /docs/. Cập nhật 2026-11-05 (sau): UC_9.8 (v1.2) theo câu trả lời của khách 2026-11-03 (Flow 30 — refund và cờ warning_80_fired).

Mục lục

UC_IDTên (tiếng Việt)File gốc
UC_9.2Luồng 13: Quản lý Nghỉ phép (DTO W-2 & Tạm ngưng Quốc tế)UC_9.2.md
UC_9.3Luồng 18: Sao lưu Cơ sở dữ liệu Cấu hình & Đồng bộ Khôi phục Thảm họaUC_9.3.md
UC_9.8Luồng 30: Cảnh báo Công suất MIDUC_9.8.md
UC_9.9Luồng 31: Giám sát Cạn kiệt Tổng hợp (Sev-1)UC_9.9.md
UC_9.11Luồng 34: Đồng bộ Sổ cái Lương RipplingUC_9.11.md
UC_9.12Luồng 35: Đồng bộ Sổ cái PTO RipplingUC_9.12.md
UC_9.13Luồng 36: Đồng bộ Sổ cái Retainer DotsUC_9.13.md
UC_9.14Luồng 32: Velocity Reward EngineUC_9.14.md
UC_9.15Luồng 33: Xác minh Amplify BountyUC_9.15.md
UC_9.16Luồng 38: Chặn Hỗ trợ & Tạo Ticket FreshdeskUC_9.16.md
UC_9.17Luồng 39: Gửi lại Hướng dẫn Dữ liệu Thị trường BPSUC_9.17.md

UC_9.2 — Luồng 13: Quản lý Nghỉ phép (DTO W-2 & Tạm ngưng Quốc tế)

TrườngGiá trị
BA phụ tráchlinh.nguyen34
Ngày tạo2026-08-20
Phiên bảnv2.7
Cập nhật lần cuối2026-11-05 — §2.2 modal Request Time Off: thêm ảnh màn hình; ghi chú thêm nút Cancel. Trước đó cùng ngày: Path A: gia hạn stagnation_deadline, đóng vị thế và khóa tài khoản bắt đầu vào leave_start_date đã đăng ký trên Rippling; trước ngày đó trader giao dịch bình thường. Trước đó cùng ngày: Bước A-3.5/B-3.5: đóng toàn bộ vị thế đang mở trước khi khóa — không còn đặc tả thuật toán TRIM_TO_COMPLIANCE. Lần trước: 2026-11-04 — Bảng tính của khách hàng (Adam/Adrian): Safety Check được viết lại dựa trên dữ liệu sẵn có (bảng blacklist, Users.status, Users.payout_status — không có field Compliance_Flagged); xử lý webhook đến muộn (2 trường hợp); hủy/rút ngắn PTO → Ops xử lý thủ công; carry của Pod Leader vẫn tiếp tục vest trong thời gian nghỉ; Flow 13 = Release 2.
Tài liệu tham chiếuCR-20261027-001 (Flow 13 hybrid — ghi đè trigger §Flow 13 của V7 + Path A Action 1) · QnA_STAGE2_SETTINGS_CAREER_VIRAL.md [HR-DEF-01] · References/Wireframe/Dashboard/Flow 13_Request Time Off modal (International).jpg · Zapier Integration V7.pdf (§Flow 13: Time-Off Management lines 1949–1982; §Flow 6: International L6 retainer trigger line 1635; §Flow 35: Rippling PTO Approval lines 2535–2548; §Flow 36: Retainer Execution lines 2549–2561; §Table A DTO_Days column lines 2952–3004; §Table B DTO_Days column lines 3005–3031; §POST /system/set-account-state lines 136–140) · RFQ_ Stack Trading Prop Tech V7.pdf (§BPS Endpoints lines 2721–2867; §Support Action Audit Trail line 3349; §Break-Glass procedure line 3379) · QnA_STAGE6_POD_SYSTEM_FLOW10_11.md [POD-XF-15] [POD-XF-16] [POD-XF-17] [POD-JOIN-19] [POD-SLA-08] [POD-AUDIT-10] [POD-DISP-08]

Danh mục UC

UC_IDTên Use CaseMô tả nghiệp vụ
UC_9.2Quản lý Nghỉ phépXử lý yêu cầu nghỉ phép và tạm ngưng giao dịch của trader Level 6+. Hai kênh vào (CR-20261027-001): path USA W-2 Paid DTO (trader yêu cầu nghỉ trong Rippling → webhook duyệt của Rippling → gia hạn deadline stagnation → khóa tài khoản giao dịch) hoặc path International Contractor Unpaid Hiatus (form "Request Time Off" trên Dashboard → tạm ngưng retainer Dots → gia hạn deadline stagnation → khóa tài khoản giao dịch). Khi kết thúc thời gian tạm ngưng, cổng Safety Check ngăn việc kích hoạt lại nếu trader khớp với bảng blacklist, có Users.status ∈ {Banned_Chargeback, Failed, Terminated}, hoặc payout_status ≠ Approved; nếu không thì khôi phục quyền giao dịch và tiếp tục thanh toán.

<a id="UC_9.2"></a>

UC_9.2 — Luồng 13: Quản lý Nghỉ phép (DTO W-2 & Tạm ngưng Quốc tế)

1. Tổng quan

TrườngNội dung
IDUC_9.2
Use CaseQuản lý Nghỉ phép
Mô tảXử lý yêu cầu nghỉ phép từ trader Level 6+ qua hai kênh vào (CR-20261027-001): trader USA W-2 yêu cầu và được duyệt ngay trong Rippling — webhook duyệt của Rippling kích hoạt Path A (Paid DTO); International Contractor gửi form native trên Dashboard — kích hoạt Path B (Unpaid Hiatus). Quốc gia đã xác minh KYC / Employment_Type được giữ lại làm guard. Khóa tài khoản giao dịch, gia hạn stagnation_deadline, và quản lý việc tạm ngưng/tiếp tục thanh toán. Khi trader quay lại, thực thi Safety Check trước khi khôi phục quyền giao dịch.
Zapier FlowFlow 13 (Time-Off Management — bao gồm delay_until cho Return Protocol) · Flow 35 (Rippling PTO Approval — Ledger Sync) · Flow 36 (Retainer Execution — Ledger Sync, cho retainer được tiếp tục)
Zapier TableTable A / Table B (cột DTO_Days — số ngày nghỉ có lương tối đa theo level)
3rd PartyRippling (USA W-2: sở hữu yêu cầu nghỉ phép, số dư DTO và việc duyệt; webhook Time Off Request Approved kích hoạt Path A và đồng bộ PTO ledger Flow 35) · Dots (International: tạm ngưng và tiếp tục retainer) · AWS SES (email DTO_Approval_Notice, DTO_Welcome_Back)
ReleaseRelease 2 (bảng tính khách hàng F13-01, 2026-11-04)

2. Trigger

Hai kênh vào — kênh quyết định path (CR-20261027-001):

Loại traderNơi trader yêu cầu nghỉ phépTrigger vào Flow 13Path
USA W-2 (Level 6+)Ngay trong Rippling (app/UI Rippling). Dashboard không cung cấp UI yêu cầu nghỉ phép cho trader W-2 — Career & HR Widget chỉ hiển thị CTA "View in Rippling" ([HR-DEF-01]).Webhook Rippling Time Off Request Approved → Zapier Flow 13Path A
International Contractor (Level 6+)Form "Request Time Off" native trên DashboardSubmit form → JSON webhook → Zapier Flow 13Path B

(Nguồn: CR-20261027-001 — khách hàng: "W2 traders can use Rippling" · "Create a very simple request form on the unified Dashboard for international contractors"; QnA [HR-DEF-01] 2026-08-15)

2.1 Trigger Path A — webhook Rippling Time Off Request Approved
  • Rippling sở hữu yêu cầu của W-2, số dư DTO và việc quản lý duyệt. Flow 13 chỉ bắt đầu sau khi Rippling đã duyệt yêu cầu.
  • Khi nhận webhook, Zap chỉ kiểm tra và lưu yêu cầu. Các bước xử lý nghỉ phép (Bước A-3 → A-4) chạy vào leave_start_date đã đăng ký trên Rippling, qua Zapier delay_until — cùng cơ chế Return Protocol dùng cho ngày kết thúc.
  • Cùng webhook này cũng kích hoạt Flow 35 — PTO Ledger Sync (UC_9.12). Flow 13 Path A và Flow 35 chạy độc lập trên cùng một event.
  • Các trường được dùng từ payload: Rippling worker → user_id; Rippling Request ID; ngày bắt đầu nghỉ; ngày kết thúc nghỉ (→ DTO_Hiatus_End_Date); số ngày được duyệt (→ Requested_Days).
2.2 Trigger Path B — form "Request Time Off" trên Dashboard (chỉ International Contractor)

Điểm vào UI (UC_4.16.2 — Career & HR Widget):

  • Nút: "Request Time Off" — góc trên bên phải của phần Employment Status trong Career & HR Widget.
  • Điều kiện hiển thị: chỉ International Contractor có Current_Level >= 6. Ẩn với trader W-2 (Employment_Type = 'W-2') và với trader dưới Level 6.
  • Thiết kế: References/Wireframe/Dashboard/Flow 13_Request Time Off modal (International).jpg · Figma — modal Request Time Off.

Modal "Request Time Off" (thiết kế đã duyệt):

Modal Request Time Off (International Contractor)

Figma: modal Request Time Off

Thành phầnLoạiQuy tắc
TitleText"Request Time Off"
DescriptionText (tĩnh)"As an international contractor, you may request an unpaid hiatus of any duration. Your account and monthly retainer will be paused during this time without penalty."
Start DateDate picker, MM/DD/YYYYBắt buộc. Ngày đầu tiên của kỳ tạm ngưng.
End DateDate picker, MM/DD/YYYYBắt buộc. Phải ≥ Start Date.
Requested DaysText chỉ đọcTự động tính từ Start Date và End Date; hiển thị _ cho đến khi cả hai ngày được chọn.
ReasonTextareaXem Q-4 (chưa xác nhận bắt buộc / độ dài tối đa).
SendNút chínhGửi form.
CancelNút phụ⚠️ Cần bổ sung — thiết kế hiện tại chưa có. Đóng modal mà không gửi: không gửi webhook, không thay đổi trạng thái DB.

⚠️ Ghi chú: cần thêm nút Cancel vào thiết kế (hiện chỉ có Send). Các cách đóng khác (X / click ra ngoài / Esc) — xem Q-4.

Công cụ form: Form native của Dashboard — KHÔNG phải công cụ bên thứ ba (ví dụ Typeform hoặc Google Forms).

Webhook payload được gửi tới Zapier Flow 13 khi Send:

TrườngMô tả
user_id (hoặc email đã đăng ký)Định danh trader — dùng để tra cứu Current_Level, Employment_Type, quốc gia đã xác minh KYC, và bản ghi DB
Start_DateNgày đầu tiên của kỳ tạm ngưng (từ form)
DTO_Hiatus_End_DateEnd Date từ form — Zapier map trực tiếp vào action delay_until cho Return Protocol
Requested_DaysSố ngày tự động tính — dùng để gia hạn stagnation_deadline (Bước B-3)
ReasonVăn bản tự do từ form

Loại trigger: Submit form → JSON webhook → endpoint catch-hook của Zapier → Flow 13.

2.3 Cổng vào (cả hai kênh)

Current_Level >= 6 — được kiểm tra khi nhận webhook Rippling (Path A) hoặc khi submit form (Path B).

  • Nếu Current_Level < 6 → từ chối / bỏ qua. Không xử lý thêm. Path A: ghi log vào BPS_Audit_Log (xem Exc-1).

Lý do: Level 6 là ngưỡng tối thiểu cho hợp đồng lao động W-2 (USA) hoặc hợp đồng independent contractor dựa trên retainer (International). Trader dưới Level 6 hoạt động theo mô hình bonus theo yêu cầu và không đủ điều kiện hưởng chính sách này. (Nguồn: Zapier Integration V7.pdf §Flow 13 lines 1949–1951; khách hàng xác nhận 2026-08-22)


3. Path Router

Path được xác định bởi kênh trigger:

Kênh triggerPath
Webhook Rippling Time Off Request ApprovedPath A — USA W-2 Paid DTO
Form "Request Time Off" trên DashboardPath B — International Contractor Unpaid Hiatus

Guard (kiểm tra nhất quán): quốc gia đã xác minh KYC (được ưu tiên hơn billing_country theo CR-20260812-005) và Employment_Type phải khớp với kênh:

  • Webhook Rippling cho trader không phải Employment_Type = 'W-2' → không xử lý; ghi log vào BPS_Audit_Log (Exc-1).
  • Form Dashboard được gửi bởi trader W-2 (nút lẽ ra phải bị ẩn — defence in depth) → từ chối; không thay đổi trạng thái.

(Nguồn: CR-20261027-001; Zapier Integration V7.pdf §Flow 13 — "Path Router" line 1951)


4. Luồng cơ bản

Path A — USA W-2 Paid DTO

Bước A-1. Nhận webhook duyệt từ Rippling

  • Zapier nhận webhook Rippling Time Off Request Approved (§2.1).
  • Ánh xạ Rippling worker sang user_id; áp dụng cổng vào (Current_Level >= 6) và guard W-2 (§3). Thất bại → Exc-1.
  • Dedup trên Rippling Request ID — webhook được gửi lại không được gia hạn stagnation_deadline hai lần.
  • Không có DTO Balance Check và không có lời gọi Rippling API nào từ Stack Trading. Rippling sở hữu số dư DTO và việc duyệt; Flow 13 chỉ xử lý các yêu cầu đã được duyệt. Requested_Days = số ngày được duyệt từ payload.

(Nguồn: QnA_STAGE2_SETTINGS_CAREER_VIRAL.md [HR-DEF-01] — yêu cầu PTO, số dư và việc duyệt do Rippling sở hữu)

Bước A-1.5. Chờ đến ngày bắt đầu nghỉ

  • Hôm nay < leave_start_date: Zap tạm dừng với delay_until = leave_start_date (lấy từ payload Rippling) và tiếp tục Bước A-3 vào ngày đó. Trước ngày đó trader giao dịch bình thường; trader_status không đổi.
  • Hôm nay ≥ leave_start_date: tiếp tục ngay — webhook đến trễ được xử lý theo Exc-2 (Trường hợp 1 / Trường hợp 2).
  • Bước A-2 (ledger Flow 35) và Bước A-5 (DTO_Approval_Notice) không bị trì hoãn — chạy ngay khi nhận webhook.

Bước A-2. PTO Ledger Sync (Flow 35 — song song, không thuộc Zap này)

  • Cùng webhook Rippling kích hoạt Flow 35 (UC_9.12), gọi POST /api/ledger/record với metric_category = "Corporate Benefits", metric_value = "[Days_Approved] Days PTO Approved (Paid Time Off)", receipt_hash = [Rippling Request ID].

(Nguồn: Zapier Integration V7.pdf §Flow 35 lines 2535–2548)

Bước A-3. Gia hạn Stagnation Deadline

  • Thực thi SQL update:
    UPDATE Users
    SET stagnation_deadline = stagnation_deadline + INTERVAL '[Requested_Days] days'
    WHERE user_id = [trader_id];
  • Việc này đảm bảo Flow 12 (Zombie Protocol) và Flow 19 (Stagnation Monitor) không phạt trader vì không hoạt động trong thời gian nghỉ phép đã được duyệt.

(Nguồn: Zapier Integration V7.pdf §Flow 13 line 1961)

Bước A-3.5. Đóng toàn bộ vị thế đang mở

Trước khi khóa tài khoản, Middleware đóng toàn bộ lệnh / vị thế đang mở của trader. Việc khóa tài khoản ở Bước A-4 chỉ được thực thi sau khi tài khoản không còn vị thế đang mở.

(Nguồn: Zapier Integration V7.pdf §Flow 13 — "Disable Trading Account via Middleware (Lock)")

Bước A-4. Khóa tài khoản giao dịch

  • Gọi POST /system/set-account-state:
    { "user_id": "[trader_id]", "state": "Locked", "context": "DTO" }
  • Middleware gửi các lệnh khóa theo từng nền tảng sau khi xác nhận tài khoản đã flat (Bước A-3.5):
    • Rithmic: R|API+ Suspend Trading.
    • MT5: YourBourse Contest Stop Out Plugin API (POST) — đặt tài khoản ở chế độ Read-Only; đóng băng giá trị Target Profit / Stop Loss trong RAM.
    • TraderEvolution: Admin API — đặt tài khoản ở Lock/Read-Only.
  • Ghi DB sau gateway (chỉ thực thi sau khi nhận HTTP 200 từ tất cả gateway đang hoạt động):
    • trader_status = 'On_Leave'
    • is_professional = TRUE (nếu trader dùng DMA)
    • stagnation_deadline đã được cập nhật ở Bước A-3

(Nguồn: Zapier Integration V7.pdf §Flow 13 line 1961; §POST /system/set-account-state lines 136–140; Supplement §3.2)

Bước A-5. Thông báo cho trader

  • Gửi ngay khi nhận webhook (không bị trì hoãn bởi Bước A-1.5). Gửi email DTO_Approval_Notice qua AWS SES xác nhận duyệt nghỉ phép, ngày bắt đầu và ngày dự kiến quay lại.
  • Thông báo Discord: Đẩy thông báo trạng thái nghỉ phép vào Redis memory queue. Zapier/Bot gom batch các message từ queue (tối đa 5 message / 5 giây) trước khi gửi tới Discord để tránh vi phạm rate-limit.

(Nguồn: Zapier Integration V7.pdf §Flow 13 line 1963; Supplement §3.4)


Path B — International Contractor Unpaid Hiatus

Bước B-1. Validation

  • Không áp dụng giới hạn số ngày DTO. Tiếp tục ngay mà không kiểm tra số dư.

(Nguồn: Zapier Integration V7.pdf §Flow 13 line 1965)

Bước B-2. Tạm ngưng Retainer Dots

  • Retainer hằng tháng của International Contractor được quản lý bởi một cron job của Middleware (Node.js, chạy hằng tháng) gọi Dots payout API. Đây KHÔNG phải một bước Zapier và không thể tạm dừng qua Zapier.
  • Bản thân Dots API không có endpoint "suspend retainer" native — Dots chỉ xử lý các yêu cầu payout riêng lẻ theo yêu cầu.
  • Cơ chế: Middleware đặt một DB flag (ví dụ is_retainer_paused = TRUE) trên bản ghi Users của trader. Cron retainer hằng tháng kiểm tra flag này trước khi gọi Dots POST /payees và bỏ qua mọi bản ghi có flag được đặt.
  • Tên field chính xác là quyết định triển khai của dev; yêu cầu nghiệp vụ là: không có khoản thanh toán retainer nào được gửi tới Dots trong khi trader đang tạm ngưng.
  • Khi quay lại (Bước R-3), Middleware xóa flag (is_retainer_paused = FALSE) để tiếp tục thanh toán hằng tháng bình thường.

(Nguồn: Zapier Integration V7.pdf §Flow 13 lines 1966–1968; §Flow 6 line 1635 — "Update the recurring backend trigger for the new Dots monthly retainer"; khách hàng xác nhận 2026-08-21)

Bước B-3. Gia hạn Stagnation Deadline

  • Cùng SQL update như Path A Bước A-3: gia hạn stagnation_deadline thêm Requested_Days.

(Nguồn: Zapier Integration V7.pdf §Flow 13 line 1969)

Bước B-3.5. Đóng toàn bộ vị thế đang mở

  • Giống Path A Bước A-3.5: đóng toàn bộ lệnh / vị thế đang mở.
  • Việc khóa tài khoản ở Bước B-4 chỉ được thực thi sau khi tài khoản không còn vị thế đang mở.

(Nguồn: Zapier Integration V7.pdf §Flow 13 — "Disable Trading Account via Middleware (Lock)")

Bước B-4. Khóa tài khoản giao dịch

  • Gọi POST /system/set-account-state:
    { "user_id": "[trader_id]", "state": "Locked", "context": "Hiatus" }
  • Middleware gửi các lệnh khóa theo từng nền tảng sau khi xác nhận tài khoản đã flat (Bước B-3.5):
    • Rithmic: R|API+ Suspend Trading.
    • MT5: YourBourse Contest Stop Out Plugin API (POST) — đặt tài khoản ở chế độ Read-Only; đóng băng Target Profit / Stop Loss trong RAM.
    • TraderEvolution: Admin API — đặt tài khoản ở Lock/Read-Only.
  • Ghi DB sau gateway (sau khi nhận HTTP 200 từ tất cả gateway đang hoạt động):
    • trader_status = 'On_Leave'
    • is_professional = TRUE (nếu trader dùng DMA)
    • stagnation_deadline đã được cập nhật ở Bước B-3

(Nguồn: Zapier Integration V7.pdf §Flow 13 line 1970; Supplement §3.2)

Bước B-5. Thông báo cho trader

  • Gửi email DTO_Approval_Notice qua AWS SES.
  • Thông báo Discord: Đẩy thông báo trạng thái nghỉ phép vào Redis memory queue. Zapier/Bot gom batch (tối đa 5 message / 5 giây) trước khi gửi tới Discord.

(Nguồn: Zapier Integration V7.pdf §Flow 13 line 1972; Supplement §3.4)


Return Protocol (áp dụng cho cả hai Path)

Trigger: Zap Flow 13 gốc (chính Zap đã xử lý việc duyệt nghỉ phép) tiếp tục thực thi thông qua action delay_until của Zapier được đặt theo DTO/Hiatus End Date — Path A: ngày kết thúc nghỉ từ payload webhook Rippling; Path B: End Date từ form Dashboard. Đây KHÔNG phải một backend cron job riêng — Zap tạm dừng giữa chừng tại thời điểm duyệt nghỉ phép và tự động tiếp tục vào ngày kết thúc đã chỉ định.

(Nguồn: Zapier Integration V7.pdf §Flow 13; khách hàng xác nhận 2026-08-22)

Mô hình sở hữu:

  • Zapier chịu trách nhiệm: timer delay_until, điều khiển luồng và trình tự các bước sau khi tiếp tục, logic kiểm tra flag/database, và điều hướng thông báo DTO_Welcome_Back.
  • Middleware chịu trách nhiệm: thực thi Safety Check (truy vấn bảng Users và blacklist trong PostgreSQL), gọi POST /system/set-account-state khi vượt qua check sạch, đẩy lệnh Restore Trading trực tiếp tới broker server (Rithmic / MT5 / TraderEvolution), và tiếp tục trigger retainer Dots (Path B).

Bước R-1. Safety Check

  • Middleware truy vấn PostgreSQL theo user_id. Compliance_Flagged không phải là một field được lưu trữ — nó được đánh giá từ dữ liệu sẵn có:
    • NẾU bất kỳ điều kiện nào sau đây đúng:
      1. Email của user có một dòng khớp trong bảng blacklist (blacklist.email = Users.email AND blacklist.is_active = TRUE — cùng cách kiểm tra như UC_2.6.2 Blacklist Check);
      2. Users.status ∈ {Banned_Chargeback, Failed, Terminated};
      3. Users.payout_status ≠ 'Approved' (ví dụ Hold / Flagged được đặt bởi BPS Apply Payout Hold, webhook payout-profile của Dots, hoặc dispute hold của trader Live ở Flow 14).
      • DỪNG toàn bộ việc kích hoạt lại. KHÔNG mở khóa tài khoản giao dịch. KHÔNG tiếp tục thanh toán.
      • Gửi cảnh báo Slack ngay lập tức cho Head of Ops để review thủ công.
      • Kết thúc luồng.
    • NGƯỢC LẠI: Tiếp tục sang Bước R-2.

(Nguồn: Zapier Integration V7.pdf §Flow 13 lines 1974–1977; khách hàng xác nhận 2026-08-22; QnA_BACKGROUND_MECHANISMS_CRON.md [BG-005] [BG-006] [BG-007] — bảng tính khách hàng 2026-11-04; schema blacklist theo UC_2.6.2 / CHR-17)

Bước R-2. Kích hoạt lại tài khoản giao dịch

  • Middleware gọi POST /system/set-account-state:
    { "user_id": "[trader_id]", "state": "Active", "context": "DTO_Return" }
  • Middleware đọc Current_Level hiện tại của trader từ PostgreSQL tại thời điểm này (không phải level tại thời điểm duyệt nghỉ phép — việc bị hạ cấp trong thời gian nghỉ được phản ánh tại đây).
  • Sau đó Middleware đẩy lệnh Restore Trading tới nền tảng thực thi của broker với các tham số rủi ro tương ứng với level hiện tại của trader: Rithmic 'Enable Trading' / MT5 'Enable' / TraderEvolution tương đương — bao gồm Notional, Daily Loss Limit và Level Stop chính xác cho Current_Level tại thời điểm quay lại.

(Nguồn: Zapier Integration V7.pdf §Flow 13 line 1978; khách hàng xác nhận 2026-08-22, 2026-09-09)

Bước R-3. Tiếp tục Retainer (chỉ Path B)

  • Middleware tiếp tục trigger payout retainer Dots định kỳ đã lên lịch (xóa is_retainer_paused = FALSE).
  • Flow 36 (Retainer Execution — Ledger Sync) kích hoạt ở chu kỳ thanh toán retainer kế tiếp và ghi bút toán Sổ cái Bất biến (Immutable Ledger).
  • Nếu trader bị hạ cấp trong thời gian nghỉ: retainer tiếp tục theo mức retainer tương ứng với Current_Level hiện tại (thấp hơn) của họ, không phải level tại thời điểm duyệt nghỉ phép.

(Nguồn: Zapier Integration V7.pdf §Flow 13 line 1980; khách hàng xác nhận 2026-08-22, 2026-09-09)

Bước R-4. Thông báo cho trader

  • Gửi mail DTO_Welcome_Back qua AWS SES.

(Nguồn: Zapier Integration V7.pdf §Flow 13 line 1982)


4.1 Trường hợp đặc biệt: Xử lý Pod Leader & Founding Mentor (Level 7+)

Mục này điều chỉnh mọi hành vi trường hợp đặc biệt chỉ áp dụng khi Trader có is_pod_leader = TRUE hoặc role_flag = 'Founding_Mentor'.

4.1.1 Failsafe Anti-Termination Gate

Trước khi thực thi bất kỳ hành động nghỉ phép nào (Bước A-1/B-1), Middleware PHẢI kiểm tra role flag:

IF users.is_pod_leader = TRUE OR users.role_flag = 'Founding_Mentor':
  → MUST block: do NOT fire POD_LEADER_TERMINATED webhook
  → MUST NOT invoke Flow 15C (offboarding cascade)
  → Proceed with leave processing (soft-lock, stagnation extension, etc.)
ELSE:
  → Standard Trader flow

Các hành động bị chặn trong thời gian nghỉ (áp dụng cho cả hai trigger):

  • Webhook POD_LEADER_TERMINATED: không bao giờ được kích hoạt
  • Flow 15C (giải thể Pod, tịch thu carry, offboarding Discord/Workspace): không bao giờ được gọi
  • Việc zero hóa Pending_Carry_Balance: không bao giờ được thực thi
  • Xóa/tạm ngưng Google Workspace: không bao giờ được kích hoạt
  • Lưu trữ kênh Discord / thu hồi Role: không bao giờ được kích hoạt

(Nguồn: QnA_STAGE6_POD_SYSTEM_FLOW10_11.md [POD-XF-15] — khách hàng xác nhận 2026-10-30: nghỉ phép đã duyệt là nghỉ tạm thời, KHÔNG phải Drawdown Defense (Flow 4B) hay Termination (Flow 15C))

4.1.2 Tài nguyên được giữ nguyên trong On_Leave
Tài nguyênActiveOn_LeaveTerminated (Flow 15C)
Tài khoản giao dịchActiveLocked (giống mọi Trader)Disabled
Google Workspace @stacktrading.comActiveActive — được giữ nguyên (vẫn tiếp tục nhận Wednesday AI Brief)Bị xóa / tạm ngưng
Pod_Leader_Registry.StatusActiveOn_Leave — xem §4.1.4Terminated
Kênh Discord pod-[leader_name]ActiveActive — không bị lưu trữĐã lưu trữ
Discord Role Pod LeaderĐã gánĐã gán — được giữ nguyênBị thu hồi
Pod_Leader_Registry.Pending_Carry_BalanceĐang tích lũy / vestingĐang tích lũy / vesting — không thay đổiBị tịch thu ($0.00)
Danh sách mentee của PodLiên kết với pod_idĐược giữ nguyên — không phân công lạiBị phân tán (Flow 15C)

Lưu ý về Founding Mentor: theo BR_9.2.19 và quy tắc Defense Bypass, tài khoản giao dịch của họ VẪN bị khóa trong On_Leave — ngoại lệ Founding Mentor chỉ bao phủ Administrative Roles (Pod/Discord), không bao phủ việc khóa tài khoản giao dịch.

(Nguồn: QnA_STAGE6_POD_SYSTEM_FLOW10_11.md [POD-XF-15], [POD-XF-16] — khách hàng xác nhận 2026-10-30; RFQ_ Stack Trading Prop Tech V7.pdf §Founding Mentor Defense Bypass)

4.1.3 Hành vi của Carry Balance

Pending_Carry_Balance tiếp tục tích lũy và vest bình thường trong thời gian nghỉ phép đã được duyệt. Lần chạy vest hằng tháng (Flow 17, ngày 1 hằng tháng) PHẢI bao gồm các Pod Leader có Pod_Leader_Registry.Status = 'On_Leave' — không đóng băng, không bỏ qua. Áp dụng như nhau cho Pod Leader thông thường và Founding Mentor. Carry chỉ bị đóng băng hoặc tịch thu khi bị tạm ngưng do Drawdown Defense hoặc Termination (Flow 15C).

Các khoản thanh toán khác trong thời gian nghỉ: lương cơ bản W-2 (Path A) tiếp tục qua payroll Rippling; retainer International (Path B) bị tạm ngưng (Bước B-2) và được tiếp tục ở R-3; các khoản payout hiệu suất giao dịch (Flow 5) đạt được trước kỳ nghỉ được xử lý bình thường — không thể đạt target mới trong khi tài khoản đang bị khóa.

(Nguồn: QnA_BACKGROUND_MECHANISMS_CRON.md [BG-008] [BG-009]; QnA_STAGE6_POD_SYSTEM_FLOW10_11.md [POD-XF-18] — bảng tính khách hàng 2026-11-04)

4.1.4 Pod_Leader_Registry Status trong thời gian nghỉ
  • Tại Bước A-4 / B-4 (sau khi khóa gateway thành công), Middleware đặt Pod_Leader_Registry.Status = 'On_Leave' cho leader.
  • Việc ghép cặp ở Flow 10 chỉ chọn Status == 'Active' [POD-JOIN-19] → leader ở On_Leave tự động bị loại khỏi việc ghép mentee mới. Việc này KHÔNG kích hoạt logic giải thể pod Suspended của Flow 15A.
  • Tại Bước R-2 của Return Protocol (khi kích hoạt lại thành công), Middleware đặt Pod_Leader_Registry.Status = 'Active'.

(Nguồn: QnA_STAGE6_POD_SYSTEM_FLOW10_11.md [POD-XF-16] — khách hàng xác nhận 2026-10-30)

4.1.5 SLA của Pod trong thời gian nghỉ

Các timer SLA của Pod được tạm dừng trong khi leader đang nghỉ — không có Acting Cover, không ghép lại mentee:

  • Cron SLA Enforcement của Flow 10.2 loại trừ các user ở Inactive_Hold (Flow 12) hoặc bị Locked do DTO/Hiatus (Flow 13) [POD-SLA-08].
  • Daily Engagement Audit của Flow 10.5 loại trừ các leader bị Locked do DTO/Hiatus [POD-AUDIT-10].
  • Calendar Compliance Auditor của Flow 10.1B: leader đang DTO/Hiatus được miễn [POD-DISP-08].

(Nguồn: QnA_STAGE6_POD_SYSTEM_FLOW10_11.md [POD-XF-17] — khách hàng xác nhận 2026-10-30)


5. Điều kiện tiên quyết

IDĐiều kiện tiên quyết
P1Path A: Rippling đã duyệt yêu cầu nghỉ phép của trader và phát webhook Time Off Request Approved. Path B: International Contractor gửi form "Request Time Off" trên Dashboard.
P2Current_Level >= 6 trong bảng Users.
P3account_status của trader là 'Active_DMA' (chưa bị Locked, Terminated hoặc Banned). Level lưu ở current_level.
P4Với Path A: Bản ghi Rippling worker tồn tại và được liên kết với user_id của trader; Employment_Type = 'W-2'.
P5Với Path B: Lịch retainer Dots đang hoạt động cho trader này.

6. Hậu điều kiện

Kết quảHậu điều kiện
Path A được xử lýstagnation_deadline được gia hạn; tài khoản giao dịch Locked; DTO_Approval_Notice đã gửi. (Kỳ nghỉ đã được ghi nhận/duyệt trong Rippling; Flow 35 ghi bút toán sổ cái.)
Path B được xử lýstagnation_deadline được gia hạn; tài khoản giao dịch Locked; retainer Dots bị tạm ngưng; DTO_Approval_Notice đã gửi.
Bị từ chối (cổng Level)Không thay đổi trạng thái.
Bị từ chối (hết DTO)Path A: được xử lý trong Rippling — không duyệt, không webhook, Flow 13 không được kích hoạt. Path B: N/A (không giới hạn ngày).
Quay lại — sạchTài khoản giao dịch được kích hoạt lại; retainer Dots được tiếp tục (Path B); DTO_Welcome_Back đã gửi.
Quay lại — Safety Check thất bạiTài khoản vẫn Locked; Head of Ops được cảnh báo; không kích hoạt lại tự động.

7. Luồng thay thế

Alt-1 — Số dư DTO đã hết (Path A):

  • Được xử lý hoàn toàn bên trong Rippling (policy Rippling do Ops cấu hình theo DTO_Days, Table A/B). Yêu cầu bị từ chối không bao giờ tạo webhook Time Off Request Approved — Flow 13 không được kích hoạt. Xem Q-1.

Alt-3 — Lần nghỉ phép thứ hai được duyệt trong Rippling khi trader đang nghỉ (Path A):

  • Mỗi webhook duyệt bổ sung của Rippling (Rippling Request ID mới) gia hạn stagnation_deadline thêm số ngày vừa được duyệt và cập nhật DTO_Hiatus_End_Date.
  • Việc gọi lại POST /system/set-account-state với state = "Locked" là idempotent (chống trùng lặp) — tài khoản đã bị khóa, không tạo flag lồng nhau hoặc khóa trùng lặp.
  • Việc thực thi hạn mức là trách nhiệm của Rippling (Stack Trading không kiểm tra lại số dư).

Alt-4 — Yêu cầu tạm ngưng thứ hai được gửi khi trader đang nghỉ (Path B):

  • Không có giới hạn ngày cho International Contractor. Luôn duyệt — gia hạn stagnation_deadline thêm Requested_Days bổ sung. Việc tạm ngưng lại retainer Dots (is_retainer_paused = TRUE) là idempotent — flag đã được đặt, không thay đổi.
  • Return Protocol (Zapier delay_until) theo dõi DTO_Hiatus_End_Date đã cập nhật. Chỉ có một lần thực thi Return Protocol vào ngày kết thúc đã gia hạn cuối cùng.

(Nguồn: Zapier Integration V7.pdf pp. 21, 228-230, 392-394; khách hàng xác nhận 2026-09-09)

Alt-2 — Ngày quay lại của trader đến trong khi các flag Safety Check đang được đặt:

  • Flow tự động kích hoạt Return Protocol vào ngày kết thúc đã lên lịch.
  • Safety Check phát hiện flag → HALT. Tài khoản vẫn Locked vô thời hạn cho đến khi Ops giải quyết thủ công và kích hoạt lại.
  • Đường kích hoạt lại thủ công: Ops gọi POST /system/set-account-state với state = "Active" sau khi giải quyết vấn đề compliance/chargeback — phải được thực thi qua BPS Admin Console (áp dụng cổng RBAC Level_2+/Admin, bắt buộc có reason + transcript_url, ghi log vào BPS_Audit_Log). Bản thân endpoint không có gate; Console là điểm thực thi RBAC (xem BR_9.2.12). (Nguồn: RFQ_ Stack Trading Prop Tech V7.pdf §BPS Endpoints lines 2721–2867; khách hàng xác nhận 2026-08-27)

Alt-5 — Trader W-2 hủy hoặc rút ngắn PTO đã duyệt trong Rippling (Path A):

  • Không tự động tính lại. Gửi cảnh báo Slack tới #ops-general (hoặc tạo ticket Freshdesk) để Ops kiểm tra thủ công, kích hoạt lại tài khoản giao dịch và điều chỉnh stagnation_deadline nếu cần.
  • Không có bút toán ledger điều chỉnh (Flow 35).
  • Nếu PTO bị hủy trước leave_start_date, Zap đang chờ (Bước A-1.5) vẫn sẽ khóa tài khoản vào ngày đó — Ops phải hủy lượt Zap đang chờ hoặc mở khóa tài khoản thủ công.

(Nguồn: QnA_BACKGROUND_MECHANISMS_CRON.md [BG-002], [BG-017] — bảng tính khách hàng 2026-11-04)


8. Luồng ngoại lệ

Exc-1 — Webhook Rippling không qua cổng vào / guard (Path A, Bước A-1):

  • Worker không thể ánh xạ sang user_id, Current_Level < 6, hoặc Employment_Type != 'W-2'.
  • Không gia hạn stagnation_deadline; không khóa. Ghi log vào BPS_Audit_Log để Ops review. Không thông báo cho trader.

Exc-2 — Webhook Rippling đến sau ngày bắt đầu nghỉ (Path A):

  • Trường hợp 1 — Hôm nay nằm giữa leave_start_date và leave_end_date: khóa ngay cho phần còn lại của kỳ nghỉ; gia hạn stagnation_deadline thêm đủ Requested_Days đã duyệt; gửi thông báo Slack thường lệ tới #ops-general ghi nhận việc duyệt muộn.
  • Trường hợp 2 — Hôm nay đã qua leave_end_date: KHÔNG khóa; Flow 35 vẫn ghi PTO vào ledger; gia hạn stagnation_deadline thêm số ngày đã duyệt; gửi thông báo Slack thường lệ tới #ops-general. Không lên lịch Return Protocol.

(Nguồn: QnA_BACKGROUND_MECHANISMS_CRON.md [BG-003] — bảng tính khách hàng 2026-11-04)

Exc-3 — Lời gọi POST /system/set-account-state thất bại HOẶC execution gateway API trả về lỗi/timeout:

  • Tài khoản giao dịch KHÔNG bị khóa như mong đợi. Rủi ro cao: trader có thể tiếp tục giao dịch trong thời gian nghỉ.
  • Xử lý lỗi gateway: Middleware retry tối đa 3 lần với exponential backoff. Nếu hết retry → ghi log vào BPS_Audit_Log + gửi cảnh báo Slack SEV-1 tới Ops (#ops-it) để khóa thủ công. (Nguồn: Zapier Integration V7.pdf §Flow 13)

Exc-4 — Việc gửi cảnh báo Safety Check thất bại (thông báo Head of Ops):

  • Bản thân quyết định HALT vẫn có hiệu lực — không kích hoạt lại tài khoản trong mọi trường hợp.
  • Ghi log lỗi gửi cảnh báo. Điều hướng sang kênh cảnh báo phụ (ví dụ: ticket Freshdesk, email dự phòng).

Exc-5 — Trader có Luồng 14 (Payment Dispute / Chargeback) đang hoạt động trong khi nghỉ phép:

  • Nếu một dispute được tạo khi trader_status = 'On_Leave', trạng thái dispute có mức ưu tiên cao hơn On_Leave: trader SIM → Users.status = 'Banned_Chargeback'; trader Live → dispute hold đặt Users.payout_status ≠ 'Approved'.
  • Tài khoản KHÔNG ĐƯỢC tự động kích hoạt lại vào Return_Date đã lên lịch cho đến khi Admin giải quyết dispute thủ công.
  • Safety Check (Bước R-1) bắt cả hai trường hợp (điều kiện 2 và 3) và dừng việc quay lại — ngoại lệ này ghi lại kịch bản dispute phát sinh giữa kỳ nghỉ để việc thiết lập dữ liệu test được rõ ràng.

(Nguồn: QnA_BACKGROUND_MECHANISMS_CRON.md [BG-005] [BG-006] — bảng tính khách hàng 2026-11-04)


9. Quy tắc nghiệp vụ

Rule IDQuy tắcNguồn
BR_9.2.1Chỉ trader có Current_Level >= 6 mới được gửi yêu cầu nghỉ phép hoặc tạm ngưng. Yêu cầu từ level thấp hơn bị từ chối mà không tạo bất kỳ thay đổi trạng thái nào.Zapier Integration V7.pdf §Flow 13
BR_9.2.2Việc điều hướng path được xác định bởi kênh trigger: webhook Rippling Time Off Request Approved → Path A (USA W-2 Paid DTO); form "Request Time Off" trên Dashboard → Path B (International Contractor Unpaid Hiatus qua Dots). Quốc gia đã xác minh KYC (được ưu tiên hơn billing_country theo CR-20260812-005) và Employment_Type chỉ được dùng làm guard kiểm tra nhất quán.CR-20261027-001; CR-20260812-005
BR_9.2.3Hạn mức DTO_Days được lấy từ Table A (Futures) hoặc Table B (Forex) theo Current_Level của trader. Hạn mức được thực thi bên trong Rippling (time-off policy do Ops cấu hình); Stack Trading không kiểm tra Used_DTO và chỉ xử lý các yêu cầu Rippling đã duyệt.Zapier Integration V7.pdf §Table A / Table B; CR-20261027-001
BR_9.2.4stagnation_deadline PHẢI được gia hạn thêm Requested_Days cho cả hai path. Điều này ngăn Flow 12 (Zombie Protocol) và Flow 19 (Stagnation Monitor) phạt trader trong thời gian nghỉ phép đã được duyệt.Zapier Integration V7.pdf §Flow 13; ngày lịch, không tính theo ngày làm việc — QnA [BG-004] bảng tính khách hàng 2026-11-04
BR_9.2.5Tài khoản giao dịch PHẢI được khóa qua POST /system/set-account-state (state = "Locked"). Path A: khóa vào leave_start_date đã đăng ký trên Rippling (Bước A-1.5). Path B: khóa khi gửi form. Việc khóa phải được thực thi ở cấp nền tảng thực thi (Rithmic Suspend Trading hoặc MT5 Disable/Read-Only).Zapier Integration V7.pdf §Flow 13; §POST /system/set-account-state
BR_9.2.6Với Path B, khoản thanh toán định kỳ retainer Dots PHẢI được tạm ngưng khi duyệt nghỉ phép và tiếp tục khi quay lại thành công. Cơ chế: Middleware đặt một DB flag (ví dụ is_retainer_paused = TRUE) trên bản ghi Users của trader; cron retainer hằng tháng bỏ qua các bản ghi có flag này được đặt trước khi gọi Dots POST /payees. Bản thân Dots API không có endpoint suspend native — cron job hoàn toàn do Middleware sở hữu. Khi quay lại, flag được xóa để tiếp tục thanh toán bình thường. Tên field là quyết định triển khai.Zapier Integration V7.pdf §Flow 13 lines 1966–1968; §Flow 6 line 1635; khách hàng xác nhận 2026-08-21
BR_9.2.7Safety Check của Return Protocol PHẢI chạy trước mọi hành động kích hoạt lại. Nếu bất kỳ điều kiện nào của Bước R-1 đúng (khớp blacklist theo email với is_active = TRUE; Users.status ∈ {Banned_Chargeback, Failed, Terminated}; Users.payout_status ≠ 'Approved'), tài khoản PHẢI giữ nguyên trạng thái khóa và Head of Ops PHẢI được thông báo. Không có kích hoạt lại tự động trong trạng thái này. Việc kích hoạt lại thủ công bởi Ops qua POST /system/set-account-state yêu cầu Admin JWT (vai trò Level_2 hoặc Admin) — được thực thi ở tầng trước, tại tầng BPS Admin Console, không phải bởi bản thân endpoint (xem BR_9.2.12). Mọi hành động đều ghi log vào BPS_Audit_Log.Zapier Integration V7.pdf §Flow 13 lines 1974–1977; RFQ_ Stack Trading Prop Tech V7.pdf §BPS Endpoints lines 2721–2867; khách hàng xác nhận 2026-08-27; QnA [BG-006] [BG-007] bảng tính khách hàng 2026-11-04
BR_9.2.8Quét hằng ngày của Flow 12 (Zombie Protocol) dùng last_trade_date < (Today - 30). Trader đang nghỉ phép đã được duyệt sẽ có stagnation_deadline được gia hạn (BR_9.2.4), bảo vệ họ khỏi Flow 19 (Stagnation Monitor). Flow 12 KHÔNG bypass đối với trader ở trạng thái nghỉ phép — đây là hành vi đã được xác nhận. Nếu last_trade_date của trader vượt quá 30 ngày (bao gồm cả những ngày nghỉ phép đã duyệt), Flow 12 sẽ kích hoạt và vô hiệu hóa market data như bình thường. Việc gia hạn stagnation_deadline (BR_9.2.4) chỉ bảo vệ khỏi việc chấm dứt của Flow 19 — không ngăn Flow 12. Những ngày nghỉ KHÔNG bị trừ khỏi bộ đếm không hoạt động 30 ngày của Zombie Protocol. Trader nghỉ phép dài ngày cần biết rằng market data có thể bị Flow 12 vô hiệu hóa trong thời gian vắng mặt.Zapier Integration V7.pdf §Flow 12; §Flow 13; khách hàng xác nhận 2026-08-22
BR_9.2.9Đồng bộ Sổ cái Bất biến (Immutable Ledger) cho PTO (Flow 35) tự động kích hoạt từ webhook duyệt của Rippling — cùng một webhook kích hoạt Flow 13 Path A. Flow 35 là một Zap tách biệt và ghi log: metric_category = "Corporate Benefits", metric_value = "[Days_Approved] Days PTO Approved (Paid Time Off)", receipt_hash = [Rippling Request ID].Zapier Integration V7.pdf §Flow 35
BR_9.2.10Return Protocol được kích hoạt bởi action delay_until của Zapier trong Zap Flow 13 gốc — KHÔNG phải một backend cron job hoặc webhook theo lịch riêng. Zap tạm dừng giữa chừng tại thời điểm duyệt nghỉ phép và tự động tiếp tục vào DTO/Hiatus End Date. Việc thực thi Return Protocol được đồng sở hữu: Zapier xử lý orchestration, điều khiển luồng và thông báo DTO_Welcome_Back; Middleware thực thi Safety Check, gọi POST /system/set-account-state, đẩy lệnh Restore Trading tới broker server (Rithmic / MT5 / TraderEvolution), và tiếp tục trigger retainer Dots (Path B).Zapier Integration V7.pdf §Flow 13; khách hàng xác nhận 2026-08-22
BR_9.2.11Kênh yêu cầu theo loại trader. Trader USA W-2 yêu cầu nghỉ phép ngay trong Rippling — Dashboard không được cung cấp UI yêu cầu nghỉ phép cho W-2 (Career & HR Widget chỉ hiển thị "View in Rippling"). International Contractor L6+ yêu cầu qua form "Request Time Off" native trên Dashboard (không phải công cụ bên thứ ba); khi Send, Dashboard gửi một JSON webhook tới catch-hook của Zapier với user_id (hoặc email đã đăng ký), Start_Date, DTO_Hiatus_End_Date, Requested_Days, Reason.CR-20261027-001; QnA [HR-DEF-01]; khách hàng xác nhận 2026-08-27
BR_9.2.12POST /system/set-account-state là một endpoint hệ thống nội bộ — nó KHÔNG tự thực thi cổng Human RBAC. Endpoint được thiết kế để Zapier automation bus và background worker gọi mà không cần ủy quyền JWT cho từng lời gọi. Human RBAC được thực thi ở tầng trước tại tầng BPS Admin Console: yêu cầu vai trò Level_2+ hoặc Admin để gọi bất kỳ hành động thủ công nào của Ops; caller Level_1 nhận HTTP 403 Forbidden tại tầng Console trước khi lời gọi tới endpoint. Bảo mật cho machine caller (Zapier, background worker) được thực thi qua Zapier JWT Signature và cô lập mạng VPC/VPN. Ops thủ công luôn phải đi qua BPS Admin Console, nơi áp dụng cổng RBAC, bắt buộc các trường reason + transcript_url, và ghi vào BPS_Audit_Log. Sau đó BPS Admin Console mới gọi xuống POST /system/set-account-state chỉ khi kiểm tra RBAC đã qua.RFQ_ Stack Trading Prop Tech V7.pdf §BPS Endpoints lines 2721–2867; khách hàng xác nhận 2026-08-27
BR_9.2.13Các yêu cầu nghỉ phép/tạm ngưng liên tiếp khi đã đang nghỉ được xử lý như gia hạn idempotent, không phải khóa chồng. Path A: mỗi lần duyệt bổ sung của Rippling (Rippling Request ID mới) gia hạn stagnation_deadline thêm số ngày vừa được duyệt; việc thực thi hạn mức là của Rippling (không kiểm tra lại). Webhook được gửi lại với cùng Rippling Request ID bị bỏ qua. Path B: luôn duyệt (không giới hạn ngày) → gia hạn stagnation_deadline. Ở cả hai path: việc gọi lại POST /system/set-account-state với state = "Locked" là idempotent (không có flag lồng nhau); flag retainer Dots (is_retainer_paused = TRUE) đã được đặt (idempotent). Return Protocol kích hoạt đúng một lần vào DTO_Hiatus_End_Date đã gia hạn cuối cùng.Zapier Integration V7.pdf pp. 21, 228-230, 392-394; khách hàng xác nhận 2026-09-09
BR_9.2.14Current_Level >= 6 chỉ là cổng vào — được kiểm tra khi nhận webhook Rippling (Path A) hoặc khi submit form (Path B), không kiểm tra khi quay lại. Cổng kích hoạt lại duy nhất của Return Protocol là Safety Check (Bước R-1: blacklist / Users.status / Users.payout_status). Nếu trader bị hạ xuống dưới Level 6 trong thời gian nghỉ, Return Protocol vẫn chạy bình thường vào ngày kết thúc đã lên lịch. Khi kích hoạt lại, Middleware đọc Current_Level hiện tại của trader từ PostgreSQL tại thời điểm đó và đẩy các tham số rủi ro (Notional, Daily Loss Limit, Level Stop) tương ứng với level bị hạ xuống broker gateway. Mọi tài khoản Live DMA từ Level 1-24 đều có account_status = 'Active_DMA' (enum cố định; level lưu ở current_level) — việc bị hạ cấp chỉ thay đổi current_level và không làm mất hiệu lực trạng thái tài khoản Live. Với Path B, retainer hằng tháng tiếp tục theo mức retainer của level bị hạ.Zapier Integration V7.pdf; khách hàng xác nhận 2026-09-09; khách hàng xác nhận 2026-09-14 (UC_5.8 BR_5.8.9)
BR_9.2.15Trước khi khóa tài khoản giao dịch (Bước A-4/B-4), Middleware PHẢI đóng toàn bộ lệnh / vị thế đang mở. Việc khóa Execution Gateway chỉ kích hoạt sau khi tài khoản không còn vị thế đang mở.Zapier Integration V7.pdf §Flow 13
BR_9.2.16Trình tự khóa Execution Gateway là: Rithmic — R|API+ Suspend Trading; MT5 — YourBourse Contest Stop Out Plugin API (POST) đặt tài khoản ở Read-Only và đóng băng Target Profit / Stop Loss trong RAM; TraderEvolution — Admin API đặt tài khoản ở Lock/Read-Only. Cả ba lời gọi gateway PHẢI thành công (HTTP 200) trước khi thực thi các lệnh ghi DB sau gateway.Supplement §3.2
BR_9.2.17Các lệnh ghi DB được sắp xếp tuần tự sau khi gateway xác nhận. Các field sau chỉ được ghi vào bảng Users sau khi nhận HTTP 200 từ tất cả broker gateway đang hoạt động: trader_status = 'On_Leave'; is_professional = TRUE (nếu trader dùng DMA). stagnation_deadline được gia hạn ở bước trước (A-3/B-3) — không phụ thuộc vào phản hồi gateway.Supplement §3.3
BR_9.2.18Thông báo trạng thái nghỉ phép trên Discord PHẢI được đẩy vào Redis memory queue thay vì gửi trực tiếp tới Discord. Zapier/Bot xả queue với mức giới hạn tối đa 5 message mỗi 5 giây trước khi gửi tới Discord, để ngăn vi phạm rate-limit trên nền tảng Discord.Supplement §3.4
BR_9.2.19Phạm vi ngoại lệ Founding Mentor: Flag Founding_Mentor chỉ bảo vệ Administrative Roles — cụ thể là miễn khỏi Digital Eviction (vai trò Pod Leader và kênh Discord Pod không bị gỡ khi tài khoản giao dịch bị khóa hoặc vi phạm). Flag này KHÔNG miễn tài khoản giao dịch khỏi việc bị khóa trong thời gian nghỉ phép hoặc Hard Breach. Trong các trạng thái On_Leave hoặc Banned_Chargeback, tài khoản giao dịch của Founding Mentor bị khóa và toàn bộ vị thế đang mở bị đóng, giống hệt như với mọi trader khác.Supplement §6 — BR 4
BR_9.2.20Form "Request Time Off" (Path B). Chỉ hiển thị cho International Contractor có Current_Level >= 6. Các trường theo thiết kế đã duyệt: Start Date (bắt buộc), End Date (bắt buộc, ≥ Start Date), Requested Days (chỉ đọc, tự động tính từ hai ngày), Reason (textarea); nút Send và nút Cancel (Cancel cần bổ sung vào thiết kế). Văn bản mô tả tĩnh được cố định như trong thiết kế đã duyệt.CR-20261027-001; References/Wireframe/Dashboard/Flow 13_Request Time Off modal (International).jpg
BR_9.2.21Thời điểm của Path A. Gia hạn stagnation_deadline (A-3), đóng vị thế đang mở (A-3.5), khóa tài khoản và trader_status = 'On_Leave' (A-4) cùng diễn ra vào leave_start_date trên Rippling. Từ lúc duyệt đến leave_start_date, trader giao dịch bình thường và chưa ở trạng thái On_Leave.§2.1; Bước A-1.5

10. Tiêu chí chấp nhận

IDKịch bảnKết quả mong đợi
AC-9.2-01Trader có Current_Level = 5 — International: không thấy nút "Request Time Off"; W-2: nhận webhook Rippling cho worker Level 5Không thay đổi DB. Không gửi email. Path A: chỉ có bản ghi audit log.
AC-9.2-02Trader USA W-2 (Current_Level = 6) yêu cầu 5 ngày trong Rippling; Rippling duyệt và gửi webhook Time Off Request ApprovedPath A: stagnation_deadline được gia hạn thêm 5 ngày; account_status = "Locked"; DTO_Approval_Notice đã gửi; Stack Trading không thực hiện lời gọi Rippling API nào.
AC-9.2-03Yêu cầu của trader USA W-2 bị từ chối bên trong Rippling (ví dụ hết DTO)Không có webhook; Flow 13 không được kích hoạt; không thay đổi trạng thái.
AC-9.2-04Trader International Contractor (Current_Level = 7) gửi form "Request Time Off" trên DashboardPath B: retainer Dots bị tạm ngưng; stagnation_deadline được gia hạn; tài khoản bị khóa; DTO_Approval_Notice đã gửi.
AC-9.2-05Đến ngày quay lại qua Zapier delay_until — trader sạch (không có flag)POST /system/set-account-state được gọi với state = "Active"; lệnh Restore Trading của broker được thực thi; DTO_Welcome_Back đã gửi; retainer Dots được tiếp tục (chỉ Path B).
AC-9.2-06Đến ngày quay lại qua Zapier delay_until — trader có Users.status = 'Banned_Chargeback'Tài khoản vẫn Locked. Không gửi DTO_Welcome_Back. Head of Ops được cảnh báo.
AC-9.2-07Đến ngày quay lại qua Zapier delay_until — trader có Users.payout_status = 'Hold' (BPS Apply Payout Hold)Giống AC-9.2-06.
AC-9.2-08Nhận webhook Rippling cho worker có Employment_Type != 'W-2' hoặc không ánh xạ được tới user_id nàoKhông được xử lý; không khóa; không thay đổi stagnation_deadline; ghi một bản ghi BPS_Audit_Log.
AC-9.2-09POST /system/set-account-state thất bại trong lúc duyệt nghỉ phépTài khoản KHÔNG bị khóa. Cảnh báo Slack SEV-1 tới Ops để khóa thủ công.
AC-9.2-10Flow 35 kích hoạt sau khi Rippling duyệt PTO cho trader Path APOST /api/ledger/record được gọi với metric_category = "Corporate Benefits", metric_value = "[Days_Approved] Days PTO Approved (Paid Time Off)".
AC-9.2-15Trader USA W-2 đang nghỉ được duyệt lần nghỉ thứ hai trong Rippling (Rippling Request ID mới)stagnation_deadline được gia hạn thêm số ngày vừa duyệt; DTO_Hiatus_End_Date được cập nhật; khóa tài khoản không đổi (idempotent).
AC-9.2-16Rippling gửi lại cùng webhook Time Off Request Approved (cùng Rippling Request ID)Bị bỏ qua — stagnation_deadline không bị gia hạn hai lần; khóa không đổi.
AC-9.2-17International Contractor đang tạm ngưng gửi yêu cầu tạm ngưng thứ haiYêu cầu được duyệt — stagnation_deadline được gia hạn thêm Requested_Days bổ sung; is_retainer_paused vẫn là TRUE (idempotent); khóa tài khoản không đổi; Return Protocol kích hoạt một lần vào DTO_Hiatus_End_Date đã gia hạn cuối cùng.
AC-9.2-18Trader là Level 7 lúc duyệt nghỉ phép; bị hạ xuống Level 4 trong thời gian nghỉ; đến ngày quay lại với Safety Check sạchTài khoản được kích hoạt lại: account_status = 'Active_DMA', current_level = 4; broker gateway được nạp tham số rủi ro Level 4 (Notional, Daily Loss Limit, Level Stop); retainer Path B tiếp tục theo mức retainer Level 4.
AC-9.2-19Trader là Level 7 lúc duyệt nghỉ phép; bị hạ xuống Level 4 trong thời gian nghỉ; đến ngày quay lại với Users.payout_status = 'Flagged'Return Protocol dừng tại Safety Check — tài khoản vẫn Locked; Head of Ops được cảnh báo; mức hạ cấp không liên quan (cổng là trạng thái flag, không phải Level).
AC-9.2-20International Contractor (Level 8) click "Request Time Off" trong Career & HR Widget, chọn Start Date + End Date (Requested Days tự động điền), nhập Reason, click SendModal đóng; payload (user_id, Start_Date, DTO_Hiatus_End_Date, Requested_Days, Reason) được gửi tới Zapier; flow tiến tới Path B.
AC-9.2-21International Contractor mở "Request Time Off" rồi click Cancel (hoặc đóng modal) mà không click SendKhông có webhook nào được gửi; không thay đổi trạng thái DB; trader giữ nguyên trạng thái hiện tại.
AC-9.2-22Path A/B được duyệt — trader có vị thế đang mởToàn bộ lệnh / vị thế đang mở được đóng; việc khóa execution gateway chỉ tiến hành sau khi tài khoản không còn vị thế đang mở.
AC-9.2-23Path A được duyệt — khóa execution gateway thành công (HTTP 200 tất cả gateway); các lệnh ghi DB thực thitrader_status = 'On_Leave'; is_professional = TRUE (nếu DMA) được ghi vào Users.
AC-9.2-24International Contractor (Path B, Live) — một dispute hold của Flow 14 được áp dụng giữa kỳ nghỉ; đến ngày quay lạiSafety Check bắt Users.payout_status ≠ 'Approved'; tài khoản vẫn Locked; Head of Ops được cảnh báo; không kích hoạt lại tự động cho đến khi Admin giải quyết dispute.
AC-9.2-25Trader W-2 (Level 8) mở Career & HR WidgetNút "Request Time Off" không được hiển thị; chỉ hiển thị CTA "View in Rippling".
AC-9.2-26International Contractor chọn End Date sớm hơn Start DateLỗi validation; Send không submit; Requested Days không được tính.
AC-9.2-27International Contractor chọn Start Date và End DateRequested Days hiển thị giá trị tự động tính (quy tắc tính theo Q-4).
AC-9.2-28Đến ngày quay lại; email của trader có một dòng đang hoạt động trong bảng blacklist (is_active = TRUE)Giống AC-9.2-06.
AC-9.2-29Webhook Rippling đến khi Hôm nay nằm giữa ngày bắt đầu và ngày kết thúc nghỉTài khoản bị khóa; stagnation_deadline + đủ Requested_Days; thông báo duyệt muộn trên Slack #ops-general.
AC-9.2-30Webhook Rippling đến sau leave_end_dateKhông khóa; stagnation_deadline được gia hạn; bút toán ledger Flow 35 được ghi; thông báo Slack #ops-general.
AC-9.2-31Pod Leader đang nghỉ phép đã duyệt; đến ngày 1 của thángFlow 17 vest Pending_Carry_Balance bình thường (không bỏ qua).
AC-9.2-32Webhook Rippling nhận ngày 01/12; leave_start_date = 10/12Trước 10/12: không khóa, stagnation_deadline không đổi, trader_status không đổi; DTO_Approval_Notice gửi ngày 01/12. Ngày 10/12: đóng vị thế, khóa tài khoản, gia hạn stagnation_deadline, trader_status = 'On_Leave'.
AC-9.2-33Giống AC-9.2-32, trader đặt lệnh ngày 05/12Lệnh được chấp nhận — tài khoản chưa bị khóa trước leave_start_date.
10.1 Câu hỏi mở (CR-20261027-001)
IDCâu hỏiGiả định hiện tại
Q-1Rippling có chặn các yêu cầu vượt DTO_Days (Table A/B) theo policy không, hay Middleware phải kiểm tra lại khi nhận webhook?Policy Rippling do Ops cấu hình; không kiểm tra lại.
Q-2Nếu trader W-2 hủy / rút ngắn kỳ nghỉ đã duyệt trong Rippling, có webhook không, và có nên mở khóa tài khoản sớm / giảm stagnation_deadline không?✅ Đã trả lời 2026-11-04 — xem Alt-5.
Q-3Webhook Rippling bị trễ quá ngày bắt đầu nghỉ → khóa muộn. Có cảnh báo Ops không?✅ Đã trả lời 2026-11-04 — xem Exc-2.
Q-4Form: Reason có bắt buộc không, độ dài tối đa? Requested Days = số ngày lịch tính cả hai đầu? Start Date có được ở quá khứ không? Ngoài nút Cancel (sẽ bổ sung), modal có đóng được qua X / click ra ngoài / Esc không?Reason tùy chọn ≤ 500 ký tự; ngày lịch tính cả hai đầu; Start Date ≥ hôm nay; đóng qua X / click ra ngoài / Esc.

11. Lịch sử thay đổi

NgàyPhiên bảnMục được cập nhậtTrướcSauLý do
2026-11-05v2.6 → v2.7Header; §2.2 modal (ảnh màn hình, dòng Cancel, ghi chú); §9 BR_9.2.20; §10 AC-9.2-21; §10.1 Q-4Chưa có ảnh màn hình; không có nút Cancel (đóng modal chỉ theo Q-4)Đã nhúng ảnh màn hình; cần bổ sung nút Cancel — đóng modal mà không gửiRà soát thiết kế 2026-11-05
2026-11-05v2.5 → v2.6Header; §2.1; §4 Bước A-1.5 (mới), Bước A-5; §7 Alt-5; §9 BR_9.2.5, BR_9.2.21 (mới); §10 AC-9.2-32/33 (mới)Path A khóa và gia hạn stagnation_deadline ngay khi nhận webhook duyệtCác bước của Path A bắt đầu vào leave_start_date trên Rippling (Zapier delay_until); email duyệt và Flow 35 vẫn chạy khi nhận webhook; Path B không đổiKỳ nghỉ bắt đầu vào ngày đã đăng ký trên Rippling
2026-11-05v2.4 → v2.5Header; §4 Bước A-3.5, B-3.5; §8 Exc-3; §9 BR_9.2.15, BR_9.2.19; §10 AC-9.2-22Thuật toán TRIM_TO_COMPLIANCE (sắp xếp theo kích thước, Market Close tuần tự, listener ExecutionReport, failsafe Hard Liquidation 2,000 ms) — nguồn "Supplement §3.1 / §7" (không có trong References)Đóng toàn bộ lệnh / vị thế đang mở trước khi khóa; chỉ khóa sau khi tài khoản không còn vị thế đang mở; không đặc tả thuật toánFlow 13 chỉ nêu việc đóng vị thế; Zapier Integration V7.pdf §Flow 13
2026-11-04v2.3 → v2.4Header; §1 (dòng Release); mô hình sở hữu Return Protocol + Bước R-1; §4.1.2 dòng carry; §4.1.3 (viết lại); §7 Alt-5 (mới); §8 Exc-2, Exc-5; §9 nguồn BR_9.2.4, BR_9.2.7; §10 AC-9.2-07/19/24, AC-9.2-28–31 (mới); Danh mục UC + cách diễn đạt Safety Check ở BR_9.2.14; §10.1 Q-2/Q-3Safety Check dựa trên Trader_Status ∈ {Banned_Chargeback, Compliance_Flagged}; Exc-2 khóa khi nhận, không cảnh báo; không có quy tắc cho việc hủy/rút ngắn PTO; carry bị đóng băng trong thời gian nghỉ, Flow 17 bỏ qua On_Leave; nguồn Exc-5 "Supplement §7"Safety Check = khớp blacklist HOẶC Users.status ∈ {Banned_Chargeback, Failed, Terminated} HOẶC payout_status ≠ Approved (chỉ PostgreSQL); Exc-2 tách thành 2 trường hợp với Slack #ops-general; Alt-5 Ops xử lý thủ công; carry vẫn tiếp tục vest với mọi Pod Leader kể cả Founding Mentor; Release 2Bảng tính khách hàng Adam/Adrian 2026-11-04 (QnA [BG-002]–[BG-009], [BG-017]; [POD-XF-18])
2026-10-30v2.2 → v2.3Header; §4.1.1 nguồn; §4.1.2 (dòng Workspace, dòng status Registry mới, nhãn dòng Pending_Carry_Balance, nguồn); §4.1.4, §4.1.5 (mới)§4.1.1/§4.1.2 trích dẫn "RFQ V7 §Time-Off & Hiatus Management Engine" không tồn tại; không có quy tắc cho Pod_Leader_Registry.Status trong thời gian nghỉ; không có quy tắc cho SLA của pod trong thời gian nghỉNguồn → xác nhận của khách hàng [POD-XF-15/16]; Pod_Leader_Registry.Status = 'On_Leave' được đặt ở A-4/B-4, trở về 'Active' ở R-2, bị loại khỏi ghép cặp Flow 10; timer SLA của pod tạm dừng (SLA cron / Daily Audit / Calendar Auditor); bỏ nhãn "Table E" — field được đặt tên Pod_Leader_Registry.Pending_Carry_BalancePhản hồi của khách hàng 2026-10-30 (F13-10, F13-11, F13-14)
2026-10-28v2.1 → v2.2§4 Bước A-4/B-4 ghi DB sau gateway; §4.1.4 (đã xoá); §9 BR_9.2.17; §10 AC-9.2-23A-4/B-4, BR_9.2.17, AC-9.2-23 ghi credentials_last_rotated_at = NOW() khi khoá tài khoản nghỉ phép (nguồn "Supplement §3.3"); §4.1.4 cơ chế Acting Cover cho SLA của mentee (nguồn "RFQ V7 §Time-Off & Hiatus Management Engine")Xoá cả hai — không có nguồn trong References (V7 chỉ set credentials_last_rotated_at khi cấp/đổi credential ở Flow 3H; Acting_Cover trong V7 chỉ là status của Flow 15A)Rà soát nguồn 2026-10-28
2026-10-27v2.0 → v2.1§5 P3; §9 BR_9.2.14; §10 AC-9.2-18account_status ghi dạng Active_L[N]_DMA / Active_Lx_DMA / Active_L4_DMA (level ghép vào status)account_status = 'Active_DMA' (enum cố định) + current_levelKhách xác nhận 2026-09-14 — account_status là enum cố định; level lưu ở current_level (UC_5.8 BR_5.8.9)
2026-10-27v1.9 → v2.0Header; Danh mục UC; §1; §2 (viết lại: 2 kênh, 2.1–2.3); §3 Path Router; §4 Steps A-1/A-2; trigger Return Protocol; §5 P1/P4; §6; §7 Alt-1/Alt-3; §8 Exc-1/Exc-2; §9 BR_9.2.2/3/9/11/13/14, BR_9.2.20 (mới); §10 AC-9.2-01/02/03/04/08/15/16/20/21, AC-9.2-25/26/27 (mới), §10.1 Câu hỏi mởMột form Dashboard cho mọi trader L6+; Path A thực hiện Rippling DTO Balance Check (A-1) + "Log Time Off in Rippling API" (A-2); path được điều hướng theo quốc gia KYC; nút hiển thị cho cả W-2 và International; trường form Request Date + Start DateW-2 yêu cầu trong Rippling → webhook duyệt của Rippling kích hoạt Path A (A-1 = nhận webhook + gate + dedup; A-2 = Flow 35 song song; không gọi Rippling API). International dùng form Dashboard đã duyệt (Start/End Date, Requested Days tự động, Reason, Send) → Path B. Điều hướng theo kênh trigger; KYC/Employment_Type làm guard. Exc-1/Exc-2 cũ bị loại bỏ.CR-20261027-001 (khách hàng chọn Option B Hybrid, 2026-10-27); [HR-DEF-01]; thiết kế form đã duyệt
2026-10-01v1.8 → v1.9Thêm §4.1 Trường hợp đặc biệt Pod Leader / Founding Mentor: Failsafe Anti-Termination Gate, bảng bảo toàn tài nguyên, đóng băng carry balance, cơ chế Acting CoverKhông có mục trường hợp đặc biệt Pod Leader / Founding Mentor; BR_9.2.19 chỉ đề cập ngoại lệ Founding Mentor trong phạm viĐã thêm §4.1: 4 mục con bao gồm anti-termination gate (chặn POD_LEADER_TERMINATED + Flow 15C), ma trận bảo toàn tài nguyên On_Leave, phân biệt đóng băng carry với tịch thu, Acting Cover bao phủ SLA tạm thờiRFQ_ Stack Trading Prop Tech V7.pdf §Time-Off & Hiatus Management Engine
2026-09-19v1.7 → v1.8§2 Trigger (UI Entry Point); §4 Steps A-3.5/B-3.5/A-4/B-4/A-5/B-5; §8 Exc-3/Exc-5; §9 BR_9.2.15–19; §10 AC-9.2-20–24Không có bước TRIM_TO_COMPLIANCE trước khi khóa; bước khóa chỉ nhắc Rithmic/MT5 một cách chung chung; không có đặc tả ghi DB sau gateway; A-5/B-5 không có Discord batching; B-5 không có link compliance Dots; chưa định nghĩa điểm vào UI; Exc-3 không có đặc tả retry; chưa ghi nhận xung đột Flow 14; ngoại lệ Founding Mentor chưa được ghi nhậnTRIM_TO_COMPLIANCE (loop & close + failsafe Hard Liquidation 2,000 ms) được thêm làm Bước A-3.5/B-3.5. Bước khóa được mở rộng: MT5 YourBourse Contest Stop Out Plugin + TraderEvolution Admin API. Thêm ghi DB sau gateway: trader_status='On_Leave', is_professional=TRUE, credentials_last_rotated_at=NOW(). Ghi nhận nút "Request Time Off" tại UC_4.16.2 Career & HR Widget (trường bắt buộc: Request Date, Start Date). Thông báo Discord qua Redis queue (tối đa 5 msg/5 s). Email B-5 được bổ sung link compliance white-label của Dots. Exc-3 được mở rộng với 3× retry + exponential backoff. Thêm Exc-5: dispute Flow 14 pre-empt việc quay lại On_Leave. Thêm BR 9.2.15–19 và AC 9.2-20–24.Technical supplement 2026-09-19
2026-09-09v1.6 → v1.7Step R-2/R-3 + BR_9.2.14 + AC-9.2-18/19Return Protocol kích hoạt lại trader về level ban đầu; trường hợp biên khi Level giảm trong thời gian nghỉ chưa được xử lýStep R-2: Middleware nay đọc Current_Level hiện tại tại thời điểm quay lại và đẩy tham số rủi ro của level bị hạ. Step R-3: retainer Path B tiếp tục theo mức của level bị hạ. BR_9.2.14: Current_Level >= 6 được xác nhận chỉ là cổng vào — không kiểm tra lại khi quay lại. Safety Check là cổng quay lại duy nhất. Mọi tài khoản Live DMA Level 1-24 đều mang trạng thái Active_Lx_DMA hợp lệ. Thêm AC-9.2-18 (quay lại sạch, bị hạ cấp) và AC-9.2-19 (Safety Check halt, bị hạ cấp).Khách hàng xác nhận 2026-09-09; đóng Q11
2026-09-09v1.5 → v1.6§7 Alternative Flows (thêm Alt-3/Alt-4) + BR_9.2.13 + AC-9.2-15/16/17Chưa ghi nhận hành vi cho các yêu cầu nghỉ phép liên tiếp khi trader đã đang nghỉThêm Alt-3 (Path A: kiểm tra lại số dư DTO → gia hạn hoặc từ chối) và Alt-4 (Path B: luôn gia hạn). BR_9.2.13 chính thức hóa hành vi state machine idempotent (POST /system/set-account-state idempotent; flag Dots idempotent; một Return Protocol duy nhất vào ngày kết thúc cuối cùng). Thêm AC-9.2-15/16/17.Khách hàng xác nhận 2026-09-09; đóng Q9
2026-08-22v1.3 → v1.4§2 Trigger được viết lại + thêm BR_9.2.11§2: "Trader submits a Time-Off / Hiatus Request Form. Trigger type: Form submission webhook." Không có công cụ form, không có danh sách field, không có định nghĩa payload.Form được xác nhận là form Dashboard native (không phải bên thứ ba). Định nghĩa webhook payload: user_id/Requested_Days/DTO_Hiatus_End_Date. Path Router truy vấn AC/PostgreSQL lấy billing_country. Thêm BR_9.2.11.Khách hàng xác nhận 2026-08-22; đóng Q2 từ audited-v1.md
2026-08-22v1.2 → v1.3Return Protocol — cơ chế Trigger + BR_9.2.10Trigger: "DTO/Hiatus end date reached (date-based cron or scheduled webhook)." Các Step R-1/R-2/R-3/R-4 không nêu rõ quyền sở hữu.Return Protocol được kích hoạt bởi Zapier delay_until trên Zap Flow 13 gốc (không phải cron). Đồng sở hữu: Zapier (orchestration/flow/email) + Middleware (thực thi Safety Check, POST /system/set-account-state, broker Restore Trading, tiếp tục retainer Dots). Thêm BR_9.2.10. Cập nhật mô tả trigger của AC-9.2-05/06/07.Khách hàng xác nhận 2026-08-22; đóng Q1 từ audited-v1.md
2026-08-22v1.1 → v1.2BR_9.2.8 — đóng OPEN[⚠️ OPEN] — Flow 12 bypass cho trader nghỉ phép chưa được định nghĩaXác nhận Flow 12 kích hoạt bình thường trong thời gian nghỉ phép đã duyệt. Market data bị vô hiệu hóa khi last_trade_date > 30 days. Những ngày nghỉ KHÔNG bị trừ khỏi bộ đếm không hoạt động 30 ngày. Việc gia hạn stagnation_deadline (BR_9.2.4) chỉ bảo vệ Flow 19.Khách hàng xác nhận 2026-08-22
2026-08-21v1.0 → v1.1Step B-2; Alt-2; BR_9.2.6; BR_9.2.7Step B-2: [OPEN] — cơ chế chưa xác định. Alt-2: [OPEN] — không có chi tiết RBAC. BR_9.2.6/7: chung chung.Step B-2: xác nhận cơ chế DB flag (is_retainer_paused) + Middleware cron — không phải Zapier, không phải Dots API. Alt-2: BPS RBAC được xác nhận (JWT Level_2/Admin, BPS_Audit_Log); cổng RBAC của POST /system/set-account-state vẫn [OPEN].Khách hàng xác nhận 2026-08-21
2026-08-20v1.0Tạo ban đầu—SRS đầy đủ cho UC_9.2 (Flow 13)Lần soạn đầu tiên. Nguồn: Zapier Integration V7.pdf §Flow 13 + §Flow 35.

UC_9.3 — Luồng 18: Sao lưu Cơ sở dữ liệu Cấu hình & Đồng bộ Khôi phục Thảm họa

TrườngGiá trị
BA phụ tráchlinh.nguyen34
Ngày tạo2026-08-21
Phiên bảnv1.3
Cập nhật lần cuối2026-11-04 — Bảng tính của khách hàng (Adam/Adrian): lịch chạy cố định 02:00 UTC (không áp dụng DST; mọi backend cron đều chạy theo UTC cố định); lifecycle = S3 Standard 90 ngày → S3 Glacier → hết hạn sau 1,856 ngày (5 năm + 1 tháng), chỉ dùng S3 Lifecycle Rule gốc. Trước đó: 2026-10-28 — Cập nhật đặc tả Flow 18: lịch chạy 02:00 AM CST (08:00 AM UTC); Object Lock bắt buộc (Compliance Mode); phân tầng lifecycle HOT/WARM/COLD + hết hạn sau 61 tháng; retry 3× với exponential backoff trước khi cảnh báo; đóng xung đột phạm vi bảng (Tables A–F + các bảng mới được thêm). Cảnh báo: chỉ Slack #ops-dev (không dùng Freshdesk).
Tài liệu tham chiếuZapier Integration V7.pdf (§Flow 18: Configuration Database Backup lines 2099–2121; §Flow 40: Zapier DR Recovery Snapshot lines 2625–2660) · RFQ_ Stack Trading Prop Tech V7.pdf (§5.0 Immutable Archival S3 Object Lock lines 3339–3357; §NFA Audit Requirements lines 3357–3362) · slack_channel_usage.md (CR-15.2 — #ops-dev) · Flow 18 spec 2026-10-28 · Câu hỏi mở: UC_9.x_Client_Questions.md §Flow 18

Danh mục UC

UC_IDTên use caseMô tả nghiệp vụ
UC_9.3Config DB Backup & DR SyncHằng ngày lúc 02:00 UTC (cố định, không áp dụng DST): export toàn bộ Zapier Tables (A–F + các bảng mới được thêm) ra JSON kèm schema_version + SHA-256 checksum → upload lên S3 bucket dùng chung với Flow 40 (SSE-KMS, versioning, Object Lock Compliance Mode, S3 Standard 90 ngày → S3 Glacier, hết hạn sau 1,856 ngày). Bước xác minh độc lập tải lại file, kiểm tra lại checksum và test-parse JSON. Sao lưu hoặc xác minh thất bại → retry tối đa 3× (exponential backoff) → cảnh báo Slack. Mọi cảnh báo chỉ gửi tới Slack #ops-dev.

<a id="UC_9.3"></a>

UC_9.3 — Luồng 18: Sao lưu Cơ sở dữ liệu Cấu hình & Đồng bộ Khôi phục Thảm họa

1. Tổng quan

TrườngNội dung
IDUC_9.3
Use CaseConfig DB Backup & DR Sync
Mô tảSao lưu toàn bộ dữ liệu cấu hình Zapier Table (Tables A–F cùng mọi bảng mới được thêm) hằng ngày lên một S3 bucket bất biến phục vụ khôi phục thảm họa và kiểm toán theo quy định. Một bước xác minh độc lập kiểm tra tính toàn vẹn của bản sao lưu. Lỗi được tự động retry trước khi cảnh báo Ops. Luồng này bảo vệ lớp business logic (giới hạn rủi ro, ma trận giá, platform registry, email/event mapping) vốn không nằm trong phạm vi sao lưu RDS PostgreSQL Multi-AZ — cơ chế xử lý dữ liệu giao dịch của trader.
Zapier FlowFlow 18 (Configuration Database Backup) · Flow 40 (Zapier DR Recovery Snapshot — dùng chung S3 bucket/prefix)
Zapier TableTables A–F (toàn bộ bảng cấu hình đang hoạt động) + mọi bảng mới được thêm, phát hiện tại runtime
3rd PartyZapier (nguồn export table) · AWS S3 (lưu trữ sao lưu — SSE-KMS, versioning, Object Lock, phân tầng lifecycle) · AWS KMS (quản lý khóa mã hóa) · Slack (#ops-dev — xác nhận thành công và cảnh báo thất bại)

2. Trigger

Lịch chạy: Cron job theo lịch, hằng ngày lúc 02:00 UTC — cố định theo UTC, không dịch chuyển theo Giờ mùa hè (DST). Mọi lịch cron backend trong toàn hệ thống đều chạy theo UTC cố định.

(Nguồn: QnA_BACKGROUND_MECHANISMS_CRON.md [BG-011] — bảng tính của khách hàng 2026-11-04; ghi đè Zapier Integration V7.pdf §Flow 18 line 2101 "Daily at 02:00 AM CST")


3. Luồng cơ bản

Bước 1 — Export Zapier Tables
  • Export toàn bộ các bảng cấu hình: Tables A đến F, cùng các bảng mới được thêm phát hiện tại runtime.
  • Định dạng export: JSON, với hai trường metadata bắt buộc được nhúng trong mọi file export:
Trường metadataMục đích
schema_versionTheo dõi phiên bản cấu trúc cấu hình để kiểm tra khả năng tương thích khi restore
checksumMã băm SHA-256 của nội dung file, tính tại thời điểm export — dùng để phát hiện dữ liệu bị hỏng hoặc bị cắt cụt trong quá trình truyền

(Nguồn: Zapier Integration V7.pdf §Flow 18 lines 2102–2108)

Bước 2 — Upload lên S3
  • Upload file export JSON lên S3 bucket riêng.
  • Quy ước đặt tên: config_backup_YYMMDD_HHMMSS.json
  • Bucket dùng chung: Flow 18 dùng cùng S3 bucket và prefix với Flow 40 (Zapier DR Recovery Snapshot). Cả hai luồng dùng chung cấu hình bảo mật và lifecycle.

S3 bucket PHẢI được cấu hình với các thuộc tính sau:

Thuộc tínhYêu cầuNguồn
SSE-KMS encryptionToàn bộ file được mã hóa at rest bằng AWS KMS với khóa do công ty quản lýZapier V7 §Flow 18
Bucket versioningBật — giữ lại nhiều phiên bản lịch sử; ngăn việc ghi đè làm mất các bản sao trước đóZapier V7 §Flow 18
Object Lock (WORM)Bắt buộc — Compliance Mode. File không thể bị chỉnh sửa hoặc xóa trong thời hạn lưu giữ bởi bất kỳ tài khoản nào, kể cả Admin/root.Flow 18 spec 2026-10-28 (V7 ghi Object Lock là tùy chọn — xem F18-02)
Phân tầng lifecycle + hết hạnXem bảng bên dưới — S3 Lifecycle Rule gốc trên prefix sao lưuBảng tính của khách hàng 2026-11-04 [BG-010]
Cross-region replicationKhuyến nghị để DR khi toàn bộ region ngừng hoạt độngZapier V7 §Flow 18 — xem F18-05

Quy tắc lifecycle (Hot / Cold):

TầngTuổi objectStorage class
Hot0–90 ngày (1 quý)S3 Standard
Cold91 ngày – 1,856 ngàyS3 Glacier
Hết hạnSau 1,856 ngày (5 năm + 1 tháng)Object tự động bị xóa
  • Không dùng script tùy biến nén thư mục theo tuần/tháng — cron hằng ngày chỉ upload file JSON; việc phân tầng và hết hạn do S3 Lifecycle Rule đảm nhiệm.
  • Bản sao lưu cấu hình là điểm khôi phục, không phải audit log — quy tắc "2 years immediately accessible" của RFQ V7 §5.0 (áp dụng cho trading archive) không áp dụng ở đây.
  • ⚠️ Thời hạn lưu giữ của Object Lock không được vượt quá 1,856 ngày, nếu không quy tắc hết hạn sẽ không thể xóa object.

(Nguồn: Zapier Integration V7.pdf §Flow 18 lines 2109–2116; §Flow 40 line 2652; QnA_BACKGROUND_MECHANISMS_CRON.md [BG-010] — bảng tính của khách hàng 2026-11-04)

Bước 3 — Xác minh sao lưu độc lập

Một bước xác minh tự động độc lập chạy ngay sau khi upload:

  1. Tải xuống file JSON vừa upload từ S3.
  2. Tính lại checksum SHA-256 của file đã tải xuống và so sánh với checksum đã tính lúc export.
    • Khớp → file toàn vẹn. Tiếp tục.
    • Không khớp → xác minh thất bại (→ Bước 4, nhánh thất bại).
  3. Test-parse nội dung file theo cấu trúc JSON kỳ vọng.
    • Parse thành công → xác minh đạt. Luồng kết thúc thành công.
    • Parse thất bại → xác minh thất bại (→ Bước 4, nhánh thất bại).

(Nguồn: Zapier Integration V7.pdf §Flow 18 lines 2117–2119)

Bước 4 — Xử lý lỗi: Retry, sau đó Cảnh báo
  • Nếu sao lưu (Bước 1–2) hoặc xác minh (Bước 3) thất bại, job tự động retry tối đa 3 lần với exponential backoff.
  • Nếu vẫn thất bại sau lần retry thứ 3 → gửi cảnh báo Slack tới #ops-dev chứa bước thất bại và lỗi cụ thể (ví dụ: lỗi xác thực KMS, S3 upload timeout, checksum mismatch, lỗi JSON parse).
Kết quảCảnh báo
Thành công✅ Xác nhận Slack: Backup complete — config_backup_YYMMDD_HHMMSS
Thất bại sau 3 lần retry🚨 Cảnh báo Slack kèm bước thất bại và chi tiết lỗi.

Kênh cảnh báo: chỉ Slack #ops-dev — theo danh mục kênh Slack (CR-15.2, slack_channel_usage.md): "Config DB Backup success/failure notifications". Không tạo ticket Freshdesk.

(Nguồn: Zapier Integration V7.pdf §Flow 18 lines 2120–2121; CR-15.2; Flow 18 spec 2026-10-28)


4. Điều kiện tiên quyết

IDĐiều kiện tiên quyết
P1Toàn bộ Zapier Tables đang hoạt động (A–F + các bảng mới được thêm) có thể truy cập và đọc được qua table API của Zapier.
P2S3 bucket riêng (dùng chung với Flow 40) đã tồn tại và được cấu hình SSE-KMS, versioning, Object Lock (Compliance Mode) và các quy tắc lifecycle ở Bước 2.
P3Khóa AWS KMS đang hoạt động và IAM role của Zapier/Middleware có quyền kms:GenerateDataKey và s3:PutObject.
P4Slack webhook cho #ops-dev đang hoạt động.

5. Hậu điều kiện

Kết quảHậu điều kiện
Thành côngconfig_backup_YYMMDD_HHMMSS.json được upload lên S3 với đầy đủ thuộc tính bảo mật; checksum và parse đã được xác minh; đã gửi xác nhận Slack ✅ tới #ops-dev.
Thất bại — phục hồi nhờ retryMột lần retry thành công; giống Thành công (xác nhận Slack ✅). Không có cảnh báo thất bại.
Thất bại — sau 3 lần retry (lỗi upload)File không được lưu vào S3. Cảnh báo thất bại Slack được gửi kèm chi tiết lỗi.
Thất bại — sau 3 lần retry (checksum mismatch / lỗi parse)File nằm trên S3 nhưng được gắn cờ là chưa xác minh. Cảnh báo thất bại Slack được gửi. File KHÔNG được dùng để restore.

6. Luồng ngoại lệ

Exc-1 — Upload S3 thất bại (network timeout, permission denied, KMS key không khả dụng):

  • Retry tối đa 3 lần với exponential backoff (Bước 4).
  • Tất cả các lần retry đều thất bại → bản sao lưu không được lưu; cảnh báo thất bại Slack được gửi kèm mã lỗi.

Exc-2 — Checksum mismatch sau khi upload:

  • File nằm trên S3 nhưng không thể tin cậy là điểm restore hợp lệ.
  • Retry tối đa 3 lần (Bước 4). Nếu vẫn không khớp → cảnh báo thất bại Slack kèm chi tiết "checksum mismatch".
  • File KHÔNG bị xóa (Object Lock ngăn việc này) — S3 versioning giữ sẵn phiên bản sạch trước đó.

⚠️ [MỞ — Exc-2] Nguồn không quy định file chưa được xác minh có được gắn tag trong S3 metadata hay không. BA cần xác nhận có nên áp dụng tag corrupt=true cho S3 object hay không.

Exc-3 — JSON parse thất bại:

  • File có thể bị cắt cụt hoặc gặp vấn đề encoding.
  • Hành vi retry và bảo toàn file giống Exc-2; chi tiết cảnh báo "JSON parse error".

Exc-4 — Đọc Zapier Table thất bại (một hoặc nhiều bảng không khả dụng):

  • Có thể sinh ra bản export một phần.
  • Bản sao lưu một phần có thể âm thầm tạo ra điểm restore không đầy đủ.

⚠️ [MỞ — Exc-4] Nguồn không quy định bản export một phần được upload hay toàn bộ job bị hủy khi một bảng lỗi. BA cần xác nhận: abort-all hay upload-partial-with-error-flag.

Exc-5 — Gửi cảnh báo Slack thất bại:

  • Kết quả sao lưu không bị ảnh hưởng, nhưng Ops không có khả năng quan sát.
  • Không có kênh dự phòng — cảnh báo chỉ qua Slack. Việc gửi thất bại được ghi log phía server.

7. Quy tắc nghiệp vụ

Rule IDQuy tắcNguồn
BR_9.3.1Flow 18 chỉ sao lưu dữ liệu cấu hình Zapier Table — KHÔNG sao lưu dữ liệu giao dịch của trader (phần này do Amazon RDS PostgreSQL Multi-AZ automated backups đảm nhiệm).Zapier Integration V7.pdf §Flow 18
BR_9.3.2Phạm vi sao lưu là Tables A–F cùng các bảng mới được thêm, phát hiện tại runtime.Zapier Integration V7.pdf §Flow 18 line 2102; Flow 18 spec 2026-10-28
BR_9.3.3Mọi bản export JSON PHẢI nhúng schema_version và trường checksum SHA-256. Đây là metadata, không phải dữ liệu payload.Zapier Integration V7.pdf §Flow 18 lines 2107–2108
BR_9.3.4S3 bucket PHẢI bật mã hóa SSE-KMS, bucket versioning và S3 Object Lock ở Compliance Mode. Cross-region replication được khuyến nghị.Zapier Integration V7.pdf §Flow 18 lines 2110–2115; Flow 18 spec 2026-10-28 (F18-02, F18-05)
BR_9.3.5S3 Lifecycle Rule trên prefix sao lưu: S3 Standard trong 90 ngày đầu → S3 Glacier sau 90 ngày → xóa sau 1,856 ngày (5 năm + 1 tháng). Không dùng code nén/xoay vòng tùy biến.QnA_BACKGROUND_MECHANISMS_CRON.md [BG-010] — bảng tính của khách hàng 2026-11-04
BR_9.3.6Bước xác minh độc lập (tải lại + so sánh checksum + JSON test-parse) PHẢI chạy ngay sau mỗi lần upload. Bản sao lưu chỉ được coi là thành công khi xác minh đạt.Zapier Integration V7.pdf §Flow 18 lines 2117–2119
BR_9.3.7Flow 40 (Zapier DR Recovery Snapshot) dùng chung S3 bucket và prefix với Flow 18. Bucket áp dụng một chính sách bảo mật, versioning và lifecycle thống nhất cho cả hai luồng.Zapier Integration V7.pdf §Flow 40 line 2652
BR_9.3.8Đặt tên file PHẢI theo quy ước: config_backup_YYMMDD_HHMMSS.json.Zapier Integration V7.pdf §Flow 18 line 2111
BR_9.3.9Nếu sao lưu hoặc xác minh thất bại, job PHẢI retry tối đa 3 lần với exponential backoff. Cảnh báo thất bại Slack chỉ được gửi sau khi lần retry thứ 3 thất bại.Flow 18 spec 2026-10-28
BR_9.3.10Mọi thông báo của Flow 18 chỉ gửi tới Slack #ops-dev: xác nhận ✅ sau mỗi lần sao lưu thành công và cảnh báo 🚨 sau lần retry thứ 3 thất bại. Không tạo ticket Freshdesk.Zapier Integration V7.pdf §Flow 18 line 2121; CR-15.2 (slack_channel_usage.md)

8. Yêu cầu phi chức năng

Khía cạnhYêu cầu
Bảo mậtMã hóa SSE-KMS at rest. IAM least-privilege cho quyền ghi S3 và truy cập KMS. Object Lock (Compliance Mode) ngăn xóa trong thời hạn lưu giữ, kể cả bởi tài khoản Admin/root.
Tuân thủLưu giữ 5 năm + 1 tháng (1,856 ngày); object cũ hơn 90 ngày nằm trong S3 Glacier; xóa ở ngày thứ 1,856.
Độ bềnĐộ bền S3 standard (99.999999999%). Cross-region replication được khuyến nghị để DR khi toàn bộ region ngừng hoạt động.
Toàn vẹnChecksum SHA-256 được nhúng trong mọi file export. Bước xác minh độc lập là bắt buộc sau mỗi lần upload.
Khả dụngChạy hằng ngày — một lần thất bại không gây mất dữ liệu (bản sao lưu ngày trước vẫn hợp lệ trên S3 nhờ versioning). Lỗi tạm thời được hấp thụ bởi 3 lần retry tự động.
Khả năng quan sátChỉ Slack #ops-dev: xác nhận ✅ sau mỗi lần sao lưu thành công; cảnh báo 🚨 sau lần retry thứ 3 thất bại, kèm bước thất bại và chi tiết lỗi cụ thể.

9. Tiêu chí chấp nhận

IDKịch bảnKết quả mong đợi
AC-9.3-01Job theo lịch chạy lúc 02:00 UTC (cùng một giờ UTC quanh năm, không dịch chuyển theo DST) — mọi bảng đều đọc đượcFile JSON được export với schema_version và SHA-256 checksum; upload lên S3 với tên config_backup_YYMMDD_HHMMSS.json; áp dụng SSE-KMS và Object Lock; xác minh đạt. Gửi xác nhận Slack ✅ tới #ops-dev.
AC-9.3-02Xác minh: checksum của file đã tải xuống khớp với checksum lúc exportXác minh đạt. Không gửi cảnh báo thất bại.
AC-9.3-03Xác minh: checksum mismatch ở mọi lần thửThực hiện 3 lần retry với exponential backoff; sau khi lần retry thứ 3 thất bại, gửi cảnh báo Slack 🚨 tới #ops-dev kèm chi tiết "checksum mismatch".
AC-9.3-04Xác minh: JSON test-parse thất bại ở mọi lần thửThực hiện 3 lần retry; gửi cảnh báo Slack 🚨 tới #ops-dev kèm chi tiết "JSON parse error".
AC-9.3-05Upload S3 thất bại (ví dụ KMS key không khả dụng) ở mọi lần thửKhông có file nào được ghi vào S3. Thực hiện 3 lần retry; gửi cảnh báo Slack 🚨 tới #ops-dev kèm mã lỗi cụ thể.
AC-9.3-06Upload S3 thất bại ở lần thử đầu và thành công ở lần retry thứ 2Sao lưu hoàn tất và xác minh đạt. Gửi xác nhận Slack ✅; không gửi cảnh báo thất bại.
AC-9.3-07Lần sao lưu thứ hai trong cùng ngày tạo ra file mớiS3 versioning giữ lại cả hai file. Không ghi đè bản sao lưu trước.
AC-9.3-08Thử xóa hoặc ghi đè một file sao lưu trong thời hạn lưu giữ (kể cả bằng tài khoản Admin/root)Bị S3 Object Lock (Compliance Mode) từ chối.
AC-9.3-09Một file sao lưu đạt 91 ngày tuổiQuy tắc lifecycle chuyển file từ S3 Standard sang S3 Glacier. File vẫn truy xuất được.
AC-9.3-10Một file sao lưu có tuổi 1–90 ngàyFile vẫn nằm trong S3 Standard (hot).
AC-9.3-11Một file sao lưu đạt 1,857 ngày tuổiQuy tắc lifecycle tự động xóa file.
AC-9.3-12Flow 40 upload một artifact lên cùng S3 bucketFile cùng tồn tại với các bản sao lưu Flow 18 dưới cùng prefix. Các quy tắc KMS, versioning, Object Lock và lifecycle áp dụng cho cả hai.

10. Lịch sử cập nhật

NgàyPhiên bảnMục được cập nhậtTrướcSauLý do
2026-11-04v1.2 → v1.3Header; Danh mục UC; §2 Trigger (lịch chạy, lý do, nguồn); §3 Bước 2 (dòng lifecycle, bảng lifecycle + ghi chú, nguồn); §7 BR_9.3.5; §8 Tuân thủ; §9 AC-9.3-01/09/10/11Hằng ngày 02:00 AM CST (08:00 AM UTC), DST còn mở (F18-04); phân tầng HOT/WARM/COLD 0–12 / 13–24 / 25–61 tháng, xóa ở 61 thángHằng ngày 02:00 UTC cố định (không DST; mọi backend cron theo UTC cố định); S3 Lifecycle Rule: S3 Standard 90 ngày → S3 Glacier → xóa ở 1,856 ngày; không dùng script nén tùy biếnBảng tính của khách hàng Adam/Adrian 2026-11-04 (QnA [BG-010] [BG-011])
2026-10-28v1.1 → v1.2§1 3rd Party; §3 Bước 4; §4 P4; §5; §6 Exc-5; §7 BR_9.3.10 (mới); §8 Khả năng quan sát; §9 AC-9.3-01/03/04/05/06Kênh cảnh báo và dự phòng Freshdesk còn mở (F18-01); chưa rõ có gửi khi thành côngChỉ Slack #ops-dev — ✅ khi thành công, 🚨 sau lần retry thứ 3 thất bại; không dùng FreshdeskQuyết định 2026-10-28 (đóng F18-01)
2026-10-28v1.0 → v1.1Header; Danh mục UC; §1; §2; §3 Bước 1–4; §4–§6; §7 BR_9.3.2/4/5/6/7, BR_9.3.9 (mới); §8; §9 AC-9.3-01–12Object Lock tùy chọn; lifecycle "> 25 tháng → Glacier, xóa ở 61 tháng"; không retry (Exc-1 OPEN); cảnh báo Slack tới #dev_ops khi thành công hoặc thất bại; SOURCE CONFLICT về phạm vi bảng (A–F vs A–J)Object Lock bắt buộc (Compliance Mode); phân tầng HOT/WARM/COLD (Instant 0–12 th → Flexible 13–24 th → Deep Archive 25–61 th) + hết hạn ở 61 th; retry 3× exponential backoff rồi cảnh báo Slack; kênh ghi nhận là #ops-dev (CR-15.2); đóng xung đột phạm vi — Tables A–F + các bảng mới được thêm. Các mục mở chuyển sang F18-01 → F18-05.Flow 18 spec 2026-10-28
2026-08-21v1.0Khởi tạo—SRS đầy đủ cho UC_9.3 (Flow 18)Lần soạn thảo đầu tiên. Nguồn: Zapier Integration V7.pdf §Flow 18; Prop Tech V7 §CFTC 1.31.

UC_9.8 — Luồng 30: Cảnh báo Công suất MID

TrườngGiá trị
BA phụ tráchlinh.nguyen34
Ngày tạo2026-09-03
Phiên bảnv1.2
Cập nhật lần cuối2026-11-05 — khách trả lời 2026-11-03: refund trừ current_mtd_volume (chặn đáy 0); warning_80_fired được re-arm trong Check MID Capacity khi volume tụt dưới 80%
Tài liệu tham chiếuZapier Integration V7.pdf (§Flow 30 lines 2461–2469) · RFQ_ Stack Trading Prop Tech V7.pdf (§Check MID Capacity lines 1455–1459; §Process Payment Webhook lines 1339–1373; §Merchant_Routing_Config lines 847–855; §Alerting lines 3273)

Danh mục UC

UC_IDTên use caseMô tả nghiệp vụ
UC_9.8MID Capacity WarningThời gian thực: sau mỗi giao dịch thanh toán thành công, Middleware kiểm tra MID được dùng đã đạt 80% hạn mức khối lượng hằng tháng hay chưa. Nếu đã đạt và chưa cảnh báo trong tháng này, bắn webhook → cảnh báo Slack tới #ops-treasury.

<a id="UC_9.8"></a>

UC_9.8 — Luồng 30: Cảnh báo Công suất MID

1. Tổng quan

TrườngNội dung
IDUC_9.8
Use CaseMID Capacity Warning
Mô tảHệ thống cảnh báo sớm về công suất xử lý hằng tháng của MID (Merchant Identification Number). Sau mỗi giao dịch thanh toán thành công, Middleware đánh giá MID được dùng đã tiêu thụ ≥ 80% monthly_limit hay chưa. Nếu vượt ngưỡng và warning_80_fired = FALSE, Middleware đặt cờ và bắn webhook để gửi cảnh báo Slack tới kênh Operations. Ngăn tình trạng đóng băng pipeline doanh thu do MID bị từ chối vì vượt hạn mức.
FlowFlow 30 (MID Capacity Warning)
BảngMerchant_Routing_Config (bảng PostgreSQL)
3rd PartyNMI (payment gateway — nguồn phát sinh sự kiện thanh toán thành công) · Slack (gửi cảnh báo)

2. Trigger

Loại: Nội bộ — được Middleware Hub kích hoạt theo chương trình ngay sau khi Process Payment Webhook cập nhật thành công current_mtd_volume trong cơ sở dữ liệu.

Điều kiện trigger: Mỗi giao dịch thanh toán thành công từ bất kỳ gateway nào (NMI, Triple-A, Nomupay, EBANX, Dusupay, Skrill) và mỗi lần refund đều dẫn đến một lệnh gọi POST /merchant/check-capacity cho MID được dùng.

(Nguồn: RFQ_ Stack Trading Prop Tech V7.pdf §Check MID Capacity lines 1455–1459; §Process Payment Webhook lines 1339–1346)


3. Luồng cơ bản

Bước 1 — Cập nhật khối lượng (upstream — Process Payment Webhook)

Sau một giao dịch thanh toán thành công, Process Payment Webhook cập nhật tổng lũy kế của MID trong Merchant_Routing_Config:

current_mtd_volume = current_mtd_volume + transaction_amount

Khi refund, tổng chạy của MID bị trừ và không bao giờ xuống dưới 0 (ví dụ refund giao dịch của tháng trước ngay sau khi reset ngày 1):

current_mtd_volume = GREATEST(0, current_mtd_volume - refund_amount)

current_mtd_volume chỉ là bộ đếm month-to-date nội bộ dùng để cân tải — không phải số dư tài khoản ngân hàng merchant. Bản thân refund vẫn được NMI xử lý bình thường kể cả khi current_mtd_volume = 0.

(Nguồn: RFQ_ Stack Trading Prop Tech V7.pdf §Process Payment Webhook line 1345; QnA_BACKGROUND_MECHANISMS_CRON.md [BG-024] — khách trả lời 2026-11-03)

Bước 2 — Kiểm tra công suất (POST /merchant/check-capacity)

Ngay sau khi cập nhật DB, Middleware gọi nội bộ POST /merchant/check-capacity.

Input payload:

{
  "merchant_name": "<MID identifier>",
  "current_mtd_volume": <updated value>
}

Logic đánh giá:

ratio = current_mtd_volume / monthly_limit

IF ratio >= 0.80 AND warning_80_fired = FALSE:
  → SET warning_80_fired = TRUE
  → FIRE webhook
ELSE IF ratio < 0.80 AND warning_80_fired = TRUE:
  → SET warning_80_fired = FALSE   (no Slack alert)
ELSE:
  → No action. Return HTTP 200.

Cờ warning_80_fired giúp cảnh báo 80% chỉ bắn một lần cho mỗi lần vượt ngưỡng: khi cờ đang được đặt, các giao dịch tiếp theo trên cùng MID không kích hoạt lại luồng, kể cả khi ratio tăng vượt 90% hoặc 100%. Nếu volume tụt lại dưới 80% (do refund, hoặc do monthly_limit được nâng), cờ được xóa và lần vượt ngưỡng kế tiếp sẽ bắn cảnh báo mới. Không xây DB trigger hay watcher riêng — toàn bộ xử lý nằm trong bước kiểm tra này.

(Nguồn: RFQ_ Stack Trading Prop Tech V7.pdf §Check MID Capacity lines 1456–1459; QnA_BACKGROUND_MECHANISMS_CRON.md [BG-025] — khách trả lời 2026-11-03)

Response: HTTP 200 OK trong mọi trường hợp (bắn hoặc không bắn).

Bước 3 — Cảnh báo Slack

Gửi tin nhắn Slack tới kênh Operations (#ops-treasury hoặc kênh Ops được cấu hình).

Nội dung tin nhắn Slack:

⚠️ [WARN] MID VOLUME CAPACITY ALERT
MID [merchant_name] has reached [ratio]% of its monthly processing limit.
Current MTD Volume: $[current_mtd_volume]
Monthly Limit: $[monthly_limit]
Action Required: Contact processor to request limit increase, or adjust
Weighted Round-Robin weights in Merchant_Routing_Config to offload traffic.

(Nguồn: Zapier Integration V7.pdf §Flow 30 lines 2466–2469)


4. Mô hình dữ liệu

Bảng Merchant_Routing_Config (PostgreSQL)
TrườngKiểuMô tả
merchant_nameVARCHAR (PK)Định danh MID duy nhất (ví dụ NMI_US_Credit_01)
nmi_routing_idVARCHARMã routing được cấu hình trong NMI gateway
monthly_limitDECIMALKhối lượng giao dịch tối đa mỗi tháng dương lịch
current_mtd_volumeDECIMALTổng lũy kế từ đầu tháng của các giao dịch thành công
is_activeBOOLEANMID này hiện có đang trong vòng xoay (rotation) hay không
warning_80_firedBOOLEAN (default: FALSE)Cờ idempotency (chống trùng lặp) — ngăn cảnh báo trùng lặp trong cùng tháng

(Nguồn: RFQ_ Stack Trading Prop Tech V7.pdf §Merchant_Routing_Config lines 847–855; §Alerting line 3273; client confirmed 2026-09-18)


5. Tham chiếu API

EndpointMethodAuthBên gọiMục đích
POST /merchant/check-capacityPOSTInternal — no public authMiddleware (gọi sau Process Payment Webhook)Đánh giá ngưỡng 80%; bắn webhook nếu được kích hoạt

Input:

TrườngKiểuBắt buộcMô tả
merchant_nameVARCHAR✅Xác định MID cần đánh giá
current_mtd_volumeDECIMAL✅Khối lượng MTD sau cập nhật của MID này

Output: HTTP 200 OK (không cần body — chỉ có side effect)

(Nguồn: RFQ_ Stack Trading Prop Tech V7.pdf §Check MID Capacity lines 1455–1459)


6. Luồng ngoại lệ

Exc-1 — warning_80_fired đã là TRUE (chặn trùng lặp):

  • Không bắn webhook. Trả về HTTP 200 âm thầm.
  • Đây là hành vi mong đợi — cờ được reset bởi cron ngày 1 hằng tháng, hoặc bởi lần kiểm tra công suất kế tiếp khi volume dưới 80% (xem §7).

Exc-2 — monthly_limit của MID là NULL hoặc bằng 0:

Middleware PHẢI áp dụng guard clause: nếu monthly_limit IS NULL OR monthly_limit = 0, bỏ qua phép tính công suất 80% cho MID đó, ghi log cảnh báo phía server với mã NULL_OR_ZERO_MONTHLY_LIMIT_WARNING, và trả về HTTP 200 (không ném exception 500). Ngoài ra, Middleware PHẢI gửi một cảnh báo Ops chủ động tới kênh Slack #ops-treasury với nội dung:

⚠️ Configuration Error: MID [merchant_name] has an active status but a zero or null monthly limit.

Lý do: monthly_limit NULL hoặc bằng 0 trên một MID đang active là lỗi cấu hình nghiêm trọng — phải chuyển cho đội Ops để sửa DB ngay. Đây là cảnh báo cấu hình nội bộ và KHÔNG ĐƯỢC chuyển tới Freshdesk.

(Nguồn: client confirmed 2026-09-18)

Exc-3 — Gửi webhook thất bại:

Khi Middleware bắn webhook cảnh báo công suất và nhận response khác 200 hoặc timeout:

Giai đoạn 1 — Retry: Middleware thực hiện 3 lần retry tự động với exponential backoff.

Giai đoạn 2 — Fallback (đã dùng hết 3 lần retry): Middleware đẩy cảnh báo fallback trực tiếp tới #dev_ops qua lệnh gọi native Slack API webhook.

(Nguồn: client confirmed 2026-09-18)


7. Quy tắc nghiệp vụ

Rule IDQuy tắcNguồn
BR_9.8.1POST /merchant/check-capacity PHẢI được gọi đồng bộ sau mỗi giao dịch thanh toán thành công và mỗi lần refund có cập nhật current_mtd_volume. Đây là trigger nội bộ — không mở ra cho client bên ngoài.RFQ_ Stack Trading Prop Tech V7.pdf §Check MID Capacity lines 1455–1459
BR_9.8.2Ngưỡng công suất là đúng 80% (ratio >= 0.80). Cảnh báo bắn một lần cho mỗi lần vượt ngưỡng — khi warning_80_fired = TRUE, các giao dịch tiếp theo KHÔNG kích hoạt lại kể cả khi ratio đạt 90% hoặc 100%. Nếu ratio tụt dưới 80%, cờ được reset về FALSE và lần vượt ngưỡng kế tiếp sẽ cảnh báo lại.RFQ_ Stack Trading Prop Tech V7.pdf §Check MID Capacity lines 1456–1458; RFQ_ Stack Trading Prop Tech V7.pdf §Alerting line 3273; QnA [BG-025] khách trả lời 2026-11-03
BR_9.8.3warning_80_fired PHẢI được đặt thành TRUE một cách atomic cùng với việc bắn webhook. Nếu cập nhật DB và bắn webhook không atomic, một lần retry có thể gửi cảnh báo Slack trùng lặp. Ghi chú triển khai: đặt cờ trước khi bắn webhook; nếu webhook thất bại, cờ vẫn được giữ nguyên (ưu tiên bỏ lỡ cảnh báo hơn là cảnh báo trùng lặp).RFQ_ Stack Trading Prop Tech V7.pdf §Check MID Capacity lines 1456–1459; client confirmed 2026-09-03
BR_9.8.4Reset hằng tháng: current_mtd_volume được reset về 0.00 VÀ warning_80_fired được reset về FALSE cho toàn bộ MID vào 00:00 UTC ngày 1 hằng tháng bởi cron job hằng tháng.RFQ_ Stack Trading Prop Tech V7.pdf §Merchant_Routing_Config line 222; client confirmed 2026-09-03
BR_9.8.5Chỉ các MID có is_active = TRUE tham gia routing Weighted Round-Robin. MID không active không được đánh giá công suất.RFQ_ Stack Trading Prop Tech V7.pdf §Merchant_Routing_Config lines 847–855
BR_9.8.6Re-arm cờ — không có trigger riêng: Không xây DB trigger hay watcher theo dõi thay đổi monthly_limit. Việc re-arm nằm trong Check MID Capacity: nếu current_mtd_volume < 0.80 × monthly_limit VÀ warning_80_fired = TRUE → đặt warning_80_fired = FALSE. Áp dụng cho cả trường hợp nâng monthly_limit lẫn refund làm volume tụt dưới 80%.QnA_BACKGROUND_MECHANISMS_CRON.md [BG-025] — khách trả lời 2026-11-03
BR_9.8.7Guard cho limit Null/Zero — bắt buộc cảnh báo Slack chủ động: Nếu monthly_limit IS NULL OR monthly_limit = 0 với một MID is_active = TRUE, Middleware PHẢI (a) bỏ qua phép tính công suất 80%, (b) ghi log NULL_OR_ZERO_MONTHLY_LIMIT_WARNING phía server, (c) trả về HTTP 200 (không 500), VÀ (d) gửi cảnh báo Slack tới #ops-treasury: "⚠️ Configuration Error: MID [merchant_name] has an active status but a zero or null monthly limit." KHÔNG ĐƯỢC chuyển tới Freshdesk.Client confirmed 2026-09-18
BR_9.8.8Gửi webhook thất bại — retry + native Slack fallback: Nếu lệnh gọi webhook thất bại (khác 200 hoặc timeout), Middleware PHẢI thực hiện 3 lần retry tự động với exponential backoff. Nếu cả 3 lần retry đều thất bại, Middleware PHẢI đẩy cảnh báo công suất trực tiếp tới #dev_ops qua lệnh gọi native Slack API webhook.Client confirmed 2026-09-18
BR_9.8.9Chặn đáy khi trừ refund: Refund trừ current_mtd_volume theo GREATEST(0, current_mtd_volume - refund_amount) — giá trị không bao giờ dưới 0. current_mtd_volume là bộ đếm nội bộ để cân tải, không phải số dư ngân hàng; NMI vẫn xử lý refund bất kể giá trị này.QnA_BACKGROUND_MECHANISMS_CRON.md [BG-024] — khách trả lời 2026-11-03

8. Tiêu chí chấp nhận

IDKịch bảnKết quả mong đợi
AC-9.8-01MID ở mức 79.9% → một giao dịch thành công đẩy lên 80.1% →warning_80_fired = FALSEWebhook được bắn; warning_80_fired được đặt thành TRUE; nhận cảnh báo Slack tại #ops-treasury
AC-9.8-02MID đã ở mức 82% (warning_80_fired = TRUE) → xử lý giao dịch mớiKhông bắn webhook; không có cảnh báo Slack; warning_80_fired vẫn là TRUE; trả về HTTP 200
AC-9.8-03MID ở mức 79% → giao dịch đẩy lên 79.9%Không bắn webhook; warning_80_fired vẫn là FALSE; trả về HTTP 200
AC-9.8-04Cron cuối tháng chạy lúc 00:00 UTC ngày 1current_mtd_volume = 0.00 và warning_80_fired = FALSE cho toàn bộ MID
AC-9.8-05MID có is_active = FALSE nhận cập nhật thanh toánBỏ qua kiểm tra công suất; không bắn cảnh báo
AC-9.8-06monthly_limit = 0 hoặc NULL với một MID activeTrả về HTTP 200; không ném 500; ghi log NULL_OR_ZERO_MONTHLY_LIMIT_WARNING; gửi cảnh báo Slack tới #ops-treasury với nội dung "Configuration Error: MID [merchant_name] has an active status but a zero or null monthly limit."
AC-9.8-07Ops nâng monthly_limit của một MID (warning_80_fired = TRUE); payment/refund kế tiếp chạy kiểm tra công suất với volume < 80% hạn mức mớiwarning_80_fired được reset về FALSE ở lần kiểm tra đó; không có cảnh báo Slack
AC-9.8-08Webhook thất bại ở lần đầu → retry → hết cả 3 lần retryThực hiện 3 lần retry với exponential backoff; cảnh báo Slack fallback được đẩy trực tiếp tới #dev_ops qua native Slack API
AC-9.8-09warning_80_fired = FALSE, monthly_limit là NULL, MID is_active = TRUEGuard clause kích hoạt: bỏ qua kiểm tra công suất; ghi log NULL_OR_ZERO_MONTHLY_LIMIT_WARNING; gửi cảnh báo Slack #ops-treasury; không có lỗi chia cho 0
AC-9.8-10Đã reset ngày 1 (current_mtd_volume = 0); refund một giao dịch $500 của tháng trướccurrent_mtd_volume = 0 (không âm); NMI xử lý refund bình thường
AC-9.8-11MID ở mức 85% (warning_80_fired = TRUE); refund kéo xuống 75%warning_80_fired = FALSE; không có cảnh báo Slack
AC-9.8-12Sau AC-9.8-11, một giao dịch đẩy MID lên lại 81%Webhook được bắn (cảnh báo lần 2 trong tháng); warning_80_fired = TRUE

9. Lịch sử thay đổi

NgàyPhiên bảnTóm tắtTrướcSauNguồn
2026-11-05v1.1 → v1.2§2 Trigger (refund) · §3 Bước 1 (trừ refund) · Bước 2 (nhánh re-arm) · §6 Exc-1 · §7 cập nhật BR_9.8.1/2/6, thêm BR_9.8.9 · §8 cập nhật AC-9.8-07, thêm AC-9.8-10/11/12 · §6 Exc-3 · §3 bỏ Bước 3 (Zapier nhận webhook), Cảnh báo Slack đánh lại số Bước 4 → Bước 3 · bỏ chữ Zapier (cảnh báo = bắn webhook)Chưa xử lý refund; cờ chỉ reset bởi cron hằng tháng hoặc khi nâng limit trên BPS (BR_9.8.6, 2026-09-18)Refund: GREATEST(0, volume - refund); cờ được re-arm trong Check MID Capacity khi volume < 80%; không có trigger riêngQnA_BACKGROUND_MECHANISMS_CRON.md [BG-024] [BG-025] — khách trả lời 2026-11-03
2026-09-18v1.0 → v1.1§4 Mô hình dữ liệu Q1 đã đóng · §6 Exc-2/Exc-3 đã giải quyết · §7 thêm BR_9.8.6/7/8 · §8 mở rộng AC-9.8-06 + thêm AC-9.8-07/08/09Q1: trường warning_80_fired chưa được xác nhận. Exc-2: guard chỉ ghi log cảnh báo, không có cảnh báo chủ động. Exc-3: [OPEN] — chưa quy định retry hay fallback.Q1 đã đóng: warning_80_fired BOOLEAN NOT NULL DEFAULT FALSE được xác nhận cho Merchant_Routing_Config. Exc-2: limit null/zero nay kích hoạt cảnh báo Slack #ops-treasury (không dùng Freshdesk) ngoài cảnh báo phía server + HTTP 200. Exc-3: 3 lần retry với exponential backoff; khi hết retry, native Slack API fallback tới #dev_ops (bỏ qua Zapier). BR_9.8.6: reset thủ công khi nâng hạn mức. BR_9.8.7: guard null/zero + đặc tả cảnh báo Slack chủ động. BR_9.8.8: đặc tả retry + fallback.Client confirmed 2026-09-18
2026-09-03v1.0Khởi tạo tài liệu——Zapier Integration V7.pdf §Flow 30; RFQ_ Stack Trading Prop Tech V7.pdf §Check MID Capacity

UC_9.9 — Luồng 31: Giám sát Cạn kiệt Tổng hợp (Sev-1)

TrườngGiá trị
BA phụ tráchlinh.nguyen34
Ngày tạo2026-09-03
Phiên bảnv1.3
Tài liệu tham chiếuZapier Integration V7.pdf (§Flow 31 lines 2471–2479) · RFQ_ Stack Trading Prop Tech V7.pdf (§Calculate Volume Pacing lines 1460–1464; §Merchant_Routing_Config lines 847–855)

Danh mục UC

UC_IDTên use caseMô tả nghiệp vụ
UC_9.9Aggregate Exhaustion Monitor (Sev-1)Hằng ngày lúc 11:00 PM CST: Zapier Flow 31 gọi GET /calculate-volume-pacing. Nếu khối lượng dự phóng cuối tháng trên toàn bộ MID đang active vượt tổng công suất tổng hợp, bắn cảnh báo SEV-1 Slack tới Operations.

<a id="UC_9.9"></a>

UC_9.9 — Luồng 31: Giám sát Cạn kiệt Tổng hợp (Sev-1)

1. Tổng quan

TrườngNội dung
IDUC_9.9
Use CaseAggregate Exhaustion Monitor (Sev-1)
Mô tảHệ thống phòng vệ dự báo ở cấp vĩ mô. Mỗi ngày lúc 11:00 PM CST, Zapier Flow 31 gọi GET /calculate-volume-pacing để tính khối lượng dự phóng cuối tháng trên toàn bộ MID đang active. Nếu dự phóng vượt tổng công suất tổng hợp, một cảnh báo SEV-1 CRITICAL được gửi tới kênh Slack Operations. Bổ trợ cho UC_9.8 (Flow 30) vốn giám sát từng MID riêng lẻ — luồng này giám sát xu hướng tổng hợp toàn hệ thống để phát hiện đột biến khối lượng trước khi xảy ra cạn kiệt cuối tháng.
Zapier FlowFlow 31 (Aggregate Exhaustion Monitor)
Zapier TableMerchant_Routing_Config (PostgreSQL — do Middleware truy vấn, không phải Zapier truy vấn trực tiếp)
3rd PartySlack (gửi cảnh báo SEV-1)

2. Trigger

Loại: Theo lịch — Zapier Cron Job.

Lịch chạy: Hằng ngày lúc 11:00 PM CST.

(Nguồn: Zapier Integration V7.pdf §Flow 31 line 2473)


3. Luồng cơ bản

Bước 1 — Trigger theo lịch (Zapier)

Scheduler tích hợp sẵn của Zapier kích hoạt lúc 11:00 PM CST hằng ngày và gọi GET /calculate-volume-pacing trên Middleware.

(Nguồn: Zapier Integration V7.pdf §Flow 31 lines 2473–2474)

Bước 2 — Tính toán pacing (GET /calculate-volume-pacing)

Middleware thực thi thuật toán sau trên Merchant_Routing_Config:

2a. Tổng hợp (chỉ MID active):

SELECT
  SUM(current_mtd_volume) AS total_mtd_volume,
  SUM(monthly_limit)      AS total_aggregate_capacity
FROM merchant_routing_config
WHERE is_active = TRUE;

2b. Tính Khối lượng trung bình ngày (ADV):

N = current day of month (e.g. 15)
ADV = total_mtd_volume / N

2c. Dự phóng khối lượng cuối tháng:

T = total days in current calendar month (e.g. 30 for September)
Projected_EOM_Volume = ADV × T

2d. Kiểm tra cạn kiệt:

IF Projected_EOM_Volume >= total_aggregate_capacity:
  projected_exhaustion = true
ELSE:
  projected_exhaustion = false

(Nguồn: RFQ_ Stack Trading Prop Tech V7.pdf §Calculate Volume Pacing lines 1460–1464; Zapier Integration V7.pdf §Flow 31 lines 2474–2475)

Bước 3 — Zapier Filter

Zapier đánh giá response. Chỉ tiếp tục nếu projected_exhaustion = true. Nếu false, luồng kết thúc âm thầm — không gửi tin nhắn Slack.

(Nguồn: Zapier Integration V7.pdf §Flow 31 line 2475)

Bước 4 — Cảnh báo Slack SEV-1

Nếu projected_exhaustion = true, gửi cảnh báo SEV-1 CRITICAL tới #ops-treasury (hoặc kênh Operations được cấu hình).

Nội dung tin nhắn Slack:

🚨 [SEV-1 CRITICAL] AGGREGATE VOLUME PACING EXHAUSTION DETECTED
Current Day: [current_day_of_month] / [total_days_in_month]
Total MTD Volume: $[total_mtd_volume]
Average Daily Volume: $[average_daily_volume]/day
Projected EOM Volume: $[projected_eom_volume]
Total Aggregate Capacity: $[total_aggregate_capacity]

CRITICAL: Aggregate pacing indicates all merchant accounts will exhaust
capacity before month end. Immediate intervention required.

(Nguồn: Zapier Integration V7.pdf §Flow 31 lines 2476–2479)


4. API Endpoint

GET /calculate-volume-pacing
TrườngGiá trị
MethodGET
AuthZapier Webhook Signature / HMAC (internal — not public)
Bên gọiZapier Flow 31 (theo lịch hằng ngày)
InputKhông có

Response payload (đường đi bình thường):

{
  "calculation_date": "2026-09-03",
  "current_day_of_month": 3,
  "total_days_in_month": 30,
  "total_mtd_volume": 45000.00,
  "total_aggregate_capacity": 450000.00,
  "average_daily_volume": 15000.00,
  "projected_eom_volume": 450000.00,
  "projected_exhaustion": true,
  "active_mids_count": 4
}

Response payload (Edge Case 2 — không có MID active):

{
  "projected_exhaustion": false,
  "total_aggregate_capacity": 0,
  "active_mids_count": 0,
  "status_code": "NO_ACTIVE_MIDS_WARNING",
  "message": "All payment MIDs are currently inactive. Ops Config Warning dispatched."
}
TrườngKiểuMô tả
calculation_dateDATENgày chạy phép tính
current_day_of_monthINTN — mẫu số cho phép tính ADV
total_days_in_monthINTT — hệ số nhân cho dự phóng EOM
total_mtd_volumeDECIMALTổng current_mtd_volume của mọi MID có is_active = TRUE
total_aggregate_capacityDECIMALTổng monthly_limit của mọi MID có is_active = TRUE
average_daily_volumeDECIMALtotal_mtd_volume / current_day_of_month
projected_eom_volumeDECIMALaverage_daily_volume × total_days_in_month
projected_exhaustionBOOLEANtrue nếu projected_eom_volume >= total_aggregate_capacity; luôn là false khi guard clause kích hoạt
active_mids_countINTSố MID có is_active = TRUE tại thời điểm tính; giá trị 0 kích hoạt guard clause
status_codeSTRINGChỉ xuất hiện trên đường guard clause: "NO_ACTIVE_MIDS_WARNING"
messageSTRINGGiải thích dễ đọc, chỉ xuất hiện trên đường guard clause

(Nguồn: RFQ_ Stack Trading Prop Tech V7.pdf §Calculate Volume Pacing lines 1460–1464)


5. Cổng an toàn & Trường hợp biên

Edge Case 1 — Chặn nhiễu đầu tháng (thời gian ân hạn 3 ngày dương lịch)

Vào ngày 1 hằng tháng, các giá trị current_mtd_volume vừa được reset về 0.00. ADV sẽ gần bằng 0 và Projected_EOM_Volume sẽ ở mức tối thiểu — phép toán tự nhiên chặn các false positive. Tuy nhiên, vài ngày đầu tháng có thể cho ra dự phóng gây hiểu lầm do mẫu số ADV có ít dữ liệu.

Hành vi đã xác nhận (thời gian ân hạn 3 ngày dương lịch — Option B):

Trong 3 ngày dương lịch đầu tiên của mỗi tháng (ngày 1, 2, 3), Middleware PHẢI bỏ qua hoàn toàn các phép tính pacing của Flow 31 và trả về projected_exhaustion = false vô điều kiện. Từ ngày 4 trở đi, phép toán pacing tiêu chuẩn tiếp tục.

IF current_day_of_month <= 3:
  → return { projected_exhaustion: false }  // Grace period — skip pacing math
ELSE:
  → Execute standard ADV / Projected_EOM_Volume calculation

Lý do: Cổng dựa trên thời gian dễ dự đoán hơn ngưỡng khối lượng tối thiểu. Nó loại bỏ sự mơ hồ về việc một ngày khối lượng thấp là do chủ ý chặn hay do vấn đề cấu hình, và cho phép ngày 4 là điểm bắt đầu sạch của dữ liệu xu hướng đáng tin cậy.

(Nguồn: client confirmed 2026-09-18)

Edge Case 2 — Tất cả MID không active (total_aggregate_capacity = 0)

Nếu không có MID nào có is_active = TRUE, thì total_aggregate_capacity = 0. Nếu không có guard clause, sẽ xảy ra hai chế độ lỗi:

  1. Chia cho 0 / NaN / Infinity khi tính tỷ lệ khối lượng.
  2. SEV-1 dương tính giả (false-positive): Projected_EOM_Volume (≥ 0) >= 0 luôn là true → bắn một cảnh báo CRITICAL sai. Điều này mô tả sai sự cố thành cạn kiệt khối lượng trong khi nguyên nhân thực là vấn đề cấu hình/vô hiệu hóa gateway.

Hành vi đã xác nhận (Guard Clause — phía server):

Step 1: Query active MIDs
  activeMIDs = SELECT * FROM Merchant_Routing_Config WHERE is_active = TRUE

Step 2: Compute total_aggregate_capacity
  total_aggregate_capacity = SUM(activeMIDs.monthly_limit)

GUARD CLAUSE:
  IF activeMIDs.length = 0 OR total_aggregate_capacity = 0:
    → log WARN: "All payment MIDs inactive — suppressing SEV-1 exhaustion alert"
    → return { projected_exhaustion: false, status_code: "NO_ACTIVE_MIDS_WARNING",
               active_mids_count: 0, total_aggregate_capacity: 0 }
    → Middleware MUST additionally dispatch a separate Ops Config Warning
      to **`#ops-treasury`** (distinct from SEV-1, NOT routed to Freshdesk):
      "🚨 CRITICAL CONFIGURATION ERROR: All MIDs are currently marked inactive."

Step 3 onwards: Standard pacing math — only executes when active_mids_count > 0

Ma trận kịch bản cảnh báo:

Kịch bảnMID activetotal_aggregate_capacityprojected_exhaustionHành động của hệ thống
Bình thường≥ 1> 0falseKhông cảnh báo
Pacing khối lượng cao≥ 1> 0trueSEV-1 tới #ops-treasury
Edge Case 200falseChặn SEV-1. Ghi log WARNING. Gửi Ops Config Warning tới #ops-treasury (không phải SEV-1, không qua Freshdesk).

(Nguồn: client confirmed 2026-09-17)

Edge Case 3 — Endpoint không khả dụng

Nếu GET /calculate-volume-pacing trả về khác 200 hoặc timeout, Flow 31 thực thi trình xử lý ngoại lệ hai giai đoạn:

Giai đoạn 1 — Tự động retry (backoff 3 lần): Zapier tự động retry 3 lần, mỗi lần cách nhau 5 phút (tổng cửa sổ: 15 phút). Tự phục hồi khi gặp lỗi mạng thoáng qua hoặc Middleware khởi động lại.

Giai đoạn 2 — Cảnh báo Slack SEV-2 (sau 3 lần retry thất bại): Nếu cả 3 lần retry thất bại, Zapier kích hoạt cảnh báo SEV-2 WARNING tới #ops-treasury và #dev_ops.

Nội dung tin nhắn SEV-2:

🟡 [SEV-2 WARNING] Volume Pacing Monitoring Endpoint Unavailable
• Event: Zapier Flow 31 failed to fetch MID volume pacing metrics.
• Target Endpoint: GET /calculate-volume-pacing
• Status: Failed after 3 retries (Non-200 / Timeout).
• Impact: Daily aggregate merchant capacity check was SKIPPED tonight.
• Action Required: @dev_ops please inspect Middleware Hub logs in AWS CloudWatch.

Phân nhánh lỗi của Flow 31:

Zapier Flow 31: GET /calculate-volume-pacing
         │
         ├─ HTTP 200 OK
         │    ├─ projected_exhaustion = true  → SEV-1 Slack Alert (#ops-treasury)
         │    └─ projected_exhaustion = false → Pass (no alert)
         │
         └─ Non-200 / Timeout
              └─ Auto-retry 3×, 5 min intervals
                   └─ Persistent fail (all 3 retries exhausted)
                        └─ SEV-2 Slack Alert (#ops-treasury + #dev_ops)

(Nguồn: client confirmed 2026-09-17)


6. Quy tắc nghiệp vụ

Rule IDQuy tắcNguồn
BR_9.9.1Flow 31 chạyhằng ngày lúc 11:00 PM CST qua trigger theo lịch của Zapier. KHÔNG được kích hoạt bởi sự kiện thanh toán và KHÔNG phải là cron của Middleware.Zapier Integration V7.pdf §Flow 31 line 2473
BR_9.9.2Mẫu số ADV là ngày hiện tại trong tháng tại thời điểm tính. Trong 3 ngày dương lịch đầu tiên của mỗi tháng (current_day_of_month <= 3), Middleware PHẢI bỏ qua hoàn toàn phép tính pacing và trả về projected_exhaustion = false vô điều kiện — thời gian ân hạn 3 ngày dương lịch ngăn cảnh báo SEV-1 dương tính giả do mẫu số ADV ở mức nhiễu khi bắt đầu chu kỳ mới. Phép toán pacing tiêu chuẩn tiếp tục từ ngày 4 trở đi.RFQ_ Stack Trading Prop Tech V7.pdf §Calculate Volume Pacing lines 1460–1464; client confirmed 2026-09-18
BR_9.9.3Chỉ các MID có is_active = TRUE được đưa vào cả hai phép tổng hợp total_mtd_volume và total_aggregate_capacity.RFQ_ Stack Trading Prop Tech V7.pdf §Merchant_Routing_Config lines 847–855
BR_9.9.4Zapier PHẢI chặn đầu ra Slack khi projected_exhaustion = false. Cảnh báo SEV-1 chỉ bắn khi và chỉ khi projected_exhaustion = true.Zapier Integration V7.pdf §Flow 31 line 2475
BR_9.9.5Cảnh báo SEV-1 chỉ mang tính thông tin. Nó KHÔNG tự động vô hiệu hóa MID, định tuyến lại lưu lượng hay sửa Merchant_Routing_Config. Việc khắc phục do Ops thực hiện thủ công.Zapier Integration V7.pdf §Flow 31 lines 2476–2479
BR_9.9.6Zapier Flow 31 trên Production PHẢI chỉ gọi endpoint Middleware Production. Cấm gọi chéo môi trường (prod → staging DB).Client spec 2026-09-03
BR_9.9.7Reset hằng tháng (dùng chung với UC_9.8 / BR_9.8.4): current_mtd_volume được reset về 0.00 cho toàn bộ MID vào 00:00 UTC ngày 1 hằng tháng. Việc này reset đường cơ sở ADV cho chu kỳ tính toán tiếp theo của Flow 31.RFQ_ Stack Trading Prop Tech V7.pdf §Merchant_Routing_Config line 222
BR_9.9.8Guard Clause — Công suất tổng hợp bằng 0: Nếu active_mids_count = 0 HOẶC total_aggregate_capacity = 0, GET /calculate-volume-pacing PHẢI trả về projected_exhaustion = false ngay lập tức mà không thực thi phép toán pacing. Ngăn (a) lỗi chia cho 0 và (b) cảnh báo SEV-1 dương tính giả do phép so sánh luôn đúng Projected_EOM_Volume >= 0. Middleware PHẢI ghi log WARNING và gửi một Ops Config Warning riêng tới Slack #ops-treasury (KHÔNG phải SEV-1, KHÔNG qua Freshdesk). Nội dung cảnh báo: "🚨 CRITICAL CONFIGURATION ERROR: All MIDs are currently marked inactive." Response bao gồm status_code: "NO_ACTIVE_MIDS_WARNING". Nguyên nhân gốc (tất cả MID không active) là vấn đề cấu hình, không phải sự kiện cạn kiệt khối lượng — loại cảnh báo PHẢI khác tương ứng.Client confirmed 2026-09-17; channel confirmed 2026-09-18
BR_9.9.9Flow 31 Endpoint Failure — Retry + SEV-2: Nếu GET /calculate-volume-pacing trả về khác 200 hoặc timeout, Zapier PHẢI retry 3 lần cách nhau 5 phút (Giai đoạn 1). Nếu cả 3 lần retry thất bại, Zapier kích hoạt cảnh báo SEV-2 WARNING tới #ops-treasury và #dev_ops (Giai đoạn 2). Tin nhắn SEV-2 phải bao gồm: tên endpoint, trạng thái lỗi, tuyên bố tác động (kiểm tra hằng ngày bị bỏ qua), và yêu cầu hành động @dev_ops kèm tham chiếu AWS CloudWatch.Client confirmed 2026-09-17

7. Mối quan hệ với UC_9.8 (Flow 30)

Khía cạnhUC_9.8 — Flow 30UC_9.9 — Flow 31
Phạm viMID riêng lẻTất cả MID active (tổng hợp)
TriggerThời gian thực, theo từng giao dịch thanh toánTheo lịch, hằng ngày 11:00 PM CST
Ngưỡng80% monthly_limit của một MID100% tổng công suất tổng hợp (EOM dự phóng)
Loại cảnh báoWarningSEV-1 CRITICAL
Mục đíchPhát hiện một MID chạy quá nóngPhát hiện đột biến khối lượng toàn hệ thống trước cuối tháng
Khắc phụcLiên hệ processor để nâng hạn mức cho một MIDKhẩn cấp: liên hệ tất cả processor + onboard các MID dự phòng + điều chỉnh trọng số round-robin

8. Tiêu chí chấp nhận

IDKịch bảnKết quả mong đợi
AC-9.9-01Ngày 15 của tháng 30 ngày;total_mtd_volume = 300,000; total_aggregate_capacity = 400,000 → ADV = 20,000; EOM dự phóng = 600,000projected_exhaustion = true; cảnh báo SEV-1 Slack được gửi tới #ops-treasury
AC-9.9-02Ngày 15 của tháng 30 ngày;total_mtd_volume = 150,000; total_aggregate_capacity = 400,000 → ADV = 10,000; EOM dự phóng = 300,000projected_exhaustion = false; không gửi cảnh báo Slack
AC-9.9-03Ngày 1 của tháng; total_mtd_volume = 1,000 (vừa reset); current_day_of_month = 1projected_exhaustion = false (trong thời gian ân hạn 3 ngày — bỏ qua phép toán pacing); không có cảnh báo Slack
AC-9.9-04total_aggregate_capacity = 0 (tất cả MID không active — active_mids_count = 0)Guard clause kích hoạt: projected_exhaustion = false; status_code = "NO_ACTIVE_MIDS_WARNING"; ghi log WARNING; gửi Ops Config Warning (không phải SEV-1); không có lỗi 500; KHÔNG thực thi phép toán pacing
AC-9.9-05projected_exhaustion = trueTin nhắn Slack chứa đủ 7 trường:current_day_of_month, total_days_in_month, total_mtd_volume, average_daily_volume, projected_eom_volume, total_aggregate_capacity và nhãn SEV-1
AC-9.9-06Cron chạy lúc 11:00 PM CST vào một ngày bất kỳFlow 31 thực thi; gọi endpoint Production (không phải staging)
AC-9.9-07Ngày 20;projected_exhaustion = falseKhông có tin nhắn Slack; Zapier filter dừng luồng âm thầm

9. Câu hỏi mở

IDƯu tiênCâu hỏiGiả định
Q1MIs the $5,000 early-month suppression threshold correct? Is Day 1 alone sufficient without a volume floor?Đã giải quyết 2026-09-18: Option B được xác nhận — thời gian ân hạn 3 ngày dương lịch. current_day_of_month <= 3 bỏ qua hoàn toàn phép toán pacing. Không có volume floor. Đã cập nhật BR_9.9.2 + Edge Case 1 + AC-9.9-03.
Q2MBehavior when total_aggregate_capacity = 0 (all MIDs inactive)?Đã giải quyết 2026-09-17: Guard clause — trả về projected_exhaustion = false + status_code: "NO_ACTIVE_MIDS_WARNING" + ghi log WARN + gửi Ops Config Warning tới #ops-treasury. Phép toán pacing bị chặn. Đã thêm BR_9.9.8.
Q3MWhat does Flow 31 do if GET /calculate-volume-pacing returns non-200 or times out?Đã giải quyết 2026-09-17: backoff 3 lần retry (cách nhau 5 phút) → SEV-2 tới #ops-treasury + #dev_ops. Đã thêm BR_9.9.9. Đã ghi nhận Edge Case 3.

10. Lịch sử thay đổi

NgàyPhiên bảnTóm tắtTrướcSauNguồn
2026-09-18v1.2 → v1.3Viết lại Edge Case 1 (ân hạn 3 ngày thay thế volume floor $5,000); kênh Ops Config Warning của Edge Case 2 được chốt là #ops-treasury; cập nhật BR_9.9.2; cập nhật BR_9.9.8 kèm kênh + nội dung cảnh báo; cập nhật AC-9.9-03; đóng Q1 + Q3 trong Câu hỏi mở; tăng phiên bảnEdge Case 1: $5,000 volume floor, [OPEN — Q1]. BR_9.9.2: logic volume floor. AC-9.9-03: "below $5,000 floor". Kênh Edge Case 2: "TBD by Ops team". Q1 + Q3: mở.Edge Case 1: ân hạn 3 ngày dương lịch — current_day_of_month <= 3 bỏ qua hoàn toàn phép toán pacing. BR_9.9.2: cổng dựa trên thời gian. AC-9.9-03: logic ân hạn. Kênh Edge Case 2: #ops-treasury (KHÔNG phải Freshdesk). Q1 + Q3: đã giải quyết.Client confirmed 2026-09-18
2026-09-17v1.0 → v1.1Mở rộng Edge Case 2 + BR_9.9.8 + AC-9.9-04 + response payload + đóng Q2Edge Case 2: [OPEN — Q2] — hành vi guard chưa được quy định. AC-9.9-04: stub tối thiểu. Response payload: 8 trường.Edge Case 2: đặc tả guard clause đầy đủ — kiểm tra active_mids_count = 0 trước phép toán pacing, status code NO_ACTIVE_MIDS_WARNING, Ops Config Warning (không phải SEV-1), thêm pseudocode + ma trận cảnh báo. Đã thêm BR_9.9.8. AC-9.9-04: mở rộng chi tiết guard clause. Response payload: 11 trường (thêm active_mids_count, status_code, message). Đã đóng Q2.Client confirmed 2026-09-17
2026-09-03v1.0Khởi tạo tài liệu——Zapier Integration V7.pdf §Flow 31; RFQ_ Stack Trading Prop Tech V7.pdf §Calculate Volume Pacing

UC_9.11 — Luồng 34: Đồng bộ Sổ cái Lương Rippling

TrườngGiá trị
UC_IDUC_9.11
Phiên bảnv1.1
Cập nhật lần cuối2026-11-04
BA PiClinh.nguyen34
Danh mụcBACKGROUND MECHANISMS & CRON JOBS
Mô-đunLuồng 34 (UC_4.15.2)
Chức năngĐồng bộ Sổ cái Lương Rippling
Tài liệu tham chiếuZapier Integration V7.pdf (§Flow 34; §7.2 Flow 34 Payroll Trigger — Option A/B) · RFQ_ Stack Trading Prop Tech V7.pdf (§Record Immutable Ledger POST /api/ledger/record; §3.6.1 Smart Contract Architecture; §Audit Requirements CFTC 1.31) · StackTrading_Backend_Technical_Proposal_v1.6.docx (§Option B provider list) · QnA_STAGE5_PAYOUT_WITHDRAWAL.md (A-33)

1. Danh mục UC

UC_IDChức năngMô tả
UC_9.11Luồng 34 — Đồng bộ Sổ cái Lương RipplingKhi Rippling thanh toán xong một kỳ lương hai tuần/hàng tháng cho trader W-2 đang hoạt động, Zapier gọi POST /api/ledger/record để mint một event W2 Payroll Executed trên contract StackTradingLedger của Polygon PoS. Middleware lưu tx_hash trả về vào PostgreSQL. Các lần Rippling gửi trùng được loại bỏ (dedup) theo provider_event_id / receipt_hash.

UC_9.11 — Luồng 34: Đồng bộ Sổ cái Lương Rippling

TrườngGiá trị
Use CaseĐồng bộ Sổ cái Lương Rippling
Mô tảCông bố bằng chứng chi trả lương W-2 (lương cơ bản + phúc lợi) lên Sổ cái Bất biến (Immutable Ledger). Mỗi kỳ lương Rippling định kỳ theo lịch (hai tuần/hàng tháng) đã thanh toán cho một trader W-2 đang hoạt động tạo ra đúng một event CorporateMetricVerified trên Polygon PoS, với Rippling Transaction ID làm verificationHash. Các kỳ lương off-cycle bị bỏ qua.
Tác nhânHệ thống (Rippling → Zapier → Middleware Hub → Polygon PoS)
Zapier FlowFlow 34
Nguồn triggerRippling webhook — Payroll Run Cleared (PAYROLL_CLEARED)
3rd PartyRippling · Zapier · Alchemy RPC · Polygon PoS
Middleware EndpointPOST /api/ledger/record
UC liên quanUC_7.4 Immutable Ledger (Payout) · UC_4.15.2 Career & HR Widget · Flow 5 (thưởng hiệu suất), Flow 9 (severance), Flow 17 (vesting của Pod Leader) — mỗi luồng tự ghi khoản chi trả W-2 off-cycle của mình lên sổ cái, xem BR_9.11.6

2. Trigger

Event: Rippling gửi webhook khi một kỳ lương hai tuần hoặc hàng tháng định kỳ theo lịch được cleared (tiền đã giải ngân).

Các kỳ lương off-cycle (thưởng hiệu suất Flow 5, severance Flow 9, vesting Pod Leader Flow 17 — đều qua Rippling Off-Cycle Payroll API) không được Luồng 34 xử lý, kể cả khi Rippling gửi cùng một webhook. Xem Alt-3.

NguồnEventĐường chuyển phát
RipplingPayroll Run Cleared (PAYROLL_CLEARED)Option A — trực tiếp đến Zapier (Rippling không nằm trong danh sách provider hardened-ingress của Option B)

(Nguồn: Zapier Integration V7.pdf §Flow 34; §7.2 Option A/B · StackTrading_Backend_Technical_Proposal_v1.6.docx §Option B provider list — Rippling được đánh dấu "—")

⚠️ Option B (POST /webhooks/payroll/rippling → POST /zapier/events/payroll_cleared) được mô tả trong Zapier Integration V7.pdf §7.2 nhưng không nằm trong phạm vi Option B đã được chấp thuận (8 provider: NMI, Triple-A, Skrill, Nomupay, EBANX, Dusupay, Veriff, Dots). Xem Q1.


3. Điều kiện tiên quyết

IDĐiều kiện tiên quyết
P1Webhook subscription của Rippling cho Payroll Run Cleared được cấu hình trỏ tới catch hook của Zapier Flow 34.
P2Payload chứa Rippling Transaction ID (dùng làm receipt_hash) và số tiền lương (Total_Amount).
P3Worker trên Rippling được ánh xạ tới một người dùng Stack Trading (trader_id) có Employment_Type = 'W-2' và trạng thái đang hoạt động.
P4Contract StackTradingLedger đã được triển khai trên Polygon PoS Mainnet; private key của owner wallet phía server khả dụng cho Middleware (môi trường bảo mật).

4. Hậu điều kiện

#Hậu điều kiện
1Một event CorporateMetricVerified được phát trên Polygon PoS với metricCategory = "W2 Payroll Executed".
2tx_hash của Polygon được ghi vào PostgreSQL (bản ghi sổ cái) theo trader_id + receipt_hash.
3receipt_hash / provider_event_id được đánh dấu đã xử lý — mọi lần gửi lại đều là no-op.
4Việc thực thi được ghi vào BPS_Audit_Log.
5Event hiển thị trên GET /public/ledger (ticker Live Payout Ledger) sau khi cache được làm mới.
6Zap kết thúc.

5. Luồng cơ bản

Bước 1 — Nhận webhook (Zapier)

Zapier catch hook nhận payload Rippling Payroll Run Cleared.

Bước 2 — Filter: chỉ trader W-2 đang hoạt động, chỉ kỳ lương định kỳ (Zapier)

  • Ánh xạ Rippling worker sang trader_id.
  • Chỉ tiếp tục nếu trader là trader W-2 đang hoạt động của Stack Trading (Employment_Type = 'W-2', tài khoản active).
  • Chỉ tiếp tục nếu kỳ lương là kỳ lương định kỳ theo lịch (không phải off-cycle). Off-cycle → dừng (xem Alt-3).
  • Ngược lại → dừng (xem Alt-2).
  • ⚠️ Trường trong payload Rippling dùng để phân biệt kỳ lương định kỳ với kỳ lương off-cycle chưa có trong nguồn — Dev cần xác nhận với Rippling API.

(Nguồn: Zapier Integration V7.pdf §Flow 34 — "Ensure payload corresponds to an active Stack Trading W2 Trader Only"; QnA_BACKGROUND_MECHANISMS_CRON.md [BG-016] — bảng tính của khách hàng 2026-11-04)

Bước 3 — Kiểm tra dedup

Trước khi gọi sổ cái, kiểm tra provider_event_id (Rippling event / transaction ID) với dedup store. Nếu đã xử lý → Alt-1.

(Nguồn: Zapier Integration V7.pdf §7.2 Option A — "Store provider_event_id in DB to dedup (required for payroll/ledger events)")

Bước 4 — Gọi Middleware POST /api/ledger/record

TrườngGiá trị
trader_idUUID trader toàn cục
metric_category"W2 Payroll Executed" (cố định)
metric_value"$[Total_Amount] Base + Benefits Paid" — số tiền định dạng 2 chữ số thập phân kèm dấu phân cách hàng nghìn, ví dụ "$4,500.00 Base + Benefits Paid"
dateHôm nay (ISO 8601 UTC)
receipt_hashRippling Transaction ID

(Nguồn: Zapier Integration V7.pdf §Flow 34)

Bước 5 — Middleware mint trên Polygon

  1. Xác thực chữ ký Zapier JWT. Từ chối nếu không hợp lệ (Exc-1).
  2. Khởi tạo Ethers.js wallet phía server bằng private key từ môi trường bảo mật.
  3. Thực thi contract.recordMetric(_traderId, _metricCategory, _metricValue, _timestamp, _verificationHash) qua Alchemy RPC, với ánh xạ: trader_id → _traderId, metric_category → _metricCategory, metric_value → _metricValue, date → _timestamp, receipt_hash → _verificationHash.
  4. Chờ block confirmation.
  5. Ghi tx_hash vào PostgreSQL; log vào BPS_Audit_Log.
  6. Trả về HTTP 200 { "status": "success", "tx_hash": "0x..." }.

(Nguồn: RFQ_ Stack Trading Prop Tech V7.pdf §Record Immutable Ledger; §3.6.1 Smart Contract Architecture)

Bước 6 — Kết thúc Zap.


6. Luồng thay thế

Alt-1 — Gửi trùng

  • provider_event_id / receipt_hash đã được xử lý.
  • Middleware không gọi lại recordMetric(); trả về HTTP 200 cùng tx_hash đã lưu trước đó.
  • Không có event sổ cái thứ hai; không có dòng ticker thứ hai.

Alt-2 — Payload không phải trader W-2 đang hoạt động

  • Filter thất bại (contractor, đã chấm dứt, worker không xác định, nhân viên không phải trader).
  • Zap dừng ở Bước 2. Không gọi sổ cái. Không có lỗi.

Alt-3 — Rippling báo một kỳ lương off-cycle

  • Zap dừng ở Bước 2. Không gọi sổ cái. Không có lỗi.
  • Các khoản chi trả W-2 off-cycle đã được chính luồng của chúng ghi nhận qua POST /api/ledger/record: Flow 5 (Performance Bonus, Path C), Flow 9 (Severance, Path C), Flow 17 (Pod Leader Vesting, nhánh US W-2). Ghi lại lần nữa trong Luồng 34 sẽ tạo bản ghi on-chain trùng lặp.

(Nguồn: QnA_BACKGROUND_MECHANISMS_CRON.md [BG-016] — bảng tính của khách hàng 2026-11-04; Zapier Integration V7.pdf §Flow 5 Path C, §Flow 9 Path C; RFQ_ Stack Trading Prop Tech V7.pdf §Process Pod Vesting — Immutable Ledger Logging)


7. Luồng ngoại lệ

Exc-1 — Zapier JWT không hợp lệ / hết hạn

  • Middleware trả về HTTP 401; không gọi contract; log vào BPS_Audit_Log với execution_status = REJECTED.

Exc-2 — Lỗi Polygon RPC / giao dịch

  • recordMetric() thất bại hoặc không nhận được confirmation.
  • Middleware trả về non-2xx; không ghi nhận là đã xử lý (để retry có thể mint).
  • Áp dụng Zapier retry (xem Q3). Khi thất bại cuối cùng → cảnh báo Slack tới Ops (kênh theo slack_channel_usage.md, xem Q3).

Exc-3 — Không thể ánh xạ trader_id từ Rippling worker

  • Xử lý như Alt-2 (dừng) và ghi log vào BPS_Audit_Log với giá trị UNMAPPED_RIPPLING_WORKER để xem xét thủ công. (Giả định của BA — xem Q4)

8. Quy tắc nghiệp vụ

BR_9.11.1: Phạm vi — Chỉ trader W-2 đang hoạt động

Luồng 34 chỉ ghi nhận lương cho trader W-2 đang hoạt động của Stack Trading. Contractor quốc tế được xử lý bởi Luồng 36 (UC_9.13).

(Nguồn: Zapier Integration V7.pdf §Flow 34)

BR_9.11.2: Ánh xạ sổ cái cố định

metric_category luôn là "W2 Payroll Executed". Định dạng metric_value là "$[Total_Amount] Base + Benefits Paid", số tiền định dạng 2 chữ số thập phân (ví dụ "$2,500.00 Base + Benefits Paid"). receipt_hash luôn là Rippling Transaction ID.

(Nguồn: Zapier Integration V7.pdf §Flow 34; QnA_BACKGROUND_MECHANISMS_CRON.md [BG-016])

BR_9.11.3: Một kỳ lương = Một event sổ cái (idempotency)

provider_event_id phải được lưu và kiểm tra trước khi mint. Các lần retry của Rippling không bao giờ được tạo ra event on-chain thứ hai. Bản trùng trả về HTTP 200 cùng tx_hash gốc.

(Nguồn: Zapier Integration V7.pdf §7.2 Option A)

BR_9.11.4: Ghi sổ cái chỉ dành cho Owner, chỉ dạng Event

Contract không lưu state; dữ liệu chỉ được ghi dưới dạng event log CorporateMetricVerified. Chỉ owner wallet mới được gọi recordMetric().

(Nguồn: RFQ_ Stack Trading Prop Tech V7.pdf §3.6.1)

BR_9.11.5: tx_hash được lưu trước khi trả response thành công

Middleware chỉ trả về thành công cho Zapier sau khi có block confirmation và sau khi tx_hash được ghi vào PostgreSQL.

(Nguồn: RFQ_ Stack Trading Prop Tech V7.pdf §Record Immutable Ledger — "Await confirmation and write the Polygon transaction hash to PostgreSQL")

BR_9.11.6: Luồng 34 chỉ ghi lương định kỳ — Các khoản chi trả off-cycle do chính luồng của chúng ghi nhận

Luồng 34 chỉ ghi nhận lương W-2 định kỳ theo lịch (lương cơ bản, phúc lợi). Các khoản chi trả W-2 off-cycle được ghi nhận bởi luồng kích hoạt chúng, qua POST /api/ledger/record: Flow 5 (Performance Bonus), Flow 9 (Severance), Flow 17 (Pod Leader Vesting). Luồng 34 lọc bỏ các kỳ lương off-cycle để mỗi khoản thanh toán tạo ra đúng một bản ghi sổ cái.

(Nguồn: QnA_BACKGROUND_MECHANISMS_CRON.md [BG-016] — bảng tính của khách hàng 2026-11-04, thay thế giả định trong QnA_STAGE5_PAYOUT_WITHDRAWAL.md A-33 rằng Luồng 34 ghi nhận các khoản chi trả off-cycle Path C; Zapier Integration V7.pdf §Flow 5, §Flow 9; RFQ_ Stack Trading Prop Tech V7.pdf §Process Pod Vesting)

BR_9.11.7: Lưu trữ audit

Mọi lần thực thi đều được ghi vào BPS_Audit_Log. Thời hạn lưu trữ: 5 năm + 1 tháng (CFTC 1.31 / NFA); các object cũ hơn 25 tháng được chuyển sang cold storage.

(Nguồn: RFQ_ Stack Trading Prop Tech V7.pdf §Audit Requirements)


9. Tiêu chí chấp nhận

AC_IDLuồngCho trướcThìLoại
AC-9.11-01Happy pathPayroll Run Cleared cho trader W-2 đang hoạt động, $4,500.00, transaction ID mớiMột event CorporateMetricVerified với metricCategory = "W2 Payroll Executed", metricValue = "$4,500.00 Base + Benefits Paid", verificationHash = Rippling Transaction ID; tx_hash được lưu; HTTP 200Integration
AC-9.11-02Trùng lặpCùng một Rippling event được gửi hai lầnLần gọi thứ hai trả về HTTP 200 cùng tx_hash gốc; chỉ có một event on-chainIntegration
AC-9.11-03Filter — contractorPayload của worker không phải W-2Zap dừng ở filter; không gọi sổ cáiIntegration
AC-9.11-04Filter — inactivePayload của trader W-2 đã chấm dứtZap dừng; không gọi sổ cáiIntegration
AC-9.11-05JWT saiRequest có chữ ký không hợp lệHTTP 401; không gọi contract; dòng audit REJECTEDSecurity
AC-9.11-06Lỗi RPCAlchemy trả về lỗiTrả về non-2xx; event không được đánh dấu đã xử lý; retry mint đúng một lầnIntegration
AC-9.11-07Public ledgerAC-9.11-01 hoàn tấtEvent xuất hiện trong GET /public/ledger recent_events sau khi cache được làm mớiIntegration
AC-9.11-08Filter — off-cycleKỳ lương off-cycle của Rippling (ví dụ severance) được cleared cho trader W-2 đang hoạt độngZap dừng ở filter; không gọi sổ cái; Luồng 34 không tạo event on-chain nàoIntegration
AC-9.11-09Định dạng số tiềnKỳ lương định kỳ được cleared, $2,500metricValue = "$2,500.00 Base + Benefits Paid" (2 chữ số thập phân)Integration

10. Tham chiếu API

POST /api/ledger/record
TrườngGiá trị
CallerZapier (Luồng 34)
AuthChữ ký Zapier JWT

Request:

{
  "trader_id": "94a2b1c8-3f4e-4b21-a123-890abcdef123",
  "metric_category": "W2 Payroll Executed",
  "metric_value": "$4,500.00 Base + Benefits Paid",
  "date": "2026-03-15T18:00:00Z",
  "receipt_hash": "rip_pay_8830192a7c41f"
}

Response (HTTP 200):

{ "status": "success", "tx_hash": "0x..." }
TrườngKiểuBắt buộcMô tả
trader_idSTRINGCóUUID trader toàn cục
metric_categorySTRINGCó"W2 Payroll Executed"
metric_valueSTRINGCó"$[Total_Amount] Base + Benefits Paid"
dateSTRINGCóISO 8601 UTC
receipt_hashSTRINGCóRippling Transaction ID

(Nguồn: RFQ_ Stack Trading Prop Tech V7.pdf §Record Immutable Ledger)


11. Câu hỏi mở

IDƯu tiênCâu hỏiGiả định
Q1HRippling không nằm trong danh sách provider Option B. Luồng 34 được chuyển phát qua Option A (Rippling → Zapier trực tiếp) hay nên bổ sung Rippling vào Option B (POST /webhooks/payroll/rippling)?Option A; dedup thực hiện trong Middleware tại POST /api/ledger/record.
Q2MMột lần chạy off-cycle của Rippling (severance, client nói Luồng 34 bao gồm severance — A-33) có cũng kích hoạt Payroll Run Cleared không? Nếu có, metric_value vẫn ghi "Base + Benefits Paid"?✅ Đã trả lời 2026-11-04 — Luồng 34 bỏ qua các kỳ lương off-cycle; xem Alt-3, BR_9.11.6 ([BG-016]).
Q3MSố lần Zapier retry / backoff và kênh Slack khi thất bại cuối cùng không được nêu trong V7.Zapier tự động replay mặc định; cảnh báo tới kênh Ops.
Q4LMột Rippling worker không ánh xạ được nên phát cảnh báo Ops hay chỉ ghi dòng audit?Chỉ ghi dòng audit.
Q5LTotal_Amount là lương gộp (gross) hay thực nhận (net)? Tiền tệ luôn là USD?Gross, USD.

12. Lịch sử thay đổi

NgàyPhiên bảnThay đổiTrướcSauNguồn
2026-11-04v1.1§1 Mô tả, UC liên quan; §2 Trigger; §5 Bước 2 (filter off-cycle), Bước 4 định dạng metric_value; §6 Alt-3 (mới); §8 BR_9.11.2, BR_9.11.6 (viết lại); §9 AC-9.11-08/09 (mới); §11 Q2Luồng 34 được giả định cũng ghi nhận các kỳ lương off-cycle, gồm severance (A-33); BR_9.11.6 = chỉ so sánh Luồng 34 với Luồng 5Luồng 34 = chỉ lương định kỳ theo lịch; các khoản chi trả W-2 off-cycle do Flow 5 / Flow 9 / Flow 17 ghi nhận; metric_value 2 chữ số thập phânBảng tính của khách hàng 2026-11-04 [BG-016]; Zapier Integration V7.pdf §Flow 5, §Flow 9; RFQ V7 §Process Pod Vesting
2026-10-27v1.0Tạo tài liệu ban đầu—Đặc tả đầy đủ: trigger, filter W-2, dedup, mint sổ cái, BR_9.11.1–7, AC-9.11-01–07Zapier Integration V7.pdf §Flow 34, §7.2; RFQ_ Stack Trading Prop Tech V7.pdf §Record Immutable Ledger, §3.6.1; QnA A-33

UC_9.12 — Luồng 35: Đồng bộ Sổ cái PTO Rippling

TrườngGiá trị
UC_IDUC_9.12
Phiên bảnv1.2
Cập nhật lần cuối2026-11-05 (v1.2 — bảng tính của khách hàng 2026-11-04: chỉ số ngày nguyên; không ghi bút toán điều chỉnh khi hủy)
BA PiClinh.nguyen34
Danh mụcBACKGROUND MECHANISMS & CRON JOBS
Mô-đunLuồng 35 (UC_4.15.2)
Chức năngĐồng bộ Sổ cái PTO Rippling
Tài liệu tham chiếuCR-20261027-001 (Flow 13 hybrid — trader W-2 yêu cầu nghỉ phép trong Rippling) · Zapier Integration V7.pdf (§Flow 35; §Flow 13 Time-Off Management) · RFQ_ Stack Trading Prop Tech V7.pdf (§Record Immutable Ledger POST /api/ledger/record; §3.6.1 Smart Contract Architecture; §Audit Requirements)

1. Danh mục UC

UC_IDChức năngMô tả
UC_9.12Luồng 35 — Đồng bộ Sổ cái PTO RipplingKhi Rippling phê duyệt yêu cầu nghỉ phép của trader W-2, Zapier gọi POST /api/ledger/record để mint một event Corporate Benefits ([Days_Approved] Days PTO Approved (Paid Time Off)) trên Polygon PoS. Chỉ ghi sổ cái — việc gia hạn stagnation và khóa tài khoản thuộc Luồng 13 (UC_9.2).

UC_9.12 — Luồng 35: Đồng bộ Sổ cái PTO Rippling

TrườngGiá trị
Use CaseĐồng bộ Sổ cái PTO Rippling
Mô tảCông bố bằng chứng nghỉ phép có lương (phúc lợi doanh nghiệp) lên Sổ cái Bất biến (Immutable Ledger). Mỗi yêu cầu nghỉ phép được Rippling phê duyệt cho trader W-2 đang hoạt động tạo ra đúng một event CorporateMetricVerified với Rippling Request ID làm verificationHash.
Tác nhânHệ thống (Rippling → Zapier → Middleware Hub → Polygon PoS)
Zapier FlowFlow 35
Nguồn triggerRippling webhook — Time Off Request Approved
3rd PartyRippling · Zapier · Alchemy RPC · Polygon PoS
Middleware EndpointPOST /api/ledger/record
UC liên quanUC_9.2 Flow 13 Time-Off Management (Path A được kích hoạt bởi cùng webhook Rippling này) · UC_9.11 · UC_4.15.2

2. Trigger

Event: Webhook Rippling Time Off Request Approved → catch hook của Zapier Flow 35.

Upstream: trader W-2 yêu cầu nghỉ phép ngay trong Rippling và Rippling phê duyệt (CR-20261027-001). Cùng một webhook được phân nhánh tới hai Zap độc lập: Flow 35 (UC này — sổ cái) và Flow 13 Path A (UC_9.2 — gia hạn stagnation_deadline, khóa tài khoản, thông báo). Stack Trading không tạo bản ghi nghỉ phép trong Rippling.

(Nguồn: Zapier Integration V7.pdf §Flow 35 · CR-20261027-001 · UC_9.2 §2.1)


3. Điều kiện tiên quyết

IDĐiều kiện tiên quyết
P1Webhook subscription của Rippling cho Time Off Request Approved trỏ tới Zapier Flow 35.
P2Payload chứa Rippling Request ID và số ngày đã được phê duyệt (Days_Approved).
P3Worker được ánh xạ tới một trader W-2 đang hoạt động của Stack Trading (Employment_Type = 'W-2').
P4Contract StackTradingLedger và owner wallet khả dụng (xem UC_9.11 P4).

4. Hậu điều kiện

#Hậu điều kiện
1Một event CorporateMetricVerified với metricCategory = "Corporate Benefits".
2tx_hash được lưu trong PostgreSQL; việc thực thi được ghi vào BPS_Audit_Log.
3Rippling Request ID được đánh dấu đã xử lý (không mint trùng).
4Zap kết thúc. Luồng này không thay đổi stagnation_deadline hay trạng thái giao dịch.

5. Luồng cơ bản

Bước 1 — Nhận webhook (Zapier).

Bước 2 — Filter: trader W-2 đang hoạt động. Chỉ tiếp tục nếu payload tương ứng với trader W-2 đang hoạt động của Stack Trading; ngược lại dừng (Alt-2).

(Nguồn: Zapier Integration V7.pdf §Flow 35)

Bước 3 — Kiểm tra dedup trên Rippling Request ID. Nếu đã xử lý → Alt-1.

Bước 4 — Gọi POST /api/ledger/record

TrườngGiá trị
trader_idUUID trader toàn cục
metric_category"Corporate Benefits" (cố định)
metric_value"[Days_Approved] Days PTO Approved (Paid Time Off)" — Days_Approved là số nguyên (chỉ tính ngày trọn), ví dụ "3 Days PTO Approved (Paid Time Off)"
dateHôm nay (ISO 8601 UTC)
receipt_hashRippling Request ID

(Nguồn: Zapier Integration V7.pdf §Flow 35)

Bước 5 — Middleware mint trên Polygon — giống hệt UC_9.11 Bước 5 (xác thực JWT → Ethers.js wallet → recordMetric() qua Alchemy → chờ confirmation → lưu tx_hash → HTTP 200).

(Nguồn: RFQ_ Stack Trading Prop Tech V7.pdf §Record Immutable Ledger)

Bước 6 — Kết thúc Zap.


6. Luồng thay thế

Alt-1 — Gửi trùng: trả về HTTP 200 cùng tx_hash đã lưu; không mint lần hai.

Alt-2 — Không phải trader W-2 đang hoạt động: Zap dừng ở filter; không gọi sổ cái.


7. Luồng ngoại lệ

Exc-1 (JWT không hợp lệ → HTTP 401) và Exc-2 (lỗi Polygon RPC → non-2xx, không đánh dấu đã xử lý, Zapier retry) — giống UC_9.11 §7.

Exc-3 — Kỳ nghỉ sau đó bị hủy trong Rippling

  • Event on-chain là bất biến và không thể đảo ngược. Không ghi bút toán sổ cái điều chỉnh.
  • Việc mở lại tài khoản giao dịch và điều chỉnh stagnation_deadline do Ops xử lý thủ công — xem UC_9.2 Alt-5.

(Nguồn: QnA_BACKGROUND_MECHANISMS_CRON.md [BG-017], [BG-002] — bảng tính của khách hàng 2026-11-04)


8. Quy tắc nghiệp vụ

BR_9.12.1: Chỉ ghi sổ cái

Luồng 35 chỉ ghi event PTO lên Sổ cái Bất biến (Immutable Ledger). Việc gia hạn stagnation_deadline, TRIM_TO_COMPLIANCE và khóa thực thi (Rithmic / MT5 / TraderEvolution) thuộc Luồng 13 (UC_9.2 Steps A-3+) và không được thực thi lại tại đây.

(Nguồn: Zapier Integration V7.pdf §Flow 35 — hành động duy nhất là POST /api/ledger/record rồi "Terminate Zap"; §Flow 13)

BR_9.12.2: Ánh xạ sổ cái cố định

metric_category = "Corporate Benefits"; metric_value = "[Days_Approved] Days PTO Approved (Paid Time Off)", với Days_Approved là số nguyên — PTO chỉ được tính theo ngày trọn (không có nửa ngày); receipt_hash = Rippling Request ID.

(Nguồn: Zapier Integration V7.pdf §Flow 35; QnA_BACKGROUND_MECHANISMS_CRON.md [BG-018] — bảng tính của khách hàng 2026-11-04)

BR_9.12.3: Phạm vi — Chỉ W-2 đang hoạt động

Thời gian tạm nghỉ (hiatus) của contractor quốc tế là không lương và không được Luồng 35 ghi nhận.

(Nguồn: Zapier Integration V7.pdf §Flow 35; §Flow 13 Path B)

BR_9.12.4: Một lần phê duyệt = Một event sổ cái

Rippling Request ID là khóa idempotency (chống trùng lặp). Giống BR_9.11.3.

BR_9.12.5: Lưu trữ audit

Giống BR_9.11.7 (5 năm + 1 tháng; > 25 tháng → cold storage).

(Nguồn: RFQ_ Stack Trading Prop Tech V7.pdf §Audit Requirements)


9. Tiêu chí chấp nhận

AC_IDLuồngCho trướcThìLoại
AC-9.12-01Happy pathRippling phê duyệt 3 ngày PTO cho trader W-2 đang hoạt độngMột event: metricCategory = "Corporate Benefits", metricValue = "3 Days PTO Approved (Paid Time Off)", verificationHash = Request ID; tx_hash được lưuIntegration
AC-9.12-02Trùng lặpCùng Request ID được gửi hai lầnChỉ một event on-chain; lần gọi thứ hai HTTP 200 cùng tx_hash gốcIntegration
AC-9.12-03ContractorPayload của contractor quốc tếZap dừng; không gọi sổ cáiIntegration
AC-9.12-04Không có side effectAC-9.12-01 hoàn tấtstagnation_deadline và trạng thái giao dịch trên broker không bị Luồng 35 thay đổi (nếu có thay đổi thì chỉ đến từ Luồng 13)Integration
AC-9.12-05JWT saiChữ ký không hợp lệHTTP 401; không mintSecurity
AC-9.12-06Số ngày nguyênRippling phê duyệt 2 ngày PTO cho trader W-2 đang hoạt độngmetricValue = "2 Days PTO Approved (Paid Time Off)" — giá trị số nguyên, không có phần thập phânIntegration

10. Tham chiếu API

POST /api/ledger/record — schema như UC_9.11 §10.

{
  "trader_id": "94a2b1c8-3f4e-4b21-a123-890abcdef123",
  "metric_category": "Corporate Benefits",
  "metric_value": "3 Days PTO Approved (Paid Time Off)",
  "date": "2026-03-15T18:00:00Z",
  "receipt_hash": "rip_pto_99120482"
}

11. Câu hỏi mở

IDƯu tiênCâu hỏiGiả định
Q1MNếu một PTO đã được phê duyệt sau đó bị hủy/rút ngắn trong Rippling, có nên mint một event sổ cái điều chỉnh (ví dụ "PTO Cancelled") không?✅ Đã trả lời 2026-11-04 — không ghi bút toán sổ cái điều chỉnh; Ops xử lý thủ công (Exc-3, [BG-017]).
Q2—Rippling có cũng kích hoạt Time Off Approved cho PTO nhập trực tiếp trong Rippling (không qua Flow 13) không?✅ Đã đóng bởi CR-20261027-001 — toàn bộ PTO của W-2 được yêu cầu trực tiếp trong Rippling; Luồng 35 ghi nhận mọi lần phê duyệt.
Q3LDays_Approved có thể là số lẻ (nửa ngày)? Định dạng?✅ Đã trả lời 2026-11-04 — chỉ số ngày nguyên, không có nửa ngày (BR_9.12.2, [BG-018]).

12. Lịch sử thay đổi

NgàyPhiên bảnThay đổiTrướcSauNguồn
2026-11-05v1.2Header; §5 dòng metric_value; §7 Exc-3; §8 BR_9.12.2; §9 AC-9.12-06 (mới); §11 Q1, Q3Giả định có thể có nửa ngày (0.5 Days…); bút toán điều chỉnh khi hủy còn mởChỉ số ngày nguyên; không ghi bút toán sổ cái điều chỉnh, Ops xử lý thủ công (UC_9.2 Alt-5)Bảng tính của khách hàng 2026-11-04 [BG-017] [BG-018] [BG-002]
2026-10-27v1.1§1 Tài liệu tham chiếu, UC liên quan; §2 Trigger upstream; đóng Q2Upstream được mô tả là "Flow 13 Step A-2 ghi nhận kỳ nghỉ trong Rippling"W-2 yêu cầu nghỉ phép trong Rippling; cùng một webhook kích hoạt Flow 35 và Flow 13 Path ACR-20261027-001
2026-10-27v1.0Tạo tài liệu ban đầu—Đặc tả đầy đủ: trigger, filter W-2, dedup, mint sổ cái, BR_9.12.1–5, AC-9.12-01–05Zapier Integration V7.pdf §Flow 35, §Flow 13; RFQ_ Stack Trading Prop Tech V7.pdf §Record Immutable Ledger

UC_9.13 — Luồng 36: Đồng bộ Sổ cái Retainer Dots

TrườngGiá trị
UC_IDUC_9.13
Phiên bảnv1.0
Cập nhật lần cuối2026-10-27
BA PiClinh.nguyen34
Danh mụcBACKGROUND MECHANISMS & CRON JOBS
Mô-đunLuồng 36 (UC_4.15.2)
Chức năngĐồng bộ Sổ cái Retainer Dots
Tài liệu tham chiếuZapier Integration V7.pdf (§Flow 36; §7.3 Flow 36 Retainer Trigger — Option B) · RFQ_ Stack Trading Prop Tech V7.pdf (§Record Immutable Ledger; §3.6.1; §Audit Requirements) · StackTrading_Backend_Technical_Proposal_v1.6.docx (§Option B — Dots ✓)

1. Danh mục UC

UC_IDChức năngMô tả
UC_9.13Luồng 36 — Đồng bộ Sổ cái Retainer DotsKhi Dots xử lý retainer hàng tháng cho contractor quốc tế đang hoạt động (Level 6+), event đi vào qua hardened ingress của Middleware Hub (Option B), được phát tới Zapier dưới dạng RETAINER_PROCESSED, và Zapier gọi POST /api/ledger/record để mint một event Payroll Executed ($[Total_Amount] Retainer Paid ([billing_country])) trên Polygon PoS.

UC_9.13 — Luồng 36: Đồng bộ Sổ cái Retainer Dots

TrườngGiá trị
Use CaseĐồng bộ Sổ cái Retainer Dots
Mô tảCông bố bằng chứng thanh toán retainer cho contractor quốc tế lên Sổ cái Bất biến (Immutable Ledger). Một retainer Dots đã xử lý = một event CorporateMetricVerified với Dots Transaction ID làm verificationHash.
Tác nhânHệ thống (Dots → Middleware Hub → Zapier → Middleware Hub → Polygon PoS)
Zapier FlowFlow 36
Nguồn triggerEvent của Middleware Hub RETAINER_PROCESSED (nguồn: Dots, Monthly Retainer Processed)
3rd PartyDots · Zapier · Alchemy RPC · Polygon PoS
Middleware EndpointsPOST /webhooks/retainer/dots (ingress) · POST /zapier/events/retainer_processed (emit) · POST /api/ledger/record
UC liên quanUC_9.11 · UC_9.2 (hiatus Path B tạm ngưng / tiếp tục retainer) · UC_4.15.2

2. Trigger

Giai đoạnThành phầnHành động
IngressPOST /webhooks/retainer/dotsXác thực chữ ký Dots / allowlist; thực thi idempotency (chống trùng lặp) qua provider_event_id; ghi vào event_log trước khi emit.
EmitPOST /zapier/events/retainer_processedPhát event chuẩn hóa RETAINER_PROCESSED (source: Dots) tới Zapier.
ZapFlow 36Được kích hoạt bởi event của Middleware Hub.

(Nguồn: Zapier Integration V7.pdf §7.3 Option B · StackTrading_Backend_Technical_Proposal_v1.6.docx §Option B provider list — Dots ✓)


3. Điều kiện tiên quyết

IDĐiều kiện tiên quyết
P1Dots webhook được cấu hình trỏ tới POST /webhooks/retainer/dots.
P2Payload chứa Dots Transaction ID, Total_Amount, và tham chiếu người nhận có thể ánh xạ về trader_id.
P3Trader là contractor quốc tế đang hoạt động ở Level 6+.
P4billing_country khả dụng trên bảng Users.
P5Contract sổ cái và owner wallet khả dụng (xem UC_9.11 P4).

4. Hậu điều kiện

#Hậu điều kiện
1Event Dots được lưu bền vững trong event_log (durable, có thể replay).
2Một event CorporateMetricVerified với metricCategory = "Payroll Executed".
3tx_hash được lưu trong PostgreSQL; việc thực thi được ghi vào BPS_Audit_Log.
4Zap kết thúc.

5. Luồng cơ bản

Bước 1 — Ingress (Middleware). Nhận Dots webhook tại POST /webhooks/retainer/dots → xác thực chữ ký → dedup trên provider_event_id (trùng → Alt-1) → ghi event_log.

Bước 2 — Emit (Middleware). POST /zapier/events/retainer_processed với payload đã chuẩn hóa.

(Nguồn: Zapier Integration V7.pdf §7.3 Option B)

Bước 3 — Filter (Zapier). Chỉ tiếp tục nếu payload tương ứng với contractor quốc tế đang hoạt động của Stack Trading (Level 6+). Ngược lại dừng (Alt-2).

(Nguồn: Zapier Integration V7.pdf §Flow 36)

Bước 4 — Gọi POST /api/ledger/record

TrườngGiá trị
trader_idUUID trader toàn cục
metric_category"Payroll Executed" (cố định)
metric_value"$[Total_Amount] Retainer Paid ([billing_country])" — ví dụ "$2,500.00 Retainer Paid (UK)"
dateHôm nay (ISO 8601 UTC)
receipt_hashDots Transaction ID

(Nguồn: Zapier Integration V7.pdf §Flow 36)

Bước 5 — Middleware mint trên Polygon — giống UC_9.11 Bước 5.

Bước 6 — Kết thúc Zap.


6. Luồng thay thế

Alt-1 — Dots gửi trùng: dedup tại ingress trên provider_event_id trả về HTTP 200 cho Dots; không emit gì tới Zapier.

Alt-2 — Không phải contractor quốc tế đang hoạt động L6+: Zap dừng ở filter; không gọi sổ cái.


7. Luồng ngoại lệ

Exc-1 — Chữ ký Dots không hợp lệ: ingress từ chối (HTTP 401); không có dòng event_log; dòng audit REJECTED.

Exc-2 — Zapier JWT không hợp lệ / lỗi Polygon RPC: giống UC_9.11 Exc-1 / Exc-2. Vì event đã nằm trong event_log, Ops có thể replay.


8. Quy tắc nghiệp vụ

BR_9.13.1: Phạm vi — contractor quốc tế đang hoạt động, Level 6+

Dưới Level 6, trader theo mô hình thưởng theo yêu cầu (on-demand bonus; không có retainer). Lương W-2 của Mỹ thuộc Luồng 34.

(Nguồn: Zapier Integration V7.pdf §Flow 36)

BR_9.13.2: Ánh xạ sổ cái cố định

metric_category = "Payroll Executed"; metric_value = "$[Total_Amount] Retainer Paid ([billing_country])"; receipt_hash = Dots Transaction ID.

(Nguồn: Zapier Integration V7.pdf §Flow 36)

BR_9.13.3: Hardened Ingress (Option B) là bắt buộc đối với Dots

Dots webhook đi vào qua Middleware Hub (xác thực chữ ký, dedup provider_event_id, ghi event_log trước khi emit). Dots không được gọi Zapier trực tiếp.

(Nguồn: Zapier Integration V7.pdf §7.3 · StackTrading_Backend_Technical_Proposal_v1.6.docx §Option B)

BR_9.13.4: Một retainer = Một event sổ cái

Dedup tại ingress (provider_event_id) và tại POST /api/ledger/record (receipt_hash). Không có bản ghi sổ cái trùng lặp.

(Nguồn: Zapier Integration V7.pdf §7.3 — "Ensure downstream actions are idempotent (no duplicate ledger entries / payouts / accounting entries)")

BR_9.13.5: Lưu trữ audit

Giống BR_9.11.7.


9. Tiêu chí chấp nhận

AC_IDLuồngCho trướcThìLoại
AC-9.13-01Happy pathRetainer Dots $2,500.00 được xử lý cho contractor L6+ đang hoạt động, billing_country = UKCó dòng event_log; event Zapier được emit; một event on-chain "$2,500.00 Retainer Paid (UK)", verificationHash = Dots Transaction IDIntegration
AC-9.13-02Trùng lặpDots retry cùng một eventIngress trả về HTTP 200; không emit lần hai; một event on-chainIntegration
AC-9.13-03Dưới L6 / W-2Payload của trader L5 hoặc W-2Zap dừng; không gọi sổ cáiIntegration
AC-9.13-04Chữ ký Dots saiChữ ký không hợp lệHTTP 401; không có dòng event_logSecurity
AC-9.13-05ReplayRPC thất bại cho event XOps replay X từ event_log; kết quả là đúng một event on-chainIntegration

10. Tham chiếu API

POST /api/ledger/record — schema như UC_9.11 §10.

{
  "trader_id": "94a2b1c8-3f4e-4b21-a123-890abcdef123",
  "metric_category": "Payroll Executed",
  "metric_value": "$2,500.00 Retainer Paid (UK)",
  "date": "2026-03-31T18:00:00Z",
  "receipt_hash": "dots_txn_441029381"
}

11. Câu hỏi mở

IDƯu tiênCâu hỏiGiả định
Q1MĐịnh dạng hiển thị billing_country — ISO alpha-2 (GB) hay nhãn (UK)? Ví dụ trong V7 hiển thị UK.ISO alpha-2 từ bảng Users; GB hiển thị nguyên trạng. Cần xác nhận.
Q2MRetainer một lần theo tỷ lệ (prorated; tăng Level 7+ giữa tháng) — có kích hoạt cùng Dots event và được ghi nhận không?Có, ghi nhận như một event riêng.
Q3LLuồng 36 có cập nhật bản ghi invoice nào không (ví dụ đánh dấu paid)? Không có trong V7.Không — chỉ ghi sổ cái.

12. Lịch sử thay đổi

NgàyPhiên bảnThay đổiTrướcSauNguồn
2026-10-27v1.0Tạo tài liệu ban đầu—Đặc tả đầy đủ: ingress Option B, filter contractor L6+, mint sổ cái, BR_9.13.1–5, AC-9.13-01–05Zapier Integration V7.pdf §Flow 36, §7.3; Backend Proposal v1.6 §Option B

UC_9.14 — Luồng 32: Velocity Reward Engine

TrườngGiá trị
UC_IDUC_9.14
Phiên bảnv1.1
Cập nhật lần cuối2026-11-05
BA PiClinh.nguyen34
Danh mụcSTAGE 9: GROWTH & REFERRAL
Mô-đunReferral Loyalty Loop
Chức năngLuồng 32 — Velocity Reward Engine
Tài liệu tham chiếuRFQ_ Stack Trading Prop Tech V7.pdf (§Velocity Reward Engine) · Zapier Integration V7.pdf (§Flow 32)

1. Danh mục UC

UC_IDChức năngMô tả
UC_9.14Luồng 32 — Velocity Reward EnginePhát hành mã khuyến mãi EVAL_L1 giảm giá 100% tại các mốc giới thiệu (3 và 6 lượt giới thiệu thành công). Được kích hoạt bởi Everflow S2S webhook (EV_MILESTONE_3_REFS / EV_MILESTONE_6_REFS). Thực thi pipeline 4 bước: cổng idempotency (chống trùng lặp) → kiểm tra sanctions → tạo mã khuyến mãi → email Klaviyo → thông báo Discord. Có audit trail tuân thủ CFTC/NFA.

UC_9.14 — Luồng 32: Velocity Reward Engine

TrườngGiá trị
Use CaseVelocity Reward Engine
Mô tảTại các mốc giới thiệu 3 hoặc 6 lượt giới thiệu thành công, Everflow gửi một S2S webhook (EV_MILESTONE_3_REFS hoặc EV_MILESTONE_6_REFS). Middleware thực thi: (1) cổng idempotency qua PostgreSQL SELECT ... FOR UPDATE + UNIQUE index trên provider_event_id, (2) sàng lọc sanctions đối chiếu Compliance_geo_restrictions, (3) tạo mã khuyến mãi (EVAL_L1, giảm giá 100%) và chèn vào bảng promo_codes, (4) email Klaviyo Velocity_Reward_Unlocked, (5) thông báo Discord tới #trading-floor-announcements qua Redis queue với giới hạn 5 msg/5 s. Audit được ghi vào bps_audit_logs và sao chép sang S3 Glacier Object Lock (WORM) để lưu trữ 5 năm theo CFTC/NFA.
Zapier FlowFlow 32 (Velocity Reward Engine)
Nguồn triggerEverflow S2S Webhook
3rd PartyEverflow · Klaviyo · Discord Bot API
Middleware EndpointPOST /api/referral/velocity-reward
ReleaseRelease 2 (QnA_BACKGROUND_MECHANISMS_CRON.md [BG-012] — client sheet 2026-11-04)

2. Trigger

Sự kiện: Middleware nhận Everflow S2S webhook tại POST /api/referral/velocity-reward.

Tên sự kiệnMốcÝ nghĩa
EV_MILESTONE_3_REFS3 lượt giới thiệu thành côngReferrer đạt bậc velocity 3 lượt giới thiệu
EV_MILESTONE_6_REFS6 lượt giới thiệu thành côngReferrer đạt bậc velocity 6 lượt giới thiệu

Everflow gửi webhook khi số lượt giới thiệu của origin_user_id vượt ngưỡng mốc. Middleware là điểm vào duy nhất — luồng không đi qua Zapier.

(Nguồn: Zapier Integration V7.pdf §Flow 32)


3. Điều kiện tiên quyết

IDĐiều kiện tiên quyết
P1Nhận được Everflow S2S webhook với provider_event_id, origin_user_id và event_type hợp lệ (EV_MILESTONE_3_REFS hoặc EV_MILESTONE_6_REFS)
P2provider_event_id chưa từng được xử lý (cổng idempotency chưa bị kích hoạt)
P3origin_user_id ứng với một user đã biết trong hệ thống
P4billing_country / billing_region của origin_user_id không có trong Compliance_geo_restrictions (sanctions hợp lệ)

4. Hậu điều kiện

#Hậu điều kiện
1Bản ghi khóa idempotency được ghi: provider_event_id được đánh dấu là đã xử lý trong bảng idempotency
2Bản ghi mã khuyến mãi được chèn vào bảng promo_codes: applicable_product_id = 'EVAL_L1', discount_percent = 100, is_used = false, origin_user_id được gán
3Email giao dịch Klaviyo Velocity_Reward_Unlocked được gửi tới origin_user_id, chứa mã khuyến mãi
4Tin nhắn Discord được broadcast tới #trading-floor-announcements qua Redis queue
5Bản ghi audit được ghi vào bps_audit_logs
6Bản ghi audit được sao chép sang S3 Glacier Object Lock (WORM) — lưu trữ 5 năm + 1 tháng

5. Luồng cơ bản

Bước 1 — Cổng Idempotency

Middleware lấy khóa mức hàng (row-level lock) trước mọi thao tác ghi:

BEGIN;
SELECT id FROM idempotency_log
WHERE provider_event_id = :provider_event_id
FOR UPDATE;
  • Nếu hàng tồn tại: trả về HTTP 200 OK với { "status": "duplicate", "skipped": true } — không xử lý tiếp.
  • Nếu hàng không tồn tại: chèn hàng mới với provider_event_id, origin_user_id, event_type, received_at; giữ khóa cho đến khi commit ở Bước 3.

UNIQUE index trên provider_event_id là lớp bảo vệ cứng chống chèn đồng thời.

(Nguồn: RFQ_ Stack Trading Prop Tech V7.pdf §Velocity Reward Engine)

Bước 2 — Cổng Sanctions

SELECT 1 FROM Compliance_geo_restrictions
WHERE country_code = :billing_country
  AND (region_code = :billing_region OR region_code IS NULL);
  • Nếu tìm thấy hàng: trả về HTTP 403 Forbidden với { "error": "SANCTIONS_BLOCKED", "user_id": :origin_user_id }. Hủy luồng. Ghi sự kiện sanctions-block vào bps_audit_logs.
  • Nếu không tìm thấy hàng: chuyển sang Bước 3.

(Nguồn: RFQ_ Stack Trading Prop Tech V7.pdf §Velocity Reward Engine)

Bước 3 — Tạo mã khuyến mãi

INSERT INTO promo_codes (
  code,
  applicable_product_id,
  discount_percent,
  is_used,
  origin_user_id,
  event_type,
  created_at
) VALUES (
  :generated_code,        -- cryptographically random alphanumeric, 16 chars
  'EVAL_L1',
  100,
  false,
  :origin_user_id,
  :event_type,
  NOW()
);
COMMIT;  -- releases FOR UPDATE lock from Step 1

generated_code là chuỗi chữ-số ngẫu nhiên mật mã học dài 16 ký tự, duy nhất nhờ ràng buộc UNIQUE trên cột code.

(Nguồn: RFQ_ Stack Trading Prop Tech V7.pdf §Velocity Reward Engine)

Bước 4 — Email Klaviyo

Middleware gọi Klaviyo Transactional API:

  • Template: Velocity_Reward_Unlocked
  • Đến: địa chỉ email của origin_user_id
  • Các trường payload: promo_code, event_type, milestone_count (3 hoặc 6), applicable_product (EVAL_L1)

Khi Klaviyo API lỗi: áp dụng retry với exponential backoff (xem Exc-1). Không chặn việc gửi Discord khi các retry Klaviyo đang diễn ra.

(Nguồn: Zapier Integration V7.pdf §Flow 32)

Bước 5 — Thông báo Discord

Đưa tin nhắn Discord vào Redis queue cho #trading-floor-announcements:

  • Giới hạn tốc độ: 5 tin nhắn mỗi 5 giây (do queue consumer thực thi).
  • Triển khai: chỉ dùng fetch() gốc — axios bị cấm tuyệt đối.
  • Nội dung tin nhắn: Thông báo thành tích đạt mốc của origin_user_id (tên hiển thị hoặc handle ẩn danh theo chính sách cộng đồng).

Queue consumer lấy tin ra khỏi queue và gọi Discord Bot API trong giới hạn tốc độ cho phép.

(Nguồn: Zapier Integration V7.pdf §Flow 32)

Bước 6 — Audit Log

Ghi vào bps_audit_logs:

{
  "event_type": "VELOCITY_REWARD_ISSUED",
  "origin_user_id": "<id>",
  "provider_event_id": "<id>",
  "milestone": 3,
  "promo_code": "<code>",
  "timestamp": "<ISO-8601>"
}

Sao chép sang S3 Glacier Object Lock (WORM). Thời gian lưu trữ: 5 năm + 1 tháng. 2 năm đầu lưu ở tầng truy cập tức thì. Sau 2 năm: Glacier Deep Archive. Theo yêu cầu lưu trữ hồ sơ của CFTC/NFA.

(Nguồn: RFQ_ Stack Trading Prop Tech V7.pdf §Velocity Reward Engine)


6. Luồng thay thế

Alt-1 — Sự kiện trùng lặp (provider_event_id đã được xử lý)

  • Cổng idempotency phát hiện hàng đã tồn tại (Bước 1).
  • Trả về HTTP 200 OK: { "status": "duplicate", "skipped": true }.
  • Không tạo mã khuyến mãi. Không gửi email. Không gửi Discord. Không có sự kiện audit (sự kiện đã được ghi ở lần xử lý đầu tiên).
  • Luồng kết thúc bình thường.

7. Luồng ngoại lệ

Exc-1 — Klaviyo API lỗi (Bước 4)

Middleware áp dụng exponential backoff:

delay(attempt) = 5s × 2^attempt
  attempt 1 → 10s
  attempt 2 → 20s
  attempt 3 → 40s

Sau 3 lần retry thất bại (tổng cửa sổ backoff ~70s):

  • Ghi một entry WARN vào bps_audit_logs: { "event": "KLAVIYO_RETRY_EXHAUSTED", "promo_code": "<code>", "origin_user_id": "<id>" }.
  • Gửi cảnh báo Slack SEV-2 tới #dev_ops: "⚠️ [SEV-2] Velocity Reward email failed after 3 retries for user <id>. Promo code <code> was issued but email not delivered. Manual resend required."
  • Thông báo Discord (Bước 5) vẫn tiếp tục bất kể Klaviyo lỗi — mã khuyến mãi đã được commit.

(Nguồn: RFQ_ Stack Trading Prop Tech V7.pdf §Velocity Reward Engine)

Exc-2 — Discord API lỗi (Bước 5)

Redis queue consumer retry theo hướng dẫn rate-limit của Discord Bot. Nếu kênh Discord không khả dụng (non-2xx sau các lần retry):

  • Ghi WARN vào bps_audit_logs.
  • Cảnh báo Slack tới #dev_ops: "⚠️ [SEV-2] Discord broadcast failed for Velocity Reward event <provider_event_id>.".
  • Không chặn luồng — mã khuyến mãi và email không bị ảnh hưởng.

Exc-3 — Bị chặn bởi sanctions (Bước 2)

  • Trả về HTTP 403 Forbidden.
  • Ghi bản ghi sanctions-block vào bps_audit_logs với event_type = 'VELOCITY_REWARD_SANCTIONS_BLOCKED'.
  • Không tạo mã khuyến mãi. Không gửi email. Không gửi Discord.
  • Việc sao chép sự kiện chặn sang S3 Glacier vẫn được áp dụng (audit trail CFTC/NFA).

Exc-4 — Xung đột khi INSERT promo_codes (ràng buộc UNIQUE trên code)

  • Middleware tạo lại code ngẫu nhiên mới và retry INSERT (tối đa 3 lần).
  • Nếu cả 3 lần retry đều thất bại: trả về HTTP 500, ghi log ERROR, gửi cảnh báo Slack SEV-2 tới #dev_ops.
  • Xác suất xung đột với chuỗi chữ-số ngẫu nhiên 16 ký tự là không đáng kể nhưng vẫn phải có cơ chế bảo vệ này.

8. Quy tắc nghiệp vụ

BR_9.14.1: Idempotency là bắt buộc — PostgreSQL FOR UPDATE + UNIQUE Index

Mọi Everflow webhook đến PHẢI được kiểm tra xem đã xử lý chưa bằng SELECT ... FOR UPDATE trên bảng idempotency trước khi ghi bất cứ thứ gì. Ràng buộc UNIQUE trên provider_event_id là lớp bảo vệ cứng. Sự kiện trùng lặp PHẢI trả về HTTP 200 OK một cách im lặng — không phải HTTP 4xx — để tránh retry storm từ Everflow.

(Nguồn: RFQ_ Stack Trading Prop Tech V7.pdf §Velocity Reward Engine)

BR_9.14.2: Cổng Sanctions chạy trước khi tạo mã khuyến mãi

Việc kiểm tra Compliance_geo_restrictions trên billing_country/billing_region PHẢI chạy trước khi bất kỳ mã khuyến mãi nào được ghi vào promo_codes. User bị sanctions tuyệt đối không được nhận mã khuyến mãi hay email, kể cả khi sự kiện mốc của Everflow là hợp lệ.

(Nguồn: RFQ_ Stack Trading Prop Tech V7.pdf §Velocity Reward Engine)

BR_9.14.3: Tham số mã khuyến mãi là cố định

Mọi mã khuyến mãi do Flow 32 phát hành PHẢI có:

  • applicable_product_id = 'EVAL_L1'
  • discount_percent = 100
  • is_used = false (trạng thái ban đầu)

Không có sản phẩm hay giá trị giảm giá nào khác hợp lệ cho luồng này.

(Nguồn: RFQ_ Stack Trading Prop Tech V7.pdf §Velocity Reward Engine)

BR_9.14.4: Triển khai Discord — chỉ dùng native fetch(), không dùng axios

Mọi lời gọi Discord API trong Flow 32 PHẢI dùng fetch() API gốc. axios bị cấm tuyệt đối. Quy tắc này áp dụng cho mọi lời gọi Discord Bot từ Middleware trong luồng này.

(Nguồn: Zapier Integration V7.pdf §Flow 32)

BR_9.14.5: Giới hạn tốc độ Discord — 5 tin nhắn mỗi 5 giây qua Redis Queue

Các broadcast Discord PHẢI được đưa vào Redis queue và tiêu thụ với tốc độ tối đa 5 tin nhắn mỗi 5 giây. Cấm các lời gọi Discord đồng bộ trực tiếp bỏ qua queue để tránh bị ban do vượt rate-limit của API.

(Nguồn: Zapier Integration V7.pdf §Flow 32)

BR_9.14.6: Audit Trail CFTC/NFA — S3 Glacier WORM, lưu trữ 5 năm + 1 tháng

Mọi sự kiện audit (phát hành thưởng, sanctions block, hết số lần retry) PHẢI được ghi vào bps_audit_logs và sao chép sang S3 Glacier Object Lock (WORM). Thời gian lưu trữ: 5 năm + 1 tháng. 2 năm đầu ở tầng truy cập tức thì. Sau 2 năm: Glacier Deep Archive. Chính sách Object Lock cấm xóa thủ công.

(Nguồn: RFQ_ Stack Trading Prop Tech V7.pdf §Velocity Reward Engine)

BR_9.14.7: Exponential Backoff — Cơ số 5s, 3 lần Retry, SEV-2 khi cạn Retry

Lỗi API bên thứ ba (Klaviyo, Discord) PHẢI áp dụng exponential backoff: delay = 5s × 2^attempt (10s, 20s, 40s). Sau 3 lần retry thất bại, gửi cảnh báo Slack SEV-2 tới #dev_ops. Luồng không bị crash — các bước phía sau đã hoàn tất không bị rollback.

(Nguồn: RFQ_ Stack Trading Prop Tech V7.pdf §Velocity Reward Engine)

BR_9.14.8: Chỉ có hai sự kiện mốc hợp lệ

Chỉ EV_MILESTONE_3_REFS và EV_MILESTONE_6_REFS là trigger hợp lệ cho Flow 32. Mọi giá trị event_type khác nhận được tại POST /api/referral/velocity-reward PHẢI trả về HTTP 400 Bad Request và được ghi log là INVALID_EVENT_TYPE. Mỗi mốc (3 và 6) phát hành đúng một mã EVAL_L1 100% dùng một lần.

(Nguồn: Zapier Integration V7.pdf §Flow 32; QnA_STAGE1_CHECKOUT_ONBOARDING.md STAGE1-064; UC_9.x_Client_Questions.md F32-01 — mốc 3/6 được xác nhận 2026-11-05)


9. Tiêu chí chấp nhận

AC_IDLuồngCho trướcThìLoại
AC-9.14-01Happy path — mốc 3 lượt giới thiệuWebhook EV_MILESTONE_3_REFS hợp lệ, sanctions hợp lệ, lần xuất hiện đầu tiênMã khuyến mãi được chèn (EVAL_L1, 100%); email Velocity_Reward_Unlocked được gửi; broadcast Discord được đưa vào queue; audit log được ghi; trả về HTTP 200 OKIntegration
AC-9.14-02Happy path — mốc 6 lượt giới thiệuWebhook EV_MILESTONE_6_REFS hợp lệ, sanctions hợp lệ, lần xuất hiện đầu tiênGiống AC-9.14-01; event_type = 'EV_MILESTONE_6_REFS' trong bản ghi promo_codesIntegration
AC-9.14-03Idempotency — sự kiện trùng lặpCùng một provider_event_id nhận được hai lầnLời gọi thứ hai trả về HTTP 200 { "status": "duplicate", "skipped": true }; không có mã khuyến mãi thứ hai; không có email thứ haiIntegration
AC-9.14-04Trùng lặp đồng thờiHai request đồng thời với cùng provider_event_idChỉ đúng một mã khuyến mãi được tạo; transaction thứ hai bị chặn bởi SELECT ... FOR UPDATE + ràng buộc UNIQUEIntegration
AC-9.14-05Sanctions blockbilling_country của user khớp Compliance_geo_restrictionsTrả về HTTP 403; không có mã khuyến mãi; không có email; sự kiện sanctions-block có trong bps_audit_logsIntegration
AC-9.14-06Cạn retry KlaviyoKlaviyo trả về non-2xx cho cả 3 lần retryCảnh báo Slack SEV-2 tới #dev_ops; mã khuyến mãi đã commit vẫn hợp lệ; broadcast Discord vẫn được gửiIntegration
AC-9.14-07Giới hạn tốc độ Discord10 sự kiện thưởng đến trong vòng 1 giâyRedis queue consumer gửi ≤ 5 tin nhắn mỗi 5 s; không có HTTP 429 từ DiscordIntegration
AC-9.14-08Discord dùng native fetchLời gọi Discord trong triển khai Flow 32Không có import axios trong đường đi của requestCode review
AC-9.14-09event_type không hợp lệWebhook với event_type = 'EV_UNKNOWN'HTTP 400 Bad Request; INVALID_EVENT_TYPE được ghi log; không tạo mã khuyến mãiIntegration
AC-9.14-10Audit WORMSự kiện thưởng được xử lý thành côngHàng bps_audit_logs có mặt; xác nhận đã sao chép S3 Glacier Object Lock; Object Lock mode = COMPLIANCEIntegration

10. Mô hình dữ liệu

Bảng: promo_codes
CộtKiểuRàng buộcMô tả
idBIGSERIALPKKhóa chính tự tăng
codeVARCHAR(32)UNIQUE NOT NULLChuỗi chữ-số ngẫu nhiên mật mã học 16 ký tự
applicable_product_idVARCHAR(64)NOT NULLCố định: 'EVAL_L1' cho Flow 32
discount_percentSMALLINTNOT NULLCố định: 100 cho Flow 32
is_usedBOOLEANNOT NULL DEFAULT falseMã đã được sử dụng hay chưa
origin_user_idBIGINTFK → users.idReferrer nhận được phần thưởng
event_typeVARCHAR(64)NOT NULL'EV_MILESTONE_3_REFS' hoặc 'EV_MILESTONE_6_REFS'
created_atTIMESTAMPTZNOT NULL DEFAULT NOW()Thời điểm phát hành mã
used_atTIMESTAMPTZNULLABLEThời điểm sử dụng mã
Bảng: idempotency_log (logic — có thể trùng với bảng idempotency hiện có)
CộtKiểuRàng buộcMô tả
idBIGSERIALPK—
provider_event_idVARCHAR(128)UNIQUE NOT NULLID sự kiện Everflow — khóa idempotency
origin_user_idBIGINTNOT NULL—
event_typeVARCHAR(64)NOT NULL—
received_atTIMESTAMPTZNOT NULL DEFAULT NOW()—

11. Tham chiếu API

POST /api/referral/velocity-reward
TrườngGiá trị
MethodPOST
AuthChữ ký HMAC của Everflow webhook (header: X-Everflow-Signature)
CallerEverflow S2S webhook
Content-Typeapplication/json

Request payload:

{
  "provider_event_id": "ef_evt_abc123xyz",
  "origin_user_id": 10042,
  "event_type": "EV_MILESTONE_3_REFS",
  "referral_count": 3,
  "billing_country": "US",
  "billing_region": "TX"
}

Response — Happy path (HTTP 200 OK):

{
  "status": "success",
  "promo_code": "ABCD1234EFGH5678",
  "applicable_product": "EVAL_L1",
  "discount_percent": 100,
  "email_dispatched": true,
  "discord_queued": true
}

Response — Sự kiện trùng lặp (HTTP 200 OK):

{
  "status": "duplicate",
  "skipped": true
}

Response — Sanctions block (HTTP 403 Forbidden):

{
  "error": "SANCTIONS_BLOCKED",
  "user_id": 10042
}

Response — event_type không hợp lệ (HTTP 400 Bad Request):

{
  "error": "INVALID_EVENT_TYPE",
  "received": "EV_UNKNOWN",
  "accepted": ["EV_MILESTONE_3_REFS", "EV_MILESTONE_6_REFS"]
}
Trường requestKiểuBắt buộcMô tả
provider_event_idSTRINGCóID sự kiện duy nhất của Everflow — khóa idempotency
origin_user_idINTCóUser ID của referrer
event_typeSTRINGCóEV_MILESTONE_3_REFS hoặc EV_MILESTONE_6_REFS
referral_countINTCóSố mốc giới thiệu hiện tại (3 hoặc 6)
billing_countrySTRINGCóMã quốc gia ISO 3166-1 alpha-2 dùng cho kiểm tra sanctions
billing_regionSTRINGKhôngMã vùng/bang ISO 3166-2 dùng cho kiểm tra sanctions

(Nguồn: RFQ_ Stack Trading Prop Tech V7.pdf §Velocity Reward Engine)


12. Câu hỏi mở

IDƯu tiênCâu hỏiGiả định
Q1MBroadcast Discord nên hiển thị tên hiển thị của user, bí danh, hay hoàn toàn ẩn danh?Giả định của BA: handle ẩn danh hoặc chỉ tên riêng; cần xác nhận với khách về chính sách cộng đồng
Q2Lidempotency_log là bảng riêng cho Flow 32 hay là bảng idempotency dùng chung toàn hệ thống hiện có?Giả định của BA: bảng dùng chung toàn hệ thống, lọc theo tiền tố event_type là EV_
Q3MTemplate ID / slug Klaviyo của Velocity_Reward_Unlocked là gì?Đang dùng tên placeholder; cần xác nhận với Marketing/cấu hình Klaviyo
Q4LViệc sao chép sang S3 Glacier là đồng bộ (trong request) hay bất đồng bộ (background job)?Giả định của BA: background job bất đồng bộ; audit log ghi đồng bộ, việc sao chép S3 được đưa vào queue

13. Lịch sử thay đổi

NgàyPhiên bảnThay đổiTrướcSauNguồn
2026-11-05v1.1§1 dòng Release; BR_9.14.8 (một mã cho mỗi mốc + nguồn)Chưa nêu Release; mô hình mốc 3/6 so với tin nhắn ghim (pinned) 2/6 + gói (bundle) chưa được giải quyết (F32-01)Release 2; mốc 3/6 đã được xác nhận, mỗi mốc một mã EVAL_L1 — câu trả lời về bundle (F32-02) không áp dụngClient sheet 2026-11-04 [BG-012]; F32-01 đóng 2026-11-05; STAGE1-064
2026-10-01v1.0Tạo tài liệu ban đầu—Đặc tả đầy đủ: pipeline 4 bước, cổng idempotency, kiểm tra sanctions, tạo mã khuyến mãi, email Klaviyo, broadcast Discord, audit trail CFTC/NFARFQ_ Stack Trading Prop Tech V7.pdf §Velocity Reward Engine; Zapier Integration V7.pdf §Flow 32

UC_9.15 — Luồng 33: Xác minh Amplify Bounty

TrườngGiá trị
UC_IDUC_9.15
Phiên bảnv1.1
Cập nhật lần cuối2026-11-05
BA PiClinh.nguyen34
Danh mụcBACKGROUND MECHANISMS & CRON JOBS
Mô-đunLuồng 33 (4.9.3/4.9.4)
Chức năngAmplify Bounty
Tài liệu tham chiếuZapier Integration V7.pdf (§Flow 33 Amplify Verification) · RFQ_ Stack Trading Prop Tech V7.pdf (§2.3 Discord Bot — Application Commands; §API GET /bounty/check-url, POST /generate-promo-code; §Audit Requirements)

1. Danh mục UC

UC_IDChức năngMô tả
UC_9.15Luồng 33 — Xác minh Amplify BountyTrader gửi URL TikTok / YouTube Shorts qua /submit-bounty [url] trong #bounty-submissions. Bot kiểm tra định dạng URL và giới hạn 1 lần/24h, sau đó Zapier chạy quy trình audit 5 bước: (1) URL chưa từng được dùng, (2) lấy Views/Likes/Comments, (3) Views ≥ 50,000 VÀ (Likes+Comments)/Views ≥ 0.015, (4) Gemini 1.5 Pro audit bot-farm trên văn bản đã ẩn PII, (5) PASS → promo code Associate Track giảm 100% + DM + email; FAIL → DM kèm lý do.

UC_9.15 — Luồng 33: Xác minh Amplify Bounty

TrườngGiá trị
Use CaseXác minh & Trao thưởng Amplify Bounty
Mô tảThưởng cho việc quảng bá video ngắn một cách tự nhiên và xác thực. Ngưỡng định lượng lọc các nội dung có độ tiếp cận thấp; phân tích pháp chứng (forensic) của Gemini 1.5 Pro loại bỏ tương tác nhân tạo (bot-farm). Mỗi URL chỉ được thưởng một lần.
Tác nhânTrader (thành viên Discord) · Hệ thống (Discord Bot, Zapier, Middleware, Gemini 1.5 Pro)
Zapier FlowFlow 33
Nguồn triggerDiscord Bot webhook từ /submit-bounty
3rd PartyDiscord · TikTok API · YouTube Data API · Google Gemini 1.5 Pro · Google Sheets · AWS SES (email PASS — chỉ cho user đã liên kết)
Middleware EndpointsGET /bounty/check-url · POST /generate-promo-code
UC liên quanUC_9.14 (dùng chung POST /generate-promo-code) · UC_2.7.8 Apply Promo Code (sử dụng mã)

2. Trigger

Trader chạy slash command Discord /submit-bounty [url] trong #bounty-submissions. Sau khi các kiểm tra phía bot đạt (§5 Bước 1–2), bot gửi webhook tới Zapier Flow 33.

(Nguồn: RFQ_ Stack Trading Prop Tech V7.pdf §2.3; Zapier Integration V7.pdf §Flow 33)


3. Điều kiện tiên quyết

IDĐiều kiện tiên quyết
P1#bounty-submissions: Send Messages bị tắt cho @everyone; Use Application Commands được bật.
P2Người gửi là thành viên của Discord server Stack Trading. Không bắt buộc liên kết tài khoản Stack Trading (QnA [BG-013] — client sheet 2026-11-04).
P3Video ở chế độ công khai trên TikTok hoặc YouTube Shorts.
P4Đã có cấu hình Gemini 1.5 Pro enterprise với điều khoản lưu giữ dữ liệu được xác định rõ.

4. Hậu điều kiện

Kết quảHậu điều kiện
PASSPromo code được tạo (dùng một lần, giảm 100% Associate Track, origin_user_id được ghi log); URL được ghi nhận trong bounty_submissions là đã thưởng; DM + email được gửi; AUDIT_PASS được lưu trong Google Sheets.
URL trùng lặpDM được gửi; không ghi nhận phần thưởng nào.
Math failureDM kèm các chỉ số hiện tại; không thưởng; URL không bị đánh dấu là đã thưởng (trader có thể gửi lại).
AI failureDM từ chối; không thưởng; AUDIT_FAIL được lưu trong Google Sheets.
Mọi kết quảLần thực thi được ghi log vào BPS_Audit_Log.

5. Luồng cơ bản

Bước 1 — Kiểm tra định dạng URL (Discord Bot, phía client)

Bot kiểm tra đầu vào là URL TikTok hoặc YouTube Shorts hợp lệ trước khi chấp nhận. Không hợp lệ → Alt-1.

(Nguồn: RFQ_ Stack Trading Prop Tech V7.pdf §2.3 — Validation)

Bước 2 — Rate limit (Discord Bot)

Mỗi discord_user_id chỉ được gửi một lần trong 24 giờ. Vượt quá → Alt-2.

Triển khai (giả định của BA): Redis SET bounty_rate:{discord_user_id} 1 NX EX 86400; key đã tồn tại → từ chối.

(Nguồn: RFQ_ Stack Trading Prop Tech V7.pdf §2.3 — Rate Limiting)

Bước 3 — Webhook tới Zapier

Payload: discord_user_id, url, platform (tiktok | youtube_shorts), timestamp.

Bước 4 — Audit Bước 1: URL chưa từng được dùng

Zapier gọi GET /bounty/check-url?url=[URL-encoded]. Middleware truy vấn bounty_submissions.

  • is_unique = false → dừng; DM: "This link has already been used to claim a reward." (Alt-3)

(Nguồn: Zapier Integration V7.pdf §Flow 33 Step 1; RFQ V7 §API Check Bounty URL)

Bước 5 — Audit Bước 2: lấy chỉ số

Zapier lấy Views, Likes, Comments từ TikTok / YouTube API. Khi API lỗi, retry 3 lần với exponential backoff (trong vòng 10 giây). Mọi lần retry đều thất bại → Exc-1.

(Nguồn: QnA_BACKGROUND_MECHANISMS_CRON.md [BG-015] — client sheet 2026-11-04)

Bước 6 — Audit Bước 3: bộ lọc định lượng (Zapier Filter)

Điều kiệnNgưỡng
Views≥ 50,000
(Likes + Comments) / Views≥ 0.015 (1.5%)

Phải đạt cả hai. Nếu không → Alt-4 (Math Failure).

(Nguồn: Zapier Integration V7.pdf §Flow 33 Step 3)

Bước 7 — Audit Bước 4: audit pháp chứng bằng Gemini 1.5 Pro

  1. Ẩn PII — loại bỏ email, số điện thoại, định danh tài khoản, thông tin thanh toán, họ tên đầy đủ khỏi toàn bộ văn bản trước khi gửi tới LLM.
  2. Đầu vào — mô tả video + 10 comment hàng đầu.
  3. Prompt (tác vụ suy luận chuyên sâu, không phải bộ phân loại spam cơ bản): "Analyze these comments for bot-farm patterns (repetitive emojis, generic praise, identical phrasing). Return 'AUDIT_PASS' or 'AUDIT_FAIL'."
  4. Lưu trữ — chỉ lưu AUDIT_PASS / AUDIT_FAIL được rút ra trong Google Sheets (không lưu comment gốc).
  5. AUDIT_FAIL → Alt-5.

(Nguồn: Zapier Integration V7.pdf §Flow 33 Step 4 — LLM Analysis (Privacy-Safe))

Bước 8 — Audit Bước 5: trao thưởng (khi PASS)

  1. Gọi POST /generate-promo-code (type = Associate Track 100%, origin_user_id = trader đã gửi).
  2. Ghi nhận URL là đã thưởng trong bounty_submissions.
  3. DM trader: "Success. Your impact is verified. Your free Associate Track code is [promo_code]. It has also been sent to your email."
  4. Truy vấn Users theo discord_user_id. Nếu tồn tại user đã liên kết có email → gửi mã tới email đó qua AWS SES. Nếu không có tài khoản liên kết → bỏ qua email; DM Discord là kênh gửi duy nhất.

(Nguồn: Zapier Integration V7.pdf §Flow 33 Step 5; QnA_BACKGROUND_MECHANISMS_CRON.md [BG-013], [BG-014] — client sheet 2026-11-04)


6. Luồng thay thế

IDĐiều kiệnHành động của hệ thốngThông báo cho trader (Discord)
Alt-1Không phải URL TikTok / YouTube ShortsBot từ chối; không có webhookEphemeral error (nội dung — xem Q5)
Alt-2Đã gửi trong vòng 24hBot từ chối; không có webhookEphemeral "one submission per 24 hours" (nội dung — xem Q5)
Alt-3URL đã được thưởngDừng tại Bước 4"This link has already been used to claim a reward."
Alt-4Math failureDừng tại Bước 6; không thưởng"Submission logged. You currently have [Views] views and a [Ratio] engagement rate. This bounty requires 50,000 views and 1.5 percent engagement. Resubmit once your metrics update."
Alt-5AUDIT_FAILDừng tại Bước 7; không thưởng; lưu AUDIT_FAIL"Submission rejected. Our system detected non-organic engagement patterns. We only reward authentic traffic. Repeated bot-farming attempts will result in an Amplify Program ban."

(Nguồn: Zapier Integration V7.pdf §Flow 33 Steps 1, 5 — Communication Matrix)


7. Luồng ngoại lệ

Exc-1 — Social API không khả dụng sau 3 lần retry / URL không hợp lệ, ở chế độ riêng tư hoặc đã bị xóa: không thưởng; lần gửi này được tính vào rate limit 24h của discord_user_id đó; DM thông báo cho user rằng xác minh thất bại và có thể gửi lại sau 24 giờ (nội dung — xem Q5); ghi log vào BPS_Audit_Log. (Nguồn: QnA [BG-015] — client sheet 2026-11-04)

Exc-2 — Gemini timeout / đầu ra sai định dạng (không đúng chính xác AUDIT_PASS / AUDIT_FAIL): coi là không đạt (fail-closed); không thưởng; ghi log để kiểm tra thủ công. (Giả định của BA)

Exc-3 — POST /generate-promo-code thất bại sau khi PASS: không đánh dấu URL là đã thưởng; cảnh báo Ops tới #ops-marketing; DM trader thông báo đang chờ phát hành thủ công. (Giả định của BA)

Exc-4 — DM Discord bị chặn bởi cài đặt quyền riêng tư của user: user đã liên kết → email vẫn được gửi khi PASS; ghi log lỗi DM. User chưa liên kết → cũng không có email, nên mã không được gửi tới user; ghi log để Ops theo dõi xử lý.


8. Quy tắc nghiệp vụ

BR_9.15.1: Chỉ nhận đầu vào có cấu trúc

#bounty-submissions chỉ chấp nhận slash command /submit-bounty (Send Messages tắt cho @everyone, Use Application Commands bật).

(Nguồn: RFQ_ Stack Trading Prop Tech V7.pdf §2.3)

BR_9.15.2: Nền tảng được hỗ trợ

Chỉ chấp nhận URL TikTok và YouTube Shorts; được bot kiểm tra trước khi gửi.

(Nguồn: RFQ_ Stack Trading Prop Tech V7.pdf §2.3)

BR_9.15.3: Một lần gửi mỗi 24 giờ cho mỗi discord_user_id

Rate limit 24h và số lần vi phạm chống bot (anti-bot strike) được theo dõi theo discord_user_id (dù đã liên kết hay chưa). Các lần xác minh thất bại (lỗi API sau khi retry, URL không hợp lệ/riêng tư) cũng được tính.

(Nguồn: RFQ_ Stack Trading Prop Tech V7.pdf §2.3; QnA_BACKGROUND_MECHANISMS_CRON.md [BG-013], [BG-015] — client sheet 2026-11-04)

BR_9.15.4: Một phần thưởng cho mỗi URL

GET /bounty/check-url trả về is_unique = false cho mọi URL đã được thưởng. Chỉ các URL đã được thưởng mới chặn việc gửi lại.

(Nguồn: RFQ_ Stack Trading Prop Tech V7.pdf §API Check Bounty URL)

BR_9.15.5: Ngưỡng định lượng

Views ≥ 50,000 VÀ (Likes + Comments) / Views ≥ 0.015. Cả hai đều bao gồm giá trị biên.

(Nguồn: Zapier Integration V7.pdf §Flow 33 Step 3)

BR_9.15.6: Quyền riêng tư với LLM

PII được ẩn trước khi bất kỳ văn bản nào đến LLM; chỉ lưu kết quả PASS/FAIL được rút ra (Google Sheets); cấu hình LLM enterprise với thời hạn lưu giữ được xác định rõ.

(Nguồn: Zapier Integration V7.pdf §Flow 33 Step 4)

BR_9.15.7: Định nghĩa phần thưởng

Dùng một lần, giảm 100% Associate Track, có thể chuyển nhượng, origin_user_id được ghi log để audit. (usage_limit = 1 theo QnA STAGE1-074.)

(Nguồn: RFQ_ Stack Trading Prop Tech V7.pdf §API Generate Promo Code · QnA_STAGE1_CHECKOUT_ONBOARDING.md STAGE1-074)

BR_9.15.8: Nội dung thông báo được cố định

Nội dung DM Discord cho Alt-3/4/5 và PASS tuân theo Communication Matrix của V7 nguyên văn (tiếng Anh).

(Nguồn: Zapier Integration V7.pdf §Flow 33 Step 5)


9. Tiêu chí chấp nhận

AC_IDLuồngCho trướcThìLoại
AC-9.15-01Happy pathURL TikTok mới, 80,000 views, 1,000 likes, 300 comments (ER 1.625%), Gemini AUDIT_PASSPromo code được tạo; URL được đánh dấu đã thưởng; PASS DM kèm mã; email được gửi; AUDIT_PASS trong SheetsE2E
AC-9.15-02BiênViews = 50,000; ER = đúng 1.5%Đạt Bước 6Integration
AC-9.15-03Math fail — views49,999 viewsAlt-4 DM kèm views và ratio thực tế; không có mãIntegration
AC-9.15-04Math fail — ER100,000 views, 1,400 likes+commentsAlt-4 DM; không có mãIntegration
AC-9.15-05AI failGemini AUDIT_FAILAlt-5 DM; không có mã; AUDIT_FAIL trong SheetsIntegration
AC-9.15-06URL trùng lặpURL đã được thưởng trước đóAlt-3 DM; Bước 5–8 không được thực thiIntegration
AC-9.15-07Rate limitCùng một user gửi hai lần trong 24hLần thứ hai bị bot từ chối; không có Zapier webhookIntegration
AC-9.15-08URL không hợp lệURL Instagram ReelBot từ chối; không có webhookIntegration
AC-9.15-09PIIComment chứa địa chỉ emailVăn bản gửi tới Gemini đã được ẩn emailSecurity
AC-9.15-10Channel ACL@everyone đăng văn bản thường trong #bounty-submissionsKhông được phépConfig
AC-9.15-11User chưa liên kếtdiscord_user_id chưa liên kết với tài khoản Stack Trading nào; bài gửi đạt mọi bước auditPromo code được tạo; PASS DM kèm mã; không gửi emailIntegration
AC-9.15-12Lỗi APISocial API lỗi ở cả 3 lần retryDM thông báo xác minh thất bại / gửi lại sau 24h; không thưởng; lần gửi thứ hai trong vòng 24h bị bot từ chốiIntegration

10. Tham chiếu API

GET /bounty/check-url
ParamKiểuMô tả
urlSTRING (URL-encoded)URL video đã gửi

Response: { "is_unique": true }

POST /generate-promo-code

Request (theo V7: type, origin_user_id):

{
  "type": "ASSOCIATE_TRACK_100",
  "origin_user_id": "94a2b1c8-3f4e-4b21-a123-890abcdef123"
}

Response: { "promo_code": "STRING" }

Các giá trị enum của type không được định nghĩa trong V7 — ASSOCIATE_TRACK_100 là placeholder do BA đặt (xem Q3).

(Nguồn: RFQ_ Stack Trading Prop Tech V7.pdf §API)


11. Câu hỏi mở

IDƯu tiênCâu hỏiGiả định
Q1HThành viên Discord có discord_user_id chưa được liên kết với tài khoản Stack Trading có được gửi không? Ai nhận mã / email?✅ Đã trả lời 2026-11-04 — bất kỳ ai trong Discord server đều có thể gửi; luôn gửi DM, chỉ gửi email nếu đã liên kết ([BG-013]).
Q2HCó giới hạn số phần thưởng cho mỗi trader không (ví dụ 1 lần/30 ngày)? V7 không đề cập — chỉ có 1 lần gửi/24h và 1 phần thưởng/URL.Không giới hạn ngoài các quy tắc của V7.
Q3MCác giá trị type cho /generate-promo-code và applicable_product_id đích cho Associate Track (kích thước tài khoản / thị trường nào)?Một mã dùng được cho Level 1 Associate Track, mọi thị trường.
Q4MKênh nào gửi email PASS — Klaviyo event (như Velocity_Reward_Unlocked) hay AWS SES? Tên template/nội dung?✅ Đã trả lời 2026-11-04 — AWS SES, chỉ cho user đã liên kết ([BG-014]).
Q5LNội dung thông báo cho URL không hợp lệ, rate-limit và lỗi API (không có trong V7).BA soạn; client phê duyệt.
Q6LNếu audit thất bại ở Bước 2 (lỗi API), rate limit 24h có còn áp dụng không?✅ Đã trả lời 2026-11-04 — có, các lần thất bại được tính vào giới hạn 24h; retry 3 lần trước ([BG-015]).
Q7MXung đột chính sách ban: DM trong Zapier V7 nói "Repeated bot-farming attempts will result in an Amplify Program ban", nhưng nội dung ghim trong #amplify-intel (Discord Server Details.md — không có trong _SOURCE_MANIFEST.yaml) nói "immediate and permanent ban" ngay lần phát hiện đầu tiên. Áp dụng cái nào, và việc ban là tự động hay thủ công?Theo cách diễn đạt của Zapier V7 (lặp lại → ban); việc ban do Ops thực hiện thủ công; lịch sử AUDIT_FAIL hiển thị trong Sheets.
Q8MDM PASS của V7 ghi "It has also been sent to your email" — sai với người gửi chưa liên kết (không có email được gửi, [BG-013]). Có dùng nội dung DM khác cho user chưa liên kết không? (BR_9.15.8: nội dung là cố định, không được thay đổi khi chưa có phê duyệt của client)Giữ nội dung V7 cho đến khi client xác nhận.

12. Lịch sử thay đổi

NgàyPhiên bảnThay đổiTrướcSauNguồn
2026-11-05v1.1Header; §1 3rd Party; §3 P2; §5 Bước 5 (retry), Bước 8.4 (email); §7 Exc-1, Exc-4; §8 BR_9.15.3; §9 AC-9.15-11/12 (mới); §11 Q1, Q4, Q6, Q8 (mới)Bắt buộc liên kết; kênh email còn mở (giả định Klaviyo); quy tắc 24h khi lỗi API còn mởKhông bắt buộc liên kết; luôn gửi DM, email AWS SES chỉ khi đã liên kết; retry social API 3 lần; các lần thất bại được tính vào giới hạn 24hClient sheet 2026-11-04 [BG-013] [BG-014] [BG-015]
2026-10-27v1.0Khởi tạo tài liệu—Đặc tả đầy đủ: kiểm tra phía bot, audit 5 bước, Communication Matrix, BR_9.15.1–8, AC-9.15-01–10Zapier Integration V7.pdf §Flow 33; RFQ_ Stack Trading Prop Tech V7.pdf §2.3, §API

UC_9.16 — Luồng 38: Chặn Hỗ trợ & Tạo Ticket Freshdesk

TrườngGiá trị
UC_IDUC_9.16
Phiên bảnv1.1
Cập nhật lần cuối2026-11-05
BA PiClinh.nguyen34
Danh mụcBACKGROUND MECHANISMS & CRON JOBS
Mô-đunLuồng 38
Chức năngSupport Interception
Tài liệu tham chiếuZapier Integration V7.pdf (§Flow 38 Support Interception & Zendesk Creation) · RFQ_ Stack Trading Prop Tech V7.pdf (§2.3 Automated Support Interception & Routing) · CR-20260720-004 (Freshdesk replaces Zendesk) · CR-20260818-002 (monitor #live-broadcast-chat) · QnA_STAGE2_COMMUNITY_LIVE_BROADCAST.md (DCS-BIZ-21, PIT-BIZ-03) · list_email.md (FD-01)

1. Danh mục UC

UC_IDChức năngMô tả
UC_9.16Luồng 38 — Support InterceptionNode.js Discord Bot giám sát #the-pit, #verify và #live-broadcast-chat. Các tin nhắn chứa từ khóa trigger vận hành sẽ đi qua cổng sentiment Gemini (light). Nếu là Complaint: bot xóa tin nhắn, đăng placeholder công khai gắn thẻ user, và gửi webhook tới Zapier; Zapier tra cứu email đã đăng ký của user theo discord_id và tạo ticket Freshdesk mức ưu tiên High; Freshdesk gửi email xác nhận.

UC_9.16 — Luồng 38: Chặn Hỗ trợ & Tạo Ticket Freshdesk

TrườngGiá trị
Use CaseSupport Interception
Mô tảChuyển các khiếu nại vận hành (slippage, lag, frozen platform, …) ra khỏi các kênh Discord công khai vào một ticket Freshdesk riêng tư, ngăn chặn sự lan truyền cảm xúc tiêu cực công khai mà vẫn hỗ trợ được trader.
Tác nhânTrader (thành viên Discord) · Hệ thống (Discord Bot, Gemini, Middleware Hub, Zapier, Freshdesk)
Zapier FlowFlow 38
Nguồn triggerWebhook từ Middleware Hub / Discord Bot — "Negative Operational Sentiment Detected"
3rd PartyDiscord · Google Gemini (light model — cùng model với "The Desk Manager") · Freshdesk
UC liên quanUC_4.5.2 The Pit · UC_4.9.1 / UC_4.14.1 Discord Chat Stream (#live-broadcast-chat)

2. Trigger

  1. Bot listener: bất kỳ tin nhắn mới nào trong kênh được giám sát có chứa từ khóa trigger.
  2. Zapier trigger: webhook từ Middleware Hub (Discord Bot) sau khi cổng sentiment trả về Complaint. Payload: discord_id, message_text, timestamp.

(Nguồn: RFQ_ Stack Trading Prop Tech V7.pdf §2.3; Zapier Integration V7.pdf §Flow 38)

Các kênh được giám sát

KênhNguồn
#the-pitRFQ V7 §2.3
#verifyRFQ V7 §2.3
#live-broadcast-chatCR-20260818-002 (CR thắng V7)

3. Điều kiện tiên quyết

IDĐiều kiện tiên quyết
P1Bot có quyền Read Message History và Manage Messages trong tất cả các kênh được giám sát.
P2Danh sách từ khóa trigger đã được cấu hình (xem BR_9.16.2).
P3URL webhook Zapier Flow 38 đã được cấu hình trong bot / Middleware.
P4Thông tin xác thực Freshdesk API đã được cấu hình trong Zapier.

4. Hậu điều kiện (nhánh Complaint)

#Hậu điều kiện
1Tin nhắn gốc bị xóa khỏi kênh công khai.
2Phản hồi placeholder công khai được đăng, gắn thẻ user (xem Q1 cho #live-broadcast-chat).
3Ticket Freshdesk được tạo: Requester = email đã đăng ký, Description = message_text, Priority = High.
4Freshdesk gửi email xác nhận cho trader.
5Lần thực thi được ghi log vào BPS_Audit_Log.

5. Luồng cơ bản

Bước 1 — Bộ lọc sơ bộ theo từ khóa (Bot)

Bot quét từng tin nhắn mới trong các kênh được giám sát. Không có từ khóa trigger → bỏ qua (Alt-1).

Bước 2 — Cổng sentiment LLM (Bot → Gemini light model)

Tin nhắn được gửi tới Gemini để phân loại ý định là Complaint hoặc Positive/Neutral (ngăn false positive như "Stack Trading has no slippage!"). Không phải Complaint → bỏ qua (Alt-2).

(Nguồn: RFQ_ Stack Trading Prop Tech V7.pdf §2.3 — LLM Sentiment Gate)

Prompt tham chiếu (BA soạn thảo — không phải do client cung cấp):

You are an operations sentiment classifier for Stack Trading. Classify the user's intent:
1. "Complaint": reports an actual operational issue, technical glitch, execution failure, or frustration with system performance.
2. "Positive/Neutral": compliments the system, discusses normal market conditions, or uses the keyword in a non-complaint context.
Output ONLY JSON: {"intent": "Complaint" | "Positive/Neutral", "confidence_score": float}

Bước 3 — Xóa tin nhắn (Bot) — ngay lập tức.

Bước 4 — Placeholder công khai (Bot)

"@[User], to protect your account details and resolve this immediately, we have opened a secure Freshdesk support ticket for you. Please check your registered email."

(Nguồn: RFQ_ Stack Trading Prop Tech V7.pdf §2.3 — "Zendesk" được thay bằng "Freshdesk" theo CR-20260720-004)

Bước 5 — Webhook tới Zapier

{ "discord_id": "123456789012345678", "discord_username": "trader_jane", "channel_name": "the-pit", "message_text": "MT5 frozen again, lost my entry", "timestamp": "2026-10-27T09:15:00Z" }

Bước 6 — Tra cứu (Zapier)

Truy vấn PostgreSQL Users theo discord_id → email đã đăng ký. Không tìm thấy → Exc-1.

Bước 6.5 — Một ticket mỗi ngày UTC (Zapier / Middleware)

Kiểm tra ngày tạo ticket Freshdesk gần nhất (UTC) của discord_id này. Nếu trong ngày đã có ticket được tạo (trước 00:00 UTC), không tạo ticket thứ hai — hoặc thêm tin nhắn dưới dạng note vào ticket của ngày đó, hoặc bỏ qua (Dev chọn phương án đơn giản hơn). Tin nhắn Discord vẫn bị xóa (Bước 3). Xem BR_9.16.7.

Bước 7 — Tạo ticket Freshdesk (Zapier → Freshdesk POST /api/v2/tickets)

Trường FreshdeskGiá trịNguồn
email (Requester)Email đã đăng kýV7 Flow 38
subjectStack Trading Support Ticket Created - Discord EscalationV7 Flow 38 (email subject) — xem Q3
descriptionmessage_text + channel_name, discord_username, discord_id, thời điểm gửi tin nhắnV7 Flow 38; [BG-019]
priority3 (High)V7 Flow 38
status2 (Open)Giả định của BA
tags["discord-escalation", channel_name][BG-019] — client sheet 2026-11-04
custom_fields.cf_discord_user_iddiscord_idGiả định của BA

Bước 8 — Email xác nhận (Freshdesk)

Subject: Stack Trading Support Ticket Created - Discord Escalation

Hello,

We intercepted your recent message in the Stack Trading Discord regarding an operational issue. To protect your privacy and ensure our team can assist you securely, we have converted your message into a high-priority support ticket. Your original message: "[Insert message_text payload]"

Our team is reviewing this now and will reply to this email directly. Please reply to this email with any additional context or screenshots.

Regards,

(Nguồn: Zapier Integration V7.pdf §Flow 38 — Notify; gửi qua Freshdesk theo CR-20260720-004)


6. Luồng thay thế

Alt-1 — Không có từ khóa trigger: không thực hiện hành động nào.

Alt-2 — Gemini trả về Positive/Neutral: tin nhắn được giữ nguyên; không tạo ticket.

Alt-3 — Tin nhắn trong #live-broadcast-chat: cùng pipeline. Release 1/2: chỉ cần xóa tin nhắn trong Discord là đủ. Việc gỡ tin nhắn khỏi Live Chat Feed của dashboard (DISCORD_CHAT_STREAM) là hạng mục Day 2, theo một trong hai cách: (1) lọc trước — giữ lại tin nhắn chứa từ khóa trigger để kiểm tra bằng Gemini trước khi đẩy vào DISCORD_CHAT_STREAM, và không bao giờ đẩy nếu bị gắn cờ; hoặc (2) delete event — đưa message_id vào payload của stream và phát delete event khi bot xóa tin nhắn. Hành vi placeholder đang chờ Q1.

(Nguồn: CR-20260818-002; QnA_BACKGROUND_MECHANISMS_CRON.md [BG-020] — client sheet 2026-11-04)


7. Luồng ngoại lệ

Exc-1 — discord_id chưa được liên kết với user nào

  • Không tạo ticket Freshdesk (email placeholder sẽ bị bounce và Ops không thể phản hồi).
  • Bot vẫn xóa tin nhắn và phản hồi công khai, hướng dẫn user liên kết tài khoản hoặc gửi email tới support@stacktrading.com (chưa có nội dung thông báo).
  • Đăng lên Slack #ops-general kèm discord_username, channel_name, message_text.

(Nguồn: QnA_BACKGROUND_MECHANISMS_CRON.md [BG-021] — client sheet 2026-11-04)

Exc-2 — Gemini không khả dụng / timeout

  • Retry lời gọi Gemini một lần. Vẫn không khả dụng / timeout → fail-open: giữ nguyên tin nhắn, không tạo ticket, ghi log cảnh báo. Không bao giờ fail-closed (một sự cố gián đoạn sẽ xóa hàng loạt tin nhắn chat bình thường và làm ngập Freshdesk).

(Nguồn: QnA_BACKGROUND_MECHANISMS_CRON.md [BG-022] — client sheet 2026-11-04)

Exc-3 — Bot không thể xóa (thiếu quyền / tin nhắn đã bị xóa): tiếp tục Bước 5–8 (ticket vẫn được tạo); ghi log cảnh báo.

Exc-4 — Freshdesk API thất bại: Zapier retry; nếu thất bại lần cuối thì cảnh báo Ops (#ops-general). Placeholder công khai đã được đăng — ticket phải được tạo thủ công.


8. Quy tắc nghiệp vụ

BR_9.16.1: Các kênh được giám sát

#the-pit, #verify, #live-broadcast-chat.

(Nguồn: RFQ_ Stack Trading Prop Tech V7.pdf §2.3 · CR-20260818-002)

BR_9.16.2: Từ khóa trigger

Ví dụ trong V7: slippage, lag, frozen. Danh sách đầy đủ chưa được xác nhận (PIT-BIZ-03 còn mở). Cấu hình đề xuất (BA soạn thảo): ["slippage", "lag", "frozen", "scam", "missing payout", "Rithmic down", "MT5 down", "TradingView down", "connection dropped"]. Phải điều khiển bằng cấu hình (Ops có thể chỉnh sửa), không phân biệt chữ hoa/thường.

(Nguồn: RFQ_ Stack Trading Prop Tech V7.pdf §2.3 · QnA PIT-BIZ-03 — open)

BR_9.16.3: Cổng LLM là bắt buộc

Chỉ khớp từ khóa thì không bao giờ xóa tin nhắn; chỉ intent = "Complaint" mới kích hoạt việc chặn. Dùng cùng light Gemini model với "The Desk Manager".

(Nguồn: RFQ_ Stack Trading Prop Tech V7.pdf §2.3)

BR_9.16.4: Nền tảng ticketing là Freshdesk

Mọi tham chiếu tới Zendesk trong V7 Flow 38 được thay bằng Freshdesk.

(Nguồn: CR-20260720-004)

BR_9.16.5: Ánh xạ ticket

Requester = email đã đăng ký (tra cứu theo discord_id); Description = message_text gốc; Priority = High.

(Nguồn: Zapier Integration V7.pdf §Flow 38)

BR_9.16.6: Thứ tự hành động

Xóa → placeholder → webhook. Việc xóa phải diễn ra ngay lập tức ("instantly") và không chờ ticket.

(Nguồn: RFQ_ Stack Trading Prop Tech V7.pdf §2.3 — Execution)

BR_9.16.7: Một ticket cho mỗi discord_id mỗi ngày UTC

Các khiếu nại lặp lại từ cùng một discord_id trong một ngày lịch UTC tạo ra tối đa một ticket Freshdesk (các tin nhắn bổ sung được thêm dưới dạng note hoặc bỏ qua). Khiếu nại sau 00:00 UTC sẽ tạo ticket mới. Mọi tin nhắn khiếu nại vẫn bị xóa trong Discord.

(Nguồn: QnA_BACKGROUND_MECHANISMS_CRON.md [BG-023] — client sheet 2026-11-04)


9. Tiêu chí chấp nhận

AC_IDLuồngCho trướcThìLoại
AC-9.16-01Happy pathUser đã liên kết đăng "MT5 frozen again" trong #the-pit; Gemini → ComplaintTin nhắn bị xóa; placeholder gắn thẻ user; ticket Freshdesk (Requester = email đã đăng ký, Priority High, description = văn bản gốc); nhận được email xác nhậnE2E
AC-9.16-02False positive"Stack Trading has no slippage!"Gemini → Positive/Neutral; tin nhắn được giữ nguyên; không tạo ticketIntegration
AC-9.16-03Không có từ khóa"Good morning traders"Không gửi tới GeminiIntegration
AC-9.16-04#verifyComplaint trong #verifyGiống AC-9.16-01Integration
AC-9.16-05#live-broadcast-chatComplaint trong lúc phát sóng trực tiếpTin nhắn bị xóa trong Discord; ticket được tạo. Gỡ khỏi Live Chat Feed của dashboard = Day 2 (không kiểm thử trong Release 1/2)E2E
AC-9.16-06Kênh không được giám sátComplaint trong #generalKhông có hành độngIntegration
AC-9.16-07User chưa liên kếtdiscord_id không có trong UsersTin nhắn bị xóa; không tạo ticket Freshdesk; phản hồi công khai (liên kết tài khoản / gửi email tới support@stacktrading.com); cảnh báo Slack #ops-generalIntegration
AC-9.16-08Thương hiệu FreshdeskAC-9.16-01Placeholder và email ghi "Freshdesk", không bao giờ ghi "Zendesk"Content
AC-9.16-09Lặp lại trong cùng ngàyUser đã liên kết đăng khiếu nại thứ hai trong cùng ngày UTCTin nhắn bị xóa; không tạo ticket thứ hai (thêm note hoặc bỏ qua)Integration
AC-9.16-10Ngày UTC kế tiếpCùng user khiếu nại lại sau 00:00 UTCTicket mới được tạoIntegration
AC-9.16-11Gemini gián đoạnLời gọi Gemini thất bại, retry cũng thất bạiTin nhắn được giữ nguyên; không tạo ticket; ghi log cảnh báoIntegration

10. Câu hỏi mở

IDƯu tiênCâu hỏiGiả định
Q1HTrong #live-broadcast-chat, bot có vẫn đăng placeholder công khai trong lúc phát sóng trực tiếp không? (DCS-BIZ-21a — còn mở)Có, giống các kênh khác.
Q2MTicket có nên được gắn tag kênh nguồn (ví dụ live-broadcast) để ưu tiên trong giờ phát sóng không? (DCS-BIZ-21c)✅ Đã trả lời 2026-11-04 — tags ["discord-escalation", channel_name] + ngữ cảnh trong description ([BG-019]).
Q3MV7 Flow 38 định nghĩa một email xác nhận tùy chỉnh; list_email.md FD-01 là auto-reply "New Ticket Created" chung của Freshdesk. Gửi cái nào (hay cả hai)?Template tùy chỉnh của Flow 38 thay thế FD-01 cho tag discord-escalation ([BG-019]).
Q4HXử lý discord_id chưa liên kết (email placeholder + cảnh báo Ops) — xác nhận hay bỏ ticket?✅ Đã trả lời 2026-11-04 — không tạo ticket; phản hồi công khai + Slack #ops-general ([BG-021]).
Q5MRace: tin nhắn đến dashboard qua WebSocket trước khi bot xóa — có cần event thu hồi (retract) không? (CR-20260818-002 Q4)✅ Đã trả lời 2026-11-04 — Release 1/2: chỉ xóa trong Discord; gỡ khỏi dashboard = Day 2 ([BG-020]).
Q6MGemini không khả dụng: fail-open hay fail-closed?✅ Đã trả lời 2026-11-04 — retry một lần, sau đó fail-open; không bao giờ fail-closed ([BG-022]).
Q7LDanh sách từ khóa trigger cuối cùng cho từng kênh (PIT-BIZ-03, DCS-BIZ-21b).Danh sách nháp ở BR_9.16.2, dùng chung cho mọi kênh.
Q8LCác khiếu nại lặp lại của cùng một user trong khoảng thời gian ngắn nên tạo một ticket hay nhiều ticket?✅ Đã trả lời 2026-11-04 — một ticket cho mỗi discord_id mỗi ngày UTC (BR_9.16.7, [BG-023]).

11. Lịch sử thay đổi

NgàyPhiên bảnThay đổiTrướcSauNguồn
2026-11-05v1.1Header; §5 payload Bước 5, Bước 6.5 (mới), Bước 7 description/tags; §6 Alt-3; §7 Exc-1, Exc-2; §8 BR_9.16.7 (mới); §9 AC-9.16-05/07, AC-9.16-09–11 (mới); §10 Q2, Q4, Q5, Q6, Q8Tags Discord_Escalation (giả định của BA); chưa liên kết → ticket placeholder; một ticket cho mỗi tin nhắn; bắt buộc gỡ khỏi dashboard; giả định Gemini fail-openTags discord-escalation + kênh; description kèm channel/username/id/timestamp; chưa liên kết → không tạo ticket, phản hồi công khai + Slack; 1 ticket / discord_id / ngày UTC; gỡ khỏi dashboard = Day 2; Gemini retry một lần rồi fail-openClient sheet 2026-11-04 [BG-019]–[BG-023]
2026-10-27v1.0Khởi tạo tài liệu—Đặc tả đầy đủ: 3 kênh được giám sát, từ khóa + cổng Gemini, xóa/placeholder/webhook, ticket + email Freshdesk, BR_9.16.1–6, AC-9.16-01–08RFQ V7 §2.3; Zapier V7 §Flow 38; CR-20260720-004; CR-20260818-002

UC_9.17 — Luồng 39: Gửi lại Hướng dẫn Dữ liệu Thị trường BPS

TrườngGiá trị
BA phụ tráchlinh.nguyen34
Ngày tạo2026-08-26
Phiên bảnv1.4
Cập nhật lần cuối2026-11-05 — Pop-up hiển thị mỗi lần vào tab "Command" trên Dashboard khi thỏa thuận CME chưa ký; dừng khi Signed_Completely = Yes; trader tự phục vụ gọi POST /resend-rtrader-instructions.
Tài liệu tham chiếuZapier Integration V7.pdf (Flow 39 lines 2614–2623) · RFQ_ Stack Trading Prop Tech V7.pdf (BPS Endpoints — Resend R|Trader Instructions lines 2941–2944)

Danh mục UC

UC_IDTên Use CaseMô tả nghiệp vụ
UC_9.17Luồng 39 — Gửi lại Hướng dẫn Dữ liệu Thị trường BPSBPS Admin kích hoạt gửi lại email thiết lập R|Trader Pro cho trader Futures chưa ký các thỏa thuận subscriber CME/CBOT/NYMEX/COMEX. Middleware gửi webhook RESEND_RTRADER_INSTRUCTIONS tới Zapier, Zapier gửi email qua AWS SES. Phạm vi: chỉ Futures. Có ba câu hỏi mở đang chờ Rithmic làm rõ (xem §6).

Lịch sử thay đổi

NgàyPhiên bảnMục cập nhậtTrướcSauGhi chú
2026-08-26v1.1Tạo ban đầu + phân nhánh phân loại SIM vs Live (CRITICAL). §1 bối cảnh nghiệp vụ. Template SES-39A/SES-39B. BR_9.17.7. Exc-5. AC-9.17-07/08.—UC_9.17 được soạnNguồn: Zapier V7 Flow 39 + bảng BPS Endpoint trong v7_full.txt + phân tích nghiệp vụ do user cung cấp 2026-08-26.
2026-10-20v1.1 → v1.2Bổ sung §1b Giao diện dành cho Trader; §3 Luồng cơ bản cập nhật đường kích hoạt trader tự phục vụ; bổ sung BR_9.17.9; bổ sung AC-9.17-16/17.Chưa có tài liệu về giao diện dành cho trader. Flow 39 chỉ do admin kích hoạt.Bổ sung modal "Action Required: Exchange Agreements Pending" trên Trader Dashboard làm điểm vào thứ hai. Nhấn "Resend Instructions" gọi cùng endpoint POST /bps/resend-rtrader-instructions.UI do khách cung cấp 2026-10-20.
2026-10-27v1.2 → v1.3§1 bảng tham số; §3 Bước 2 xác định phase; §3 bảng phân nhánh template; Exc-7account_status Live ghi dạng Active_L1_DMA → Active_L24_DMA / Active_Lx_DMAaccount_status = 'Active_DMA' (current_level 1–24)Khách xác nhận 2026-09-14 — account_status là enum cố định; level lưu ở current_level (UC_5.8 BR_5.8.9)
2026-11-05v1.3 → v1.4§1b điều kiện hiển thị, hành vi Cancel, endpoint Resend, Completion Gate (mới); §2 Điểm vào B; BR_9.17.10/11 (mới); cập nhật AC-9.17-16/16b/17, thêm AC-9.17-18Modal hiển thị một lần ở lần đăng nhập Dashboard đầu tiên (cme_modal_acknowledged); trader tự phục vụ gọi POST /bps/resend-rtrader-instructionsModal hiển thị mỗi lần vào tab "Command" khi chưa ký; đóng modal không lưu trạng thái; dừng khi Signed_Completely = Yes; trader tự phục vụ gọi POST /resend-rtrader-instructionsFlow 39 update 2026-11-05

Thuật ngữ

Đối với toàn bộ thuật ngữ dùng chung của dự án, tham khảo: Project Glossary.


UC_9.17 — Luồng 39: Gửi lại Hướng dẫn Dữ liệu Thị trường BPS

1. Tổng quan

TrườngNội dung
IDUC_9.17
Use CaseGửi lại Hướng dẫn Dữ liệu Thị trường BPS
Mô tảCho phép BPS Admin/Support kích hoạt thủ công việc gửi lại email thiết lập R|Trader Pro cho trader Futures có luồng dữ liệu thị trường bị khóa do chưa ký thỏa thuận subscriber CME. Admin gọi BPS endpoint POST /bps/resend-rtrader-instructions với user_id của trader. Middleware gửi webhook RESEND_RTRADER_INSTRUCTIONS tới Zapier (Flow 39), Zapier gửi email AWS SES chứa thông tin đăng nhập và hướng dẫn từng bước để ký thỏa thuận.
Zapier FlowFlow 39 (BPS Resend Market Data Instructions)
Backend EndpointPOST /bps/resend-rtrader-instructions — gửi webhook RESEND_RTRADER_INSTRUCTIONS tới Zapier
Zapier TableBảng Users (user_id, platform_username, asset_class)
3rd PartyZapier (Flow 39) · AWS SES (gửi email — SES-44 cho SIM, SES-45 cho Live) · Rithmic (nguồn thông tin đăng nhập platform)

1b. Giao diện dành cho Trader — Modal "Action Required: Exchange Agreements Pending"

Flow 39 có hai điểm vào: BPS Admin (§2 Trigger) và trader tự phục vụ qua modal trên Dashboard bên dưới.

Đặc tả modal (UI do khách cung cấp 2026-10-20):

Thành phầnNội dung
Tiêu đềAction Required: Exchange Agreements Pending
Nội dungYou must log into the R|Trader Pro desktop terminal to digitally sign your CME exchange agreements. Your data feeds cannot activate until this step is complete.
Nút chínhResend Instructions
Nút phụCancel

Điều kiện hiển thị: Modal được hiển thị mỗi lần trader mở hoặc chuyển tới tab "Command" trên Dashboard khi TẤT CẢ các điều kiện sau đúng:

  • account_status IN ('SIM_ACTIVE', 'Active_DMA') (tài khoản Futures)
  • Các thỏa thuận CME Market Data Agreements chưa được ký (Signed_Completely khác Yes)

Cơ chế hiển thị giống Soft Breach modal. (Nguồn: Flow 39 update 2026-11-05)

Hành vi nút "Resend Instructions":

  • Trader nhấn → frontend Dashboard gọi POST /resend-rtrader-instructions (kích hoạt Flow 39) với user_id của chính trader (xác thực bằng Dashboard session JWT — không phải admin token).
  • Middleware áp dụng cùng các gate check như đường BPS Admin (asset class, kiểm tra credential, rate limit, kiểm tra phase).
  • Khi thành công: nút hiển thị trạng thái xác nhận ngắn (ví dụ: "Instructions sent"); modal vẫn có thể đóng bằng Cancel.
  • Khi thất bại (rate limit 429, sai phase 422, v.v.): modal hiển thị thông báo lỗi inline; không tự động đóng.

Nút "Cancel" / tắt modal: Đóng modal. Không gọi API và không lưu trạng thái nào. Luồng dữ liệu vẫn bị khóa. Modal xuất hiện lại mỗi lần trader quay lại tab "Command" khi các thỏa thuận vẫn chưa được ký.

Điều kiện ngưng hiển thị (Completion Gate): Ngay khi backend xác nhận qua Rithmic rằng trader đã ký xong, hệ thống lưu Signed_Completely = Yes vào CSDL. Từ đó hệ thống dừng kiểm tra Rithmic và không hiển thị modal ở các lần vào tab "Command" sau. (Nguồn: Flow 39 update 2026-11-05)

Lưu ý — các trường admin_id và reason: BPS endpoint yêu cầu admin_id và reason cho audit log. Với các lời gọi trader tự phục vụ, admin_id PHẢI được đặt thành một giá trị hệ thống dành riêng (ví dụ "SYSTEM_TRADER_SELF_SERVICE") và reason thành một chuỗi cố định (ví dụ "Trader self-initiated via Dashboard modal"). Điều này giữ nguyên việc ghi BPS_Audit_Log mà không cần trader nhập liệu.

Ảnh chụp màn hình (khách cung cấp 2026-10-20):

Action Required: Exchange Agreements Pending modal

(Nguồn: UI do khách cung cấp 2026-10-20)

1a. Bối cảnh nghiệp vụ

Vì sao trader Futures phải ký thỏa thuận sàn giao dịch: Với các tài khoản Futures dùng Rithmic, CME Group (và các sàn thành viên CBOT, NYMEX, COMEX) bắt buộc mọi trader phải ký điện tử Subscriber Agreement trước khi luồng giá real-time được kích hoạt. Cho đến khi ký, Rithmic chặn luồng dữ liệu ở cấp hạ tầng bất kể trạng thái tài khoản. Trader dùng NinjaTrader 8, Quantower, ATAS, Sierra Chart hoặc MotiveWave sẽ thấy "No Market Data" hoặc biểu đồ trống cho đến khi hoàn tất ký. Dashboard của Stack Trading không thể theo dõi trạng thái ký của Rithmic theo thời gian thực — nghĩa là support phải chủ động gửi lại hướng dẫn khi trader báo thiếu dữ liệu.

Thời điểm gửi email hướng dẫn ký — theo từng phase:

Phase A — SIM (Level 0 Associate Track): Được kích hoạt ngay sau khi thanh toán SIM challenge thành công. Middleware đặt account_status = 'Guest' và gửi Welcome_Sim_Challenge qua AWS SES. Email chứa thông tin đăng nhập Rithmic Paper + khối hướng dẫn CME bắt buộc: "You must download R|Trader Pro and log in using your provided credentials to activate your CME data feeds, digitally sign your exchange agreements..." Trader phải tải R|Trader Pro (desktop hoặc web), đăng nhập bằng thông tin SIM và ký với tư cách Non-Professional. Luồng giá trên tất cả terminal giao dịch vẫn bị khóa cho đến khi hoàn tất ký.

Phase B — Live Onboarding (Level 1, 2 hoặc 5): Email hướng dẫn ký (Live_Onboarding_Credentials) được gửi khi hoàn tất Flow 3H — sau toàn bộ chuỗi Stage 3: Veriff KYC → thiết lập payout Dots → ký hợp đồng ICA Rippling → chọn/thanh toán Market Data (Flow 3F/3G) → tài khoản Live được Middleware cấp phát qua Rithmic Live FCM API. Trader phải đăng nhập vào Live gateway của R|Trader Pro và ký các thỏa thuận CME với tư cách Professional trước khi mở terminal giao dịch. (Nguồn: Zapier Integration V7.pdf Flow 1 Step 8 lines 983–1001; Flow 3H lines 1264–1332; RFQ_ Stack Trading Prop Tech V7.pdf §122 Steps 2/4/6/8)

Vì sao phân loại Non-Pro và Pro quan trọng: CME Group phân biệt hai loại subscriber với mức phí và nghĩa vụ pháp lý khác nhau:

Tham sốSIM (Level 0)Live (Level 1+)
account_statusSIM_ACTIVEActive_DMA (current_level 1–24)
Rithmic GatewayPaper Trading GatewayLive / Ironbeam Gateway
Phân loại CMENon-Professional (bắt buộc)Professional (bắt buộc)
Phí$18.00/exchange/tháng — do công ty chi trả, trader trả $0.00; chính sách CME "4 exchanges billed as 3"$137.50/exchange/tháng — trừ từ tài khoản của trader (BR_5.6.7)
Ký thỏa thuậnBắt buộc trước khi luồng dữ liệu được kích hoạtBắt buộc trước khi giao dịch live bắt đầu

(Nguồn: RFQ_ Stack Trading Prop Tech V7.pdf §315, §317, §44, §356)

Lý do phân tách: tài khoản SIM chạy trên Rithmic Paper Trading Gateway (tách biệt khỏi live FCM/Ironbeam để tránh phí định tuyến live). CME phân loại tài khoản trên Paper server là mục đích cá nhân/giáo dục — Non-Professional là bắt buộc theo luật. Tài khoản Live vận hành bằng vốn tự doanh của công ty — CME bắt buộc Professional bất kể lý lịch cá nhân. Nếu trader Live ký dưới Non-Professional → vi phạm kiểm toán CME, công ty phải chịu trách nhiệm.

Quy trình ký thỏa thuận — phụ thuộc hệ điều hành:

HĐHPhương thứcCác bước chính
Windows — Option AR|Trader Pro Desktop (.msi)Cài đặt → đăng nhập bằng platform_username + mật khẩu Dashboard → Rithmic tự động hiển thị pop-up Wizard (khóa terminal) → chọn phân loại → nhập tên pháp lý KYC → ký CME, CBOT, NYMEX, COMEX → pop-up đóng, luồng dữ liệu kích hoạt
Windows — Option BR|Trader Pro Web (trình duyệt)Giống luồng macOS bên dưới
macOSR|Trader Pro Web (trình duyệt)Mở Safari/Chrome/Firefox → R|Trader Pro Web → đăng nhập → chọn đúng Gateway (Paper cho SIM, Live cho Live DMA) → ký 4 thỏa thuận online → luồng dữ liệu mở khóa trên toàn hệ thống; kết nối MotiveWave hoặc platform native macOS khác

(Nguồn: RFQ_ Stack Trading Prop Tech V7.pdf §276, §314, §315, §356, §486)

Biện pháp bảo vệ vận hành (cấp Rithmic Gateway):

  • Khóa cấp Gateway: Rithmic tạm dừng luồng giá real-time ở cấp hạ tầng cho đến khi cả 4 thỏa thuận được ký. Dashboard Stack Trading KHÔNG theo dõi việc ký theo thời gian thực (không cần polling — Rithmic tự mở khóa).
  • Giới hạn 1 session + Plug-In Mode: Rithmic áp dụng 1 session đồng thời cho mỗi tài khoản. Trader phải bật "Allow Plug-In Connection" trong R|Trader Pro Desktop trước khi kết nối NinjaTrader 8 (qua chế độ "Connect using R|Trader Pro") — tránh bị đá session khi chạy đồng thời cả hai ứng dụng.

(Nguồn: RFQ_ Stack Trading Prop Tech V7.pdf §315)

Xử lý lỗi — chọn sai phân loại khi ký:

Phân loại CME Professional/Non-Professional là yêu cầu pháp lý nghiêm ngặt với hệ quả phí đáng kể (Non-Pro: $18/exchange/tháng; Pro: $137.50/exchange/tháng). Stack Trading đã thiết kế các cơ chế kiểm soát sau:

Trường hợp A — Trader Live (Professional) vô tình chọn "Non-Pro": Điều này không thể xảy ra. Vì trader vận hành vốn tự doanh của công ty theo Independent Contractor Agreement với Stack Trading Brokerage LLC, CME bắt buộc theo luật phân loại Professional. Tại Flow 3H, Middleware thực thi khóa cứng: gọi Rithmic Live FCM API và cấu hình Trader ID profile với Is_Professional = True. Khi trader đăng nhập R|Trader Pro Live, Rithmic chỉ hiển thị form ký Professional — không có tùy chọn Non-Pro nào hiển thị trên giao diện. (Nguồn: RFQ_ Stack Trading Prop Tech V7.pdf lines 1141–1146; Zapier Integration V7.pdf lines 1274–1285)

Trường hợp B — Trader SIM (Non-Professional) vô tình chọn "Professional": Điều này CÓ THỂ xảy ra. Giá trị mặc định trong DB cho SIM là Is_Professional = False (công ty chi trả chi phí Non-Pro). Nếu trader đăng nhập R|Trader Pro SIM và chọn "Professional", Rithmic ghi nhận Trader ID là Professional — CME sẽ cố tính phí $137.50/tháng cho mỗi exchange thay vì mức Non-Pro do công ty chi trả.

Phát hiện: GET /api/bps/check-market-data-status liên tục đối chiếu entitlement trong DB (Non-Pro) với trạng thái chữ ký thực tế từ Rithmic API. Nếu phát hiện không khớp (Rithmic báo Professional trong khi DB báo Non-Pro) → hệ thống nâng cờ cảnh báo.

Phương án khắc phục:

  • Tự động (Flow 39): Ops dùng POST /bps/resend-rtrader-instructions. Webhook này gửi lại email hướng dẫn VÀ đặt lại/vô hiệu hóa trạng thái chữ ký CME sai trên Rithmic gateway — cho phép trader đăng nhập lại và ký lại đúng với tư cách Non-Professional.
  • Thủ công (R|Admin): Ops có thể truy cập phần mềm middle-office R|Admin của Rithmic để chỉnh phân loại của trader từ Professional về Non-Professional. (Nguồn: khách xác nhận 2026-09-09) Flow 39 chỉ áp dụng cho trader có asset_class = 'Futures'. Trader Forex (MT5/TE) dùng luồng giá LP phi tập trung — không cần thỏa thuận CME/Rithmic. asset_class IN ('Forex_MT5', 'Forex_TE') → từ chối tại gate của Middleware, không gửi webhook.

(Nguồn: RFQ_ Stack Trading Prop Tech V7.pdf §314, §315)

Lưu ý về trigger — chỉ thủ công (đang chờ): Flow 39 hiện được tài liệu hóa là hành động do admin kích hoạt thủ công. Việc có nên tự động kích hoạt sau khi cấp phát Rebuy (khi sub-account mới được gán cho User ID hiện có) hay không vẫn là câu hỏi mở — xem F39-Q1/Q2 trong §6.


2. Trigger

Điểm vào A — BPS Admin: BPS Admin nhấn "Resend R|Trader Instructions" trong BPS Admin Panel cho một trader cụ thể.

Điểm vào B — Trader tự phục vụ (UI 2026-10-20): Trader nhấn "Resend Instructions" trên modal "Action Required: Exchange Agreements Pending" trên Dashboard của mình.

Điểm vào A gọi POST /bps/resend-rtrader-instructions; Điểm vào B (pop-up trên Dashboard) gọi POST /resend-rtrader-instructions. Cả hai đi theo cùng các gate check của Middleware và cùng đường dispatch.

  1. Admin gửi POST /bps/resend-rtrader-instructions với user_id trong request body.
  2. Middleware xác thực request, gửi webhook event RESEND_RTRADER_INSTRUCTIONS tới Zapier.
  3. Zapier Flow 39 được kích hoạt khi nhận webhook.

(Nguồn: Zapier Integration V7.pdf Flow 39 line 2616 — "Trigger: Webhook RESEND_RTRADER_INSTRUCTIONS received from Middleware Hub"; RFQ_ Stack Trading Prop Tech V7.pdf BPS Endpoint table lines 2941–2944)

Đặc tả BPS Endpoint:

TrườngGiá trị
MethodPOST
Path/bps/resend-rtrader-instructions
Inputuser_id, admin_id, reason
Response{ "status": "success" }
Tác độngGửi webhook RESEND_RTRADER_INSTRUCTIONS tới Zapier

(Nguồn: RFQ_ Stack Trading Prop Tech V7.pdf lines 2941–2944 — path /bps/resend-rtrader-instructions)

⚠️ Sai lệch path endpoint: Đặc tả do user cung cấp dùng /api/bps/rtrader-instructions. Nguồn V7 dùng /bps/resend-rtrader-instructions. Nguồn V7 là chuẩn — SotaTek phải triển khai /bps/resend-rtrader-instructions. Xác nhận với khách trước khi build.

RBAC gate: Yêu cầu tối thiểu token support Level_1 trở lên (bất kỳ JWT admin/support agent đã xác thực). KHÔNG yêu cầu vai trò cao hơn (Level_2 / Admin) cho endpoint này — khác với các hành động phá hủy (Hard Reset, Force Session Kick, Full Refund, Admin Platform Reassignment) vốn yêu cầu Level_2. Xác thực JWT trả về 401 nếu không hợp lệ/hết hạn; agent Level_1 được phép. admin_id và reason là các trường bắt buộc trong request body — mọi BPS POST endpoint đều bắt buộc tham số reason. (Nguồn: khách xác nhận 2026-08-26 — Stack Trading V7 BPS administrative security protocol)


3. Luồng cơ bản

Bước 1 — Admin tra cứu và thao tác

  • Admin tìm trader trong BPS Admin Panel theo user_id hoặc email.
  • BPS Panel hiển thị nút "Resend R|Trader Instructions" — luôn hiển thị và luôn nhấn được, bất kể trạng thái ký hiện tại của trader. Nút KHÔNG bị ẩn hay vô hiệu hóa dựa trên đầu ra của GET /bps/trader/market-data-status.
  • BPS Panel có thể gọi GET /bps/trader/market-data-status ở nền (non-blocking) để hiển thị nút ở một trong ba trạng thái:
    • Amber/Alert — phát hiện không khớp: db_entitlements có luồng exchange nhưng rithmic_status của exchange đó = false → tooltip: "Discrepancy Detected: Trader has unsigned agreements. Click to resend."
    • Muted/Success — đồng bộ hoàn toàn: mọi db entitlement khớp với chữ ký Rithmic đang hoạt động → tooltip: "All agreements successfully signed. Click to force resend if needed."
    • Neutral/Gray — chưa tải xong so sánh hoặc Rithmic API không khả dụng → nút vẫn hoạt động đầy đủ; admin vẫn có thể kích hoạt resend
  • Nhấn nút mở modal xác nhận hiển thị: địa chỉ email đích + ô nhập text "Reason for Resending" bắt buộc (cần cho việc ghi BPS_Audit_Log).
  • Admin điền reason và xác nhận → kích hoạt POST /bps/resend-rtrader-instructions.

(Nguồn: khách xác nhận 2026-08-26 — BPS Endpoints Passage 105/677; GET /bps/trader/market-data-status chỉ mang tính thông tin/chẩn đoán, không phải cổng hạn chế)

Bước 2 — Middleware xử lý

  • Middleware nhận POST /bps/resend-rtrader-instructions.
  • Gate check 1 — Auth: Xác thực Admin JWT. Nếu không hợp lệ hoặc hết hạn → 401 Unauthorized, không gửi webhook (xem Exc-5).
  • Gate check 2 — Asset class: asset_class = 'Futures'. Nếu là Forex → trả về 400 Bad Request, không gửi webhook (xem Exc-2).
  • Gate check 3 — Tra cứu user: Xác nhận user_id tồn tại trong PostgreSQL. Nếu không tìm thấy → 404 Not Found (xem Exc-1).
  • Gate check 4 — Kiểm tra credential: Xác nhận platform_username IS NOT NULL AND platform_username != ''. Nếu tài khoản Rithmic chưa được cấp phát → 422 Unprocessable Entity với thông báo "Rithmic account has not been provisioned yet". Không gửi webhook (xem Exc-6).
  • Gate check 5 — Rate limit & dedup:
    • Dedup (cửa sổ idempotency): Nếu một request giống hệt cho cùng user_id đã được xử lý trong 5 phút gần nhất → trả về 200 OK (thành công im lặng) mà không gửi webhook mới. Ngăn việc click đúp ngoài ý muốn mà không hiển thị lỗi gây nhầm lẫn cho admin.
    • Giới hạn hằng ngày: Nếu trader đã nhận 3–5 lần resend thành công trong 24 giờ gần nhất → trả về 429 Too Many Requests với thông báo: "Resend limit reached for this user. Please try again tomorrow." Không gửi webhook (xem Exc-8). (Nguồn: khách xác nhận 2026-09-09)
  • Xác định phase: Truy vấn account_status từ bảng Users để xác định template email sẽ dùng:
    • account_status = 'SIM_ACTIVE' (Level 0) → template = 'SES-44' (Non-Professional)
    • account_status = 'Active_DMA' (current_level >= 1) → template = 'SES-45' (Professional)
    • Mọi account_status khác (ví dụ Guest, Failed, Terminated, Locked, SUSPENDED_DEFENSE, In_Defense, Active_Challenge) → trả về 422 Unprocessable Entity với thông báo: "Trader is not in an active phase eligible for R|Trader instructions resend". Không gửi webhook. Lý do: các tài khoản ngoài SIM_ACTIVE / Active_DMA không có credential Rithmic đang hoạt động (sub-account chưa được gán hoặc bị soft-lock để dừng phí platform $25/tháng); gửi hướng dẫn đăng nhập cho tài khoản không hoạt động sẽ gây nhầm lẫn cho trader và làm quá tải support desk.
  • Middleware ghi một audit entry bất biến vào BPS_Audit_Log: { admin_id, action: "RESEND_RTRADER_INSTRUCTIONS", target_user_id, reason, template_used, timestamp }. Bắt buộc theo yêu cầu lưu trữ hồ sơ CFTC/NFA — mọi BPS POST endpoint đều thực thi điều này. (Nguồn: khách xác nhận 2026-08-26)
  • Middleware gửi webhook RESEND_RTRADER_INSTRUCTIONS tới Zapier với user_id, platform_username, email, template.

Bước 3 — Gửi mail (Flow 39)

  • Zapier Flow 39 được kích hoạt khi nhận webhook RESEND_RTRADER_INSTRUCTIONS.
  • Zapier đọc trường template từ payload webhook để chọn đúng template SES.
  • Zapier gọi AWS SES để gửi email tới địa chỉ email đã đăng ký của trader.

Phân nhánh template email:

Điều kiệnTemplatePhân loại CME
account_status = 'SIM_ACTIVE' (Level 0)SES-44 — RTrader_Setup_NonProNon-Professional
account_status = 'Active_DMA' (current_level >= 1)SES-45 — RTrader_Setup_ProProfessional (bắt buộc — vốn tự doanh)

Về đặc tả nội dung email đầy đủ và lý do tuân thủ, xem SES-44 và SES-45 trong list_email.md.

(Nguồn: Zapier Integration V7.pdf Flow 39 lines 2619–2623; phân loại Non-Pro vs. Pro: phân tích nghiệp vụ do user cung cấp 2026-08-26)

RÀNG BUỘC BẢO MẬT QUAN TRỌNG: platform_password_ciphertext KHÔNG BAO GIỜ được trả về cho Zapier và KHÔNG BAO GIỜ được đưa vào bất kỳ email nào. Mật khẩu chỉ trader truy cập được qua GET /platform-credentials trên Dashboard sau khi xác thực Auth0 OTP (hiển thị một lần). Ràng buộc này áp dụng cho TẤT CẢ các luồng email, bao gồm Flow 39.

Hậu điều kiện: Trader nhận được email. Bản thân Flow 39 không kích hoạt thay đổi trạng thái DB nào trong bảng Users. Trạng thái luồng dữ liệu vẫn bị khóa cho đến khi trader hoàn tất việc ký trong R|Trader Pro — việc cập nhật trạng thái diễn ra qua cơ chế callback riêng của Rithmic (ngoài phạm vi Flow 39).


4. Luồng ngoại lệ

Exc-1 — Không tìm thấy user_id

  • Middleware tra cứu user_id không có bản ghi.
  • Trả về 404 Not Found cho BPS Admin Panel.
  • Không gửi webhook. Không gửi email.
  • Admin kiểm tra lại user_id và thử lại.

Exc-2 — Trader Forex (ngoài phạm vi)

  • Middleware phát hiện asset_class IN ('Forex_MT5', 'Forex_TE').
  • Trả về 400 Bad Request với thông báo: "Flow 39 is scoped to Futures traders only. Forex traders use MT5/TE platform — no CME agreements required."
  • Không gửi webhook. Không gửi email.

Exc-3 — Gửi email SES thất bại (Hard Bounce / Complaint)

  • AWS SES trả về Bounce (email không tồn tại) hoặc Complaint (trader báo spam) qua SNS webhook tới Middleware.
  • Mức độ nghiêm trọng: SEV-2 — #ops-alerts. Chỉ ảnh hưởng đường gửi của một trader.
  • Cập nhật DB: Middleware tự động đặt email_delivery_status = 'Bounced' hoặc 'Complaint' + email_banned = TRUE trên bản ghi của trader.
  • BPS Panel: Banner đỏ hiển thị trên màn hình chi tiết của trader: ⚠️ Email Delivery Blocked: Hard Bounce / Complaint Registered.
  • Trạng thái nút: "Resend R|Trader Instructions" bị vô hiệu hóa/làm xám vĩnh viễn cho đến khi Admin cập nhật địa chỉ email hợp lệ mới cho trader — ngăn spam SES và bảo vệ Sender Reputation của nền tảng (SPF/DKIM/DMARC). Cố ý không tự động retry khi Hard Bounce; retry một địa chỉ chết khiến AWS SES hạ điểm sender của Stack Trading và có thể đình chỉ tài khoản SES. (Nguồn: khách xác nhận 2026-09-09 — Stage 3 - KYC - DOT's Feedback.pdf Category B Row 4; Zapier Integration V7.pdf pp.102, 166, 228; RFQ_ Stack Trading Prop Tech V7.pdf §1.0)

Exc-4 — Zapier không nhận được webhook

  • Middleware gửi webhook RESEND_RTRADER_INSTRUCTIONS nhưng Zapier trả về 5xx hoặc timeout (> 10s).
  • Mức độ nghiêm trọng: SEV-1 — #ops-alerts. Nâng lên SEV-1 vì đây là kết nối bị hỏng giữa Middleware và bus tích hợp Zapier chính.
  • Retry: Middleware retry 3× với Exponential Backoff. Nếu cạn mọi retry → trạng thái được ghi là Failed_Exhausted trong bảng failed_webhooks_queue.
  • BPS Panel: Admin theo dõi lỗi tại tab "Failed Webhooks Monitor" trong BPS Admin Console. Mỗi hàng log hiển thị: timestamp, Trader ID, tên flow (Resend R|Trader Instructions — Flow 39), số lần retry (3/3), mã lỗi Zapier.
  • Khôi phục: Một nút 🔄 Replay Webhook xuất hiện cạnh entry log. Khi Zapier được khôi phục, Admin nhấn nút để Middleware đẩy lại payload thủ công — không cần trader khởi động lại quy trình. (Nguồn: khách xác nhận 2026-09-09 — Zapier Integration V7.pdf pp.146–147 [Webhook Reliability: provider_event_id + correlation_id for replay/dedup], p.147 [Break-glass runbook mandate], p.198 [failed_webhooks_queue + Replay]; RFQ_ Stack Trading Prop Tech V7.pdf p.13 [CloudWatch → Slack SEV-1 alerting])

Exc-5 — Admin JWT không hợp lệ hoặc hết hạn

  • Xác thực JWT của Middleware thất bại (token hết hạn, sai định dạng hoặc vai trò RBAC không đủ).
  • Trả về 401 Unauthorized.
  • Không tiếp tục các gate check. Không gửi webhook. Không gửi email.
  • Admin xác thực lại và thử lại.

Exc-6 — Tài khoản Rithmic chưa được cấp phát

  • Middleware phát hiện platform_username IS NULL OR platform_username = '' của trader đích.
  • Trả về 422 Unprocessable Entity với thông báo: "Rithmic account has not been provisioned yet".
  • Không gửi webhook. Không gửi email.
  • Admin kiểm tra trạng thái cấp phát của trader và escalate lên đội BE nếu việc cấp phát thất bại ở upstream.

Exc-7 — Trader không ở phase đang hoạt động

  • Middleware phát hiện account_status KHÔNG phải SIM_ACTIVE hoặc Active_DMA (ví dụ Guest, Failed, Terminated, Locked, SUSPENDED_DEFENSE, In_Defense, Active_Challenge).
  • Trả về 422 Unprocessable Entity với thông báo: "Trader is not in an active phase eligible for R|Trader instructions resend".
  • Không gửi webhook. Không gửi email.
  • Lý do: các tài khoản ở những trạng thái này không có credential Rithmic đang hoạt động (sub-account chưa được gán hoặc bị soft-lock). Gửi hướng dẫn đăng nhập cho tài khoản không hoạt động thì không có template hợp lệ để chọn và gây nhầm lẫn cho trader + làm quá tải support desk. Áp dụng khớp template theo kiểu best-effort hoặc mặc định SES-45 có nguy cơ gửi sai hướng dẫn phân loại CME — vi phạm quy định. (Nguồn: khách xác nhận 2026-08-26 — RFQ_ Stack Trading Prop Tech V7.pdf §508, §516, §521, §522)

Exc-8 — Vượt giới hạn resend hằng ngày

  • Middleware phát hiện trader đã nhận 3–5 lần resend thành công trong 24 giờ gần nhất.
  • Trả về 429 Too Many Requests với thông báo: "Resend limit reached for this user. Please try again tomorrow."
  • Không gửi webhook. Không gửi email.
  • Admin phải chờ cửa sổ 24 giờ được đặt lại trước khi thử lại. (Nguồn: khách xác nhận 2026-09-09)

BR_9.17.1 — Phạm vi chỉ Futures Flow 39 chỉ áp dụng cho trader có asset_class = 'Futures'. Trader Forex (MT5/TE) không dùng Rithmic, không có thỏa thuận subscriber CME, và bị loại trừ rõ ràng. Middleware phải gate theo asset_class trước khi gửi webhook. (Nguồn: Zapier Integration V7.pdf Flow 39 — các thỏa thuận CME/CBOT/NYMEX/COMEX là đặc thù của Rithmic)

BR_9.17.2 — Chỉ admin kích hoạt thủ công (phạm vi hiện tại) Flow 39 hiện là hành động BPS do admin kích hoạt thủ công. Hành vi tự động kích hoạt sau khi cấp phát Rebuy là câu hỏi mở đang chờ (F39-Q1/F39-Q2). Cho đến khi Rithmic xác nhận phạm vi gắn kết của thỏa thuận CME (User ID hay sub-account), không được triển khai auto-trigger. (Xem §6 — F39-Q1, F39-Q2)

BR_9.17.3 — Không bao giờ đưa mật khẩu vào email Mật khẩu platform Rithmic của trader KHÔNG ĐƯỢC đưa vào bất kỳ payload email nào. Email phải hướng trader đến luồng lấy credential trên Dashboard (GET /platform-credentials sau Auth0 OTP). Đây là ràng buộc bảo mật tuyệt đối áp dụng cho mọi luồng.

BR_9.17.4 — Nội dung email: bắt buộc 4 thỏa thuận exchange Email phải bao gồm hướng dẫn ký cho cả 4 sàn CME Group: CME, CBOT, NYMEX, COMEX. Bỏ sót bất kỳ thỏa thuận nào dẫn đến việc kích hoạt luồng dữ liệu không đầy đủ cho exchange tương ứng. (Nguồn: Zapier Integration V7.pdf Flow 39 lines 2622–2623)

BR_9.17.5 — Bắt buộc ghi BPS_Audit_Log (tuân thủ CFTC/NFA) Mỗi lần gọi POST /bps/resend-rtrader-instructions phải ghi một bản ghi bất biến vào bảng audit BPS trong PostgreSQL. Các trường bắt buộc: admin_id, user_id, action (RESEND_RTRADER_INSTRUCTIONS), timestamp, reason, transcript_url. Điều này đáp ứng yêu cầu lưu trữ hồ sơ của CFTC và NFA cho mọi hành động override quản trị và hỗ trợ được thực hiện qua Support Screen. (Nguồn: khách xác nhận 2026-08-26 — mọi BPS POST endpoint đều thực thi giao thức audit)

BR_9.17.6 — [PENDING F39-Q1] CME agreement carry-over khi Rebuy Nếu Rithmic xác nhận các thỏa thuận CME gắn với User ID (không phải sub-account), trader không cần ký lại sau Rebuy. Trong trường hợp này, Flow 39 KHÔNG nên tự động kích hoạt sau Rebuy, và việc kiểm tra không khớp GET /bps/trader/market-data-status là chỉ báo duy nhất để gửi lại. Nếu thỏa thuận gắn với sub-account → bắt buộc auto-trigger. Việc triển khai bị chặn chờ phản hồi từ Rithmic.

BR_9.17.7 — Template email phải khớp với phase tài khoản của trader Middleware PHẢI xác định đúng template trước khi gửi webhook. Gửi SES-44 (hướng dẫn Non-Professional) cho trader Live DMA là rủi ro tuân thủ CME. Gửi SES-45 (hướng dẫn Professional) cho trader SIM sẽ gây nhầm lẫn không cần thiết. Việc chọn template là không thể thương lượng và phải dựa trên account_status tại thời điểm gọi.

BR_9.17.8 — Rate limiting: cửa sổ dedup + giới hạn hằng ngày Middleware PHẢI thực thi hai lớp chống spam trên POST /bps/resend-rtrader-instructions:

  • Cửa sổ dedup (Idempotency): Các request giống hệt cho cùng user_id trong cửa sổ 5 phút bị chặn im lặng — Middleware trả về 200 OK mà không gửi webhook mới. Ngăn kịch bản click đúp ngoài ý muốn.
  • Giới hạn hằng ngày: Tối đa 3–5 lần resend thành công cho mỗi trader trong cửa sổ trượt 24 giờ. Vượt giới hạn trả về 429 Too Many Requests với thông báo: "Resend limit reached for this user. Please try again tomorrow." Không gửi webhook.

Lý do: bảo vệ sender reputation của SES (tỷ lệ bounce/complaint cao do gửi lặp lại tới cùng một địa chỉ có thể khiến AWS đình chỉ tài khoản) và ngăn các vòng lặp lỗi của admin làm ngập inbox của trader. (Nguồn: khách xác nhận 2026-09-09)

BR_9.17.9 — Trader tự phục vụ: admin_id và reason phải do hệ thống điền (UI 2026-10-20) Khi Flow 39 được kích hoạt qua modal trên Dashboard của trader (nút "Resend Instructions"), frontend Dashboard KHÔNG ĐƯỢC yêu cầu trader nhập admin_id hay reason. Các trường này bắt buộc theo endpoint để tuân thủ BPS_Audit_Log. Frontend PHẢI tự động điền:

  • admin_id = "SYSTEM_TRADER_SELF_SERVICE"
  • reason = "Trader self-initiated via Dashboard modal"

Điều này giữ nguyên audit trail bắt buộc mà không để lộ các trường admin cho trader.

BR_9.17.10 — Pop-up hiển thị mỗi lần vào tab "Command" Với tài khoản Futures (account_status IN ('SIM_ACTIVE', 'Active_DMA')) có CME Market Data Agreements chưa ký, pop-up "Action Required: Exchange Agreements Pending" PHẢI hiển thị mỗi lần trader mở hoặc chuyển tới tab "Command". Tắt pop-up không lưu trạng thái; pop-up xuất hiện lại ở lần vào tiếp theo. (Nguồn: Flow 39 update 2026-11-05)

BR_9.17.11 — Completion Gate: Signed_Completely Khi backend xác nhận qua Rithmic rằng việc ký đã hoàn tất, hệ thống PHẢI lưu Signed_Completely = Yes. Khi cờ đã được đặt, hệ thống dừng kiểm tra ký trên Rithmic và không bao giờ hiển thị lại pop-up cho trader đó. (Nguồn: Flow 39 update 2026-11-05)


6. Câu hỏi mở (đang chờ Rithmic làm rõ)

#Câu hỏiTác độngTrạng thái
F39-Q1Các thỏa thuận subscriber CME/CBOT/NYMEX/COMEX — gắn với Rithmic User ID hay sub-account? Sau Rebuy (sub-account mới, cùng User ID), trader có cần ký lại không? Trạng thái "Data Feed Locked" có xuất hiện lại cho sub-account mới không?Quyết định liệu có cần auto-trigger Flow 39 sau Rebuy hay không. Ảnh hưởng BR_9.17.2 và BR_9.17.6.🔴 Mở — chặn thiết kế UX rebuy
F39-Q2Khi một sub-account mới được cấp phát vào User ID hiện có (kịch bản rebuy), R|Trader Pro có tự động nhắc lại màn hình ký thỏa thuận ở lần đăng nhập kế tiếp của trader — hay luồng dữ liệu chuyển thẳng sang Active vì User ID đã ký?Quyết định liệu Flow 39 có cần auto-trigger trong chuỗi rebuy Flow 3H hay chỉ thủ công là đủ.🔴 Mở — chặn thiết kế luồng rebuy
F39-Q3Nếu GET /bps/trader/market-data-status trả về trạng thái luồng dữ liệu không khớp với DB entitlement (ví dụ DB báo CME=Active nhưng Rithmic báo CME=false), có API nào để force-sync hoặc re-provision luồng dữ liệu trực tiếp không — tách biệt với việc gửi email resend cho trader?Quyết định liệu nút "Resend Instructions" có đủ để khắc phục không khớp, hay cũng cần một hành động admin force-sync.🟡 Mở — ảnh hưởng phạm vi BPS panel

7. Tiêu chí chấp nhận

IDKịch bảnKết quả mong đợi
AC-9.17-01Admin gọi POST /bps/resend-rtrader-instructions với user_id hợp lệ của trader Futures SIMWebhook RESEND_RTRADER_INSTRUCTIONS được gửi với template = 'SES-44'; Flow 39 gửi email SES-44 (hướng dẫn Non-Professional); trả về response { "status": "success" }
AC-9.17-02Admin gọi endpoint với user_id hợp lệ của trader Live DMA (Level 1+)Webhook RESEND_RTRADER_INSTRUCTIONS được gửi với template = 'SES-45'; Flow 39 gửi email SES-45 (hướng dẫn Professional kèm cảnh báo tuân thủ); trả về response { "status": "success" }
AC-9.17-03Trader SIM nhận email (SES-44)Subject = "Stack Trading: Market Data & R|Trader Pro Setup"; chứa platform_username; chứa link tải R|Trader Pro; hướng dẫn chọn Non-Professional; KHÔNG chứa mật khẩu
AC-9.17-04Trader Live DMA nhận email (SES-45)Subject = "Stack Trading: Market Data & R|Trader Pro Setup"; chứa platform_username; chứa link tải R|Trader Pro; hướng dẫn chọn Professional; chứa cảnh báo tuân thủ CME; KHÔNG chứa mật khẩu
AC-9.17-05Admin gọi endpoint với user_id của trader Forex_MT5 hoặc Forex_TEMiddleware trả về 400 Bad Request; không gửi webhook; không gửi email
AC-9.17-06Admin gọi endpoint với user_id không tồn tạiMiddleware trả về 404 Not Found; không gửi webhook; không gửi email
AC-9.17-07Admin gọi endpoint với JWT hết hạn hoặc không hợp lệMiddleware trả về 401 Unauthorized; không gửi webhook; không gửi email
AC-9.17-08Admin gọi endpoint cho trader có platform_username là NULL hoặc rỗngMiddleware trả về 422 Unprocessable Entity với thông báo "Rithmic account has not been provisioned yet"; không gửi webhook; không gửi email
AC-9.17-09Flow 39 được kích hoạt — trạng thái DB sau khi thực thiBản thân Flow 39 không sửa trường nào trong bảng Users; trạng thái luồng dữ liệu không đổi cho đến khi trader hoàn tất việc ký trong R|Trader Pro
AC-9.17-10Admin gọi endpointAudit entry được ghi vào BPS_Audit_Log với admin_id, user_id, action: "RESEND_RTRADER_INSTRUCTIONS", reason, transcript_url, timestamp — bắt buộc theo yêu cầu lưu trữ hồ sơ CFTC/NFA
AC-9.17-11Admin gọi endpoint cho trader có account_status là Failed, Terminated, Guest, Locked, SUSPENDED_DEFENSE, In_Defense hoặc Active_ChallengeMiddleware trả về 422 Unprocessable Entity với thông báo "Trader is not in an active phase eligible for R|Trader instructions resend"; không gửi webhook; không gửi email
AC-9.17-12Admin kích hoạt resend cho cùng user_id hai lần trong vòng 5 phútRequest thứ hai trả về 200 OK (thành công im lặng); không gửi webhook mới; không gửi email trùng lặp
AC-9.17-13Admin kích hoạt resend cho trader đã nhận số lần resend tối đa hằng ngày (3–5) trong 24 giờMiddleware trả về 429 Too Many Requests với thông báo "Resend limit reached for this user. Please try again tomorrow."; không gửi webhook; không gửi email
AC-9.17-14AWS SES trả về Hard Bounce cho email của traderemail_delivery_status = 'Bounced' + email_banned = TRUE được đặt trên bản ghi trader; banner đỏ ⚠️ Email Delivery Blocked: Hard Bounce / Complaint Registered hiển thị trong BPS Panel; nút "Resend" bị làm xám; cảnh báo SEV-2 gửi tới #ops-alerts
AC-9.17-15Middleware gửi webhook nhưng Zapier trả về 5xx / timeoutMiddleware retry 3× với exponential backoff; khi cạn retry: trạng thái Failed_Exhausted được ghi vào failed_webhooks_queue; entry hiển thị trong tab "Failed Webhooks Monitor" của BPS với nút 🔄 Replay Webhook; cảnh báo SEV-1 gửi tới #ops-alerts
AC-9.17-16Trader Futures có thỏa thuận CME chưa ký mở tab "Command"Modal "Action Required: Exchange Agreements Pending" hiển thị với các nút "Resend Instructions" và "Cancel"
AC-9.17-16bTrader tắt modal, rời tab "Command" rồi quay lại (thỏa thuận vẫn chưa ký)Modal hiển thị lại
AC-9.17-17Trader nhấn "Resend Instructions" trên modal DashboardPOST /resend-rtrader-instructions được gọi với admin_id = "SYSTEM_TRADER_SELF_SERVICE" và reason = "Trader self-initiated via Dashboard modal"; áp dụng cùng các gate check như đường admin; khi thành công: nút hiển thị trạng thái xác nhận; khi 429: lỗi inline hiển thị trong modal
AC-9.17-18Backend nhận xác nhận từ Rithmic rằng trader đã ký toàn bộ thỏa thuận CMELưu Signed_Completely = Yes; lần vào tab "Command" tiếp theo không hiển thị modal và không kích hoạt kiểm tra Rithmic

On this page

Bản dịch: UC_9.2 → UC_9.17 (BACKGROUND MECHANISMS & CRON JOBS)Mục lụcUC_9.2 — Luồng 13: Quản lý Nghỉ phép (DTO W-2 & Tạm ngưng Quốc tế)Danh mục UCUC_9.2 — Luồng 13: Quản lý Nghỉ phép (DTO W-2 & Tạm ngưng Quốc tế)1. Tổng quan2. Trigger2.1 Trigger Path A — webhook Rippling Time Off Request Approved2.2 Trigger Path B — form "Request Time Off" trên Dashboard (chỉ International Contractor)2.3 Cổng vào (cả hai kênh)3. Path Router4. Luồng cơ bảnPath A — USA W-2 Paid DTOPath B — International Contractor Unpaid HiatusReturn Protocol (áp dụng cho cả hai Path)4.1 Trường hợp đặc biệt: Xử lý Pod Leader & Founding Mentor (Level 7+)4.1.1 Failsafe Anti-Termination Gate4.1.2 Tài nguyên được giữ nguyên trong On_Leave4.1.3 Hành vi của Carry Balance4.1.4 Pod_Leader_Registry Status trong thời gian nghỉ4.1.5 SLA của Pod trong thời gian nghỉ5. Điều kiện tiên quyết6. Hậu điều kiện7. Luồng thay thế8. Luồng ngoại lệ9. Quy tắc nghiệp vụ10. Tiêu chí chấp nhận10.1 Câu hỏi mở (CR-20261027-001)11. Lịch sử thay đổiUC_9.3 — Luồng 18: Sao lưu Cơ sở dữ liệu Cấu hình & Đồng bộ Khôi phục Thảm họaDanh mục UCUC_9.3 — Luồng 18: Sao lưu Cơ sở dữ liệu Cấu hình & Đồng bộ Khôi phục Thảm họa1. Tổng quan2. Trigger3. Luồng cơ bảnBước 1 — Export Zapier TablesBước 2 — Upload lên S3Bước 3 — Xác minh sao lưu độc lậpBước 4 — Xử lý lỗi: Retry, sau đó Cảnh báo4. Điều kiện tiên quyết5. Hậu điều kiện6. Luồng ngoại lệ7. Quy tắc nghiệp vụ8. Yêu cầu phi chức năng9. Tiêu chí chấp nhận10. Lịch sử cập nhậtUC_9.8 — Luồng 30: Cảnh báo Công suất MIDDanh mục UCUC_9.8 — Luồng 30: Cảnh báo Công suất MID1. Tổng quan2. Trigger3. Luồng cơ bảnBước 1 — Cập nhật khối lượng (upstream — Process Payment Webhook)Bước 2 — Kiểm tra công suất (POST /merchant/check-capacity)Bước 3 — Cảnh báo Slack4. Mô hình dữ liệuBảng Merchant_Routing_Config (PostgreSQL)5. Tham chiếu API6. Luồng ngoại lệ7. Quy tắc nghiệp vụ8. Tiêu chí chấp nhận9. Lịch sử thay đổiUC_9.9 — Luồng 31: Giám sát Cạn kiệt Tổng hợp (Sev-1)Danh mục UCUC_9.9 — Luồng 31: Giám sát Cạn kiệt Tổng hợp (Sev-1)1. Tổng quan2. Trigger3. Luồng cơ bảnBước 1 — Trigger theo lịch (Zapier)Bước 2 — Tính toán pacing (GET /calculate-volume-pacing)Bước 3 — Zapier FilterBước 4 — Cảnh báo Slack SEV-14. API EndpointGET /calculate-volume-pacing5. Cổng an toàn & Trường hợp biênEdge Case 1 — Chặn nhiễu đầu tháng (thời gian ân hạn 3 ngày dương lịch)Edge Case 2 — Tất cả MID không active (total_aggregate_capacity = 0)Edge Case 3 — Endpoint không khả dụng6. Quy tắc nghiệp vụ7. Mối quan hệ với UC_9.8 (Flow 30)8. Tiêu chí chấp nhận9. Câu hỏi mở10. Lịch sử thay đổiUC_9.11 — Luồng 34: Đồng bộ Sổ cái Lương Rippling1. Danh mục UCUC_9.11 — Luồng 34: Đồng bộ Sổ cái Lương Rippling2. Trigger3. Điều kiện tiên quyết4. Hậu điều kiện5. Luồng cơ bản6. Luồng thay thế7. Luồng ngoại lệ8. Quy tắc nghiệp vụBR_9.11.1: Phạm vi — Chỉ trader W-2 đang hoạt độngBR_9.11.2: Ánh xạ sổ cái cố địnhBR_9.11.3: Một kỳ lương = Một event sổ cái (idempotency)BR_9.11.4: Ghi sổ cái chỉ dành cho Owner, chỉ dạng EventBR_9.11.5: tx_hash được lưu trước khi trả response thành côngBR_9.11.6: Luồng 34 chỉ ghi lương định kỳ — Các khoản chi trả off-cycle do chính luồng của chúng ghi nhậnBR_9.11.7: Lưu trữ audit9. Tiêu chí chấp nhận10. Tham chiếu APIPOST /api/ledger/record11. Câu hỏi mở12. Lịch sử thay đổiUC_9.12 — Luồng 35: Đồng bộ Sổ cái PTO Rippling1. Danh mục UCUC_9.12 — Luồng 35: Đồng bộ Sổ cái PTO Rippling2. Trigger3. Điều kiện tiên quyết4. Hậu điều kiện5. Luồng cơ bản6. Luồng thay thế7. Luồng ngoại lệ8. Quy tắc nghiệp vụBR_9.12.1: Chỉ ghi sổ cáiBR_9.12.2: Ánh xạ sổ cái cố địnhBR_9.12.3: Phạm vi — Chỉ W-2 đang hoạt độngBR_9.12.4: Một lần phê duyệt = Một event sổ cáiBR_9.12.5: Lưu trữ audit9. Tiêu chí chấp nhận10. Tham chiếu API11. Câu hỏi mở12. Lịch sử thay đổiUC_9.13 — Luồng 36: Đồng bộ Sổ cái Retainer Dots1. Danh mục UCUC_9.13 — Luồng 36: Đồng bộ Sổ cái Retainer Dots2. Trigger3. Điều kiện tiên quyết4. Hậu điều kiện5. Luồng cơ bản6. Luồng thay thế7. Luồng ngoại lệ8. Quy tắc nghiệp vụBR_9.13.1: Phạm vi — contractor quốc tế đang hoạt động, Level 6+BR_9.13.2: Ánh xạ sổ cái cố địnhBR_9.13.3: Hardened Ingress (Option B) là bắt buộc đối với DotsBR_9.13.4: Một retainer = Một event sổ cáiBR_9.13.5: Lưu trữ audit9. Tiêu chí chấp nhận10. Tham chiếu API11. Câu hỏi mở12. Lịch sử thay đổiUC_9.14 — Luồng 32: Velocity Reward Engine1. Danh mục UCUC_9.14 — Luồng 32: Velocity Reward Engine2. Trigger3. Điều kiện tiên quyết4. Hậu điều kiện5. Luồng cơ bản6. Luồng thay thế7. Luồng ngoại lệ8. Quy tắc nghiệp vụBR_9.14.1: Idempotency là bắt buộc — PostgreSQL FOR UPDATE + UNIQUE IndexBR_9.14.2: Cổng Sanctions chạy trước khi tạo mã khuyến mãiBR_9.14.3: Tham số mã khuyến mãi là cố địnhBR_9.14.4: Triển khai Discord — chỉ dùng native fetch(), không dùng axiosBR_9.14.5: Giới hạn tốc độ Discord — 5 tin nhắn mỗi 5 giây qua Redis QueueBR_9.14.6: Audit Trail CFTC/NFA — S3 Glacier WORM, lưu trữ 5 năm + 1 thángBR_9.14.7: Exponential Backoff — Cơ số 5s, 3 lần Retry, SEV-2 khi cạn RetryBR_9.14.8: Chỉ có hai sự kiện mốc hợp lệ9. Tiêu chí chấp nhận10. Mô hình dữ liệuBảng: promo_codesBảng: idempotency_log (logic — có thể trùng với bảng idempotency hiện có)11. Tham chiếu APIPOST /api/referral/velocity-reward12. Câu hỏi mở13. Lịch sử thay đổiUC_9.15 — Luồng 33: Xác minh Amplify Bounty1. Danh mục UCUC_9.15 — Luồng 33: Xác minh Amplify Bounty2. Trigger3. Điều kiện tiên quyết4. Hậu điều kiện5. Luồng cơ bản6. Luồng thay thế7. Luồng ngoại lệ8. Quy tắc nghiệp vụBR_9.15.1: Chỉ nhận đầu vào có cấu trúcBR_9.15.2: Nền tảng được hỗ trợBR_9.15.3: Một lần gửi mỗi 24 giờ cho mỗi discord_user_idBR_9.15.4: Một phần thưởng cho mỗi URLBR_9.15.5: Ngưỡng định lượngBR_9.15.6: Quyền riêng tư với LLMBR_9.15.7: Định nghĩa phần thưởngBR_9.15.8: Nội dung thông báo được cố định9. Tiêu chí chấp nhận10. Tham chiếu APIGET /bounty/check-urlPOST /generate-promo-code11. Câu hỏi mở12. Lịch sử thay đổiUC_9.16 — Luồng 38: Chặn Hỗ trợ & Tạo Ticket Freshdesk1. Danh mục UCUC_9.16 — Luồng 38: Chặn Hỗ trợ & Tạo Ticket Freshdesk2. Trigger3. Điều kiện tiên quyết4. Hậu điều kiện (nhánh Complaint)5. Luồng cơ bản6. Luồng thay thế7. Luồng ngoại lệ8. Quy tắc nghiệp vụBR_9.16.1: Các kênh được giám sátBR_9.16.2: Từ khóa triggerBR_9.16.3: Cổng LLM là bắt buộcBR_9.16.4: Nền tảng ticketing là FreshdeskBR_9.16.5: Ánh xạ ticketBR_9.16.6: Thứ tự hành độngBR_9.16.7: Một ticket cho mỗi discord_id mỗi ngày UTC9. Tiêu chí chấp nhận10. Câu hỏi mở11. Lịch sử thay đổiUC_9.17 — Luồng 39: Gửi lại Hướng dẫn Dữ liệu Thị trường BPSDanh mục UCLịch sử thay đổiThuật ngữUC_9.17 — Luồng 39: Gửi lại Hướng dẫn Dữ liệu Thị trường BPS1. Tổng quan1b. Giao diện dành cho Trader — Modal "Action Required: Exchange Agreements Pending"1a. Bối cảnh nghiệp vụ2. Trigger3. Luồng cơ bản4. Luồng ngoại lệ6. Câu hỏi mở (đang chờ Rithmic làm rõ)7. Tiêu chí chấp nhận