# OpenCRM – komplettes Setup: MariaDB + Backend/Frontend + Adminer
# Konfiguration über ./.env (siehe ./.env.example)
#
# Quick-Start (Compose v2):
#   cp .env.example .env       # Werte anpassen (Secrets rotieren!)
#   docker compose up -d       # erstes Mal: holt Images, baut Backend, startet alles
# Quick-Start (Compose v1, Legacy):
#   docker-compose up -d
#
# Browser:
#   http://localhost:${OPENCRM_PORT}     # CRM
#   http://localhost:${ADMINER_PORT}     # DB-UI
#
# Daten liegen alle unter ./data/* – Bind-Mounts statt Volumes (auf Wunsch).

#version: '3.8'

services:
  db:
    image: mariadb:10.11
    container_name: opencrm-db
    restart: unless-stopped
    environment:
      MARIADB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
      MARIADB_DATABASE: ${DB_NAME}
      MARIADB_USER: ${DB_USER}
      MARIADB_PASSWORD: ${DB_PASSWORD}
    ports:
      # Externe Erreichbarkeit für lokale DB-Tools (TablePlus etc.).
      # Auf 127.0.0.1 binden – kein public exposure.
      - "127.0.0.1:${DB_PORT:-3306}:3306"
    volumes:
      - ${DB_DATA_DIR:-./data/db}:/var/lib/mysql
    healthcheck:
      test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
      start_period: 20s
      interval: 10s
      timeout: 5s
      retries: 5

  opencrm:
    build:
      context: .
      dockerfile: backend/Dockerfile
    container_name: opencrm-app
    restart: unless-stopped
    depends_on:
      db:
        condition: service_healthy
    environment:
      # DATABASE_URL wird vom entrypoint.sh aus den DB_*-Komponenten gebaut –
      # mit encodeURIComponent für Passwörter mit Sonderzeichen ($, !, #, @, :,
      # / etc.). KEIN root für die App, sondern der App-User ${DB_USER}, den
      # MariaDB beim ersten Start automatisch mit GRANT ALL PRIVILEGES auf
      # ${DB_NAME}.* anlegt (über MARIADB_USER/MARIADB_PASSWORD).
      DB_HOST: db
      DB_PORT: 3306
      DB_NAME: ${DB_NAME}
      DB_USER: ${DB_USER}
      DB_PASSWORD: ${DB_PASSWORD}
      JWT_SECRET: ${JWT_SECRET}
      JWT_EXPIRES_IN: ${JWT_EXPIRES_IN:-15m}
      JWT_REFRESH_EXPIRES_IN: ${JWT_REFRESH_EXPIRES_IN:-7d}
      ENCRYPTION_KEY: ${ENCRYPTION_KEY}
      # Siegel für das Audit-Log: signiert jeden Eintrag mit einem Schlüssel,
      # der außerhalb der Datenbank liegt. Ohne Wert läuft alles normal weiter,
      # nur ungesiegelt (fail-safe). AUDIT_HMAC_KEY_OLD nur beim Wechsel füllen
      # (kommagetrennte Liste früherer Schlüssel).
      AUDIT_HMAC_KEY: ${AUDIT_HMAC_KEY:-}
      AUDIT_HMAC_KEY_OLD: ${AUDIT_HMAC_KEY_OLD:-}
      NODE_ENV: production
      PORT: 3001
      LISTEN_ADDR: 0.0.0.0
      CORS_ORIGINS: ${CORS_ORIGINS:-}
      HTTPS_ENABLED: ${HTTPS_ENABLED:-false}
      # SSRF-Schutz: bei Cloud-Deploys auf `true` setzen, sonst kann ein
      # eingeloggter Admin via Provider-Test-Connection interne Services
      # anpingen (127/10/172.16/192.168, ::1, localhost). On-Prem-Default
      # ist `false`, weil Plesk/Dovecot häufig lokal laufen. Cloud-
      # Metadata-Endpoints sind UNABHÄNGIG vom Flag immer geblockt.
      SSRF_BLOCK_PRIVATE_IPS: ${SSRF_BLOCK_PRIVATE_IPS:-false}
      RUN_SEED: ${RUN_SEED:-false}
    ports:
      - "${OPENCRM_PORT:-3010}:3001"
    volumes:
      # Bind-Mounts für persistente Daten unter ./data/
      - ${UPLOADS_DIR:-./data/uploads}:/app/uploads
      - ${FACTORY_DEFAULTS_DIR:-./data/factory-defaults}:/app/factory-defaults
      - ${BACKUPS_DIR:-./data/backups}:/app/prisma/backups
      # Auto-aktualisierter BLZ-/Bankdaten-Datensatz (Bundesbank-Bankleitzahlen)
      - ${BANKDATA_DIR:-./data/bankdata}:/app/bankdata

  # Optionaler Reverse-Proxy mit automatischem SSL – nur fuer Betreiber OHNE
  # eigenen Proxy. Wird standardmaessig NICHT angelegt.
  #
  # Einschalten ueber die .env (kein Auskommentieren noetig):
  #     COMPOSE_PROFILES=caddy
  # Danach reicht wie gewohnt `docker-compose up -d`. Alternativ einmalig per
  # Flag: `docker-compose --profile caddy up -d`.
  # Wer nginx / Nginx Proxy Manager / Traefik davor hat, laesst das Feld leer.
  caddy:
    image: caddy:2-alpine
    container_name: opencrm-caddy
    restart: unless-stopped
    profiles: ["caddy"]
    depends_on:
      - opencrm
    environment:
      DOMAIN: ${DOMAIN:-localhost}
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      # Zertifikate liegen wie alle Daten unter ./data/ – nicht loeschen,
      # sonst werden bei jedem Start neue Zertifikate angefordert
      # (Let's-Encrypt-Limits!).
      - ${CADDY_DIR:-./data/caddy}:/data
      - ${CADDY_CONFIG_DIR:-./data/caddy-config}:/config

  adminer:
    image: adminer:latest
    container_name: opencrm-adminer
    restart: unless-stopped
    depends_on:
      - db
    environment:
      ADMINER_DEFAULT_SERVER: db
      ADMINER_DESIGN: ${ADMINER_DESIGN:-pepa-linha}
    # Adminers offizieller entrypoint linkt nur Designs, deren CSS exakt
    # `adminer.css` heißt. Manche Designs (dracula, adminer-dark) haben aber
    # `adminer-dark.css`. Wir machen den Symlink generisch: erstes .css im
    # gewählten Design wird verlinkt. Danach übergeben wir an den originalen
    # entrypoint.sh.
    entrypoint:
      - /bin/sh
      - -c
      - >
        cd /var/www/html;
        if [ -n "$$ADMINER_DESIGN" ] && [ -d "designs/$$ADMINER_DESIGN" ]; then
          CSS=$$(ls designs/$$ADMINER_DESIGN/*.css 2>/dev/null | head -1);
          if [ -n "$$CSS" ]; then
            ln -sf "$$CSS" adminer.css;
            touch .adminer-init;
            echo "[adminer-bootstrap] Theme aktiv: $$ADMINER_DESIGN -> $$CSS";
          else
            echo "[adminer-bootstrap] Design '$$ADMINER_DESIGN' enthält kein CSS – nutze Default";
          fi;
        fi;
        exec entrypoint.sh docker-php-entrypoint "$$@"
      - --
    command: ["php", "-S", "[::]:8080", "-t", "/var/www/html"]
    ports:
      - "127.0.0.1:${ADMINER_PORT:-8090}:8080"
