diff --git a/deploy/.env.example b/deploy/.env.example new file mode 100644 index 0000000..923efaa --- /dev/null +++ b/deploy/.env.example @@ -0,0 +1,37 @@ +# Provenance configuration — copy to `.env` and fill in. Never commit `.env`. +# Everything is twelve-factor; no endpoints or secrets live in code. + +# --- Core --- +APP_ENV=development + +# --- Database (Postgres) --- +POSTGRES_USER=provenance +POSTGRES_PASSWORD=change-me +POSTGRES_DB=provenance +# Backend connection string (async driver). Host 'postgres' = compose service. +DATABASE_URL=postgresql+asyncpg://provenance:change-me@postgres:5432/provenance + +# --- Object storage (S3-compatible / MinIO) --- +MINIO_ROOT_USER=provenance +MINIO_ROOT_PASSWORD=change-me-too +S3_ENDPOINT_URL=http://minio:9000 +S3_BUCKET=provenance +S3_ACCESS_KEY=provenance +S3_SECRET_KEY=change-me-too +S3_REGION=us-east-1 + +# --- Edge (Caddy) --- +# Local: ':80' (http://localhost). Production: 'provenance.example.com' for auto-HTTPS. +PROVENANCE_SITE_ADDRESS=:80 + +# --- Email (SMTP) — wired in a later phase --- +SMTP_HOST= +SMTP_PORT=587 +SMTP_USERNAME= +SMTP_PASSWORD= +SMTP_FROM= + +# --- Model providers — wired in Phase 4 (AI assistant). BYO key. --- +# ANTHROPIC_API_KEY= +# OPENAI_API_KEY= +# XAI_API_KEY= diff --git a/deploy/Caddyfile b/deploy/Caddyfile new file mode 100644 index 0000000..c784da2 --- /dev/null +++ b/deploy/Caddyfile @@ -0,0 +1,25 @@ +# Provenance edge. Site address is env-driven: ':80' for local http://localhost, +# a domain in production for automatic HTTPS. Behind a Cloudflare Tunnel you can +# keep this on plain HTTP and let the tunnel terminate TLS. + +{$PROVENANCE_SITE_ADDRESS::80} { + encode gzip + + # Versioned API surface (FastAPI). The assistant mounts under /assistant later. + handle /api/* { + reverse_proxy backend:8000 + } + + # Liveness/readiness probes, proxied for external monitoring. + handle /health* { + reverse_proxy backend:8000 + } + + # Frontend (Next.js) — not yet deployed in Phase 0. Uncomment when it lands. + # handle { + # reverse_proxy frontend:3000 + # } + handle { + respond "Provenance — Phase 0. Backend health at /health; frontend not yet deployed." 200 + } +} diff --git a/deploy/docker-compose.yml b/deploy/docker-compose.yml new file mode 100644 index 0000000..75d5d33 --- /dev/null +++ b/deploy/docker-compose.yml @@ -0,0 +1,81 @@ +name: provenance + +# One stack stands up the whole system. Configuration is entirely env-driven +# (see .env.example). Run from this directory: `docker compose up -d`. + +services: + postgres: + # pgvector image = Postgres + pgvector; pg_trgm ships in contrib. + image: pgvector/pgvector:pg17 + environment: + POSTGRES_USER: ${POSTGRES_USER:-provenance} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-provenance} + POSTGRES_DB: ${POSTGRES_DB:-provenance} + volumes: + - pgdata:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-provenance} -d ${POSTGRES_DB:-provenance}"] + interval: 5s + timeout: 5s + retries: 10 + restart: unless-stopped + + minio: + image: minio/minio:latest + command: server /data --console-address ":9001" + environment: + MINIO_ROOT_USER: ${MINIO_ROOT_USER:-provenance} + MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:-change-me-too} + volumes: + - miniodata:/data + healthcheck: + test: ["CMD-SHELL", "mc ready local || exit 1"] + interval: 10s + timeout: 5s + retries: 10 + restart: unless-stopped + + backend: + build: + context: ../backend + dockerfile: Dockerfile + environment: + APP_ENV: ${APP_ENV:-development} + DATABASE_URL: ${DATABASE_URL:-postgresql+asyncpg://provenance:provenance@postgres:5432/provenance} + depends_on: + postgres: + condition: service_healthy + healthcheck: + test: + - CMD-SHELL + - >- + python -c "import urllib.request,sys; + sys.exit(0 if urllib.request.urlopen('http://localhost:8000/health').status==200 else 1)" + interval: 10s + timeout: 5s + retries: 5 + start_period: 20s + restart: unless-stopped + + caddy: + image: caddy:2 + ports: + - "80:80" + - "443:443" + environment: + # Local default ':80' -> http://localhost. Set to a domain in production + # for automatic HTTPS (or run plain HTTP behind a Cloudflare Tunnel). + PROVENANCE_SITE_ADDRESS: ${PROVENANCE_SITE_ADDRESS:-:80} + volumes: + - ./Caddyfile:/etc/caddy/Caddyfile:ro + - caddydata:/data + - caddyconfig:/config + depends_on: + - backend + restart: unless-stopped + +volumes: + pgdata: + miniodata: + caddydata: + caddyconfig: