This is an early-stage draft. Details will evolve as the system matures.
Vatix Backend is a monorepo of services that together power the Vatix prediction market protocol on Stellar.
┌─────────────┐
HTTP clients ────────▶│ API (src) │
└──────┬──────┘
│ reads/writes
┌──────▼──────┐
│ PostgreSQL │◀──────────────────┐
└──────▲──────┘ │
│ writes │ writes
┌──────┴──────┐ ┌────────┴───────┐
│ Indexer │ │ Workers │
│(apps/indexer│ │(apps/workers) │
└──────┬──────┘ └────────┬───────┘
│ polls │ consumes
┌──────▼──────┐ ┌────────▼───────┐
│ Stellar │ │ Redis │
│ Network │ │ (job queues) │
└─────────────┘ └────────────────┘
▲
┌─────────────┐ │ enqueues
│ Oracle │───────────────────▶│
│(apps/oracle)│
└─────────────┘
| Module | Directory | Responsibility |
|---|---|---|
| API | src/ |
HTTP server (Fastify). Handles order placement, market queries, position reads. Owns the CLOB matching engine. |
| Indexer | apps/indexer/ |
Polls Stellar network for on-chain events, parses them, and writes canonical records to PostgreSQL. |
| Oracle | apps/oracle/ |
Fetches external price/resolution data, signs reports, and submits them on-chain via the Stellar SDK. |
| Workers | apps/workers/ |
Queue consumers and scheduled jobs (e.g. settlement, expiry sweeps). Decoupled from the HTTP request lifecycle. |
All public HTTP routes are mounted under /v1. The canonical positions read is
GET /v1/wallets/:wallet/positions; the older
GET /positions/user/:address root path is a temporary deprecation redirect.
- Client
POST /v1/orders→ API validates and writes order to PostgreSQL - CLOB matching engine runs synchronously; fills are written in the same transaction
- Matched fills are enqueued to Redis for downstream settlement by Workers
The API and Oracle submit asynchronous work into Redis-backed queues that are processed by the Workers service. This submission queue decouples real-time HTTP request handling from downstream settlement and finalization.
Workers consume queue entries and perform background tasks such as trade settlement, expiry sweeps, and resolution candidate processing.
- Oracle fetches external outcome data and signs a resolution report
- Oracle submits the report on-chain (Stellar)
- Indexer detects the on-chain event and writes a
ResolutionCandidateto PostgreSQL - Workers pick up the candidate, apply the challenge window, and settle positions
- The Indexer stores a
ledger_cursorin PostgreSQL (IndexerCursortable) to resume from the last processed ledger after restarts.
- Queue technology: Resolved — BullMQ selected. See docs/adr/001-queue-technology.md. Settlement and oracle submission queues migrated to BullMQ Workers with unified retry/backoff/DLQ config.
- Oracle multi-provider strategy:
fallback-adapter.tsexists but the failover policy (timeout, retry count) is not finalised. - Monorepo build tooling: Services currently share
tsconfig.jsonat the root. Evaluate per-package tsconfigs as the repo grows. - Authentication: Admin routes use a static key guard (
adminGuard.ts). A proper auth layer is needed before public launch. - Workers deployment: resolved — the root
Dockerfiledefinesfinalization-workerandoracle-workerbuild targets, anddocker-compose.ymlruns them under theworkersprofile. No standalone process manager is used; each container runs a single process and relies on Docker/Kubernetes restart policies. See docs/docker-compose.md.
- All services share a single PostgreSQL instance (separate schemas are not used)
- Redis is used exclusively for caching and job queues (no persistence guarantees relied upon)
- Stellar Horizon is the only chain data source; no EVM chains are in scope