StackTrading Docs

SRS: UC_4.10.4 — Time Extension Purchase

UC_4.10.4: Time Extension Purchase

FieldValue
BA in ChargeHuyen Dinh
Date Created2026-08-08
Versionv1
Document ReferencesRFQ_ Stack Trading Prop Tech V7.pdf · RFQ_ Website and Dashboard Implementation V7.pdf (§Time Extension Module) · Zapier Integration V7.pdf (§Table J · §Global Variables Table)

Document References

#Original DocumentKey Sections Used
1RFQ_ Website and Dashboard Implementation V7.pdf§Time Extension Module — Trigger, UI, Action Flow (Path A / Path B), Modal UI (Headline, Line Items, Vaulted Card, CTA)
2RFQ_ Stack Trading Prop Tech V7.pdf§Scenario A —POST /purchase-time-extension endpoint
3Zapier Integration V7.pdf§Table J (Extension Fee per level: L1 $150, L2 $1,049, L5 $3,599) · §Global Variables Table (Challenge_Extension_Days = 30) · §Flow 19

1. Overview

FieldContent
IDUC_4.10.4
Use CaseTime Extension Purchase
DescriptionAn active SIM trader whose account has fewer than 10 days remaining can purchase a time extension (duration =Challenge_Extension_Days days from the Global Variables Table) to continue the evaluation. The UI trigger and "Extend Time" button behaviour are described in UC_4.7.4. Purchase flows through a 1-Click Confirmation Modal (Path A — vaulted card present) or Secure Checkout (Path B/C — no vaulted card or user changes payment method).
Zapier FlowFlow 19 (Stagnation Monitor, SIM leg) — computes days_remaining from expiration_date and drives the 14/7/2/1/0-day warning email cascade; on expiry (days_remaining < 0) triggers Hard Breach + Flow 7B per BR_4.10.4.2
Zapier TableTable J (Extension Fee per level — L1: $150, L2: $1,049, L5: $3,599)Global Variables Table (Challenge_Extension_Days = 30)
3rd PartyNMI (vaulted card charge)Quaderno (tax calculation via /calculate-cart)Compliance_geo_restrictions (sanctions check)

2. Trigger

UI Trigger:

  • User is in SIM evaluation (Status = Active_SIM)
  • days_remaining < 10
  • Visual trigger and "Extend Time" button behaviour → Ref: UC_4.7.4

User Action:

  • Trader clicks the "Extend Time" button

3. Pre-conditions

  • User Status = Active_SIM (must be in active SIM evaluation)
  • days_remaining < 10 (less than 10 days remaining)
  • On the final day (days_remaining = 0, same UTC date as expiration): extension is still purchasable
  • Once Status transitions away from Active_SIM (e.g., Failed, Promoting), extension is no longer available

4. Post-conditions

  • Payment successful
  • POST /purchase-time-extensionnew_expiration_date = current_expiration_date + Challenge_Extension_Days calendar days
  • Dashboard timer immediately updates to show new days_remaining
  • Status remains Active_SIM
  • No email, no Interstitial, Auth0 unchanged
  • User continues trading without interruption

5. Basic Flow

Step 1 — Trader clicks "Extend Time":

  1. The "Extend Time" button is visible only when days_remaining < 10
  2. On click → move to step 2.

Step 2 — Tax priming:

  1. FE calls POST /calculate-cart → Quaderno API calculates tax: billing_country + billing_region + user_ip → Tax.
  2. Final_Total = extension_fee (Table J, by level) + Tax.
  3. Tax is primed before modal opens.

Step 3 — Time Extension Modal renders:

Wireframe reference: Buy extension.png

Modal elements and layout → see §9.1 for full screen description.

Step 4 — Payment (Gate checks + 1-Click):

The system performs three gate checks in order:

Gate 1: Status = Active_SIM → Continue. If not → modal closes and display TE-DASH-01.

Gate 2: Sanctions — Query billing_country + billing_region from Users table → check Compliance_geo_restrictions → If match → display 403 screen, Ref: FP-02.

Gate 3: Check Users table for customer_vault_id (NMI):

Path A — 1-Click Purchase (vaulted card present):

  1. User clicks CTA button → frontend calls POST /purchase-time-extension.
  2. Modal closes → Processing Payment popup displayed → Wireframe: Processing payment modal.png
  3. Success: Server adds Challenge_Extension_Days calendar days to current_expiration_date. days_remaining recalculated → timer updates. → Brief success state: Wireframe: Buy extension successfully (1).png
  4. Failure: Processing Payment popup closes → Time Extension modal re-displayed with banner error. User can retry or click "Change Payment Method" (Path C). See error handling → §6.

