# shopdb-flask AIR-GAPPED single-site stack.
#
# For a site with NO internet. Nothing is built or pulled here: the images are
# built on a connected box (scripts/build-offline-bundle.ps1), shipped as a
# tarball, and `docker load`ed at the site. This file only RUNS pre-loaded
# images. See docs/DEPLOY-AIRGAP.md for the full runbook.
#
# Differences from docker-compose.yml (the connected/build template):
#   - api uses `image:` (a loaded image), never `build: .` (build needs the net).
#   - NO ./plugins bind mount. The image already carries every plugin baked in;
#     binding a host ./plugins (which does not exist at an image-only site) would
#     mask the baked plugins with an empty dir and load ZERO plugins.
#   - a one-shot `migrate` service runs db upgrade + plugin upgrade-all + seed
#     BEFORE api starts, so `up -d` alone brings up a working site (no manual
#     `docker compose exec ... flask db upgrade` to forget).
#
# Usage at the site:
#   docker load < shopdb-stack-<version>.tar.gz
#   cp .env.example .env    # then edit: secrets, CORS_ORIGINS, IMAGE_TAG
#   docker compose -f docker-compose.airgap.yml up -d
#   docker compose -f docker-compose.airgap.yml exec api flask seed admin <user> <email> <password>

# Shared application environment, reused by the migrate one-shot and the api
# service so the two never drift. A YAML anchor, not a container.
x-app-env: &app-env
  FLASK_APP: wsgi.py
  FLASK_ENV: production
  DATABASE_URL: mysql+pymysql://shopdb:${MYSQL_PASSWORD}@db:3306/shopdb_flask?charset=utf8mb4
  SECRET_KEY: ${SECRET_KEY:?SECRET_KEY must be set}
  JWT_SECRET_KEY: ${JWT_SECRET_KEY:?JWT_SECRET_KEY must be set}
  CORS_ORIGINS: ${CORS_ORIGINS:?CORS_ORIGINS must be set}
  LOG_LEVEL: ${LOG_LEVEL:-INFO}
  ZABBIX_URL: ${ZABBIX_URL:-}
  ZABBIX_TOKEN: ${ZABBIX_TOKEN:-}

services:
  db:
    image: mysql:8.0
    command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:?MYSQL_ROOT_PASSWORD must be set}
      MYSQL_DATABASE: shopdb_flask
      MYSQL_USER: shopdb
      MYSQL_PASSWORD: ${MYSQL_PASSWORD:?MYSQL_PASSWORD must be set}
    volumes:
      - db_data:/var/lib/mysql
    ports:
      - "127.0.0.1:${MYSQL_PORT:-3306}:3306"
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p${MYSQL_ROOT_PASSWORD}"]
      interval: 10s
      timeout: 5s
      retries: 5

  # One-shot schema + seed. Runs to completion and exits; api waits for it.
  # Every step is idempotent, so it is safe to run on every `up`.
  migrate:
    image: shopdb-flask:${IMAGE_TAG:-0.7.0}
    restart: "no"
    depends_on:
      db:
        condition: service_healthy
    environment:
      <<: *app-env
    command:
      - sh
      - -c
      - >
        flask db upgrade &&
        flask plugin upgrade-all &&
        flask seed permissions &&
        flask seed settings &&
        flask seed reference-data

  api:
    image: shopdb-flask:${IMAGE_TAG:-0.7.0}
    restart: unless-stopped
    depends_on:
      db:
        condition: service_healthy
      migrate:
        condition: service_completed_successfully
    environment:
      <<: *app-env
    ports:
      - "${API_PORT:-5001}:5001"

volumes:
  db_data:
