No description
Find a file
Daniel f39f906fa5 fix(admin): restore SSO settings loading on admin panel
loadOidcConfig() was called from the first IIFE in admin.js but declared
in the second IIFE. Function declarations don't cross IIFE boundaries,
so the call threw ReferenceError and left the SSO form empty with
"Disabled" selected — even when SSO was configured and working. Moved
the call into the tabChanged handler of the IIFE where the function
lives.
2026-04-21 22:19:50 +02:00
.github/workflows ci: multi-arch Docker via native runners + Node 24 opt-in + PAT for tag-trigger chain 2026-04-15 00:05:34 +02:00
android Fix APK crash: replace XML splash with PNG, add real mipmap launcher icons 2026-03-29 11:07:10 +00:00
docs feat: neonatal calculator, DOCX/PPTX/ODT/EPUB support, gateway-agnostic URL helper, TTS/STT fixes 2026-04-19 02:17:06 +02:00
e2e test(e2e): stage 2 — auth-gated pages (11 tabs × 2 viewports, 22 tests) 2026-04-21 01:48:17 +02:00
migrations Batch of security + scale fixes 2026-04-14 05:24:40 +02:00
mobile Release v6.7.0 2026-04-20 21:20:01 +00:00
monitoring Add Loki + Grafana monitoring stack, ntfy notifications, biometric auth 2026-04-11 03:00:52 +02:00
public fix(admin): restore SSO settings loading on admin panel 2026-04-21 22:19:50 +02:00
scripts feat: A1+A2 — Playwright smoke suite + index.html mtime-based caching 2026-04-20 03:51:22 +02:00
src fix: auth/API logging to Loki, TTS voice auto-detection, STT ElevenLabs support 2026-04-19 21:26:49 +02:00
test feat: B — extract drug data to public/data/drugs.json (schema v1.0) 2026-04-20 04:23:24 +02:00
.dockerignore Add .dockerignore (exclude .env, .agent-config, node_modules, data) 2026-03-21 19:27:21 -04:00
.env.example Security hardening: PHI encryption, argon2, DOMPurify, SRI 2026-04-14 02:49:38 +02:00
.gitignore feat: B — extract drug data to public/data/drugs.json (schema v1.0) 2026-04-20 04:23:24 +02:00
.gitmessage docs: add CONTRIBUTING.md + .gitmessage template for conventional commits 2026-04-14 23:51:09 +02:00
.node-pg-migraterc.json Add node-pg-migrate for versioned schema changes + better mobile UA labels 2026-04-14 05:06:19 +02:00
admin-cli.js v3.0.0: Auth, admin panel, security fixes, per-tab model selector 2026-03-21 19:25:51 -04:00
BROWSER_WHISPER_SETUP.md Update docs for v3 truly self-hosted setup 2026-03-31 23:12:46 +00:00
BROWSER_WHISPER_TROUBLESHOOTING.md v16: Make Browser Whisper CDN failure graceful with clear warnings 2026-03-31 16:18:46 +00:00
CONTRIBUTING.md fix: verify auto-version → android + docker pipeline end-to-end 2026-04-15 00:10:35 +02:00
DEVELOPER_GUIDE.md Expand DEVELOPER_GUIDE with detailed architecture, DB layer, file descriptions 2026-03-24 19:30:01 -04:00
docker-compose.e2e.yml test(e2e): stage 2 — auth-gated pages (11 tabs × 2 viewports, 22 tests) 2026-04-21 01:48:17 +02:00
docker-compose.local.yml Feat: admin CMS, save/resume encounters, user templates, SSHADESS, well visit notes, sick visit, ROS/PE checklists, ICD-10 diagnoses 2026-03-22 16:43:39 -04:00
docker-compose.monitoring.yml Update bilirubin to exact AAP 2022 values, add exchange transfusion 2026-04-11 05:50:19 +02:00
docker-compose.yml Maintenance CLI + unpin postgres digest 2026-04-14 04:00:13 +02:00
Dockerfile Dockerfile: add build tools for argon2 native compile 2026-04-14 03:09:38 +02:00
EMBEDDINGS_SETUP.md Add embeddings setup documentation 2026-03-31 14:37:46 +00:00
FEATURES_EXPLAINED.md Fix TTS preview + Browser Whisper preload, add comprehensive docs 2026-03-31 15:13:53 +00:00
grafana-dashboard.json feat: neonatal calculator, DOCX/PPTX/ODT/EPUB support, gateway-agnostic URL helper, TTS/STT fixes 2026-04-19 02:17:06 +02:00
IMPROVEMENTS.md Add automatic ICD-10 and CPT billing code suggestions 2026-04-11 01:50:17 +02:00
OPENID_SETUP.md v4: Fix milestones display + add OpenID auth + 100MB PDF support 2026-04-01 17:59:51 +00:00
package-lock.json FAQ page, dep security patches, model dropdown and UI fixes 2026-04-09 01:56:11 +02:00
package.json Release v6.7.0 2026-04-20 21:20:01 +00:00
README.md docs: add Testing section (unit + Playwright e2e) 2026-04-21 02:14:54 +02:00
server.js fix: scope CORS middleware to /api so static assets aren't rejected 2026-04-20 23:19:50 +02:00
TRANSCRIPTION_OPTIONS.md Add comprehensive transcription options documentation 2026-03-31 21:58:17 +00:00

Pediatric AI Scribe v6

AI-powered clinical documentation platform for pediatric medicine. Generates HPIs, hospital courses, chart reviews, SOAP notes, well/sick visit notes, and developmental milestone assessments from voice recordings or dictation.

Features

Clinical Documentation

  • Live Encounter — record doctor-patient conversations, AI generates structured OLDCARTS HPI
  • Voice Dictation — dictate narrative, AI cleans and restructures
  • Hospital Course — paste progress notes, generates prose, day-by-day, organ-system (ICU), or psych format
  • Chart Review / Precharting — summarize outpatient, subspecialty, and ED notes
  • SOAP Notes — full SOAP or subjective-only from dictation
  • Well Visit — AAP 2025 Bright Futures periodicity with vaccines, screenings, billing codes, SSHADESS (12+), milestones
  • Sick Visit — quick documentation with auto-suggested ROS and PE from chief complaint
  • Developmental Milestones — AAP/Nelson tracker (birth-11y) with narrative/structured/summary output

AI & Speech

  • 5 AI Providers — OpenRouter, AWS Bedrock, Azure OpenAI, Google Vertex AI, LiteLLM
  • 5 STT Providers — Google Gemini, Amazon Transcribe (Medical), OpenAI Whisper, Local Whisper, LiteLLM
  • 3 TTS Providers — Google Cloud TTS, LiteLLM (OpenAI), ElevenLabs
  • Browser Whisper — fully offline in-browser transcription via WebAssembly (HIPAA-safe)
  • Per-tab model selector — choose fast vs. smart vs. premium models per task
  • Physician memory system — Dragon-like learning from your corrections

Learning Hub

  • Content Management — articles, clinical pearls, quizzes, presentations
  • AI Content Generation — generate from topics, uploaded PDFs, or Nextcloud files
  • Marp Presentations — slide editor with preview and PPTX export
  • Semantic Search — vector-based search via pgvector embeddings
  • Quiz System — MCQ, multi-select, true/false with scoring and progress tracking

Platform

  • Multi-user with roles — admin, moderator, user
  • OIDC/SSO — Azure AD, Okta, Keycloak, PocketID, Google
  • 2FA — TOTP-based two-factor authentication
  • Cloudflare Turnstile — bot protection on login, register, password reset
  • Email verification — with customizable templates
  • Nextcloud integration — WebDAV export
  • S3 Document Storage — AWS S3, Backblaze B2, MinIO
  • PWA — installable, works on mobile
  • Admin Panel — user management, settings, prompt editor, model configuration, logs

Quick Start

1. Configure

cp .env.example .env

Edit .env — at minimum set:

AI_PROVIDER=litellm          # or openrouter, bedrock, azure, vertex
LITELLM_API_BASE=https://your-litellm.example.com
LITELLM_API_KEY=sk-...

OPENAI_API_KEY=sk-...        # for Whisper transcription (if not using LiteLLM STT)

JWT_SECRET=<64-char random>  # openssl rand -hex 32
DB_PASSWORD=<strong password>
APP_URL=https://your-domain.com

2. Start

docker compose up -d

App runs on port 3552. First user to register becomes admin.

3. Admin CLI

docker exec pediatric-ai-scribe node admin-cli.js list-users
docker exec pediatric-ai-scribe node admin-cli.js create-admin admin@example.com password123 "Dr. Admin"
docker exec pediatric-ai-scribe node admin-cli.js make-admin user@example.com
docker exec pediatric-ai-scribe node admin-cli.js reset-password user@example.com newpassword
docker exec pediatric-ai-scribe node admin-cli.js toggle-registration
docker exec pediatric-ai-scribe node admin-cli.js stats

AI Provider Configuration

Switch providers by setting AI_PROVIDER in .env. No code changes needed.

Provider HIPAA Config
LiteLLM Depends on backend LITELLM_API_BASE, LITELLM_API_KEY
AWS Bedrock Yes (with BAA) AWS_BEDROCK_REGION, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY
Azure OpenAI Yes (with BAA) AZURE_OPENAI_ENDPOINT, AZURE_OPENAI_API_KEY, AZURE_DEPLOYMENT_NAME
Google Vertex AI Yes (with BAA) GOOGLE_VERTEX_PROJECT, GOOGLE_VERTEX_LOCATION
OpenRouter No OPENROUTER_API_KEY

Transcription (Speech-to-Text)

Set TRANSCRIBE_PROVIDER or let the app auto-detect.

Provider HIPAA Config
Google Gemini Yes GOOGLE_VERTEX_PROJECT, GOOGLE_STT_MODEL
Amazon Transcribe Yes AWS creds + TRANSCRIBE_PROVIDER=aws
Amazon Transcribe Medical Yes AWS_TRANSCRIBE_MEDICAL=true, AWS_TRANSCRIBE_SPECIALTY=PRIMARYCARE
Local Whisper Yes (offline) TRANSCRIBE_PROVIDER=local, WHISPER_BINARY, WHISPER_MODEL_SIZE
OpenAI Whisper No OPENAI_API_KEY
LiteLLM Depends TRANSCRIBE_PROVIDER=litellm, LITELLM_STT_MODEL
Browser Whisper Yes (client-side) No config needed — toggle in user settings

Text-to-Speech

Provider HIPAA Config
Google Cloud TTS Yes GOOGLE_VERTEX_PROJECT, GOOGLE_TTS_VOICE
LiteLLM Depends LITELLM_TTS_MODEL, LITELLM_TTS_VOICE
ElevenLabs No ELEVENLABS_API_KEY

OpenID Connect / SSO

Supports Azure AD, Okta, Keycloak, PocketID, Google, and any OIDC-compliant provider.

  1. Register callback URL: https://your-domain.com/api/auth/oidc/callback
  2. Admin Panel > Settings > Configure OIDC (Issuer URL, Client ID, Client Secret)
  3. Users are auto-created and linked by email on first SSO login

See OPENID_SETUP.md for provider-specific guides.


Cloudflare Turnstile (Bot Protection)

Optional CAPTCHA on login, registration, and password reset forms.

TURNSTILE_SITE_KEY=0x4AAA...
TURNSTILE_SECRET_KEY=0x4AAA...

Email

Without SMTP, email verification is skipped and users are auto-verified.

SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=your-email@gmail.com
SMTP_PASS=your-app-password
SMTP_FROM=noreply@yourdomain.com

Maintenance CLI

After a Postgres image upgrade (major version bump or silent base-layer change), btree indexes on text columns can become inconsistent with the new ICU/glibc library. The app auto-detects this at startup and reindexes on drift, but you can also trigger it manually:

# Health check — no writes
docker exec pediatric-ai-scribe npm run maint:check

# Rebuild all indexes + refresh collation + ANALYZE
docker exec pediatric-ai-scribe npm run maint:reindex

Run maint:reindex any time after:

  • Upgrading the Postgres image (major or minor)
  • Restoring from a dump created on a different Linux distro
  • Seeing "invalid credentials" on credentials you know are correct
  • Seeing 0 rows returned from a lookup that should match

The reindex takes seconds on a small DB and a minute or two on larger ones. Safe to run while the app is serving traffic, though queries may slow briefly.


Docker Hub

docker pull danielonyejesi/pediatric-ai-scribe-v3:latest

Minimal compose without building:

services:
  app:
    image: danielonyejesi/pediatric-ai-scribe-v3:latest
    ports:
      - "3552:3000"
    env_file: .env
    depends_on:
      postgres:
        condition: service_healthy
    restart: unless-stopped

  postgres:
    image: pgvector/pgvector:pg16
    environment:
      POSTGRES_DB: pedscribe
      POSTGRES_USER: pedscribe
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    volumes:
      - pgdata:/var/lib/postgresql/data
    restart: unless-stopped
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U pedscribe"]
      interval: 10s
      retries: 5

volumes:
  pgdata:

HIPAA Notice

This application processes data through third-party AI APIs.

  • All connections use HTTPS/TLS
  • Authentication required for all AI endpoints
  • 2FA and SSO available
  • Cloudflare Turnstile bot protection
  • AWS Bedrock, Azure OpenAI, and Google Vertex AI offer BAAs
  • OpenRouter and ElevenLabs do NOT offer BAAs
  • Browser Whisper and Local Whisper keep audio fully private

Do not use real PHI without executed BAAs with all providers in your deployment.


Documentation

See the docs/ directory for detailed documentation:


Development

npm install
cp .env.example .env   # edit with your keys
# Requires PostgreSQL with pgvector
node server.js

Testing

Two layers, both zero-config after the initial setup.

Unit tests — pure dose math (Node built-in)

npm test

Runs node --test test/ against public/js/calc-math.js — pure functions for APLS / Best Guess weight, Parkland, Holliday-Segar 4-2-1, PRAM, Westley, epi (anaphylaxis vs arrest vs NRP, different concentrations), RSI drugs, min SBP, ETT sizing, Lund-Browder TBSA. 36 assertions, no dependencies.

End-to-end tests — Playwright smoke suite

Runs a headless Chromium against the live app. 128 tests covering every calculator tab, every Bedside sub-pill + widget, auth-gated pages (encounter, well visit, charts, vaccines, catch-up, learning hub, dictation, settings, FAQ), at both desktop and mobile (Pixel 5) viewports.

# First-time setup: spin up the auth-less test container (port 3553)
docker compose -f docker-compose.yml -f docker-compose.e2e.yml up -d pediatric-scribe-e2e

# Then run the full suite (runs inside an official Playwright container)
npm run e2e

The runner script (scripts/e2e.sh) uses mcr.microsoft.com/playwright so you don't need Node or browsers on the host.

Test environment:

  • pediatric-ai-scribe (port 3552) — your normal app
  • pediatric-ai-scribe-e2e (port 3553) — identical image, but with TURNSTILE_SECRET_KEY="" and SMTP_HOST="" so Playwright can log in without a bot challenge. Shares the same Postgres + pgdata volume.
  • Test user: e2e-user@ped-ai.test (auto-verified on first register)
  • Harness page: public/e2e-harness.html loads the calculators component without the auth wall for smoke tests that don't need a logged-in session.

Viewing failures — Playwright writes e2e/test-results/<test-name>/ with:

  • test-failed-1.png — screenshot at the point of failure
  • trace.zip — full action trace (replay with npx playwright show-trace)
  • error-context.md — DOM snapshot and console logs

Everything but the specs and config is gitignored under e2e/.

Files:

  • e2e/tests/bedside-smoke.spec.js — 26 tests for the Bedside module
  • e2e/tests/top-calculators.spec.js — 27 tests for BP / BMI / Growth / Bili / Vitals / BSA / Dose / Resus / GCS / Equipment
  • e2e/tests/auth-gated-smoke.spec.js — 11 tests for the auth-gated tabs
  • e2e/playwright.config.js — runs all the above under both chromium (Desktop Chrome) and mobile-chrome (Pixel 5) projects

Writing a new test:

const { test, expect } = require('@playwright/test');

test('my new smoke test', async ({ page }) => {
  await page.goto('/e2e-harness.html');             // bypasses auth for calculators
  await page.waitForFunction(() => window.__harnessReady === true);
  await page.click('button.calc-nav-pill[data-calc="bedside"]');
  await expect(page.locator('#calc-bedside')).toBeVisible();
});

For auth-gated routes, use the login fixture in auth-gated-smoke.spec.js as a template — it caches the token at module scope so you don't hit the login rate-limit.