Path B — Secure Checkout Fallback (no vaulted card):

  1. System detects no customer_vault_id → returns UI Fallback payload.
  2. Frontend displays Secure Checkout page (reuses Step 5 UI component from checkout funnel).
  3. Full payment flow (form validation, processing, success/failure handling, error recovery) → see §6 — Payment flow, all standard cases, citing UC_2.8.1 §5 directly.

Path C — Change Payment Method:

  1. User clicks "Change Payment Method" on the modal.
  2. System opens Secure Checkout page. Same flow as Path B. → Wireframe: Change payment method.png

Step 5 — On successful payment:

  1. POST /purchase-time-extension processes the charge via NMI.
  2. Server adds Challenge_Extension_Days calendar days to the current expiration_date: new_expiration_date = current_expiration_date + Challenge_Extension_Days.
  3. days_remaining recalculated → dashboard timer immediately updates.
  4. Brief success popup displayed → modal closes. User continues trading without interruption. No re-login. Status unchanged.

6. Exceptional Flow

  • [Payment fails — vaulted card declined]

    • CTA button click → Time Extension modal closes → Processing Payment popup displayed. NMI returns a decline code (hard decline, soft decline, insufficient funds, expired card, etc.) → Processing Payment popup closes → Time Extension modal re-displayed with a banner error message showing the failure reason. User can retry or click "Change Payment Method" (Path C).
    • Same UX pattern as UC_4.10.3 §7 — Payment fails 1-Click Path A. No automatic fallback to Path B.
  • [Extension on final day (days_remaining = 0, same UTC date as expiration)]

    • Extension is still purchasable — the user has the entire final day to purchase before the day rolls over.
    • If the day rolls over with no extension purchased, Ref: BR_4.10.4.2 applies.
  • [Status no longer Active_SIM at charge time]

    • If Status changed between modal open and CTA click (e.g., Flow 3 promotion, or the day-expiry Hard Breach in BR_4.10.4.2), the endpoint rejects the charge.
    • Modal closes and display TE-DASH-01.
  • [Promo code — invalid, expired, or already redeemed]

  • [Payment flow — all standard cases]

    The 1-Click modal flow for Time Extension follows the same backend payment handling as the checkout flow. All cases (dedup check, card declines, 5-failure email lock, 10-minute timeout, post-payment restricted-region fail-safe, etc.) and their exact UX/reference are canonically documented in UC_4.10.3 §6a — Payment Flow, All Standard Cases.

7. Business Rules

BR_4.10.4.1: Frequency — Multiple Purchases Allowed

  • Users can purchase time extension multiple times during a single SIM evaluation, with no frequency limit or cooldown.
  • Condition to unlock purchase: days_remaining < 10.
  • Each successful purchase adds Challenge_Extension_Days calendar days to current_expiration_date at the time of purchase.
  • Example: user purchases at days_remaining = 5new_expiration_date = current_expiration_date + 30. If they later drop to < 10 days remaining again, they can purchase again.

BR_4.10.4.2: Day Expires Without Extension Purchased — Hard Breach (Flow 19: Stagnation Monitor)

Flow 19: Stagnation Monitor

  • Trigger: Scheduled Job (Database Filter/View).
  • Query: Import only Traders where expiration_date (SIM) or stagnation_deadline (LIVE) approaches (Days_Remaining = 14, 7, 2, 1, 0) AND Status != 'Admin_Pause' (International Exception).
  • Throttle: Add 1 second delay per loop to respect API Rate Limits.
  • Logic Loop (Per Trader):
    1. Check: IF Status == 'Promoting' → SKIP (Race Condition Prevention).
    2. Calculate: Days_Remaining = expiration_date - Today (SIM) or stagnation_deadline - Today (LIVE).
    3. Warning 1 (14 Days Left): IF Days_Remaining == 14 AND Current_Profit < Profit_Target: Send Stagnation_Warning_14_Days Email.
    4. Warning 2 (7 Days Left): IF Days_Remaining == 7 AND Current_Profit < Profit_Target: Send Stagnation_Warning_7_Days Email.
    5. Warning 3 (2 Days Left): IF Days_Remaining == 2 AND Current_Profit < Profit_Target: Send Stagnation_Warning_2_Days Email.
    6. Warning 4 (1 Day Left): IF Days_Remaining == 1 AND Current_Profit < Profit_Target: Send Stagnation_Warning_1_Day Email.
    7. Final Warning (0 Days Left): Send Final Day Email. SIM users can still buy time extension on this day.
    8. Termination (< 0 Days Left): IF Days_Remaining < 0 AND Current_Profit < Profit_Target:
      • [LIVE] Defense Check: IF Level >= 9 AND Defense_Used == False: Send Stagnation_Defense_Activated Email. Trigger Flow 4B Webhook.
      • [BOTH] ELSE: Send Stagnation_Termination Email with Reason Code STAGNATION:
        • SIM: Trigger the same basic flow as Hard Breach (UC_4.10.2) — but do NOT send the Challenge_Failed email. (This email would normally be sent by Flow 7B Path A — Ref: Zapier_Flow_Full_Reference_v1.md Flow 7B.)
        • LIVE: Trigger Flow 7 (Trader Failure/Stop Out).

Suppression rule: Zapier must suppress the native downstream emails (Drawdown_Defense_Activated_Initial and Live_Account_Closed or Challenge_Failed) when the incoming Reason Code is STAGNATION.

Klaviyo payload requirement: The marketing team needs to differentiate between a SIM user letting their evaluation expire, a LIVE user losing their funded account, and a Senior Trader entering Defense mode. The JSON payload sent to the Klaviyo API for BOTH the Stagnation_Defense_Activated and Stagnation_Termination events must include the user's status string (e.g. Active_Challenge vs Active_DMA) and current_level. This allows the marketing team to build conditional splits in Klaviyo and serve the proper email copy without SotaTek managing separate Zapier webhook events.

Note: All emails above (Stagnation_Warning_*, Stagnation_Defense_Activated, Stagnation_Termination) are sent via Klaviyo.

After this, control returns to UC_4.10.2 and proceeds via Reset or Start New Track, per UC_4.10.3.

8. Wireframe / UI

Wireframe references:

WireframeFileNote
Time Extension Modal (1-Click, vaulted card)References/Wireframe/Stage 2/Failure and Recovery/Buy extension.pngExtension-specific
No Vaulted Card — Secure Checkout (Extension)References/Wireframe/Stage 2/Failure and Recovery/Popup Time extension when users have not saved vaulted card info before.pngExtension-specific
Buy Extension Successfully (Success popup)References/Wireframe/Stage 2/Failure and Recovery/Buy extension successfully (1).pngExtension-specific
Change Payment MethodReferences/Wireframe/Stage 2/Failure and Recovery/Change payment method.pngShared
Processing PaymentReferences/Wireframe/Stage 2/Failure and Recovery/Processing payment modal.pngShared

UX flow note: Unlike Hard Breach (Reset) where user clicks Hard Breach Popup CTA → tax calculation → modal opens: for Time Extension, user clicks "Extend Time" button on the dashboard → tax calculation fires immediately → Time Extension Modal opens directly.

9. Screen Description and Business Rules

9.1 Time Extension Modal (1-Click)

Wireframe reference: Buy extension.png

