mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-07 04:12:04 +00:00
Add the per-user health-score composition column
A nullable JSONB column on users carrying which pillars the person chose to count toward the composite score. Stored as a deselection list so a pillar shipped later counts by default and cannot be confused with one the person removed. NULL keeps its own meaning: never chose, which is not the same as counting nothing.
This commit is contained in:
1 parent
63b54587a8
commit
c574ef78fb
2 files changed
+59
No files matched your search
@@ -0,0 +1,35 @@
|
||||
-- v1.35.0 — per-user Health Score composition.
|
||||
--
|
||||
-- A single nullable JSONB column on `users` carrying which pillars the
|
||||
-- person chose to count toward the composite Health Score. Follows the
|
||||
-- established per-user JSON-column convention (`module_preferences_json`,
|
||||
-- `dashboard_widgets_json`, `coach_prefs_json`).
|
||||
--
|
||||
-- Shape (validated by `src/lib/analytics/score/config.ts`):
|
||||
-- { "excludedPillars": ["SLEEP", "LIPIDS"],
|
||||
-- "version": 3,
|
||||
-- "changedAt": "2026-07-31T09:12:44.000Z" }
|
||||
--
|
||||
-- The stored list is a DESELECTION list, the same posture as
|
||||
-- `module_preferences_json`, and it is stored that way on purpose. A
|
||||
-- pillar shipped after the person made their choice is simply absent
|
||||
-- from the list, so it counts by default and the score keeps its
|
||||
-- "everything eligible" starting point without a backfill. Storing the
|
||||
-- positive selection instead would make a newly shipped pillar
|
||||
-- indistinguishable from one the person deliberately removed.
|
||||
--
|
||||
-- NULL = the person never chose, which is NOT the same as choosing to
|
||||
-- count nothing (an `excludedPillars` list naming every pillar). The
|
||||
-- resolver keeps those two apart because only the first one may inherit
|
||||
-- a later change of defaults.
|
||||
--
|
||||
-- `version` is the per-user recipe version: it increments on every
|
||||
-- accepted write and, with `changedAt`, is what a score record and the
|
||||
-- weekly delta key off to tell "you changed what counts" apart from a
|
||||
-- real movement in the person's health.
|
||||
--
|
||||
-- Additive + nullable: every existing account keeps NULL and the
|
||||
-- resolver treats NULL as "counts every pillar", which is exactly what
|
||||
-- those accounts get today.
|
||||
|
||||
ALTER TABLE "users" ADD COLUMN "health_score_config_json" JSONB;
|
||||
@@ -602,6 +602,30 @@ model User {
|
||||
// `GET /api/auth/me` as a `modules: { <key>: boolean }` map.
|
||||
modulePreferencesJson Json? @map("module_preferences_json")
|
||||
|
||||
// v1.35.0 — which pillars count toward the composite Health Score.
|
||||
//
|
||||
// A DESELECTION list, the same posture as `modulePreferencesJson`:
|
||||
// { "excludedPillars": ["SLEEP"], "version": 2, "changedAt": "<ISO>" }
|
||||
//
|
||||
// A pillar shipped after the person made their choice is absent from
|
||||
// the list and therefore counts, so the score keeps its "everything
|
||||
// eligible" starting point with no backfill. Storing the positive
|
||||
// selection instead would make a newly shipped pillar look exactly
|
||||
// like one the person deliberately removed.
|
||||
//
|
||||
// NULL means the person never chose and is deliberately distinct from
|
||||
// a list naming every pillar ("count nothing"): only the first may
|
||||
// inherit a later change of defaults.
|
||||
//
|
||||
// `version` increments on every accepted write and, with `changedAt`,
|
||||
// is the per-user recipe identity a score record and the weekly delta
|
||||
// read to tell an authored change apart from a health movement.
|
||||
//
|
||||
// Schema + resolver: `src/lib/analytics/score/config.ts`. Written by
|
||||
// `PATCH /api/auth/me/health-score-config` with field-by-field merge
|
||||
// (no mass assignment) under the write-time breadth rule.
|
||||
healthScoreConfigJson Json? @map("health_score_config_json")
|
||||
|
||||
// Document vault — per-user storage-quota override in bytes. NULL = the
|
||||
// instance default (`AppSettings.documentQuotaBytes`) applies. Admin-set
|
||||
// only (the admin user PUT); resolved by
|
||||
|
||||
Reference in new issue
Block a user