Repository navigation
14 Vaccination Model
The vaccination model in HealthBook AI (internal code name: BabyCare) records what the family's vaccination card or doctor says. It does not record what a national schedule predicts. Each row separates the date a dose was given from the date a dose is due. A row is not trusted for reminders until a caregiver confirms it against a real card or doctor schedule. Reference schedules exist only to help a caregiver compare; they never become confirmed entries.
A due_date is an appointment written on the card. It is never evidence that a vaccine was given. Only given_date describes administration. An undated card line is never treated as given, and the review validator rejects a vaccine row that has no date (see OCR and Human Verification Workflow).
- Store vaccine rows with given and due dates, dose label, batch, facility, doctor, source document and page.
- Gate reminders on confirmation, a real source document and a non-reference source type.
- Detect possible duplicate doses before saving.
- Reset confirmation when a material field changes.
- Provide India UIP and IAP reference charts as reference-only overlays.
- Expose a status-labelled vaccination chart and a CSV export.
| Endpoint | Purpose |
|---|---|
GET/POST /api/patients/{pid}/vaccines |
list rows (by due date) / add a row (always confirmed=false) |
PATCH /api/vaccines/{id} |
edit or confirm; snapshot written first |
GET /api/patients/{pid}/vaccine-reference?schedule=India_UIP|IAP_private |
reference chart computed from DOB, with warnings |
POST /api/patients/{pid}/vaccine-reference/import |
create unconfirmed India_UIP_reference drafts |
GET /api/patients/{pid}/vaccination-chart |
rows with status, age at date, scheduled reminders |
GET /api/patients/{pid}/vaccination-chart.csv |
export (formula-injection safe) |
| Field | Values / rule |
|---|---|
name, dose_label
|
required name; dose label up to 70 chars |
given_date |
must be between the profile's DOB and today (profile timezone) |
due_date |
appointment date; no range restriction |
confirmed |
false on create; set only by PATCH or by review confirmation |
source_type |
manual, vaccination_card, doctor_schedule, India_UIP_reference
|
schedule |
card, India_UIP, IAP_private
|
reminder_days |
lead days, default 7,1,0, up to 10 values |
batch_number, facility, doctor, note
|
free text, encrypted |
source_document_id, source_page
|
provenance, validated against the document's page count |
version |
incremented on each edit; part of the reminder key |
PATCH /api/vaccines/{id} enforces these rules:
- Confirming requires a
source_document_id, andsource_typemust not beIndia_UIP_reference. The error is "Reference-only dates require a real vaccination card or doctor schedule before confirmation". - Confirming requires at least one of
due_dateorgiven_date. - If
due_date,given_date,name,dose_label,source_document_id,source_type,source_pageorreminder_dayschanges,confirmedis reset to false, unless the same request also setsconfirmed. - Changing the profile timezone un-confirms every confirmed row that has no given date, because its reminder times would otherwise silently shift.
check_vaccine_duplicate compares the name with all non-word characters removed and case-folded, plus the case-folded dose label. A match returns 409 with the existing rows, unless the request carries duplicate_confirmed: true. Review confirmation reports the same check per row as possible_duplicate.
When a reviewed card row has both a given date and a next_due_date, confirmation creates two rows: the administered dose, and a new row for the next dose with only a due date and an empty batch number. The next-dose row is confirmed only if the caregiver ticked "activate reminders". The audit records confirmed_next_dose or unconfirmed_next_dose. An appointment is never folded into the administered record.
api/vaccination.py holds two static age charts:
- India UIP, attributed to a Government of India annual report;
- IAP private-clinic milestones, attributed to an IAP ACVIP publication.
reference(dob, schedule) adds weeks, months or years to the DOB and returns reference_date, an optional window end, the source, and the warning "REFERENCE ONLY: schedule varies; not an appointment or catch-up instruction". The API adds that reference dates are not individualised eligibility or catch-up recommendations, and that JE applies only in specific areas. The import endpoint creates unconfirmed India_UIP_reference rows (skipping name and dose pairs that already exist) and says that no reminders will be generated. Reference rows can never schedule reminders, and the chart shows them as reference_only.
reminder_items only schedules a vaccine when all of the following hold:
-
confirmed = true; - no
given_date; - a
due_date; - a
source_document_id; -
source_typeis notIndia_UIP_reference.
There is one reminder per lead day, at 09:00 profile-local time, keyed vaccine-{id}-v{version}-{due}-{lead}d. Delivery never marks a dose as given (see Notifications and Reminder Architecture).
Diagram: Vaccine entry state diagram
flowchart TD
N["New row, confirmed false"] --> Q{"Given date present"}
Q -->|"yes"| GP["documented_given_pending_verification"]
Q -->|"no, due date only"| DP["due_pending_verification"]
Q -->|"reference import"| RO["reference_only, never confirmable as is"]
Q -->|"no dates"| IN["incomplete_record"]
GP -->|"confirm with source document"| GV["documented_given_verified"]
DP -->|"confirm with source document"| UC["upcoming_confirmed, reminders active"]
DP -->|"due date passes"| DX["due_date_passed_unverified"]
UC -->|"due date passes"| CX["confirmed_date_passed, ask provider"]
UC -->|"material edit"| DP
GV -->|"material edit"| GP
UC -->|"caregiver records given date"| GV
vaccine_status() in api/history_api.py:
| Status | Meaning shown to user |
|---|---|
reference_only |
Reference schedule only |
documented_given_verified |
Documented given (caregiver verified) |
documented_given_pending_verification |
Documented given on card, pending caregiver verification |
upcoming_confirmed |
Upcoming, confirmed appointment |
confirmed_date_passed |
Confirmed date has passed, ask provider |
due_pending_verification |
Due date on card, pending verification |
due_date_passed_unverified |
Card due date has passed, unverified; ask provider |
incomplete_record |
Incomplete record |
The chart also returns age_at_date, reminders_scheduled per row, pending due dates grouped by date, and the next confirmed appointment. The simple timeline shows only confirmed given doses. The history view shows given doses with a certainty label and due dates as "Vaccine due on card".
- Vaccination due date ≠ vaccination administered.
- Reference schedules are not personalised orders and never activate reminders.
- OCR extracted ≠ clinically verified: card transcriptions stay pending until confirmed.
- A reminder is never proof a dose was given.
api/main.py (VaccineIn, VaccineUpdate, add, edit, reference routes), api/workflows.py (check_vaccine_duplicate, review confirmation, timezone reconciliation, CSV), api/vaccination.py, api/reminders.py, api/history_api.py (vaccine_status, vaccination_chart), web/history.js.
OCR and Human Verification Workflow · Notifications and Reminder Architecture · Medical Document Ingestion · Design Decisions
Overview
Platform
Identity and access
Medical records
- 10 Document Ingestion
- 11 OCR and Human Verification
- 13 Medicines and Administration
- 14 Vaccination Model
- 15 Labs, Growth, Longitudinal
- 16 Illness and Lifetime Health
Daily care
Output and sharing
Security
Engineering
- 26 Testing and Validation
- 27 Deployment and CI/CD
- 28 Technology Stack
- 29 Design Decisions
- 30 Limitations
- 31 Roadmap