mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-08 12:32:43 +00:00
Blood-pressure fixtures in the in-target integration suite were copied from live readings; they are now synthetic with the same in/out split so every assertion holds. Hard-coded operator hostnames move behind env vars (DEPLOY_LOGS_URL, HEALTHLOG_PROD_URL), the codex client identifies via the public repository URL, the OpenAPI servers entry points at a neutral example host, and remaining workflow, docs and comment references to the operator's instance or working notes are generalised. The compose whitelist also gains DEPLOY_WEBHOOK_SECRET, which was missing and made the deploy webhook unusable on compose installs.
145 lines
6.8 KiB
YAML
145 lines
6.8 KiB
YAML
services:
|
|
# Single-container default (HEALTHLOG_PROCESS_TYPE=all). Existing
|
|
# self-host deployments stay working with `docker compose up`.
|
|
# For horizontal scaling switch to the web/worker split below
|
|
# (HEALTHLOG_PROCESS_TYPE=web on this service + uncomment app-worker).
|
|
app:
|
|
# Tracks the GHCR `:latest` multi-arch image. `pull_policy: always`
|
|
# is the load-bearing line — without it, Docker keeps a stale
|
|
# `:latest` digest cached on the host and skips the registry round-
|
|
# trip on `compose up`, which is what kept Coolify re-deploying the
|
|
# previous image after every tag push. With pull_policy=always the
|
|
# compose-up always re-checks the registry digest and pulls when
|
|
# GHCR has a fresher manifest. The small bandwidth cost on every
|
|
# `compose up` is the price of digest-correctness.
|
|
image: ghcr.io/mbombeck/healthlog:latest
|
|
pull_policy: always
|
|
container_name: healthlog-app
|
|
ports:
|
|
- "3000:3000"
|
|
environment:
|
|
# connection_limit is set explicitly: Prisma's own default is
|
|
# cpu_count*2+1, which starves the combined web+worker process
|
|
# (HEALTHLOG_PROCESS_TYPE=all) under background AI/rollup load. Default
|
|
# 20 suits a small host; raise DB_CONNECTION_LIMIT on a busy one (keep it
|
|
# below the database's max_connections, leaving headroom for pg-boss,
|
|
# migrations, and backups). pool_timeout is the seconds a query waits for
|
|
# a free connection before erroring.
|
|
DATABASE_URL: "postgresql://healthlog:${POSTGRES_PASSWORD}@db:5432/healthlog?schema=public&connection_limit=${DB_CONNECTION_LIMIT:-20}&pool_timeout=${DB_POOL_TIMEOUT:-20}"
|
|
NODE_ENV: production
|
|
ENCRYPTION_KEY: "${ENCRYPTION_KEY}"
|
|
ENCRYPTION_KEYS: "${ENCRYPTION_KEYS:-}"
|
|
ENCRYPTION_ACTIVE_KEY_ID: "${ENCRYPTION_ACTIVE_KEY_ID:-}"
|
|
API_TOKEN_HMAC_KEY: "${API_TOKEN_HMAC_KEY}"
|
|
NEXT_PUBLIC_APP_URL: "${NEXT_PUBLIC_APP_URL:-http://localhost:3000}"
|
|
APP_URL: "${APP_URL:-http://localhost:3000}"
|
|
# v1.5.1 session-cookie Secure-flag opt-out. Forwarded explicitly so
|
|
# an operator setting SESSION_COOKIE_SECURE=false in .env actually
|
|
# reaches the Node process (the compose `environment:` block is a
|
|
# whitelist — vars not listed here don't propagate from .env into
|
|
# the container, even though docker-compose reads .env for
|
|
# `${VAR}` substitution at compose-up time).
|
|
SESSION_COOKIE_SECURE: "${SESSION_COOKIE_SECURE:-}"
|
|
# all = bundle web + worker in this container (default, single-host)
|
|
# web = serve HTTP only; pair with a separate app-worker service
|
|
HEALTHLOG_PROCESS_TYPE: "${HEALTHLOG_PROCESS_TYPE:-all}"
|
|
BACKUP_ENCRYPTION_KEY: "${BACKUP_ENCRYPTION_KEY:-}"
|
|
BACKUP_S3_ENDPOINT: "${BACKUP_S3_ENDPOINT:-}"
|
|
BACKUP_S3_BUCKET: "${BACKUP_S3_BUCKET:-}"
|
|
BACKUP_S3_ACCESS_KEY: "${BACKUP_S3_ACCESS_KEY:-}"
|
|
BACKUP_S3_SECRET_KEY: "${BACKUP_S3_SECRET_KEY:-}"
|
|
BACKUP_S3_REGION: "${BACKUP_S3_REGION:-auto}"
|
|
BACKUP_RETENTION_DAYS: "${BACKUP_RETENTION_DAYS:-30}"
|
|
# Per-export ceiling on MedicationAdministration rows in the FHIR
|
|
# health-record Bundle. Bounded 1..50000, default 5000. Listed here so
|
|
# an operator override in .env actually reaches the container (the
|
|
# `environment:` block is a whitelist).
|
|
FHIR_MAX_MEDICATION_ADMINISTRATIONS: "${FHIR_MAX_MEDICATION_ADMINISTRATIONS:-}"
|
|
# WHOOP integration (optional). The app client id/secret are per-user
|
|
# BYO-keys stored encrypted in the DB, so there is no
|
|
# WHOOP_CLIENT_ID/SECRET env. WHOOP_WEBHOOK_SECRET is the instance-level
|
|
# path-segment + HMAC-verification secret for the webhook;
|
|
# WHOOP_REDIRECT_URI overrides the derived
|
|
# `${NEXT_PUBLIC_APP_URL}/api/whoop/callback` when the public URL
|
|
# differs. Listed here so an operator override in .env reaches the
|
|
# container (the `environment:` block is a whitelist).
|
|
WHOOP_WEBHOOK_SECRET: "${WHOOP_WEBHOOK_SECRET:-}"
|
|
WHOOP_REDIRECT_URI: "${WHOOP_REDIRECT_URI:-}"
|
|
# Deploy-result webhook (optional). DEPLOY_WEBHOOK_SECRET authenticates
|
|
# POST /api/internal/deploy-webhook; DEPLOY_LOGS_URL is the
|
|
# deployment-dashboard URL (e.g. the Coolify UI) linked in
|
|
# deploy-failure notifications. Listed here so operator values in
|
|
# .env reach the container (the `environment:` block is a whitelist).
|
|
DEPLOY_WEBHOOK_SECRET: "${DEPLOY_WEBHOOK_SECRET:-}"
|
|
DEPLOY_LOGS_URL: "${DEPLOY_LOGS_URL:-}"
|
|
# TLS leaf SPKI-change alarm baseline (optional). The native client
|
|
# pins the served TLS leaf; this is the known-good pin set the monitor
|
|
# alarms against on a rotation. Comma-separated for the dual-pin
|
|
# renewal window. Listed here so an operator value in .env reaches the
|
|
# container (the `environment:` block is a whitelist). See
|
|
# docs/ops/tls-cert-pin.md.
|
|
TLS_LEAF_SPKI_PINS: "${TLS_LEAF_SPKI_PINS:-}"
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
restart: unless-stopped
|
|
healthcheck:
|
|
test:
|
|
[
|
|
"CMD-SHELL",
|
|
"wget --no-verbose --tries=1 --spider http://127.0.0.1:3000/api/version || exit 1",
|
|
]
|
|
interval: 30s
|
|
timeout: 5s
|
|
retries: 3
|
|
start_period: 30s
|
|
|
|
# Optional dedicated worker container — uncomment + set
|
|
# HEALTHLOG_PROCESS_TYPE=web on `app` to split the deployment.
|
|
# See docs/self-hosting/scaling.md for the full guide.
|
|
#
|
|
# app-worker:
|
|
# image: ghcr.io/mbombeck/healthlog:latest
|
|
# build:
|
|
# context: .
|
|
# dockerfile: Dockerfile
|
|
# container_name: healthlog-worker
|
|
# environment:
|
|
# DATABASE_URL: "postgresql://healthlog:${POSTGRES_PASSWORD}@db:5432/healthlog?schema=public"
|
|
# NODE_ENV: production
|
|
# ENCRYPTION_KEY: "${ENCRYPTION_KEY}"
|
|
# ENCRYPTION_KEYS: "${ENCRYPTION_KEYS:-}"
|
|
# ENCRYPTION_ACTIVE_KEY_ID: "${ENCRYPTION_ACTIVE_KEY_ID:-}"
|
|
# API_TOKEN_HMAC_KEY: "${API_TOKEN_HMAC_KEY}"
|
|
# APP_URL: "${APP_URL:-http://localhost:3000}"
|
|
# HEALTHLOG_PROCESS_TYPE: "worker"
|
|
# BACKUP_ENCRYPTION_KEY: "${BACKUP_ENCRYPTION_KEY:-}"
|
|
# BACKUP_S3_ENDPOINT: "${BACKUP_S3_ENDPOINT:-}"
|
|
# BACKUP_S3_BUCKET: "${BACKUP_S3_BUCKET:-}"
|
|
# BACKUP_S3_ACCESS_KEY: "${BACKUP_S3_ACCESS_KEY:-}"
|
|
# BACKUP_S3_SECRET_KEY: "${BACKUP_S3_SECRET_KEY:-}"
|
|
# BACKUP_S3_REGION: "${BACKUP_S3_REGION:-auto}"
|
|
# depends_on:
|
|
# db:
|
|
# condition: service_healthy
|
|
# restart: unless-stopped
|
|
|
|
db:
|
|
image: postgres:16-alpine
|
|
container_name: healthlog-db
|
|
environment:
|
|
POSTGRES_USER: healthlog
|
|
POSTGRES_PASSWORD: "${POSTGRES_PASSWORD}"
|
|
POSTGRES_DB: healthlog
|
|
volumes:
|
|
- pgdata:/var/lib/postgresql/data
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "pg_isready -U healthlog"]
|
|
interval: 5s
|
|
timeout: 5s
|
|
retries: 5
|
|
restart: unless-stopped
|
|
|
|
volumes:
|
|
pgdata:
|