pediatric-ai-scribe-v3/docs/configuration.md
Daniel fa2e7523d6
Some checks failed
Forgejo Docker Build / Build Docker image (push) Blocked by required conditions
Forgejo Docker Build / Deploy to the host (push) Blocked by required conditions
Forgejo Android APK / Root app tests (push) Successful in 50s
Forgejo Docker Build / Root app tests (push) Successful in 48s
Forgejo Android APK / Build signed APK (push) Has been cancelled
docs: My Resources, sign-in codes, invitations, and what the image carries
Nothing documented My Resources, the slide renderer, PubMed or web search, and
the authentication doc predated both sign-in codes and registration invitations.

docs/my-resources.md is new and covers the feature end to end: what a resource
is, where its material comes from, why both searches run in the route rather
than as tools the model never called, why keyword engines get the topic while
retrieval gets the instruction too, how a presentation is designed as a deck
rather than written as markdown, the separate multi-image path, and what the
export pipeline is made of.

docs/authentication.md gains sign-in codes — storage, lifetime, reuse,
supersession, guessing, and that two-factor still applies — and registration
invitations, including the exact condition that decides when a code may be
deleted and why it is written to match the status the list displays. Both new
rate limits are in the table, with a note that Express matches app.use paths on
segment boundaries, so a new sign-in endpoint needs its own limiter or it has
none at all.

docs/deployment.md now says what the runtime image carries and why — pandoc for
Word, python3 with apk-installed lxml and pillow for the slide renderer,
python-pptx pinned, and that PDF conversion is not in the image at all but goes
to Gotenberg, so Word and PowerPoint still work when it is down.

docs/configuration.md picks up LOGIN_RATE_LIMIT_MAX, LOGIN_CODE_RATE_LIMIT_MAX
and GOTENBERG_URL, none of which were listed. README gains a My Resources
section and indexes the two new docs.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dv6sqaY6Vq3ChZHMem3cnU
2026-09-11 20:49:10 +02:00

9.2 KiB

Configuration

Runtime configuration sources, in override order (later wins for overlapping keys):

  1. .env file / container environment variables (startup only)
  2. app_settings table (live, editable from Admin Panel with 2-minute cache)

Environment variables

Core (production-required)

Variable Purpose
APP_URL Public base URL. Enables production mode — fail-closed CORS, HSTS, secure cookies.
JWT_SECRET HMAC key for JWT signing and OIDC state. Server refuses to start without it in production.
DATA_ENCRYPTION_KEY AES-256-GCM key for PHI at rest (Nextcloud tokens, audio backups). 64 hex chars (openssl rand -hex 32). Refuses to start without it in production.
AUDIO_BACKUPS_S3_ENDPOINT, _BUCKET, _REGION Optional. Keeps the 24-hour recording copies in object storage instead of the audio_backups column; metadata stays in Postgres either way. See docs/speech.md.
AUDIO_BACKUPS_S3_ACCESS_KEY_FILE, _SECRET_KEY_FILE Credentials for the above, read from files so they never appear in the process environment. AUDIO_BACKUPS_S3_ACCESS_KEY / _SECRET_KEY are the inline fallback.
DB_PASSWORD / DATABASE_URL Postgres password or full connection string.
PORT HTTP listen port (default 3000).
NODE_ENV production forces prod-only guards on even without APP_URL.

CORS

Variable Purpose
CORS_ORIGINS Comma-separated additional allowed origins beyond APP_URL.

AI provider

Variable Purpose
AI_PROVIDER openrouter / bedrock / azure / vertex / litellm. If unset, the startup loader uses configured credentials and the last initialized provider in Bedrock → Azure → Vertex → LiteLLM order wins; otherwise OpenRouter is the default.
OPENROUTER_API_KEY OpenRouter key (not HIPAA-eligible).
AWS_BEDROCK_REGION, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY Bedrock chat provider.
AZURE_OPENAI_ENDPOINT, AZURE_OPENAI_API_KEY, AZURE_DEPLOYMENT_NAME, AZURE_OPENAI_API_VERSION Azure OpenAI.
GOOGLE_VERTEX_PROJECT, GOOGLE_VERTEX_LOCATION, GOOGLE_APPLICATION_CREDENTIALS Vertex AI chat provider.
LITELLM_API_BASE, LITELLM_API_KEY OpenAI-compatible AI gateway (Bifrost, LiteLLM, or similar).

Speech-to-text

Variable Purpose
TRANSCRIBE_PROVIDER Use litellm; auto mode uses LiteLLM when configured.
LITELLM_STT_MODEL Model name for LiteLLM-routed STT.

Text-to-speech

Variable Purpose
LITELLM_TTS_MODEL, LITELLM_TTS_VOICE LiteLLM-routed TTS model and default voice.
LITELLM_TTS_VOICES Comma-separated LiteLLM-compatible voices exposed in voice search and user preferences.

Embeddings

Variable Purpose
EMBEDDING_MODEL LiteLLM embedding model name (default openai-text-embedding-3-large).
EMBEDDING_DIMENSIONS Vector dimensions (default 3072).

Email (SMTP)

Variable Purpose
SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASS, SMTP_FROM SMTP config for verification + password reset emails. Overridable per-instance via app_settings.

Security / external

