Backend Architecture
NestJS monorepo running on Fastify. Exposes two APIs (dashboard and platform), a cron service, and shared packages for database access, business logic, and utilities.
Project Structure
Code
Dependency Graph
All packages compile to dist/. Consumers import from the compiled output, not source.
Build Pipeline
Each package requires two build steps:
npm run build-- tsup generates.js/.cjs+ barrel.d.ts(re-exports only)npm run build:types--tsc -b .generates individual.d.tsfiles per service/model
Build in dependency order:
Code
{% hint style="warning" %}
Skipping build:types leaves stale type declarations in dist/. Symptom: Property X does not exist on type Y in consumers that reference changed signatures.
{% endhint %}
Controller Pattern
Routes are registered as Fastify plugins. Each route file exports a function that receives the Fastify instance and registers handlers.
Static routes must be registered before parameterized routes. Fastify matches in registration order -- if /:id is registered before /history, the string "history" is captured as a param.
Code
Service Pattern
Services are classes with static methods that use Objection.js models for database access. No dependency injection -- services are imported directly.
Code
Cron Jobs
The cron service runs 12 scheduled jobs:
| Key | Interval | Description |
|---|---|---|
CHECK_JOBS | 1 min | Health check -- ensures other jobs are running |
OPS_BALANCE_UPDATE | 5 min | Updates operational wallet balances from on-chain |
CONTRACT_DATA_COLLECTION | 15 min | Collects contract state (total supply, etc.) |
WALLET_BALANCE_CHECKER | 10 min | Checks wallet balances and flags anomalies |
DAILY_BALANCE_SNAPSHOT | Daily | Records daily balance snapshots for reporting |
WEEKLY_REWARD_PROCESSOR | Wed | Processes staking reward distributions |
PAYMENT_RETRY | 15 min | Retries failed payment transactions |
ORACLE_PRICE_UPDATE | 5 min | Pushes token prices to on-chain oracle contract |
MINTING_TX_SYNC | 2 min | Syncs minting transaction states with BitGo |
BRIDGE_TX_SYNC | 2 min | Syncs bridge transaction states with LayerZero |
UNISWAP_AUTO_REBALANCE | 5 min | Auto-rebalances Uniswap V4 positions when price deviates |
CIRCULATION_SNAPSHOT | Daily | Records circulating supply snapshots per token |
Registering a new cron job requires changes in 3 places:
cron-service/src/jobs/cron-keys.ts-- enum keycron-service/src/jobs/manager.ts-- import + jobHandlers mapdashboard/src/cron-handlers.ts-- handler for on-demand execution from UI
BitGo Integration
Two patterns for sending transactions through BitGo Express:
Pattern 1: Contract Call
Used for oracle updates, Uniswap liquidity operations, and ERC20 approvals. Sends a zero-value transaction with encoded calldata.
Code
Pattern 2: Token Transfer
Used for minting (sending tokens to recipients). Uses the full coin identifier including token suffix.
Code
{% hint style="info" %}
GET endpoints on BitGo use the base coin (e.g., baseeth, polygon) without the token suffix. See getBaseCoin() in bitgo-express.client.ts.
{% endhint %}