TradeScope AI — Project Scope & Status
Prepared: 2026-07-07 (updated same day after the realness build). Audience: incoming engineering team.
This document describes what the platform is, what is already built and verified working on each side, what is simulated versus real, and which phase the project is in right now.
0. The whole app on one chart
Module status chart
| # | Module | Side | Status | What it runs on |
|---|---|---|---|---|
| 1 | Operator auth + RBAC (7 roles, 15-perm matrix, audit) | Admin | LIVE, real | Server tokens, scrypt, fail-closed |
| 2 | CRM clients/leads + client card + phones directory | Admin | LIVE, real | Supabase, per-field audit |
| 3 | Money ledger (deposit/withdraw/adjust + approve/reject) | Both | LIVE, real bookkeeping | Single decide() path; no PSP connected |
| 4 | Balance Control (admin manual adjustments) | Admin | LIVE, real (2026-07-07) | Ledger adjustment rows, overdraw-guarded, audited |
| 5 | User Management overview | Admin | LIVE, real (2026-07-07) | /users-overview join: CRM + balances + flags + AI + positions |
| 6 | Platform Settings | Admin | LIVE, server-owned (2026-07-07) | min-deposit + withdrawals enforced; spread/commission multipliers applied; leverage/signups stored, labeled not-yet-enforced |
| 7 | Web Trader terminal (35 instruments, pending orders) | Client | LIVE | Simulated fills on the sim book |
| 8 | Charts | Client | LIVE, server history (2026-07-07) | /web-trader/candles, deterministic, gapless to live mid |
| 9 | Market news feed | Client | LIVE, real headlines (2026-07-07) | /news RSS proxy, 10-min cache |
| 10 | AI auto-trading + per-client loss-limit/profit-target | Both | LIVE, simulated PnL | Paper sessions; per-session overrides (2026-07-07) |
| 11 | AI Control monitoring | Admin | LIVE, real counts (2026-07-07) | /ai-trading/summary, agrees with reports |
| 12 | Live Traders board | Client | LIVE, real + anonymized (2026-07-07) | Salted-hash pseudonyms; honest empty state under 3 active sessions |
| 13 | KYC upload + review | Both | LIVE, real | Private Storage bucket, signed URLs |
| 14 | Mass Data Import (staging→commit→rollback) | Admin | LIVE, drilled 12/12 | Awaits security pass before real book |
| 15 | Web calls (LiveKit) + call log + recording seam | Both | LIVE, real | Recording env-gated |
| 16 | PSTN dial-out + predictive dialer + number health | Admin | Built, dry-run | Blocked on outbound SIP trunk env only |
| 17 | WhatsApp inbound inbox | Admin | LIVE, real | Bridge service; outbound = roadmap |
| 18 | SMS two-way | Admin | Seam built | Blocked on provider choice (3 env vars) |
| 19 | Agent Workspace (3-zone daily board) | Admin | LIVE (2026-07-07) | Priority tiers, agenda, inboxes |
| 20 | Client auth | Client | Demo only | Any email+password, localStorage; real accounts = planned |
| 21 | Market prices | Backend | Demo-grade sim | Nudged to real FX refs; vendor swap = one seam |
| 22 | Trade execution | Backend | Simulated by design | Real execution gated on broker bridge + license |
| 23 | Security hardening pass | Backend | NEXT PHASE | RLS, rate limits, CORS narrowing, secret rotation — before mass import |
1. What the product is
TradeScope AI is a forex/CFD broker platform with two user-facing zones plus a shared backend:
- Client Zone — a trading web app for the broker's clients: dashboard, multi-asset web trading terminal, wallet (deposits/withdrawals), KYC document submission, AI auto-trading opt-in, live chat and web calls with the operator team.
- Agent/Admin Zone — a full broker back-office CRM for the operations team: client management, lead pipeline, transaction approval, KYC review, calling (WebRTC + PSTN dial-out + predictive dialer), mass data import, reports, role-based access control, and a daily "agent workspace" board.
- Backend — one FastAPI service that powers both zones.
The business is a real forex-broker operation (owner: Ben). The platform currently runs on simulated market data and simulated trading fills by deliberate decision; the CRM, ledger records, calling infrastructure, auth, and audit systems are real.
2. Architecture, repos, environments
Repositories
| Repo | Location | Remote | Deploy |
|---|---|---|---|
| Frontend (both zones) | ~/apex-ai-app |
none — local only | Cloudflare Pages via wrangler |
| Backend | ~/web-app-test-two/backend |
github.com/benf-ux/web-app-test-two-backend |
Render (auto-deploy on push to main) |
| Legacy operator dashboard + call widget | ~/web-app-test-two/dashboard |
(same parent dir) | Cloudflare Pages project web-app-test-two |
Onboarding note: the frontend repo has no git remote. First team task should be pushing it to a private GitHub repo. All history is intact locally.
Frontend stack
Expo SDK 56 universal app (React Native + react-native-web + expo-router, TypeScript). One codebase renders the client zone, the admin zone, and (future) native iOS/Android. Web is the current focus; app-store submission is deliberately on hold until the web product is final. Charting uses TradingView lightweight-charts v5 (canvas) on web with a native SVG fallback. State is a small custom store (src/lib/data/store.ts) — the single seam between screens and the repository/fetch layer; screens never call the network directly.
Backend stack
FastAPI (Python 3.12) on Render (free tier, kept warm by a Cloudflare Worker cron pinging /health every 10 minutes). Persistence pattern used everywhere: Supabase Postgres (via PostgREST) is the store of record, with an in-memory write-through cache per store module that also serves as the whole store if Supabase is unconfigured. No ORM, no SQLite (Render disk is ephemeral). 31 SQL migrations (migrations/001 … 031), all additive and idempotent, applied via the Supabase Management API. Binary files (KYC docs, call recordings) live in Supabase Storage (private buckets, signed URLs); an optional Cloudflare R2 driver exists behind the same seam for larger files.
Live URLs
| Surface | URL |
|---|---|
| Client zone (production project) | https://tradescope-app.pages.dev |
| Client zone (preview alias, same bundle) | https://tradescope-web-preview.apex-ai-app.pages.dev |
| Client zone (custom domain, CNAME to the apex-ai-app Pages project) | clientzoneapp.faircroftcorebit.net |
| Admin zone | https://tradescope-admin.pages.dev (root 302 → /admin/login) |
| Backend API | https://web-app-test-two.onrender.com (all routes under /dashboard) |
| Legacy operator panel + embeddable call widget | https://web-app-test-two.pages.dev |
All three Pages targets are built from the same expo export --platform web bundle; the admin target adds a / → /admin/login redirect.
3. Client Zone — built and working
Authentication (client side) — DEMO ONLY
Client sign-in/sign-up is local: any valid-looking email plus any password creates a client session in localStorage (apex.session). There is no server-side client credential store yet. The session's display identity (crmIdentity = name || email) is the opaque string that keys every backend record for that client (positions, ledger, chat, KYC, AI sessions). Real client authentication is a known, planned gap — see §8.
Screens that exist and work
Dashboard (accounts, quick actions, balance), Accounts / New Account / Account Details, Wallet with Deposit and Withdraw flows, Transactions history, Transfer, Analysis, Live Traders (real anonymized board since 2026-07-07: active AI sessions rendered under salted-hash pseudonyms, honest empty state below 3 active sessions), TradeScope AI (header stats — balance, buying power, daily P/L, open trades — now read the real account payload and AI session status; the market-analysis visual stays cosmetic and is labeled SIMULATED; the news feed inside it shows real RSS headlines), AI Settings with per-client daily-loss-limit and profit-target steppers + a blocking AI-trading opt-in disclosure gate, Verification (KYC upload), Personal Info, Profile, Settings, Support, Notifications, Referrals, Terms gate, Sign-in/Sign-up (desktop split-screen design), password-reset stub, and the in-call screen (call.tsx) with chat.
Web Trader terminal (flagship, rebuilt to professional grade 2026-07-06)
Desktop layout ≥1024px: watchlist rail (35 instruments: 10 FX, 10 commodities, 10 stocks, 5 indices) with class filters and search, chart area, order ticket column, positions panel, account bar. Mobile: stacked layout with a watchlist overlay.
Chart engine (TradingView lightweight-charts v5):
- ~1,500 bars of deterministic history per (symbol, timeframe), generated backward from the live price so the last close always equals the live anchor. History is frozen per symbol/timeframe for the session; polls only update the last bar. Zoom and pan survive every data refresh by construction.
- Mouse-wheel zoom, Ctrl/Cmd+wheel accelerated zoom anchored at the cursor, drag-to-pan, axis drag scaling, double-click view reset, pinch on touch.
- Live OHLC legend following the crosshair, dotted bid/ask spread lines, countdown-to-bar-close chip, on-chart price lines for every open position (entry/SL/TP) and pending order.
- Timeframes 1m/5m/15m/1H/1D; candles/line/area; SMA-20/EMA-50 overlays.
- Keyboard shortcuts (+/- zoom, arrows pan, F fullscreen, 1-5 timeframes, with input-focus guards), element fullscreen, and a one-click "ARMED" trading mode that skips confirmation dialogs (persisted per browser).
- QA seam:
window.__apexChartexposes read-only chart state for automated tests.
Order management: market orders, limit and stop pending orders (MT-style placement validation; SL/TP validated against the entry price; pending orders reserve no margin; fills happen at the stored entry when the book crosses it, with a margin check at fill time and auto-cancel if insufficient), position modify (SL/TP), close, cancel, Open/Pending/History tabs. The account engine computes balance, equity, floating PnL, margin, free margin, margin level; commissions per instrument class and overnight swap are simulated.
Verified live via automated Playwright drills (21/22 passing; the one failure is a headless-browser fullscreen artifact, not an app bug).
Client communication
Web call button (LiveKit WebRTC) connecting the client to an operator room, with in-call text chat over the LiveKit data channel; every message is also persisted to the CRM. A public "visit ping" updates the client's last-seen time on the admin card.
4. Agent/Admin Zone — built and working
Operator authentication + RBAC v2 (live, production-drilled 14/14)
Real server-side operator accounts: scrypt password hashes, SHA-256-hashed session tokens with 7-day expiry, fail-closed auth on every admin endpoint. 7 roles (owner, admin, account_manager, retention_manager, conversion_manager, it_manager, agent) with an owner-editable 15-permission matrix at /admin/roles (30s cache; changes take effect live). Owner bypasses the matrix; the last active owner cannot be demoted. Permission denials return 403 "Missing permission: <slug>". The old shared-secret backdoor has been fully removed. Every operator action writes to a per-field audit trail (crm_audit_log) with the real operator username.
Agent Workspace (admin Overview — live 2026-07-07)
Three-zone daily board: systematically prioritized client lists (tier order: new FTD ≤7 days → deposit pending → meeting scheduled → plain → no-answer last, annotated server-side on every client list), a 7-day meetings/callbacks agenda (reminders with snooze/dismiss, red flag for missed-call meetings, flashing imminent meetings, browser notification + chime), and a WhatsApp + SMS inbox with per-operator unread counts. SMS is provider-ready (webhook + send seam wired, returns 503 until a provider's three env vars are set on Render).
Clients (CRM)
Full client/lead pipeline: create/edit/delete with duplicate detection (identity → phone → email), lead vs client status, deposit status roll-ups, per-client flags (do-not-call, high-risk, complaint), consent timestamps, notes. In-place client expansion on the list (click a row → key-details and more-details accordions, no page jump) plus a full client card with collapsible sections: facts row (created date, FTD date, last visit, client-local time from IANA timezone), qualification profile (age, occupation, trading experience, savings, retirement fund — labeled Superannuation/Building Society by country), live trading account summary (balance, equity, P/L, trades, win rate, weekly/monthly result), KYC documents review, transactions, calls, tasks, phones directory (multiple numbers per client with primary mirroring), communication channel buttons (Web call / Phone call / WhatsApp), and the AI-trading session card. Every field edit is audited.
Money
Transaction ledger (crm_transactions): client deposit/withdraw requests → pending rows → admin approve/reject with a single decide() write path, decided_by recorded, client balance credited on completion, deposit fields recomputed. Verified end-to-end on production (client submits → admin approves → client sees completed with correct totals). Balance Control screen for manual adjustments. No real payment provider is connected — the ledger is real bookkeeping, money movement is not.
KYC review
Client uploads (jpeg/png/pdf, ≤10MB) go to a private Supabase Storage bucket; admin reviews via signed URLs (each view audited), approves/rejects per document; aggregate client KYC status recomputed automatically. Document types include ID, utility bill, and source-of-funds.
Mass Data Import (Ben: "the core foundation for this CRM") — live, drilled 12/12
Staging-first pipeline for importing an existing broker book: upload CSV/XLSX (25MB / 50k rows) → column auto-mapping with synonym + Hebrew-header + value-pattern detection and reusable mapping templates → validation with dedup preview → chunked idempotent commit engine (≤200 rows/tick, cursor-resumable, crash-safe) → full rollback (children first, merge targets never deleted, deposit fields recomputed). Lineage table guarantees idempotency. Call-recording files upload via presigned URLs to the storage seam (Supabase Storage free driver live, 50MB/object cap; R2 driver ready as an env-var upgrade for bigger files).
Calling stack
- Web calls: admin call center (
/admin/call) joins LiveKit rooms with clients; call log with duration, outcome, and recording linkage; call recording via LiveKit Egress → S3-compatible storage (env-gated). - PSTN dial-out:
dial-clientand permission-gated custom dial (with DNC guard via a phone → client reverse lookup) place a real phone call into the same LiveKit room the operator sits in. Blocked on one thing: an outbound SIP trunk (DIALER_OUTBOUND_TRUNK_IDenv). Until set, endpoints return a cleandialed:falsedry-run. Inbound trunkST_ewgoxxYiNUnpexists and is live for number routing. - Predictive dialer: campaigns, agent presence, pacing governor with a hard 2% internal abandoned-call ceiling (US TCPA legal line is 3%; ≥3% latches and requires manual reset), abandoned-call handling, claim-race-safe entry assignment (verified with concurrent requests against production). Compliance constants are load-bearing — do not loosen without owner sign-off.
- Phone Numbers / Agents / Number Health: number inventory with bulk paste import, agent directory, per-number LiveKit dispatch-rule assignment (verified creating/tearing down real dispatch rules), daily number-health job (answer rates, best call windows, quiet-hours violations, env-gated spam-score checking).
- WhatsApp: a separate bridge service feeds inbound WhatsApp messages into the CRM inbox (inbound auth fixed 2026-07-07). Outbound business messaging via the WhatsApp Cloud API is on the roadmap, not built.
Other admin screens
All of the following were rewired from seed data to the real backend on 2026-07-07 and verified with production drills:
- User Management — renders
GET /users-overview(one-round-trip join of CRM identity, real balance, open-position count, AI-active flag, view-only flag). The old fake suspend/activate and per-user AI switches were replaced by the real trading view-only toggle and a read-only AI badge. - Balance Control — posts real ledger adjustments (
POST /transactions/adjust, permissiontransactions:approve): amount validated, overdraw rejected, row borncompletedwithdecided_by, audit written, client balance actually moves (the client app shows it immediately). - Platform Settings — server-owned row (
GET/PATCH /platform-settings, permissiontrading:settings). Min-deposit and withdrawals-enabled are enforced at request creation with clear error messages; spread-markup and commission multipliers are applied inside the trading engine; leverage cap and signups are stored and honestly labeled "not yet enforced". - AI Control — header counts come from
GET /ai-trading/summary(active sessions, trades, win rate) and match the reports rollup; global enable / emergency stop / risk / capacity were already server-enforced. - Transactions — filter segments All / Deposits / Withdrawals / Adjustments (server-side
kindparam), adjustment rows get a distinct badge; approve/reject/CSV unchanged.
Also: Reports (funnel + KPIs with collapsible sections), Operators management, Roles & Permissions matrix, Data Import wizard, Dialer console.
5. Backend inventory
- 27 routers under
/dashboard: crm, transactions, kyc, client_profile, tasks, calendar, inbox, whatsapp, notifications, call_log, calling, recording, webrtc_dashboard, phone_numbers, number_health, dialer, ai_trading, web_trader, import_router, import_commit_router, reports, operator_auth, users_overview, platform_settings, news, live_traders, plus the SMS webhook. - ~42 store modules, all following the same Supabase-authoritative + memory write-through pattern (
store_base.pyprovides shared id/time helpers).platform_settings_storeadds the peek()/warm() discipline (sync cache-only reads in hot paths, async 30s-TTL refresh riding existing entry points) shared withquote_providerandnews_provider. - 33 migrations applied through
033(032 = ledger adjustment type, 033 = platform_settings). Numbering discipline matters: concurrent work streams claim numbers, so always check the real directory before creating one. - Auth model: client-facing endpoints are public but scoped to a concrete
client_idstring (no client credentials exist yet); operator endpoints requireX-Operator-Tokenand fail closed; permissions checked per-slug viarequire_permission. - Key engine detail: there is no background worker (free Render tier). Everything that looks scheduled is lazy: SL/TP triggers, pending-order fills, and AI-trading ticks settle on the next read. The one true cron is the external keep-alive Worker.
- Test suites live next to the code and run standalone in memory mode: web-trader v2 + pending orders, pacing governor, RBAC (32 checks), workspace suites, import pipeline. They are the regression gate before any deploy.
6. What is real vs simulated (critical for the team)
| Area | Status |
|---|---|
| Market prices | Demo-grade: deterministic two-scale random walk, nudged toward real reference rates for FX (Coinbase → Frankfurter, free keyless APIs, stale-while-error caching). Not an execution feed. A paid vendor (Polygon/Finnhub/broker feed) is deliberately deferred until a paying client exists; the swap point is a single seam (quote_provider.py / _raw_mid). |
| Chart history | Real server history of the sim book (GET /web-trader/candles): deterministic sampling of the same price function the trading engine fills against, gapless, last bar closes at the live mid. The client chart loads it with a synthetic offline fallback. |
| Market news | Real headlines (GET /news): backend RSS proxy over Yahoo Finance, Google News, Investing.com; 10-minute cache, stale-while-error. |
| Trade execution | Simulated end-to-end (fills at the sim book, no broker). Real execution is gated on an MT4/MT5/cTrader bridge (not built) and the owner's trading license (in progress). No live-execution code path exists anywhere by design. |
| AI auto-trading | Simulated (paper sessions, Gaussian PnL per risk profile, server-enforced stops and global emergency stop). Session records, counts, and the admin summary are real. |
| Live Traders board | Real and anonymized: active AI sessions only, pseudonyms from a salted hash, no identity fields in the payload, honest empty state below 3 active sessions. Nothing is fabricated. |
| Admin screens (users / balances / settings / AI control / transactions) | Real backend data end-to-end since 2026-07-07. No seed arrays remain in the admin bundle. |
| Client money | Ledger records are real and audited; no payment provider is connected. |
| Client auth | Local demo auth (any email/password). Server-side client accounts are a planned build. |
| Operator auth / RBAC / audit | Real and enforced in production. |
| Calling (WebRTC) | Real (LiveKit). |
| Calling (PSTN out) | Built and verified in dry-run; blocked on outbound SIP trunk credentials only. |
| SMS | Seam built; blocked on choosing a provider (3 env vars). |
| WhatsApp inbound | Real via the bridge. Outbound Cloud API: roadmap. |
| KYC docs, recordings, imports | Real (Supabase Storage / optional R2). |
| Push-to-call (mobile push) | Built, blocked on FCM/EAS prerequisites. |
7. Current phase
The demo/sim platform is feature-complete and live, and every screen now reads the real backend. The last three builds were the professional web-trader terminal (2026-07-06), the agent workspace (2026-07-07), and the "kill the demo data" realness build (2026-07-07: backend commit 204cead, frontend commit 8ddcf5b, drilled live — Wave 1-3 curl checks plus 13/13 Playwright UI checks). Both repos are clean, committed, deployed, and verified with production drills.
The next agreed phase is security hardening, before any real client data is mass-imported (decision made with the owner on 2026-07-05): Supabase RLS review, API rate limiting, CORS narrowing from * to the three Pages origins, secret rotation, and a pass over the public client-scoped endpoints. Estimated 1–2 days. This should precede the first real-book import through the Data Import wizard.
Open blockers that need external action (not code)
- Outbound SIP trunk credentials →
DIALER_OUTBOUND_TRUNK_IDon Render (unblocks all PSTN dialing). - SMS provider choice → 3 env vars (unblocks two-way SMS in the workspace inbox).
- WhatsApp Cloud API onboarding (unblocks outbound WhatsApp + calling API).
- TURN server for WebRTC (currently no TURN — calls fail on symmetric-NAT networks).
- Payment service provider (real deposits/withdrawals).
- Broker bridge + trading license (real execution).
- Render Starter upgrade (~$7/mo) to retire the keep-alive Worker and the free-tier hour cap.
- Business registration completion → Free Caller Registry for number reputation.
Known deferred/backlog items (by decision, not accident)
Web-trader: drawing tools, draggable SL/TP price lines, order expiry (GTC only today), partial close, cancelled-order history view, depth-of-market ladder. CRM: sanctions/PEP screening, IB/affiliate commissions, KYC tiering, malware scan on uploads. Workspace: month-grid calendar, per-thread read state. Client zone: real server-side client accounts, password reset backend. Platform: production domain cutover for the admin zone, legacy clientzoneapp alias strategy, iOS/Android store submission (on hold until web is final).
8. Access and secrets (locations only — no values in this document)
- Deploy and management tokens: held privately by the owner (locations omitted from this public copy).
- Render env holds:
OPERATOR_SECRET(whatsapp-bridge server-to-server only),SUPABASE_URL/SUPABASE_SERVICE_KEY, LiveKit keys, and the gated integrations' vars (RECORDING_S3_*,SMS_*,DIALER_OUTBOUND_TRUNK_ID,R2_*). - Admin login: owner-role account; credentials held by the owner (omitted from this public copy).
- Client zone needs no credentials (demo auth).
9. Working practices the team should keep
- Additive, idempotent migrations only; verify the highest migration number in the repo and what actually ran in Supabase before writing the next one.
- Every store follows the Supabase-or-memory write-through pattern; keep it — tests depend on memory mode.
- Screens talk to the store, the store talks to the repository; do not fetch from screens.
- Run the standalone backend test suites and
tsc/eslint/expo exportbefore deploying; deploy frontend from a clean worktree; verify live with a Playwright drill after deploying. - The dialer pacing constants and the DNC guard are compliance-load-bearing. Treat them as frozen without owner sign-off.