Full system architecture diagram and component inventory
Vezta's backend orchestrates data ingestion from two prediction market exchanges plus crypto price feeds, runs multiple intelligence pipelines, and delivers data to the web frontend via REST and WebSocket APIs.
The backend contains 40+ NestJS modules organized by domain. Each module follows the standard pattern: module.ts, controller.ts, service.ts, dto/, and optionally processor.ts for BullMQ jobs.
In-app conversational AI assistant. SSE token streaming (DeepSeek via an OpenAI-compatible API), an MCP-shaped tool layer + market_intel skill, prompt-injection / funds-leaving safety guards, web search, and rich result cards. Runs on the ai worker domain (agent-request / agent-resume / agent-summarize queues) when FF_AGENT_QUEUE_SPLIT=true, else in-process on the API container
research
Long-form structured market-research pipeline backing the agent (research-request queue, ai domain)
Both environments deploy from ghcr.io/morcalabs/vezta-be-api and ghcr.io/morcalabs/vezta-fe via Docker Compose on self-hosted VMs. Backend production deploys use a promoted-image model — staging builds and tags sha-<sha>, production workflow_dispatch takes that image ref as input (no rebuild). Frontend follows the same pattern. Rollback by re-running the deploy workflow with an older image ref.
Each backend VM runs 9 application containers (1 API + 8 specialized workers) sharing the same ghcr.io/<owner>/vezta-be-api image, plus supporting redis, loki, promtail, and grafana containers:
Container
Role
Memory / CPU
Liveness
vezta-production-api
HTTP API + Socket.IO gateway
1.5 GB / 1.5 CPU
port 3001
vezta-production-worker-traders
Order execution, confirmations, fee collection, copy-trade, sniper, counter-trade, insider-signals
Polymarket CLOB combo / RFQ order catalog + settlement
384 MB / 0.25 CPU
port 3009
Domain ownership is enforced at the provider level: backgroundOnly([Processor, Scheduler], '<domain>') excludes providers from DI on sibling workers (so BullMQ never registers a competing consumer). WS connectors check shouldRunInDomain('<domain>') inside onModuleInit. Rollback by setting WORKER_DOMAIN=all on a single fallback worker.
GCP VPC firewall: only ports 22 / 80 / 443 open to the internet.
Nginx reverse proxy with SSL via Certbot, rate limits (api_general 30r/s, api_auth 5r/s burst 10), CORS map (map $http_origin $cors_origin), 30 conn/IP, 10s body/header timeouts, 2MB body max.
Polymarket CLOB proxy — a dedicated vezta-proxy VM runs Tinyproxy (port 8888) to route CLOB API traffic past geo-restrictions. The proxy address is supplied to the backend via environment variable, never hardcoded.
The production VM has 15 GiB RAM; staging has 8 GiB. Memory-intensive operations like uncapped event fetching or running price-change queries every 60 seconds can exhaust available memory. Critical optimizations (delta-only writes, deferred price-change queries) are in place — do not remove them.