# =============================================================================
# SOSO 서버 - 프로덕션 인프라 구성
# =============================================================================
#
# 이 파일은 SOSO 애플리케이션의 전체 인프라를 정의합니다.
#
# 포함된 서비스들:
# - Jenkins: CI/CD 파이프라인 (자동 빌드, 테스트, 배포)
# - API: SOSO 메인 애플리케이션 서버 (Spring Boot)
# - Proxy: 리버스 프록시 (Caddy - HTTPS, 라우팅)
# - Database: MySQL 데이터베이스 (사용자, 게시글, 댓글 등)
# - Redis: 캐시 및 세션 스토어
# - Watchtower: 컨테이너 자동 업데이트
#
# 네트워크: 모든 서비스는 soso_net 네트워크로 연결
# 볼륨: 데이터 영속성을 위한 named volume 사용
# =============================================================================

# Docker Compose 프로젝트 이름 명시
# 이 설정으로 모든 컨테이너, 네트워크, 볼륨의 이름이 통일됩니다.
# 환경변수나 디렉토리명에 관계없이 항상 동일한 프로젝트명으로 관리됩니다.
name: soso-server

services:
  # =============================================================================
  # Jenkins CI/CD 서버
  # =============================================================================
  #
  # GitHub 푸시 시 자동으로 트리거되어 다음 작업을 수행:
  # 1. 코드 체크아웃 및 테스트 실행
  # 2. Spring Boot JAR 파일 빌드
  # 3. Docker 이미지 생성
  # 4. 프로덕션 환경에 자동 배포
  #
  # 주요 기능:
  # - Java 21 기반 (최신 LTS)
  # - Docker-in-Docker로 컨테이너 제어
  # - Git 자동 설정 (컨테이너 재시작 시)
  # - 자동 권한 설정 스크립트
  # =============================================================================
  jenkins:
    build:
      context: ./infrastructure/jenkins # 커스텀 Dockerfile 위치
      dockerfile: Dockerfile
    container_name: jenkins
    user: root # Docker 소켓 접근을 위한 root 권한 필요
    environment:
      TZ: Asia/Seoul # 한국 시간대 설정
      JAVA_OPTS: "-Djenkins.install.runSetupWizard=false" # 초기 설정 위저드 건너뛰기
      JENKINS_OPTS: "--prefix=/jenkins" # URL 프리픽스 설정 (/jenkins 경로)
    ports:
      - "8080:8080" # Jenkins 웹 UI 접근 포트
      - "50000:50000" # Jenkins 에이전트 연결 포트
    volumes:
      - jenkins_data:/var/jenkins_home # Jenkins 설정 및 작업 데이터 영속화
      - /var/run/docker.sock:/var/run/docker.sock # Docker-in-Docker (호스트 Docker 제어)
    networks: [soso_net] # 내부 네트워크 연결
    restart: unless-stopped # 시스템 재부팅 시 자동 시작
    healthcheck: # Jenkins 서비스 상태 확인
      test:
        ["CMD-SHELL", "curl -f http://localhost:8080/jenkins/login || exit 1"]
      interval: 30s # 30초마다 상태 확인
      timeout: 10s # 10초 내 응답 없으면 실패
      retries: 3 # 3번 실패 시 unhealthy 상태
      start_period: 60s # 시작 후 60초 대기 시간

  # =============================================================================
  # SOSO API 애플리케이션 서버
  # =============================================================================
  #
  # Spring Boot 기반의 메인 애플리케이션 서버
  #
  # 주요 기능:
  # - REST API 제공 (사용자, 게시글, 댓글, 좋아요 등)
  # - JWT 기반 인증/인가
  # - 카카오 OAuth 소셜 로그인
  # - AWS S3 이미지 업로드
  # - Redis 기반 캐싱 및 세션 관리
  # - JPA/Hibernate 기반 데이터베이스 ORM
  #
  # 보안:
  # - 외부 직접 접근 차단 (expose만 사용)
  # - Caddy 프록시를 통해서만 접근 가능
  # =============================================================================
  api:
    image: ${API_IMAGE:-soso/api:latest} # Jenkins가 빌드한 이미지 사용
    container_name: soso-api
    environment:
      TZ: Asia/Seoul # 한국 시간대 설정
      SPRING_PROFILES_ACTIVE: ${SPRING_PROFILES_ACTIVE:-prod} # 프로덕션 프로파일

      # =================================================================
      # 데이터베이스 연결 설정 (컨테이너 네트워크 내부 통신)
      # =================================================================
      DB_HOST: db # MySQL 컨테이너 서비스명
      DB_PORT: 3306 # MySQL 기본 포트
      DB_NAME: ${DB_NAME:-soso} # 데이터베이스명
      DB_USER: ${DB_USER:-soso_user} # 애플리케이션 전용 계정
      DB_PASS: ${DB_PASS:-12341234} # 데이터베이스 비밀번호

      # =================================================================
      # JPA/Hibernate 설정
      # =================================================================
      JPA_DDL: ${JPA_DDL:-update} # 스키마 자동 생성/업데이트 (update 모드)

      # =================================================================
      # Redis 캐시 설정 (컨테이너 네트워크 내부 통신)
      # =================================================================
      REDIS_HOST: redis # Redis 컨테이너 서비스명
      REDIS_PORT: 6379 # Redis 기본 포트

      # =================================================================
      # 애플리케이션 설정
      # =================================================================
      FRONTEND_ORIGIN: ${FRONTEND_ORIGIN} # CORS 허용 프론트엔드 URL
      JWT_SECRET: ${JWT_SECRET} # JWT 토큰 서명 비밀키
      JWT_AT_VALIDITY: ${JWT_AT_VALIDITY:-1800000} # Access Token 유효시간 (30분)
      JWT_RT_VALIDITY: ${JWT_RT_VALIDITY:-1209600000} # Refresh Token 유효시간 (14일)

      # =================================================================
      # 외부 서비스 연동
      # =================================================================
      # 카카오 OAuth 소셜 로그인
      KAKAO_CLIENT_ID: ${KAKAO_CLIENT_ID} # 카카오 앱 클라이언트 ID
      KAKAO_REDIRECT_URIS: ${KAKAO_REDIRECT_URIS} # 카카오 로그인 리다이렉트 URL

      # AWS S3 이미지 저장소
      AWS_REGION: ${AWS_REGION} # AWS 리전 (ap-northeast-2)
      AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID} # AWS 액세스 키
      AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY} # AWS 시크릿 키
      AWS_S3_BUCKET: ${AWS_S3_BUCKET} # S3 버킷명
      S3_BASE_URL: ${S3_BASE_URL} # S3 이미지 베이스 URL

      # Apache Kafka (현재 미사용)
      KAFKA_BOOTSTRAP: ${KAFKA_BOOTSTRAP} # Kafka 브로커 주소

      # =================================================================
      # 쿠키 설정 (환경별)
      # =================================================================
      COOKIE_SECURE: ${COOKIE_SECURE:-true} # 프로덕션: HTTPS 필수
      COOKIE_SAME_SITE: ${COOKIE_SAME_SITE:-None} # 프로덕션: 크로스 도메인 허용

    depends_on: # 서비스 시작 순서 의존성
      db:
        condition: service_healthy # MySQL이 healthy 상태일 때 시작
      redis:
        condition: service_healthy # Redis가 healthy 상태일 때 시작

    expose: ["8080"] # 내부 네트워크에만 포트 노출 (보안)
    networks: [soso_net] # 내부 네트워크 연결
    restart: unless-stopped # 장애 시 자동 재시작

    healthcheck: # API 서버 상태 확인
      test:
        ["CMD-SHELL", "curl -f http://localhost:8080/actuator/health || exit 1"]
      interval: 10s # 10초마다 상태 확인 (빠른 피드백)
      timeout: 3s # 3초 내 응답 없으면 실패
      retries: 5 # 5번 실패 시 unhealthy 상태 (Spring Boot는 15-20초면 시작)
      start_period: 30s # 시작 후 30초 대기 시간 (실제 시작 시간에 최적화)

    labels:
      - "com.centurylinklabs.watchtower.enable=true" # Watchtower 자동 업데이트 활성화

  # =============================================================================
  # 리버스 프록시 (Caddy)
  # =============================================================================
  #
  # 모든 외부 트래픽의 진입점 역할
  #
  # 주요 기능:
  # - 자동 HTTPS/SSL 인증서 (Let's Encrypt)
  # - 요청 라우팅 (API, Jenkins, Swagger 등)
  # - 보안 헤더 자동 추가
  # - Gzip 압축
  # - 정적 파일 캐싱
  # - 무중단 설정 리로드
  #
  # 라우팅:
  # - / → Jenkins (임시, 나중에 프론트엔드로 변경 예정)
  # - /api/* → API 서버
  # - /jenkins/* → Jenkins 관리자 페이지
  # - /swagger-ui/* → API 문서
  # =============================================================================
  proxy:
    image: caddy:2 # 공식 Caddy v2 이미지
    container_name: soso-proxy
    environment:
      TZ: Asia/Seoul # 한국 시간대 설정
    ports:
      - "80:80" # HTTP 포트 (HTTPS로 리다이렉트)
      - "443:443" # HTTPS 포트 (메인 접속점)
    volumes:
      - ./infrastructure/Caddyfile:/etc/caddy/Caddyfile:ro # Caddy 설정 파일 (읽기 전용)
      - caddy_data:/data # SSL 인증서 및 데이터 저장소
      - caddy_config:/config # Caddy 내부 설정 저장소
    depends_on: # 서비스 시작 순서 의존성
      api:
        condition: service_healthy # API가 정상일 때 시작
      # Jenkins 의존성 제거: Jenkins가 unhealthy여도 Proxy는 정상 작동
      # Jenkins는 관리 페이지일 뿐, 핵심 서비스 아님
    networks: [soso_net] # 내부 네트워크 연결
    restart: unless-stopped # 장애 시 자동 재시작
    healthcheck: # Caddy 설정 파일 검증
      test: ["CMD", "caddy", "validate", "--config", "/etc/caddy/Caddyfile"]
      interval: 30s # 30초마다 설정 유효성 확인
      timeout: 10s # 10초 내 검증 완료
      retries: 3 # 3번 실패 시 unhealthy 상태

  # =============================================================================
  # 데이터베이스 (MySQL)
  # =============================================================================
  #
  # SOSO 애플리케이션의 메인 데이터 저장소
  #
  # 저장되는 데이터:
  # - 사용자 정보 (users)
  # - 게시글 및 댓글 (posts, comments)
  # - 좋아요 정보 (post_likes, comment_likes)
  # - 이미지 메타데이터 (post_images)
  # - 기타 애플리케이션 데이터
  #
  # 주요 설정:
  # - UTF-8 완전 지원 (utf8mb4)
  # - 엄격한 SQL 모드 (데이터 무결성 보장)
  # - 네이티브 비밀번호 인증 (호환성)
  # - 초기화 스크립트 지원
  # =============================================================================
  db:
    image: mysql:8.4 # MySQL 8.4 LTS 버전
    container_name: soso-mysql
    environment:
      TZ: Asia/Seoul # 한국 시간대 설정
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-rootpassword} # root 계정 비밀번호
      MYSQL_DATABASE: ${DB_NAME:-soso} # 애플리케이션 데이터베이스 자동 생성
      MYSQL_USER: ${DB_USER:-soso_user} # 애플리케이션 전용 계정 생성
      MYSQL_PASSWORD: ${DB_PASS:-12341234} # 애플리케이션 계정 비밀번호
    command: # MySQL 서버 시작 옵션
      [
        "--character-set-server=utf8mb4", # 한글 및 이모지 완전 지원
        "--collation-server=utf8mb4_0900_ai_ci", # 최신 정렬 규칙 (대소문자 구분 안함)
        "--mysql-native-password=ON", # 기존 인증 방식 사용 (호환성)
        "--sql-mode=STRICT_TRANS_TABLES,NO_ZERO_DATE,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO", # 엄격한 SQL 모드
      ]
    volumes:
      - mysql_data:/var/lib/mysql # 데이터 영속화 (재시작 후에도 데이터 보존)
      # - ./infrastructure/mysql-init:/docker-entrypoint-initdb.d:ro  # 초기화 SQL 스크립트
    networks: [soso_net] # 내부 네트워크만 접근
    restart: unless-stopped # 장애 시 자동 재시작
    healthcheck: # MySQL 서버 상태 확인
      test:
        [
          "CMD-SHELL",
          "mysqladmin ping -h localhost -u${DB_USER} -p${DB_PASS} --silent",
        ]
      interval: 10s # 10초마다 상태 확인
      timeout: 5s # 5초 내 응답 없으면 실패
      retries: 10 # 10번 실패 시 unhealthy 상태
      start_period: 30s # 시작 후 30초 대기 시간

  # =============================================================================
  # 캐시 및 세션 스토어 (Redis)
  # =============================================================================
  #
  # 고성능 인메모리 데이터 저장소
  #
  # 사용 목적:
  # - API 응답 캐싱 (성능 향상)
  # - 사용자 세션 관리
  # - 임시 데이터 저장 (JWT 블랙리스트 등)
  # - 실시간 기능 지원 (향후 알림 등)
  #
  # 주요 설정:
  # - AOF 영속성 활성화 (데이터 손실 방지)
  # - 메모리 제한 256MB (적절한 리소스 사용)
  # - LRU 정책 (메모리 부족 시 오래된 데이터 자동 삭제)
  # =============================================================================
  redis:
    image: redis:7-alpine # Redis 7 (경량 Alpine 기반)
    container_name: soso-redis
    environment:
      TZ: Asia/Seoul # 한국 시간대 설정
    command: # Redis 서버 실행 옵션
      [
        "redis-server", # Redis 서버 실행
        "--appendonly",
        "yes", # AOF 영속성 활성화 (데이터 손실 방지)
        "--maxmemory",
        "256mb", # 최대 메모리 사용량 제한
        "--maxmemory-policy",
        "allkeys-lru", # 메모리 부족 시 LRU 알고리즘으로 데이터 삭제
      ]
    volumes:
      - redis_data:/data # AOF 파일 영속화 (재시작 후 데이터 복구)
    networks: [soso_net] # 내부 네트워크만 접근
    restart: unless-stopped # 장애 시 자동 재시작
    healthcheck: # Redis 서버 상태 확인
      test: ["CMD", "redis-cli", "ping"] # PING 명령으로 응답성 확인
      interval: 10s # 10초마다 상태 확인
      timeout: 3s # 3초 내 응답 없으면 실패
      retries: 5 # 5번 실패 시 unhealthy 상태

  # =============================================================================
  # 자동 업데이트 (Watchtower)
  # =============================================================================
  #
  # 컨테이너 이미지 자동 업데이트 서비스
  #
  # 주요 기능:
  # - Docker Hub에서 새로운 이미지 버전 자동 감지
  # - 라벨 기반 선택적 업데이트 (api 서비스만)
  # - 자동 컨테이너 재시작
  # - 이전 이미지 자동 정리
  #
  # 업데이트 대상:
  # - API 서버 (watchtower.enable=true 라벨이 있는 경우)
  # - 기타 인프라 서비스들은 수동 관리
  # =============================================================================
  watchtower:
    image: containrrr/watchtower # Watchtower 공식 이미지
    container_name: watchtower
    environment:
      TZ: Asia/Seoul # 한국 시간대 설정
      WATCHTOWER_CLEANUP: "true" # 이전 이미지 자동 정리
      WATCHTOWER_INCLUDE_RESTARTING: "true" # 재시작 중인 컨테이너도 포함
      WATCHTOWER_POLL_INTERVAL: 300 # 5분마다 새 이미지 확인
      WATCHTOWER_LABEL_ENABLE: "true" # 라벨이 있는 컨테이너만 업데이트
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock # Docker 데몬 제어를 위한 소켓 접근
    restart: unless-stopped # 장애 시 자동 재시작

