mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-14 14:40:52 +00:00
feat(mental-health): make the screener score rows server-owned COMPUTED measurements
Each completed PHQ-9 / GAD-7 administration already projects its total onto a PHQ9_SCORE / GAD7_SCORE measurement row (unit score, linked via externalId assessment:<id>). Those rows were attributed MANUAL — a client-writable source. The projection is a server-derived value, so it now writes source COMPUTED, the same server-owned source RECOVERY_SCORE uses: no client write surface can attribute COMPUTED, so a forged score trend point cannot enter through the measurement POST. Migration 0225 re-attributes the existing assessment-linked projection rows; a score a user typed into the generic measurement form keeps MANUAL. OpenAPI description updated and the spec regenerated.
This commit is contained in:
1 parent
f7920d81a6
commit
b6aedfeb61
7 files changed
+64
-10
No files matched your search
@@ -108,7 +108,7 @@ export const mentalHealthPaths: NonNullable<ZodOpenApiObject["paths"]> = {
|
||||
tags: ["Mental health"],
|
||||
summary: "Record a completed PHQ-9 / GAD-7 screener",
|
||||
description:
|
||||
"Stores one administration (item answers encrypted) and writes the derived total as a PHQ9_SCORE / GAD7_SCORE measurement. On a positive PHQ-9 item-9 the response carries the locale-aware crisis-resource set.",
|
||||
"Stores one administration (item answers encrypted) and writes the derived total as a server-owned PHQ9_SCORE / GAD7_SCORE measurement (source COMPUTED — never client-writable). On a positive PHQ-9 item-9 the response carries the locale-aware crisis-resource set.",
|
||||
requestBody: {
|
||||
content: {
|
||||
"application/json": { schema: createAssessmentSchema },
|
||||
|
||||
@@ -470,6 +470,24 @@ describe("measurement validation", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("rejects a COMPUTED-attributed screener score row on a client write", () => {
|
||||
// v1.27.6 — the mental-wellbeing screener projects each completed
|
||||
// administration onto a COMPUTED-source PHQ9_SCORE / GAD7_SCORE row
|
||||
// (the RECOVERY_SCORE precedent). COMPUTED is not client-attributable,
|
||||
// so a client can never mint a server-owned score trend point.
|
||||
for (const type of ["PHQ9_SCORE", "GAD7_SCORE"]) {
|
||||
const parsed = createMeasurementSchema.safeParse({
|
||||
type,
|
||||
value: 5,
|
||||
measuredAt: "2026-06-02T12:00:00Z",
|
||||
source: "COMPUTED",
|
||||
});
|
||||
expect(parsed.success, `expected COMPUTED ${type} to be rejected`).toBe(
|
||||
false,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it("accepts the client-writable sources MANUAL and APPLE_HEALTH", () => {
|
||||
for (const source of ["MANUAL", "APPLE_HEALTH"]) {
|
||||
const parsed = createMeasurementSchema.safeParse({
|
||||
|
||||
Reference in new issue
Block a user