services: # ── PostgreSQL ──────────────────────────────────────────────────────────────── db: image: postgres:16-alpine restart: unless-stopped environment: POSTGRES_DB: ${POSTGRES_DB:-lms_db} POSTGRES_USER: ${POSTGRES_USER:-lms_user} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-lms_dev_password} volumes: - postgres_data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-lms_user} -d ${POSTGRES_DB:-lms_db}"] interval: 5s timeout: 5s retries: 10 networks: - lms_net # ── Redis (temp annotation cache) ──────────────────────────────────────────── redis: image: redis:7-alpine restart: unless-stopped command: redis-server --save "" --appendonly no # in-memory only, no disk writes healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 5s timeout: 3s retries: 5 networks: - lms_net # ── FastAPI backend ─────────────────────────────────────────────────────────── backend: image: ${BACKEND_IMAGE:-lms-backend:latest} build: context: ./backend dockerfile: Dockerfile restart: unless-stopped depends_on: db: condition: service_healthy redis: condition: service_healthy environment: DATABASE_URL: postgresql+psycopg2://${POSTGRES_USER:-lms_user}:${POSTGRES_PASSWORD:-lms_dev_password}@db:5432/${POSTGRES_DB:-lms_db} JWT_SECRET_KEY: ${JWT_SECRET_KEY:-lms_dev_jwt_secret_change_in_production} JWT_ALGORITHM: HS256 ACCESS_TOKEN_EXPIRE_MINUTES: ${ACCESS_TOKEN_EXPIRE_MINUTES:-60} UPLOAD_DIR: /uploads REDIS_URL: redis://redis:6379/0 volumes: - pdf_uploads:/uploads expose: - "8000" networks: - lms_net # ── Next.js frontend ────────────────────────────────────────────────────────── frontend: image: ${FRONTEND_IMAGE:-lms-frontend:latest} build: context: ./frontend dockerfile: Dockerfile args: NEXT_PUBLIC_API_URL: http://backend:8000 restart: unless-stopped depends_on: - backend environment: NEXT_PUBLIC_API_URL: http://backend:8000 NODE_ENV: production ports: - "${FRONTEND_PORT:-3000}:3000" networks: - lms_net # ── Volumes ─────────────────────────────────────────────────────────────────── volumes: postgres_data: pdf_uploads: # ── Networks ────────────────────────────────────────────────────────────────── networks: lms_net: driver: bridge