Skip to content

12 Daily Health and Care Calendar

Anubha Parashar edited this page Oct 10, 2026 · 1 revision

Daily Health is HealthBook AI's optional caregiver journal (internal code name: BabyCare). It records fluids, diapers, stool, medicines actually given, symptoms, activity and sleep as typed, profile-scoped rows. The same rows feed the day summary, the unified timeline, the Care Calendar (month, week and day views), observational analytics, before/during/after illness comparison and a doctor-ready care export. Everything is computed from what the caregiver recorded. Nothing is inferred clinically.

Responsibilities

  • Store seven entry kinds with validation, provenance (source, recorded_by) and an encrypted free-text note.
  • Place every entry on the profile's local calendar date, computed in the profile's timezone at write time.
  • Keep corrections auditable: edits snapshot the previous values, and rows are withdrawn, never deleted.
  • Make duplicate or offline re-submissions idempotent through client_key.
  • Produce day summaries, timelines, calendar markers, analytics and exports that use counting and co-occurrence language only.

Entry kinds

Kind (/care/{kind}) Model Key fields Notable validation
fluid FluidEntry amount_ml, amount_unknown, custom_amount, fluid_type, duration_minutes oz is converted to ml; you must give an amount, a description or "unknown" (breastmilk may omit it); 0–3000 ml
diaper DiaperEntry kind wet/stool/mixed/dry, urine_amount, stool_entry_id a linked stool entry must belong to the same profile
stool StoolEntry colour, consistency, amount, mucus/blood observed, watery, parent_concern, AI review fields clinical_review_suggested is set for black, red, pale or white colour, or when blood is observed
medicine MedicationAdministration medicine_id or name, dose, route, scheduled_for, administration_status status is one of given, skipped, missed, later, unknown
symptom SymptomEntry kind, severity, temperature + unit, ended_at, episode links a temperature needs a unit
activity ActivityEntry kind, ended_at, duration_minutes, camera_observation_id duration is derived from the end time when it is missing
sleep SleepEntry night/nap, ended_at, duration, location same as activity

Every kind also rejects times more than 5 minutes in the future, times before birth, and an end time earlier than the start time. All shared columns live in the _CareEntry mixin: at, local_date, note, source (parent, camera_confirmed, import), status, version and client_key.

Inputs and outputs

Endpoint Purpose
POST /api/patients/{pid}/care/{kind} Add an entry. If the client_key was already used, the existing row is returned with existing: true
PATCH /api/care/{kind}/{eid} Correct an entry. The old values go to record_revisions and version goes up by 1
POST /api/care/{kind}/{eid}/withdraw Set status=withdrawn. The row stays in history
GET /api/care/{kind}/{eid}/history Current row plus previous snapshots
GET …/care/day, …/care/timeline?filters= Day summary and filtered timeline
GET …/care/calendar/month, …/care/calendar/week Calendar markers and week grid
GET …/care/analytics?range=today|7d|30d|custom Daily series, totals, statements (custom range is capped at one year)
GET …/care/compare?kind=episode|admission&ref_id= Before/during/after windows (1–30 days, default 7)
GET …/care/export?preset=24h|3d|7d|illness|custom&format=json|txt Doctor export of daily care
GET/PUT …/care/settings, PUT …/care/day/{day}/note Settings and a per-day note
POST …/care/medicine/quick, GET …/care/medicines/today GIVEN / SKIP / LATER / MISSED from the schedule card

Data flow

flowchart LR
  A["Caregiver quick-add<br/>web or mobile"] -->|"POST with client_key"| B["care_api.prepare<br/>validate and compute local_date"]
  B --> C{"client_key already used"}
  C -->|"yes"| D["Return existing row"]
  C -->|"no"| E["Typed entry row<br/>status active"]
  E -->|"PATCH"| R["record_revisions snapshot<br/>version plus one"]
  E -->|"withdraw"| W["status withdrawn<br/>excluded from views"]
  E --> F["care.entries<br/>active rows by local_date"]
  F --> G["day_summary"]
  F --> H["timeline with filters"]
  F --> I["month_markers and week_grid"]
  F --> J["daily_series and analytics"]
  J --> K["compare_illness<br/>before during after"]
  J --> L["care_export<br/>summary_text and sections"]
  L --> M["PDF export and doctor share"]
Loading

care.entries() returns only status == 'active' rows, so a withdrawn entry disappears from every derived view at once while its history stays intact.

Day summary

day_summary() returns:

  • Fluids: total ml for entries with a known amount, the event count, the number of entries with an unknown amount (kept out of the total), and a breakdown by fluid type.
  • Diapers: wet, stool, mixed, dry checks and total changes. For today it also looks back to earlier days to compute minutes since the last wet diaper and the last stool.
  • Stool: entries, watery or loose count, how many have photos, review flags and photo metadata.
  • Medicines: due slots from verified prescriptions that have schedule times, matched against administration records. A slot with no record is no_record, never given.
  • Symptoms, activity minutes, sleep minutes, and the number of camera suggestions still pending.
  • Fixed warnings: "Fluid volumes and diaper counts are what you recorded; they are not a hydration assessment." and "Medicines are counted as given only when you recorded them as given."

Timeline and filters

timeline() merges every kind for one local day and sorts by time. Filters are a comma list: all, fluid, diaper, stool, medicine, symptom, activity, sleep, clinical and camera. clinical adds confirmed vaccinations, hospital visits, admissions, lab observations and documented fever episodes. camera adds observations that were not dismissed; unconfirmed ones are labelled "Camera suggestion". When a diaper was logged together with a stool entry, it is folded into that stool item ("diaper changed") so it is not counted twice. The legacy MedicationEvent rows also appear as "medication history".

Care Calendar

The web client (web/care.js) offers Day, Week and Month views.

View Backend Content
Month month_markers(year, month) Per-day counts per category: medicine, fever, admission, visit, stool, diaper, vaccine, lab, illness, fluid, symptom, activity, sleep, camera (confirmed only), plus fluid_ml and wet
Week week_grid(start) Seven days, each with its full timeline and a summary subset
Day care/day Day summary, day note and timeline including clinical and camera items

Analytics and illness comparison

Analytics ranges are Today, Last 7 days, 30 days and Custom. The output includes a per-day series, totals, stool colour and consistency distributions, mucus/blood report counts, medicine adherence ("a given record exists for N of M scheduled slots") and symptom counts. Statements describe co-occurrence only, for example "Loose or watery stool entries were recorded on 4 of 6 recorded days." Tests check that the output never contains "cured", "dehydrat" or causal "caused" wording.

compare_illness() buckets the window before, during and after an illness episode or admission. It lists documented fevers, antibiotic records, labs and visits in the extended window, with the warning that differences "are observations, not evidence that any treatment or event caused them."

Doctor export of daily care

care_export() builds a plain-language DAILY CARE SUMMARY with fluids, diapers, stool patterns, "MEDICINES RECORDED AS GIVEN", symptoms, sleep and activity, followed by a day-by-day list. Stool photographs are left out unless include_photos=true, in which case only their ids are listed. The same function feeds the daily_care_7d preset of the PDF Export Architecture and the daily-care section of Share With Doctor. Every export is audited.

Settings

CareSettings holds the quick fluid amounts, the default fluid type, review colours and an optional wet_diaper_threshold_per_day. The app never supplies a threshold. SettingsIn rejects a threshold unless threshold_source names who gave it (for example "Dr A, 2026-01-15"). If the day ends below the threshold, the summary shows "Review requested: fewer wet diapers than the threshold you entered." It never says "dehydrated".

Mobile offline queue

mobile/DailyCareScreen.tsx generates a random client_key for every POST. If a POST fails with a network error, the request is stored in expo-secure-store (one key per queued item plus an index), and the screen shows "N entries saved offline, waiting to sync". queueFlush() replays the queue when the screen loads, when the app returns to the foreground, or when the caregiver taps "Sync now". Because of client_key, a replay that already reached the server returns the existing row instead of creating a duplicate. Non-network errors drop the queued item. The web client has no offline queue.

Clinical safety rules

  • Scheduled ≠ given: only an explicit GIVEN record counts. A reminder never marks a dose as given (see Medicines).
  • Counts are not a hydration, illness or developmental assessment.
  • Stool interpretation is observational only, not a diagnosis (see Stool Photo Pipeline).
  • Parent-entered rows keep source=parent. Camera-derived rows keep source=camera_confirmed.

Security boundaries

Every route resolves the profile through own_patient / own_resource. Another family gets 404, and an unauthenticated request gets 401. Notes, custom amounts and locations use EncryptedText. See Family Profile Isolation.

Implementation

api/care_models.py, api/care.py, api/care_api.py, api/history.py, web/care.js, mobile/DailyCareScreen.tsx, tests/test_care.py.

Related pages

Medicines and Administration Model · Stool Photo Pipeline · Home Camera Architecture · PDF Export Architecture · Database and Data Model · Illness History and Lifetime Health

Clone this wiki locally