mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-11 13:52:20 +00:00
77 lines
3.6 KiB
Markdown
77 lines
3.6 KiB
Markdown
# Doctor Report
|
|
|
|
The doctor report is a printable PDF summary of a user's tracked vitals,
|
|
medication compliance, glucose context, and mood over a configurable window
|
|
(default 90 days, max 365). It is intended as discussion material for a
|
|
doctor's appointment, **not** a medical diagnosis.
|
|
|
|
## Two endpoints
|
|
|
|
The same aggregation logic backs both endpoints — `collectDoctorReportData`
|
|
in `src/lib/doctor-report-data.ts` is the single source of truth — so the
|
|
JSON payload and the server-rendered PDF are guaranteed to be in sync.
|
|
|
|
### `POST /api/doctor-report` — JSON payload
|
|
|
|
Returns the aggregated `DoctorReportData` envelope. Used by the PWA's
|
|
client-side renderer (`src/lib/doctor-report-pdf.ts`, jsPDF + autotable).
|
|
Best on desktop browsers and on Android, where local generation keeps the
|
|
PDF off the wire and works offline (cached page).
|
|
|
|
- Auth: session required.
|
|
- Rate-limit: 10/h per user.
|
|
- Body: `{ days?: number }` (default 90).
|
|
- Response: `200 application/json` with envelope `{ data, error: null }`.
|
|
- Audit action: `doctor-report.generate`.
|
|
|
|
### `POST /api/doctor-report/pdf` — server-rendered PDF
|
|
|
|
Returns the ready-to-download PDF bytes. Used primarily on iOS/Safari, where
|
|
the client-side jsPDF download UX is unreliable (Safari sometimes opens the
|
|
PDF in a new tab without preserving the filename or fails the blob save).
|
|
|
|
- Auth: session required (`401` otherwise).
|
|
- Rate-limit: 10/h per user, shared with the JSON endpoint (`429` on excess).
|
|
- Body: `{ days?: number; locale?: "de" | "en" }`. Body is optional — empty
|
|
bodies are accepted.
|
|
- Locale resolution: explicit `body.locale` wins, then the
|
|
`Accept-Language` header (`de*` → `de`, anything else → `en`), then the
|
|
hard fallback `de`.
|
|
- Response: `200 application/pdf` with
|
|
`Content-Disposition: attachment; filename="healthlog-report-YYYY-MM-DD.pdf"`
|
|
and `Cache-Control: no-store`. Body is the raw PDF bytes.
|
|
- Errors: JSON envelope `{ data: null, error: "..." }` for `401` and `429`;
|
|
`500` if rendering fails.
|
|
- Audit action: `doctor-report.pdf.generate`.
|
|
|
|
## Wellness summary (derived scores)
|
|
|
|
Since v1.10.0 the report carries a **Wellness summary** section below the
|
|
clinical content, holding the server-derived wellness scores (Recovery,
|
|
Stress, Strain) and the other derived metrics where present. It is kept
|
|
deliberately separate from the clinical vitals table:
|
|
|
|
- Each entry is labelled **descriptive, not a clinical assessment**, and the
|
|
scores never enter the vitals table or the clinical aggregations.
|
|
- The Stress score is shown as an HRV-derived proxy, not a sensor-measured
|
|
stress value.
|
|
- In the FHIR export the same scores are emitted as `survey`-category
|
|
`Observation`s (text-only `code`, no fabricated LOINC) with a per-Observation
|
|
non-clinical note — so a downstream system never mistakes them for a vital
|
|
sign or a diagnosis.
|
|
|
|
Each derived metric states its inputs, method, and the cited standard it is
|
|
grounded in (the same provenance the in-app explainer shows).
|
|
|
|
## Implementation notes
|
|
|
|
- `src/lib/doctor-report-pdf-core.ts` contains the isomorphic renderer.
|
|
jsPDF runs unchanged in Node — `doc.output("arraybuffer")` returns a valid
|
|
`%PDF-` byte stream in both environments, so we deliberately avoid headless
|
|
Chromium (Puppeteer/Playwright) to keep the runtime dependency surface low.
|
|
- `src/lib/doctor-report-pdf.ts` is a thin client façade that returns the
|
|
raw `jsPDF` instance so the existing settings-page download flow (which
|
|
calls `doc.save(...)`) keeps working unchanged.
|
|
- Server-side translations come from `messages/{de,en}.json` via
|
|
`getServerTranslator()` (`src/lib/i18n/server-translator.ts`).
|