# bhupeshv29/perps-exchange-platform architecture

> Architecture diagram of the GitHub repository bhupeshv29/perps-exchange-platform, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-06-21). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/bhupeshv29/perps-exchange-platform
- Repository: https://github.com/bhupeshv29/perps-exchange-platform

## Overview

1. This is a monorepo for a simplified perpetual futures exchange. The system is split into independently deployed services: a Next.js frontend, an HTTP backend API, a matching engine, a DB worker, a WebSocket gateway, and a price worker. Shared packages provide common market math, Redis helpers, database access, UI components, and config.

2. The frontend lives in `apps/frontend` and is the user-facing trading app. It uses Next.js app routes, NextAuth-style auth plumbing, TanStack/React Query-style data fetching, local state stores, and a WebSocket layer for realtime market/account updates. The trade page is composed from specialized panels for order entry, depth, fills, positions, balances, and history.

3. The backend in `apps/backend` is the request gateway for authenticated REST actions such as account, auth, market, and order operations. Its key role is orchestration: validate input, authenticate the user, publish a request into Redis, wait for the engine response, and return the HTTP result. It does not own balances, positions, orders, or orderbook state.

4. The matching engine in `apps/engine` is the source of truth for trading state. It keeps balances, orders, orderbooks, positions, and mark prices in memory, performs order matching with price-time priority, computes fills and PnL, handles liquidation, and generates depth updates. It also persists periodic snapshots to disk for recovery after restart.

5. The engine receives inputs from two Redis-backed channels: trading requests and price updates. Requests come from the backend through Redis Streams; mark price updates come from the price worker through another stream. After applying state transitions, the engine emits two kinds of outputs: durable events for database persistence and realtime events for user/client updates.

6. Persistence is isolated in `apps/dbWorker`. That service consumes engine-generated database events from Redis Streams and writes them to PostgreSQL via Prisma. The schema layer in `packages/db` defines the relational history the platform keeps, such as users, balances, orders, fills, and closed positions. Notably, open positions are not stored in Postgres; they exist only in the engine’s runtime state.

7. Realtime fanout is handled by `apps/wsGateway`. It subscribes to Redis Pub/Sub events produced by the engine and broadcasts them over WebSocket to connected clients. The gateway also authenticates socket connections using a JWT cookie and attaches a user identity so it can distinguish private events from market-wide events.

8. The price worker in `apps/priceWorker` is the external market-data ingress for mark-price updates. Its output is fed into Redis Streams and consumed by the engine for liquidation and unrealized PnL calculations. This worker is part of the risk loop because it drives the engine’s view of current market value.

9. Redis is the core integration backbone. Streams are used for ordered, reliable processing between services: engine requests, engine responses, DB events, and price updates. Pub/Sub is used only for low-latency websocket fanout. The architecture intentionally separates these two patterns so critical state changes are durable while UI updates stay fast.

10. The shared packages define the common contract surface. `packages/common` contains market utilities, constants, formatting, and stream/type helpers; `packages/redis` centralizes Redis client and stream/pubsub primitives; `packages/ui` provides reusable frontend components; `packages/eslint-config` and `packages/typescript-config` standardize tooling across apps.

11. The main business flow is: frontend submits an order or account action to the backend, backend writes a request to Redis, engine consumes it and mutates trading state, engine emits persistence and websocket events, DB worker writes history to Postgres, and WebSocket gateway pushes live updates back to subscribed clients. This is the central architecture boundary: the engine owns live state, while the other services are thin adapters around it.

12. Startup recovery is a first-class concern. The engine periodically snapshots its in-memory state to a local file and reloads that snapshot on restart before resuming stream consumption. That means the system can recover trading state without reconstructing open orders or positions solely from the database.

13. Deployment is containerized per service. Each app has its own production Dockerfile, with a root `docker-compose` setup for local or production-style orchestration. The repo also includes docs for installation and e2e testing, which suggests the system is intended to be run as a multi-process distributed exchange rather than a single web server.

