Tusker FX + SKY Trader — Build Specification

Full-stack recreation document · v1.0 · 10/29/2026

Part A — Full Technical Blueprint

Complete, line-level detail: every entity schema, backend function, core library, hook, RLS rule, workflow, and page route required to rebuild both applications from scratch.

A1Data Model — Entities

All persistent data is stored as JSON-schema entities. Every record auto-includes id, created_date, updated_date, created_by_id. Below is every entity, its fields, and its row-level security posture.

ClientAccount

A client's trading account (custom auth, separate from Base44 User).

FieldTypeDescription
trading_user_idstringUnique public ID, e.g. TFX-100001
password_hashstringSHA-256 hash of password + salt
full_namestringClient display name
phone_numberstringContact phone
emailstringContact email
account_balancenumberRealized balance (deposits − withdrawals + closed P/L)
equitynumberLive equity = balance + bonus + floating P/L
floating_plnumberSum of open position P/L
used_marginnumberMargin locked by open positions
free_marginnumberEquity − used margin
margin_levelnumberEquity / used margin × 100 (0 when no positions)
account_statusenumActive | Suspended | Disabled
leveragenumberAccount leverage, default 100
currencystringUSD (default)
account_typeenumBasic | ECN | Royal | VIP | Demo
auto_withdrawal_enabledbooleanAuto-approve withdrawals if first deposit was USDT/BTC
last_logindate-timeLast client login timestamp
last_statement_generated_atdate-time24h statement cooldown anchor
notesstringAdmin notes

RLS: Open (create/read/update/delete = null) — access controlled at the application layer via client session + admin role checks.

Position

An open or closed trade position.

FieldTypeDescription
account_idstringClientAccount id
ticketstringUnique position ticket
symbolstringInstrument symbol, e.g. EURUSD
typeenumbuy | sell
volumenumberLot size
open_pricenumberEntry price
close_pricenumberExit price
current_pricenumberLive mark
stop_lossnumberSL level
take_profitnumberTP level
profitnumberRealized P/L on close
commissionnumberPer-trade commission
swapnumberAccumulated overnight swap
statusenumopen | closed | pending
order_typeenummarket | buy_limit | sell_limit | buy_stop | sell_stop
close_reasonstringtp | sl | stop_out | neg_balance | manual | ai
ai_modeenumSAFE | OPTIMIZED (AI session mode, if AI-generated)
open_timedate-timeOpen timestamp
close_timedate-timeClose timestamp (also a race lock)

RLS: Open — app-layer gated by account ownership / admin role.

Transaction

Deposit or withdrawal request.

FieldTypeDescription
account_idstringClientAccount id
typeenumdeposit | withdrawal
amountnumberUSD amount
currencystringUSD
statusenumpending | approved | rejected
methodenumbank_transfer | credit_card | crypto | e_wallet | manual
notesstringPayment details (wallet address, etc.)
processed_bystringAdmin who processed
processed_atdate-timeProcessing timestamp

RLS: Read/create open; update/delete admin-only (super_admin, admin, broker_admin).

Instrument

A tradable instrument and its contract spec.

FieldTypeDescription
symbolstringe.g. EURUSD, BTCUSD
namestringDisplay name
categoryenumforex | metals | crypto | indices | stocks
contract_sizenumberLot contract size (forex=100000, gold=100, silver=5000)
min_lot / max_lotnumberLot bounds
spreadnumberAdmin-configurable spread added to ASK
commissionnumberPer-trade commission
swap_long / swap_shortnumberSwap points for daily rollover
stop_levelnumberMin distance for SL/TP
digitsnumberPrice precision (5 forex, 2 crypto/gold)
base_pricenumberPersisted fallback price (updated every 10 min)
manual_price_activebooleanSuper-admin toggle pinning base_price as the live price
base_price_locked_untildate-timeLegacy lock window (now manual toggle only)
enabledbooleanTradable flag

RLS: Default (no RLS declared) — public read.

AISimulationTier

Admin-configured AI auto-dealing parameters per balance range.

FieldTypeDescription
tier_namestringDisplay label, e.g. "Starter $20-99"
min_balance / max_balancenumberInclusive balance range for this tier
daily_profit_min / daily_profit_maxnumberTarget daily AI profit range (USD)
daily_loss_limitnumberMax daily loss before AI pauses (0 = no cap)
win_ratenumberFraction of trades that are wins (0-1), default 0.9
trade_interval_min_sec / max_secnumberRandom cooldown between AI trades
lot_sizenumberLot size for AI trades in this tier
enabledbooleanTier active flag
display_ordernumberAdmin UI sort order

RLS: Admin-only CRUD (super_admin, admin, broker_admin).

AISession

An active AI trading session for an account.

FieldTypeDescription
trading_account_idstringClientAccount id
modeenumSAFE | OPTIMIZED
statusenumACTIVE | STOPPED
started_at / stopped_atdate-timeSession bounds
total_tradesnumberCount of AI deals
total_profit / total_lossnumberCumulative P/L split

RLS: Open.

AITrade

A single AI-simulated deal (history only — never an open Position).

FieldTypeDescription
session_idstringAISession id
trading_account_idstringClientAccount id
symbolstringInstrument traded
sideenumBUY | SELL
lot_sizenumberLot size
profit_lossnumberDeal P/L
deal_statusenumWIN | LOSS
sourceenumSIMULATOR | ADMIN
created_atdate-timeDeal timestamp

RLS: Open.

PendingOrder

