Skip to content

Repository files navigation

Exness-v3 Monorepo

A high-performance trading simulation platform built as a exness monorepo. It streams live market data, executes orders through a lightweight engine layer, and renders a responsive trading UI.

Architecture Overview

  • apps/web (Next.js 14)
    • App Router UI for trading: Assets, PriceChart, TradingPanel, MobileTradingDrawer, UserOrders
    • Cookie-based auth (JWT in httpOnly cookie token) and route protection via middleware.ts for /trade
    • Live prices via a shared price-store fed by a single websocket connection
    • React Query for API mutations/queries, Tailwind + shadcn/ui for styling
  • apps/api (Express)
    • REST API (auth, trading)
    • Magic-link sign-in: POST /api/v1/auth/signup issues a verification link; GET /api/v1/auth/signin/verify?token=... sets token httpOnly cookie and redirects to the web app
    • JWT validation middleware reads the token cookie (authMiddleware.ts)
    • Prisma ORM to Postgres
  • apps/ws (Node ws)
    • Subscribes to Redis pub/sub channel ws:price:update
    • Forwards aggregated price updates to connected browser clients
  • apps/poller (Data ingestion)
    • Connects to Backpack Exchange websocket (wss://ws.backpack.exchange/)
    • Aggregates and publishes price snapshots every ~100ms to Redis channel ws:price:update; also pushes to Redis Streams (stream:engine)
  • apps/engine
    • Handlers that react to Redis streams and manage in-memory state
    • Communicates with Redis, DB (and Mongo in docker compose for auxiliary storage)
  • packages/db (Prisma)
    • Prisma schema + migrations; exposes @imex/db client
  • packages/redis
    • Lightweight Redis client, pub/sub and streams utils used by ws and poller
  • packages/eslint-config, packages/typescript-config
    • Shared lint and TS configs

Data Flow

  1. Poller subscribes to exchange, aggregates ticks → publishes { type: 'PRICE_UPDATE', data: JSON.stringify(priceMap) } to Redis every ~100ms.
  2. WebSocket service (apps/ws) receives pub/sub messages and broadcasts them to all connected clients.
  3. Web client (apps/web) maintains a single shared WS connection (useWebSocket) and writes to a shared price-store (useSymbolPrice).
  4. UI components render bid/ask and compute order sizing using the store.
  5. Orders are posted to the API; engine and DB update state; user orders and balances are re-fetched in the UI.

Authentication

  • Sign-in flow: User submits email → API generates a short-lived JWT link → user opens link → API verifies and sets token cookie (httpOnly, SameSite=Lax) → redirects to /trade.
  • Protection: apps/web/src/middleware.ts redirects unauthenticated users from /trade to /login.
  • API protection: authMiddleware.ts verifies token cookie and sets req.user.

Tech Stack

  • Web: Next.js 14 (App Router), React 18, Tailwind CSS, shadcn/ui, TanStack Query, Axios, Lucide icons
  • API: Express, Zod (validation), JWT, Prisma, PostgreSQL
  • Realtime: ws (WebSocket), Redis (pub/sub, streams)
  • Engine: Node TypeScript, Redis, in-memory state
  • Tooling: Turborepo, Bun (package manager/runtime), TypeScript, ESLint/Prettier, Docker Compose

Monorepo Layout

  • apps/
    • api/ (Express REST)
    • engine/ (engine handlers)
    • poller/ (market data ingestion)
    • web/ (Next.js 14 app)
    • ws/ (WebSocket broadcaster)
  • packages/
    • db/ (Prisma schema/client)
    • redis/ (Redis helper lib)
    • eslint-config/, typescript-config/
  • docker/ (Dockerfiles for api, engine, poller, ws)
  • docker-compose.yml (local infra and app containers)

Getting Started (Local, without Docker Compose)

Prerequisites:

  • Bun 1.1.x (declared in packageManager)
  • Node.js >= 18
  • Postgres 15 running locally (or a DATABASE_URL you can reach)
  • Redis 7 running locally
  1. Install deps
bun install
  1. Configure env Create the following env files or export these in your shell. Example minimal vars:
  • API (apps/api)
  • Web (apps/web)
  • WS (apps/ws)
    • WS_PORT=8080
    • Redis connection envs if your redis package expects them
  • Poller (apps/poller)
    • Redis connection envs if your redis package expects them
  • Engine (apps/engine)
    • DATABASE_URL (if required by the engine)
    • Redis connection envs
  1. Prepare database
bun run db:generate
bun run db:migrate
  1. Run services (each in its own terminal)
bun run start:ws       # WebSocket broadcaster on :8080
bun run start:api      # REST API on :4000
bun run start:poller   # Market data ingestor
bun run start:engine   # Engine
  1. Run the web app
cd apps/web
bun install
bun run dev  # http://localhost:3000

Sign-in: open http://localhost:3000/login, request magic link (in dev the API logs the verify URL), open the verify URL to set the cookie and get redirected to /trade.

Getting Started (Docker Compose)

Docker Compose will start Postgres, Redis, Mongo, and app services.

  1. Create env files referenced in compose:
  • env.dockercompose/.env.backend (for api)
  • env.dockercompose/.env.web-socket (for ws)
  • env.dockercompose/.env.engine (for engine)
  • env.dockercompose/.env.poller (for poller)

Ensure these contain the variables described in the local setup (JWT_SECRET, DATABASE_URL, etc.).

  1. Build and start
docker compose up --build

Services/ports:

  • api: 4000
  • ws: 8080
  • db (postgres): 5432
  • redis: 6379
  • mongo: 27017

Note: The Next.js web app is not included in compose; run it locally (see local web step).

Useful Scripts

  • bun run dev # turbo dev across workspace
  • bun run build # turbo build across workspace
  • bun run lint # turbo lint across workspace
  • bun run db:generate # prisma generate
  • bun run db:migrate # prisma migrate
  • bun run start:api # start API
  • bun run start:ws # start WS
  • bun run start:poller # start Poller
  • bun run start:engine # start Engine

Key Conventions

  • Auth cookie name: token (httpOnly, SameSite=Lax)
  • Protected route: /trade (web enforced by apps/web/src/middleware.ts)
  • WS price channel: Redis pub/sub ws:price:update
  • Web price store: apps/web/src/lib/price-store.ts with useSymbolPrice(symbol)

Troubleshooting

  • 401s in the web app: cookie may be missing/expired; sign in again.
  • No prices in UI: verify poller is running, ws is broadcasting on :8080, and NEXT_PUBLIC_WS_URL matches.
  • DB errors: confirm DATABASE_URL and that migrations have been run.

License

MIT (or your preferred license)

About

A high-performance trading simulation platform built as a exness monorepo.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages