pediatric-ai-scribe-v3/src/routes/sickVisit.js
Daniel 020e831b3c v6.2: Session management, password change, audit logging, refine context, UI fixes
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
2026-04-08 20:27:45 +02:00

74 lines
2.6 KiB
JavaScript

// ============================================================
// SICK VISIT ROUTE — sick visit note generation
// ============================================================
var express = require('express');
var router = express.Router();
var { callAI } = require('../utils/ai');
var PROMPTS = require('../utils/prompts');
var { authMiddleware } = require('../middleware/auth');
var logger = require('../utils/logger');
// ── POST generate sick visit note ────────────────────────────────────────
router.post('/sick-visit/note', authMiddleware, async function(req, res) {
var start = Date.now();
try {
var {
patientAge, patientGender, chiefComplaint,
transcript, dictation,
ros, physicalExam, diagnoses,
physicianMemories,
model
} = req.body;
if (!chiefComplaint) {
return res.status(400).json({ error: 'Chief complaint is required' });
}
// Assemble context
var context = 'SICK VISIT\n';
context += 'Patient: ' + (patientAge || 'Unknown age') + ', ' + (patientGender || 'Unknown gender') + '\n';
context += 'Chief Complaint: ' + chiefComplaint + '\n\n';
if (transcript) {
context += 'ENCOUNTER TRANSCRIPT/DICTATION:\n' + transcript + '\n\n';
} else if (dictation) {
context += 'PHYSICIAN DICTATION:\n' + dictation + '\n\n';
}
if (ros) {
context += ros + '\n\n';
}
if (physicalExam) {
context += physicalExam + '\n\n';
}
if (diagnoses) {
context += diagnoses + '\n\n';
}
if (physicianMemories) {
context += '[STYLE HINTS (low priority — only apply if relevant to the current note, never copy content from these examples)]\n' + physicianMemories + '\n[END STYLE HINTS]\n\n';
}
var result = await callAI([
{ role: 'system', content: PROMPTS.sickVisitNote },
{ role: 'user', content: context }
], { model });
var dur = Date.now() - start;
logger.apiCall(req.user.id, '/api/sick-visit/note', {
model: result.model, tokensInput: result.usage?.input_tokens,
tokensOutput: result.usage?.output_tokens, duration: dur, statusCode: 200
});
res.json({ success: true, note: result.content, model: result.model });
logger.audit(req.user.id, 'generate_sick_visit', 'Generated sick visit note', req, { category: 'clinical' });
} catch (e) {
logger.error('[SickVisit] Note generation failed', e.message);
res.status(500).json({ error: e.message });
}
});
module.exports = router;