Backend Overview
Location:apps/backend/Runtime: Node.js 20 LTS
Framework: Express.js
Database: PostgreSQL 16 via Prisma ORM
Queue: BullMQ + Redis The backend serves two roles:
REST API
Exposes vault, analytics, and leaderboard data to the frontend via Express.js routes on port
4000.BullMQ Workers
Consume jobs from Redis queues produced by the indexer and persist results to PostgreSQL.
Entry Point
apps/backend/src/index.ts bootstraps the Express server and imports all workers:
Data Models (Prisma)
Defined inpackages/db/prisma/schema.prisma:
User
| Field | Type | Notes |
|---|---|---|
id | String | UUID primary key |
walletAddress | String | Unique, checksummed EVM address |
argusScore | Int | Reputation score from Argus Engine (default 0) |
vaultsLed | Vault[] | Vaults this user leads |
subscriptions | FollowerSubscription[] | Vaults this user follows |
Vault
| Field | Type | Notes |
|---|---|---|
id | String | UUID primary key |
contractAddress | String | Unique, on-chain proxy address |
leaderId | String | FK → User.id |
name | String | Vault display name |
baseAsset | String | ERC-20 address for deposits |
tvl | String | Total value locked (stored as string for BigInt safety) |
roi | Float | Return on investment % |
drawdown | Float | Maximum drawdown % |
riskScore | Int | Argus-derived risk score |
status | Enum | ACTIVE | PAUSED | LIQUIDATED |
createdAt | DateTime | Vault creation timestamp |
Trade
| Field | Type | Notes |
|---|---|---|
id | String | UUID primary key |
txHash | String | Unique, on-chain transaction hash |
vaultId | String | FK → Vault.id |
assetIn | String | Token sold (ERC-20 address) |
assetOut | String | Token received (ERC-20 address) |
amountIn | String | Amount of assetIn (BigInt string) |
amountOut | String | Amount of assetOut (BigInt string) |
isProfit | Boolean | Whether this trade closed profitably |
pnlAmount | String | PnL amount (BigInt string) |
executedAt | DateTime | Block timestamp |
FollowerSubscription
| Field | Type | Notes |
|---|---|---|
id | String | UUID primary key |
vaultId | String | FK → Vault.id |
userId | String | FK → User.id |
depositedAmount | String | Current deposited balance (BigInt string) |
subscribedAt | DateTime | First subscription timestamp |
@@unique([vaultId, userId])
Worker Architecture
The workers run inside the same backend process. They are imported byworkers/index.ts which is itself imported in index.ts.
Configuration
apps/backend/src/config/redis.ts — ioredis connection shared by all workers: