mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-11 13:52:20 +00:00
* Revert "revert: roll source tree back to v1.4.0 to restore production"
This reverts commit e444a90b10.
* fix(v1.4.2): summaries.WEIGHT + medications array guards + healthcheck IPv4
Three production bugs surfaced after the v1.4.0 deploy stabilized:
1. `TypeError: undefined is not an object (evaluating 'E?.summaries.WEIGHT')`
on /dashboard and /insights for users without weight readings —
the optional chain stopped at `data` when it needed to also cover
`data.summaries`. Fixed: `data?.summaries?.WEIGHT` (one level deeper).
2. `TypeError: y?.filter is not a function` on /medications — the
medications query value was non-array (likely a stale
service-worker response from an older API shape). Replaced with
`Array.isArray(medications) ? medications : []` so the page is
immune to any future shape drift.
3. Healthcheck-induced 503 outage (already in 1.4.1 — included here
so 1.4.2 is the single coherent release). The docker-compose
healthcheck used `localhost` which busybox-wget resolves to IPv6
::1; Next.js standalone listens on IPv4 0.0.0.0 only. Pinned
to 127.0.0.1.
This release also includes everything from v1.4.1 (which never
published a clean GHCR tag): the per-section admin extraction, the
testcontainers integration suite, the Playwright + axe-core E2E
foundation, the moodLog SSRF fix, the central error-redaction in
WideEventBuilder + Glitchtip, the medical-citation drift fixes
(ESH 2023, Saint-Maurice attribution, steps source), and the docs
sync.
Co-Authored-By: Marc-André Bombeck <mbombeck@gmail.com>
211 lines
7.7 KiB
TypeScript
211 lines
7.7 KiB
TypeScript
/**
|
|
* Single source of truth for medical guideline citations.
|
|
*
|
|
* Every threshold, every range, every "ESC/ESH says…" statement in the
|
|
* code or AI prompts MUST reference one of the entries below — either
|
|
* by importing the constant directly or by quoting the same `name` and
|
|
* `url` in a comment above the value.
|
|
*
|
|
* Adding a new citation:
|
|
* 1. Verify the source against THREE independent reputable references
|
|
* (guideline document + WHO/fachgesellschaft + peer-reviewed paper
|
|
* or government publication is the gold standard).
|
|
* 2. Capture the publication URL so the truthfulness drift-test can
|
|
* re-resolve it.
|
|
* 3. Document any caveat ("BIA-derived, not DEXA-equivalent",
|
|
* "pediatric only", "treated cohort only") inline so consumers
|
|
* can decide whether the citation applies to their use case.
|
|
*
|
|
* Drift-test (`src/lib/__tests__/medical-citations.test.ts`) asserts
|
|
* that every CITATIONS entry has a non-empty url + caveat field.
|
|
*/
|
|
|
|
export interface Citation {
|
|
/** Stable id used to reference this citation in code. */
|
|
readonly id: string;
|
|
/** Human-readable name shown in UI ("source" attribution). */
|
|
readonly name: string;
|
|
/** Year of publication. */
|
|
readonly year: number;
|
|
/** Stable URL to the source document. */
|
|
readonly url: string;
|
|
/** One-sentence caveat about scope or limitation. */
|
|
readonly caveat: string;
|
|
}
|
|
|
|
export const CITATIONS = {
|
|
/**
|
|
* 2023 ESH Guidelines for the management of arterial hypertension.
|
|
* The last joint ESC/ESH guideline was 2018; ESH published 2023
|
|
* standalone (ESC withdrew from the joint authoring). Targets that
|
|
* HealthLog uses (SBP 120-129 / DBP 70-79 for <65; SBP 130-139 / DBP
|
|
* 70-79 for ≥65) are unchanged from 2018 to 2023.
|
|
*/
|
|
ESH_2023_HYPERTENSION: {
|
|
id: "esh-2023-hypertension",
|
|
name: "ESH 2023",
|
|
year: 2023,
|
|
url: "https://journals.lww.com/jhypertension/fulltext/2023/12000/2023_esh_guidelines_for_the_management_of_arterial.2.aspx",
|
|
caveat: "Pure-hypertension guideline; not a joint ESC document since 2023.",
|
|
},
|
|
|
|
/**
|
|
* Saint-Maurice PF, et al. "Association of daily step count and step
|
|
* intensity with mortality among US adults." JAMA. 2020.
|
|
* The paper reports continued dose-response benefit (HR 0.49 at 8k
|
|
* vs 4k, HR 0.35 at 12k vs 4k) — NOT a plateau. The plateau-shaped
|
|
* finding belongs to Paluch 2022 Lancet Public Health (PMID
|
|
* 35247352, age-stratified meta-analysis). WHO 2020 PA guidelines
|
|
* publish minutes per week, NOT a step quota — DO NOT cite WHO
|
|
* for a step number.
|
|
*/
|
|
STEPS_SAINT_MAURICE_2020: {
|
|
id: "steps-saint-maurice-2020",
|
|
name: "Saint-Maurice JAMA 2020",
|
|
year: 2020,
|
|
url: "https://jamanetwork.com/journals/jama/fullarticle/2763292",
|
|
caveat:
|
|
"U.S. adult cohort, observational; benefit accumulates strongly through ~12k steps/day (continued dose-response, not a plateau).",
|
|
},
|
|
|
|
/**
|
|
* WHO 2020 Guidelines on Physical Activity and Sedentary Behaviour.
|
|
* Adults: 150-300 min/wk moderate OR 75-150 min/wk vigorous activity.
|
|
* Cite this document for activity time, NOT for steps.
|
|
*/
|
|
WHO_2020_PA: {
|
|
id: "who-2020-physical-activity",
|
|
name: "WHO 2020 Physical Activity",
|
|
year: 2020,
|
|
url: "https://www.who.int/publications/i/item/9789240015128",
|
|
caveat: "Publishes minutes/week, not a step quota.",
|
|
},
|
|
|
|
/**
|
|
* BTS Emergency Oxygen Guideline 2017 — explicit treatment target
|
|
* 94-98% saturation (88-92% for chronic hypercapnia risk). Used as
|
|
* comparison anchor for HealthLog's consumer band.
|
|
*/
|
|
BTS_2017_OXYGEN: {
|
|
id: "bts-2017-emergency-oxygen",
|
|
name: "BTS 2017 Emergency Oxygen",
|
|
year: 2017,
|
|
url: "https://thorax.bmj.com/content/72/Suppl_1/ii1",
|
|
caveat: "Hospital emergency context, not consumer monitoring.",
|
|
},
|
|
|
|
/**
|
|
* NICE NG115 — Chronic obstructive pulmonary disease in over 16s:
|
|
* diagnosis and management. Recommends ≤92% SpO2 as escalation
|
|
* threshold ("call provider").
|
|
*/
|
|
NICE_NG115_COPD: {
|
|
id: "nice-ng115-copd",
|
|
name: "NICE NG115",
|
|
year: 2018,
|
|
url: "https://www.nice.org.uk/guidance/ng115",
|
|
caveat: "COPD-focused; useful as the 'call provider' floor.",
|
|
},
|
|
|
|
/**
|
|
* ADA Standards of Medical Care in Diabetes — 2024 (§6 Glycemic
|
|
* Targets). Pre-prandial 80-130 mg/dL, post-prandial <180 mg/dL.
|
|
* No published adult bedtime target — ISPAD 2022 publishes 80-140
|
|
* for pediatric T1D.
|
|
*/
|
|
ADA_2024_GLYCEMIC: {
|
|
id: "ada-2024-glycemic",
|
|
name: "ADA 2024 Standards of Care",
|
|
year: 2024,
|
|
url: "https://diabetesjournals.org/care/article/47/Supplement_1/S111/153957",
|
|
caveat:
|
|
"Pre-prandial 80-130, post-prandial <180; no published adult bedtime target.",
|
|
},
|
|
|
|
/**
|
|
* ISPAD Clinical Practice Consensus Guidelines 2022 — pediatric
|
|
* T1D bedtime target 80-140 mg/dL. NOT validated for adults.
|
|
*/
|
|
ISPAD_2022_PEDIATRIC: {
|
|
id: "ispad-2022-pediatric",
|
|
name: "ISPAD 2022",
|
|
year: 2022,
|
|
url: "https://onlinelibrary.wiley.com/doi/10.1111/pedi.13455",
|
|
caveat: "Pediatric T1D context; not validated for adult use.",
|
|
},
|
|
|
|
/**
|
|
* ACE (American Council on Exercise) body-fat percentage standards.
|
|
* Essential fat: M 2-5% / F 10-13%. Athletes: M 6-13% / F 14-20%.
|
|
* Fitness: M 14-17% / F 21-24%. Acceptable: M 18-24% / F 25-31%.
|
|
* Obese: M 25%+ / F 32%+. Source widely cited; ACE bases the bands
|
|
* on Heyward & Wagner "Applied Body Composition Assessment".
|
|
*/
|
|
ACE_BODY_FAT: {
|
|
id: "ace-body-fat-standards",
|
|
name: "ACE Body-Fat Standards",
|
|
year: 2009,
|
|
url: "https://www.acefitness.org/resources/everyone/blog/112/what-are-the-guidelines-for-percentage-of-body-fat-loss/",
|
|
caveat:
|
|
"Reference categories; clinical decisions should use DEXA or hydrostatic.",
|
|
},
|
|
|
|
/**
|
|
* AASM 2015 — adults need 7+ hours of sleep on a regular basis.
|
|
* 9+ hours acceptable for young adults, less for older adults.
|
|
*/
|
|
AASM_2015_SLEEP: {
|
|
id: "aasm-2015-adult-sleep",
|
|
name: "AASM 2015 Adult Sleep Duration",
|
|
year: 2015,
|
|
url: "https://aasm.org/resources/pdf/pressroom/adult-sleep-duration-consensus.pdf",
|
|
caveat: "Target ≥7h adults; older adults may need slightly less.",
|
|
},
|
|
|
|
/**
|
|
* Watson PE, et al. "Total body water volumes for adult males and
|
|
* females estimated from simple anthropometric measurements." Am J
|
|
* Clin Nutr. 1980. Establishes the canonical TBW (L) equations
|
|
* referenced by Withings hydration estimates.
|
|
*/
|
|
WATSON_1980_TBW: {
|
|
id: "watson-1980-tbw",
|
|
name: "Watson 1980 TBW formula",
|
|
year: 1980,
|
|
url: "https://pubmed.ncbi.nlm.nih.gov/6986753/",
|
|
caveat:
|
|
"Original anthropometric TBW equations; predictive, not measurement.",
|
|
},
|
|
|
|
/**
|
|
* ICRP Publication 89 (2002) — Reference values for adult human TBW
|
|
* (~42 L male, ~29 L female). Used as bounds for plausibility checks.
|
|
*/
|
|
ICRP_89_REFERENCE_MAN: {
|
|
id: "icrp-89-reference-man",
|
|
name: "ICRP 89 Reference Man",
|
|
year: 2002,
|
|
url: "https://www.icrp.org/publication.asp?id=ICRP%20Publication%2089",
|
|
caveat:
|
|
"Reference values for an idealised adult; individual variation broad.",
|
|
},
|
|
} as const satisfies Record<string, Citation>;
|
|
|
|
export type CitationId = keyof typeof CITATIONS;
|
|
|
|
/** Returns the URL for the given citation id. */
|
|
export function citationUrl(id: CitationId): string {
|
|
return CITATIONS[id].url;
|
|
}
|
|
|
|
/**
|
|
* Returns a localized "source: NAME (YEAR)" string for UI use.
|
|
* Locale-agnostic for now (English-first); German UI consumers can
|
|
* format the year via `Intl.NumberFormat` if needed but the citation
|
|
* name itself is canonical and not translated.
|
|
*/
|
|
export function citationLabel(id: CitationId): string {
|
|
const c = CITATIONS[id];
|
|
return `${c.name} (${c.year})`;
|
|
}
|