# 운영 배포용 컴포즈 — EC2에서 이 파일 하나로 전체 스택이 뜹니다.
# 사용법: cd deploy && cp .env.example .env (비밀번호 수정) && docker compose -f docker-compose.prod.yml up -d --build
# 학습 포인트: 개발(로컬)과 운영의 차이 —
#  - DB 포트를 외부에 안 엽니다(컨테이너끼리 내부 네트워크로만 통신)
#  - 비밀번호는 .env 파일로 주입 (코드/이미지에 안 넣음)
#  - 재부팅해도 자동 시작(restart: unless-stopped)

# 학습 포인트 — 로그도 자원이다(디스크). Docker 기본값은 로그를 "무제한"으로 쌓아서,
# 작은 EC2 디스크가 몇 달이면 꽉 차고 그 순간 스택 전체가 조용히 멈춘다("아무도 모르는 다운").
# 아래 앵커(&logging)로 각 서비스에 "파일당 10MB, 3개까지만" 회전 정책을 공통 적용한다.
# YAML 앵커(&이름)와 병합(<<: *이름)은 "같은 설정을 한 번 쓰고 여러 곳에 붙이는" 문법이다.
x-logging: &logging
  driver: json-file
  options:
    max-size: "10m"
    max-file: "3"

services:
  postgres:
    image: postgres:17-alpine
    container_name: mirim-postgres
    logging: *logging
    environment:
      POSTGRES_DB: mirim
      POSTGRES_USER: mirim
      POSTGRES_PASSWORD: ${DB_PASSWORD:?deploy/.env에 DB_PASSWORD를 설정하세요}
    volumes:
      - pgdata:/var/lib/postgresql/data
    restart: unless-stopped
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U mirim"]
      interval: 10s
      timeout: 5s
      retries: 5

  backend:
    build: ../backend
    container_name: mirim-backend
    logging: *logging
    environment:
      DB_HOST: postgres        # 학습 포인트: 컨테이너끼리는 서비스 이름이 곧 주소예요
      DB_PORT: 5432
      DB_NAME: mirim
      DB_USER: mirim
      DB_PASSWORD: ${DB_PASSWORD}
      COOKIE_SECURE: "true"   # 운영은 HTTPS(Caddy)이므로 세션 쿠키를 HTTPS 전용으로
      LOG_LEVEL: INFO         # 운영 로그는 INFO
      # 텔레그램 알림 (값은 .env에 — 비어 있으면 알림만 꺼지고 앱은 정상)
      TELEGRAM_BOT_TOKEN: ${TELEGRAM_BOT_TOKEN:-}
      TELEGRAM_CHAT_ID: ${TELEGRAM_CHAT_ID:-}
      # 멘토 최초 비밀번호 (첫 부팅 시드용). 비우면 랜덤 생성돼 로그에 1회 출력된다.
      MENTOR_INITIAL_PASSWORD: ${MENTOR_INITIAL_PASSWORD:-}
      # 멘토 피드백 AI 초안 — 아래 ollama-proxy 경유로 워크스테이션(tailnet)의 Ollama를 쓴다.
      # 학습 포인트: @Value("${llm.base-url:}")는 환경변수 relaxed binding이 약해, LLM_BASE_URL을
      # 줘도 안 읽히는 경우가 있다. JVM 시스템 프로퍼티(-D)로 주면 확실하다.
      # 이 값이 없으면 초안 기능만 조용히 꺼지고 앱은 정상 동작한다.
      JAVA_TOOL_OPTIONS: "-Dllm.base-url=http://ollama-proxy:11434"
    depends_on:
      postgres:
        condition: service_healthy
      ollama-proxy:
        condition: service_started
    restart: unless-stopped

  # 로컬 LLM 프록시 — 멘토 피드백 AI 초안이 워크스테이션(tailnet)의 Ollama를 쓰게 한다.
  # 왜 프록시가 필요한가: Ollama는 DNS-rebinding 방어로 요청 Host 헤더를 검증해서,
  # tailnet 이름(awesomedev.taildc21b5.ts.net)으로 오는 요청을 403으로 막는다.
  # 이 프록시가 Host를 localhost로 재작성해 통과시킨다(Caddyfile 참조).
  # 워크스테이션 쪽은 `tailscale serve`로 Ollama를 tailnet 전용 노출한다(Ollama는 127.0.0.1 유지).
  ollama-proxy:
    image: caddy:2-alpine
    container_name: ollama-proxy
    logging: *logging
    extra_hosts:
      - "awesomedev.taildc21b5.ts.net:100.67.10.124"   # 워크스테이션 tailnet IP
    volumes:
      - ./ollama-proxy/Caddyfile:/etc/caddy/Caddyfile:ro
    restart: unless-stopped

  # 프론트 빌드 결과물을 공유 볼륨(webroot)에 복사해 주고 종료하는 일회성 컨테이너
  frontend-build:
    build: ../frontend
    container_name: mirim-frontend-build
    volumes:
      - webroot:/out
    restart: "no"

  caddy:
    image: caddy:2-alpine
    container_name: mirim-caddy
    logging: *logging
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - webroot:/srv:ro
      - caddy-data:/data      # HTTPS 인증서 보관 (재시작해도 유지)
    depends_on:
      - backend
      - frontend-build
    restart: unless-stopped

  # Gitea — 가벼운 사내 Git 서버. 학생들이 clone/commit/push를 연습하는 곳.
  # 학습 포인트: GitHub 같은 서비스를 우리 서버 안에 직접 띄운 것. 웹 UI는 :3000.
  gitea:
    image: gitea/gitea:1.23
    container_name: mirim-gitea
    logging: *logging
    environment:
      GITEA__server__ROOT_URL: http://${GIT_HOST:-edu.awesomedevapp.com}:3000/
      GITEA__server__SSH_PORT: "222"
      GITEA__service__DISABLE_REGISTRATION: "false"   # 학생 스스로 가입 가능
      GITEA__security__INSTALL_LOCK: "true"           # 웹 설치 마법사 건너뛰기(설정은 env로 완료)
      GITEA__actions__ENABLED: "true"                 # CI — Gitea Actions(push 시 자동 테스트) 켜기
    ports:
      - "3000:3000"   # 웹 UI + HTTP clone/push
      - "222:22"      # SSH clone/push (선택)
    volumes:
      - gitea-data:/data
    restart: unless-stopped

  # CI 러너 — push마다 .gitea/workflows/ci.yml을 실행한다(Gitea Actions).
  # 학습 포인트: 러너는 "일감을 받아 job 컨테이너를 띄우는 일꾼"이라 Docker 소켓을 마운트한다.
  #   최초 등록은 /opt/mirim-runner에 .runner 파일로 저장되므로(호스트에 준비됨),
  #   컨테이너를 다시 만들어도 재등록 없이 이어진다. 설정은 /opt/mirim-runner/config.yaml.
  runner:
    image: gitea/act_runner:0.2.11
    container_name: mirim-runner
    logging: *logging
    depends_on:
      - gitea
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /opt/mirim-runner:/data
    working_dir: /data
    environment:
      GITEA_INSTANCE_URL: http://gitea:3000
      CONFIG_FILE: /data/config.yaml
    restart: unless-stopped

volumes:
  pgdata:
  webroot:
  caddy-data:
  gitea-data:
