Funded Futures Family — full system flow
The risk/compliance dashboard is one corner of a larger platform spread across four repositories. This page draws the whole path a request takes — browser to database and back — and gives a module-by-module reference for every service involved.
| Repo | Role | Deploys as |
|---|---|---|
fff-risk-web | Next.js staff UI + BFF — seefff-risk-web overview and User flow | frontend |
fff-risk-api | Django views/permissions/RBAC layer for the risk dashboard | BACKEND_SCOPE = risk_dash |
FFF-Backend | Core trading-platform Django backend — owns the actual models (users, accounts, payouts, security flags) | BACKEND_SCOPE = fff_backend |
fff_be_automation (referenced, not explored in this pass) | Celery worker that executes background jobs dispatched by the other two | worker |
The relationship between the two Django services is closer than a typical microservice boundary: fff-risk-api imports Python modules directly from the FFF-Backend package (RBAC permission definitions, payout-transition logic, KYC config) and both operate against the same PostgreSQL database — they're two settings-scoped deployments of a shared codebase family, not independent systems that only talk over HTTP.
System map
One request, start to finish
Login through to a gated data fetch and an async compliance check — the same mechanism every feature in the dashboard reuses.
Module reference — fff-risk-web (frontend / BFF)
Covered in full in fff-risk-web architecture docs; summarized here for continuity.
| Layer | Modules | Role |
|---|---|---|
| Pages & feature UI | pages/**, modules/dashboard/pages/** | Route shells →use<Feature> hooks + <Feature>UI> components |
| Data fetching | api/hooks/** (React Query) | ~280 hooks across auth, dashboard, security flags, exceptions, policy center, compliance cases |
| BFF proxy | pages/api/**, lib/functions/commonApiHandler.ts, bffAuth.ts | Decrypts the Knox token cookie, forwards tofff-risk-api, normalizes responses |
| Auth/session | modules/auth/SessionContextProvider.tsx | PollsGET auth/session-context/, exposes live capability checks app-wide |
| State | redux-toolkit/** (encrypted persist), React Query cache | Small persisted UI/bootstrap state vs. all server data |
Module reference — fff-risk-api (BACKEND_SCOPE=risk_dash)
Thin views/permissions layer; most models.py files here are empty — it operates on models imported from FFF-Backend.
| App | Mounted at | Owns / exposes | Purpose |
|---|---|---|---|
risk_dash | /risk-dash/ | ~360 routes: orders, traders, customers, products, dashboard KPIs, payouts, exposure/hedging reports, security-flags (run checks, enforcement, notices, IP lookups), policy center, exception center, compliance cases, ip-ingestion webhooks | The dashboard's own API surface — nearly every hook inapi/hooks/dashboard/* in the frontend maps to a route here |
user_management | /auth/ | login-v2, login-v2-verify, session-context/, generate-otp, logout, profile | Auth entry point;session_authorization_service.py builds the capabilities map the frontend polls; scoped_token_service.py issues one Knox token per user per scope |
rbac_manage | (routes defined, not wired into core/urls.py) | admin/role/permission CRUD views | Dormant in this snapshot — likely superseded by the sharedFFF-Backend.rbac_manage app |
utils (not an installed app) | — | permissions.py, risk_dashboard_permissions.py, endpoint catalog, strict-matrix registry | Section-based capability primitives (HasRiskDashboardAccess, CanView*/CanManage*) every view's permission_classes are built from |
RBAC response shape (GET /auth/session-context/) — this is exactly what SessionContextProvider on the frontend consumes: user, roles, permissions (risk_dashboard.* names), capabilities (flat {key: bool} map, _view/_manage pairs per section), permission_version (a hash the frontend uses to invalidate caches), rbac_mode (empty|audit|compat|strict).
Module reference — FFF-Backend (BACKEND_SCOPE=fff_backend)
The platform of record. 15 registered Django apps.
| App | Mounted at | Key models | Purpose |
|---|---|---|---|
user_management | auth/ | FFFAuthUser, BrokerAccountInfo, CustomAuthToken (Knox), SessionScope | Identity + trading-account graph; the apprisk_dash depends on most directly |
account_management | account/ | Broker, BrokerCountryRule, AccountType | Broker/account admin & lifecycle (ban/unban, autoscale, sync) |
ecommerce_app | shop/ | Product, Coupon, Subscription, CartCheckoutOrder, Orders | Evaluation/funded-account purchase funnel |
payout_manage | payout/ | TraderPayoutRequest, TraderPayoutActivityLog, PayoutRuleVersion | Shared payout transition logic — used by both the trader-facing submit flow here and the risk-dashboard's admin approve/deny UI |
dashboard_manage | dashboard/ | SecurityFlag (+ large related family), Fill/PositionInterval/ExposureInterval, HedgeGroup/HedgeViolation | Largest app — realtime trade ingestion and the compliance/security-flag engine thatrisk_dash is built on top of |
rbac_manage | rbac-manage/ | Permissions, Role, UserRoles | Authoritative role/permission store; owns therisk_dashboard.* permission namespace fff-risk-api imports |
rise_manage | rise-manage/ | RiseIdOfusers, PaymentIntentForRise | Rise payout/KYC processor integration |
kyc_manage | kyc/ | KycProviderSession, UserKycAttempt | Didit KYC verification |
plaid_manage | — | PlaidKYC | Plaid identity verification (parallel to Didit) |
affiliate_management | affiliate-manage/ | AffiliateUserProfile, AffiliateCommission | Affiliate program |
activity_log_manage | activities/ | ActivityLog, SchedulerLog, ExternalAPILog | Audit trail + scheduler/automation logs |
automation_control | (service-only, no urls.py) | Automation, AutomationPipeline* | Advisory locking + manual-run tracking for jobsfff_be_automation executes |
common | common/ | RuntimeControl, AppNotification, Decision* rule engine | Feature flags — includingrisk-dash-features/, the endpoint useRiskDashFeatures on the frontend polls |
live_ops_manage | (service-only) | LiveAccountManagerRecord, LivePayoutRequest | Funded → live trading account pipeline |
disputifier | disputifier/ | Dispute, PayarcWebhookEvent | Chargeback/dispute management |
Shared infrastructure & external providers
| System | Used for |
|---|---|
| PostgreSQL | Single database both Django deployments read/write |
| Redis | Shared cache (fff_risk_api key prefix) + Celery broker |
fff_be_automation | Celery worker executing async jobsrisk_dash dispatches by task name (security-flag checks, payout side effects) |
| Tradovate / WealthCharts | Broker trading-account data and session sync |
| Rise | Payout disbursement + KYC invites |
| Didit / Plaid | Two parallel KYC/identity-verification providers |
| IPQualityScore | IP reputation / VPN / proxy scoring for the security-flags engine |
| Twilio / Vonage | SMS OTP delivery for 2FA |
| Worthy / 365 / PayPal | Payment processing for the e-commerce funnel |
| Disputifier / Payarc | Chargeback handling |
Things worth knowing before touching this system
- Not independent services.
fff-risk-apiimports Python modules straight fromFFF-Backend(RBAC aliases, payout-transition logic, KYC config) and shares its database — changes toFFF-Backendmodels can breakfff-risk-apiwithout a network call ever failing. - One deployment flag separates the two backends.
BACKEND_SCOPE(fff_backendvs.risk_dash) is checked throughout both codebases to decide which product's rules apply — notification routing, session scoping, RBAC product-scope checks. - Auth sessions are scoped, not shared.
scoped_token_serviceissues a separate Knox token per(user, BACKEND_SCOPE), and only one is active at a time per scope — logging into the risk dashboard doesn't reuse a trading-platform session or vice versa. - RBAC has one owner.
Permissions/Role/UserRoleslive only inFFF-Backend.rbac_manage;fff-risk-api's ownrbac_manageapp has its routes unwired and appears dormant. - Async work has no consumer in
fff-risk-api. It only ever callscelery.send_task()by name onto a shared Redis broker — the actual execution (and any retry/failure handling) happens infff_be_automation, a fourth repository this pass didn't open.