No.ElementTypeValidation Rule / Behaviour
1Days Remaining Display (in modal)LabelDisplay rule:- Displays remaining time in the same format as the dashboard counter (e.g., "9 days, 9h remaining")- Format and display logic → Ref: UC_4.7.4Behaviour:- Dynamic: value sourced from days_remaining at modal open time
2Modal HeadlineLabelDisplay rule:- "Keep Your Progress. Add [Challenge_Extension_Days] Days."- Day-count pluralization: displays "1 Day" when the value is exactly 1; displays "X Days" when the value is greater than 1 (default Challenge_Extension_Days = 30 → "Add 30 Days.")Behaviour:- Dynamic copy — number of days reflects current Challenge_Extension_Days value
3Promo Code — "Have a promo code?"Expandable Text LinkDisplay rule:- Text link "Have a promo code?" positioned directly above the line items / price breakdown- Defaults to collapsed on modal open- On click → expands to show input + "Apply" button; input placeholder: "Enter promo code"Behaviour:- Same flow as UC_4.10.3 §6 Promo Code Flow
4Line Items (Price Breakdown)LabelDisplay rule:- Extension Fee line item: "Time Extension ([Challenge_Extension_Days] Day(s))" — same pluralization rule as row 2 (e.g. "Time Extension (30 days)")- Tax line item: "Tax ([billing_region])" — region/country name is dynamic per the user'sbilling_region - Promo line item: "Promo ([promo_code])" showing the discount as a negative amount — only rendered when a promo code has been successfully applied; not shown otherwise- Total line item: "Total"- All monetary values follow CR-11 Numeric/Monetary Value DisplayBehaviour:- extension_fee from Table J (by level): L1 $150, L2 $1,049, L5 $3,599. Tax added by Quaderno via billing_country + billing_region + user_ip. Final_Total = extension_fee + Tax − Promo discount (if applied).- Promo line item is added/removed dynamically as the promo is applied/removed via UC_4.10.3 §6 Promo Code Flow
5Vaulted Card DisplayLabel (read-only)Display rule:- Format: "[Brand] ending in [last 4 digits]" — no "Billed to" prefix- Card brand follows UC_4.10.3 BR_4.10.3.8- Example: "Visa ending in 4821"Behaviour:- Sourced from NMI Customer Vault via customer_vault_id
6"Change Payment Method" LinkLinkBehaviour:- On click → Secure Checkout (Path C)- Ref: UC_4.10.3 §5.1 Path C
7Primary CTA ButtonButton (Primary)Display rule:- Label: "Add [Challenge_Extension_Days] Days Now ($[Final_Total])" — e.g. "Add 30 Days Now ($162.38)" / with promo applied "Add 30 Days Now ($152.38)"- Both Challenge_Extension_Days and Final_Total are dynamic; Final_Total follows CR-11Behaviour:- On click → modal closes → Processing Payment popup displays- On success → Buy extension successfully (1).png popup shown → closes- On failure → Processing popup closes → modal re-displayed with banner error
8"Cancel" ButtonButton (Secondary)Behaviour:- On click → modal closes; user returns to Dashboard- No unsaved-changes warning (modal contains no data-entry form state requiring confirmation)

9.2 Payment Flow States

StateWireframeNote
Time Extension Modal — DefaultBuy extension.pngExtension-specific
Time Extension Modal — Promo AppliedBuy extension - Promo code applied.pngExtension-specific
Loading / ProcessingProcessing payment modal.pngShared
Payment SuccessBuy extension successfully (1).pngExtension-specific
No Vaulted CardPopup Time extension when users have not saved vaulted card info before.pngExtension-specific
Change Payment MethodChange payment method.pngShared

9.3 Buy Extension Successfully Modal

Wireframe reference: Buy extension successfully (1).png

No.ElementTypeValidation Rule / Behaviour
1Success IconIconDisplay rule:- Checkmark iconBehaviour:- Static
2HeaderLabelDisplay rule:- "Extension Purchase Complete"Behaviour:- Fixed text
3Body TextLabelDisplay rule:- "30 days have been added to complete the Associate Track."- Sourced dynamically from Challenge_Extension_Days)Behaviour:- Renders immediately after POST /purchase-time-extension succeeds
4"Return to Dashboard"Button (Primary)Behaviour:- On click → popup closes → user returns to Dashboard with updated days_remaining counter 

9.4 Processing Payment Modal

Wireframe reference: Processing payment modal.png

No.ElementTypeValidation Rule / Behaviour
1Circular Loading SpinnerLoading IndicatorDisplay rule:- Circular spinner, gold/cream colorBehaviour:- Animates continuously while awaiting NMI response- No close/cancel affordance; user cannot dismiss this popup
2HeaderLabelDisplay rule:- Fixed text: "Processing payment..."Behaviour:- Static
3SubtextLabelDisplay rule:- "Charging [Brand] ending in [last 4]" — e.g. "Charging Visa ending in 4821"- [Brand] and [last 4] sourced dynamically from the vaulted card in use (same card as displayed in §9.1 Row 5)Behaviour:- Dynamic per session

Changelog

DateVersionUpdated itemBeforeAfterNotes
2026-08-08v1Initial creationFull SRS with 6 BRs, Basic Flow, Exceptional Flow, Screen Description + Dynamic/Fixed Field Classification, Promo Code, Apple Pay / Google Pay card variants, Payment pattern reference to UC_4.9.3Init Flow Step 3: Architect
2026-08-17v1.1Named Flow 19 as the source of days_remaining/warning emails; tightened BR_4.10.4.2 threshold and added Challenge_Failed suppression exceptionv1 content§1 Zapier Flow, §2 Trigger, §7 BR_4.10.4.2 updated to cite Flow 19 (expiration_date, days_remaining < 0) and note Challenge_Failed is not sent on this pathQnA FR-52

On this page