We want:


update .env file (environment variables)

DATABASE_URL="postgresql://devarena:supersecretpassword@localhost:5432/devarenadb?schema=public"
JWT_ACCESS_SECRET=
JWT_REFRESH_SECRET=
RESEND_API_KEY = 
ACCESS_TOKEN_EXPIRY=15m
REFRESH_TOKEN_EXPIRY=7d
OTP_TTL_SECONDS=120
OTP_MAX_ATTEMPTS=5
NODE_ENV=development
PORT = 5000
REDIS_URL=redis://default:supersecret@redis:6379
EMAIL_FROM ='devArena <team@company.in>'

POSTGRES_USER=devarena
POSTGRES_PASSWORD=supersecretpassword
POSTGRES_DB=devarenadb
POSTGRES_PORT=5432

REDIS_PORT=6379

We’ll inject these into our containers safely.


Step 3: The docker-compose.yml

Here’s a clean, CTO-grade compose setup:

version: '3.9'

services:
  postgres:
    image: postgres
    container_name: devarena_postgres
    restart: unless-stopped
    env_file:
      - .env
    environment:
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: ${POSTGRES_DB}
    ports:
      - "${POSTGRES_PORT}:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"]
      interval: 10s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7-alpine
    container_name: devarena_redis
    restart: unless-stopped
    ports:
      - "${REDIS_PORT}:6379"
    command: ["redis-server", "--requirepass", "supersecret", "--save", "", "--appendonly", "no"]
    # 'save' and 'appendonly no' ensures pure in-memory mode for OTPs
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  postgres_data:
  redis_data:


🧠 Step 4: Understanding the setup (CTO-level reasoning)

Component Why it’s configured this way
restart: unless-stopped Ensures containers reboot automatically on crash.
postgres:16-alpine Lightweight, secure, latest stable Postgres.
volumes Keeps Postgres data persistent across container restarts.
redis:7-alpine Latest Redis with minimal footprint.
--save "", --appendonly no Prevents Redis from persisting data — OTPs should die in memory.
healthcheck Lets other services (like backend) wait until DB/Redis are “healthy.”

🧩 Step 5: Starting the services

Run:

docker-compose up -d