Calculators:
- Bedside tab consolidating emergency protocols (Neonatal+Apgar+NRP, Airway/RSI,
Cardiac Arrest/PALS, Respiratory, O2 & Ventilation, Status Epilepticus,
Sepsis & Fever with PECARN/Aronson/Rochester/Step-by-Step, Anaphylaxis,
Procedural Sedation, Agitation, Antiemetics, Antimicrobials, Burns with
Lund-Browder body-parts TBSA + Parkland, Toxicology, Trauma).
- Global age→weight estimator at top of Calculators tab (APLS + Best Guess).
- Pressure-time waveform SVG teaching graphic for Ventilation.
- Algorithm image lightbox (fullscreen, Esc/tap-to-close).
- Every weight-based dose shows mg/kg inline for clinician verification.
- Drug tables wrapped in overflow-x:auto for mobile.
Infrastructure:
- Pure dose math extracted to public/js/calc-math.js (dual-export Node+browser).
- 36 unit tests in test/calc-math.test.js via node:test (zero new deps).
- "npm test" added to package.json.
New feature: after generating any clinical note, the app automatically
suggests relevant billing codes displayed as clickable chips below the output.
Backend (src/routes/billing.js):
- POST /api/suggest-codes endpoint analyzes note text
- Extracts diagnoses from Assessment section via regex
- Looks up ICD-10 codes: local common pediatric map (40+ conditions)
first, then NLM Clinical Tables API for unknown terms
- Suggests CPT E/M codes based on note type, visit complexity,
ROS/PE system counts, and MDM level estimation
- Supports: outpatient (new/established), well visit (age-based),
ED, inpatient (admit/subsequent/discharge)
Frontend (public/js/app.js):
- suggestBillingCodes() renders collapsible card with ICD-10 and CPT chips
- Click any chip to copy the code to clipboard
- Shows E/M level assessment (diagnosis count, ROS, PE, MDM complexity)
- Disclaimer: "Suggestions only. Always verify codes."
Integration: called after note generation in all 6 tabs
(encounter, SOAP, sick visit, well visit, hospital course, chart review)
Calculators tab with 7 tools:
- BP Percentile (AAP 2017) with age/sex/height classification
- BMI Percentile (CDC 2000) with extended obesity classification
(Class 1/2/3 using % of 95th percentile per CDC 2022)
- Growth Charts: weight-for-age, length-for-age, head circumference,
weight-for-length (WHO/CDC LMS), Fenton preterm (22-50 weeks)
- Bilirubin: AAP 2022 phototherapy threshold + Bhutani nomogram
with Nelson Table 137.1 risk factors for severe hyperbilirubinemia
- Vital Signs by Age (Harriet Lane) with quick reference formulas
(estimated weight, min SBP, ETT size, maintenance fluids 4-2-1)
- Body Surface Area (Mosteller formula)
- Weight-Based Dosing with max cap and volume calculation
Fix growth chart sub-tab navigation (pills scoped separately from
top-level nav to prevent panel disappearing)
- Add FAQ tab with accordion sections: Getting Started, AI & Models,
Voice & Transcription, Saving & Export, Privacy & Security,
Well Visit & Sick Visit, Learning Hub, Troubleshooting
- Documents how AI learns from physician edits (correction tracker)
- Fix FAQ accordion (CSP was blocking inline script, moved to app.js)
- Patch all 5 npm vulnerabilities: nodemailer 8.0.5, xmldom, basic-ftp,
path-to-regexp (npm audit now reports 0 vulnerabilities)
- Remove model category grouping from dropdown (flat list, no optgroups)
- Fix model dropdown dark background on options (white bg, dark text)
- Update FAQ model guidance to reflect admin-managed model selection
Security:
- Add session management: users can view/revoke active sessions in Settings
- Add password change in Settings (requires current password, HIBP check)
- Force logout all sessions on password reset
- Fix logout to destroy server-side session (was only clearing cookie)
- Add trust proxy for correct client IP in rate limiting and audit logs
- Add CORS support for multiple domains (CORS_ORIGINS env var)
- Add HIBP breach check endpoint and inline warnings on password fields
Audit logging:
- Add audit logging to all 24 PHI-handling endpoints across 13 route files
- Covers: generation, transcription, TTS, refine, encounters, documents, Nextcloud
- All fire-and-forget (no response delay)
AI improvements:
- Refine now includes original source material (transcript, notes, labs)
so AI can reference the full input when modifying output
- Add correction tracking (trackAIOutput) to sick visit and well visit tabs
- Fix sickvisit missing from encounter save noteIdMap
UI fixes:
- Non-blocking busy bar for transcription and AI generation (replaces full-screen overlay)
- Fix encounter recording: hide record button during recording (was showing two stop buttons)
- Fix ROS/PE "All WNL" stacking duplicate event handlers; add Clear buttons
- Enlarge AI instructions textarea in Learning Hub CMS
Domain:
- Primary domain now app.pedshub.com, with scribe.pedshub.com and peds.danvics.com as CORS origins
- 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
- Full model management UI in admin panel: toggle models on/off, add custom
model IDs (any OpenRouter/Bedrock ID), set admin-configured default model
- /api/models now returns admin-set default model, frontend respects it
- Toggle switch CSS for clean enable/disable UX
- Backend already had the API endpoints, this adds the missing UI
- Add local Whisper (whisper.cpp / faster-whisper) as transcription provider
Set TRANSCRIBE_PROVIDER=local with configurable model size and binary path
- Upgrade all refine/instruction inputs to resizable textareas across
encounter, dictation, hospital course, chart review, well visit, sick visit
- Make AI memory injection flexible: physician preferences and corrections
are now actively applied (not just "formatting reference"), while still
overridable by current prompt instructions
- Add type="button" to all CMS action buttons to prevent default submit
- Change overflow:hidden to overflow:visible on .cms-main to prevent clipping
- Add z-index to .cms-editor-actions for reliable click targeting
- Replace AI "Topic" text input with a descriptive textarea context box
so users can tell AI what to generate (AI creates its own title)
- Rename AI tab from "By Topic" to "Describe Content"
Bug: classList.toggle('hidden') was silently ignored because
.lh-ai-opt-field{display:flex} is defined at CSS line 758, after
.hidden{display:none} at line 242 — same specificity, later rule wins.
Fix: updateAiOptions() now uses element.style.display directly (inline
styles always override class rules).
Also fix initial state: lh-ai-slides-field now uses style="display:none"
instead of class="hidden" so it's correctly hidden on load.
Panel syncs content type from editor on open (editorType → ctype select
→ updateAiOptions called immediately).
Per type:
- Quiz: word count hidden, slides hidden, quiz card visible (no toggle)
- Presentation: word count hidden, slides visible, quiz card hidden
- Article/Pearl: word count visible, slides hidden, quiz card with toggle
Quiz card redesign: gradient blue/indigo background, white header with
icon, clean body — replaces the plain grey rectangle.
REVERT: httpOnly cookie auth removed — reverts to JWT in localStorage.
The cookie implementation broke the login page (always-hidden auth screen).
localStorage token approach is restored fully:
- Login/register return token in JSON body
- getAuthHeaders() sends Authorization: Bearer header
- Session check reads localStorage token on load
- clearSession() removes localStorage token
Fix: slide preview padding — section elements now have 40px 48px padding
so text is not flush against the frame edges.
Kept from v3.14: AI panel context-aware options (word count, slide count,
quiz question toggle), delete confirmation wording per content type.
Delete bar bug:
- Root cause: .lh-delete-confirm-bar{display:flex} defined after .hidden{display:none}
so flex overrode hidden (no !important on global .hidden rule)
- Fix: remove display:flex from base rule, use .lh-delete-confirm-bar:not(.hidden){display:flex}
so hidden class always wins regardless of CSS order
Slide preview (replace window.open + document.write approach):
- Backend /preview-slides now returns JSON: {css, slides[]} (individual <section> HTML)
- In-page full-screen modal with dark overlay, white slide frame
- Prev/Next arrow buttons, dot indicators, slide counter
- Keyboard navigation (arrow keys, Escape to close)
- Touch/swipe support for mobile
- Overlay click closes modal
- No popups required, works in all browsers
Marp textarea:
- Placeholder updated to guide users: "Click AI Generate above to create slides"
- Makes it clear AI is the primary authoring path; textarea for review/edits
Delete confirmation:
- Replaced browser confirm() popup with inline red warning bar in editor
- Shows content title, Cancel and Delete buttons inline in the editor header
- Category delete uses double-click pattern with toast feedback
Login screen:
- Changed from dark blue/purple gradient to light gray background (var(--g50))
- Card now matches 404 page style: white, subtle blue shadow, indigo border
Presentation content type:
- New 'Presentation' button in CMS toolbar (green style)
- Marp markdown textarea editor (dark code editor style) shown when type=presentation
- Body/Tiptap editor hidden; Marp section shown (toggleEditorMode)
- Preview button: renders Marp HTML via @marp-team/marp-core, opens in new tab
- Download PPTX: pure-JS pptxgenjs (no Chromium), parses slides, exports .pptx
- AI generate: returns Marp markdown directly when contentType=presentation
- Body column stores Marp markdown for presentations
Backend:
- POST /api/admin/learning/generate-pptx — pptxgenjs PPTX from Marp markdown
- POST /api/admin/learning/preview-slides — Marp HTML preview
GitHub repo set to private via API.
Backend (src/routes/learningAI.js):
- POST /api/admin/learning/ai-generate
* Accepts: topic text, uploaded file (PDF/TXT/MD/HTML), or Nextcloud WebDAV path
* Extracts text from PDFs via pdf-parse; plain text read directly
* Fetches WebDAV files using stored Nextcloud credentials
* Prompts AI to return structured JSON: title, subject, body (HTML), questions[]
* Strips code fences, falls back to regex JSON extraction if needed
- POST /api/admin/learning/ai-refine — refine existing body with instructions
- GET /api/admin/learning/webdav-browse — PROPFIND-based Nextcloud file browser
- POST /api/admin/learning/webdav-path — save user's default browse path
Frontend:
- AI Generate button in CMS editor header (gradient purple→blue)
- Panel with 3 source tabs: By Topic / Upload File / Nextcloud
- Drag-and-drop file dropzone with DataTransfer API support
- WebDAV file browser: navigate folders, select files, breadcrumb path
- Options: question count, content type (article/quiz/pearl), model selector, instructions
- Refine Current Body: prompt-driven AI rewrite of existing content
- Generated content auto-fills title, subject, type, Tiptap body, quiz questions
Settings:
- Nextcloud section: "Learning Hub Default Browse Path" field (shown when connected)
- Saves to webdav_learning_path column via /api/admin/learning/webdav-path
DB: ALTER TABLE users ADD COLUMN IF NOT EXISTS webdav_learning_path TEXT
- Bundle Tiptap 2 (StarterKit, Link, Underline) with esbuild into
public/vendor/tiptap.bundle.js — fully self-hosted, no CDN needed
- Remove Quill (quill.min.js, quill.snow.css, patchQuillTooltip hack)
- Headless Tiptap editor: custom toolbar (bold/italic/underline/strike,
headings, lists, blockquote, code, link) with active-state highlighting
- Link insertion: inline link bar below toolbar (no popup, no tooltip)
— type URL, press Apply or Enter; Remove button to unset
- Mini editor for question text and option text (same toggle UX)
- ProseMirror content styles: headings, lists, blockquote, code, links
Quill tooltip: move tooltip element to document.body via patchQuillTooltip()
so overflow:hidden on .cms-main cannot clip it. Recalculates position from
container-relative to viewport (fixed) coordinates with viewport clamping.
Removes overflow:hidden from quill wrappers; applies border-radius to toolbar/container.
Registration: hide #show-register by default in HTML; reveal only after
registration-status fetch confirms enabled=true. Endpoint already returns 403
when disabled — no backend change needed.
- Replace textarea+toolbar with Quill.js (free, MIT) for body editor
- Full WYSIWYG: headings, bold/italic, lists, blockquote, code, link (inline, no popup)
- Rich Text toggle button on each question text field and option text field
- Plain textarea by default; toggle activates mini Quill editor per field
- New 'Multiple Select' question type: checkboxes, all correct must be chosen
- Backend scoring: allCorrectChosen && noWrongChosen
- Results show all correct options highlighted, wrong selections flagged
- quiz display uses sanitizeHtml for question/option text (supports formatted HTML)
- sanitizeHtml allows Quill class attrs (ql-indent, etc.)
Adds setOutputText() helper that escapes HTML and converts \n to <br>,
applied to all AI-generated note outputs so line breaks are preserved
in contenteditable divs. Also cleans up CSS for quiz option markers.
- New dedicated Content Manager tab (WordPress-like layout) with:
- Stats dashboard (published, drafts, categories, quizzes, attempts)
- Sidebar with category tree and filter controls (status, category)
- Table-style content list with search
- Full-page editor with title bar, meta fields, body editor, quiz builder
- Content Manager visible only for admin and moderator roles in sidebar
- Removed CMS from admin panel (admin panel is admin-only again)
- Email templates: fully responsive with max-width, proper mobile breakpoints,
table-based layout for Outlook/Gmail compatibility, no overflow
- Security: escape all user data in emails with escHtml(), escape APP_URL
in verify-email HTML, replace raw err.message with generic errors in auth
- Security: email body from admin settings now HTML-escaped before rendering
- New Learning Hub under Pediatric menu with content feed, category browsing,
search, content viewer, and interactive quizzes (MCQ, true/false)
- Quiz system with per-option wrong-answer explanations and general explanations
- Admin CMS for creating/editing categories, content (articles, pearls, quizzes),
and inline question builder with answer options
- 3-role system: admin (full access), moderator (can manage Learning Hub content),
user (all clinical features + learning hub read access)
- 5 new database tables: learning_categories, learning_content, learning_questions,
learning_options, learning_progress
- User progress tracking with score history per quiz
- Moderators see "Content Manager" tab instead of full Admin panel
- Growth reference data by age (newborn through 21y): expected weight/length/HC
gains per day/month/year, puberty growth spurt details
- Feeding/nutrition guidance by age: formula amounts, breastfeeding frequency,
solid food introduction timeline, juice limits, milk transitions, calorie needs
- BMI/obesity classification per AAP 2023 CPG + CDC Extended BMI:
Underweight, Healthy, Overweight, Obesity Class I/II/III with action items
(≥120% and ≥140% of 95th percentile thresholds)
- Weight-for-length guidance for children <2 years
- "By Visit" panel now shows growth reference + feeding guidance + BMI table
- Well visit AI prompt updated to include growth assessment, BMI classification,
and feeding counseling in generated notes
- Backend injects age-appropriate growth/nutrition data into AI context
- Fix 2FA status stuck at "Loading...": export load2FAStatus globally so
app.js tabChanged handler can call it when navigating via sidebar
- Fix admin models silent failure: add error message + retry button on catch
- Fix save encounter doubles: persist _savedEncId_* to sessionStorage so
page refresh reuses existing record instead of inserting a duplicate;
add _savingInProgress guard to prevent race-condition double-saves
- Desktop sidebar collapsible: add collapse/expand buttons (not collapsed
by default), state saved to localStorage; hidden on mobile
- Copy to Visit Note now also copies SSHADESS assessment to wv-shadess-text
- Store selected visit age in window._wellVisitAge + sessionStorage so
other tabs can read the patient's age
- Bigger screening/vaccine boxes: min-height on wv-vax-list, wv-screen-list,
wv-visit-detail; slightly more padding on vaccine items
- Wire New Patient (clearTab) buttons to document click handler
- CSS: .enc-load-popover.hidden now overrides display:flex (specificity bug
caused popovers to always be visible)
- resumeEncounter: add domPfxMap to correctly resolve label element IDs
(enc_type 'wellvisit' → 'wv-label', 'hospital' → 'hosp-label', etc.)
- resumeEncounter: use noteIdMap to find the right output element per tab
- resumeEncounter: use enc.enc_type (not tabName) as _savedEncId_ key for
consistency with saveFromTab
- Replace horizontal tab-nav with collapsible left sidebar (sticky desktop, slide-in mobile with hamburger toggle)
- Fix tab persistence: use localStorage instead of URL hash; restore last tab after login in enterApp()
- Fix admin CMS models loading: move autoDeleteDays read inside .then() callback (was ReferenceError), switch admin loading from click-only to tabChanged event
- Add Save/Load bars to Hospital Course and Chart Review tabs with popover support
- Add wv (well visit) save handler in encounters.js
- Register load handlers for hospital and chart tabs
- Expand popover prefix list to include hosp and chart
- Wrap save-bar + popover in .save-bar-wrap (position:relative) so the
absolute-positioned popover anchors correctly below the Load button
(previously popovers were outside the save-bar, so had no positioned
ancestor and appeared at the wrong place on screen)
- Remove confirm() dialog from deleteEncounter — encounter disappears
immediately from the popover list after deletion
- ICD-10 diagnoses: replace static-only lookup with live NLM Clinical
Tables API search (clinicaltables.nlm.nih.gov) with 280ms debounce;
results appear in a dropdown below the search input; Enter/click selects
- Add clinicaltables.nlm.nih.gov to CSP connect-src
- Drop unused position:relative from .save-bar (now on .save-bar-wrap)
- Add Well Visit tab with three sub-views: By Visit Age, Full Vaccine Schedule, Catch-Up Schedule
- By Visit Age: shows ICD-10/CPT billing codes, vaccines due with dose info, measurements, sensory/developmental/behavioral/procedure screenings, oral health, notes
- Full Schedule: scrollable table of all vaccines vs all visit ages
- Catch-Up Schedule: per-vaccine minimum ages, intervals, and catch-up notes per CDC 2025
- Add pediatricScheduleData.js (1719-line AAP 2025 Bright Futures dataset)
- Add wellVisit.js for tab logic (lazy-initialized on first tab activation)
- Fire tabChanged CustomEvent on tab switch for lazy initialization
- Add Well Visit CSS styles to styles.css