Deployment Guide
Last Updated: April 2026
Prerequisites
| Tool | Version | Purpose |
|---|---|---|
| Go | 1.26+ | Compile the service binary |
| Docker | 24+ | Container images |
| kind | 0.20+ | Local Kubernetes cluster |
| ctlptl | 0.8+ | Declarative cluster management |
| Tilt | 0.33+ | Live development environment |
| Atlas | latest | Database migration tooling |
Environment Variables Reference
All configuration uses the BATTLESBIT_ prefix. Nested keys use double underscores (__) as separators.
HTTP / API
| Variable | Default | Description |
|---|---|---|
BATTLESBIT_HTTP__HOST | 0.0.0.0 | Listen address |
BATTLESBIT_HTTP__PORT | 8888 | Listen port |
BATTLESBIT_HTTP__ALLOWED_ORIGINS | * | CORS allowed origins (comma-separated). Restrict in production. |
BATTLESBIT_HTTP__RATE_LIMIT | 20 | Max requests per window |
BATTLESBIT_HTTP__RATE_LIMIT_WINDOW | 1s | Rate limit window |
BATTLESBIT_HTTP__DEBUG | false | Enable debug mode |
BATTLESBIT_HTTP__BASE_URL | "" | Public base URL |
BATTLESBIT_HTTP__GQL__PLAYGROUND | true | Enable GraphQL playground |
BATTLESBIT_HTTP__GQL__INTROSPECTION | true | Enable introspection |
BATTLESBIT_HTTP__GQL__COMPLEXITY_LIMIT | 100 | Max query complexity |
Database
| Variable | Default | Description |
|---|---|---|
BATTLESBIT_DATABASE__URI | postgresql://postgres:postgres@localhost:5432/postgres?sslmode=disable | PostgreSQL connection string |
BATTLESBIT_DATABASE__DEBUG | false | Log all SQL queries |
BATTLESBIT_DATABASE__AUTO_MIGRATE | true | Run migrations on startup |
BATTLESBIT_DATABASE__MAX_OPEN_CONNS | 10 | Max open connections |
BATTLESBIT_DATABASE__MAX_IDLE_CONNS | 5 | Max idle connections |
Authentication / JWT
| Variable | Default | Description |
|---|---|---|
BATTLESBIT_JWT__SIGNING_KEY | beryberysecret | JWT HMAC signing key. Must change in production. |
BATTLESBIT_JWT__ACCESS_DURATION | 168h | Token validity period |
BATTLESBIT_JWT__DEV_LOGIN | false | Allow passwordless login (dev only) |
Cache (Redis)
| Variable | Default | Description |
|---|---|---|
BATTLESBIT_CACHES__REDIS__ADDRS | localhost:6379 | Redis addresses |
BATTLESBIT_CACHES__REDIS__PASSWORD | redis | Redis password |
NATS JetStream
| Variable | Default | Description |
|---|---|---|
BATTLESBIT_NATS__URI | nats://nats:nats@localhost:4222 | NATS server URI |
Monitoring
| Variable | Default | Description |
|---|---|---|
BATTLESBIT_MONITORING__PROMETHEUS_ENABLED | true | Expose Prometheus metrics |
BATTLESBIT_MONITORING__METRICS_PATH | /metrics | Metrics endpoint path |
BATTLESBIT_MONITORING__SENTRY_DSN | "" | Sentry DSN for error tracking |
BATTLESBIT_MONITORING__SENTRY_TRACING | true | Enable Sentry performance tracing |
Market Data (Binance)
| Variable | Default | Description |
|---|---|---|
BATTLESBIT_MARKET__BINANCE__API_URL | https://api.binance.com/api/v3 | Binance REST API URL |
BATTLESBIT_MARKET__BINANCE__WS_URL | wss://fstream.binance.com | Binance WebSocket URL |
BATTLESBIT_MARKET__BINANCE__TIMEOUT | 10s | HTTP timeout |
BATTLESBIT_MARKET__BINANCE__ASSETS | BTCUSDT,ETHUSDT,... | Subscribed trading pairs |
Solana / HD Wallet
| Variable | Default | Description |
|---|---|---|
BATTLESBIT_SOLANA__ENDPOINT | https://api.testnet.solana.com | Solana RPC endpoint |
BATTLESBIT_HDWALLET__MASTER_SEED_PHRASE | (dev seed) | CRITICAL: Store in KMS/Vault in production. |
Email (SMTP)
| Variable | Default | Description |
|---|---|---|
BATTLESBIT_EMAIL__HOST | smtp.hostinger.com | SMTP host |
BATTLESBIT_EMAIL__PORT | 465 | SMTP port |
BATTLESBIT_EMAIL__USERNAME | noreply@battlesbit.com | SMTP username |
BATTLESBIT_EMAIL__PASSWORD | "" | SMTP password |
Object Storage (S3)
| Variable | Default | Description |
|---|---|---|
BATTLESBIT_S3__ENDPOINT | s3.ir-thr-at1.arvanstorage.ir | S3-compatible endpoint |
BATTLESBIT_S3__BUCKET | battlesbit | Bucket name |
BATTLESBIT_S3__ACCESS_KEY | (placeholder) | S3 access key |
BATTLESBIT_S3__SECRET_KEY | (placeholder) | S3 secret key |
Firebase
| Variable | Default | Description |
|---|---|---|
BATTLESBIT_FIREBASE__CREDENTIALS_FILE | path_to_file.json | Firebase service account credentials |
Database Migration Strategy
Migrations are managed via Ent + Atlas.
Before deploying a new version
# Run migrations against the target database
go run . migrateThe service also supports auto_migrate: true (default), which runs migrations on startup. For production, it is safer to run migrations as a separate pre-deploy step:
- Build the binary
- Run
./service migrateas a Kubernetes Job before rolling out the new Deployment - Set
BATTLESBIT_DATABASE__AUTO_MIGRATE=falseon the running service pods
Rolling back a migration
# Atlas CLI rollback
atlas migrate down --env production
# If Atlas is unavailable, apply manual SQL
psql $DATABASE_URL < rollback.sqlService Scaling Guidance
Stateless services (scale horizontally)
| Service | Notes |
|---|---|
cmd/web (GraphQL API) | Standard HTTP service. Scale with HPA on CPU/request latency. |
| Arena Worker | Processes positions via NATS pull consumers. Multiple replicas safe with same durable name. |
| Withdrawal Worker | Processes withdrawals via NATS pull consumers. Constrained by Solana RPC rate limits. |
| Achievement Worker | Processes achievement events via NATS. Multiple replicas with same durable name. |
Stateful services (scale with care)
| Service | Notes |
|---|---|
| PostgreSQL | Use managed Postgres (RDS, CloudSQL). Scaling requires read replicas or sharding. |
| NATS | Run as a NATS cluster (3+ nodes recommended). |
| Redis | Run as a Redis cluster or managed service. |
NATS JetStream Consumer Scaling
Multiple replicas of the same worker can consume from the same stream using the same durable consumer name. NATS will distribute messages across consumers automatically (pull-based load balancing).
Worker-1 ─┐
Worker-2 ─┤── Pull from "POSITIONS" stream, consumer "arena-worker"
Worker-3 ─┘Secret Management
Production secrets that MUST be secured
| Secret | Recommended Storage |
|---|---|
HDWALLET__MASTER_SEED_PHRASE | AWS KMS, HashiCorp Vault, or GCP Secret Manager |
JWT__SIGNING_KEY | Kubernetes Secret or Vault |
DATABASE__URI | Kubernetes Secret or Vault |
EMAIL__PASSWORD | Kubernetes Secret |
S3__SECRET_KEY | Kubernetes Secret |
FIREBASE__CREDENTIALS_FILE | Mounted secret volume |
The Solana HD wallet seed phrase is the most sensitive secret. In V2, migrate to a proper KMS/Vault integration for key signing operations.
Kubernetes Deployment
Manifest structure
Kubernetes manifests should include:
- Deployment for each service (web, arena, withdrawal, achievement)
- Service (ClusterIP) for internal routing
- Ingress for external HTTPS access
- ConfigMap for non-sensitive configuration
- Secret for credentials
- Job for pre-deploy database migrations
Health checks
The web service exposes:
- Readiness:
GET /healthz - Liveness:
GET /healthz - Metrics:
GET /metrics(Prometheus format)
Monitoring
Prometheus
Metrics are exposed at /metrics when BATTLESBIT_MONITORING__PROMETHEUS_ENABLED=true.
Key metrics to monitor:
- GraphQL operation duration (p50, p95, p99)
- Active WebSocket connections
- NATS consumer lag (messages pending)
- Database connection pool utilization
Sentry
Error tracking is enabled by setting BATTLESBIT_MONITORING__SENTRY_DSN. Performance tracing captures request spans when SENTRY_TRACING=true.
CORS Configuration for Production
The default allowed_origins: ["*"] is permissive for development. In production:
BATTLESBIT_HTTP__ALLOWED_ORIGINS="https://app.battlesbit.com,https://admin.battlesbit.com"Set this to the exact list of frontend origins that should be allowed.