Three concurrent themes from this session:
═══════════════════════════════════════════════════════════════════
ED ENCOUNTERS — per-stage cards + consolidate→MDM finalize
═══════════════════════════════════════════════════════════════════
UX redesign per Daniel's feedback ("every stage note should be shown,
if AI is told to modify that particular note then the modified version
is used in final mdm"):
- Each generated stage stays on screen as its own editable card with
its own embedded "Don't Miss" panel. No more single rolling note
element that gets replaced on each generation.
- gatherCurrentNotes() reads contenteditable text from each stage card
before any operation (advance, finalize, persist) so inline edits
flow into the next AI call and the final consolidate.
- Stage badge is now state-accurate. "Stage N (recording)" with yellow
background after Add-more before generation; "Stage N" with gray
after generation. Fixes the bug where the badge flipped to Stage 2
the moment Add-more was clicked.
- Save & Done now runs TWO server-side AI calls in /finalize:
1. edConsolidate (new prompt) → polished single final note that
integrates every stage chronologically (HPI / ROS / PE / ED Course /
A&P with disposition).
2. edFinalize (rewritten with full inline 2023 AMA E/M element
rubric — problems / data / risk definitions, level mapping with
concrete examples) → MDM JSON.
- Two new cards render after finalize: blue-bordered Final Consolidated
Note + green-bordered MDM. Stage cards become read-only.
- partial_data on the saved row now stores {stages, finalNote, mdm,
finalized} so resume re-renders the full state.
Why two-call finalize: a single combined prompt makes the model cut
corners on one task. Two focused calls cost ~2× latency at the very end
of an encounter — acceptable since finalize is a one-time terminal
action, not a per-stage hot path.
Files: public/components/ed-encounter.html, public/js/ed-encounters.js,
src/routes/edEncounters.js, src/utils/prompts.js (edConsolidate added,
edFinalize rewritten).
═══════════════════════════════════════════════════════════════════
EXTENSIONS / PAGERS — visual polish
═══════════════════════════════════════════════════════════════════
Multiple iterations based on Daniel's feedback:
- Layout: align-items:flex-start so action buttons stay pinned top-right
when long numbers wrap (was align-items:center → buttons drifted into
the text area, causing visible overlap).
- Number: word-break:break-all + min-width:0 + font-feature-settings:tnum
so long numbers wrap within their column instead of pushing under the
buttons. Click-to-copy with a 0.55s green flash + ✓ copied badge.
- Phone/pager Font Awesome icon next to the number in the type color —
at-a-glance type signal (replacing an earlier 3px left stripe that
Daniel found visually bulky).
- Name: font-weight 700, font-size 14.5px, color g900, letter-spacing
-0.012em — scan-target headline typography for long lists.
- Alternating subtle backgrounds by index (white vs #fafbfc) so a long
list reads as distinct rows.
- Hover: card lifts 1px with a soft shadow; action buttons fade from
55% to 100% opacity. Cubic-bezier transition on transform.
- Entrance: staggered fade-up animation per card (35ms × index, capped
at 12). prefers-reduced-motion media query disables motion.
- Empty state: 48px FA icon + heading instead of plain gray text.
Files: public/js/extensions.js, public/css/styles.css.
═══════════════════════════════════════════════════════════════════
DOCS REORGANIZATION + APPLICATION-LOGIC DOCS + ADMIN VIEWER
═══════════════════════════════════════════════════════════════════
Document moves (preserving git history via git mv):
BROWSER_WHISPER_SETUP.md → docs/browser-whisper-setup.md
BROWSER_WHISPER_TROUBLESHOOTING.md → docs/browser-whisper-troubleshooting.md
DEVELOPER_GUIDE.md → docs/developer-guide-extended.md
EMBEDDINGS_SETUP.md → docs/embeddings-setup.md
FEATURES_EXPLAINED.md → docs/features-explained.md
IMPROVEMENTS.md → docs/improvements.md
OPENID_SETUP.md → docs/openid-setup.md
TRANSCRIPTION_OPTIONS.md → docs/transcription-options.md
README.md updated with the new paths + a Documentation section that
links to docs/logic/ at the top.
New application-logic doc series (~8,300 lines total) at docs/logic/.
Built with 5 parallel doc-writing agents per Daniel's "use multiple
agents" directive. Each doc explains how a part of the app actually
works — application logic, data flow, design decisions, sacred zones,
how-to-extend recipes — at a depth that lets a new dev (or an AI
assistant) modify the code confidently.
docs/logic/README.md — index + recommended reading order
docs/logic/architecture.md (2166 L) — frontend IIFE pattern, lazy tab
load, backend route convention,
schema, encryption, deployment
docs/logic/clinical-notes.md (1546L) — every note tab + helper trio
docs/logic/bedside-and-calculators.md (1373L) — bedside ES module
pocket + calculators + PE Guide
+ suture selector
docs/logic/auth-admin-learning.md (1281L) — auth (local+OIDC+2FA) +
admin panel + Learning Hub
(Quiz engine logic at sub-detail
only — TODO follow-up)
docs/logic/ai-and-voice.md (1128 L) — callAI 5-provider routing,
prompts, voice/STT, helper trio
docs/logic/ed-encounters.md (821 L) — multi-stage ED + MDM (this
session's worked example)
Admin-only docs viewer:
- New route /api/admin/docs/{tree,file}: recursively walks docs/, returns
the tree as JSON; /file?path=X validates path stays inside docs/ and
renders markdown via marked. Both gated by req.user.role==='admin'.
- New tab "Docs" (book icon) in the sidebar, hidden by default and
revealed in auth.js when user.role==='admin' (same pattern as the
existing Admin and CMS tabs).
- New component public/components/admin-docs.html: split-pane layout
with a tree sidebar + filter input + a markdown reader pane.
- New module public/js/admin-docs.js: lazy-loads the tree on first tab
activation, renders collapsible folders, persists expanded state and
last-opened path via UIState. Server-rendered HTML so no client
markdown parser needed.
- CSS for the viewer (responsive split-pane, code-block styling, table
scrolling, etc.).
- Mounted at /api/admin/docs (NOT /api) — important: mounting a router
with router.use(authMiddleware) at /api accidentally 401s every other
/api/* path (caught and fixed during testing — /api/health was 401'ing).
Files: docs/* (moved + new), README.md, public/components/admin-docs.html
(new), public/js/admin-docs.js (new), src/routes/adminDocs.js (new),
public/index.html (tab + section + script), public/js/auth.js (admin
gate + logout cleanup), public/css/styles.css (viewer styles), server.js
(mount).
═══════════════════════════════════════════════════════════════════
KNOWN GAPS (TODO follow-ups)
═══════════════════════════════════════════════════════════════════
- Learning Hub quiz engine (MCQ / multi-select / T-F scoring + attempt
tracking + progress dashboard) is covered at the architectural level
in docs/logic/auth-admin-learning.md but not drilled into the quiz
data model and scoring flow. Worth a focused follow-up doc.
- ED finalize: if MDM step JSON parse fails, server returns 502 with
the consolidated finalNote in the error payload, but client doesn't
surface the partial result. Add a "MDM failed, retry" affordance.
- No e2e Playwright coverage for ED encounters or the new docs viewer.
|
||
|---|---|---|
| .. | ||
| ai-and-voice.md | ||
| architecture.md | ||
| auth-admin-learning.md | ||
| bedside-and-calculators.md | ||
| clinical-notes.md | ||
| ed-encounters.md | ||
| README.md | ||
Application Logic — index
Deep, dev-friendly documentation of how each part of the ped-ai app actually works. Written so a human developer can understand the codebase without spelunking, and so an AI assistant can confidently modify code without breaking sacred zones.
These docs explain application logic — what the user does, what the
system does in response, what the data flow is, and why the design
looks the way it does. They are not API reference (see
../api-reference.md) and not deployment
recipes (see ../deployment.md).
Read in this order
For someone brand new to the codebase:
-
architecture.md — Start here. The big picture: IIFE frontend pattern, lazy tab loading, backend route convention, PostgreSQL schema, encryption at rest, Dockerfile + compose layout, sacred zones. (~2,000 lines, the longest doc — but the foundation.)
-
clinical-notes.md — How every clinical note tab works. The shared "record → transcribe → generate → save" lifecycle, then per-tab deep dives for Encounter HPI, Dictation HPI, Sick Visit, Well Visit, SOAP, Hospital Course, Chart Review, and Personal Notes. Includes the helper trio (refine / billing-codes / don't-miss).
-
ed-encounters.md — The ED encounter feature (multi-stage notes, per-stage don't-miss, consolidate→MDM finalize). Newest, most explicit explanation of how a clinical workflow gets composed in this codebase. Read this for a worked example.
-
bedside-and-calculators.md — Bedside emergencies module (the one ES-module pocket of the frontend), the pediatric calculators (BP percentile, Fenton growth, bilirubin nomograms, etc.), the PE Guide, vax schedule, milestones. Includes the suture selector. Important: lists every clinical formula that must NOT be modified without test vectors.
-
ai-and-voice.md — The 5-provider AI routing (
callAI), the centralizedPROMPTSobject with DB overrides, thewrapUserText+INJECTION_GUARDsafety pattern, server-side STT routing (Whisper / AWS Transcribe / Vertex / LiteLLM), browser Whisper, the AudioRecorder. Voice/STT plumbing is sacred — the doc describes it without proposing changes. -
auth-admin-learning.md — Authentication (local + OIDC SSO + 2FA), session management, OpenBao secret loading at container start, the Admin panel (model allowlist, prompt overrides, milestone editor), and the Learning Hub (AI-authored quizzes / outlines / Marp presentations).
What's NOT here
- Reference data details. Every clinical formula's math lives in the source files; this doc series points to the formula and explains what it does but doesn't reproduce the lookup tables.
- API endpoint signatures. See
../api-reference.md. - Operational runbooks. See
../deployment.md,../configuration.md. - Recent change history. See git log + the rollback tags
(
pre-ts-migration-2026-04-26,pre-ed-encounters-2026-04-26, etc.).
Voice + conventions
Each doc follows the same structure:
- Overview — what this part is and why it exists
- User flow — what the physician does and sees
- Data flow — what HTTP calls happen, what the server does
- File map — which files do what
- Key design decisions — why it works the way it does
- Sacred zones — what NOT to refactor without explicit approval
- How to extend — concrete recipes for adding a new X
When a doc mentions a sacred zone, it means there's a project-memory rule that this code must not be refactored without per-change approval from Daniel. The full sacred-zone roster:
| Zone | Why |
|---|---|
public/js/encounters.js save/load/idempotency |
Save/version/idempotency logic has been carefully tuned; refactors keep silently breaking it. |
Voice/STT plumbing (audioBackup.js, speechRecognition.js, browserWhisper.js, voicePreferences.js, transcriptionSettings.js, recorder paths in each clinical tab) |
Recording UX has been hardened against many edge cases; refactor only with smallest-diff bug fixes. |
| Validated clinical formulas (BP percentile LMS, Fenton 2013, bilirubin AAP 2022, Bhutani, APLS / Best-Guess weight, PE Guide SCALES) | Validated against peditools / AAP tables; modifying without test vectors risks miscoding patient care. |
Auth + crypto (crypto.js, passwords.js, sessions.js, auth.js, oidc.js) |
Security; changes without security review are unsafe. |
MDM rubric in PROMPTS.edFinalize |
Load-bearing for billing accuracy; trim only with explicit AMA/coding source citation. |
Total size
~8,300 lines of new application-logic documentation across 6 files. If that feels like a lot, remember: the codebase is ~33,000 lines of frontend JS + ~14,000 lines of backend JS. The docs are dense by design — "200% detailed" was the explicit ask. Search them like a reference; don't try to read end to end.
Cross-cutting topics
A few topics span multiple docs. Use these as your jump-off points:
| Topic | Where to look |
|---|---|
The IIFE pattern + window.x = y cross-file globals |
architecture.md §2-3 |
Lazy tab loading (loadComponent, tabChanged event) |
architecture.md §3-4 |
getUserMemoryContext → templates feeding into AI prompts |
clinical-notes.md §6, ed-encounters.md §9 |
The helper trio: refineDocument, suggestBillingCodes, suggestDontMiss |
ai-and-voice.md §12, clinical-notes.md §5 |
wrapUserText + INJECTION_GUARD prompt-injection defense |
ai-and-voice.md §5 |
saveEncounter API + optimistic locking + idempotency keys |
architecture.md §13, clinical-notes.md §4, ed-encounters.md §5 |
cryptoUtil.encryptString / encryptBuffer "enc1:" format |
architecture.md §12 |
5-provider AI routing (callAI) |
ai-and-voice.md §2-3 |
| 2023 AMA E/M MDM rubric | ed-encounters.md §6 |
User templates (user_memories table, template_* categories) |
clinical-notes.md §6, ed-encounters.md §9 |
How to keep these docs current
Each doc has a date implicit in the most recent feature it describes. When you add a feature, update the relevant doc in the same commit. When you remove a feature (e.g., the Dragon-style AI corrections removal in late April 2026), remove its section + leave a one-line historical note in the relevant doc.
When you write a new doc, follow the same structure as these (Overview / User flow / Data flow / File map / Design decisions / Sacred zones / How to extend) and add it to this index.