Add standalone GeminiEngine class for maintenance schedule extraction from PDF owners manuals using Vertex AI Gemini 2.5 Flash with structured JSON output enforcement, 20MB size limit, and lazy initialization. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
125 lines
5.3 KiB
YAML
125 lines
5.3 KiB
YAML
# Staging Environment Docker Compose
|
|
# Runs full application stack on staging server (staging.motovaultpro.com)
|
|
# Usage: docker compose -f docker-compose.yml -f docker-compose.staging.yml up -d
|
|
#
|
|
# Differences from production:
|
|
# - Single stack (no blue-green)
|
|
# - Staging domain (staging.motovaultpro.com)
|
|
# - Separate database (isolated from production)
|
|
# - Uses same images as production for accurate testing
|
|
|
|
services:
|
|
# ========================================
|
|
# Traefik - Reverse Proxy (Staging)
|
|
# ========================================
|
|
mvp-traefik:
|
|
image: ${REGISTRY_MIRRORS:-git.motovaultpro.com/egullickson/mirrors}/traefik:v3.6
|
|
container_name: mvp-traefik-staging
|
|
volumes:
|
|
- ./config/traefik/dynamic-staging:/etc/traefik/dynamic:ro
|
|
labels:
|
|
- "traefik.http.routers.traefik-dashboard.rule=Host(`traefik.staging.motovaultpro.com`)"
|
|
|
|
# ========================================
|
|
# Frontend (Staging)
|
|
# ========================================
|
|
mvp-frontend:
|
|
image: ${FRONTEND_IMAGE:-git.motovaultpro.com/egullickson/frontend:latest}
|
|
container_name: mvp-frontend-staging
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.docker.network=motovaultpro_frontend"
|
|
- "traefik.http.routers.mvp-frontend.rule=Host(`staging.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"
|
|
|
|
# ========================================
|
|
# Backend (Staging)
|
|
# ========================================
|
|
mvp-backend:
|
|
image: ${BACKEND_IMAGE:-git.motovaultpro.com/egullickson/backend:latest}
|
|
container_name: mvp-backend-staging
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.docker.network=motovaultpro_backend"
|
|
- "traefik.http.routers.mvp-backend.rule=Host(`staging.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"
|
|
- "traefik.http.routers.mvp-backend-health.rule=Host(`staging.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"
|
|
- "traefik.http.services.mvp-backend.loadbalancer.server.port=3001"
|
|
|
|
# ========================================
|
|
# OCR Service (Staging)
|
|
# ========================================
|
|
mvp-ocr:
|
|
image: ${OCR_IMAGE:-git.motovaultpro.com/egullickson/ocr:latest}
|
|
container_name: mvp-ocr-staging
|
|
environment:
|
|
# Python log levels: DEBUG | INFO | WARNING | ERROR | CRITICAL
|
|
LOG_LEVEL: debug
|
|
REDIS_HOST: mvp-redis
|
|
REDIS_PORT: 6379
|
|
REDIS_DB: 1
|
|
# OCR engine configuration (Google Vision primary, PaddleOCR fallback)
|
|
OCR_PRIMARY_ENGINE: google_vision
|
|
OCR_FALLBACK_ENGINE: paddleocr
|
|
OCR_CONFIDENCE_THRESHOLD: "0.6"
|
|
OCR_FALLBACK_THRESHOLD: "0.6"
|
|
GOOGLE_VISION_KEY_PATH: /run/secrets/google-wif-config.json
|
|
VISION_MONTHLY_LIMIT: "1000"
|
|
# Vertex AI / Gemini configuration (maintenance schedule extraction)
|
|
VERTEX_AI_PROJECT: ${VERTEX_AI_PROJECT:-}
|
|
VERTEX_AI_LOCATION: us-central1
|
|
GEMINI_MODEL: gemini-2.5-flash
|
|
volumes:
|
|
- ./secrets/app/auth0-ocr-client-id.txt:/run/secrets/auth0-ocr-client-id:ro
|
|
- ./secrets/app/auth0-ocr-client-secret.txt:/run/secrets/auth0-ocr-client-secret:ro
|
|
- ./secrets/app/google-wif-config.json:/run/secrets/google-wif-config.json:ro
|
|
|
|
# ========================================
|
|
# PostgreSQL (Staging - Separate Database)
|
|
# ========================================
|
|
mvp-postgres:
|
|
container_name: mvp-postgres-staging
|
|
volumes:
|
|
- mvp_postgres_staging_data:/var/lib/postgresql/data/pgdata
|
|
- ./secrets/app/postgres-password.txt:/run/secrets/postgres-password:ro
|
|
|
|
# ========================================
|
|
# Redis (Staging)
|
|
# ========================================
|
|
mvp-redis:
|
|
container_name: mvp-redis-staging
|
|
volumes:
|
|
- mvp_redis_staging_data:/data
|
|
|
|
# ========================================
|
|
# Grafana (Staging domain override)
|
|
# ========================================
|
|
mvp-grafana:
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.docker.network=motovaultpro_frontend"
|
|
- "traefik.http.routers.grafana.rule=Host(`logs.staging.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"
|
|
|
|
# Staging-specific volumes (separate from production)
|
|
volumes:
|
|
mvp_postgres_staging_data:
|
|
name: mvp_postgres_staging_data
|
|
mvp_redis_staging_data:
|
|
name: mvp_redis_staging_data
|