# Hekoti stack: Postgres + Redis + app (+ optional LanguageTool).
#
# Faster image builds: `export DOCKER_BUILDKIT=1` (or set in ~/.docker/config.json `"features": { "buildkit": true }`).
#
# Database URL: you do not need DATABASE_URL in `.env` for Compose. The app
# container receives POSTGRES_* (defaults below) and `docker-entrypoint.sh`
# builds `DATABASE_URL` unless you set `DATABASE_URL` yourself (e.g. external DB).
#
# If you see Prisma `AuthenticationFailed`: ensure `DATABASE_URL` (if set) matches
# `POSTGRES_*`, or remove `DATABASE_URL` so the entrypoint builds it. If you
# changed `POSTGRES_PASSWORD` after Postgres was first created, reset the volume
# or align credentials with the existing cluster.
#
# Migrations: on each `hekoti-app` start, `docker-entrypoint.sh` runs
# `prisma migrate deploy`, затем `scripts/ensure-admin.ts` (если User пусто — admin/hehe), потом `node server.js`.
#
# Seed DB (tsx is a production dep so it exists in the image; no interactive npx):
#   docker compose exec hekoti-app npm run db:seed
#   docker compose exec hekoti-app npx --yes tsx prisma/seed.ts
#
# Optional `.env`: use `required: false` so `docker compose up` works with zero
# files; copy `.env.example` when you want to override secrets or app settings.
#
# Postgres troubleshooting:
# - Compose substitutes POSTGRES_* from a project `.env` file. A stray `POSTGRES_USER=postgres`
#   (from tutorials) initializes the DB with role `postgres` only — `hekoti_user` will NOT exist.
# - The official image does NOT create the `postgres` DB role when `POSTGRES_USER` is custom;
#   use `psql -U "$POSTGRES_USER" ...`, not blindly `-U postgres`.
# - Diagnose: `docker compose exec hekoti-postgres sh -c 'printenv POSTGRES_USER; psql -U "${POSTGRES_USER}" -d postgres -c "\\du"'`
#
# Reverse proxy (Nginx Proxy Manager и т.д.): создайте сеть один раз
#   docker network create proxy-network
# В NPM укажите upstream http://hekoti-app:3310 (имя контейнера резолвится в proxy-network).

services:
  hekoti-postgres:
    image: postgres:17-alpine
    container_name: hekoti-postgres
    restart: unless-stopped
    environment:
      # Defaults match hekoti-app / docker-entrypoint. Override only with matching DB volume or after recreate.
      POSTGRES_DB: ${POSTGRES_DB:-hekoti_db}
      POSTGRES_USER: ${POSTGRES_USER:-hekoti_user}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-hekoti_password}
    volumes:
      - hekoti_pg_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"]
      interval: 10s
      timeout: 5s
      retries: 10
    networks:
      - default

  hekoti-redis:
    image: redis:7-alpine
    container_name: hekoti-redis
    restart: unless-stopped
    command: ["redis-server", "--appendonly", "yes"]
    volumes:
      - hekoti_redis_data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 10
    networks:
      - default

  hekoti-languagetool:
    image: erikvl87/languagetool:latest
    container_name: hekoti-languagetool
    restart: unless-stopped
    # Optional: expose to host for debugging — "8010:8010"
    healthcheck:
      test: ["CMD-SHELL", "curl -sf http://127.0.0.1:8010/v2/languages >/dev/null || exit 1"]
      interval: 20s
      timeout: 10s
      retries: 15
      start_period: 120s
    networks:
      - default

  hekoti-app:
    image: hekoti-hekoti-app
    build:
      context: .
      dockerfile: Dockerfile
    container_name: hekoti-app
    restart: unless-stopped
    env_file:
      - path: .env
        required: false
    environment:
      # Must override Docker-injected HOSTNAME (container id) so Next binds 0.0.0.0, not a single NIC IP.
      HOSTNAME: "0.0.0.0"
      PORT: "3310"
      # Публичный URL (лучше https://домен за NPM). Cookie Secure также ставится по X-Forwarded-Proto от прокси.
      APP_URL: ${APP_URL:-http://localhost:3310}
      POSTGRES_DB: ${POSTGRES_DB:-hekoti_db}
      POSTGRES_USER: ${POSTGRES_USER:-hekoti_user}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-hekoti_password}
      REDIS_URL: ${REDIS_URL:-redis://hekoti-redis:6379}
      # Spellcheck API (`/api/spellcheck`); override with empty in `.env` to disable. LT has no `ports:` here — only app network.
      LANGUAGETOOL_URL: ${LANGUAGETOOL_URL:-http://hekoti-languagetool:8010}
      # Bootstrap админа после migrate (см. scripts/ensure-admin.ts). Сброс пароля: HEKOTI_FORCE_ADMIN_RESET=1.
      HEKOTI_ADMIN_EMAIL: ${HEKOTI_ADMIN_EMAIL:-admin}
      HEKOTI_ADMIN_PASSWORD: ${HEKOTI_ADMIN_PASSWORD:-hehe}
      HEKOTI_FORCE_ADMIN_RESET: ${HEKOTI_FORCE_ADMIN_RESET:-0}
      # Production (entrypoint sets HEKOTI_ENFORCE_PROD_SECRETS=1): задайте в `.env`, каждый ≥32 символов.
      # Сгенерировать: openssl rand -hex 32
      WEBHOOK_SECRET: ${WEBHOOK_SECRET:-}
      AUTH_PENDING_SECRET: ${AUTH_PENDING_SECRET:-}
      HEKOTI_TOTP_ENCRYPTION_KEY: ${HEKOTI_TOTP_ENCRYPTION_KEY:-}
    depends_on:
      hekoti-postgres:
        condition: service_healthy
      hekoti-redis:
        condition: service_healthy
    ports:
      - "3310:3310"
    volumes:
      - hekoti_uploads:/app/public/uploads
    # After HOSTNAME=0.0.0.0, loopback reaches the server; node is always present (no wget/curl in slim images).
    healthcheck:
      test:
        [
          "CMD",
          "node",
          "-e",
          "fetch('http://127.0.0.1:'+(process.env.PORT||'3310')+'/api/health/live').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))",
        ]
      interval: 15s
      timeout: 5s
      retries: 5
      start_period: 120s
    networks:
      - default
      - proxy-network

networks:
  default:
    driver: bridge
  proxy-network:
    external: true

volumes:
  hekoti_pg_data:
  hekoti_redis_data:
  hekoti_uploads:
