# Запуск на сервере my-olymp.ru:
#
#   docker compose -f docker-compose.prod.yml up -d --build
#
# Отличия от локального docker-compose.yml:
#
#   * наружу смотрит nginx на 80 и 443, а не бэкенд напрямую;
#   * nginx собран из того же frontend/Dockerfile, но вместо локальной
#     конфигурации получает my-olymp.ru.conf с TLS;
#   * сертификат выписывает и продлевает certbot — туннель больше не нужен;
#   * порты Postgres и бэкенда на хост не публикуются вовсе;
#   * APP_ENV по умолчанию production: схема API наружу не отдаётся;
#   * пароль базы обязателен: без POSTGRES_PASSWORD в .env compose
#     откажется стартовать, а не поднимет базу с паролем из примера.
#
# Файл самостоятельный, а не надстройка над docker-compose.yml: список
# ports при слиянии файлов не заменяется, а дополняется, и бэкенд всё
# равно оказался бы виден на 8000 в обход TLS.
#
# Первый выпуск сертификата и остальные шаги — docs/deploy-my-olymp.md.

services:
  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: ${POSTGRES_USER:-app}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?задайте POSTGRES_PASSWORD в .env}
      POSTGRES_DB: ${POSTGRES_DB:-app}
    volumes:
      - pgdata:/var/lib/postgresql/data
    # Порт наружу не публикуется: в базу ходит только бэкенд по сети
    # compose. Чтобы заглянуть в неё клиентом, есть docker compose exec.
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-app} -d ${POSTGRES_DB:-app}"]
      interval: 5s
      timeout: 3s
      retries: 10
    restart: unless-stopped

  backend:
    build:
      context: ./backend
      target: runtime
    # В проде .env обязателен: без токена бота и секрета вебхука
    # приложение поднимется, но работать не будет.
    env_file:
      - .env
    environment:
      DATABASE_URL: postgresql+asyncpg://${POSTGRES_USER:-app}:${POSTGRES_PASSWORD:?задайте POSTGRES_PASSWORD в .env}@db:5432/${POSTGRES_DB:-app}
      EXTRA_CA_CERTS_DIR: /app/certs
      # Схему API наружу не отдаём. Значение задано здесь, а не взято из
      # .env: файл на сервере обычно копируют с .env.example, где стоит
      # development, и /docs открылся бы молча. Нужна схема на сервере —
      # поправьте эту строку осознанно.
      APP_ENV: production
      PUBLIC_BASE_URL: ${PUBLIC_BASE_URL:-https://my-olymp.ru}
    command:
      - sh
      - -c
      - alembic upgrade head && python -m scripts.seed
        && exec uvicorn app.main:app --host 0.0.0.0 --port 8000
        --proxy-headers --forwarded-allow-ips '*'
    depends_on:
      db:
        condition: service_healthy
    volumes:
      - ./certs:/app/certs:ro
    healthcheck:
      test:
        - CMD
        - python
        - -c
        - "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/health')"
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s
    restart: unless-stopped

  nginx:
    # Статика и proxy.conf запечены в образ — тот же, что поднимается
    # локально. Правка фронтенда доезжает через git pull и up --build.
    build:
      context: .
      dockerfile: frontend/Dockerfile
    ports:
      - "80:80"
      - "443:443"
    volumes:
      # Вместо локальной конфигурации без TLS — боевая, с сертификатом.
      - ./deploy/nginx/my-olymp.ru.conf:/etc/nginx/conf.d/default.conf:ro
      - letsencrypt:/etc/letsencrypt:ro
      - certbot-webroot:/var/www/certbot:ro
    # Ждём готовности бэкенда: имя upstream'а nginx разрешает один раз при
    # старте и без запущенного контейнера падает с host not found.
    depends_on:
      backend:
        condition: service_healthy
    # Раз в сутки перечитываем конфигурацию: так подхватывается
    # продлённый сертификат, без перезапуска и без обрыва соединений.
    command:
      - sh
      - -c
      - |
        while :; do sleep 24h & wait $${!}; nginx -s reload; done &
        exec nginx -g 'daemon off;'
    restart: unless-stopped

  certbot:
    # Версия закреплена: latest при следующем pull мог бы принести
    # несовместимые ключи командной строки посреди продления.
    image: certbot/certbot:v5.8.0
    volumes:
      - letsencrypt:/etc/letsencrypt
      - certbot-webroot:/var/www/certbot
    # Продление через тот же nginx: certbot кладёт файл-подтверждение в
    # webroot, nginx отдаёт его по http. Пока до истечения больше 30 дней,
    # renew ничего не делает, поэтому проверять дважды в сутки не накладно.
    entrypoint:
      - sh
      - -c
      - |
        trap exit TERM
        while :; do
          certbot renew --webroot --webroot-path /var/www/certbot --quiet
          sleep 12h & wait $${!}
        done
    restart: unless-stopped

volumes:
  pgdata:
  # Сертификат и ключ. Том, а не каталог в репозитории: ключ не должен
  # оказаться в git даже случайно.
  letsencrypt:
  certbot-webroot:
