# Локальный запуск одной командой:
#
#   docker compose up --build
#
# Поднимаются три сервиса:
#
#   db       Postgres;
#   backend  API и бот; при старте применяет миграции и, если каталог
#            пуст, наполняет его выгрузками из backend/data;
#   web      nginx: мини-приложение на http://localhost:8080 и прокси
#            /api, /webhook, /health в бэкенд — та же раскладка, что на
#            сервере, только без TLS.
#
# Для сервера есть docker-compose.prod.yml — там nginx получает
# сертификат на my-olymp.ru, а порты бэкенда и базы с хоста убраны.
# Порядок развёртывания — в docs/deploy-my-olymp.md.

services:
  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: ${POSTGRES_USER:-app}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-app}
      POSTGRES_DB: ${POSTGRES_DB:-app}
    volumes:
      - pgdata:/var/lib/postgresql/data
    ports:
      # Наружу — только чтобы можно было заглянуть в базу клиентом, и
      # только с этой машины: пароль по умолчанию в локальной сети ни к чему.
      - "127.0.0.1:${POSTGRES_PORT:-5432}:5432"
    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_file:
      # required: false — первый запуск не падает, если .env ещё не создан.
      - path: .env
        required: false
    environment:
      # Адрес базы собирается здесь: внутри сети compose хост — имя сервиса.
      DATABASE_URL: postgresql+asyncpg://${POSTGRES_USER:-app}:${POSTGRES_PASSWORD:-app}@db:5432/${POSTGRES_DB:-app}
      EXTRA_CA_CERTS_DIR: /app/certs
    # Схему создаёт и обновляет Alembic, а не приложение: так одна и та
    # же команда поднимает и чистую базу, и уже существующую. Следом
    # scripts.seed наполняет каталог — но только пустой.
    command:
      - sh
      - -c
      - alembic upgrade head && python -m scripts.seed
        && exec uvicorn app.main:app --host 0.0.0.0 --port 8000
    depends_on:
      db:
        condition: service_healthy
    ports:
      - "${BACKEND_PORT:-8000}:8000"
    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

  web:
    build:
      # Корень, а не frontend/: образу нужны ещё конфигурации nginx из
      # deploy/nginx/. Лишнее из контекста отсекает корневой .dockerignore.
      context: .
      dockerfile: frontend/Dockerfile
    ports:
      - "${WEB_PORT:-8080}:80"
    # Имя upstream'а nginx разрешает один раз при старте и без запущенного
    # бэкенда падает с host not found.
    depends_on:
      backend:
        condition: service_healthy
    restart: unless-stopped

  # Прогон тестов: docker compose --profile test run --rm tests
  # В обычный `up` не попадает и базу не требует.
  tests:
    profiles: ["test"]
    build:
      context: ./backend
      target: dev
    command: ["pytest"]

volumes:
  pgdata:
