# Base registry for mirrored images (override with environment variable)
x-registry: &registry
  REGISTRY_MIRRORS: ${REGISTRY_MIRRORS:-git.motovaultpro.com/egullickson/mirrors}

services:
  # Traefik - Service Discovery and Load Balancing
  mvp-traefik:
    image: ${REGISTRY_MIRRORS:-git.motovaultpro.com/egullickson/mirrors}/traefik:v3.6
    container_name: mvp-traefik
    restart: unless-stopped
    command:
      - --configFile=/etc/traefik/traefik.yml
    environment:
      LOG_LEVEL: debug
      CLOUDFLARE_DNS_API_TOKEN_FILE: /run/secrets/cloudflare-dns-token
    ports:
      - "80:80"
      - "443:443"
      - "8080:8080"  # Dashboard
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./config/traefik/traefik.yml:/etc/traefik/traefik.yml:ro
      - ./config/traefik/dynamic:/etc/traefik/dynamic:ro
      - ./certs:/certs:ro
      - ./data/traefik:/data
      - ./secrets/app/cloudflare-dns-token.txt:/run/secrets/cloudflare-dns-token:ro
    networks:
      frontend:
        ipv4_address: 10.96.1.50
      backend:
    healthcheck:
      test: ["CMD", "traefik", "healthcheck"]
      interval: 5s
      timeout: 5s
      retries: 3
      start_period: 10s
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.traefik-dashboard.rule=Host(`traefik.motovaultpro.local`)"
      - "traefik.http.routers.traefik-dashboard.tls=true"
      - "traefik.http.services.traefik-dashboard.loadbalancer.server.port=8080"
      - "traefik.http.middlewares.dashboard-auth.basicauth.users=admin:$$2y$$10$$foobar"
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"

  # Application Services - Frontend SPA
  mvp-frontend:
    build:
      context: ./frontend
      dockerfile: Dockerfile
      cache_from:
        - node:lts-alpine
        - nginx:alpine
      args:
        VITE_AUTH0_DOMAIN: ${VITE_AUTH0_DOMAIN:-motovaultpro.us.auth0.com}
        VITE_AUTH0_CLIENT_ID: ${VITE_AUTH0_CLIENT_ID:-yspR8zdnSxmV8wFIghHynQ08iXAPoQJ3}
        VITE_AUTH0_AUDIENCE: ${VITE_AUTH0_AUDIENCE:-https://api.motovaultpro.com}
        VITE_API_BASE_URL: ${VITE_API_BASE_URL:-/api}
        VITE_STRIPE_PUBLISHABLE_KEY: ${VITE_STRIPE_PUBLISHABLE_KEY:-pk_live_51Sr2yQJk87CpWj04YNBIaUWUtnJjeVTgk5NqHdpjqxgsbjy3dMKkIsqhjcpSkCzp3KvLi23BGgxhwV021EnEW3H400HhPYVyfN}
    container_name: mvp-frontend
    restart: unless-stopped
    environment:
      VITE_API_BASE_URL: /api
      VITE_AUTH0_DOMAIN: ${VITE_AUTH0_DOMAIN:-motovaultpro.us.auth0.com}
      VITE_AUTH0_CLIENT_ID: ${VITE_AUTH0_CLIENT_ID:-yspR8zdnSxmV8wFIghHynQ08iXAPoQJ3}
      VITE_AUTH0_AUDIENCE: ${VITE_AUTH0_AUDIENCE:-https://api.motovaultpro.com}
      SECRETS_DIR: /run/secrets
    volumes:
      - ./secrets/app/google-maps-api-key.txt:/run/secrets/google-maps-api-key:ro
      - ./secrets/app/google-maps-map-id.txt:/run/secrets/google-maps-map-id:ro
    networks:
      - frontend
    depends_on:
      - mvp-backend
    healthcheck:
      test: ["CMD-SHELL", "curl -sf http://localhost:3000 || exit 1"]
      interval: 5s
      timeout: 5s
      retries: 3
      start_period: 10s
    labels:
      - "traefik.enable=true"
      - traefik.docker.network=motovaultpro_frontend
      - "traefik.http.routers.mvp-frontend.rule=(Host(`motovaultpro.com`) || Host(`www.motovaultpro.com`)) && !PathPrefix(`/api`)"
      - "traefik.http.routers.mvp-frontend.entrypoints=websecure"
      - "traefik.http.routers.mvp-frontend.tls=true"
      - "traefik.http.routers.mvp-frontend.tls.certresolver=letsencrypt"
      - "traefik.http.routers.mvp-frontend.priority=10"
      - "traefik.http.services.mvp-frontend.loadbalancer.server.port=3000"
      - "traefik.http.services.mvp-frontend.loadbalancer.healthcheck.path=/"
      - "traefik.http.services.mvp-frontend.loadbalancer.healthcheck.interval=30s"
      - "traefik.http.services.mvp-frontend.loadbalancer.passhostheader=true"
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"

  # Application Services - Backend API
  mvp-backend:
    build:
      context: .
      dockerfile: backend/Dockerfile
      cache_from:
        - node:lts-alpine
    container_name: mvp-backend
    restart: unless-stopped
    environment:
      # Core configuration (K8s pattern)
      NODE_ENV: production
      CONFIG_PATH: /app/config/production.yml
      SECRETS_DIR: /run/secrets
      LOG_LEVEL: debug
      # Service references
      DATABASE_HOST: mvp-postgres
      REDIS_HOST: mvp-redis
      #Stripe Variables
      STRIPE_PRO_MONTHLY_PRICE_ID: prod_Toj6BG9Z9JwREl
      STRIPE_PRO_YEARLY_PRICE_ID: prod_Toj8oo0RpVBQmB
      STRIPE_ENTERPRISE_MONTHLY_PRICE_ID: prod_Toj8xGEui9jl6j
      STRIPE_ENTERPRISE_YEARLY_PRICE_ID: prod_Toj9A7A773xrdn
    volumes:
      # Configuration files (K8s ConfigMap equivalent)
      - ./config/app/production.yml:/app/config/production.yml:ro
      - ./config/shared/production.yml:/app/config/shared.yml:ro
      # Secrets (K8s Secrets equivalent)
      - ./secrets/app/postgres-password.txt:/run/secrets/postgres-password:ro
      - ./secrets/app/auth0-client-secret.txt:/run/secrets/auth0-client-secret:ro
      - ./secrets/app/google-maps-api-key.txt:/run/secrets/google-maps-api-key:ro
      - ./secrets/app/google-maps-map-id.txt:/run/secrets/google-maps-map-id:ro
      - ./secrets/app/resend-api-key.txt:/run/secrets/resend-api-key:ro
      - ./secrets/app/auth0-management-client-id.txt:/run/secrets/auth0-management-client-id:ro
      - ./secrets/app/auth0-management-client-secret.txt:/run/secrets/auth0-management-client-secret:ro
      - ./secrets/app/stripe-secret-key.txt:/run/secrets/stripe-secret-key:ro
      - ./secrets/app/stripe-webhook-secret.txt:/run/secrets/stripe-webhook-secret:ro
      # Filesystem storage for documents
      - ./data/documents:/app/data/documents
      # Filesystem storage for backups
      - ./data/backups:/app/data/backups
    networks:
      - backend
      - database
    depends_on:
      - mvp-postgres
      - mvp-redis
    healthcheck:
      test:
        - CMD-SHELL
        - node -e "require('http').get('http://localhost:3001/health', r => process.exit(r.statusCode===200?0:1)).on('error', () => process.exit(1))"
      interval: 5s
      timeout: 5s
      retries: 5
      start_period: 180s
    labels:
      - "traefik.enable=true"
      - "traefik.docker.network=motovaultpro_backend"
      # Main API router
      - "traefik.http.routers.mvp-backend.rule=(Host(`motovaultpro.com`) || Host(`www.motovaultpro.com`)) && PathPrefix(`/api`)"
      - "traefik.http.routers.mvp-backend.entrypoints=websecure"
      - "traefik.http.routers.mvp-backend.tls=true"
      - "traefik.http.routers.mvp-backend.tls.certresolver=letsencrypt"
      - "traefik.http.routers.mvp-backend.priority=20"
      # Health check router (bypass auth)
      - "traefik.http.routers.mvp-backend-health.rule=(Host(`motovaultpro.com`) || Host(`www.motovaultpro.com`)) && Path(`/api/health`)"
      - "traefik.http.routers.mvp-backend-health.entrypoints=websecure"
      - "traefik.http.routers.mvp-backend-health.tls=true"
      - "traefik.http.routers.mvp-backend-health.tls.certresolver=letsencrypt"
      - "traefik.http.routers.mvp-backend-health.priority=30"
      # Service configuration
      - "traefik.http.services.mvp-backend.loadbalancer.server.port=3001"
      - "traefik.http.services.mvp-backend.loadbalancer.healthcheck.path=/health"
      - "traefik.http.services.mvp-backend.loadbalancer.healthcheck.interval=30s"
      - "traefik.http.services.mvp-backend.loadbalancer.healthcheck.timeout=10s"
      - "traefik.http.services.mvp-backend.loadbalancer.passhostheader=true"
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"

  # Application Services - OCR Processing
  mvp-ocr:
    build:
      context: ./ocr
      dockerfile: Dockerfile
    container_name: mvp-ocr
    restart: unless-stopped
    environment:
      LOG_LEVEL: debug
      REDIS_HOST: mvp-redis
      REDIS_PORT: 6379
      REDIS_DB: 1
      # OCR engine configuration (PaddleOCR primary, cloud fallback optional)
      OCR_PRIMARY_ENGINE: paddleocr
      OCR_FALLBACK_ENGINE: ${OCR_FALLBACK_ENGINE:-none}
      OCR_FALLBACK_THRESHOLD: ${OCR_FALLBACK_THRESHOLD:-0.6}
      GOOGLE_VISION_KEY_PATH: /run/secrets/google-vision-key.json
    volumes:
      - /tmp/vin-debug:/tmp/vin-debug
      # Optional: Uncomment to enable Google Vision cloud fallback.
      # Requires: secrets/app/google-vision-key.json and OCR_FALLBACK_ENGINE=google_vision
      # - ./secrets/app/google-vision-key.json:/run/secrets/google-vision-key.json:ro
    networks:
      - backend
      - database
    depends_on:
      - mvp-redis
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
      interval: 5s
      timeout: 5s
      retries: 3
      start_period: 15s
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"

  # Database Services - Application PostgreSQL
  mvp-postgres:
    image: ${REGISTRY_MIRRORS:-git.motovaultpro.com/egullickson/mirrors}/postgres:18-alpine
    container_name: mvp-postgres
    restart: unless-stopped
    environment:
      POSTGRES_DB: motovaultpro
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD_FILE: /run/secrets/postgres-password
      POSTGRES_INITDB_ARGS: --encoding=UTF8
      LOG_LEVEL: debug
      POSTGRES_LOG_STATEMENT: all
      POSTGRES_LOG_MIN_DURATION_STATEMENT: 0
      PGDATA: /var/lib/postgresql/data
    volumes:
      - mvp_postgres_data:/var/lib/postgresql/data
      # Secrets (K8s Secrets equivalent)
      - ./secrets/app/postgres-password.txt:/run/secrets/postgres-password:ro
    networks:
      - database
    ports:
      - "5432:5432"  # Development access only
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 5s
      retries: 5
      start_period: 15s
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"

  # Database Services - Application Redis
  mvp-redis:
    image: ${REGISTRY_MIRRORS:-git.motovaultpro.com/egullickson/mirrors}/redis:8.4-alpine
    container_name: mvp-redis
    restart: unless-stopped
    command: redis-server --appendonly yes --loglevel ${LOG_LEVEL:-info}
    environment:
      LOG_LEVEL: debug
    volumes:
      - mvp_redis_data:/data
    networks:
      - database
    ports:
      - "6379:6379"  # Development access only
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 5s
      timeout: 5s
      retries: 5
      start_period: 5s
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"

  # Log Aggregation - Loki
  mvp-loki:
    image: ${REGISTRY_MIRRORS:-git.motovaultpro.com/egullickson/mirrors}/grafana/loki:3.6.1
    container_name: mvp-loki
    restart: unless-stopped
    volumes:
      - ./config/loki/config.yml:/etc/loki/config.yml:ro
      - mvp_loki_data:/loki
    command: -config.file=/etc/loki/config.yml
    networks:
      - backend
    healthcheck:
      # Loki 3.x uses a distroless image with no shell or HTTP client.
      # Disable in-container healthcheck; Alloy and Grafana verify connectivity.
      disable: true
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"

  # Log Aggregation - Alloy (replaces Promtail)
  mvp-alloy:
    image: ${REGISTRY_MIRRORS:-git.motovaultpro.com/egullickson/mirrors}/grafana/alloy:v1.12.2
    container_name: mvp-alloy
    restart: unless-stopped
    volumes:
      - ./config/alloy/config.alloy:/etc/alloy/config.alloy
      - /var/lib/docker/containers:/var/lib/docker/containers:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
    command:
      - run
      - --server.http.listen-addr=0.0.0.0:12345
      - --storage.path=/var/lib/alloy/data
      - /etc/alloy/config.alloy
    networks:
      - backend
    depends_on:
      - mvp-loki
    healthcheck:
      test: ["CMD-SHELL", "bash -c 'echo > /dev/tcp/localhost/12345'"]
      interval: 30s
      timeout: 10s
      retries: 3
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"

  # Log Aggregation - Grafana
  mvp-grafana:
    image: ${REGISTRY_MIRRORS:-git.motovaultpro.com/egullickson/mirrors}/grafana/grafana:12.4.0-21693836646
    container_name: mvp-grafana
    restart: unless-stopped
    environment:
      GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_ADMIN_PASSWORD:-admin}
      GF_USERS_ALLOW_SIGN_UP: "false"
    volumes:
      - ./config/grafana/datasources:/etc/grafana/provisioning/datasources:ro
      - ./config/grafana/provisioning:/etc/grafana/provisioning/dashboards:ro
      - ./config/grafana/alerting:/etc/grafana/provisioning/alerting:ro
      - ./config/grafana/dashboards:/var/lib/grafana/dashboards:ro
      - mvp_grafana_data:/var/lib/grafana
    networks:
      - backend
      - frontend
    depends_on:
      - mvp-loki
    healthcheck:
      test: ["CMD-SHELL", "wget -q --spider http://localhost:3000/api/health || exit 1"]
      interval: 30s
      timeout: 10s
      retries: 3
    labels:
      - "traefik.enable=true"
      - "traefik.docker.network=motovaultpro_frontend"
      - "traefik.http.routers.grafana.rule=Host(`logs.motovaultpro.com`)"
      - "traefik.http.routers.grafana.entrypoints=websecure"
      - "traefik.http.routers.grafana.tls=true"
      - "traefik.http.routers.grafana.tls.certresolver=letsencrypt"
      - "traefik.http.routers.grafana.middlewares=grafana-ipwhitelist@file"
      - "traefik.http.services.grafana.loadbalancer.server.port=3000"
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"

# Network Definition
networks:
  frontend:
    driver: bridge
    internal: false  # Only for Traefik public access
    ipam:
      config:
        - subnet: 10.96.1.0/24
    labels:
      - "com.motovaultpro.network=frontend"
      - "com.motovaultpro.purpose=public-traffic-only"

  backend:
    driver: bridge
    internal: false   # Needs external access for Auth0 JWT validation
    ipam:
      config:
        - subnet: 10.96.20.0/24
    labels:
      - "com.motovaultpro.network=backend"
      - "com.motovaultpro.purpose=api-services"

  database:
    driver: bridge
    internal: true   # Data isolation
    ipam:
      config:
        - subnet: 10.96.64.0/24
    labels:
      - "com.motovaultpro.network=database"
      - "com.motovaultpro.purpose=data-layer"

# Volume Definitions
volumes:
  mvp_postgres_data:
    name: mvp_postgres_data
  mvp_redis_data:
    name: mvp_redis_data
  mvp_loki_data:
    name: mvp_loki_data
  mvp_grafana_data:
    name: mvp_grafana_data