Variable Purpose
TURNSTILE_SITE_KEY, TURNSTILE_SECRET_KEY Cloudflare Turnstile. Turnstile check is no-op when secret is unset.
LOKI_URL Optional Loki ingest URL for shipping audit/api/access logs.
NTFY_URL, NTFY_TOPIC Optional ntfy push for new-login / password-change notifications.
LOGIN_RATE_LIMIT_MAX Sign-in attempts per IP per 15 min (default 10). Raised in the e2e stack so multi-worker Playwright runs do not trip it.
LOGIN_CODE_RATE_LIMIT_MAX Emailed sign-in codes per IP per hour (default 5). Lower than the sign-in limit because each request sends mail to somebody else's address. See docs/authentication.md.

Integrations

Variable Purpose
NEXTCLOUD_URL Nextcloud base URL (per-user credentials entered in app).
GOTENBERG_URL Document conversion service for PDF export (default http://gotenberg:3000). PowerPoint and Word are produced in-process and keep working when this is unreachable; only PDF fails.
S3_BUCKET, S3_REGION, S3_PREFIX, S3_ENDPOINT, S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY, S3_FORCE_PATH_STYLE Document object storage. S3_FORCE_PATH_STYLE=true for MinIO, Backblaze B2, most non-AWS providers.

app_settings — live runtime configuration

Key-value rows in the app_settings table. Read via config.get(key, default) with 2-minute in-memory cache. Writes invalidate the cache immediately.

Registration & site

Key Purpose
registration_enabled true/false. Gate new signups.
site.name Display name.
site.auto_delete_days Days before encounters auto-expire (default 7).

Announcements

Key Purpose
announcement.text Banner text. Empty = banner hidden.
announcement.type info / warning / error / success.

SMTP overrides (override env)

smtp.host, smtp.port, smtp.user, smtp.pass, smtp.from.

Email templates

email.{flow}.subject, email.{flow}.body where {flow} is verify / reset / new_login / password_changed.

OIDC / SSO

Key Purpose
oidc.enabled Toggle SSO.
oidc.issuer OIDC issuer URL.
oidc.client_id, oidc.client_secret OAuth client credentials.
oidc.button_label Login-page button text (default "Sign in with SSO").
oidc.disable_local_auth Hide local login form when SSO is enabled.
oidc.allowed_ips CIDR whitelist for SSO (optional).

AI / models / prompts

Key Purpose
models.default Default model ID.
models.disabled JSON array of disabled model IDs.
models.custom JSON array of admin-added models.
ai.allow_model_fallback Enable silent fallback to secondary model on primary failure. Default false — fallback could spill to a non-BAA provider.
stt.model, tts.model, tts.voice System-wide STT/TTS defaults (users can override per-account).
prompt.{name} Prompt overrides. Any template in src/utils/prompts.js can be replaced live.
embeddings.model, embeddings.dimensions Override embedding config.

Feature flags

feature.* — any key matching this prefix can be consulted via config.get('feature.foo').

Internal migration flags

Key Purpose
migration.text_indexes_c Set to 'true' once lookup-critical text indexes have been converted to COLLATE "C". Prevents re-running.

Admin panel

The Admin Panel (/admin route, admin-only) exposes everything above plus:

  • User list: verify, disable, delete, promote to admin/moderator.
  • Session viewer: active sessions per user, admin-revoke.
  • Logs: audit / api / access tables with filtering.
  • Detailed health: /api/health/detailed reports configured providers (admin-only; the public /api/health returns only {ok: true} to avoid leaking stack info).
  • Model management: enable/disable, add custom, set default, discover from provider.
  • Prompt editor: live-edit any PROMPTS.* key.
  • Test SMTP / test STT / test TTS.

Switching AI gateways

The LITELLM_API_BASE and LITELLM_API_KEY variables work with any OpenAI-compatible gateway — LiteLLM, Bifrost, or other proxies.

Migration steps

  1. Set the base URLLITELLM_API_BASE should include /v1 if the gateway serves on that path (e.g., https://gateway.example.com/v1). The application normalizes double /v1 paths internally for TTS, STT, and embedding endpoints.

  2. Set the API keyLITELLM_API_KEY accepts any key format the gateway issues (virtual keys, bearer tokens, etc.).

  3. Update model names — Different gateways use different naming conventions. Bifrost requires provider/model format (e.g., openrouter/gpt-4.1), while LiteLLM can use deployment aliases (e.g., openrouter-gpt-4.1). Update model names in:

    • Admin Panel → Models (chat models)
    • Admin Panel → Settings → stt.model (speech-to-text)
    • Admin Panel → Settings → tts.model (text-to-speech)
    • LITELLM_TTS_MODEL env var (if set)
  4. Embedding model — Set via Admin Panel → Settings → embeddings.model. The embedding vector column is VECTOR(768), so any model producing 768 dimensions works without re-embedding (e.g., vertex/text-embedding-005). Switching to a model with different dimensions requires altering the column and re-embedding all content.

  5. Restart the containerdocker compose up -d --force-recreate to pick up .env changes (a plain restart does not re-read .env).

Verified gateways

Gateway Model format Notes
Bifrost provider/model Virtual keys, semantic caching, MCP gateway
LiteLLM Custom aliases Requires PostgreSQL + Redis
Any OpenAI-compatible Varies Must serve /v1/chat/completions, /v1/audio/speech, /v1/audio/transcriptions, /v1/embeddings

Retrieval sizing

How many corpus excerpts the Clinical Assistant, the Learning Hub and My Resources each receive, and the reranker cap that overrides all three: retrieval-tuning.md.