# ============================================================ # OPENBAO (optional — recommended for production) # ============================================================ # When these three are set, the container fetches everything else below # from OpenBao at kv/ped-ai/prod and ignores the equivalent .env values. # Leave them unset (or blank) to fall back to .env-only (local dev, e2e). # # OPENBAO_ADDR=https://app.danvics.com # OPENBAO_ROLE_ID= # OPENBAO_SECRET_ID= # OPENBAO_KV_PATH=kv/ped-ai/prod # override path if needed # ============================================================ # Everything below is sourced from OpenBao when OPENBAO_ADDR is set. # Only fill these in for local dev / e2e / when running without vault. # ============================================================ # ============================================================ # AI PROVIDER (choose one) # ============================================================ # Option 1: OpenRouter (default, cheapest, NOT HIPAA) AI_PROVIDER=openrouter OPENROUTER_API_KEY=sk-or-v1-your-key # Option 2: AWS Bedrock (HIPAA compliant with BAA) # AI_PROVIDER=bedrock # AWS_BEDROCK_REGION=us-east-1 # AWS_ACCESS_KEY_ID=AKIA... # AWS_SECRET_ACCESS_KEY=... # (Or use IAM role — no keys needed if running on EC2/ECS) # Option 3: Azure OpenAI (HIPAA compliant with BAA) # AI_PROVIDER=azure # AZURE_OPENAI_ENDPOINT=https://your-resource.openai.azure.com # AZURE_OPENAI_API_KEY=your-key # AZURE_DEPLOYMENT_NAME=gpt-4o-mini # AZURE_OPENAI_API_VERSION=2024-02-01 # Option 4: Google Vertex AI (HIPAA compliant with BAA) # AI_PROVIDER=vertex # GOOGLE_VERTEX_PROJECT=your-gcp-project-id # GOOGLE_VERTEX_LOCATION=us-central1 # GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json # (Or use default credentials if running on GCE/GKE/Cloud Run) # # Google STT — Gemini inline audio (auto-detected when GOOGLE_VERTEX_PROJECT set) # TRANSCRIBE_PROVIDER=google # GOOGLE_STT_MODEL=gemini-2.0-flash # or gemini-2.5-flash for better accuracy # # Google TTS — Google Cloud Text-to-Speech (auto-detected when GOOGLE_VERTEX_PROJECT set) # TTS_PROVIDER=google # GOOGLE_TTS_VOICE=en-US-Journey-F # female | en-US-Journey-D = male # Other options: en-US-Studio-O, en-US-Neural2-C, en-US-Neural2-J # Option 5: LiteLLM Proxy (self-hosted, routes to any provider) # AI_PROVIDER=litellm # LITELLM_API_BASE=http://localhost:4000 # LITELLM_API_KEY=sk-litellm-your-key # Admin can discover available models via the admin panel # # LiteLLM Speech-to-Text # TRANSCRIBE_PROVIDER=litellm # LITELLM_STT_MODEL=whisper-1 # Use the model name from your LiteLLM model_list # If your LiteLLM config uses full paths as model names, use the full path: # LITELLM_STT_MODEL=openai/whisper-1 # NOTE: vertex_ai/chirp does NOT work via LiteLLM audio proxy. # For Vertex AI speech, use TRANSCRIBE_PROVIDER=google (Gemini inline audio). # # LiteLLM TTS # TTS_PROVIDER=litellm (auto-detected when LITELLM_API_BASE set) # LITELLM_TTS_MODEL=tts-1 # Use model name from your LiteLLM model_list # If your config uses full paths: LITELLM_TTS_MODEL=vertex_ai/google-tts # LITELLM_TTS_VOICE=en-US-Journey-F # Google Cloud voice name (or alloy/nova for OpenAI) # ============================================================ # TRANSCRIPTION (speech-to-text) # ============================================================ # Option A: OpenAI Whisper (default if no AWS configured) OPENAI_API_KEY=sk-your-openai-key # Option B: Amazon Transcribe (HIPAA eligible, no S3 needed) # Uses same AWS credentials as Bedrock above. # Set TRANSCRIBE_PROVIDER=aws to force AWS even if OPENAI_API_KEY is set. # Leave unset to auto-detect (uses AWS when AWS_BEDROCK_REGION is configured). # TRANSCRIBE_PROVIDER=aws # Option C: Local Whisper (privacy-first, no cloud API needed) # Requires whisper.cpp or faster-whisper installed on the server. # TRANSCRIBE_PROVIDER=local # WHISPER_MODEL_SIZE=small # tiny, base, small, medium, large # WHISPER_BINARY=whisper-cpp # or: whisper, faster-whisper # WHISPER_MODEL_PATH= # custom path to .bin model file # WHISPER_LANGUAGE=en # WHISPER_THREADS=4 # defaults to CPU count - 1 # Amazon Transcribe Medical — better accuracy for clinical dictation # Knows drug names, diagnoses, procedures, SOAP terminology # HIPAA eligible (ensure your AWS account has a BAA) # AWS_TRANSCRIBE_MEDICAL=true # AWS_TRANSCRIBE_SPECIALTY=PRIMARYCARE # Other options: CARDIOLOGY, NEUROLOGY, ONCOLOGY, RADIOLOGY, UROLOGY # Optional ELEVENLABS_API_KEY= # Push Notifications (ntfy — self-hosted, optional) # NTFY_URL=https://ntfy.yourdomain.com # NTFY_TOKEN=tk_your_token_here # App PORT=3000 APP_URL=https://your-domain.com # Cloudflare Turnstile (anti-bot on registration, optional) # TURNSTILE_SITE_KEY=your-site-key # TURNSTILE_SECRET_KEY=your-secret-key JWT_SECRET=generate-a-random-64-char-string-here # Application-layer encryption key for PHI at rest (Nextcloud tokens, audio backups) # Generate with: openssl rand -hex 32 # REQUIRED in production. Rotating invalidates existing encrypted data. DATA_ENCRYPTION_KEY=generate-with-openssl-rand-hex-32 # Email (for verification & password reset) SMTP_HOST=smtp.gmail.com SMTP_PORT=587 SMTP_USER=your-email@gmail.com SMTP_PASS=your-app-password SMTP_FROM=noreply@yourdomain.com # Nextcloud (optional) NEXTCLOUD_URL=https://cloud.yourdomain.com # S3 Document Storage (optional — works with AWS S3, Backblaze B2, MinIO) # S3_BUCKET=your-bucket-name # S3_REGION=us-east-1 # S3_PREFIX=documents/ # # For AWS S3: uses same AWS credentials as Bedrock above, or set S3-specific keys: # S3_ACCESS_KEY_ID=... # S3_SECRET_ACCESS_KEY=... # # For Backblaze B2: # S3_ENDPOINT=https://s3.us-west-004.backblazeb2.com # S3_REGION=us-west-004 # S3_ACCESS_KEY_ID=your-b2-application-key-id # S3_SECRET_ACCESS_KEY=your-b2-application-key # # For MinIO (self-hosted): # S3_ENDPOINT=http://minio:9000 # S3_REGION=us-east-1 # S3_ACCESS_KEY_ID=minio-access-key # S3_SECRET_ACCESS_KEY=minio-secret-key # S3_FORCE_PATH_STYLE=true # ============================================================ # EMBEDDINGS (for Learning Hub semantic search) # ============================================================ # Enables vector-based semantic search in Learning Hub # Requires pgvector extension: apt-get install postgresql-16-pgvector # Default model (Vertex AI text-embedding-005, 768 dims, English + code optimized) EMBEDDING_MODEL=vertex_ai/text-embedding-005 EMBEDDING_DIMENSIONS=768 # Other Vertex AI embedding models: # - vertex_ai/text-embedding-005 → 768 dims, English + code (recommended) # - vertex_ai/gemini-embedding-001 → up to 3072 dims, multilingual + code # - vertex_ai/text-multilingual-embedding-002 → 768 dims, multilingual focus # # LiteLLM usage (if using LiteLLM proxy): # EMBEDDING_MODEL=text-embedding-005 # LiteLLM will route to configured provider # # OpenAI fallback (NOT HIPAA-eligible): # Uses text-embedding-3-small if OPENAI_API_KEY is set and no Vertex/LiteLLM configured # ============================================================ # DATABASE # ============================================================ DATABASE_URL=postgresql://pedscribe:@postgres:5432/pedscribe DB_PASSWORD=pedscribe_secret_change_me # ── Audio backups (optional) ──────────────────────────────────────────────── # Every recording is kept for 24 hours, whether its transcription succeeded or # not. Unset, the audio lives in the audio_backups table; set, it goes to a # bucket instead and only metadata stays in Postgres. The generated-images key # is scoped to that bucket and cannot be reused here — create a bucket and a # user of its own, and give the bucket a 24h expiry rule as a backstop. # Audio is gzipped and AES-256-GCM encrypted before it is stored, either way. # AUDIO_BACKUPS_S3_ENDPOINT=http://assets:9000 # AUDIO_BACKUPS_S3_BUCKET=audio-backups # AUDIO_BACKUPS_S3_REGION=us-east-1 # Prefer the _FILE variants: credentials then stay out of the process environment. # AUDIO_BACKUPS_S3_ACCESS_KEY_FILE=/run/secrets/audio-backups-access-key # AUDIO_BACKUPS_S3_SECRET_KEY_FILE=/run/secrets/audio-backups-secret-key # AUDIO_BACKUPS_S3_ACCESS_KEY= # AUDIO_BACKUPS_S3_SECRET_KEY= # ============================================================ # EVERY REMAINING VARIABLE THE APP READS # Completed 2026-09-11: this file listed 18 of the 67 variables src/ actually # reads. Each entry below shows the default the code falls back to, so an # unset line means "this default", not "broken". # ============================================================ # ── Mail ──────────────────────────────────────────────────────────────────── # SMTP_SECURE=false # true for implicit TLS (port 465) # ── Admin lockdown ────────────────────────────────────────────────────────── # With several admins, everything in the admin panel is editable by all of # them. Set this and configuration becomes read-only in the panel and refused # by the server: prompts, model policy, retrieval limits and budgets, TTS/STT, # embeddings, SMTP and email templates. Day-to-day operation stays available — # announcements, registration and invitations, feature flags, site details. # A setting added later is locked until it is deliberately added to the # editable list, rather than defaulting to open. # # It is deliberately an environment variable: a setting could be switched off # by the very admin it restrains, so lifting it needs host access and a # restart. Read access is unaffected — locked settings stay visible. # ADMIN_LOCKDOWN=false # ── Identity and limits ───────────────────────────────────────────────────── # SITE_NAME=Pediatric AI Scribe # API_RATE_LIMIT_MAX=200 # requests per window across /api # LOGIN_RATE_LIMIT_MAX=10 # login attempts per 15 minutes # NODE_ENV=production # with APP_URL, puts the app in production mode: # refuses to start without JWT_SECRET or a CORS origin # CORS_ORIGINS= # extra allowed origins, comma-separated, beyond APP_URL # ── Services ──────────────────────────────────────────────────────────────── # REDIS_URL=redis://ped-ai-redis:6379 # LOKI_URL=http://monitoring-loki:3100 # log shipping; unset disables it # MCP_SERVER_URL= # legacy single MCP URL # ── LiteLLM gateway ───────────────────────────────────────────────────────── # LITELLM_MASTER_KEY= # falls back to OPENAI_API_KEY, then 'sk-litellm' # LITELLM_DEFAULT_MODEL= # falls back to OPENAI_MODEL # LITELLM_FALLBACK_MODEL= # tried when the default model fails # OPENAI_MODEL= # legacy name for the default chat model # LITELLM_TTS_VOICES= # comma-separated voices offered in the pickers # ── Clinical Assistant: retrieval ─────────────────────────────────────────── # CLINICAL_ASSISTANT_MCP_URL=http://mcp:8000/mcp # CLINICAL_ASSISTANT_MCP_URLS= # comma-separated, tried in order # CLINICAL_ASSISTANT_SEARCH_TOOL=clinical_semantic_search # the only accepted value # CLINICAL_ASSISTANT_MCP_INITIALIZE_TIMEOUT_MS=30000 # CLINICAL_ASSISTANT_MCP_REQUEST_TIMEOUT_MS=90000 # CLINICAL_ASSISTANT_MCP_SESSION_TTL_MS=600000 # CLINICAL_ASSISTANT_MCP_WARMUP= # open a session at boot # CLINICAL_ASSISTANT_MCP_WARMUP_DELAY_MS= # ── Clinical Assistant: models and prompts ────────────────────────────────── # CLINICAL_ASSISTANT_IMAGE_MODEL=openai-gpt-image-1 # CLINICAL_ASSISTANT_PROMPT_MODEL= # model that writes the starter prompts # CLINICAL_ASSISTANT_PROMPT_POOL_TARGET=1000 # CLINICAL_ASSISTANT_PROMPT_POOL_KEY=clinical-assistant:prompt-pool:v2 # CLINICAL_ASSISTANT_PROMPT_POOL_REFRESH_MS= # CLINICAL_ASSISTANT_PROMPT_POOL_WARMUP_DELAY_MS= # CLINICAL_ASSISTANT_EXAMPLE_CACHE_MS=600000 # PATIENT_TAKEHOME_BEHAVIOR= # overrides the admin-editable take-home guidance # ============================================================ # OPENBAO (optional) # The entrypoint fetches secrets from OpenBao only when OPENBAO_ADDR is set; # unset, it uses this file and nothing else. A value set here or in the compose # environment always wins over the OpenBao copy, so an override needs no # OpenBao change. # # To use OpenBao: set OPENBAO_ADDR, OPENBAO_ROLE_ID, OPENBAO_SECRET_ID # (and OPENBAO_KV_PATH if not kv/ped-ai/prod) # To stop using it: unset OPENBAO_ADDR, and put the keys it held in this # file. List them without printing values: # bao kv get -format=json kv/ped-ai/prod | jq 'keys' # ============================================================ # OPENBAO_ADDR= # OPENBAO_ROLE_ID= # OPENBAO_SECRET_ID= # OPENBAO_KV_PATH=kv/ped-ai/prod # Optional. Lets something outside this host scrape /metrics with # `Authorization: Bearer `. Unset by default, and an unset token can # never match — Prometheus scrapes pediatric-ai-scribe:3000 directly over the # Docker network, which needs no token. Requests arriving through the reverse # proxy (they carry X-Forwarded-For) get a 404 either way. METRICS_TOKEN=