A pending (limit/stop) order awaiting trigger.

FieldTypeDescription
ticketstringOrder ticket
trading_account_idstringClientAccount id
symbolstringInstrument
order_typeenumbuy_limit | sell_limit | buy_stop | sell_stop
volumenumberLot size
trigger_pricenumberActivation price
stop_loss / take_profitnumberAttached SL/TP
statusenumpending | triggered | cancelled | expired
executed_at / executed_pricedate-time/numberFill details

RLS: Open.

TradingBonus

A bonus credited to an account.

FieldTypeDescription
trading_account_idstringClientAccount id
bonus_typeenumWelcome | Deposit | Trading Credit | Promotional | Manual Adjustment
bonus_amountnumberBonus USD
statusenumACTIVE | REMOVED | EXPIRED
created_by_adminstringAdmin who granted

RLS: Open.

BonusLedger

Audit trail of every bonus change.

FieldTypeDescription
trading_account_idstringClientAccount id
action_typeenumBONUS_ADDED | REMOVED | EXPIRED | ADJUSTED
amountnumberChange amount
previous_bonus_balance / new_bonus_balancenumberBalances before/after
admin_userstringAdmin responsible

RLS: Open.

Notification

In-app notification for a client account.

FieldTypeDescription
trading_account_idstringClientAccount id
typeenumTP_HIT | SL_HIT | PENDING_TRIGGERED | DEPOSIT_APPROVED | WITHDRAWAL_APPROVED | BONUS_ADDED | MARGIN_CALL | STOP_OUT | AI_SESSION_STARTED | AI_SESSION_STOPPED | REGISTRATION_REQUEST | DUPLICATE_REGISTRATION | ACCOUNT_UPGRADE
title / messagestringNotification content
readbooleanRead flag
created_atdate-timeTimestamp

RLS: Open (create null, read null).

RiskSettings

Global broker risk configuration (single 'global' record).

FieldTypeDescription
setting_keystring"global"
timezonestringDisplay timezone for all client-facing times (IANA), default Asia/Colombo
max_leveragenumberMax allowed leverage, default 1000
stop_out_levelnumberMargin % triggering stop-out, default 50
margin_call_levelnumberMargin % for margin-call warning, default 100
warning_levelnumberWarning threshold, default 80
negative_balance_protectionbooleanClose all when equity ≤ 0
max_lot / min_lotnumberLot bounds
hedging_allowedbooleanAllow hedging
swap_enabled / commission_enabledbooleanFee toggles
bonus_included_in_equitybooleanBonus counts toward equity

RLS: Read open; create/update/delete admin-only.

ClientOffer

A promotional offer popup shown to clients.

FieldTypeDescription
title / bodystringOffer copy
image_urlstringBanner image
cta_text / cta_linkstringCall-to-action label + URL
target_audienceenumall | specific
target_account_idsstringComma-separated account ids (specific)
auto_close_secondsnumberPopup auto-close (0 = none)
show_interval_hoursnumberMin hours between showings
statusenumactive | paused | expired
start_date / end_datedate-timeValidity window
accent_colorstringHSL channels for accent

RLS: Create/update/delete admin-only; read open.

OfferImpression

Tracks offer views/claims per client.

FieldTypeDescription
offer_idstringClientOffer id
client_account_idstringClientAccount id
last_shown_atdate-timeLast view time
view_countnumberTotal views
claimedbooleanClient clicked CTA
claimed_atdate-timeClaim timestamp

RLS: Create/read/update open; delete admin-only.

ClientReview

A client review/testimonial.

FieldTypeDescription
client_account_idstringClientAccount id
full_name / trading_user_idstringReviewer identity (real name shown publicly)
ratingnumber1-5 stars
remarkstringReview text
instrumentstringTraded instrument
is_publicbooleanShown on homepage when approved
statusenumpending | approved | rejected
submitted_at / reviewed_atdate-timeLifecycle timestamps

RLS: Create/read open; update/delete admin-only.

ClientVerification

KYC document submission.

FieldTypeDescription
client_account_idstringClientAccount id
id_proof_front_url / back_urlstringID front/back
address_proof_front_url / back_urlstringAddress proof
card_front_url / back_urlstringCard images
bank_statement_urlstringBank statement
statusenumpending | verified | rejected
verified_by_admin / verified_atstring/date-timeVerification audit

RLS: Create/read open; update/delete admin-only.

AcademyRegistration

A registration request from the marketing/academy site.

FieldTypeDescription
full_name / email / phone_numberstringApplicant contact
account_typeenumBasic | ECN | Royal | VIP
password_hashstringSHA-256 hash
statusenumpending | contacted | created | rejected
created_trading_user_idstringAccount id once created
sourceenumacademy | account | deal
remarkstringClient-submitted details

RLS: Create open; read/update admin-only; delete super_admin only.

PaymentMethod

Configured deposit/withdrawal methods.

FieldTypeDescription
method_typeenumdeposit | withdrawal | both
name / method_keystringDisplay name + internal key
iconstringEmoji icon
min_amount / max_amountnumberAmount bounds
fee_percentnumberFee %
instructionsstringWallet address / bank details shown to client
card_linkstringCopyable payment link

RLS: Read open; CRUD admin-only.

AuditLog

Admin action audit trail.

FieldTypeDescription
actionstringe.g. ACCOUNT_RESTORE_PRE_TRADEOUT
admin_userstringAdmin name
account_idstringAffected account
detailsstringAction description
timestampdate-timeWhen

RLS: Open.

TradingAccount (legacy)

Older account entity tied to Base44 User (RLS-protected).

FieldTypeDescription
user_idstringBase44 User id
account_numberstringAccount number
account_typeenumstandard | ecn | vip | demo
balance / equity / used_margin / free_margin / margin_level / floating_plnumberLive metrics
statusenumactive | suspended | closed

RLS: Owner read/update; broker_admin/super_admin all; create/delete admin-only.

User (built-in)

Base44 platform user — admins only. Cannot be created via SDK; users join via invites.

FieldTypeDescription
id / created_datestring/dateBuilt-in
full_name / emailstringProfile
rolestringadmin | user (customizable to super_admin, broker_admin)

RLS: Built-in: only admins list/update/delete others.

A2Backend Functions

Five serverless functions (Deno/TypeScript) handle all server-side automation. Each is invoked via base44.functions.invoke(name, payload) or a scheduled workflow.

backgroundTradingEngine

Schedule: every ~30 seconds via workflow. Auth: service-role (no user context).

The institutional core. Runs even when clients are offline. Three phases per tick:

  1. AI Auto-Dealing — for each ACTIVE AISession, find the matching AISimulationTier by balance range. Respect cooldown (random within tier interval), daily profit cap, and daily loss limit. Pick a live, open-market symbol, derive per-deal P/L from the tier's daily targets, create an AITrade record (history only — no Position), and adjust balance + session stats.
  2. TP/SL Monitoring — for every open Position, skip if the asset class market is closed (weekend) or the price isn't live. Close at the TP/SL trigger price (not the bid). Use a unique close_time timestamp as a race lock: re-read the position after update; only the monitor whose timestamp persists applies P/L to the balance. Send TP_HIT/SL_HIT notification + Telegram alert.
  3. Stop-Out Guard — iterative loop (max 25): recompute equity = balance + bonus + floating P/L using live prices; persist equity/margin metrics. If negative-balance protection and equity ≤ 0, close all positions. If margin level ≤ stop_out_level, liquidate only currently-tradeable (liquid) positions worst-loss-first, re-running until margin normalizes. Two-tier margin alerts (neutral/professional tone).

Manual price override: instruments with manual_price_active=true pin the engine's price to base_price, overriding the live feed.

dailyRolloverEngine

Schedule: once daily (~00:05 ET) via workflow. Auth: admin-only.

Applies overnight swap/financing to every open Position. Rules:

  • Currency/Metal: triple swap on Wednesday (3-day weekend settlement).
  • Stock/Index: triple swap on Friday (equity weekend settlement).
  • Crypto: standard daily swap, no triple rollover.
  • Stock financing: APR-based daily fee = (shares × entry × rate%) / 365, default 4% APR.

Swap fee = volume × contract × swapPoints × pointSize × conversionFactor, realized daily against balance.

updateInstrumentBasePrices

Schedule: every 10 minutes via workflow. Auth: service-role.

Fetches live Finnhub REST quotes for all instruments and persists them as Instrument.base_price — the fallback used when live socket data is unavailable (weekend freeze, disconnect, outage). Skips instruments under manual price override.

restoreAccountPreTradeOut

Auth: super_admin only. Payload: { account_id }.

Reopens every Position closed by stop_out or neg_balance, restoring each to its pre-close state, and reverses the booked P/L: new_balance = current_balance − sum(closed_profits). Writes an AuditLog entry.

sendTelegramAlert

Auth: open (called server-side). Payload: { title, message }.

Sends a Markdown-formatted message to the super-admin Telegram chat using TELEGRAM_BOT_TOKEN + TELEGRAM_CHAT_ID secrets. Fire-and-forget from the frontend via base44.functions.invoke.

A3Frontend Core Libraries

lib/marginEngine.js — Broker-grade margin (MT4/MT5 compatible)

All P/L and margin math. Key formulas:

calcPositionMargin(symbol, volume, price, leverage):
  contractSize = getContractSize(symbol)   // forex=100000, gold=100, silver=5000, crypto/stock/index=1
  return (volume * contractSize * price) / leverage

calcPositionPL(symbol, type, volume, openPrice, currentPrice):
  direction = type === 'buy' ? 1 : -1
  return (currentPrice - openPrice) * contractSize * volume * direction

calcEquity(balance, bonus, floatingPL, bonusIncludedInEquity=true):
  return balance + (bonusIncludedInEquity ? bonus : 0) + floatingPL

calcFreeMargin(equity, usedMargin) = equity - usedMargin
calcMarginLevel(equity, usedMargin) = usedMargin > 0 ? (equity / usedMargin) * 100 : Infinity

validateNewOrder({ account, symbol, type, volume, currentPrice, openPositions, priceMap, riskSettings }):
  - reject if account suspended/disabled
  - enforce min/max lot
  - reject if equity <= 0 (negative balance protection)
  - reject if marginLevel <= marginCallLevel
  - reject if freeMargin < requiredMargin for new position

lib/finnhubService.js — Live market data

REST quote API for initial prices + WebSocket trade stream for real-time updates. Symbol map: forex/metals → OANDA:, crypto → BINANCE:, indices → ^/INDEX:, stocks → ticker. BID = live price; ASK = BID + admin spread. Manual price overrides pin a symbol and skip the live feed. isSymbolLive() tracks which symbols have received a real tick. Indices polled via REST every 10s (no WS). Auto-reconnect on WS close (5s).

lib/marketData.js — Compatibility shim

