####################################################################
# ICDB — Customer Self-Hosted Stack (Docker Compose)
#
# Runs the ICDB server against PostgreSQL, with named volumes that survive
# container rebuilds. Use this once you have outgrown the single-binary
# `./icdb serve` shape on a laptop and want Postgres-grade backups,
# automatic restart, and stable identity keys.
#
# Quick start
# -----------
#   1.  mkdir ic && cd ic
#   2.  curl -O https://pid4.io/ic/customer-compose.yml
#   3.  Drop a `.env` next to it (template below).
#   4.  docker compose -f customer-compose.yml up -d
#   5.  Open http://localhost:8181 and sign in with ICDB_ADMIN_EMAIL and
#       the password printed in the first-boot banner (docker compose logs).
#
# Upgrading
# ---------
#   docker compose -f customer-compose.yml build
#   docker compose -f customer-compose.yml up -d
#
#   The build step re-downloads ICDB only when a new release has actually
#   been published; otherwise it completes from cache in a couple of
#   seconds. Your data lives in the named volumes and a rebuild does not
#   touch it. To stay on a fixed release instead, set ICDB_VERSION below.
#
# .env template
# -------------
#   # Required. NOTE: .env files are read literally — Docker does NOT run
#   # command substitution here. Generate the secrets first, then paste
#   # the resulting values in:
#   #     echo "POSTGRES_PASSWORD=$(openssl rand -hex 24)" >> .env
#   #     echo "ICDB_JWT_SECRET=$(openssl rand -hex 32)"  >> .env
#   ICDB_ADMIN_EMAIL=admin@yourcompany.example
#   ICDB_ADMIN_PASSWORD=change-me-or-leave-blank-for-random-on-first-boot
#   POSTGRES_PASSWORD=<paste 48 hex chars>
#   ICDB_JWT_SECRET=<paste 64 hex chars>
#
#   # Optional — pin the ICDB release the image is built from.
#   # Bare version, no leading 'v'. Defaults to the newest release.
#   # ICDB_VERSION=0.202.1
#
#   # Recommended for production
#   ICDB_PUBLIC_URL=https://ic.yourcompany.example
#   # ICDB_COOKIE_DOMAIN=.yourcompany.example     # cross-subdomain cookies
#
#   # Optional — federate with the hosted pid4 consortium broker
#   # ICDB_BROKER_URL=https://broker.ic.pid4.io
#
#   # Optional — transactional email + OAuth
#   # ICDB_RESEND_API_KEY=re_...
#   # ICDB_GOOGLE_CLIENT_ID=...
#   # ICDB_GOOGLE_CLIENT_SECRET=...
#
# Backups
# -------
#   PostgreSQL volume (ic-postgres) holds the threat-intel database.
#     docker exec ic-postgres-1 pg_dump -U ic ic > backup-$(date -I).sql
#
#   ic-data volume holds the Ed25519 identity keys and the error log.
#   Lose these and your tenant can no longer cryptographically attribute
#   shares it has already published into a consortium.
#     docker run --rm -v ic_ic-data:/d -v $PWD:/out alpine \
#       tar czf /out/ic-data-$(date -I).tgz -C /d .
####################################################################

services:

  postgres:
    image: postgres:17-alpine
    restart: unless-stopped
    environment:
      POSTGRES_USER: ic
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required — see .env template at the top of this file}
      POSTGRES_DB: ic
    volumes:
      - ic-postgres:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ic"]
      interval: 10s
      retries: 5

  server:
    # Built locally from the same signed binary the downloads page serves,
    # so what runs in the container cannot drift from the release you can
    # verify by hand. The first `up` spends roughly 30 extra seconds
    # fetching it; later rebuilds come from cache unless a new release has
    # been published.
    #
    # `dockerfile_inline` is what keeps this a single-file install. It needs
    # Docker Compose v2.19 or newer — on older versions, move the block
    # below into a file named `Dockerfile` beside this one and replace this
    # whole `build:` section with `build: .`.
    build:
      context: .
      args:
        ICDB_VERSION: ${ICDB_VERSION:-latest}
      dockerfile_inline: |
        FROM alpine:3 AS fetch
        ARG ICDB_VERSION=latest
        ARG TARGETARCH
        RUN apk add --no-cache curl xz ca-certificates
        WORKDIR /stage

        # Fetching the checksum file with ADD keys this layer on its
        # contents, which is what makes `build` correct without --no-cache:
        # an unchanged release rebuilds from cache, a new release
        # invalidates and re-downloads on its own.
        ADD https://pid4.io/ic/$${ICDB_VERSION}/SHA256SUMS /stage/SHA256SUMS

        RUN set -eux; \
            arch="$${TARGETARCH:-amd64}"; \
            file="icdb-linux-$${arch}.tar.xz"; \
            curl -fsSL -o "$$file" "https://pid4.io/ic/$${ICDB_VERSION}/$$file"; \
            grep " $$file$$" SHA256SUMS > want.sha256; \
            test -s want.sha256; \
            sha256sum -c want.sha256; \
            tar -xJf "$$file"; \
            test -x ./icdb
        # The checksum catches a truncated or corrupted download. `icdb update`
        # additionally verifies the release's Ed25519 signature.

        FROM alpine:3
        RUN apk add --no-cache ca-certificates tzdata
        COPY --from=fetch /stage/icdb /usr/local/bin/icdb
        COPY --from=fetch /stage/THIRD-PARTY-NOTICES /usr/share/doc/icdb/THIRD-PARTY-NOTICES
        WORKDIR /data
        EXPOSE 8181
    restart: unless-stopped
    ports:
      - "8181:8181"
    volumes:
      # Identity (Ed25519) + encryption (X25519) keys + the append-only
      # error log (errors.log; see --error-log below). One volume keeps
      # the backup story simple: tar this dir and you've captured every
      # piece of state that does not live in Postgres.
      - ic-data:/data
    environment:
      # The flags below read straight from these — the binary accepts
      # every --flag as an ICDB_<UPPER_SNAKE> env var. Override via .env
      # without editing this file. Empty values are tolerated where the
      # flag itself is optional (see comment column below).
      ICDB_ADMIN_EMAIL:        ${ICDB_ADMIN_EMAIL:?ICDB_ADMIN_EMAIL is required}
      ICDB_ADMIN_PASSWORD:     ${ICDB_ADMIN_PASSWORD:-}            # empty = generate-and-print on first boot
      ICDB_JWT_SECRET:         ${ICDB_JWT_SECRET:?ICDB_JWT_SECRET is required for stable sessions across restarts; run `openssl rand -hex 32`}
      ICDB_PUBLIC_URL:         ${ICDB_PUBLIC_URL:-}                # canonical URL the server emits in invite/oauth links
      ICDB_COOKIE_DOMAIN:      ${ICDB_COOKIE_DOMAIN:-}             # e.g. .yourco.example for cross-subdomain
      ICDB_BROKER_URL:         ${ICDB_BROKER_URL:-}                # connect to consortium broker
      ICDB_RESEND_API_KEY:     ${ICDB_RESEND_API_KEY:-}            # transactional email (empty = disabled)
      # Passed as an env var rather than a --flag so the credential never
      # lands in the container's argv, where `docker inspect` would expose it.
      ICDB_DB_PASSWORD:        ${POSTGRES_PASSWORD}
      ICDB_GOOGLE_CLIENT_ID:     ${ICDB_GOOGLE_CLIENT_ID:-}
      ICDB_GOOGLE_CLIENT_SECRET: ${ICDB_GOOGLE_CLIENT_SECRET:-}
    command:
      - "icdb"
      - "serve"
      - "--host=0.0.0.0"
      - "--port=8181"
      - "--db-host=postgres"
      - "--db-port=5432"
      - "--db-username=ic"
      - "--db-name=ic"
      - "--db-sslmode=disable"
      - "--identity-key-path=/data/identity.pem"
      - "--encryption-key-path=/data/encryption.pem"
      - "--error-log=/data/errors.log"
    depends_on:
      postgres:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "wget", "-qO-", "http://127.0.0.1:8181/livez"]
      interval: 5s
      timeout: 3s
      retries: 10
      start_period: 15s

volumes:
  ic-postgres:
  ic-data:
