UC 8.1.1
Flow 4A - Promotion: Profit_Target_Hit trigger — Stage 1 Lock & Liquidate through Stage 5 Klaviyo/Everflow emission
| Field | Value |
|---|---|
| BA in Charge | Huyen Dinh |
| Date Created | 2026-10-06 |
| Version | v1.11 |
| Document References | Zapier Integration V7.pdf (§Flow 4 — Retention, Promotion & "Delta" Funding, Tables A/B/G/H) · RFQ_ Stack Trading Prop Tech V7.pdf (§Financial & Transaction Endpoints, §Immutable Ledger / Proof of Payout) · Discord Server Details.md (§Compiled Discord Roles and Badges, §Announcements) |
Scope note (Source: QnA_init_docs.md A-00/A-09): This UC owns the FULL Flow 4A core pipeline (Stage 1–5), including Level 24 Prestige Reset and Defense Protocol Recharge Check (Standard Accrual). No separate
UC_8.4.1/UC_8.4.2/UC_8.4.3are created — this was an explicit client-confirmed scope decision, not an omission.
1. Overview
| Field | Content |
|---|---|
| ID | UC_8.1.1 |
| Use Case | Flow 4A: Promotion (Profit_Target_Hit) |
| Description | When a trader's live account hits its profit target, the Middleware deduplicates the event, locks and liquidates the account, resets the ledger, calculates next-level parameters, updates risk/account state across execution platforms, logs the promotion immutably, announces the promotion on Discord, calculates any Level 3 data-fee refund, and emits the Level-dependent Klaviyo/Everflow/Perk payloads. |
| Zapier Flow | Flow 4 (Retention, Promotion & "Delta" Funding) — Trigger A:Profit_Target_Hit |
| Zapier Table | Table A (Forex Level Params, incl.Margin_Rate) · Table B (Futures Level Params) · Table G (Discord Title Mapping) · Table H (Perks Registry) |
| 3rd Party | Rithmic / MT5 / TraderEvolution (execution platforms — lock, flatten, risk update) · Discord (promotion announcement, role sync) · Polygon (Ethers.js — immutable ledger write) · AWS S3 (certificate PNG storage) · Klaviyo (lifecycle promotion emails) · Everflow (Level 6 affiliate bounty S2S postback) · AWS SES (operational emails) |
Trigger
The Middleware receives webhook Profit_Target_Hit from the execution platform (Rithmic, MT5, or TraderEvolution) indicating a live trader has reached their profit target for the current level.
Pre-conditions
- The trader holds an active Live account (
Status == 'Active_DMA'). - The
Event_IDassociated with thisProfit_Target_Hitwebhook has not been previously processed (deduplication check).
Post-conditions
- The trader's
Current_Levelis incremented toNext_Level. - The trader's execution account (Rithmic/MT5/TraderEvolution) is flat, re-enabled for trading, with risk parameters updated to the new level.
ledgers.virtual_equityandledgers.allocated_capitalreflect the newLevel_Starting_Capital.- The promotion event is recorded on the immutable ledger (Polygon) and a certificate (PNG) is available via
GET /certificate. - The appropriate Discord role is assigned and (if applicable) the promotion is announced in the corresponding channel.
- The appropriate Klaviyo promotion payload (Path A/B/C) has been emitted.
stagnation_deadlineis reset toToday + 90 Days.
Basic Flow
Stage 1 — Dedup, Lock & Liquidate, Immutable Ledger Write, Prestige Reset trigger
-
Users reach profit target, and the execution does the work:
- Flatten all open positions.
- Cancel: the broker cancels all working/pending orders.
- Lock (login-but-no-trade): the broker puts the account into a login-but-no-trade state
-
Execution platform fire the
Profit_Target_Hitwebhook to the Middleware. The Middleware checksEvent_IDagainst the SQL database.- [If
Event_IDalready exists] → the Middleware halts — no stage of the promotion pipeline executes again for that event. This prevents duplicate promotions, duplicate payouts, and duplicate ledger entries if the webhook fires twice or the network retries.
- [If
-
Blocking gate: Every later steps and stages MUST NOT begin until the account is confirmed 100% flat (
Open_Positions == 0).- If the liquidation cannot complete immediately, the downstream stages simply remain blocked until the flat confirmation arrives.
-
[If
Current_Level == 24] → the Middleware executes the Level 24 Prestige Reset branch instead of the standard promotion path and halts after completion — Stages 2–5 below do not run for this event. No promotion certificate is generated for this branch — see BR_8.1.1.3. -
[Else] Still before any other Stage 2/3 processing, the Middleware sets
Next_Level = Current_Level + 1and looks up Table A (Forex) or Table B (Futures) for theNext_Levelrow, then calculatesLevel_Starting_Capital:- Futures:
Level_Starting_Capital = Futures_Capital(from Table B). [CHR-122]Forex:Level_Starting_Capital = (Max_Forex_Notional * Margin_Rate) + Market_Loss_When_Stopped, whereMargin_Rate,Max_Forex_Notional,Market_Loss_When_Stoppedare read from Table A.
- Futures:
-
[CHR-128]The Middleware callsPOST /api/ledger/recordto write the promotion metric to the immutable ledger (Polygon) — this is a blocking step: theLEVEL_PROMOTIONWebSocket event (step below) MUST NOT fire until this write completes successfully:Input field Value trader_idID of the promoted trader metric_category"Capital Allocation Upgraded"metric_valueFutures: "Level [Next_Level] Reached ($[Next_Level_Starting_Balance] Equivalent Unlocked)"Forex:"Level [Next_Level] Reached ($[Next_Level_Starting_Balance] Unlocked)"—Next_Level_Starting_Balanceis NOTLevel_Starting_Capital. Forex:Max_Forex_Notional(purchasing power, e.g. "$25,000 Unlocked"). Futures:Max_Contracts_ES_Equiv(contract-count limit, e.g. "8 ES Equivalent Unlocked") — cash capital is never displayed for Futures. Both values are read directly from Table A/B, independent of theLevel_Starting_Capitalformula calculated in step 5.dateToday receipt_hashInternal PostgreSQL ledger record ID (temporary reference, not a blockchain hash) Processing sequence:
- Validate the JWT signature.
- Initialize the server-side Ethers.js wallet.
- Call
contract.recordMetric()via the Alchemy RPC to write the metric to the Polygon smart contract. - On confirmation, save the returned
tx_hash(the real Polygon transaction hash) into PostgreSQL. The Middleware MUST NOT proceed to step 7 until this save succeeds. tx_hashis now saved and immediately available for the following uses:- Display the record publicly via
GET /public/ledger. - Render the PolygonScan QR code onto the certificate PNG generated in step 7.
- Display the record publicly via
-
Certificate generation: once the
tx_hashwrite succeeds, the certificate is generated as a PNG viaGET /certificate, using the savedtx_hashto render the PolygonScan QR code, and the backend pushes this PNG to the S3 immutable storage bucket, storing the resulting S3 URL soGET /certificatecan return it later for a hard-copy download. -
Once the S3 upload in step 7 succeeds, the Middleware fires the
LEVEL_PROMOTIONWebSocket event. The frontend, upon receiving it, immediately begins the celebration sequence — cinematic motion first, then the certificate animation, then the post-certificate modal (see BR_8.1.1.4).- If the trader is not logged in, the cinematic/certificate sequence instead plays on their next login, for the latest level achieved.
Stage 2 — Ledger Reset, Pod Leader Carry, Defense Recharge Check
-
The Middleware updates:
- Captures the trader's final realized PnL (after the account is confirmed flat) into
historical_pnl. - Resets
ledgers.virtual_equity = 0as an atomic accounting step.
- Captures the trader's final realized PnL (after the account is confirmed flat) into
-
[If
Pod_Leader_IDexists for the trader] → the Middleware calculates a fixed carry amount based onNext_Level:Next_Level Carry_Amount 3 $250 5 $500 7 $1,500 Any other level $0 The Middleware then updates
Pending_Carry_Balance = Pending_Carry_Balance + Carry_AmountonPod_Leader_Registry(native PostgreSQL table), on the Pod Leader's own row (WHERE Leader_ID = pod_leader_id).- This is an accrual step only — it does NOT trigger a payment. The actual payout is executed by Flow 17 (Pod Leader Vesting Payout) — UC_8.2.12, a scheduled job that runs monthly on the 1st of the month.
-
[CHR-72][IfNext_Level == Min_Pod_Leader_Level(Zapier Table C) ANDPod_Leader_IDexists for the trader] → the trader graduates out of their Pod. The Middleware runs the Pod Graduation sequence:- Capacity Reset: query
Pod_Leader_Registry(native PostgreSQL table) using the trader'sPod_Leader_IDand decrementCurrent_Countby 1. - Profile Wipe: update the
Userstable for the promoted trader and setpod_leader_id = NULL. - Role Management: call
POST /manage-discord-rolewithremove_role = 'Pod Member'to revoke the trader's access to the private mentor channel. - Waitlist Trigger: since the mentor's
Current_Countdecreased, trigger Flow 11 (Waitlist Processor) — UC_8.2.8 to automatically assign the next trader in the queue to the newly opened seat. - Pod Leader Invitation email: since
Next_Level == Min_Pod_Leader_Level, the Middleware fires thepod_leader_inviteevent to Klaviyo with payloaduser_id,email,first_name,achieved_level(dynamically populates "Congratulations on hitting Level X!" copy),accept_invite_url(unique URL https://app.stacktrading.com) — Klaviyo sends the email to the graduating trader. Flow 15B (Pod Leader Opt-In) — UC_8.2.10 is triggered when the trader subsequently clicks the button inside thisPod_Leader_Inviteemail, landing onaccept_invite_url.- Redirect timing: the backend does not wait for Flow 15B to finish before redirecting. It validates the opt-in token, triggers Flow 15B — UC_8.2.10 asynchronously in the background, and immediately returns an HTTP 302 redirect to
https://app.stacktrading.com. - Login & security: the token in
accept_invite_urlonly authorizes the Pod Leader opt-in action — it never bypasses login or issues an Auth0 session. On redirect, a trader with an active session lands on the dashboard; otherwise they land on the standard Auth0 login screen.
- Redirect timing: the backend does not wait for Flow 15B to finish before redirecting. It validates the opt-in token, triggers Flow 15B — UC_8.2.10 asynchronously in the background, and immediately returns an HTTP 302 redirect to
- Capacity Reset: query
-
[If the trader's level is between 9 and 17 AND
Defense_Used == True] → the Middleware runs the Defense Recharge Check (Standard Accrual) on every promotion event:- Increment
Promotions_Since_Defense = Promotions_Since_Defense + 1. - If
Promotions_Since_Defense >= 2: setDefense_Used = Falseand resetPromotions_Since_Defense = 0. - Send the
Defense_Protocol_Rechargedemail via AWS SES.
- Increment
-
[If
Next_Level == 9] → the Middleware initializesDefense_Used = FALSEon the trader's record. This is a first-time setup step distinct from the Recharge Check above — it is what makes the Defense Protocol'sDefense_Usedflag valid/evaluable the first time the trader enters the Level 9–17 band. -
Stagnation timer reset: the Middleware resets
stagnation_deadline = Today + 90 Dayson every promotion event. See BR_8.1.1.19.
Stage 3 — Ledger Balance Update, Account/Risk Update, Discord
-
The Middleware updates
ledgers.virtual_equity = Level_Starting_Capitalandledgers.allocated_capital = Level_Starting_Capital, and updatesCurrent_Level = Next_Level. -
The Middleware calculates the Discord title for
Next_Levelfrom Table G and callsPOST /manage-discord-rolewithuser_id,add_role = [New Title],remove_role = [Previous Title], then posts the corresponding announcement per the routing table in BR_8.1.1.12.- Skip-if-unlinked: if
discord_user_id IS NULLfor the trader, the Middleware skips the Discord API role-assignment call entirely and returns200 OK. The promotion flow does not fail or crash because of a missing Discord link.- Late-linking role sync: when a trader subsequently links their Discord account via the
/linkslash command, the Middleware must query their currentCurrent_Levelfrom PostgreSQL, map it to the correct title via Table G, and apply that specific role. It must NOT default to "Associate Trader".
- Late-linking role sync: when a trader subsequently links their Discord account via the
- SotaTek's Discord bot only needs to assign/remove the Role via
POST /manage-discord-role— it does not need to programmatically configure the channel-level access permissions tied to each Title.
- Skip-if-unlinked: if
-
Blocking gate — Flow 6 / Flow 8 redirect: before any account unlock step runs, the Middleware checks
Next_Leveland redirects to the corresponding flow(s), blocking all remaining Stage 3 steps until the redirected flow(s) complete successfully:- [If
Next_Level == 6] → trigger Flow 6 (Level 6 Transition) and wait for it to complete (Rippling HR onboarding + employment agreement signed) before continuing. - [If
Next_Level > 6] → trigger Flow 8 (Pay Raise Engine) and wait for it to complete before continuing. - [Else] → no redirect; continue immediately.
- The Middleware does not proceed to step 4 (Reset Balance) until every triggered flow above has returned a completed status.
- [If
-
Reset Balance: the Middleware executes an Adjustment operation on the execution platform to withdraw the account's current balance down to
$0, then executes a separate Deposit operation. The deposited amount is platform-conditional, not theLevel_Starting_Capitalvalue written to the internal ledger in step 1 above: for Forex (MT5/TraderEvolution) the deposit isMax_Forex_Notional, set directly without the Margin + Drawdown formula; for Futures (Rithmic) the deposit isFutures_Capital, used for PnL and Auto-Liquidate tracking. For Futures, the Rithmic Risk Group must also be configured to bypass margin-availability checks and enforce buying power solely viaMax_Contracts_ES_Equiv, so a trader currently in drawdown can still trade the full contract size their new level allows. If this Adjustment/Deposit call errors or times out, the same retry-then-halt behavior as BR_8.1.1.18 applies. -
Update Risk: the Middleware calls the Rithmic/MT5/TraderEvolution API to push the
Next_Levelrow's risk parameters from Table A/B onto the account. If this call errors or times out, the Middleware applies the retry-then-halt behavior defined in BR_8.1.1.18 before continuing to step 6.Risk parameters pushed (all values read from the
Next_Levelrow):Parameter Forex (Table A) Futures (Table B) Notional / Contract limit Max_Forex_Notional[CHR-110]No single notional cap. Middleware loops Table B's per-root-symbol contract-limit columns for theNext_Levelrow; for each symbol with limit> 0ANDEnabled = TRUEinCME_Whitelist, pushes that explicit per-symbol contract limit directly to the Rithmic risk engine. (Ref: UC_2.7-2.8_v1.md — Per-Symbol Risk Provisioning[CHR-110])Max Drawdown (Hard Breach) Market_Loss_When_StoppedMarket_Loss_When_StoppedDaily Loss Limit (Soft Breach) Daily_Loss_Limit = Market_Loss_When_Stopped × Daily_Loss_Ratio(Daily_Loss_Ratiois read from Table C)Daily_Loss_Limit = Market_Loss_When_Stopped × Daily_Loss_Ratio(Daily_Loss_Ratiois read from Table C)Profit Target Profit_TargetProfit_Target -
Re-Enable Trading: once the risk parameters in step 5 are confirmed pushed, the Middleware removes the read-only/login-but-no-trade lock from the account so the trader can begin trading their new Level configuration. If this call errors or times out, the same retry-then-halt behavior as BR_8.1.1.18 applies.
-
Dashboard Day-0 state: the Middleware uses a new internal shadow account record (database-level only — not a new broker/execution-platform account; the broker-side Rithmic/MT5/TE sub-account is unchanged) scoped to
Next_Level, and points the Dashboard at this new shadow account for all widget calculations (Win Rate, Profit Factor, Equity Curve, etc.) going forward. Because the shadow account is a fresh record with no prior metrics, the Dashboard naturally shows Day-0 — this is not achieved by filtering existing trade history by the level-up timestamp. The trader's full trading history remains intact and visible inside the execution platform terminal (Rithmic/MT5/TE) and the database; only the Dashboard's own widget calculations are scoped to the new shadow account's metrics.
Stage 4 — Data Fee Refund Calculation (Level 3)
-
[If
Next_Level == 3ANDAsset_Class == "Futures"] → the Middleware callsGET /financial/calculate-data-refundwithuser_idas input:- Refunded fee: only the CME base data fee (
fee_type = 'MARKET_DATA_BASE'), i.e. the market data fee the trader paid while at Level 1 and Level 2 of the current challenge cycle. Not refunded: add-on fees (NYMEX, CBOT, COMEX) and platform fees. - Invoices summed: the Middleware sums the
amountof everyMARKET_DATA_BASEinvoice belonging to this trader's current challenge cycle, where the invoice isstatus = 'paid'ANDrefunded_at IS NULL - Mark as refunded: each refunded invoice is set
refunded_at = Today, so it can never be refunded again. - Termination exception: if a trader is terminated before reaching Level 3, this refund logic does NOT run for them — their paid
MARKET_DATA_BASEfees for Level 1 and Level 2 are not refunded. The data fee refund is strictly a Level 3 milestone bonus, not an automatic entitlement upon leaving the system — a trader who fails/terminates before Level 3 must bear that market data cost themselves.
- Refunded fee: only the CME base data fee (
-
Calculate the payout, then trigger Flow 5 (runs on every promotion event — not gated by the
Next_Level == 3/Futures condition in step 1, sinceLevel_Performance_Bonusalways applies):Total_Payoutcombines up to three amounts, each with its own independent condition for being included:Level_Performance_Bonus— always included. This is the fixed performance bonus for the level the trader just completed, read from Table A/B. This amount is present on every promotion event, regardless of asset class or level.refundable_amount— included only ifNext_Level == 3ANDAsset_Class == "Futures". This is the CMEMARKET_DATA_BASErefund calculated in step 1 above. If the condition is not met, this amount is omitted.[CHR-117] final_amount— included only ifNext_Level == 3ANDAsset_Class == "Futures". This is the Sierra Chart license fee refund. Sierra Chart refund itself runs at every Futures level. If the condition is not met, this amount is omitted here (Ref: CHR-117).- Calculation:
Total_Payout = Level_Performance_Bonus + refundable_amount (if applicable) + final_amount (if applicable). - Write the payout record: the Middleware updates the
payoutstable record for this promotion event withamount = Total_Payout. - Trigger Flow 5: once that
payoutsrow exists, Flow 5 (Payout) picks it up by its payout ID and processes the combined amount (bonus + any applicable CME refund + any applicable Sierra Chart refund) automatically — in one single payout, never as separate payouts for the same promotion event.
Stage 5 — Klaviyo Emission, Everflow, Perk Check
-
Feedback Survey Gate (runs before the Klaviyo branch): the Middleware queries
Users.pod_leader_idandUsers.last_survey_date.- [If
pod_leader_id IS NOT NULLAND (last_survey_date IS NULLOR more than 60 days ago)][CHR-141]→ emitsTemplate_Mentee_Survey(Form 4 — Bi-Monthly Pod Performance Audit, see UC_8.2.6 BR_8.2.6.3) to Klaviyo and setslast_survey_date = NOW(). The "Typeform link" in this email is NOT a rawtypeform.comURL. Per the Typeform embedding standard, the email's call-to-action link points to a dedicated Stack Trading wrapper page (on thestacktrading.comdomain) that mounts the@typeform/embed-reactcomponent, with the user'suser_idand other dynamic variables injected as Hidden Fields; the webhook from this Typeform pushes the submission payload to the Zapier Catch Hook defined for Flow 10.4. last_survey_datestores the date the survey was sent (not submitted).- Processing the Typeform submission and routing the score to
Pod_Leader_Registry— handled by Flow 10.4 — UC_8.2.6.
- [If
-
Klaviyo promotion branch: the Middleware routes to exactly one path based on
Next_Level(=Current_Levelafter the Stage 3 update):Path Condition Klaviyo event Payload Also triggers A — Level 3 Refund Next_Level == 3ANDAsset_Class == "Futures"Promotion_Level_3user_name,refund_amount,total_bonus, Level-Up URL— B — Level 6 Next_Level == 6Promotion_Level_6user_name,new_level,next_target, Level-Up URLEverflow Level 6 bounty postback (BR_8.1.1.17) — mandatory C — Standard All other cases Promotion_Standarduser_name,new_level,next_target, Level-Up URL— next_target=Profit_Targetof the new level (Table A/B).- Level-Up URL: a unique, unauthenticated shareable URL. The trader receives it in the Klaviyo email. Opening it plays the cinematic certificate animation and audio for social sharing.
-
Perk Check (runs for every promotion, regardless of which Klaviyo path — A, B, or C — was taken in step 2 above): the Middleware queries Table H (Perks Registry) for
Next_Level.Condition Action Active == YesANDClaimed < Limit1. Read the Fulfillment_Zapfrom Table H2. Trigger that fulfillment Zap3. SendPerk_Unlocked_Generalto Klaviyo withuser_name,user_email,perk_description(e.g. "Founding 500 Heavyweight Hoodie", "Tom James Custom Suit"),new_level,perkNext_Levelhas no row in Table H at all, OR its row hasActive == No/Claimed >= LimitSkip perk fulfillment and the perk notification - Perk Check never blocks the promotion — the rest of the pipeline completes either way.
Business Rules
BR_8.1.1.3: Level 24 Prestige Reset
If Current_Level == 24 at the time of promotion, the Middleware executes the Prestige Reset branch instead of the standard Stage 2–5 pipeline, then halts:
Level 24 is the top tier (Managing Principal Trader). "Sweep Profit" means withdrawing the trader's accumulated profit above their Level 24 baseline notional, resetting their account equity back down to that baseline starting capital so they can trade the level again from a clean slate, and separately paying out the fixed Level 24 bonus.
- No promotion certificate for this branch. Traders executing a Prestige Reset do NOT receive the cinematic/certificate animation, or any certificate. The system simply executes the Sweep Profit logic (steps 1–3 below) and the corresponding payout flow (step 2).
- Bonus amount is always fixed =
Bonus_Paid_To_Trader(Table A/B)
- Sweep Profit — the Middleware calculates the trader's accumulated profit above the Level 24 baseline (
Max_Forex_Notionalfor Forex,Futures_Capitalfrom Table B for Futures). This is a calculation only; no fiat is moved at this step. - Pay Bonus — the Middleware writes a new row into the
payoutstable withamount = Bonus_Paid_To_Trader(Table A/B). Flow 5 (Payout) picks up thispayoutsrecord and processes it off-platform via Dots/Rippling. - Reset Account — the Middleware executes a Balance Adjustment on the execution platform (Rithmic/MT5/TE) so the sub-account's balance is set back to exactly
Max_Forex_Notional(Forex, MT5/TE) /Futures_Capital(Futures, Rithmic) — this is the broker-side execution-platform balance, distinct from the internal ledger value below.- In parallel,
ledgers.virtual_equityandledgers.allocated_capitalin the internal database are set to the baselineLevel_Starting_Capitalvalue:[CHR-122]Forex: (Max_Forex_Notional * Margin_Rate) + Market_Loss_When_Stopped- Future: Futures_Capital
- All params are taken from Zapier table A (for Forex) and table B (fore Future)
- Dashboard Reset — once the Balance Adjustment and ledger sync above complete, the Middleware use internal shadow account record (database-level only — not a new broker/execution-platform account) scoped to the fresh Level 24 cycle, and points the Dashboard at it so all widget calculations (Win Rate, Profit Factor, Equity Curve, etc.) start from Day-0.
- Stagnation timer reset: the Middleware resets
stagnation_deadline = Today + 90 Days.
- In parallel,
- Freshdesk Ticket — the Middleware constructs a Freshdesk API payload: Trader Full Name, Email Address, User ID, Subject =
"Level 24 Prestige Reset", Body containing the trader's final profit metrics and a prompt for the CEO to initiate contact.-
"[Trader_Full_Name] (User ID: [User_ID]) just completed a Level 24 Prestige Reset — Sweep Profit: $[Swept_Profit_Amount], Bonus Paid: [Bonus_Paid_To_Trader]. Please reach out to [Trader_Full_Name] directly to personally congratulate them on this achievement."
-
- Klaviyo Event — the Middleware fires a
Level_24_Prestige_Resetevent to Klaviyo with payload:user_name,email, and the event identifier (Level_24_Prestige_Reset)
BR_8.1.1.4: Frontend LEVEL_PROMOTION Sequence
[CHR-128] The Middleware does not fire the LEVEL_PROMOTION WebSocket event until the account is confirmed flat AND the Polygon tx_hash has been generated and saved to PostgreSQL. Once the event is received, the frontend immediately launches the celebration sequence in a strict 3-step order — cinematic motion → certificate animation → post-certificate modal, and without interruption if that remaining processing is still pending or fails:
| # | Trader's case | Sequence |
|---|---|---|
| 1 | Level 6, US (W-2) | Cinematic motion → certificate animation →"Professional Transition" modal (US) |
| 2 | Level 6, International | Cinematic motion → certificate animation →"Professional Transition" modal (International) |
| 3 | All other levels | Cinematic motion → certificate animation →"Provisioning in Progress" modal |
- The cinematic motion and certificate animation, once started, always run to completion — the trader is never interrupted mid-animation by backend state.
- Only after the trader closes the certificate/sharing modal does the frontend display the post-certificate modal for the trader's case.
- Modal A (Professional Transition), Modal B (Professional Retainer Activation), and Modal C (Setting up your account) each block the entire screen with no close control, and the trader cannot perform any other Dashboard action while any of them is displayed. This is true whether the trader is seeing it live right after closing the certificate, logging in fresh, or simply refreshing the page — the modal reappears/persists under all three entry paths until its closing condition is met.
BR_8.1.1.18: Stage 3 Execution-Platform Call Retry — Exponential Backoff, Then Halt
This BR covers the three execution-platform API calls in Stage 3 that provision the trader's account for Next_Level: Reset Balance (Adjustment + Deposit, step 4), Update Risk (risk parameter push, step 5), and Re-Enable Trading (unlock, step 6).
If any of these calls returns an error (non-2xx response) or times out:
-
Retry with exponential backoff — standard 3 attempts over 10 seconds total:
Attempt Wait before this attempt 1 (initial call) — 2 2 seconds 3 4 seconds (cumulative wait so far: 6s) 4 (final) 4 seconds (cumulative wait so far: 10s) - The step does not advance to the next Stage 3 step until an attempt returns success, or all retries above are exhausted.
-
If the call still errors after the final retry:
- The Middleware halts the Flow 4A pipeline for this trader at the failed step. No later Stage 3 step, nor Stage 4/5, executes for this promotion event.
- The frontend-side effect is the existing behavior at UC_8.1.1-UI step 5: the applicable post-certificate modal (Modal A, Modal B, or Modal C, per the trader's case) remains on screen with no close control and no technical-error screen shown to the trader.
- The Middleware fires a dedicated Sev-1 Slack alert to
#ops-general(ProdC0BR8LRC5MK) /#test-ops-general(TestC0BR6UXRR8D):- Message:
"🚨 SEV-1: Risk Parameter Update Failed — Trader [Trader_ID], Level [Current_Level] → [Next_Level], Step: [Reset Balance | Update Risk | Re-Enable Trading], Platform: [Rithmic | MT5 | TraderEvolution]. Retries exhausted (3x / 10s). Manual intervention required."
- Message:
BR_8.1.1.12: Discord Promotion Announcement Routing (Table G)
The Middleware calculates the trader's title for Next_Level from Table G and routes the promotion announcement to exactly one of two channels.
| Title (Table G) | Level Range | Target Channel |
|---|---|---|
| The First Allocation | Level 1 | #trading-floor-announcements |
| The Standard Progression | Levels 2–5, 7–8, 11–13 | #trading-floor-announcements |
| The Career Milestone | Level 6 | #trading-floor-announcements |
| Drawdown Defense | Level 9 | #trading-floor-announcements |
| Senior Trader 1 | Level 10 | #trading-floor-announcements |
| Senior Trader 2 | Level 14 | #viral-wins |
| Heavy Hitters | Levels 15–24 | #viral-wins |
Announcement text templates (final, per Discord Server Details.md §Announcements):
- The First Allocation (Level 1):
🚨 ALLOCATION SECURED 🚨 Congratulations to @[User] for passing the Associate Track evaluation. They have officially secured their live capital allocation and are starting at Level 1. Time to scale. 📈🏦 - The Standard Progression (Levels 2–5, 7–8, 11–13):
🔥 LEVEL UP 🔥 @[User] just hit their profit target and leveled up from Level [Old_Level] to Level [New_Level]. The discipline is paying off. Back to the charts. 📊💸 - The Career Milestone (Level 6):
💼 CAREER UNLOCKED 💼 Massive congratulations to @[User] for surviving the first five live levels and reaching Level 6! They have officially secured an international retainer or W2 offer with base salary and benefits. Welcome to the inner circle. 🤝🏆 - Drawdown Defense (Level 9):
🛡️ DRAWDOWN DEFENSE ACTIVATED 🛡️ @[User] just hit Level 9. We see the potential and we are investing heavier in their success. Drawdown Defense is now unlocked to protect their seat at the table. 🏰🛡️ - Senior Trader 1 (Level 10):
👔 SENIOR TRADER 1 👔 Welcome to the big leagues. @[User] just hit Level 10 and earned the Senior Trader 1 promotion. They might want to start taking measurement of what comes next. 🧵✂️ - Senior Trader 2 (Level 14):
⌚ SENIOR TRADER 2 ⌚ @[User] just cleared Level 14 and earned the Senior Trader 2 promotion. Elite execution deserves elite hardware. Time will tell what the firm sends their way. 👑⏱️ - Heavy Hitters (Levels 15–24):
🐳 INSTITUTIONAL SCALING 🐳 Take notes. @[User] just cleared Level [Old_Level] and is advancing to Level [New_Level]. They are now managing a total notional allocation of $[Notional_Amount]. This is what elite risk management looks like. 🚀💰
Discord bot failure handling:
- 5xx or 429 response: the worker must not drop the payload — it leaves the message in the Redis queue and retries via a cron job running every 30 minutes.
- 404 response (channel permanently unavailable or deleted): the worker drops the message from the queue immediately (no retry) and posts the following message, verbatim, to
#ops-general(ProdC0BR8LRC5MK) /#test-ops-general(TestC0BR6UXRR8D):"⚠️ Discord Notification Failed: User ID [ID] not found or channel missing. Skipping retry."
BR_8.1.1.17: Everflow Level 6 Bounty Touchpoint
[CHR-124] This UC owns exactly one touchpoint with the Everflow affiliate system: the Level 6 bounty conversion. This touchpoint fires only for Level 6 — promotions to any other level never touch Everflow.
[CHR-126] The everflow_transaction_id used for this postback is the same value captured earlier at checkout via the Everflow JavaScript SDK reading the st_affiliate_data first-party cookie, or via the backend's S2S Click API fallback if the SDK was blocked. The postback payload does NOT include a bounty_amount field.
Mechanism:
-
Trigger. Zapier Flow 4 (Level-Up), Path A: a trader is promoted and
Next_Level == 6. -
Referral check. The Node.js backend reads
everflow_transaction_idon this trader'sUsersrecord — the same field written at checkout by Flow 1 (Flow A Step A6).- [If
NULL] → this trader was never referred. The flow ends here: no postback is sent, there is nobody to credit. - [If present] → continue to step 3.
- [If
-
Postback. The backend fires a GET Server-to-Server (S2S) postback directly to Everflow's tracking domain:
https://[TRACKING_DOMAIN]/?nid=[NID]&transaction_id=[TRANSACTION_ID]&event_id=[EVENT_ID]Parameter Value transaction_idThe trader's stored everflow_transaction_id— tells Everflow which referral this belongs to.event_idThe Everflow-side ID configured specifically for the "Level 6 milestone" conversion. -
Await confirmation. The backend awaits the
SUCCESSstring response from Everflow.- No-retry policy: consistent with the general S2S postback policy for every conversion event (checkout Flow A Step A5) — if Everflow does not return
SUCCESS, the backend does NOT retry and does NOT block anything. It logs the failure for manual reconciliation (step 5).
- No-retry policy: consistent with the general S2S postback policy for every conversion event (checkout Flow A Step A5) — if Everflow does not return
-
Log for reconciliation. The backend logs the transaction ID (and the failure status, if step 4 did not return
SUCCESS) to theinvoicestable — this is the middleware's record that the Level 6 event was delivered, used to reconcile against Everflow's payouts, or for Operations to manually credit the partner if the postback failed.
BR_8.1.1.19: Stagnation Timer Reset on Promotion
Every promotion event (Stage 2) resets the trader's inactivity/stagnation clock: stagnation_deadline = Today + 90 Days.
- This mirrors the standard 90-day timer set at Flow 3E (contract signed → Live) and resumed by Flow 4B (Drawdown/Stagnation Defense, UC_4.15.4) after a successful PIP. Promotion is a new point in the trader's lifecycle where the clock restarts, consistent with that same 90-day standard.
- This reset runs on every
Next_Levelregardless of asset class, Pod Leader status, or Defense Protocol state — it is unconditional, parallel to the other Stage 2 bookkeeping steps. - Flow 19 (Stagnation Monitor) is the sole consumer of
stagnation_deadline— it reads the field to drive the inactivity warning ladder and eventual termination/Defense handoff. This UC only writes the field; it does not evaluate it. - Does not apply to the Level 24 Prestige Reset branch (Basic Flow Stage 1 step 4) — that branch halts before Stage 2 runs.
UI/UX — Post-Promotion Display Sequence
Display Sequence
-
The cinematic motion plays first, then the certificate.
- Trigger: the frontend receives the
LEVEL_PROMOTIONWebSocket event (Basic Flow Stage 1 step 7 — fired only after flat confirmation and the Polygontx_hashsave, per Stage 1 step 6). - The full certificate experience runs exactly as specified in the certificate UC, in that order (motion first, then the certificate animation), and always includes the real
tx_hashsince it is already saved by the time the event fires. - It runs whether or not the remaining backend processing (Stage 2/3) has finished.
- Trigger: the frontend receives the
-
The trader closes the certificate modal.
- The trader activates [Close] on the certificate modal. Ref: UC_4.16.1 §9.1 row 1.
- This is the only point at which a post-certificate modal may appear.
-
The frontend resolves the trader's case and shows at most one modal — but only if the corresponding completion condition is not already satisfied by the time the trader closes the certificate modal. If provisioning (and, for Level 6, every Flow 6 onboarding step) already finished while the cert/certificate sharing sequence was still playing, no modal is shown at all — the trader lands directly on the Dashboard:
Case Condition What the trader sees 1. US W-2, Level 6 Next_Level == 6ANDis_us_resident == trueAND the Flow 6 onboarding steps are not yet all completeModal A — Professional Transition 2. International, Level 6 Next_Level == 6ANDis_us_resident == falseAND the Flow 6 onboarding step is not yet completeModal B — Professional Retainer Activation 3. All other levels Next_Level != 6AND backend provisioning forNext_Levelis not yet completeModal C — Setting up your account 4. Already complete The relevant condition above (provisioning, or — for Level 6 — all Flow 6 onboarding steps) was already satisfied before the trader closed the certificate modal No modal — the Dashboard loads normally -
The modal stays until the account is fully provisioned for
Next_Level. All three modals (cases 1–3) block the entire screen and carry no close control. The trader cannot perform any other Dashboard action while a modal is displayed.- Modal C: closes automatically once the backend has completed all Basic Flow for
Next_Level. - Modal A / B (Level 6): unlike Modal C, Level 6 promotion requires work on the trader's part (e.g. accepting the job offer) before the account can proceed — the modal remains on screen tracking the trader's progress with green dots against each required employment/contractor onboarding step. It only closes once every required step (via the links sent by Flow 6) is validated as complete and the account is provisioned for Level 6.
- Modal C: closes automatically once the backend has completed all Basic Flow for
-
Provisioning failure is never shown as a technical error. If provisioning fails, the modal stays displayed — no failure screen is rendered to the trader — and a Sev 1 Slack alert is sent to the Ops team for manual intervention:
- Channel:
#ops-general(ProdC0BR8LRC5MK) /#test-ops-general(TestC0BR6UXRR8D). - Message:
"🚨 Provisioning Failed: Trader [Trader_ID] — Level [Current_Level] to Level [Next_Level]. Manual intervention required"
- Channel:
-
Multi-level-up without login. If the trader passed several levels without opening the Dashboard, the sequence above runs once, for the highest level reached only.
Modal A — Professional Transition (US W-2, Level 6)
| # | Element | Type | Rule |
|---|---|---|---|
| 1 | Title | Label | Static text:Professional TransitionOverflow: Wrap text |
| 2 | Subtitle | Label | Static text:Level 6 AdvancementOverflow: Wrap text |
| 3 | Body | Label | Static text:Congratulations on advancing to Level 6 and securing your professional W-2 Trader position. Please monitor your inbox for the links required to finalize your employment onboarding and unlock your live trading account.Overflow: Wrap text |
| 4 | Next Steps heading | Label | Static text:Next Steps:Overflow: Wrap text |
| 5 | Step item 1 | Label | Static text:Access the Offer Configurator link to select your compensation track.Overflow: Wrap text |
| 6 | Step item 2 | Label | Static text:Input your requested trading hours. Choose 30 to 35 hours per week for Full Benefits, or under 29 hours per week for Flex Cash. Federal law classifies roles under 30 hours as part time, which legally permits the higher Flex Cash payout in lieu of mandatory benefit enrollments.Overflow: Wrap text |
| 7 | Step item 3 | Label | Static text:Complete your health and welfare benefits enrollment if you selected the Full Benefits track.Overflow: Wrap text |
| 8 | Step item 4 | Label | Static text:Sign your W2 Offer and complete the I-9 Section 2 employment verification via Rippling.Overflow: Wrap text |
| 9 | Step item 5 | Label | Static text:Submit your Trading Hours Declaration form via Rippling.Overflow: Wrap text |
- Step items themselves are not clickable (the links arrive by email via Flow 6)
Modal B — Professional Retainer Activation (International, Level 6)
| # | Element | Type | Rule |
|---|---|---|---|
| 1 | Title | Label | Static text:Professional Retainer ActivationOverflow: Wrap text |
| 2 | Subtitle | Label | Static text:Level 6 AdvancementOverflow: Wrap text |
| 3 | Body — paragraph 1 | Label | Static text:Congratulations on advancing to Level 6. As an International Trader, you remain an independent contractor but you now earn higher profit splits and your Base Income is paid as a monthly retainer.Overflow: Wrap text |
| 4 | Body — paragraph 2 | Label | Static text:Please monitor your inbox for the link required to finalize your transition and unlock your live trading account.Overflow: Wrap text |
| 5 | Next Steps heading | Label | Static text:Next Steps:Overflow: Wrap text |
| 6 | Step item 1 | Label | Static text:Complete your Level 6 Retainer & Hours Declaration form via the link sent to your email.Overflow: Wrap text |
- Step items themselves are not clickable (the links arrive by email via Flow 6)
Modal C — Setting up your account (all levels except 6)
| # | Element | Type | Rule |
|---|---|---|---|
| 1 | Title | Label | Static text:Setting up your accountOverflow: Wrap text |
| 2 | Subtitle | Label | Dynamic text:Level [Next_Level] AdvancementOverflow: Wrap text |
| 3 | Body | Label | Dynamic text:Congratulations on advancing to Level [Next_Level]. We are provisioning your new capital allocation and risk parameters. Execution will unlock momentarily.Overflow: Wrap text |
[Next_Level]is the level the trader has just been promoted to.
Changelog
| Date | Version | Updated item | Before | After | Notes |
|---|---|---|---|---|---|
| 2026-10-06 | v1 | Initial document | — | — | — |
| 2026-10-11 | v1.2 | Stage 1 Step 5/6 ([CHR-131] placement), BR_8.1.1.4, BR_8.1.1.17, Stage 3 ([CHR-122]), Flow 6 touchpoint ([CHR-72]) | [CHR-131] tag was on Step 5 (Next_Level/Level_Starting_Capital lookup — unrelated to tx_hash gating); other tags used underscore format CHR_NNN | Moved [CHR-131] to Step 6 (POST /api/ledger/record, the actual blocking step gated before LEVEL_PROMOTION WebSocket fires) — kept at BR_8.1.1.4 where it was already correctly placed. Normalized all underscore tags (CHR_131, CHR_122, CHR_72, CHR_124) to the repo-wide hyphen convention (CHR-NNN). | User flagged tag as "weird". Content/logic unchanged — tag placement and formatting only. |
| 2026-10-11 | v1.3 | Stage 1 Step 6 (metric_value), Stage 3 (new blocking step 3 "Flow 6/8 redirect", renumbered steps 3→4, 4→5, 5→6, 6→7), Stage 5 Klaviyo table ("Also triggers" column) | Display string documented as equal to Level_Starting_Capital; Reset Balance deposit amount undocumented as platform-specific; Flow 6/Flow 8 trigger lived at Stage 5 (Klaviyo "Also triggers" column) with no blocking relationship to account unlock | Display string now Max_Forex_Notional (Forex) / Max_Contracts_ES_Equiv (Futures), never Level_Starting_Capital; Reset Balance deposit now platform-conditional (Forex = Max_Forex_Notional, Futures = Futures_Capital + Rithmic Risk Group bypass-margin/enforce-contract-cap config); Flow 6 (Next_Level==6) and Flow 8 (Next_Level>6) redirect moved to Stage 3 as a new blocking step, both must complete before Reset Balance / Re-Enable Trading proceed | Client QnA Round 6 (QnA_Level_Promotion.md §3.4, A1/A2/A3) |
| 2026-10-12 | v1.4 | Stage 2 Step 3 (Pod Graduation sequence — Pod Leader Invitation email) | "the Middleware automatically sends the Pod_Leader_Invite email to the graduating trader" (channel/mechanism unstated) | "the Middleware fires the Pod_Leader_Invite event to Klaviyo (Klaviyo sends the email to the graduating trader)" | BA clarification: Pod Leader Invite is a Klaviyo-triggered email, consistent with other lifecycle emails in this UC — Middleware fires the event, Klaviyo handles delivery. |
| 2026-10-13 | v1.5 | New BR_8.1.1.18 (Stage 3 execution-platform call retry); Stage 3 steps 4/5/6 | No retry/halt behavior documented for Reset Balance, Update Risk, Re-Enable Trading errors | Added standard exponential backoff retry (3 attempts over 10s) for Stage 3 execution-platform calls; on retry exhaustion the pipeline halts, the applicable post-certificate modal (A/B/C) stays on screen per existing UI step 5 behavior, and a dedicated Sev-1 Slack alert fires naming the failed step/platform | User-requested addition — [ASSUMPTION]: scope extended from "risk parameter updates" to all three Stage 3 execution-platform calls, and resume-after-manual-intervention path, both flagged [ASSUMPTION]/[OPEN] pending client confirmation |
| 2026-10-17 | v1.6 | Stage 2 Step 3 (Pod Graduation sequence — pod_leader_invite Klaviyo payload; "Table E" references renamed) | pod_leader_invite event fired to Klaviyo with no documented payload fields; Pending_Carry_Balance/Current_Count updates referenced "Table E (Pod_Leader_Registry)" | Added explicit Klaviyo payload: user_id, email, first_name, achieved_level, accept_invite_url. Renamed "Table E (Pod_Leader_Registry)" references to "Pod_Leader_Registry (native PostgreSQL table)" — Pod_Leader_Registry is built natively in PostgreSQL as the single source of truth, not a live Zapier Table. | Client supplement, 2026-10-17 — Klaviyo Payload Fields for pod_leader_invite; PostgreSQL-only build instruction for Pod_Leader_Registry, restating POD-JOIN-02 |
| 2026-10-18 | v1.7 | Post-conditions, Stage 2 (new step 6), new BR_8.1.1.19 | stagnation_deadline not referenced anywhere in this UC | Added Stage 2 step: Middleware resets stagnation_deadline = Today + 90 Days on every promotion event, consistent with the standard 90-day timer used elsewhere (Flow 3E onboarding, Flow 4B PIP success). Flow 19 (Stagnation Monitor) remains the sole consumer of the field. | User-requested addition (common rule, not tied to a specific CR/QnA citation) |
| 2026-10-20 | v1.8 | Stage 3 step 7 ("Dashboard Day-0 state") and Level 24 Prestige Reset step 3 ("Dashboard Reset") — mechanism corrected | Both described the Day-0 reset as the Dashboard filtering/ignoring trade history prior to the exact level-up timestamp when calculating widget metrics | Corrected to: the Middleware creates a new internal shadow account record (database-level only, not a new broker/execution-platform account) scoped to the new level, and the Dashboard reads widget metrics (Win Rate, Profit Factor, Equity Curve, etc.) from that shadow account — not a timestamp filter over the existing trade history. Prestige Reset now explicitly cross-references the same mechanism instead of restating a separate "clear/reset to Day-0" instruction. | Dev team clarification (Dieu Truong, internal Slack, this week): timestamp-based filtering was rejected because the internal level-up record can lag the broker's own event feed (sàn trả message chậm), which would misclassify trades near the promotion boundary; the shadow account avoids that gap entirely. |
| 2026-10-27 | v1.9 | BR_8.1.1.3 Level 24 Prestige Reset, step 3 — new "Stagnation timer reset" bullet | BR_8.1.1.19 resets stagnation_deadline = Today + 90 Days on "every promotion event," but that rule lives in Stage 2 — which the Level 24 Prestige Reset branch explicitly skips (per BR_8.1.1.3: "executes the Prestige Reset branch instead of the standard Stage 2–5 pipeline"). No step inside BR_8.1.1.3 itself reset the field, so a Level 24 trader's stagnation clock was left stale after Prestige Reset even though they resume trading on a fresh cycle. | Added an explicit bullet inside BR_8.1.1.3 step 3 (Reset Account): Middleware resets stagnation_deadline = Today + 90 Days, same as every standard promotion, cross-referencing BR_8.1.1.19. | Gap found during BA self-audit — Level 24 Prestige Reset is in all other respects a trader continuing to trade (fresh cycle, same level), so there was no business reason to exempt it from the standard stagnation-timer reset; this was a documentation omission, not an intentional exception. |
| 2026-11-02 | v1.10 | Stage 2 Step 3 (Pod Graduation sequence — Pod Leader Invitation email), new bullets "Redirect timing" and "Login & security" | accept_invite_url click behavior undocumented — no stated redirect timing relative to Flow 15B completion, no stated login/session behavior | Added: backend does not wait for Flow 15B to finish — validates the opt-in token, triggers Flow 15B asynchronously, and immediately 302-redirects to https://app.stacktrading.com. The opt-in token never bypasses login or issues an Auth0 session — trader lands on dashboard if already logged in, else the standard Auth0 login screen. | Client supplement, 2026-11-02 — Pod Leader Invite (accept_invite_url) redirect timing and login/security clarification. |
| 2026-11-06 | v1.11 | Stage 2 Step 2/3 (Flow 17, Flow 11, Flow 15B mentions), Stage 5 Step 1 (Flow 10.4 mention) | Flow 17 (Pod Leader Vesting Payout), Flow 11 (Waitlist Processor), Flow 15B (Pod Leader Opt-In), and Flow 10.4 were referenced by name only, with no cross-link to their owning UC | Added doc cross-links: Flow 17 → UC_8.2.12, Flow 11 → UC_8.2.8, Flow 15B → UC_8.2.10 (both mentions), Flow 10.4 → UC_8.2.6 | BA cross-reference audit requested by user — rà UC_8.1.1/8.1.2/8.3.1 cho Pod-UC mentions chưa gắn ref link. Content/logic unchanged — link-only fix. |