Main entry points: [`apps/engine`](https://github.com/bhupeshv29/perps-exchange-platform/tree/main/apps/engine) (Engine), [`apps/backend`](https://github.com/bhupeshv29/perps-exchange-platform/tree/main/apps/backend) (Backend API), [`packages/redis`](https://github.com/bhupeshv29/perps-exchange-platform/tree/main/packages/redis) (Redis pkg), [`packages/common`](https://github.com/bhupeshv29/perps-exchange-platform/tree/main/packages/common) (Common)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_apps["Apps"]
  node_frontend["Frontend<br/>Next.js trading app"]
  node_frontend_trade["Trade page<br/>Trading UI<br/>[page.tsx]"]
  node_frontend_providers["Providers<br/>React context"]
  node_frontend_ws["WebSocket layer<br/>client realtime"]
  node_backend["Backend API<br/>HTTP gateway"]
  node_backend_routes["API routes<br/>REST endpoints"]
  node_backend_middleware["Middleware<br/>auth/validation"]
  node_backend_redis["Backend Redis<br/>redis client<br/>[redis.ts]"]
  node_engine["Engine<br/>matching core"]
  node_engine_state["State core<br/>runtime state<br/>[state.ts]"]
  node_engine_match["Matching<br/>price-time matcher<br/>[match.ts]"]
  node_engine_publish["Publishers<br/>event emitters"]
  node_engine_snapshot["Snapshots<br/>recovery"]
  node_dbworker["DB worker<br/>persistence worker"]
  node_wsgateway["WS gateway<br/>websocket server"]
  node_priceworker["Price worker<br/>price ingress"]
end

subgraph group_packages["Shared packages"]
  node_db_schema["DB schema<br/>prisma schema<br/>[schema.prisma]"]
  node_common["Common<br/>shared market utils"]
  node_redis_pkg["Redis pkg<br/>shared redis helpers"]
  node_ui["UI kit<br/>shared components"]
end

node_frontend -->|"uses"| node_frontend_providers
node_frontend_providers -->|"includes"| node_frontend_ws
node_frontend -->|"renders"| node_frontend_trade
node_frontend_trade -->|"uses"| node_ui
node_frontend_trade -->|"calls"| node_backend
node_backend -->|"exposes"| node_backend_routes
node_backend -->|"wraps"| node_backend_middleware
node_backend -->|"publishes"| node_backend_redis
node_backend_redis -->|"uses"| node_redis_pkg
node_engine -->|"owns"| node_engine_state
node_engine -->|"matches"| node_engine_match
node_engine -->|"emits"| node_engine_publish
node_engine -->|"recovers"| node_engine_snapshot
node_engine -->|"uses"| node_common
node_engine -->|"uses"| node_redis_pkg
node_engine -->|"consumes prices from"| node_priceworker
node_backend -.->|"request loop"| node_engine
node_dbworker -->|"consumes"| node_engine_publish
node_dbworker -->|"writes"| node_db_schema
node_dbworker -->|"uses"| node_redis_pkg
node_wsgateway -->|"subscribes"| node_engine_publish
node_wsgateway -->|"uses"| node_redis_pkg
node_wsgateway -->|"feeds"| node_frontend_ws
node_priceworker -->|"publishes"| node_redis_pkg
node_priceworker -.->|"drives risk"| node_engine
node_common -.->|"shared by"| node_backend
node_common -.->|"shared by"| node_frontend
node_common -.->|"shared by"| node_engine

click node_frontend "https://github.com/bhupeshv29/perps-exchange-platform/tree/main/apps/frontend"
click node_frontend_trade "https://github.com/bhupeshv29/perps-exchange-platform/blob/main/apps/frontend/app/trade/[marketId]/page.tsx"
click node_frontend_providers "https://github.com/bhupeshv29/perps-exchange-platform/tree/main/apps/frontend/providers"
click node_frontend_ws "https://github.com/bhupeshv29/perps-exchange-platform/blob/main/apps/frontend/providers/WebSocketProvider.tsx"
click node_backend "https://github.com/bhupeshv29/perps-exchange-platform/tree/main/apps/backend"
click node_backend_routes "https://github.com/bhupeshv29/perps-exchange-platform/tree/main/apps/backend/src/routes"
click node_backend_middleware "https://github.com/bhupeshv29/perps-exchange-platform/tree/main/apps/backend/src/middleware"
click node_backend_redis "https://github.com/bhupeshv29/perps-exchange-platform/blob/main/apps/backend/src/redis.ts"
click node_engine "https://github.com/bhupeshv29/perps-exchange-platform/tree/main/apps/engine"
click node_engine_state "https://github.com/bhupeshv29/perps-exchange-platform/blob/main/apps/engine/src/state/state.ts"
click node_engine_match "https://github.com/bhupeshv29/perps-exchange-platform/blob/main/apps/engine/src/orderbook/match.ts"
click node_engine_publish "https://github.com/bhupeshv29/perps-exchange-platform/tree/main/apps/engine/src/publish"
click node_engine_snapshot "https://github.com/bhupeshv29/perps-exchange-platform/tree/main/apps/engine/src/snapshot"
click node_dbworker "https://github.com/bhupeshv29/perps-exchange-platform/tree/main/apps/dbWorker"
click node_db_schema "https://github.com/bhupeshv29/perps-exchange-platform/blob/main/packages/db/prisma/schema.prisma"
click node_wsgateway "https://github.com/bhupeshv29/perps-exchange-platform/tree/main/apps/wsGateway"
click node_priceworker "https://github.com/bhupeshv29/perps-exchange-platform/tree/main/apps/priceWorker"
click node_common "https://github.com/bhupeshv29/perps-exchange-platform/tree/main/packages/common"
click node_redis_pkg "https://github.com/bhupeshv29/perps-exchange-platform/tree/main/packages/redis"
click node_ui "https://github.com/bhupeshv29/perps-exchange-platform/tree/main/packages/ui"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_frontend,node_frontend_trade,node_frontend_providers,node_frontend_ws,node_backend,node_backend_routes,node_backend_middleware,node_backend_redis,node_engine,node_engine_state,node_engine_match,node_engine_publish,node_engine_snapshot,node_dbworker,node_wsgateway,node_priceworker toneBlue
class node_db_schema,node_common,node_redis_pkg,node_ui toneAmber
```

## Components

### Apps

Deployable services that make up the exchange

- [Frontend](https://github.com/bhupeshv29/perps-exchange-platform/tree/main/apps/frontend): Next.js trading app · User-facing trading interface with routes, data fetching, local state, and realtime updates · `apps/frontend`
- [Trade page](https://github.com/bhupeshv29/perps-exchange-platform/blob/main/apps/frontend/app/trade/[marketId]/page.tsx): Trading UI · Composed view for entering orders and monitoring market/account state · `apps/frontend/app/trade/[marketId]/page.tsx`
- [Providers](https://github.com/bhupeshv29/perps-exchange-platform/tree/main/apps/frontend/providers): React context · Wires query, websocket, market, and account state for the frontend · `apps/frontend/providers`
- [WebSocket layer](https://github.com/bhupeshv29/perps-exchange-platform/blob/main/apps/frontend/providers/WebSocketProvider.tsx): client realtime · Client-side subscription and event handling for live market and account updates · `apps/frontend/providers/WebSocketProvider.tsx`
- [Backend API](https://github.com/bhupeshv29/perps-exchange-platform/tree/main/apps/backend): HTTP gateway · Authenticated REST orchestration layer that forwards requests into Redis and returns engine results · `apps/backend`
- [API routes](https://github.com/bhupeshv29/perps-exchange-platform/tree/main/apps/backend/src/routes): REST endpoints · Account, auth, market, and order request handlers · `apps/backend/src/routes`
- [Middleware](https://github.com/bhupeshv29/perps-exchange-platform/tree/main/apps/backend/src/middleware): auth/validation · Auth, rate limiting, validation, and error handling around HTTP requests · `apps/backend/src/middleware`
- [Backend Redis](https://github.com/bhupeshv29/perps-exchange-platform/blob/main/apps/backend/src/redis.ts): redis client · Publishes trading requests and waits for loopback responses · `apps/backend/src/redis.ts`
- [Engine](https://github.com/bhupeshv29/perps-exchange-platform/tree/main/apps/engine): matching core · Source of truth for balances, orders, orderbooks, positions, matching, liquidation, and snapshots · `apps/engine`
- [State core](https://github.com/bhupeshv29/perps-exchange-platform/blob/main/apps/engine/src/state/state.ts): runtime state · In-memory balances, orders, positions, orderbooks, and mark prices · `apps/engine/src/state/state.ts`
- [Matching](https://github.com/bhupeshv29/perps-exchange-platform/blob/main/apps/engine/src/orderbook/match.ts): price-time matcher · Executes order matching and depth updates · `apps/engine/src/orderbook/match.ts`
- [Publishers](https://github.com/bhupeshv29/perps-exchange-platform/tree/main/apps/engine/src/publish): event emitters · Produces durable DB events and realtime websocket events after state transitions · `apps/engine/src/publish`
- [Snapshots](https://github.com/bhupeshv29/perps-exchange-platform/tree/main/apps/engine/src/snapshot): recovery · Loads and saves engine state snapshots for restart recovery · `apps/engine/src/snapshot`
- [DB worker](https://github.com/bhupeshv29/perps-exchange-platform/tree/main/apps/dbWorker): persistence worker · Consumes engine persistence events and writes exchange history to PostgreSQL · `apps/dbWorker`
- [WS gateway](https://github.com/bhupeshv29/perps-exchange-platform/tree/main/apps/wsGateway): websocket server · Authenticates socket clients and fans out realtime events from Redis Pub/Sub · `apps/wsGateway`
- [Price worker](https://github.com/bhupeshv29/perps-exchange-platform/tree/main/apps/priceWorker): price ingress · Feeds external mark-price updates into Redis Streams for engine risk and PnL calculations · `apps/priceWorker`

### Shared packages

Cross-cutting contracts and libraries

- [DB schema](https://github.com/bhupeshv29/perps-exchange-platform/blob/main/packages/db/prisma/schema.prisma): prisma schema · Relational history for users, balances, orders, fills, and closed positions · `packages/db/prisma/schema.prisma`
- [Common](https://github.com/bhupeshv29/perps-exchange-platform/tree/main/packages/common): shared market utils · Shared market math, constants, formatting, and stream/type helpers · `packages/common`
- [Redis pkg](https://github.com/bhupeshv29/perps-exchange-platform/tree/main/packages/redis): shared redis helpers · Centralized Redis client, stream, and pubsub primitives · `packages/redis`
- [UI kit](https://github.com/bhupeshv29/perps-exchange-platform/tree/main/packages/ui): shared components · Reusable frontend UI components · `packages/ui`

## Connections

- Frontend → Providers: uses · Frontend composition depends on shared providers and app-level state
- Providers → WebSocket layer: includes · WebSocket provider supplies realtime transport to the app
- Frontend → Trade page: renders · Trade route assembles the main trading workspace
- Trade page → UI kit: uses · Trading UI reuses shared visual components
- Trade page → Backend API: calls · User actions and queries go through the backend API
- Backend API → API routes: exposes · Route modules define the REST surface
- Backend API → Middleware: wraps · Requests are authenticated, validated, and rate-limited
- Backend API → Backend Redis: publishes · Backend sends authenticated commands into Redis
- Backend Redis → Redis pkg: uses · Backend relies on shared Redis primitives
- Engine → State core: owns · Engine maintains live trading state in memory
- Engine → Matching: matches · Order matching updates books, fills, and depth
- Engine → Publishers: emits · State transitions produce persistence and realtime events
- Engine → Snapshots: recovers · Snapshots are saved and restored across restarts
- Engine → Common: uses · Engine shares market math and stream contracts
- Engine → Redis pkg: uses · Engine consumes and publishes through Redis helpers
- Engine → Price worker: consumes prices from · Mark-price updates arrive from the price worker stream
- Backend API → Engine: request loop · HTTP actions are forwarded to engine and responses loop back
- DB worker → Publishers: consumes · Database worker persists engine-generated durable events
- DB worker → DB schema: writes · Prisma schema defines stored exchange history
- DB worker → Redis pkg: uses · DB worker listens on Redis streams
- WS gateway → Publishers: subscribes · Gateway receives realtime events from Redis Pub/Sub
- WS gateway → Redis pkg: uses · WebSocket server shares Redis client and pubsub helpers
- WS gateway → WebSocket layer: feeds · Broadcast events are delivered to connected clients
- Price worker → Redis pkg: publishes · Price updates are written into Redis Streams
- Price worker → Engine: drives risk · Mark prices affect liquidation and unrealized PnL
- Common → Backend API: shared by · Backend uses shared contracts and utilities
- Common → Frontend: shared by · Frontend uses shared market helpers and helpers
- Common → Engine: shared by · Engine uses common market math and stream helpers