# =============================================================================
# 네트워크 설정
# =============================================================================
#
# 모든 서비스들이 안전하게 통신할 수 있는 격리된 네트워크
#
# 특징:
# - 브리지 네트워크 (컨테이너 간 통신)
# - 서비스명으로 DNS 해결 (db, redis, api 등)
# - 외부와 격리된 내부 통신
# - 172.25.0.0/18 서브넷 사용
# =============================================================================
networks:
  soso_net:
    name: soso_net # 네트워크명
    driver: bridge # 브리지 드라이버 (기본값)
    ipam: # IP 주소 관리
      config:
        - subnet: 172.25.0.0/16 # 사용할 IP 대역

# =============================================================================
# 영구 볼륨 설정
# =============================================================================
#
# 컨테이너 재시작/재생성 시에도 데이터를 보존하는 영구 저장소
#
# 각 볼륨의 역할:
# - jenkins_data: Jenkins 설정, 빌드 히스토리, 플러그인
# - mysql_data: MySQL 데이터베이스 파일
# - redis_data: Redis AOF 파일 (데이터 복구용)
# - caddy_data: SSL 인증서, Caddy 데이터
# - caddy_config: Caddy 내부 설정
# =============================================================================
volumes:
  jenkins_data:
    name: jenkins_data # Jenkins 데이터 영속화
  mysql_data:
    name: mysql_data # MySQL 데이터베이스 영속화
  redis_data:
    name: redis_data # Redis 데이터 영속화
  caddy_data:
    name: caddy_data # Caddy SSL 인증서 영속화
  caddy_config:
    name: caddy_config # Caddy 설정 영속화
