All checks were successful
Auto-Deploy Changed Stacks / deploy (push) Successful in 12s
101 lines
3.8 KiB
YAML
101 lines
3.8 KiB
YAML
services:
|
|
db:
|
|
image: postgres:16-alpine
|
|
restart: unless-stopped
|
|
environment:
|
|
POSTGRES_DB: jobsquatch
|
|
POSTGRES_USER: postgres
|
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD must be set}
|
|
volumes:
|
|
- postgres_data:/var/lib/postgresql/data
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
|
interval: 5s
|
|
timeout: 5s
|
|
retries: 10
|
|
networks:
|
|
- jobsquatch-internal
|
|
|
|
redis:
|
|
image: redis:7-alpine
|
|
restart: unless-stopped
|
|
volumes:
|
|
- redis_data:/data
|
|
command: redis-server --appendonly yes
|
|
networks:
|
|
- jobsquatch-internal
|
|
|
|
app:
|
|
image: ghcr.io/teamcastaldi/jobsquatch-backend:${IMAGE_TAG:-latest}
|
|
restart: unless-stopped
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
redis:
|
|
condition: service_started
|
|
environment:
|
|
APP_ENV: production
|
|
DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:?POSTGRES_PASSWORD must be set}@db:5432/jobsquatch
|
|
REDIS_URL: redis://redis:6379/0
|
|
SECRET_KEY: ${SECRET_KEY:?SECRET_KEY must be set}
|
|
ACCESS_TOKEN_EXPIRE_DAYS: ${ACCESS_TOKEN_EXPIRE_DAYS:-7}
|
|
APP_BASE_URL: ${APP_BASE_URL:?APP_BASE_URL must be set}
|
|
ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY:?ANTHROPIC_API_KEY must be set}
|
|
RESEND_API_KEY: ${RESEND_API_KEY:?RESEND_API_KEY must be set}
|
|
EMAIL_FROM: ${EMAIL_FROM:?EMAIL_FROM must be set}
|
|
STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:?STRIPE_SECRET_KEY must be set}
|
|
STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:?STRIPE_WEBHOOK_SECRET must be set}
|
|
STRIPE_STARTER_PRICE_ID: ${STRIPE_STARTER_PRICE_ID:?STRIPE_STARTER_PRICE_ID must be set}
|
|
STRIPE_PACK_PRICE_ID: ${STRIPE_PACK_PRICE_ID:?STRIPE_PACK_PRICE_ID must be set}
|
|
STRIPE_BETA_PRICE_ID: ${STRIPE_BETA_PRICE_ID:?STRIPE_BETA_PRICE_ID must be set}
|
|
CORS_ORIGINS: ${CORS_ORIGINS:-}
|
|
LOG_LEVEL: ${LOG_LEVEL:-INFO}
|
|
command: >
|
|
sh -c "alembic upgrade head && uvicorn src.web.app:app --host 0.0.0.0 --port 8000"
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "python -c \"import urllib.request; urllib.request.urlopen('http://localhost:8000/health')\""]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
start_period: 30s
|
|
networks:
|
|
- jobsquatch-internal
|
|
|
|
frontend:
|
|
image: ghcr.io/teamcastaldi/jobsquatch-frontend:${IMAGE_TAG:-latest}
|
|
restart: unless-stopped
|
|
ports:
|
|
- "80:80"
|
|
depends_on:
|
|
app:
|
|
condition: service_healthy
|
|
labels:
|
|
# When a container is on multiple networks, Traefik picks one arbitrarily.
|
|
# Pin it to proxy-net so Traefik never tries to route via jobsquatch-internal.
|
|
traefik.docker.network: proxy-net
|
|
- "traefik.enable=true"
|
|
- "traefik.http.routers.jobsquatch.rule=Host(`jobsquatch-alpha.castaldifamily.com`)"
|
|
- "traefik.http.routers.jobsquatch.entrypoints=websecure"
|
|
- "traefik.http.routers.jobsquatch.tls=true"
|
|
- "traefik.http.routers.jobsquatch.tls.certresolver=cloudflare"
|
|
- "traefik.http.routers.jobsquatch.middlewares=security-headers@file"
|
|
- "traefik.http.services.jobsquatch.loadbalancer.server.port=80"
|
|
networks:
|
|
- jobsquatch-internal
|
|
- proxy-net
|
|
|
|
volumes:
|
|
postgres_data:
|
|
redis_data:
|
|
|
|
networks:
|
|
# Internal bridge for service-to-service communication (db, redis, app, frontend).
|
|
# Named explicitly so the full Docker network name is <project>_jobsquatch-internal,
|
|
# where <project> is the Compose project name (COMPOSE_PROJECT_NAME or directory name).
|
|
# On heimdall this is jobsquatch-alpha_jobsquatch-internal.
|
|
jobsquatch-internal:
|
|
driver: bridge
|
|
# External network managed by Traefik on heimdall. The frontend must be on this
|
|
# network so Traefik can route inbound HTTPS traffic to it.
|
|
proxy-net:
|
|
external: true |