152 lines
5.0 KiB
YAML
152 lines
5.0 KiB
YAML
# =============================================================================
|
|
# docker-compose.yml — LeoCRM Multi-Container Setup
|
|
#
|
|
# Full stack: PostgreSQL + Redis + App + Worker, all with persistent volumes.
|
|
#
|
|
# This file serves two purposes:
|
|
# 1. Local development / testing: `docker compose up --build`
|
|
# 2. Reference for the production multi-container architecture
|
|
#
|
|
# Production deploys via Coolify use scripts/deploy.py which automates:
|
|
# - Coolify API build & deploy
|
|
# - Persistent volume mounting (patched into Coolify's generated compose)
|
|
# - Worker container startup
|
|
# - RLS policy enforcement
|
|
# - Health & domain verification
|
|
#
|
|
# Usage (local testing):
|
|
# cp .env.docker.example .env.docker
|
|
# $EDITOR .env.docker # fill SECRET_KEY, POSTGRES_PASSWORD, ...
|
|
# docker compose --env-file .env.docker up --build
|
|
# curl http://localhost:8000/api/v1/health
|
|
# =============================================================================
|
|
|
|
services:
|
|
# ── PostgreSQL 16 with pgvector ─────────────────────────────────────
|
|
postgres:
|
|
image: pgvector/pgvector:pg16
|
|
container_name: crm-postgres
|
|
restart: unless-stopped
|
|
environment:
|
|
POSTGRES_USER: ${POSTGRES_USER:-crm_user}
|
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}
|
|
POSTGRES_DB: ${POSTGRES_DB:-crm_db}
|
|
PGDATA: /var/lib/postgresql/data/pgdata
|
|
volumes:
|
|
- pgdata:/var/lib/postgresql/data
|
|
ports:
|
|
- "5432:5432" # local-only; remove for prod-like runs
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-crm_user} -d ${POSTGRES_DB:-crm_db}"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
start_period: 10s
|
|
networks:
|
|
- crm-net
|
|
|
|
# ── Redis 7 (sessions, rate limiting, ARQ queue) ────────────────────
|
|
redis:
|
|
image: redis:7-alpine
|
|
container_name: crm-redis
|
|
restart: unless-stopped
|
|
command: redis-server --requirepass ${REDIS_PASSWORD:-changeme}
|
|
volumes:
|
|
- redisdata:/data
|
|
ports:
|
|
- "6379:6379" # local-only; remove for prod-like runs
|
|
healthcheck:
|
|
test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD:-changeme}", "ping"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
networks:
|
|
- crm-net
|
|
|
|
# ── CRM API (FastAPI + Uvicorn) ─────────────────────────────────────
|
|
crm-app:
|
|
build:
|
|
context: .
|
|
dockerfile: Dockerfile
|
|
container_name: crm-app
|
|
restart: unless-stopped
|
|
depends_on:
|
|
postgres:
|
|
condition: service_healthy
|
|
redis:
|
|
condition: service_healthy
|
|
environment:
|
|
DATABASE_URL: ${DATABASE_URL:?DATABASE_URL is required}
|
|
REDIS_URL: ${REDIS_URL:-redis://:${REDIS_PASSWORD:-changeme}@redis:6379/0}
|
|
SECRET_KEY: ${SECRET_KEY:?SECRET_KEY is required (min 32 chars)}
|
|
CORS_ORIGINS: ${CORS_ORIGINS:-http://localhost:8000,http://localhost:5173}
|
|
ENVIRONMENT: ${ENVIRONMENT:-production}
|
|
LOG_LEVEL: ${LOG_LEVEL:-INFO}
|
|
SESSION_COOKIE_SECURE: ${SESSION_COOKIE_SECURE:-true}
|
|
STORAGE_PATH: ${STORAGE_PATH:-/data/storage}
|
|
BCRYPT_ROUNDS: ${BCRYPT_ROUNDS:-12}
|
|
# S3 Storage (optional — if STORAGE_BACKEND=s3)
|
|
STORAGE_BACKEND: ${STORAGE_BACKEND:-local}
|
|
S3_ENDPOINT: ${S3_ENDPOINT:-}
|
|
S3_BUCKET: ${S3_BUCKET:-}
|
|
S3_ACCESS_KEY: ${S3_ACCESS_KEY:-}
|
|
S3_SECRET_KEY: ${S3_SECRET_KEY:-}
|
|
S3_REGION: ${S3_REGION:-us-east-1}
|
|
S3_SECURE: ${S3_SECURE:-true}
|
|
ports:
|
|
- "8000:8000"
|
|
volumes:
|
|
- storage:/data/storage
|
|
healthcheck:
|
|
test: ["CMD", "curl", "-fsS", "http://localhost:8000/api/v1/health"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
start_period: 15s
|
|
networks:
|
|
- crm-net
|
|
|
|
# ── CRM Worker (ARQ background jobs, cron, outbox processor) ───────
|
|
crm-worker:
|
|
build:
|
|
context: .
|
|
dockerfile: Dockerfile
|
|
container_name: crm-worker
|
|
restart: unless-stopped
|
|
depends_on:
|
|
postgres:
|
|
condition: service_healthy
|
|
redis:
|
|
condition: service_healthy
|
|
entrypoint: ["/app/worker.sh"]
|
|
environment:
|
|
DATABASE_URL: ${DATABASE_URL:?DATABASE_URL is required}
|
|
REDIS_URL: ${REDIS_URL:-redis://:${REDIS_PASSWORD:-changeme}@redis:6379/0}
|
|
SECRET_KEY: ${SECRET_KEY:?SECRET_KEY is required (min 32 chars)}
|
|
ENVIRONMENT: ${ENVIRONMENT:-production}
|
|
LOG_LEVEL: ${LOG_LEVEL:-INFO}
|
|
SESSION_COOKIE_SECURE: ${SESSION_COOKIE_SECURE:-true}
|
|
STORAGE_PATH: ${STORAGE_PATH:-/data/storage}
|
|
STORAGE_BACKEND: ${STORAGE_BACKEND:-local}
|
|
S3_ENDPOINT: ${S3_ENDPOINT:-}
|
|
S3_BUCKET: ${S3_BUCKET:-}
|
|
S3_ACCESS_KEY: ${S3_ACCESS_KEY:-}
|
|
S3_SECRET_KEY: ${S3_SECRET_KEY:-}
|
|
volumes:
|
|
- storage:/data/storage
|
|
networks:
|
|
- crm-net
|
|
|
|
volumes:
|
|
pgdata:
|
|
name: crm_pgdata
|
|
redisdata:
|
|
name: crm_redisdata
|
|
storage:
|
|
name: crm_storage
|
|
|
|
networks:
|
|
crm-net:
|
|
name: crm-net
|
|
driver: bridge
|