Re-exports finnhubService functions under legacy names (startMarketData, subscribePrices, getPrice). Also provides async generateCandleData(symbol, timeframe, count) for charts via Finnhub REST candles, with a simulated-candle fallback.

lib/tradingEngine.js — Order validation + formatters

Re-exports marginEngine functions and adds validateOrder() (account status, lot bounds, margin sufficiency, stop-level distance for SL/TP) and helpers: generateTicket(), generateAccountNumber(), formatPrice(), formatMoney(), formatVolume().

lib/clientAuth.js — Custom client session

Separate from Base44 admin auth. SHA-256 password hashing (Web Crypto, salt _zio_salt_2024). Session stored in localStorage (tuskerfx_client_session), auto-logout after 8h inactivity. generateTradingUserId() produces unique TFX-XXXXXX IDs.

lib/statementPdf.js — PDF statement generator

Uses jsPDF + moment. Branded TuskerFX statement with: account summary (balance, equity, total deposits/withdrawals, open count, closed P/L), deposits & withdrawals table, bonus history, AI trading summary (overall stats only — no tier details), client trade history, running positions. Footer: "This Statement is generated by Tusker FX." 24h generation cooldown enforced.

lib/telegramAlert.js + lib/timezone.js + lib/marketStatus.js

telegramAlert.js fire-and-forget wrapper. timezone.js Intl-based formatting in the configured display timezone (default Asia/Colombo). marketStatus.js client-side market-open check mirroring the server's marketHours.

shared/marketHours.ts — Server-side market gating

Asset-class metadata + market-hours logic. isMarketClosedForClass(): non-crypto closes Fri 17:00 ET → Sun 17:00 ET; crypto 24/7/365. symbolCategory(), getInstrumentMeta(), quoteCurrency(), conversionFactor() (USD-base = 1).

A4React Hooks

useLivePrices(openPositions)

Subscribes to the market feed; exposes allLive — true only when every open position has a real live price. Price-dependent metrics stay hidden until the feed connects.

useTPSLMonitor({ accountId, openPositions })

Client-side TP/SL watcher (mirrors backend). Throttled to 2s. Closes at the TP/SL trigger price. Race lock via unique close_time timestamp + re-read confirmation. Skips non-live prices and closed markets. Invalidates React Query caches on close.

useAISimulator({ session, accountId, onTradeExecuted })

Client-side AI deal generator (active while the client is online). Reads AISimulationTier records (falls back to hardcoded tiers). Derives per-trade P/L from daily targets. Creates AITrade records (history only) and adjusts balance. Respects weekend (crypto-only symbols).

useMarginMonitor, usePendingOrderEngine, useClientSync, useAppTimezone

Live margin/equity recalculation, pending-order trigger evaluation, client data sync, and global timezone fetching respectively.

A5Row-Level Security Summary

RLS is declared per entity in base44/entities/*.jsonc. Three patterns:

  • Open (null): ClientAccount, Position, Transaction (read/create), Notification, AISession, AITrade, PendingOrder, TradingBonus, BonusLedger, AuditLog, OfferImpression, ClientReview (read/create), ClientVerification (read/create), AcademyRegistration (create), Instrument, PaymentMethod (read), RiskSettings (read) — access controlled at the app layer by session/role.
  • Admin-only CRUD: AISimulationTier, RiskSettings (write), PaymentMethod (write), ClientOffer (write), ClientReview (write), ClientVerification (write), AcademyRegistration (read/update), BonusLedger delete.
  • Owner + admin: TradingAccount (legacy) — owner reads/updates own records; broker_admin/super_admin full access.

A6Workflows (Scheduled Automations)

Three scheduled workflows drive the backend:

WorkflowTriggerFunction
Background Trading EngineEvery ~30s (scheduled)backgroundTradingEngine
Daily RolloverOnce daily ~00:05 ETdailyRolloverEngine
Update Instrument Base PricesEvery 10 minupdateInstrumentBasePrices

A7Pages & Routes

Full route inventory (src/App.jsx):

RoutePageAccess
/HomePagePublic
/featuresFeaturesPagePublic
/accountsAccountsPagePublic
/marketsMarketsPagePublic
/academy/trading-academyLearnPage
/contactContactPagePublic
/client-loginClientLoginPublic (client auth)
/client-registerClientRegisterPublic (client auth)
/client-dashboardClientDashboardClient session
/client-tradeClientTradeClient session
/client-positionsClientPositionsClient session
/client-historyClientHistoryClient session
/client-walletClientWalletClient session
/client-ai-tradingAITradingClient session
/mobile-terminalMobileTerminalClient session
/client-bonusesClientBonusesClient session
/client-verificationClientVerificationClient session
/client-reviewsClientReviewsClient session
/loginLoginBase44 admin auth
/registerRegisterBase44 admin auth
/forgot-passwordForgotPasswordBase44 admin auth
/reset-passwordResetPasswordBase44 admin auth
/adminAdminDashboardAdmin (ProtectedRoute)
/admin/trading-accountsTradingAccountsAdminAdmin
/admin/clientsClientManagementAdmin
/admin/positionsAdminPositionsAdmin
/admin/transactionsAdminTransactionsAdmin
/admin/instrumentsInstrumentManagementAdmin
/admin/riskRiskControlsAdmin
/admin/reportsReportsAdmin
/admin/ai-tradesAdminAITradesAdmin
/admin/bonusesAdminBonusesAdmin
/admin/verificationAdminVerificationAdmin
/admin/learning-centerLearningCenterAdmin
/admin/account-watchAccountWatchAdmin
/admin/reviewsAdminReviewsAdmin
/admin/offersAdminOffersAdmin

Part B — Architecture & Key Logic

A mid-level overview of the system's architecture, data flow, and the core algorithms that govern trading, risk, and automation — enough to rebuild without line-by-line detail.

B1System Architecture

Two co-located apps sharing one codebase and database, separated by route prefix and auth model:

  • Tusker FX (Marketing & Academy): public routes (/, /features, /accounts, /markets, /academy, /contact). Drives registration requests into AcademyRegistration for admin follow-up. No login required.
  • SKY Trader (Trading Terminal): client portal (/client-*) using a custom localStorage session (ClientAuthContext), and an admin console (/admin/*) using Base44 platform auth (AuthProvider + ProtectedRoute).

Stack: React 18 + Vite + Tailwind CSS + shadcn/ui on the frontend; Base44 BaaS (entities, functions, workflows, auth) on the backend. Live market data via Finnhub (REST + WebSocket). Admin alerts via Telegram Bot API.

B2Market Data Pipeline

A single source of truth for prices, with a strict live-only trading gate:

  1. Initialization: startFinnhub(instruments) seeds prices from INSTRUMENT_DEFAULTS base values for instant display, then fetches REST quotes for all symbols.
  2. Live stream: WebSocket subscribes to forex/metals/crypto/stocks. Indices (US30, NAS100, SPX500, GER40, UK100) have no WS — polled via REST every 10s.
  3. Spread: ASK = BID + admin-configured per-instrument spread (default 0 → BID = ASK).
  4. Manual override: when Instrument.manual_price_active=true, the live feed is skipped for that symbol and the price is pinned to base_price. All consumers compute P/L from the manual price.
  5. isLive gate: liveSymbols tracks symbols that have received a real tick. useLivePrices exposes allLive; all trading metrics and engine actions stay hidden/dormant until every open position has a live price.
  6. Weekend freeze: non-crypto markets close Fri 17:00 ET → Sun 17:00 ET; the last tick is frozen and TP/SL never fires on frozen assets. Crypto stays 24/7.
  7. Fallback persistence: updateInstrumentBasePrices writes live REST quotes to Instrument.base_price every 10 min for use during outages.

B3Margin & P/L Engine

MT4/MT5-compatible calculations, multi-asset:

Required Margin = (volume × contractSize × price) / leverage
  forex: contractSize = 100000
  gold:  contractSize = 100
  silver: contractSize = 5000
  crypto/stock/index: contractSize = 1

Position P/L = (currentPrice - openPrice) × contractSize × volume × direction
  direction = buy ? +1 : -1

Equity      = balance + bonus + floatingPL
FreeMargin  = equity - usedMargin
MarginLevel = (equity / usedMargin) × 100   (Infinity when no positions)

Balance = deposits - withdrawals + closedPnL   (excludes bonus)

B4TP/SL & Stop-Out Rules

Two monitors (frontend + backend) run the same logic with a race lock to prevent double-closure:

  • Close-price model: BUY closes at BID (sell to close) → TP when bid ≥ TP, SL when bid ≤ SL. SELL closes at ASK → TP when ask ≤ TP, SL when ask ≥ SL.
  • Trigger price fill: positions close at the TP/SL level, not the current market price (institutional standard).
  • Race lock: a unique close_time timestamp is written; after update the position is re-read — only the monitor whose timestamp persisted applies P/L to the balance. Prevents double credit when both monitors race.
  • Market gate: TP/SL never fires on closed/frozen markets or non-live prices.
  • Stop-out: iterative loop liquidates only currently-tradeable (liquid) positions, worst-loss-first, re-running until margin normalizes or no liquid positions remain. Balance may go negative — only equity gates further trading.
  • Negative-balance protection: when equity ≤ 0, all positions close and balance reflects realized P/L (not reset to 0).
  • Margin alerts: two tiers (approaching stop-out vs. margin call), both neutral and professional in tone.

B5Daily Rollover / Swap

Once-daily financing applied to every open position:

Currency/Metal: triple swap on Wednesday (3-day settlement)
Stock/Index:   triple swap on Friday   (equity weekend settlement)
Crypto:        standard daily swap, no triple rollover

Swap fee = volume × contract × swapPoints × pointSize × conversionFactor
  pointSize = 10^(-digits)

Stock financing (APR model):
  dailyFee = (shares × entryPrice × APR%) / 365   (default 4% APR)

Swap is realized daily against the account balance and accumulated on the Position's swap field.

B6AI Simulation Engine

Automated dealing for active AI sessions, driven by admin-configured tiers:

  1. For each ACTIVE AISession, find the AISimulationTier whose balance range contains the account balance.
  2. Respect cooldown (random within tier's min/max interval seconds) and daily caps (stop if daily P/L ≥ daily_profit_max or ≤ −daily_loss_limit).
  3. Pick a live, open-market symbol; derive per-deal P/L from the tier's daily targets divided by estimated trades/day.
  4. Win/loss decided by the tier's win_rate (default 0.9).
  5. Create an AITrade record (history only — never an open Position) and adjust balance + session stats.

Critical invariant: AI simulations appear only as closed history, never as live positions. Tier details are hidden from the client UI.

B7Authentication Flows

Client (custom session)

Admin-only account creation (no self-service). Login validates SHA-256 hash against ClientAccount.password_hash, stores a localStorage session (8h inactivity timeout), and redirects — mobile logins go to /mobile-terminal. ClientProtectedRoute guards all /client-* routes.

Admin (Base44 platform auth)

Email/password + Google OAuth via Base44 AuthProvider. Roles: super_admin, broker_admin, admin. ProtectedRoute gates /admin/*. Registration → OTP → verify → token → redirect.

B8Notification & Telegram Alert Flow

Two parallel channels for every significant event:

  • In-app: a Notification record is created per client account; the client NotificationCenter subscribes via React Query + realtime subscriptions.
  • Telegram: critical admin alerts (registration, deposits, withdrawals, margin breaches, stop-outs, client logins) are forwarded to the super-admin chat via the sendTelegramAlert function using TELEGRAM_BOT_TOKEN + TELEGRAM_CHAT_ID secrets. Fire-and-forget; never blocks the caller.

B9Statement PDF Generation

Client-triggered, branded PDF via jsPDF, with a 24h-per-account cooldown:

  • Account summary: balance, equity, total deposits, total withdrawals, open count, total closed P/L.
  • Deposits & withdrawals table; bonus history; AI trading summary (overall stats only).
  • Client trade history (full details) + running positions.
  • Footer: "This Statement is generated by Tusker FX." Admin adjustments are never disclosed.

Part C — Feature Inventory

A structured inventory of every feature with a one-paragraph summary. Use this layer for scope estimation and feature checklists.

C1Marketing & Academy Site (Tusker FX)

Homepage

Animated forex-themed hero with live BTC price card, floating Telegram CTA, live price ticker, trust strip, popular markets, AI trading showcase, trading academy preview, latest client reviews (fixed deterministic order, real names), how-to-start steps, and contact centers.

Features Page

Detailed breakdown of platform capabilities: multi-asset trading, AI automation, account types, risk management.

Accounts Page

Four-tier account structure (Basic, ECN, Royal, VIP) with leverage, spreads, and minimums.

Markets Page

Instrument catalog across forex, metals, crypto, indices, and stocks with live pricing.

Trading Academy

Course listing with AI-generated video content (credit-gated), category filtering, and progress tracking. Registration requests flow to admin for manual account creation.

Contact Page

Contact form and office/location details.

C2Client Portal (SKY Trader)

Dashboard

Account overview: balance, equity, margin, floating P/L, open positions summary, recent transactions, AI session status, and quick actions.

Trade Terminal

Full trading interface: market watch, price chart (Finnhub candles), order panel (market + pending orders), live positions table with TP/SL modification, and pending orders panel. All metrics gated on live prices.

Positions

Dedicated open-positions view with close, modify TP/SL, and live P/L.

History

Dual-view trade history: combined total P/L header, side-by-side AI vs manual performance sections, win rates, and date-range filtering (timezone-aware).

Wallet

Deposit/withdrawal workflows with method-specific payment detail collection, auto-withdrawal for qualifying accounts, available-balance calculation accounting for margin and floating P/L, and transaction history. Withdrawals locked while positions are open.

AI Trading

Start/stop AI sessions (SAFE/OPTIMIZED modes), live session stats, and AI deal feed. Tier details hidden from the client.

Mobile Terminal

Compact mobile-optimized trading terminal; mobile logins redirect here.

Bonuses

Active bonus balance, bonus history, and ledger.

Verification

KYC document upload (partial uploads allowed; manual admin verification), status tracking.

Reviews

Submit a review (rating + remark + instrument); admins approve for public display with real names.

Notifications

Real-time in-app notification center with copy-to-clipboard, unread badges, and type-specific icons.

Offer Popups

Targeted promotional offers with view/claim tracking, auto-close, and show-interval throttling.

Statement PDF

One-click branded PDF statement with 24h cooldown.

C3Admin Console

Dashboard

Platform-wide KPIs: total clients, AUM, open positions, pending transactions, AI activity.

Trading Accounts Admin

Create/edit/suspend client accounts, reset passwords, change account types, toggle auto-withdrawal, send notifications, and manage wallet payment methods.

Client Management

Review academy registration requests, create accounts from requests, mark contacted/rejected, detect duplicates.

Positions

Monitor/close all positions across clients, bulk close, and filter by account/symbol/status.

Transactions

Approve/reject deposits & withdrawals, manual adjustments, edit/delete any transaction (with balance reversal), reverse approved withdrawals, and auto-withdrawal processing with payment-detail notifications.

Instruments

Full CRUD on tradable instruments: contract specs, spreads, swaps, leverage, digits, and manual price override toggle (pins price until toggled off).

Risk Controls

Global risk settings: max leverage, stop-out/margin-call levels, negative-balance protection, lot bounds, hedging/swap/commission toggles, and global display timezone.

Reports

Aggregate reports across clients, instruments, and time periods.

AI Trades

Review AI-simulated deals; configure AISimulationTier records (balance ranges, daily profit/loss caps, win rates, intervals, lot sizes).

Bonuses

Grant/remove/adjust bonuses with full ledger audit.

Verification

Review KYC submissions, approve/reject with notes.

Account Watch

Real-time super-admin monitor: margin metrics, account status, live floating P/L, last-online tracking, expandable position breakdowns, and client-online Telegram alerts.

Reviews

Approve/reject client reviews for public homepage display (real names, fixed order).

Offers

Create/target promotional offers with audience targeting, scheduling, and a Claims tab tracking engagement and claim rates.

Learning Center

Manage academy courses and AI-generated video content.

Restore Pre-Trade-Out

Super-admin tool to reopen stop-out/neg-balance closures and reverse the booked P/L.

Appendix I — Base44 Implementation Guide

Templates and conventions for rebuilding on the Base44 platform.

I.1Entity Schema Template

Each entity is a JSON-schema object at base44/entities/<Name>.jsonc. Example (ClientAccount, abridged):

{
  "name": "ClientAccount",
  "type": "object",
  "properties": {
    "trading_user_id": { "type": "string" },
    "password_hash": { "type": "string" },
    "full_name": { "type": "string" },
    "account_balance": { "type": "number", "default": 0 },
    "equity": { "type": "number", "default": 0 },
    "account_status": { "type": "string", "enum": ["Active","Suspended","Disabled"], "default": "Active" },
    "leverage": { "type": "number", "default": 100 }
  },
  "required": ["trading_user_id", "password_hash", "full_name"],
  "rls": {
    "create": null, "read": null, "update": null, "delete": null
  }
}

Built-in fields id, created_date, updated_date, created_by_id are automatic — never declared. RLS uses user_condition with role and $or for admin tiers.

I.2Backend Function Template

Functions live at base44/functions/<name>/entry.ts (Deno/TypeScript). Pattern:

import { createClientFromRequest } from 'npm:@base44/sdk@0.8.48';
import { secrets } from "base44:runtime";

export default async function(req: Request): Promise<Response> {
  const base44 = createClientFromRequest(req);
  const user = await base44.auth.me();
  // ...logic using base44.asServiceRole.entities.<Name>.filter/create/update
  return Response.json({ ok: true });
}

Use base44.asServiceRole for service-role access (bypasses RLS). Secrets via secrets.get("NAME"). Invoke from frontend with base44.functions.invoke('name', payload).

I.3Workflow Schedule Reference

Workflows are JSON at base44/workflows/<Name>.jsonc. The three scheduled workflows:

Background Trading Engine  →  scheduled every ~30s   →  invoke backgroundTradingEngine
Daily Rollover           →  scheduled once daily      →  invoke dailyRolloverEngine
Update Instrument Prices →  scheduled every 10 min    →  invoke updateInstrumentBasePrices

I.4Secrets

Two secrets power the Telegram alert channel:

  • TELEGRAM_BOT_TOKEN — Bot API token from BotFather.
  • TELEGRAM_CHAT_ID — Super-admin chat/channel id (user must /start the bot first).

Finnhub API key is currently hardcoded in the market-data libs (replace with a secret for production).

I.5SDK Entity Operations

base44.entities.Todo.list('-updated_date', 20)
base44.entities.Todo.filter({status:'active'}, '-created_date', 10)
base44.entities.Todo.create({title:'x'})
base44.entities.Todo.bulkCreate([{...},{...}])
base44.entities.Todo.update(id, {status:'done'})
base44.entities.Todo.updateMany({status:'active'}, {$set:{status:'done'}})
base44.entities.Todo.bulkUpdate([{id, status:'done'}, ...])
base44.entities.Todo.delete(id)
base44.entities.Todo.deleteMany({status:'archived'})
base44.entities.Todo.subscribe((event) => { /* realtime */ })

Appendix II — Stack-Agnostic Build Guide

Data model, API contract, auth, and cron jobs for rebuilding on any framework (Next.js, Django, Laravel, NestJS, etc.).

II.1Data Model (SQL/ERD)

Core tables and relationships. All tables have id (uuid PK), created_at, updated_at, created_by_id.

client_accounts (id PK, trading_user_id UNIQUE, password_hash, full_name,
  email, phone_number, account_balance, equity, floating_pl, used_margin,
  free_margin, margin_level, account_status, leverage, currency, account_type,
  auto_withdrawal_enabled, last_login, last_statement_generated_at)

positions (id PK, account_id FK→client_accounts, ticket, symbol, type,
  volume, open_price, close_price, current_price, stop_loss, take_profit,
  profit, commission, swap, status, order_type, close_reason, ai_mode,
  open_time, close_time)

transactions (id PK, account_id FK→client_accounts, type, amount, currency,
  status, method, notes, processed_by, processed_at)

instruments (id PK, symbol UNIQUE, name, category, contract_size, min_lot,
  max_lot, spread, commission, swap_long, swap_short, stop_level, digits,
  base_price, manual_price_active, enabled)

ai_simulation_tiers (id PK, tier_name, min_balance, max_balance,
  daily_profit_min, daily_profit_max, daily_loss_limit, win_rate,
  trade_interval_min_sec, trade_interval_max_sec, lot_size, enabled)

ai_sessions (id PK, trading_account_id FK→client_accounts, mode, status,
  started_at, stopped_at, total_trades, total_profit, total_loss)

ai_trades (id PK, session_id FK→ai_sessions, trading_account_id, symbol,
  side, lot_size, profit_loss, deal_status, source, created_at)

pending_orders (id PK, trading_account_id, symbol, order_type, volume,
  trigger_price, stop_loss, take_profit, status, created_at, executed_at,
  executed_price)

trading_bonuses (id PK, trading_account_id, bonus_type, bonus_amount,
  status, created_by_admin, created_at)

bonus_ledger (id PK, trading_account_id, action_type, amount,
  previous_bonus_balance, new_bonus_balance, admin_user, created_at)

notifications (id PK, trading_account_id, type, title, message, read, created_at)

risk_settings (id PK, setting_key UNIQUE, timezone, max_leverage,
  stop_out_level, margin_call_level, warning_level,
  negative_balance_protection, max_lot, min_lot, hedging_allowed,
  swap_enabled, commission_enabled, bonus_included_in_equity)

client_offers (id PK, title, body, image_url, cta_text, cta_link,
  target_audience, target_account_ids, auto_close_seconds,
  show_interval_hours, status, start_date, end_date)

offer_impressions (id PK, offer_id FK→client_offers, client_account_id,
  last_shown_at, view_count, claimed, claimed_at)

client_reviews (id PK, client_account_id, full_name, trading_user_id,
  rating, remark, instrument, is_public, status, submitted_at, reviewed_at)

client_verifications (id PK, client_account_id, id_proof_front_url,
  id_proof_back_url, address_proof_front_url, address_proof_back_url,
  card_front_url, card_back_url, bank_statement_url, status,
  verified_by_admin, verified_at)

academy_registrations (id PK, full_name, email, phone_number, account_type,
  password_hash, status, created_trading_user_id, source, remark)

payment_methods (id PK, method_type, name, method_key, icon, enabled,
  min_amount, max_amount, fee_percent, instructions, card_link)

audit_logs (id PK, action, admin_user, account_id, details, timestamp)

users (platform auth — admin only; not client accounts)

II.2REST API Contract

On Base44 these are SDK calls; on a custom backend they map to REST endpoints. Auth via Bearer token (client session or admin JWT).

# Client auth (custom)
POST   /api/client/login            { trading_user_id, password } → { session_token }
POST   /api/client/logout           → { ok }
GET    /api/client/me               → { account }

# Accounts (admin)
GET    /api/admin/accounts           ?status=&q=
POST   /api/admin/accounts           { full_name, account_type, leverage }
PATCH  /api/admin/accounts/:id       { ...fields }
POST   /api/admin/accounts/:id/reset-password
POST   /api/admin/accounts/:id/notify   { title, message }
POST   /api/admin/accounts/:id/restore-pre-tradeout   (super_admin)

# Positions
GET    /api/positions?account_id=&status=
POST   /api/positions                { account_id, symbol, type, volume, ... }
PATCH  /api/positions/:id             { stop_loss, take_profit } | { status:'closed', ... }
POST   /api/admin/positions/bulk-close  { ids }

# Transactions
GET    /api/transactions?account_id=&status=
POST   /api/transactions             { account_id, type, amount, method, notes }
PATCH  /api/transactions/:id          { status, amount, method, notes }   (admin)
DELETE /api/transactions/:id                                            (admin)
POST   /api/transactions/:id/reverse                                    (admin)

# Instruments
GET    /api/instruments
POST   /api/instruments               (admin)
PATCH  /api/instruments/:id          { spread, base_price, manual_price_active, ... }

# AI
GET    /api/ai-sessions?account_id=
POST   /api/ai-sessions               { trading_account_id, mode }
PATCH  /api/ai-sessions/:id           { status }
GET    /api/ai-trades?account_id=
GET    /api/ai-tiers   POST/PATCH/DELETE   (admin)

# Risk
GET    /api/risk-settings
PATCH  /api/risk-settings             (admin)

# Market data (or use Finnhub directly client-side)
GET    /api/prices                    → { symbol: { bid, ask, isLive, ... } }
GET    /api/prices/:symbol/candles?tf=1H&count=80

# Notifications
GET    /api/notifications?account_id=
PATCH  /api/notifications/:id         { read:true }

# Offers / Reviews / Verification / Bonuses / KYC — standard CRUD per entity

# Statements
POST   /api/statements/generate       { account_id } → PDF (24h cooldown)

II.3Authentication Flow

Client (custom)

1. Admin creates ClientAccount (password hashed SHA-256 with salt).
2. Client POST /api/client/login { trading_user_id, password }.
3. Server hashes password, compares to password_hash, issues session token (JWT or opaque).
4. Client stores token (localStorage); 8h inactivity expiry.
5. ClientProtectedRoute guards /client-* routes.
6. Mobile logins redirect to /mobile-terminal.

Admin (platform auth)

1. Register { email, password } → user created (unverified).
2. OTP sent → verifyOtp → access token issued.
3. Token stored; ProtectedRoute guards /admin/*.
4. Roles: super_admin, broker_admin, admin — enforced in RLS / route guards.
5. Google OAuth alternative login.

II.4Cron Jobs / Scheduled Tasks

Every 30s:  backgroundTradingEngine
  - AI auto-dealing for ACTIVE sessions (tier-matched)
  - TP/SL monitoring + close (race-locked)
  - Stop-out / negative-balance protection (iterative, liquid-only)

Once daily (~00:05 ET):  dailyRolloverEngine
  - Apply swap/financing to all open positions
  - Triple swap: Wed (fx/metals), Fri (stocks/indices)

Every 10 min:  updateInstrumentBasePrices
  - Fetch Finnhub REST quotes → persist as Instrument.base_price (fallback)
  - Skip manual-override instruments

II.5External Services

  • Finnhub — REST quote API + WebSocket trade stream. Symbol map: OANDA: (fx/metals), BINANCE: (crypto), ^/INDEX: (indices), ticker (stocks). API key required.
  • Telegram Bot API — super-admin alerts via sendMessage. Requires bot token + chat id; recipient must /start the bot.
  • jsPDF + moment — client-side statement PDF generation.
End of specification · Tusker FX Academy & SKY Trader Trading Platform