Files
bookorbit/docker-compose.prod.yml
T
neon a3579ac57f ci: overhaul CI workflows for reliability and maintainability
- add CODEOWNERS assigning .github/ to @neonsolstice
- configure automated updates for npm, docker, and github-actions ecosystems
- replace custom change-detection bash script with dorny/paths-filter@v4
- consolidate lint, typecheck, and test into a single checks matrix job
- gate per-package change detection via has-changes step (matrix unavailable in job-level if)
- fix duplicate actions/setup-node call in setup-node-pnpm composite action
- scope pnpm store cache key by pnpm version to prevent stale cross-version cache hits
- pin all action references to commit SHAs
- fix container-image concurrency group to use commit SHA across all trigger types
- add timeout-minutes to all jobs
- document fail-fast: false rationale and checks: write trade-off
2026-03-07 18:14:36 -06:00

107 lines
3.0 KiB
YAML

name: projectx
x-logging: &default-logging
driver: json-file
options:
max-size: "10m"
max-file: "5"
services:
postgres:
image: pgvector/pgvector:pg16
restart: unless-stopped
environment:
POSTGRES_USER: ${POSTGRES_USER?POSTGRES_USER is required}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD?POSTGRES_PASSWORD is required}
POSTGRES_DB: ${POSTGRES_DB?POSTGRES_DB is required}
volumes:
- postgres_data:/var/lib/postgresql/data
- ./docker/postgres/init.sql:/docker-entrypoint-initdb.d/init.sql:ro
healthcheck:
test:
[
"CMD-SHELL",
"pg_isready -U ${POSTGRES_USER?POSTGRES_USER is required} -d ${POSTGRES_DB?POSTGRES_DB is required}",
]
interval: 10s
timeout: 5s
retries: 10
start_period: 20s
logging: *default-logging
migrate:
image: ${APP_IMAGE?APP_IMAGE is required}
restart: "no"
init: true
environment:
DATABASE_URL: postgres://${POSTGRES_USER?POSTGRES_USER is required}:${POSTGRES_PASSWORD?POSTGRES_PASSWORD is required}@postgres:5432/${POSTGRES_DB?POSTGRES_DB is required}
NODE_ENV: production
depends_on:
postgres:
condition: service_healthy
command: ["node", "dist/scripts/migrate.js"]
read_only: true
tmpfs:
- /tmp
cap_drop:
- ALL
security_opt:
- no-new-privileges:true
logging: *default-logging
app:
image: ${APP_IMAGE?APP_IMAGE is required}
restart: unless-stopped
init: true
ports:
- "${APP_PORT:-3000}:3000"
environment:
DATABASE_URL: postgres://${POSTGRES_USER?POSTGRES_USER is required}:${POSTGRES_PASSWORD?POSTGRES_PASSWORD is required}@postgres:5432/${POSTGRES_DB?POSTGRES_DB is required}
JWT_SECRET: ${JWT_SECRET?JWT_SECRET is required}
APP_URL: ${APP_URL?APP_URL is required}
NODE_ENV: production
BOOKS_PATH: /books
STAGING_PATH: /books/staging
PORT: 3000
JWT_EXPIRES_IN: ${JWT_EXPIRES_IN:-15m}
JWT_REFRESH_EXPIRES_IN: ${JWT_REFRESH_EXPIRES_IN:-7d}
CLIENT_URL: ${CLIENT_URL:-http://localhost:5173}
SMTP_HOST: ${SMTP_HOST:-}
SMTP_PORT: ${SMTP_PORT:-587}
SMTP_SECURE: ${SMTP_SECURE:-false}
SMTP_USER: ${SMTP_USER:-}
SMTP_PASS: ${SMTP_PASS:-}
SMTP_FROM: ${SMTP_FROM:-noreply@projectx.local}
EMAIL_ENCRYPTION_KEY: ${EMAIL_ENCRYPTION_KEY:-}
GOOGLE_BOOKS_API_KEY: ${GOOGLE_BOOKS_API_KEY:-}
depends_on:
postgres:
condition: service_healthy
migrate:
condition: service_completed_successfully
volumes:
- books_data:/books
read_only: true
tmpfs:
- /tmp
cap_drop:
- ALL
security_opt:
- no-new-privileges:true
stop_grace_period: 30s
healthcheck:
test:
[
"CMD-SHELL",
'node -e "fetch(''http://127.0.0.1:3000/api/v1/health'').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"',
]
interval: 30s
timeout: 5s
retries: 3
start_period: 20s
logging: *default-logging
volumes:
postgres_data:
books_data: