Ctrl K
ComunidadGuías…

docker-compose.dev.yml

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# 로컬 개발용 Docker Compose — R-23 통합 dev stack (Sprint 3-4).
#
# 사용법
#   docker compose -f docker-compose.dev.yml up -d
#   docker compose -f docker-compose.dev.yml down -v   # -v로 volume까지 정리
#
# 무엇을 포함하나 / 무엇을 포함 안 하나
#
#   포함:
#     - server     (apps/server, Hono, tsx-watch)
#     - db         (Postgres 17 — production과 메이저 버전 매칭, gotcha #16)
#     - mock-openai (R-3 E2E용 mock LLM, scripts/mock-openai-server.ts)
#
#   포함 안 함 (의도적):
#     - GoTrue + Kong + Supabase Studio — 로컬은 `supabase start` CLI가
#       표준 (CLAUDE.md "supabase start" 권장). dev compose에서 이 셋을
#       관리하면 supabase CLI와 두 가지 진실의 출처가 됨. CI에서도
#       `supabase start`를 sidecar로 띄우는 게 supabase 팀이 유지하는
#       세팅 그대로라 깨질 일 적음.
#     - web (apps/web)            — `pnpm --filter web dev`로 직접 실행.
#       Next.js dev server는 hot reload + RSC 변경 감지가 컨테이너 외부
#       실행이 훨씬 빠름.
#
# 환경 변수 (.env 또는 export)
#   필수: SUPABASE_URL / SUPABASE_ANON_KEY / SUPABASE_SERVICE_ROLE_KEY /
#         ENCRYPTION_KEY
#   ClickHouse(컨테이너): 아래 service 안에서 자동 설정 (외부 .env 불필요)
#   Mock OpenAI: 자동 (port 4000)

version: '3.9'

services:
  server:
    build:
      context: ./apps/server
      dockerfile: Dockerfile.dev
    ports:
      - '3001:3001'
    environment:
      PORT: 3001
      SUPABASE_URL: ${SUPABASE_URL:-http://supabase-kong:8000}
      SUPABASE_ANON_KEY: ${SUPABASE_ANON_KEY}
      SUPABASE_SERVICE_ROLE_KEY: ${SUPABASE_SERVICE_ROLE_KEY}
      ENCRYPTION_KEY: ${ENCRYPTION_KEY}
      # 로컬 Postgres 직결. Supavisor는 로컬 스택에 없으므로 pooler 대신
      # db service를 그대로 가리킨다 — 프로덕션은 포트 6543 transaction
      # 모드를 쓴다 (.env.example 참고).
      SUPABASE_DB_POOLER_URL: postgresql://postgres:postgres@db:5432/postgres
      # E2E 모드에서 mock OpenAI를 LLM upstream으로 사용. proxy가 실제
      # OpenAI API에 도달하지 않게 하려면 OPENAI_API_BASE를 mock-openai
      # service URL로 override. 평상시 dev에선 unset 두면 진짜 OpenAI.
      OPENAI_API_BASE: ${OPENAI_API_BASE:-}
    volumes:
      - ./apps/server/src:/app/src
    restart: unless-stopped
    depends_on:
      db:
        condition: service_healthy
    # R-22: readiness probe — same endpoint Vercel preview / production
    # docker invocations use. /health/ready pings Postgres (both routes) +
    # Upstash (Upstash 'skipped' is OK), so a half-broken container shows
    # up as "unhealthy" before Docker routes traffic to it. start_period
    # gives node + tsx-watch time to compile on cold container start.
    #
    # Why `node -e` instead of curl/wget: node:22-alpine ships neither by
    # default, and adding an apk install just for healthcheck inflates the
    # image. node 22 has fetch built in, so this stays zero-dep.
    healthcheck:
      test:
        - 'CMD-SHELL'
        - "node -e \"fetch('http://localhost:3001/health/ready').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))\""
      interval: 30s
      timeout: 5s
      retries: 3
      start_period: 30s

  db:
    # R-23: production은 Postgres 17 (gotcha #16). dev도 17로 맞춰서
    # major-version skew로 인한 SQL/feature 차이 없게. supabase/postgres
    # 이미지는 extension까지 포함이라 supabase CLI 환경과 동일하지만
    # 별도 dependency가 무거우므로 plain alpine으로 시작 — extension
    # 필요해지면 image만 supabase/postgres:17.x로 swap.
    image: postgres:17-alpine
    ports:
      - '54322:5432'
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: postgres
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ['CMD-SHELL', 'pg_isready -U postgres']
      interval: 5s
      timeout: 5s
      retries: 5

  mock-openai:
    # R-3 E2E용 OpenAI-compatible mock. server의 OPENAI_API_BASE를
    # http://mock-openai:4000/v1로 override하면 실제 OpenAI API에 비용
    # 없이 E2E를 돌릴 수 있다. 평상시 dev에선 OPENAI_API_BASE를 비워두면
    # 진짜 OpenAI로 갑니다 (이 컨테이너는 그래도 띄우지만 traffic이 안 옴).
    build:
      context: ./apps/server
      dockerfile: Dockerfile.dev
    command: ['pnpm', 'exec', 'tsx', 'scripts/mock-openai-server.ts']
    ports:
      - '4000:4000'
    environment:
      MOCK_OPENAI_PORT: 4000
    volumes:
      - ./apps/server/scripts:/app/scripts
    healthcheck:
      test:
        - 'CMD-SHELL'
        - "node -e \"fetch('http://localhost:4000/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))\""
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 10s

volumes:
  postgres_data: