StackTrading Docs

UC 8.1.1

Flow 4A - Promotion: Profit_Target_Hit trigger — Stage 1 Lock & Liquidate through Stage 5 Klaviyo/Everflow emission

FieldValue
BA in ChargeHuyen Dinh
Date Created2026-10-06
Versionv1.11
Document ReferencesZapier 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.3 are created — this was an explicit client-confirmed scope decision, not an omission.

1. Overview

FieldContent
IDUC_8.1.1
Use CaseFlow 4A: Promotion (Profit_Target_Hit)
DescriptionWhen 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 FlowFlow 4 (Retention, Promotion & "Delta" Funding) — Trigger A:Profit_Target_Hit
Zapier TableTable A (Forex Level Params, incl.Margin_Rate) · Table B (Futures Level Params) · Table G (Discord Title Mapping) · Table H (Perks Registry)
3rd PartyRithmic / 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_ID associated with this Profit_Target_Hit webhook has not been previously processed (deduplication check).

Post-conditions

  • The trader's Current_Level is incremented to Next_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_equity and ledgers.allocated_capital reflect the new Level_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_deadline is reset to Today + 90 Days.

Basic Flow

Stage 1 — Dedup, Lock & Liquidate, Immutable Ledger Write, Prestige Reset trigger

  1. 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
  2. Execution platform fire the Profit_Target_Hit webhook to the Middleware. The Middleware checks Event_ID against the SQL database.

    • [If Event_ID already 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.
  3. 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.
  4. [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.

  5. [Else] Still before any other Stage 2/3 processing, the Middleware sets Next_Level = Current_Level + 1 and looks up Table A (Forex) or Table B (Futures) for the Next_Level row, then calculates Level_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, where Margin_Rate, Max_Forex_Notional, Market_Loss_When_Stopped are read from Table A.
  6. [CHR-128] The Middleware calls POST /api/ledger/record to write the promotion metric to the immutable ledger (Polygon) — this is a blocking step: the LEVEL_PROMOTION WebSocket event (step below) MUST NOT fire until this write completes successfully:

    Input fieldValue
    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_Balance is NOT Level_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 the Level_Starting_Capital formula calculated in step 5.
    dateToday
    receipt_hashInternal PostgreSQL ledger record ID (temporary reference, not a blockchain hash)

    Processing sequence:

    1. Validate the JWT signature.
    2. Initialize the server-side Ethers.js wallet.
    3. Call contract.recordMetric() via the Alchemy RPC to write the metric to the Polygon smart contract.
    4. 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.
    5. tx_hash is 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.
  7. Certificate generation: once the tx_hash write succeeds, the certificate is generated as a PNG via GET /certificate, using the saved tx_hash to render the PolygonScan QR code, and the backend pushes this PNG to the S3 immutable storage bucket, storing the resulting S3 URL so GET /certificate can return it later for a hard-copy download.

  8. Once the S3 upload in step 7 succeeds, the Middleware fires the LEVEL_PROMOTION WebSocket 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

  1. The Middleware updates:

    • Captures the trader's final realized PnL (after the account is confirmed flat) into historical_pnl.
    • Resets ledgers.virtual_equity = 0 as an atomic accounting step.
  2. [If Pod_Leader_ID exists for the trader] → the Middleware calculates a fixed carry amount based on Next_Level:

    Next_LevelCarry_Amount
    3$250
    5$500
    7$1,500
    Any other level$0

    The Middleware then updates Pending_Carry_Balance = Pending_Carry_Balance + Carry_Amount on Pod_Leader_Registry (native PostgreSQL table), on the Pod Leader's own row (WHERE Leader_ID = pod_leader_id).

  3. [CHR-72] [If Next_Level == Min_Pod_Leader_Level(Zapier Table C) AND Pod_Leader_ID exists 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's Pod_Leader_ID and decrement Current_Count by 1.
    • Profile Wipe: update the Users table for the promoted trader and set pod_leader_id = NULL.
    • Role Management: call POST /manage-discord-role with remove_role = 'Pod Member' to revoke the trader's access to the private mentor channel.
    • Waitlist Trigger: since the mentor's Current_Count decreased, 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 the pod_leader_invite event to Klaviyo with payload user_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 this Pod_Leader_Invite email, landing on accept_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_url only 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.
  4. [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: set Defense_Used = False and reset Promotions_Since_Defense = 0.
    • Send the Defense_Protocol_Recharged email via AWS SES.
  5. [If Next_Level == 9] → the Middleware initializes Defense_Used = FALSE on the trader's record. This is a first-time setup step distinct from the Recharge Check above — it is what makes the Defense Protocol's Defense_Used flag valid/evaluable the first time the trader enters the Level 9–17 band.

  6. Stagnation timer reset: the Middleware resets stagnation_deadline = Today + 90 Days on every promotion event. See BR_8.1.1.19.


Stage 3 — Ledger Balance Update, Account/Risk Update, Discord

  1. The Middleware updates ledgers.virtual_equity = Level_Starting_Capital and ledgers.allocated_capital = Level_Starting_Capital, and updates Current_Level = Next_Level.

  2. The Middleware calculates the Discord title for Next_Level from Table G and calls POST /manage-discord-role with user_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 NULL for the trader, the Middleware skips the Discord API role-assignment call entirely and returns 200 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 /link slash command, the Middleware must query their current Current_Level from PostgreSQL, map it to the correct title via Table G, and apply that specific role. It must NOT default to "Associate Trader".
    • 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.
  3. Blocking gate — Flow 6 / Flow 8 redirect: before any account unlock step runs, the Middleware checks Next_Level and 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.
  4. 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 the Level_Starting_Capital value written to the internal ledger in step 1 above: for Forex (MT5/TraderEvolution) the deposit is Max_Forex_Notional, set directly without the Margin + Drawdown formula; for Futures (Rithmic) the deposit is Futures_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 via Max_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.

  5. Update Risk: the Middleware calls the Rithmic/MT5/TraderEvolution API to push the Next_Level row'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_Level row):

    ParameterForex (Table A)Futures (Table B)
    Notional / Contract limitMax_Forex_Notional [CHR-110] No single notional cap. Middleware loops Table B's per-root-symbol contract-limit columns for the Next_Level row; for each symbol with limit > 0 AND Enabled = TRUE in CME_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_Stopped
    Daily Loss Limit (Soft Breach)Daily_Loss_Limit = Market_Loss_When_Stopped × Daily_Loss_Ratio (Daily_Loss_Ratio is read from Table C)Daily_Loss_Limit = Market_Loss_When_Stopped × Daily_Loss_Ratio (Daily_Loss_Ratio is read from Table C)
    Profit TargetProfit_Target  Profit_Target
  6. 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.

  7. 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)

  1. [If Next_Level == 3 AND Asset_Class == "Futures"] → the Middleware calls GET /financial/calculate-data-refund with user_id as 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 amount of every MARKET_DATA_BASE invoice belonging to this trader's current challenge cycle, where the invoice is status = 'paid' AND refunded_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_BASE fees 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.
  2. Calculate the payout, then trigger Flow 5 (runs on every promotion event — not gated by the Next_Level == 3/Futures condition in step 1, since Level_Performance_Bonus always applies): Total_Payout combines up to three amounts, each with its own independent condition for being included:

    1. 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.
    2. refundable_amount — included only if Next_Level == 3 AND Asset_Class == "Futures". This is the CME MARKET_DATA_BASE refund calculated in step 1 above. If the condition is not met, this amount is omitted.
    3. [CHR-117] final_amount — included only if Next_Level == 3 AND Asset_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).
    4. Calculation: Total_Payout = Level_Performance_Bonus + refundable_amount (if applicable) + final_amount (if applicable).
    5. Write the payout record: the Middleware updates the payouts table record for this promotion event with amount = Total_Payout.
    6. Trigger Flow 5: once that payouts row 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

  1. Feedback Survey Gate (runs before the Klaviyo branch): the Middleware queries Users.pod_leader_id and Users.last_survey_date.

    • [If pod_leader_id IS NOT NULL AND (last_survey_date IS NULL OR more than 60 days ago)] [CHR-141] → emits Template_Mentee_Survey (Form 4 — Bi-Monthly Pod Performance Audit, see UC_8.2.6 BR_8.2.6.3) to Klaviyo and sets last_survey_date = NOW(). The "Typeform link" in this email is NOT a raw typeform.com URL. Per the Typeform embedding standard, the email's call-to-action link points to a dedicated Stack Trading wrapper page (on the stacktrading.com domain) that mounts the @typeform/embed-react component, with the user's user_id and 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_date stores 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.
  2. Klaviyo promotion branch: the Middleware routes to exactly one path based on Next_Level (= Current_Level after the Stage 3 update):

    PathConditionKlaviyo eventPayloadAlso triggers
    A — Level 3 RefundNext_Level == 3 AND Asset_Class == "Futures"Promotion_Level_3user_name, refund_amount, total_bonus, Level-Up URL—
    B — Level 6Next_Level == 6Promotion_Level_6user_name, new_level, next_target, Level-Up URLEverflow Level 6 bounty postback (BR_8.1.1.17) — mandatory
    C — StandardAll other casesPromotion_Standarduser_name, new_level, next_target, Level-Up URL—
    • next_target = Profit_Target of 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.
  3. 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.

    ConditionAction
    Active == Yes AND Claimed < Limit1. Read theFulfillment_Zap from Table H2. Trigger that fulfillment Zap3. Send Perk_Unlocked_General to Klaviyo with user_name, user_email, perk_description (e.g. "Founding 500 Heavyweight Hoodie", "Tom James Custom Suit"), new_level, perk
    Next_Level has no row in Table H at all, OR its row has Active == 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)
  1. Sweep Profit — the Middleware calculates the trader's accumulated profit above the Level 24 baseline (Max_Forex_Notional for Forex, Futures_Capital from Table B for Futures). This is a calculation only; no fiat is moved at this step.
  2. Pay Bonus — the Middleware writes a new row into the payouts table with amount = Bonus_Paid_To_Trader (Table A/B). Flow 5 (Payout) picks up this payouts record and processes it off-platform via Dots/Rippling.
  3. 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_equity and ledgers.allocated_capital in the internal database are set to the baseline Level_Starting_Capital value:
      • [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.
  4. 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."

  5. Klaviyo Event — the Middleware fires a Level_24_Prestige_Reset event 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 caseSequence
1Level 6, US (W-2)Cinematic motion → certificate animation →"Professional Transition" modal (US)
2Level 6, InternationalCinematic motion → certificate animation →"Professional Transition" modal (International)
3All other levelsCinematic 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:

  1. Retry with exponential backoff — standard 3 attempts over 10 seconds total:

    AttemptWait before this attempt
    1 (initial call)—
    22 seconds
    34 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.
  2. 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 (Prod C0BR8LRC5MK) / #test-ops-general (Test C0BR6UXRR8D):
      • 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."

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 RangeTarget Channel
The First AllocationLevel 1#trading-floor-announcements
The Standard ProgressionLevels 2–5, 7–8, 11–13#trading-floor-announcements
The Career MilestoneLevel 6#trading-floor-announcements
Drawdown DefenseLevel 9#trading-floor-announcements
Senior Trader 1Level 10#trading-floor-announcements
Senior Trader 2Level 14#viral-wins
Heavy HittersLevels 15–24#viral-wins

Announcement text templates (final, per Discord Server Details.md §Announcements):

  1. 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. 📈🏦
  2. 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. 📊💸
  3. 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. 🤝🏆
  4. 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. 🏰🛡️
  5. 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. 🧵✂️
  6. 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. 👑⏱️
  7. 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 (Prod C0BR8LRC5MK) / #test-ops-general (Test C0BR6UXRR8D): "⚠️ 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:

  1. Trigger. Zapier Flow 4 (Level-Up), Path A: a trader is promoted and Next_Level == 6.

  2. Referral check. The Node.js backend reads everflow_transaction_id on this trader's Users record — 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.
  3. 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]
    ParameterValue
    transaction_idThe trader's storedeverflow_transaction_id — tells Everflow which referral this belongs to.
    event_idThe Everflow-side ID configured specifically for the "Level 6 milestone" conversion.
  4. Await confirmation. The backend awaits the SUCCESS string 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).
  5. Log for reconciliation. The backend logs the transaction ID (and the failure status, if step 4 did not return SUCCESS) to the invoices table — 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_Level regardless 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

  1. The cinematic motion plays first, then the certificate.

    • Trigger: the frontend receives the LEVEL_PROMOTION WebSocket event (Basic Flow Stage 1 step 7 — fired only after flat confirmation and the Polygon tx_hash save, 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_hash since it is already saved by the time the event fires.
    • It runs whether or not the remaining backend processing (Stage 2/3) has finished.
  2. 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.
  3. 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:

    CaseConditionWhat the trader sees
    1. US W-2, Level 6Next_Level == 6 AND is_us_resident == true AND the Flow 6 onboarding steps are not yet all completeModal A — Professional Transition
    2. International, Level 6Next_Level == 6 AND is_us_resident == false AND the Flow 6 onboarding step is not yet completeModal B — Professional Retainer Activation
    3. All other levelsNext_Level != 6 AND backend provisioning for Next_Level is not yet completeModal C — Setting up your account
    4. Already completeThe relevant condition above (provisioning, or — for Level 6 — all Flow 6 onboarding steps) was already satisfied before the trader closed the certificate modalNo modal — the Dashboard loads normally
  4. 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.
  5. 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 (Prod C0BR8LRC5MK) / #test-ops-general (Test C0BR6UXRR8D).
    • Message: "🚨 Provisioning Failed: Trader [Trader_ID] — Level [Current_Level] to Level [Next_Level]. Manual intervention required"
  6. 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.

#ElementTypeRule
1TitleLabelStatic text:Professional TransitionOverflow: Wrap text
2SubtitleLabelStatic text:Level 6 AdvancementOverflow: Wrap text
3BodyLabelStatic 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
4Next Steps headingLabelStatic text:Next Steps:Overflow: Wrap text
5Step item 1LabelStatic text:Access the Offer Configurator link to select your compensation track.Overflow: Wrap text
6Step item 2LabelStatic 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
7Step item 3LabelStatic text:Complete your health and welfare benefits enrollment if you selected the Full Benefits track.Overflow: Wrap text
8Step item 4LabelStatic text:Sign your W2 Offer and complete the I-9 Section 2 employment verification via Rippling.Overflow: Wrap text
9Step item 5LabelStatic 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)

#ElementTypeRule
1TitleLabelStatic text:Professional Retainer ActivationOverflow: Wrap text
2SubtitleLabelStatic text:Level 6 AdvancementOverflow: Wrap text
3Body — paragraph 1LabelStatic 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
4Body — paragraph 2LabelStatic text:Please monitor your inbox for the link required to finalize your transition and unlock your live trading account.Overflow: Wrap text
5Next Steps headingLabelStatic text:Next Steps:Overflow: Wrap text
6Step item 1LabelStatic 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)

#ElementTypeRule
1TitleLabelStatic text:Setting up your accountOverflow: Wrap text
2SubtitleLabelDynamic text:Level [Next_Level] AdvancementOverflow: Wrap text
3BodyLabelDynamic 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

DateVersionUpdated itemBeforeAfterNotes
2026-10-06v1Initial document———
2026-10-11v1.2Stage 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_NNNMoved [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-11v1.3Stage 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 unlockDisplay 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 proceedClient QnA Round 6 (QnA_Level_Promotion.md §3.4, A1/A2/A3)
2026-10-12v1.4Stage 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-13v1.5New BR_8.1.1.18 (Stage 3 execution-platform call retry); Stage 3 steps 4/5/6No retry/halt behavior documented for Reset Balance, Update Risk, Re-Enable Trading errorsAdded 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/platformUser-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-17v1.6Stage 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-18v1.7Post-conditions, Stage 2 (new step 6), new BR_8.1.1.19stagnation_deadline not referenced anywhere in this UCAdded 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-20v1.8Stage 3 step 7 ("Dashboard Day-0 state") and Level 24 Prestige Reset step 3 ("Dashboard Reset") — mechanism correctedBoth described the Day-0 reset as the Dashboard filtering/ignoring trade history prior to the exact level-up timestamp when calculating widget metricsCorrected 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-27v1.9BR_8.1.1.3 Level 24 Prestige Reset, step 3 — new "Stagnation timer reset" bulletBR_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-02v1.10Stage 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 behaviorAdded: 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-06v1.11Stage 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 UCAdded 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.6BA 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.

On this page