- Add deduplication logic to prevent Chrome Speech API from repeating
sentences during long recording sessions (all 4 recording modules)
- Enable AWS Transcribe Medical with PRIMARYCARE specialty in .env
- Bump version to 8.0.0
pdf-parse (was v2, broken API):
- Downgraded to v1.1.1 — default export is a function again
- pdfParse is not a function error fixed
WebDAV file selection (style.display bug, same cascade issue):
- lh-ai-webdav-selected had inline style="display:flex" always visible
- selectWebdavFile() / deselectWebdavFile() now use element.style.display
- On select: browser div hides, selected indicator shows with file name + X
- On deselect (X): indicator hides, browser shows again
Topic context for Upload and Nextcloud tabs:
- Both tabs now have optional "Topic / context" field
- Sent to backend as 'topic' param to help AI focus the generated content
Inline refine bar (replaces window.prompt):
- Refine Body button shows/hides an amber inline input bar below generate buttons
- Enter instructions, press Apply — no browser dialog, works in all contexts
CSP: remove unsafe-inline from scriptSrc (security issue #2):
- Converted all 26 onclick= handlers in component HTML files to
data-action / data-target / data-label attributes
- Added delegated click handler in app.js for copy/speak/nc-export actions
- script-src now 'self' only; script-src-attr 'none'
WebDAV path endpoint (security issue #5):
- New POST /api/user/webdav-path (authMiddleware only, not moderator)
- nextcloud.js updated to use new endpoint
nodemailer: already at 6.10.1 (vulnerability fixed).
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.
AI Generate panel:
- Content type synced from editor on open
- Article/Pearl: optional word count field
- Presentation: optional slide count field
- Questions row: checkbox toggle for article/pearl (optional), always on for quiz,
hidden for presentation; count input shown only when enabled
- Backend: passes wordCount/slideCount to prompt; questionCount=0 skips questions
Delete confirmation:
- Wording built dynamically from content type
- Presentation: no mention of questions
- Quiz: "All quiz questions will be permanently removed"
- Article/pearl: "Any quiz questions attached will also be removed"
Auth refactor — JWT → httpOnly cookie:
- Backend: setAuthCookie() sets ped_auth as httpOnly, Secure, SameSite=Lax, 7d
- Backend: clearAuthCookie() on POST /api/auth/logout (new endpoint)
- Backend: auth middleware reads ped_auth cookie first, falls back to Bearer header
- Login/register: no longer return token in JSON body; cookie is the session
- Frontend: getAuthHeaders() returns only Content-Type (no Authorization header)
- Frontend: session check uses /api/auth/me via cookie (no localStorage token)
- Frontend: clearSession() calls /api/auth/logout to clear cookie server-side
- Frontend: no token in localStorage; window.AUTH_TOKEN removed
- All FormData fetches use credentials:'same-origin' (cookie sent automatically)
- index.html: optimistic auth-screen hide (removed localStorage token check)
Tested: login, logout, /api/auth/me, admin routes, FormData uploads, cookie httpOnly
flag, 401 without cookie, cookie cleared on logout.
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.
- 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
- 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
- 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
- speakText: revert async ElevenLabs fetch chain — browser requires
speechSynthesis.speak() to be called synchronously within user gesture;
async .catch() context caused silent failure across browsers
- copyText: fix fallback that always showed 'Copied!' even when it failed;
now shows real error message, uses selectNodeContents for accuracy,
handles missing clipboard API gracefully
- Switch speakText() to call /api/text-to-speech backend (ElevenLabs) with fallback to native speechSynthesis
- Upgrade ElevenLabs voice from Rachel to Adam (pNInz6obpgDQGcFmaJgB) — warmer, more professional
- Upgrade model from eleven_monolingual_v1 to eleven_turbo_v2_5 for better quality and lower latency