name: scholarr

services:
  db:
    image: postgres:15-alpine
    restart: unless-stopped
    environment:
      POSTGRES_DB: ${POSTGRES_DB:-scholar}
      POSTGRES_USER: ${POSTGRES_USER:-scholar}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-scholar} -d ${POSTGRES_DB:-scholar}"]
      interval: 5s
      timeout: 5s
      retries: 20

  app:
    image: ${SCHOLARR_IMAGE:-justinzeus/scholarr:latest}
    restart: unless-stopped
    environment:
      DATABASE_URL: ${DATABASE_URL:-postgresql+asyncpg://${POSTGRES_USER:-scholar}:${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB:-scholar}}
      MIGRATE_ON_START: ${MIGRATE_ON_START:-1}
      APP_NAME: ${APP_NAME:-scholarr}
      APP_HOST: ${APP_HOST:-0.0.0.0}
      APP_PORT: ${APP_PORT:-8000}
      APP_RELOAD: ${APP_RELOAD:-0}
      SESSION_SECRET_KEY: ${SESSION_SECRET_KEY:?set SESSION_SECRET_KEY}
      SESSION_COOKIE_SECURE: ${SESSION_COOKIE_SECURE:-1}
      FRONTEND_ENABLED: ${FRONTEND_ENABLED:-1}
      FRONTEND_DIST_DIR: ${FRONTEND_DIST_DIR:-/app/frontend/dist}
      LOGIN_RATE_LIMIT_ATTEMPTS: ${LOGIN_RATE_LIMIT_ATTEMPTS:-5}
      LOGIN_RATE_LIMIT_WINDOW_SECONDS: ${LOGIN_RATE_LIMIT_WINDOW_SECONDS:-60}
      LOG_LEVEL: ${LOG_LEVEL:-INFO}
      LOG_FORMAT: ${LOG_FORMAT:-console}
      LOG_REQUESTS: ${LOG_REQUESTS:-1}
      LOG_UVICORN_ACCESS: ${LOG_UVICORN_ACCESS:-0}
      LOG_REQUEST_SKIP_PATHS: ${LOG_REQUEST_SKIP_PATHS:-/healthz}
      LOG_REDACT_FIELDS: ${LOG_REDACT_FIELDS:-}
      SCHEDULER_ENABLED: ${SCHEDULER_ENABLED:-1}
      SCHEDULER_TICK_SECONDS: ${SCHEDULER_TICK_SECONDS:-60}
      INGESTION_AUTOMATION_ALLOWED: ${INGESTION_AUTOMATION_ALLOWED:-1}
      INGESTION_MANUAL_RUN_ALLOWED: ${INGESTION_MANUAL_RUN_ALLOWED:-1}
      INGESTION_MIN_RUN_INTERVAL_MINUTES: ${INGESTION_MIN_RUN_INTERVAL_MINUTES:-15}
      INGESTION_MIN_REQUEST_DELAY_SECONDS: ${INGESTION_MIN_REQUEST_DELAY_SECONDS:-2}
      INGESTION_NETWORK_ERROR_RETRIES: ${INGESTION_NETWORK_ERROR_RETRIES:-1}
      INGESTION_RETRY_BACKOFF_SECONDS: ${INGESTION_RETRY_BACKOFF_SECONDS:-1.0}
      INGESTION_MAX_PAGES_PER_SCHOLAR: ${INGESTION_MAX_PAGES_PER_SCHOLAR:-30}
      INGESTION_PAGE_SIZE: ${INGESTION_PAGE_SIZE:-100}
      INGESTION_ALERT_BLOCKED_FAILURE_THRESHOLD: ${INGESTION_ALERT_BLOCKED_FAILURE_THRESHOLD:-1}
      INGESTION_ALERT_NETWORK_FAILURE_THRESHOLD: ${INGESTION_ALERT_NETWORK_FAILURE_THRESHOLD:-2}
      INGESTION_ALERT_RETRY_SCHEDULED_THRESHOLD: ${INGESTION_ALERT_RETRY_SCHEDULED_THRESHOLD:-3}
      INGESTION_SAFETY_COOLDOWN_BLOCKED_SECONDS: ${INGESTION_SAFETY_COOLDOWN_BLOCKED_SECONDS:-1800}
      INGESTION_SAFETY_COOLDOWN_NETWORK_SECONDS: ${INGESTION_SAFETY_COOLDOWN_NETWORK_SECONDS:-900}
      INGESTION_CONTINUATION_QUEUE_ENABLED: ${INGESTION_CONTINUATION_QUEUE_ENABLED:-1}
      INGESTION_CONTINUATION_BASE_DELAY_SECONDS: ${INGESTION_CONTINUATION_BASE_DELAY_SECONDS:-120}
      INGESTION_CONTINUATION_MAX_DELAY_SECONDS: ${INGESTION_CONTINUATION_MAX_DELAY_SECONDS:-3600}
      INGESTION_CONTINUATION_MAX_ATTEMPTS: ${INGESTION_CONTINUATION_MAX_ATTEMPTS:-6}
      SCHEDULER_QUEUE_BATCH_SIZE: ${SCHEDULER_QUEUE_BATCH_SIZE:-10}
      SCHOLAR_IMAGE_UPLOAD_DIR: ${SCHOLAR_IMAGE_UPLOAD_DIR:-/var/lib/scholarr/uploads}
      SCHOLAR_IMAGE_UPLOAD_MAX_BYTES: ${SCHOLAR_IMAGE_UPLOAD_MAX_BYTES:-2000000}
      SCHOLAR_NAME_SEARCH_ENABLED: ${SCHOLAR_NAME_SEARCH_ENABLED:-1}
      SCHOLAR_NAME_SEARCH_CACHE_TTL_SECONDS: ${SCHOLAR_NAME_SEARCH_CACHE_TTL_SECONDS:-21600}
      SCHOLAR_NAME_SEARCH_BLOCKED_CACHE_TTL_SECONDS: ${SCHOLAR_NAME_SEARCH_BLOCKED_CACHE_TTL_SECONDS:-300}
      SCHOLAR_NAME_SEARCH_CACHE_MAX_ENTRIES: ${SCHOLAR_NAME_SEARCH_CACHE_MAX_ENTRIES:-512}
      SCHOLAR_NAME_SEARCH_MIN_INTERVAL_SECONDS: ${SCHOLAR_NAME_SEARCH_MIN_INTERVAL_SECONDS:-8.0}
      SCHOLAR_NAME_SEARCH_INTERVAL_JITTER_SECONDS: ${SCHOLAR_NAME_SEARCH_INTERVAL_JITTER_SECONDS:-2.0}
      SCHOLAR_NAME_SEARCH_COOLDOWN_BLOCK_THRESHOLD: ${SCHOLAR_NAME_SEARCH_COOLDOWN_BLOCK_THRESHOLD:-1}
      SCHOLAR_NAME_SEARCH_COOLDOWN_SECONDS: ${SCHOLAR_NAME_SEARCH_COOLDOWN_SECONDS:-1800}
      SCHOLAR_NAME_SEARCH_ALERT_RETRY_COUNT_THRESHOLD: ${SCHOLAR_NAME_SEARCH_ALERT_RETRY_COUNT_THRESHOLD:-2}
      SCHOLAR_NAME_SEARCH_ALERT_COOLDOWN_REJECTIONS_THRESHOLD: ${SCHOLAR_NAME_SEARCH_ALERT_COOLDOWN_REJECTIONS_THRESHOLD:-3}
      BOOTSTRAP_ADMIN_ON_START: ${BOOTSTRAP_ADMIN_ON_START:-0}
      BOOTSTRAP_ADMIN_EMAIL: ${BOOTSTRAP_ADMIN_EMAIL:-}
      BOOTSTRAP_ADMIN_PASSWORD: ${BOOTSTRAP_ADMIN_PASSWORD:-}
      BOOTSTRAP_ADMIN_FORCE_PASSWORD: ${BOOTSTRAP_ADMIN_FORCE_PASSWORD:-0}
      DB_WAIT_TIMEOUT_SECONDS: ${DB_WAIT_TIMEOUT_SECONDS:-60}
      DB_WAIT_INTERVAL_SECONDS: ${DB_WAIT_INTERVAL_SECONDS:-2}
    ports:
      - "${APP_HOST_PORT:-8000}:8000"
    volumes:
      - scholar_uploads:/var/lib/scholarr/uploads
    depends_on:
      db:
        condition: service_healthy
    healthcheck:
      test: ["CMD-SHELL", "curl -fsS http://localhost:8000/healthz >/dev/null || exit 1"]
      interval: 10s
      timeout: 5s
      retries: 12

volumes:
  postgres_data:
  scholar_uploads:
