# deploy/portainer/federated-test.stack.yml # # Portainer / Docker Swarm stack template — federated-tier test instance # # PURPOSE # Deploys a single federated-tier Mosaic gateway with co-located Postgres # (pgvector) and Valkey for end-to-end federation testing. Intended for # mos-test-1.woltje.com and mos-test-2.woltje.com (DEPLOY-03/04). # # REQUIRED ENV VARS (set per-stack in Portainer → Stacks → Environment variables) # STACK_NAME Unique name for Traefik router/service labels. # Examples: mos-test-1, mos-test-2 # HOST_FQDN Fully-qualified domain name served by this stack. # Examples: mos-test-1.woltje.com, mos-test-2.woltje.com # POSTGRES_PASSWORD Database password — set per stack; do NOT commit a default. # BETTER_AUTH_SECRET Random 32-char string for BetterAuth session signing. # Generate: openssl rand -base64 32 # BETTER_AUTH_URL Public gateway base URL, e.g. https://mos-test-1.woltje.com # # OPTIONAL ENV VARS (uncomment and set in Portainer to enable features) # ANTHROPIC_API_KEY sk-ant-... # OPENAI_API_KEY sk-... # OTEL_EXPORTER_OTLP_ENDPOINT http://:4318 # OTEL_SERVICE_NAME (default: mosaic-gateway) # # REQUIRED EXTERNAL RESOURCES # traefik-public Docker overlay network — must exist before deploying. # Create: docker network create --driver overlay --attachable traefik-public # letsencrypt Traefik cert resolver configured on the Swarm manager. # DNS A record ${HOST_FQDN} → Swarm ingress IP (or Cloudflare proxy). # # IMAGE # Pinned to digest fed-v0.1.0-m1 (DEPLOY-01 verified). # Update digest here when promoting a new build. # # NOTE: This is a TEST template — production deployments use a separate # parameterised template with stricter resource limits and secrets. version: '3.9' services: gateway: image: git.mosaicstack.dev/mosaicstack/stack/gateway@sha256:9b72e202a9eecc27d31920b87b475b9e96e483c0323acc57856be4b1355db1ec # Tag for human reference: fed-v0.1.0-m1 environment: # ── Tier ─────────────────────────────────────────────────────────────── MOSAIC_TIER: federated # ── Database ─────────────────────────────────────────────────────────── DATABASE_URL: postgres://gateway:${POSTGRES_PASSWORD}@postgres:5432/mosaic # ── Queue ────────────────────────────────────────────────────────────── VALKEY_URL: redis://valkey:6379 # ── Gateway ──────────────────────────────────────────────────────────── GATEWAY_PORT: '3000' GATEWAY_CORS_ORIGIN: https://${HOST_FQDN} # ── Auth ─────────────────────────────────────────────────────────────── BETTER_AUTH_SECRET: ${BETTER_AUTH_SECRET} BETTER_AUTH_URL: https://${HOST_FQDN} # ── Observability ────────────────────────────────────────────────────── OTEL_SERVICE_NAME: ${STACK_NAME:-mosaic-gateway} # OTEL_EXPORTER_OTLP_ENDPOINT: http://:4318 # ── AI Providers (uncomment to enable) ───────────────────────────────── # ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY} # OPENAI_API_KEY: ${OPENAI_API_KEY} networks: - federated-test - traefik-public deploy: replicas: 1 restart_policy: condition: on-failure delay: 5s max_attempts: 3 labels: - 'traefik.enable=true' - 'traefik.docker.network=traefik-public' - 'traefik.http.routers.${STACK_NAME}.rule=Host(`${HOST_FQDN}`)' - 'traefik.http.routers.${STACK_NAME}.entrypoints=websecure' - 'traefik.http.routers.${STACK_NAME}.tls=true' - 'traefik.http.routers.${STACK_NAME}.tls.certresolver=letsencrypt' - 'traefik.http.services.${STACK_NAME}.loadbalancer.server.port=3000' healthcheck: test: ['CMD', 'wget', '-qO-', 'http://localhost:3000/health'] interval: 30s timeout: 5s retries: 3 start_period: 20s depends_on: - postgres - valkey postgres: image: pgvector/pgvector:pg17 environment: POSTGRES_USER: gateway POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} POSTGRES_DB: mosaic volumes: - postgres-data:/var/lib/postgresql/data networks: - federated-test deploy: replicas: 1 restart_policy: condition: on-failure delay: 5s max_attempts: 3 healthcheck: test: ['CMD-SHELL', 'pg_isready -U gateway'] interval: 10s timeout: 5s retries: 5 start_period: 10s valkey: image: valkey/valkey:8-alpine volumes: - valkey-data:/data networks: - federated-test deploy: replicas: 1 restart_policy: condition: on-failure delay: 5s max_attempts: 3 healthcheck: test: ['CMD', 'valkey-cli', 'ping'] interval: 10s timeout: 3s retries: 5 start_period: 5s volumes: postgres-data: valkey-data: networks: federated-test: driver: overlay traefik-public: external: true