# {{projectName}} full-stack PROD docker compose.
#
# Builds locked images per app via docker/{api,web}.Dockerfile and
# runs them behind Postgres. No source volumes — each app's code is
# baked in at image-build time. Use this to smoke-test prod config
# locally before deploying.
#
# This is NOT the production deploy target itself — that's helm or
# your cloud provider's container runtime. This file gives parity
# checking on localhost.
#
# Run:
#   pnpm prod:build              # build all images (slow, ~5 min)
#   pnpm prod:up                 # boot the stack
#   pnpm prod:down               # tear down
#
# Different DB user from dev so accidental `pnpm db:reset` against
# the dev compose doesn't wipe a prod-shape dataset you wanted to
# poke at.

services:
  postgres:
    image: postgres:17-alpine
    container_name: {{projectName}}-postgres-prod
    restart: unless-stopped
    environment:
      POSTGRES_USER: {{projectNameSnake}}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-change-me-in-prod}
      POSTGRES_DB: {{projectNameSnake}}
    ports:
      - "5434:5432"
    command:
      - "postgres"
      - "-c"
      - "wal_level=logical"
      - "-c"
      - "max_wal_senders=4"
      - "-c"
      - "max_replication_slots=4"
    volumes:
      - {{projectName}}-prod-pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U {{projectNameSnake}} -d {{projectNameSnake}}"]
      interval: 5s
      timeout: 3s
      retries: 20

  api:
    build:
      context: ./
      dockerfile: docker/api.Dockerfile
      target: prod
      args:
        APP_PATH: apps/{{projectName}}/api
    image: {{projectName}}-api:latest
    container_name: {{projectName}}-api
    restart: unless-stopped
    environment:
      NODE_ENV: production
      DB_URL: postgres://{{projectNameSnake}}:${POSTGRES_PASSWORD:-change-me-in-prod}@postgres:5432/{{projectNameSnake}}
      VOLTRO_SESSION_SECRET: ${VOLTRO_SESSION_SECRET:?must be set for prod compose}
      # Only needed once an app turns on a plugin that encrypts columns at rest
      # (`governance` with `fieldEncryption`, or any `.encrypted()` column). It
      # is commented out because a generated file cannot know which plugins you
      # will enable — and left here, named, because the alternative is finding
      # out at `onActivate` in a container:
      #
      #   governance: fieldEncryption is enabled but secret
      #   "VOLTRO_FIELD_ENCRYPTION_KEY" did not resolve
      #
      # Mint it with `voltro secret generate field-encryption` — same shape as
      # `openssl rand -hex 32`, but it is the documented path and it cannot
      # produce the wrong length. LOSE THE KEY, LOSE THE DATA: there is no
      # recovery for a column encrypted under a key you no longer have, so back
      # it up wherever you keep the session secret.
      # VOLTRO_FIELD_ENCRYPTION_KEY: ${VOLTRO_FIELD_ENCRYPTION_KEY:?must be set once fieldEncryption is on}
    ports:
      - "4000:4000"
    depends_on:
      postgres:
        condition: service_healthy

  web:
    build:
      context: ./
      dockerfile: docker/web.Dockerfile
      target: prod
      args:
        APP_PATH: apps/{{projectName}}/web
        APP_PORT: "5173"
    image: {{projectName}}-web:latest
    container_name: {{projectName}}-web
    restart: unless-stopped
    environment:
      NODE_ENV: production
    ports:
      - "5173:5173"
    depends_on:
      - api

volumes:
  {{projectName}}-prod-pgdata:
