# =============================================================================
# jasonwoltje.com — Docker Swarm / Portainer stack
# =============================================================================
#
# Deploy target: w-docker0 (10.1.1.45), Portainer endpoint 7.
# Routing:
#   jasonwoltje.com / www.jasonwoltje.com -> web (Next.js + Payload CMS)
#
# Ingress pattern (mirrors MosaicStack):
#   Edge Traefik (10.1.1.43) terminates TLS
#     -> per-swarm Traefik on w-docker0 on entrypoint "web" (HTTP)
#     -> web:3000
#
# Usage (Portainer):
#   Stacks -> Add Stack -> Git repository
#     URL: https://git.mosaicstack.dev/jason.woltje/professional-website
#     Compose path: docker-compose.swarm.yml
#   Env vars: see .env.example (all required unless marked optional)
#   Deploy
#
# Image tag rule: WEB_IMAGE_TAG MUST be an immutable tag (sha-<8> or vX.Y.Z).
# Never point this stack at `latest`.
# =============================================================================

services:
  web:
    image: git.mosaicstack.dev/jason.woltje/professional-website:${WEB_IMAGE_TAG}
    environment:
      DATABASE_URI: postgresql://${PAYLOAD_POSTGRES_USER}:${PAYLOAD_POSTGRES_PASSWORD}@jasonwoltje_postgres:5432/${PAYLOAD_POSTGRES_DB}
      PAYLOAD_SECRET: ${PAYLOAD_SECRET}
      PAYLOAD_PUBLIC_SERVER_URL: https://${SITE_DOMAIN:-jasonwoltje.com}
      NEXT_PUBLIC_SITE_URL: https://${SITE_DOMAIN:-jasonwoltje.com}
      NEXT_PUBLIC_BUILD_SHA: ${WEB_IMAGE_TAG}
      NEXT_PUBLIC_BUILD_REV: ${WEB_IMAGE_TAG}
      TURNSTILE_SITE_KEY: ${TURNSTILE_SITE_KEY:-}
      TURNSTILE_SECRET_KEY: ${TURNSTILE_SECRET_KEY:-}
      NEXT_PUBLIC_UMAMI_SRC: ${NEXT_PUBLIC_UMAMI_SRC:-}
      NEXT_PUBLIC_UMAMI_WEBSITE_ID: ${NEXT_PUBLIC_UMAMI_WEBSITE_ID:-}
      RESEND_API_KEY: ${RESEND_API_KEY:-}
      RESEND_FROM: ${RESEND_FROM:-no-reply@jasonwoltje.com}
      RESEND_TO: ${RESEND_TO:-jason@diversecanvas.com}
      MAUTIC_FORM_URL: ${MAUTIC_FORM_URL:-}
    volumes:
      - media:/app/media
    healthcheck:
      test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:3000/api/health || exit 1"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 60s
    networks:
      - internal
      - traefik-public
    deploy:
      replicas: 1
      update_config:
        parallelism: 1
        delay: 30s
        order: start-first
      restart_policy:
        condition: on-failure
        delay: 5s
        max_attempts: 5
        window: 120s
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.jasonwoltje.rule=Host(`${SITE_DOMAIN:-jasonwoltje.com}`) || Host(`www.${SITE_DOMAIN:-jasonwoltje.com}`)"
        - "traefik.http.routers.jasonwoltje.entrypoints=web"
        - "traefik.http.services.jasonwoltje.loadbalancer.server.port=3000"
        # www -> apex 301
        - "traefik.http.middlewares.jasonwoltje-www-redirect.redirectregex.regex=^https?://www\\.${SITE_DOMAIN:-jasonwoltje.com}/(.*)"
        - "traefik.http.middlewares.jasonwoltje-www-redirect.redirectregex.replacement=https://${SITE_DOMAIN:-jasonwoltje.com}/$${1}"
        - "traefik.http.middlewares.jasonwoltje-www-redirect.redirectregex.permanent=true"
        - "traefik.http.routers.jasonwoltje.middlewares=jasonwoltje-www-redirect"

  postgres:
    image: postgres:17-alpine
    environment:
      POSTGRES_DB: ${PAYLOAD_POSTGRES_DB:-payload}
      POSTGRES_USER: ${PAYLOAD_POSTGRES_USER:-payload}
      POSTGRES_PASSWORD: ${PAYLOAD_POSTGRES_PASSWORD}
    volumes:
      - postgres-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER}"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s
    networks:
      - internal
    deploy:
      replicas: 1
      restart_policy:
        condition: on-failure
        delay: 5s
        max_attempts: 5
      placement:
        constraints:
          - node.role == manager

volumes:
  postgres-data:
  media:

networks:
  internal:
    driver: overlay
  traefik-public:
    external: true
