name: dashboard-cpsp-executive services: database: image: postgres:16-alpine container_name: dashboard-cpsp-executive-database restart: unless-stopped environment: POSTGRES_USER: ${DB_USER:-executive} POSTGRES_PASSWORD: ${DB_PASSWORD:-change_this_to_a_strong_password} POSTGRES_DB: ${DB_NAME:-executive} PGDATA: /var/lib/postgresql/data/pgdata volumes: - db-data:/var/lib/postgresql/data networks: - dashboard-cpsp-executive-network healthcheck: test: [ "CMD-SHELL", "pg_isready -U ${DB_USER:-executive} -d ${DB_NAME:-executive}", ] interval: 10s timeout: 5s retries: 5 start_period: 10s # Host 15433 avoids clash with site dashboard-cpsp (15432). # Mac dev: add docker-compose.override.yml from docker/compose.override.local.example for :5432. ports: - "127.0.0.1:15433:5432" api: image: dashboard-cpsp-executive-api build: context: . dockerfile: docker/Dockerfile.api container_name: dashboard-cpsp-executive-api restart: unless-stopped ports: - "127.0.0.1:18001:8000" environment: DEBUG: ${DEBUG:-false} SECRET_KEY: ${SECRET_KEY:-test-secret-key} ALLOWED_HOSTS: ${ALLOWED_HOSTS:-localhost,127.0.0.1,api,frontend,executive.local} CSRF_TRUSTED_ORIGINS: ${CSRF_TRUSTED_ORIGINS:-http://localhost,http://127.0.0.1,http://executive.local} CORS_ALLOWED_ORIGINS: ${CORS_ALLOWED_ORIGINS:-http://localhost,http://127.0.0.1,http://executive.local} CORS_ALLOW_CREDENTIALS: "true" DB_ENGINE: django.db.backends.postgresql DB_NAME: ${DB_NAME:-executive} DB_USER: ${DB_USER:-executive} DB_PASSWORD: ${DB_PASSWORD:-change_this_to_a_strong_password} DB_HOST: database DB_PORT: "5432" KARUNG_WEB_ADMIN_BASE_URL: ${KARUNG_WEB_ADMIN_BASE_URL:-http://host.docker.internal:5000} KARUNG_WEB_ADMIN_TIMEOUT_SECONDS: ${KARUNG_WEB_ADMIN_TIMEOUT_SECONDS:-30} KARUNG_WEB_ADMIN_SYNC_ENABLED: ${KARUNG_WEB_ADMIN_SYNC_ENABLED:-false} DASHBOARD_PUBLISH_HOUR: ${DASHBOARD_PUBLISH_HOUR:-17} DASHBOARD_PUBLISH_MINUTE: ${DASHBOARD_PUBLISH_MINUTE:-0} IOT_SYNC_ENABLED: ${IOT_SYNC_ENABLED:-false} IOT_API_BASE_URL: ${IOT_API_BASE_URL:-} IOT_FLOCK_ID_MAP: ${IOT_FLOCK_ID_MAP:-{}} IOT_SYNC_LOOKBACK_MINUTES: ${IOT_SYNC_LOOKBACK_MINUTES:-20} IOT_SYNC_MAX_PAGES: ${IOT_SYNC_MAX_PAGES:-10} CHICKEN_COUNTING_EDGE_BASE_URL: ${CHICKEN_COUNTING_EDGE_BASE_URL:-} CHICKEN_COUNTING_EDGE_TIMEOUT_SECONDS: ${CHICKEN_COUNTING_EDGE_TIMEOUT_SECONDS:-30} CHICKEN_COUNTING_EDGE_COUNTING_SYNC_ENABLED: ${CHICKEN_COUNTING_EDGE_COUNTING_SYNC_ENABLED:-false} CHICKEN_COUNTING_EDGE_MORTALITY_SYNC_ENABLED: ${CHICKEN_COUNTING_EDGE_MORTALITY_SYNC_ENABLED:-false} CHICKEN_COUNTING_EDGE_WEIGHT_SYNC_ENABLED: ${CHICKEN_COUNTING_EDGE_WEIGHT_SYNC_ENABLED:-false} BOOTSTRAP_API_KEY: ${BOOTSTRAP_API_KEY:-} BOOTSTRAP_ADMIN_USER: ${BOOTSTRAP_ADMIN_USER:-admin} BOOTSTRAP_ADMIN_PASSWORD: ${BOOTSTRAP_ADMIN_PASSWORD:-Pr04dm1n} BOOTSTRAP_STAFF_USER: ${BOOTSTRAP_STAFF_USER:-} BOOTSTRAP_STAFF_PASSWORD: ${BOOTSTRAP_STAFF_PASSWORD:-} extra_hosts: - "host.docker.internal:host-gateway" volumes: - api-media:/app/media depends_on: database: condition: service_healthy networks: - dashboard-cpsp-executive-network healthcheck: test: [ "CMD", "python", "-c", "import urllib.request; r=urllib.request.urlopen('http://127.0.0.1:8000/api/v1/health/'); exit(0 if r.status == 200 else 1)", ] interval: 30s timeout: 5s retries: 3 start_period: 60s cron: image: dashboard-cpsp-executive-cron build: context: . dockerfile: docker/Dockerfile.api container_name: dashboard-cpsp-executive-cron restart: unless-stopped entrypoint: ["/app/entrypoint-cron.sh"] environment: DEBUG: ${DEBUG:-false} SECRET_KEY: ${SECRET_KEY:-test-secret-key} ALLOWED_HOSTS: ${ALLOWED_HOSTS:-localhost,127.0.0.1,api,frontend,executive.local} DB_ENGINE: django.db.backends.postgresql DB_NAME: ${DB_NAME:-executive} DB_USER: ${DB_USER:-executive} DB_PASSWORD: ${DB_PASSWORD:-change_this_to_a_strong_password} DB_HOST: database DB_PORT: "5432" KARUNG_WEB_ADMIN_BASE_URL: ${KARUNG_WEB_ADMIN_BASE_URL:-http://host.docker.internal:5000} KARUNG_WEB_ADMIN_TIMEOUT_SECONDS: ${KARUNG_WEB_ADMIN_TIMEOUT_SECONDS:-30} KARUNG_WEB_ADMIN_SYNC_ENABLED: ${KARUNG_WEB_ADMIN_SYNC_ENABLED:-false} DASHBOARD_PUBLISH_HOUR: ${DASHBOARD_PUBLISH_HOUR:-17} DASHBOARD_PUBLISH_MINUTE: ${DASHBOARD_PUBLISH_MINUTE:-0} IOT_SYNC_ENABLED: ${IOT_SYNC_ENABLED:-false} IOT_API_BASE_URL: ${IOT_API_BASE_URL:-} IOT_FLOCK_ID_MAP: ${IOT_FLOCK_ID_MAP:-{}} IOT_SYNC_LOOKBACK_MINUTES: ${IOT_SYNC_LOOKBACK_MINUTES:-20} IOT_SYNC_MAX_PAGES: ${IOT_SYNC_MAX_PAGES:-10} CHICKEN_COUNTING_EDGE_BASE_URL: ${CHICKEN_COUNTING_EDGE_BASE_URL:-} CHICKEN_COUNTING_EDGE_TIMEOUT_SECONDS: ${CHICKEN_COUNTING_EDGE_TIMEOUT_SECONDS:-30} CHICKEN_COUNTING_EDGE_COUNTING_SYNC_ENABLED: ${CHICKEN_COUNTING_EDGE_COUNTING_SYNC_ENABLED:-false} CHICKEN_COUNTING_EDGE_MORTALITY_SYNC_ENABLED: ${CHICKEN_COUNTING_EDGE_MORTALITY_SYNC_ENABLED:-false} CHICKEN_COUNTING_EDGE_WEIGHT_SYNC_ENABLED: ${CHICKEN_COUNTING_EDGE_WEIGHT_SYNC_ENABLED:-false} extra_hosts: - "host.docker.internal:host-gateway" volumes: - api-media:/app/media depends_on: api: condition: service_healthy networks: - dashboard-cpsp-executive-network frontend: image: dashboard-cpsp-executive-frontend build: context: . dockerfile: docker/Dockerfile.web container_name: dashboard-cpsp-executive-frontend restart: unless-stopped ports: - "80:80" depends_on: api: condition: service_healthy networks: - dashboard-cpsp-executive-network healthcheck: test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:80/health"] interval: 30s timeout: 3s retries: 3 start_period: 10s networks: dashboard-cpsp-executive-network: driver: bridge volumes: db-data: driver: local api-media: driver: local