Ctrl K
ComunidadGuías…

docker-compose.yml

Rama master · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# DOMINUS — Docker Compose for development and community deployment.
#
# Community edition (SQLite, single-user): all services start by default.
#   docker compose up -d
#
# DOMINUS Cloud (PostgreSQL, multi-tenant): use the production overlay,
# which adds postgres, redis and the monitoring stack:
#   docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
#
# Production (with .env file for secrets):
#   docker compose --env-file .env up -d
#
# Service note:
#   api + worker + scheduler start by default — the job-queue worker and
#   the background scheduler are required for async runs, backups and
#   renewal checks (ADR-0023). This file intentionally has no
#   PostgreSQL/Redis: the community edition runs on SQLite at €0 infra
#   cost. The production overlay adds the data stores and monitoring.

services:
  api:
    build:
      context: .
      dockerfile: Dockerfile
      target: api
    image: dominus-api:latest
    ports:
      # Bind to loopback by default: the API is unauthenticated on /
      # health only, and exposing the app port on the host network
      # without a reverse proxy is a firewall dependency the operator
      # must opt into explicitly. Override with 0.0.0.0:${PORT}:3000
      # when a LAN-exposed deployment is intended.
      - "127.0.0.1:${PORT:-3000}:3000"
    volumes:
      # DATA_DIR lets the local Docker gate run against a throwaway database
      # instead of the developer's ./data (a stale schema there makes the
      # smoke fail for reasons that have nothing to do with the image).
      - ${DATA_DIR:-./data}:/app/data
    environment:
      - NODE_ENV=${NODE_ENV:-production}
      - DATABASE_PATH=/app/data/dominus.db
      - DATABASE_URL=${DATABASE_URL:-}
      - PORT=${PORT:-3000}
      - HOST=0.0.0.0
      - LOG_LEVEL=${LOG_LEVEL:-info}
      - LOG_PRETTY=${LOG_PRETTY:-false}
      - KEYWORD_DATA_PATH=${KEYWORD_DATA_PATH:-}
      - COMPS_DATA_PATH=${COMPS_DATA_PATH:-}
      - EUIPO_CLIENT_ID=${EUIPO_CLIENT_ID:-}
      - EUIPO_CLIENT_SECRET=${EUIPO_CLIENT_SECRET:-}
      - USPTO_SEARCH_URL=${USPTO_SEARCH_URL:-}
      - EUIPO_AUTH_URL=${EUIPO_AUTH_URL:-}
      - EUIPO_API_URL=${EUIPO_API_URL:-}
      - TM_CACHE_TTL_DAYS=${TM_CACHE_TTL_DAYS:-7}
      - SCORING_WEIGHTS_OVERRIDE=${SCORING_WEIGHTS_OVERRIDE:-}
      - DNS_BULK_CONCURRENCY=${DNS_BULK_CONCURRENCY:-10}
      - WHOIS_LOOKUP_TIMEOUT=${WHOIS_LOOKUP_TIMEOUT:-10000}
      - BUY_MAX_ABSOLUTE_CAP=${BUY_MAX_ABSOLUTE_CAP:-0}
      - TRUST_PROXY_DEPTH=${TRUST_PROXY_DEPTH:-0}
      - FRONTEND_DIST_PATH=./dist/web
      # Boot-required: HOST below is 0.0.0.0, so the API refuses to start
      # without authentication (fail-closed guard in src/index.ts). Without
      # this guard the api container crash-loops through the ~30 s Unbound
      # readiness wait on every restart, which looks like a hang to an
      # operator. Docker Compose resolves this :? guard and aborts `up -d`
      # with the fix in the message. The message intentionally contains no
      # "=" and no shell substitution: Compose parses list-form environment
      # entries by splitting on the first "=", so either would corrupt it.
      - API_KEYS=${API_KEYS:?API_KEYS is required. Generate one with openssl rand -hex 32, then export it as admin=<key>}
      - DROP_SCORE_THRESHOLD=${DROP_SCORE_THRESHOLD:-25}
      - DROP_RENEWAL_HORIZON_DAYS=${DROP_RENEWAL_HORIZON_DAYS:-60}
      - WORKER_ENABLED=false
      - SCHEDULER_ENABLED=false
      - REDIS_URL=${REDIS_URL:-}
      - PURCHASE_AUTO_APPROVAL=${PURCHASE_AUTO_APPROVAL:-never}
      # Unbound via the docker-compose.unbound.yml overlay (ADR-0072/0075).
      # The overlay provides the Unbound sidecar and injects
      # DNS_UNBOUND_HOSTS=unbound:5300 plus DNS_UNBOUND_STRICT=true.
      # Without the overlay, DNS_UNBOUND_STRICT falls back to its
      # context-aware default (ADR-0076): community edition uses the
      # Node.js fallback for non-Available verdicts, cloud stays strict.
      # Fallback never serves Available verdicts (ADR-0002 conservatism).
      - DNS_UNBOUND_ENABLED=true
      - DNSSEC_MODE=strict
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"
        compress: "true"
    restart: unless-stopped

  worker:
    build:
      context: .
      dockerfile: Dockerfile
      target: worker
    image: dominus-worker:latest
    depends_on:
      api:
        condition: service_healthy
    volumes:
      - ${DATA_DIR:-./data}:/app/data
      - backups:/backups
    environment:
      - NODE_ENV=${NODE_ENV:-production}
      - DATABASE_PATH=/app/data/dominus.db
      - DATABASE_URL=${DATABASE_URL:-}
      - LOG_LEVEL=${LOG_LEVEL:-info}
      - KEYWORD_DATA_PATH=${KEYWORD_DATA_PATH:-}
      - COMPS_DATA_PATH=${COMPS_DATA_PATH:-}
      - EUIPO_CLIENT_ID=${EUIPO_CLIENT_ID:-}
      - EUIPO_CLIENT_SECRET=${EUIPO_CLIENT_SECRET:-}
      - USPTO_SEARCH_URL=${USPTO_SEARCH_URL:-}
      - EUIPO_AUTH_URL=${EUIPO_AUTH_URL:-}
      - EUIPO_API_URL=${EUIPO_API_URL:-}
      - TM_CACHE_TTL_DAYS=${TM_CACHE_TTL_DAYS:-7}
      - SCORING_WEIGHTS_OVERRIDE=${SCORING_WEIGHTS_OVERRIDE:-}
      - DNS_BULK_CONCURRENCY=${DNS_BULK_CONCURRENCY:-10}
      - WHOIS_LOOKUP_TIMEOUT=${WHOIS_LOOKUP_TIMEOUT:-10000}
      - BUY_MAX_ABSOLUTE_CAP=${BUY_MAX_ABSOLUTE_CAP:-0}
      - DROP_SCORE_THRESHOLD=${DROP_SCORE_THRESHOLD:-25}
      - DROP_RENEWAL_HORIZON_DAYS=${DROP_RENEWAL_HORIZON_DAYS:-60}
      - WORKER_ENABLED=true
      - SCHEDULER_ENABLED=false
      - WORKER_CONCURRENCY=${WORKER_CONCURRENCY:-2}
      - JOB_QUEUE_POLL_INTERVAL_MS=${JOB_QUEUE_POLL_INTERVAL_MS:-1000}
      - BACKUP_DIR=${BACKUP_DIR:-/backups}
      - REDIS_URL=${REDIS_URL:-}
      # Unbound via the docker-compose.unbound.yml overlay (ADR-0072/0075).
      # The overlay provides the Unbound sidecar and injects
      # DNS_UNBOUND_HOSTS=unbound:5300 plus DNS_UNBOUND_STRICT=true.
      # Without the overlay, DNS_UNBOUND_STRICT falls back to its
      # context-aware default (ADR-0076): community edition uses the
      # Node.js fallback for non-Available verdicts, cloud stays strict.
      # Fallback never serves Available verdicts (ADR-0002 conservatism).
      - DNS_UNBOUND_ENABLED=true
      - DNSSEC_MODE=strict
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"
        compress: "true"
    restart: unless-stopped

  scheduler:
    build:
      context: .
      dockerfile: Dockerfile
      target: scheduler
    image: dominus-scheduler:latest
    depends_on:
      api:
        condition: service_healthy
    volumes:
      - ${DATA_DIR:-./data}:/app/data
      - backups:/backups
    environment:
      - NODE_ENV=${NODE_ENV:-production}
      - DATABASE_PATH=/app/data/dominus.db
      - DATABASE_URL=${DATABASE_URL:-}
      - LOG_LEVEL=${LOG_LEVEL:-info}
      - KEYWORD_DATA_PATH=${KEYWORD_DATA_PATH:-}
      - COMPS_DATA_PATH=${COMPS_DATA_PATH:-}
      - EUIPO_CLIENT_ID=${EUIPO_CLIENT_ID:-}
      - EUIPO_CLIENT_SECRET=${EUIPO_CLIENT_SECRET:-}
      - USPTO_SEARCH_URL=${USPTO_SEARCH_URL:-}
      - EUIPO_AUTH_URL=${EUIPO_AUTH_URL:-}
      - EUIPO_API_URL=${EUIPO_API_URL:-}
      - TM_CACHE_TTL_DAYS=${TM_CACHE_TTL_DAYS:-7}
      - SCORING_WEIGHTS_OVERRIDE=${SCORING_WEIGHTS_OVERRIDE:-}
      - DNS_BULK_CONCURRENCY=${DNS_BULK_CONCURRENCY:-10}
      - WHOIS_LOOKUP_TIMEOUT=${WHOIS_LOOKUP_TIMEOUT:-10000}
      - BUY_MAX_ABSOLUTE_CAP=${BUY_MAX_ABSOLUTE_CAP:-0}
      - DROP_SCORE_THRESHOLD=${DROP_SCORE_THRESHOLD:-25}
      - DROP_RENEWAL_HORIZON_DAYS=${DROP_RENEWAL_HORIZON_DAYS:-60}
      - WORKER_ENABLED=false
      - SCHEDULER_ENABLED=true
      - SCHEDULER_BACKUP_CRON=${SCHEDULER_BACKUP_CRON:-0 4 * * *}
      - SCHEDULER_PRUNE_CRON=${SCHEDULER_PRUNE_CRON:-0 10 1 * *}
      - BACKUP_DIR=${BACKUP_DIR:-/backups}
      - REDIS_URL=${REDIS_URL:-}
      # Unbound via the docker-compose.unbound.yml overlay (ADR-0072/0075).
      # The overlay provides the Unbound sidecar and injects
      # DNS_UNBOUND_HOSTS=unbound:5300 plus DNS_UNBOUND_STRICT=true.
      # Without the overlay, DNS_UNBOUND_STRICT falls back to its
      # context-aware default (ADR-0076): community edition uses the
      # Node.js fallback for non-Available verdicts, cloud stays strict.
      # Fallback never serves Available verdicts (ADR-0002 conservatism).
      - DNS_UNBOUND_ENABLED=true
      - DNSSEC_MODE=strict
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"
        compress: "true"
    restart: unless-stopped

# Dedicated backups volume: keeps VACUUM INTO/pg_dump backups off the
# disk that holds dominus.db (isolation from DB write amplification and
# from accidental wipes of ./data). The image pre-creates /backups owned
# by the non-root dominus user. For off-disk durability, mount an
# external drive at /backups instead (see docs/deployment/README.md).
volumes:
  backups: