[object Object]

← back to AbramsOS

health: lapsed-habit BP reading reminders (only nudges prior loggers, never new users)

85982870ba68133e452b37fba050b4591a222c1b · 2026-07-13 01:13:32 -0700 · Steve

- lib/vitals-reminders.js: fires 'time for a BP check' only if a person logged BP before but not in 14d; deduped via reminder engine
- reminder-engine.generateForUser hooks it in alongside returns/warranty/recall reminders
- verified: lapsed(20d)=fire, recent(2d)=skip, never-logged=skip

Files touched

Diff

commit 85982870ba68133e452b37fba050b4591a222c1b
Author: Steve <steve@designerwallcoverings.com>
Date:   Mon Jul 13 01:13:32 2026 -0700

    health: lapsed-habit BP reading reminders (only nudges prior loggers, never new users)
    
    - lib/vitals-reminders.js: fires 'time for a BP check' only if a person logged BP before but not in 14d; deduped via reminder engine
    - reminder-engine.generateForUser hooks it in alongside returns/warranty/recall reminders
    - verified: lapsed(20d)=fire, recent(2d)=skip, never-logged=skip
---
 lib/reminder-engine.js  |  3 +++
 lib/vitals-reminders.js | 44 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 47 insertions(+)

diff --git a/lib/reminder-engine.js b/lib/reminder-engine.js
index d9ef012..0021f65 100644
--- a/lib/reminder-engine.js
+++ b/lib/reminder-engine.js
@@ -140,6 +140,9 @@ async function generateForUser(userId) {
     }
   }
 
+  // Health: gentle "time for a BP check" nudge for lapsed loggers (never nags new users).
+  inserted += await require('./vitals-reminders').generateReadingReminders(userId, tryInsert);
+
   return inserted;
 }
 
diff --git a/lib/vitals-reminders.js b/lib/vitals-reminders.js
new file mode 100644
index 0000000..a176a64
--- /dev/null
+++ b/lib/vitals-reminders.js
@@ -0,0 +1,44 @@
+// vitals-reminders.js — gentle "time for a BP check" reminders.
+//
+// Design rule (don't nag about an unadopted feature): a reminder fires ONLY for a person
+// who has logged blood pressure BEFORE but not in the last N days (a lapsed habit). If they
+// have never logged a reading, no reminder. Deduped by the reminder engine, so it can't spam.
+const db = require('./db');
+
+const REMIND_AFTER_DAYS = 14;
+
+async function generateReadingReminders(userId, tryInsert) {
+  let inserted = 0;
+  const rows = (await db.query(
+    `SELECT person_id, max(measured_at) AS last, count(*)::int AS n
+       FROM health_reading WHERE user_id = $1 AND metric = 'blood_pressure'
+       GROUP BY person_id`,
+    [userId]
+  )).rows;
+
+  for (const r of rows) {
+    if (!r.n) continue;                       // never logged → don't nudge
+    const days = (Date.now() - new Date(r.last).getTime()) / 86400e3;
+    if (days < REMIND_AFTER_DAYS) continue;   // logged recently → fine
+
+    let personName = null;
+    if (r.person_id) {
+      const p = await db.query(`SELECT full_name FROM person WHERE id = $1`, [r.person_id]);
+      personName = p.rows[0] && p.rows[0].full_name;
+    }
+    const rr = await tryInsert({
+      userId,
+      ownerTable: 'health_reading',
+      ownerId: `bp-${r.person_id || 'self'}`,
+      dueAt: new Date(),
+      reasonCode: 'bp_reading_due',
+      title: personName ? `Time for ${personName}'s blood-pressure check` : 'Time for a blood-pressure check',
+      body: `It's been ${Math.floor(days)} days since the last reading. A quick check keeps the trend meaningful.`,
+      metadata: { medical: true, person_id: r.person_id || null },
+    });
+    if (rr) inserted += 1;
+  }
+  return inserted;
+}
+
+module.exports = { generateReadingReminders, REMIND_AFTER_DAYS };

← 355389e health: BP-medication context — show active meds that raise/  ·  back to AbramsOS  ·  assets: net-worth tracker — enter home by address + current a78d4ae →