Kulcare Docs

Health Diary — Product Specification

Issue: #2291 Status: Shipped in #2417 and #2518, pending manual QA. Promises P1 to P10 are built; P4 still runs on a starter term list until clinical review. Companion docs: Web interface design · How a patient uses it · Developer guide · QA guide

This document states what the Health Diary promises a patient. The backend plan states how we build it. §5 is the join between the two: every promise maps to the endpoints that deliver it and the test that proves it. If a promise has no row in §5, we have not built it — we have only intended it.


1. What this is

A patient opens the Kulcare app at 11pm because their head has hurt for three days and they don't know whether that is worth a doctor's appointment. The Health Diary is where they type that. They get back an answer that helps them decide what to do next, a saved record of what they said, and a one-tap route to an actual clinician.

It is not a symptom checker that returns a diagnosis, and it is not a triage system that makes decisions for the patient. It is the space between "something is wrong" and "I have seen someone about it" — a space that is currently a Google search.

Who it is for

UserWhat they are doing
The patientRecording something they are feeling, in their own words, in their own language, usually outside clinic hours.
The caregiverA parent, an adult child, a spouse managing a dependent's account — recording on someone else's behalf, and needing the record to belong to that person, not to them.
The clinician (not v1)Eventually: seeing what the patient recorded between visits. This is the long-term value and the reason the data is worth storing.

2. The promises

Ten promises. Each one is testable, and each is traced to code in §5.

#PromiseIn the patient's words
P1Somewhere to put it. Anything they type or say is saved, in any supported language, any time."I wrote it down and it's still there."
P2An answer that helps them decide. Orientation, not diagnosis: is this something to watch, to book for, or to act on now."I know what to do next."
P3It never pretends to be a doctor. Every answer says so, and a real clinician is always one tap away."It told me to check with someone, and I could."
P4Emergencies come first. If what they describe could be an emergency, that guidance leads the reply — before anything else."It told me to go now."
P5It remembers. History survives a reinstall, a new phone, a switch to the web."Everything I've written is here."
P6It shows them the shape of their health. Entries, topics, and a plain-language summary of a period."I could see it's been happening all month."
P7It works in their language. Seven languages, typed or spoken."I said it in Tamil and it understood."
P8A caregiver can do this for someone they look after. And the record belongs to that person."I logged my mother's symptoms and they're in her file, not mine."
P9Nothing they typed is lost. Even when our AI fails."It errored, but my message was still there."
P10Their diary is theirs. They can delete any entry; nobody else can read it."I deleted it and it's gone."

3. What we are not promising in v1

Being explicit here is what keeps the promises above honest.

Not promisedWhy, and what we say instead
A clinician reads thisNobody is monitoring the diary. The UI must never imply otherwise — emergency guidance says "call your local emergency number", never "we have alerted someone".
This is your medical recordIt is the patient's own account of how they feel. It does not enter the clinical record and does not reach the treating clinician in v1.
A live, typing-as-it-goes replyv1 returns the whole answer at once. Streaming is deferred.
Your voice note is keptAudio is transcribed and discarded. Only the transcript is stored — which is also how we avoid holding recordings under an unsettled retention policy.
It knows your clinic historyv1 reads the patient's own recorded data for context, not records held by clinics they have visited.
It works offlineThe app can queue, but the answer requires a connection.

4. Core journeys

J1 — First message. Patient types their symptom → sees their own message immediately → sees the reply with a disclaimer and up to three next-step buttons → a diary entry has appeared in their history without them doing anything.

J2 — Coming back. A week later they open the same thread, add "it's worse in the mornings", and the reply takes the earlier messages into account.

J3 — Organizing. They move a thread into a topic folder, or accept the assistant's offer to start tracking a topic ("Track Headaches"), which creates the folder and moves the thread.

J4 — Looking back. They open History, filter by topic or date, and read what they recorded.

J5 — The summary. They ask for the last 30 days and get a plain-language summary plus the topics that came up most.

J6 — Speaking instead of typing. They hold the mic, speak in Tamil, and their words appear as text with a reply — because reading and typing are a real barrier for a large share of our users.

J7 — Caregiver. A daughter switches into her mother's context, records her mother's symptom, and the entry sits in her mother's diary with her own identity recorded as who entered it.

J8 — Something serious. Patient writes "chest pain and I can't breathe properly". The reply leads with immediate-help guidance and a route to care, and the message is flagged.


5. Traceability — promise → build → proof

This table is the point of this document. It is the checklist a reviewer runs before we call the feature done. "Unit" refers to the backend plan's work breakdown (docs/plans/, a working document that is not part of the docs site); F-units are from the web interface design. Every row below is now built; the tests named in "Proven by" live in backend/domains/patient/test/**/health_diary/ and patient/src/features/health-diary/**, and the manual pass is the QA guide.

PromiseAcceptance criteriaDelivered byProven by
P1 Somewhere to put itMessage of 1–2000 chars in any of 7 languages is persisted before any AI work begins; retrievable from another device.POST /chat/messages · U6, U1Request test: message row exists after a forced AI failure.
P2 An answer that decidesEvery assistant reply carries 1–3 CTAs; see_care_options always present; labels in the request language.CTA builder · U6Test: CTA invariants across all 7 languages.
P3 Never pretendsDisclaimer present on every assistant message, appended by code, not by the model.Disclaimer step · U6Test: disclaimer present even when the model returns an empty completion.
P4 Emergencies firstEmergency phrasing sets safety_flag: "emergency" and prepends immediate-help guidance; UI renders it above the answer.Safety pipeline · U10 (seam in U6) · F4Test per language once the clinical term list lands (B-1).
P5 It remembersThreads, messages, entries survive reinstall; history pages in both directions; caregiver and patient see the same data.Threads/messages/entries · U4, U5, U7Cursor-paging tests at boundaries; cross-device manual check.
P6 Shape of their healthAn entry is auto-created per exchange with a title and tags; GET /summary?days=N returns summary, entry count and top tags.Entry creation · U6 · summary · U8Test: entry created per exchange; summary cache honours its freshness window.
P7 Their languageReplies and CTA labels match the requested language; typing in all 7, voice in en, hi, pa, ta, te and ar. Not Malayalam -- verified against the speech provider: no model on our plan transcribes it (backend plan §6.4).i18n · U3 (incl. new ar.yml) · STT · U9Test per language; STT coverage verified per language before we promise it (§7 R-3).
P8 CaregiverRows carry the dependent as owner and the caregiver as recorder; a non-dependent target is refused.Existing Patient::BaseController · U6 · F5Test: owner/recorder columns; 403 on a stranger; on-behalf-of query param ignored on writes.
P9 Nothing lostA provider failure returns the documented unavailable error and the user's message is already persisted. A note whose answer failed can be asked again, including after a page reload; a note that never reached the server stays on screen until the patient dismisses it, however many there are.U6 degradation path · resume flag and the un-sent note list (#2518)Test: forced provider error → 503 + message row present; a stranded reply comes back resumable; two failed sends both survive.
P10 TheirsPatient can delete an entry; another user's entry returns 404, never 403.DELETE /entries/:id · U7 · policies · U1Test: cross-user access returns 404 (no existence leak).

6. Rules that are not negotiable

These are product rules, not implementation preferences. They exist because the failure mode is a patient harmed, not a bug ticket.

  1. The model does not get to decide safety. Disclaimer, CTA composition and emergency guidance are written by our code and appended after the model returns. A model that ignores its instructions must not be able to remove them.
  2. Never claim a human has been alerted. Nobody is watching. Emergency copy directs the patient to emergency services, never to us.
  3. No diagnosis, no prescription. The assistant does not name a condition as fact and does not recommend a specific drug or dose.
  4. The patient's own words are sacred. They are persisted before the AI is called and are never edited, summarized in place, or discarded on error.
  5. The route to a human is always present. Every reply carries a way to reach care.
  6. A caregiver's action is always attributed. Two identities on every row: whose diary, and who typed.

7. Where the technology could fail the promise

Honest reading of the plan against the promises above.

RiskWhich promise it threatensMitigation in the plan
R-1 Emergency term list is not signed offP4 — the promise we least want to ship softv1 ships the detection seam with an English seed; the promise is not advertised until U10 lands with a clinician-reviewed list. Product decision: do not put "detects emergencies" in store copy before then.
R-2 No moderation provider chosenP2, P3Null provider blocks nothing — which is today's behaviour, so not a regression. Revisit before scale.
R-3 Speech-to-text language coverage -- verified 2026-09-18P7 for voiceSix of seven pass; Malayalam does not on our plan. As planned: voice for the six, typing for all seven, and the mic is hidden for Malayalam rather than offered and failing.
R-4 Rate limits do not currently workP1, P2 (cost and abuse)Cache-store fix in U11. Until then the per-patient ceiling is unenforced and spend is uncapped.
R-5 Model quality is unproven for Indian-language health chatP2 — the whole valueNeeds a pre-launch evaluation pass against real phrasings per language, not just an English smoke test. Not currently in the plan — added as a product gate below.
R-6 Retention is unansweredP5, P10No audio is stored at all; message retention must be answered before general availability.
R-7 No clinician ever sees the diaryThe long-term product valueExplicitly deferred; the entry/tag model is designed so a clinician view can be added without reshaping data.

Product gate added by R-5: before launch, a reviewed sample of real patient phrasings per language is run through the pipeline and read by a clinician. Quality of the answer is the product; an API that returns 200 with a useless reply passes every test in §5 and still fails the patient.


8. Measures

QuestionMeasure
Does it help them decide?Share of assistant replies whose CTA is tapped; share of diary threads that lead to a booking within 7 days.
Do they come back?Patients with a second message on a later day; threads with 3+ turns.
Is it safe?Emergency-flag precision and recall against a clinician-reviewed sample; moderation block rate.
Does it work?p95 chat latency; provider-failure rate; transcription success rate per language; 429 rate.
Is it used the way we think?Voice vs typed share, by language; folder use; summary pulls per patient per month.

9. Open product questions

  1. Who is the diary for, eventually? If the answer is "the clinician sees it at the next visit", that should shape the entry model now rather than later.
  2. Is it available to every patient, or gated by entitlement? There is no tenant to bill, so diary AI spend sits outside per-facility cost reporting (D-3 in the backend plan).
  3. What happens to a thread when a dependent grows up and takes over their own account?
  4. Does an emergency flag ever leave the device? Today it is recorded and shown. Whether it should notify anyone is part of B-1.
  5. How much un-sent work should the diary hold? A note that never reached the server is kept on screen until dismissed. With several at once, only the newest carries the explanation and the controls, the list is unbounded, and it does not survive navigating away. Raised by the #2518 review; the answer decides whether this state deserves its own design.
  6. What do we tell patients about processors? The user guide says recordings are not kept and that only caregivers can see a diary. It does not yet name the model provider or the transcription provider. Product and legal own that wording.

On this page