pediatric-ai-scribe-v3/docs/deployment.md
Daniel a36235c646 v6.1: Turnstile bot protection, LiteLLM provider, PPTX tables, audio backup fixes, docs
- Add Cloudflare Turnstile to login, register, and password reset forms
- Switch AI provider to LiteLLM, transcription to OpenAI Whisper
- Change domain to scribe.pedshub.com
- Fix PPTX export: add tables, bold/italic, numbered lists, code blocks, blockquotes
- Fix announcement banner close button (CSP was blocking inline onclick)
- Fix auth middleware: empty Bearer token now falls through to cookie auth
- Fix audio backups: only save on transcription failure, stop auto-deleting on success
- Soften AI correction injection to prevent model hallucination from correction history
- Fix LiteLLM TTS model name handling (no incorrect openai/ prefix)
- Expand AI instructions textarea in Learning Hub CMS
- Update README for v6 with all features and providers
- Add comprehensive docs/: architecture, API reference, database schema,
  authentication, AI providers, speech, learning hub, configuration, deployment
2026-04-04 22:56:24 +02:00

4.6 KiB

Deployment Guide

Requirements

  • Docker and Docker Compose
  • PostgreSQL 16 with pgvector extension (included in pgvector/pgvector:pg16 image)
  • Reverse proxy (Nginx, Caddy, or Traefik) for HTTPS termination
  • At least one AI provider configured

Docker Deployment

1. Configure Environment

cp .env.example .env

Required settings:

AI_PROVIDER=litellm              # or bedrock, azure, vertex, openrouter
JWT_SECRET=<64-char random>      # openssl rand -hex 32
DB_PASSWORD=<strong password>
APP_URL=https://your-domain.com  # used for CORS, emails, verification links

2. Build and Start

docker compose up -d --build

This starts two containers:

  • pediatric-ai-scribe -- Node.js app on port 3552 (mapped to container port 3000)
  • pedscribe-db -- PostgreSQL 16 with pgvector

3. Verify

docker compose ps
curl http://localhost:3552/api/health

4. First User

Navigate to https://your-domain.com and register. The first user is automatically promoted to admin.

Reverse Proxy

The app binds to 127.0.0.1:3552 by default. You need a reverse proxy for HTTPS.

Nginx

server {
    listen 443 ssl http2;
    server_name scribe.example.com;

    ssl_certificate     /etc/ssl/certs/scribe.example.com.pem;
    ssl_certificate_key /etc/ssl/private/scribe.example.com.key;

    client_max_body_size 100M;

    location / {
        proxy_pass http://127.0.0.1:3552;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Caddy

scribe.example.com {
    reverse_proxy localhost:3552
}

Trust Proxy

If you see X-Forwarded-For warnings in logs, add trust proxy to Express. The app currently runs behind a local reverse proxy, so rate limiting uses the direct connection IP.

Volumes

Volume Purpose Backup Priority
pgdata PostgreSQL data (all user data, settings, content) Critical
scribe-logs Application log files (YYYY-MM-DD.log) Low

Backup PostgreSQL

docker exec pedscribe-db pg_dump -U pedscribe pedscribe > backup.sql

Restore

cat backup.sql | docker exec -i pedscribe-db psql -U pedscribe pedscribe

Updating

git pull
docker compose build --no-cache
docker compose up -d

Database migrations run automatically on startup (CREATE TABLE IF NOT EXISTS, ALTER TABLE ADD COLUMN IF NOT EXISTS patterns).

Health Check

The container includes a built-in health check:

wget --spider -q http://localhost:3000/api/health

Runs every 30 seconds with a 20-second start period. Docker marks the container as healthy/unhealthy automatically.

Resource Requirements

  • Memory: 256MB minimum, 512MB recommended
  • Disk: ~200MB for Docker image (includes self-hosted Whisper WASM models)
  • PostgreSQL: depends on usage (audio backups use BYTEA storage, auto-deleted after 24h)

Environment-Specific Notes

Production Checklist

  • Set a strong JWT_SECRET (64+ characters)
  • Set a strong DB_PASSWORD
  • Set APP_URL to your actual domain (required for CORS, email links)
  • Configure SMTP for email verification and password reset
  • Use a HIPAA-eligible AI provider if handling PHI (Bedrock, Azure, Vertex)
  • Enable Cloudflare Turnstile for bot protection
  • Set up regular PostgreSQL backups
  • Configure OIDC/SSO for enterprise environments

Development

npm install
cp .env.example .env
# Start PostgreSQL separately or use docker compose for just the DB:
docker compose up -d postgres
node server.js

The app runs on port 3000 by default. Without APP_URL set, CORS allows all origins.

Ports

Service Internal External (default)
Node.js app 3000 127.0.0.1:3552
PostgreSQL 5432 Not exposed

To change the external port, edit docker-compose.yml:

ports:
  - "127.0.0.1:YOUR_PORT:3000"

Logs

Application logs are written to:

  • Console (visible via docker compose logs)
  • /app/data/logs/YYYY-MM-DD.log inside the container (mapped to scribe-logs volume)
  • Database tables: audit_log, api_log, access_log

View logs:

docker compose logs -f pediatric-scribe
docker compose logs --since=1h pediatric-scribe

Auto-Cleanup

The application automatically cleans up expired data:

  • Saved encounters: deleted after 7 days (configurable via site.auto_delete_days)
  • Audio backups: deleted after 24 hours
  • Cleanup runs hourly and 10 seconds after startup