How bhupeshv29/perps-v2 works
1. This is a Bun-based Turborepo for a trading/exchange system, not a single app. The repo is split into multiple deployable services plus shared packages, with turbo used to coordinate builds/dev across the monorepo.
2. The frontend lives in apps/frontend and is a Next.js app. It contains the user-facing trading UI: dashboard, markets, orders, positions, admin screens, sign-in/sign-up, and several domain-specific components such as charts, order entry, order books, fills, and balance/deposit/on-ramp views.
3. The frontend does not talk directly to every backend service. It has an API proxy layer under app/api/backend/[...path], an auth route under app/api/auth/[...nextauth], and dedicated client-side state stores for market, account, and websocket state. That makes the browser-facing app a presentation and session layer over the internal backend services.
4. apps/backend is the main HTTP API boundary. Its middleware set shows the core responsibilities: authentication, admin authorization, logging, rate limiting, request validation, and error handling. This service likely exposes the user/account/order/admin APIs consumed by the frontend proxy.
5. apps/engine is the trading core and is the most important backend subsystem. Its source files indicate clear internal domains: order handling, orderbook management, balances, positions, risk checks, liquidations, market-price consumption, replay, hydration, state management, and snapshot/recovery. Architecturally, this is the stateful matching/risk engine that maintains authoritative market and account state.
6. The engine is designed around persistence and recovery rather than being purely in-memory. The snapshot folder and replay/hydrate modules indicate it can rebuild state from stored events or snapshots, which is important for crash recovery, restarts, and deterministic reprocessing.
7. Redis is the main intra-system messaging backbone. There is a shared packages/redis library with client/producer/consumer/stream abstractions, and each service that participates in async processing has its own Redis integration. This suggests Redis Streams or similar queue semantics are used to connect the API, engine, workers, and websocket fanout.
8. Real-time market data and user updates are separated from the HTTP API. apps/ws-gateway is a dedicated websocket service, and the frontend has a ws-provider plus a ws-store, implying the browser subscribes to live feeds through this gateway rather than polling REST endpoints.
9. Background processing is split into workers. apps/price-worker likely ingests external market prices into the system, while apps/db-worker appears to consume event streams and apply durable writes or projections into the database. This keeps the core engine and API responsive while persistence and market-data ingestion happen asynchronously.
10. packages/db is the database boundary, built with Prisma and backed by migrations and seed data. Its schema evolves around the trading domain: markets, orders, positions, closed positions, on-ramp, realized PnL, and timestamps. That makes the database a system-of-record for durable business entities and reporting, not the engine’s primary execution store.
11. Shared code is centralized in packages/common, which holds constants and types used across services. This reduces schema drift between the frontend, API, engine, and workers, especially for domain objects like markets, orders, and account-related payloads.
12. Infrastructure-wise, the repo is structured for multiple long-running services plus a database and Redis, with Docker Compose present at the root. The practical runtime boundary is: browser → Next.js frontend → backend API → engine/Redis/db worker, with websocket updates flowing separately through the gateway and persistent state flowing into Postgres via Prisma-backed writes.
Main entry points: engine Engine · frontend Frontend · package.json Turbo repo · backend API backend
Components 18
Apps
Deployable services and the browser app.
- Frontend · User-facing trading UI with dashboard, markets, orders, positions, admin, auth, and real-time views.
apps/frontend - App routes · Dashboard pages plus backend/auth proxy routes.
apps/frontend/app - Trading UI · Charts, order entry, books, fills, balances, deposits, and admin panels.
apps/frontend/components - Client state · Market, account, and websocket state kept in the browser.
apps/frontend/stores - API backend · Main authenticated API boundary with validation, logging, rate limits, and admin controls.
apps/backend - Middleware stack · Auth, admin checks, validation, logging, rate limiting, and error handling.
apps/backend/middlewares - Engine · Stateful matching, risk, balances, positions, liquidation, replay, and recovery subsystem.
apps/engine - Orders & book · Order handling and orderbook management.
apps/engine/src/orderbook.ts - Risk & liq · Risk checks and liquidation logic.
apps/engine/src/risk.ts - Engine state · Balances, positions, and authoritative runtime state.
apps/engine/src/state.ts - Recovery · Hydration, replay, snapshot creation, and crash recovery.
apps/engine/src/snapshot - WS gateway · Dedicated websocket fanout for live market and account updates.
apps/ws-gateway - Price worker · Ingests external market prices into the system.
apps/price-worker - DB worker · Consumes streams and applies durable database writes or projections.
apps/db-worker
Packages
Shared libraries and platform boundaries.
- Common types · Shared constants and types used across services.
packages/common - Redis bus · Shared Redis client, producer, consumer, and stream abstractions for async coordination.
packages/redis - Database · Durable system-of-record for markets, orders, positions, on-ramp, and reporting.
packages/db - Turbo repo · Coordinates builds and dev workflows across apps and packages.
package.json
Connections 29
- Turbo repo → Frontend: build/dev · Coordinates frontend tasks.
- Turbo repo → API backend: build/dev · Coordinates backend tasks.
- Turbo repo → Engine: build/dev · Coordinates engine tasks.
- Turbo repo → WS gateway: build/dev · Coordinates websocket gateway tasks.
- Turbo repo → Price worker: build/dev · Coordinates price worker tasks.
- Turbo repo → DB worker: build/dev · Coordinates db worker tasks.
- Frontend → App routes: serves · Pages and API proxy/auth routes.
- Frontend → Trading UI: renders · Trading and account UI components.
- Frontend → Client state: uses · Client-side market/account/ws state.
- App routes → API backend: proxy/API · Browser requests are forwarded to backend services.
- API backend → Middleware stack: guards · Applies auth, validation, logging, and rate limiting.
- API backend → Engine: orchestrates · Main API boundary for trading and account actions.
- API backend → Redis bus: publishes/consumes · Uses async messaging for coordination.
- Engine → Orders & book: manages · Matching and orderbook state.
- Engine → Risk & liq: checks · Risk and liquidation decisions.
- Engine → Engine state: tracks · Balances, positions, and runtime state.
- Engine → Recovery: persists/rebuilds · Snapshot, replay, hydrate, and recovery.
- Engine → Redis bus: streams · Consumes and emits events over Redis.
- Engine → Database: projects · Writes durable trading records and reports.
- WS gateway → Redis bus: subscribes · Fans out live updates from the event bus.
- Price worker → Redis bus: ingests · Publishes external price data into streams.
- DB worker → Redis bus: consumes · Reads event streams for persistence/projections.
- DB worker → Database: writes · Applies durable writes to Postgres.
- API backend → Common types: shares contracts · Uses shared types and constants.
- Engine → Common types: shares contracts · Uses shared domain types.
- Frontend → Common types: shares contracts · Uses shared domain types.
- Database → Common types: shares contracts · Uses shared domain types.
- Frontend → WS gateway: live updates · Browser subscribes to websocket feeds.
- Frontend → Database: reads durable data · Loads persisted markets, orders, positions, and account data.