# Inou Intake System — Design Specification ## Vision Transform how non-technical users capture health data. No forms. No configuration. Just conversation that crystallizes into structure. The user talks, the system learns. Yesterday's input becomes today's smart prompt with previous values pre-filled. --- ## Core Principles | Principle | Meaning | |-----------|---------| | **Intake AI, not advice AI** | We capture, structure, and ask smart follow-ups. We never diagnose or recommend treatment. | | **Complexity on server, simplicity on client** | All intelligence lives server-side. Apps are dumb renderers. | | **Templates emerge, not configured** | User describes leg trainer once → system learns the shape → next time shows fields with previous values. | | **Conversation, not forms** | Onboarding isn't a moment, it's a relationship. Learn one thing at a time, naturally. | | **Show before save** | Always confirm what was understood. Build trust. | --- ## Phase 1: Server + Ugly UI ### Goal Fully functional intake system with web-based interface. Prove the model works before investing in pretty UI or mobile. ### Deliverables #### 1. Data Model Extensions **Prompt table:** ```sql prompts ( prompt_id INTEGER PRIMARY KEY, dossier_id INTEGER NOT NULL, category TEXT, -- "medication", "vital", "exercise", "symptom" type TEXT, -- "Lisinopril", "BP", "leg_trainer" question TEXT, -- "Did you take your morning meds?" -- Scheduling frequency TEXT, -- "daily", "weekly:mon,wed,fri", "once", "until_resolved" time_of_day TEXT, -- "08:00", "12:00", "21:00", NULL for anytime next_ask INTEGER, -- epoch: next time to show expires_at INTEGER, -- epoch: stop asking after this (0 = never) -- Input definition input_type TEXT, -- "checkbox", "checkbox_group", "number", "text", "scale", "custom" input_config TEXT, -- JSON: field definitions, scale labels -- Grouping group_name TEXT, -- "morning_meds", "gym_session" — for collapsing -- Source/linking trigger_entry INTEGER, -- entry that spawned this (for follow-ups) created_by INTEGER, -- dossier_id of who created (self, caregiver) -- Last response (for pre-filling) last_response TEXT, -- JSON: parsed/structured answer last_response_raw TEXT, -- what they actually said/typed last_response_at INTEGER, -- epoch -- State dismissed INTEGER DEFAULT 0, -- 1 = "don't ask again" active INTEGER DEFAULT 1, -- 1 = active, 0 = paused created_at INTEGER, updated_at INTEGER ) CREATE INDEX idx_prompts_dossier ON prompts(dossier_id); CREATE INDEX idx_prompts_dossier_active ON prompts(dossier_id, active, next_ask); ``` ### input_config Field Schema The `input_config` column stores a JSON object defining form fields. The frontend renders these directly — no AI interpretation needed. **Structure:** ```json { "fields": [ { "key": "duration_min", "label": "Duration", "type": "number", "datatype": "int", "min": 1, "max": 120, "unit": "min", "required": true }, { "key": "intensity", "label": "How hard was it?", "type": "select", "datatype": "string", "options": ["easy", "moderate", "hard"], "required": true }, { "key": "exercises", "label": "Exercises", "type": "multiselect", "datatype": "string[]", "options": ["bench", "squat", "deadlift", "treadmill"], "required": false }, { "key": "notes", "label": "Notes", "type": "text", "datatype": "string", "maxlength": 500, "required": false } ] } ``` **Field types (what to render):** | type | datatype | renders as | |------|----------|------------| | `text` | string | text input | | `textarea` | string | multiline | | `number` | int / float | number input with +/- | | `checkbox` | bool | single checkbox | | `select` | string | dropdown | | `multiselect` | string[] | checkboxes or multi-picker | | `scale` | int | 1-5 or 1-10 buttons | | `time` | string | time picker (HH:MM) | | `date` | string | date picker | **Field properties:** | property | applies to | meaning | |----------|-----------|--------| | `key` | all | JSON key in response | | `label` | all | display label | | `type` | all | widget type | | `datatype` | all | validation type | | `required` | all | must fill | | `default` | all | pre-fill value (overridden by last_response) | | `min` | number | minimum value | | `max` | number | maximum value | | `unit` | number | suffix to display ("°", "min", "lbs") | | `step` | number | increment (0.1 for float) | | `maxlength` | text | character limit | | `options` | select, multiselect | choices | | `scale_labels` | scale | e.g. ["terrible", "poor", "ok", "good", "great"] | **Response handling:** When rendering a prompt, the frontend: 1. Reads `input_config.fields` 2. For each field, checks `last_response[key]` 3. Pre-fills if exists 4. User submits → stored as new `last_response` **Entry table additions:** ```sql -- Existing entry table, ensure these fields: entries ( ... parent_id INTEGER, -- for nested entries (gym session → exercises) data TEXT, -- JSON blob for structured details + raw input ... ) ``` **Dossier table additions (now live):** ```sql -- Added to dossiers table: weight_unit TEXT, -- "kg" or "lbs" height_unit TEXT, -- "cm" or "ft" last_pull_at INTEGER, -- epoch: last time app fetched prompts is_provider INTEGER DEFAULT 0, -- 1 if healthcare provider provider_name TEXT, -- practice/clinic name away_message TEXT, -- auto-responder text away_enabled INTEGER DEFAULT 0 -- 1 if auto-responder active -- (language already exists on dossier) ``` #### 2. API Endpoints **GET /api/prompts?dossier=X** Returns prompts due now for this dossier. Response: ```json { "prompts": [ { "id": "abc123", "category": "medication", "type": "morning_meds", "question": "Did you take your morning medications?", "input_type": "checkbox_group", "input_config": { "items": [ { "name": "Lisinopril", "amount": "10mg" }, { "name": "Metoprolol", "amount": "25mg" } ] }, "group_name": "morning_meds", "group_count": 2, "actions": ["took_all", "missed_some", "skip"] }, { "id": "def456", "category": "exercise", "type": "leg_trainer", "question": "Leg trainer (morning)", "input_type": "custom", "input_config": { "fields": [ { "name": "left_min", "label": "Left min", "type": "number", "previous": 20 }, { "name": "left_angle", "label": "Left °", "type": "number", "previous": 30 }, { "name": "left_speed", "label": "Left speed", "type": "number", "previous": 4 }, { "name": "right_min", "label": "Right min", "type": "number", "previous": 20 }, { "name": "right_angle", "label": "Right °", "type": "number", "previous": 42 }, { "name": "right_speed", "label": "Right speed", "type": "number", "previous": 5 } ], "notes_field": true }, "actions": ["save", "skip"] }, { "id": "ghi789", "category": "followup", "type": "symptom_check", "question": "Yesterday you had a headache. How are you today?", "input_type": "scale", "input_config": { "options": ["Much better", "Same", "Worse"] }, "actions": ["select", "skip"] }, { "id": "open", "category": "general", "type": "anything_else", "question": "Anything else you'd like to mention?", "input_type": "freeform", "input_config": { "placeholder": "Voice, text, or photo...", "allow_photo": true, "allow_voice": true }, "actions": ["save", "nothing"] } ], "for_dossiers": [ { "id": "xxx", "name": "Johan", "relation": "self" }, { "id": "yyy", "name": "Sophia", "relation": "daughter" }, { "id": "zzz", "name": "Mama", "relation": "mother-in-law" } ] } ``` **POST /api/prompts/respond** Submit response to a prompt. Request: ```json { "prompt_id": "abc123", "dossier_id": "xxx", "action": "took_all", "response": null } ``` Or for custom input: ```json { "prompt_id": "def456", "dossier_id": "yyy", "action": "save", "response": { "left_min": 15, "left_angle": 25, "left_speed": 3, "right_min": 15, "right_angle": 35, "right_speed": 4, "notes": "She was tired today" } } ``` Returns: ```json { "success": true, "entries_created": ["entry_id_1", "entry_id_2"], "prompt_updated": true } ``` **POST /api/intake/parse** Parse freeform input (text, voice transcript, photo). Request: ```json { "dossier_id": "xxx", "input_type": "text", "content": "Sophia did leg trainer 20 min, left 30 degrees speed 4, right 40 degrees speed 5", "attachments": [] } ``` Or with photo: ```json { "dossier_id": "xxx", "input_type": "photo", "content": null, "attachments": [ { "type": "image", "data": "base64..." } ], "context": "supplement_bottle" } ``` Returns parsed interpretation for confirmation: ```json { "interpretation": { "target_dossier": { "id": "yyy", "name": "Sophia", "confidence": 0.95 }, "entries": [ { "category": "exercise", "type": "leg_trainer", "display": "Leg trainer — 20 min", "data": { "duration_min": 20, "left": { "angle": 30, "speed": 4 }, "right": { "angle": 40, "speed": 5 } } } ], "follow_up_question": null, "suggested_prompt": { "question": "You log leg trainer regularly. Want me to remind you?", "options": ["Yes, daily", "Yes, twice daily", "No thanks"] } }, "raw": "Sophia did leg trainer 20 min, left 30 degrees speed 4, right 40 degrees speed 5" } ``` **POST /api/intake/confirm** Confirm parsed interpretation, create entries. Request: ```json { "interpretation_id": "temp_xxx", "confirmed_dossier": "yyy", "entries": [...], "create_prompt": { "answer": "Yes, twice daily" } } ``` **POST /api/intake/ask** Handle intake AI asking follow-up questions. Request: ```json { "dossier_id": "xxx", "context": "unit_clarification", "question_type": "weight_unit", "user_input": "80" } ``` Response: ```json { "question": "Is that kg or lbs?", "options": ["kg", "lbs"], "store_preference": true } ``` **GET /api/summary?dossier=X&period=30d** Generate summary for doctor visit. Response: ```json { "dossier": { "name": "Sophia", "dob": "...", "sex": "female" }, "period": "last 30 days", "sections": { "medications": [], "therapy": [ { "name": "Leg trainer", "frequency": "2x daily", "compliance": "12/14 sessions", "typical": "L 30° speed 4, R 40° speed 5", "trend": "Right side improving (was 35° in December)" } ], "symptoms": [ { "date": "Dec 28", "type": "headache", "resolution": "resolved after 2 days" } ], "vitals": { "weight": { "start": "32kg", "end": "32.5kg" } }, "imaging": [...], "labs": [...], "notes": [ "Tired after school most days", "Slept poorly Tuesday, better Wednesday" ] }, "markdown": "...", "shareable_link": "https://inou.com/s/xxxxx" } ``` #### 3. Intake AI Logic (Server-side) **Parsing engine:** - Receives text/voice transcript/photo - Identifies target dossier from context ("Sophia", "my son", "I") - Extracts structured data - Detects patterns that could become prompts - Generates follow-up questions when needed **Prompt generation:** - From explicit statements: "I take vitamin D every morning" → daily prompt - From repeated behavior: 5 similar entries → suggest prompt - From concerning entries: "running stool" → follow-up tomorrow **Template learning:** - First entry with structure → store shape in prompt's input_config - Next time → pre-fill with previous values - Evolves as user input evolves **Multi-dossier routing:** - Parse input for person references - Match against accessible dossiers - Require confirmation if ambiguous - Default to last-used dossier if truly unclear #### 4. Onboarding Flows Not a wizard. A series of prompts that appear naturally. **Initial (account creation):** - Name, DOB, sex — required - That's it. Done. **Day 1-7 (prompted when they return):** - "What brings you to inou?" — capture chief concern - "Do you take any daily medications?" — yes → capture list - "Any supplements?" — yes → capture list - "Anything you're tracking? Weight, blood pressure, exercise?" **Week 2+ (contextual):** - After first lab upload: "Any conditions we should know about?" - After logging same thing 5x: "Want me to remind you?" - After 2 weeks: "It helps to know family health history. Mind sharing?" **Family history flow:** - "Is your mother still living?" → [Yes] [No] - If no: "How old? What happened?" → captures cause - If yes: "Any health conditions?" → open field - Same for father, siblings - "Anything that runs in the family?" → open field #### 5. Ugly Web UI Minimal but functional. Prove the model. **Dashboard:** - List of prompts due today - Grouped where applicable ("Morning meds (8)") - Each renders based on input_type - "Anything else" always at bottom **Prompt rendering:** - checkbox_group: checkboxes + "Took all" button - number: input field with unit - scale: buttons with labels - custom: dynamic fields from input_config - freeform: text area + photo upload + mic button (browser speech-to-text) **Confirmation modal:** - Shows parsed interpretation - Allows dossier change if wrong - Edit button for corrections - Save / Cancel **History view:** - Today's entries - Past 7 days - Searchable - Editable (tap to modify) **Summary view:** - Generate summary for selected period - Copy as text - Print - Share link --- ## Phase 2: Pretty UI + Mobile ### Goal Native mobile experience with Flutter. Beautiful UI. Local capabilities (speech-to-text, barcode, camera). ### Deliverables #### 1. Flutter App **Architecture:** - Calls same API endpoints - Local speech-to-text (send transcript to server) - Local barcode scanning (send code to server for lookup) - Local OCR first pass (send text + image if low confidence) - Local notifications scheduled from prompt data **Pull model:** - On app open: GET /api/prompts - Background refresh: once daily - Store prompts locally for offline - Queue responses if offline, sync when connected **Push fallback:** - Server tracks last_pull_at per dossier - If no pull in 3+ days AND prompts due → push notification - Push just says "Don't forget to log" — opens app → pull → render **Screens:** *Home (Prompts):* - Cards for each due prompt - Swipe to skip - Tap to expand/respond - Grouped cards for multi-item (morning meds) - Always: "Anything else?" at bottom *Input:* - Big mic button for voice - Camera for photos (bottle labels, wounds, readings) - Text field - Confirmation before save *Log (History):* - Timeline view - Filter by category, dossier - Tap to edit *Summary:* - Pick dossier, pick period - Generate and display - Share / Export *Dossiers:* - Switch between accessible dossiers - Default for logging (remembers last used) #### 2. Notification System **Local notifications:** - App schedules based on prompt times - "Morning meds" at 8:00 - "Leg trainer (evening)" at 18:00 - Tapping opens app directly to that prompt **Server push:** - Firebase Cloud Messaging - Only when app hasn't pulled in days - Generic "Check in with inou" #### 3. Offline Support **Cached data:** - Prompts (with input_config, previous values) - Recent entries - Dossier list **Queued responses:** - If offline, store locally - Sync on reconnect - Show "pending" indicator #### 4. Voice Flow **User taps mic:** 1. Device speech-to-text (on-device) 2. Transcript sent to server: POST /api/intake/parse 3. Server parses, returns interpretation 4. App shows confirmation 5. User confirms → entry created **Natural language examples:** - "Sophia did leg trainer, 20 minutes, left 30 degrees speed 4, right 40 degrees speed 5" - "I took 2 Tylenol for a headache" - "Mom took her pills" - "Blood pressure 120 over 80" - "Walked for an hour this morning" #### 5. Photo Flow **Supplement bottle:** 1. User taps camera on "Any supplements?" prompt 2. Takes photo of bottle 3. Device OCR extracts text (or barcode scan) 4. Server: looks up product, extracts dose 5. Returns: "Vitamin D3 5000 IU — when do you take this?" 6. User selects [Morning] [Evening] etc. 7. Prompt created **Vitals (BP monitor, scale):** 1. Photo of display 2. OCR extracts numbers 3. Confirm values 4. Entry created **Injury/symptom:** 1. Photo of knee scrape 2. User adds context: "My son fell" 3. Entry created with photo attached #### 6. Pretty UI Design Follow existing inou aesthetic: - Warm, not clinical - IBM Plex Sans - Desert palette: warm beige (#F5EDE4), dark brown (#4A3728), terracotta (#C4704B) Cards with generous padding. Large tap targets. Clear typography. Accessible: works for someone with shaky hands or poor vision. --- ## Appendix A: Example Prompt Types | Type | Input | Previous values? | Follow-up? | |------|-------|------------------|------------| | Medication (single) | checkbox | N/A | If missed 3+ days | | Medications (group) | checkbox_group + "took all" | N/A | If missed | | Vital (number) | number field + unit | Optional | If concerning | | Supplement | checkbox | N/A | No | | Exercise (simple) | number (duration) | Yes | If goal missed | | Exercise (complex) | custom fields | Yes, all fields | No | | Symptom follow-up | scale | N/A | If "worse" | | Freeform | text + voice + photo | N/A | Based on content | ## Appendix B: Entry Structure Examples **Simple medication:** ```json { "category": "medication", "type": "Lisinopril", "value": "taken", "data": { "dose": "10mg" }, "timestamp": 1704369600 } ``` **Leg trainer session:** ```json { "category": "exercise", "type": "leg_trainer", "value": "20 min", "data": { "duration_min": 20, "left": { "angle": 30, "speed": 4 }, "right": { "angle": 40, "speed": 5 }, "notes": "She was tired today", "raw": "Sophia did leg trainer, 20 min..." }, "timestamp": 1704369600 } ``` **Gym session with nested entries:** ```json // Parent { "id": "gym_001", "category": "exercise", "type": "gym_session", "value": null, "timestamp": 1704369600 } // Children { "parent_id": "gym_001", "category": "exercise", "type": "bench_press", "value": "200", "data": { "unit": "lbs" } } { "parent_id": "gym_001", "category": "exercise", "type": "squats", "value": "150", "data": { "unit": "lbs" } } ``` **Supplement from photo:** ```json { "category": "supplement", "type": "Vitamin D3", "value": "1", "data": { "dose": "5000 IU", "brand": "Nature's Way", "source": "photo_ocr", "photo_id": "attach_xxx" }, "timestamp": 1704369600 } ``` **Family history:** ```json { "category": "family_history", "type": "mother", "value": "deceased", "data": { "age_at_death": 78, "cause": "heart attack", "conditions": ["diabetes", "hypertension"], "raw": "She had diabetes and high blood pressure, died of a heart attack at 78" } } ``` ## Appendix C: Intake AI Prompt Guidelines **Role:** You are an intake assistant for a health tracking system. Your job is to: 1. Parse natural language into structured health data 2. Ask clarifying questions when needed 3. Identify which person (dossier) an entry is about 4. Never give medical advice or interpret results **Parsing rules:** - Extract: category, type, value, relevant details - Preserve raw input in data.raw - Resolve aliases (D3 → Vitamin D3, BP → blood pressure) - Detect time references ("yesterday", "this morning") - Detect person references ("my son", "Sophia", "mom", "I") **Multi-dossier:** - If person mentioned matches an accessible dossier → route there - If ambiguous ("blood pressure 120/80") → ask who - If clearly about self ("I walked") → current user's dossier **Follow-up questions:** - Unknown unit: "Is that kg or lbs?" - New supplement: "When do you take this?" - Symptom logged: create follow-up prompt for tomorrow - Repeated activity: "Want me to remind you about this?" **What NOT to do:** - Don't interpret if values are good/bad - Don't recommend treatments - Don't diagnose - Don't say "you should see a doctor" (unless asked about resources) --- ## Appendix D: Implementation Order ### Phase 1 — Server + Ugly UI 1. **Database:** Add prompts table, extend entries 2. **API:** /api/prompts, /api/prompts/respond 3. **Web UI:** Render prompts, handle responses 4. **Intake parsing:** POST /api/intake/parse (start simple, text only) 5. **Confirmation flow:** Show interpretation, confirm, save 6. **Prompt generation:** From explicit statements ("I take X daily") 7. **Follow-up logic:** Symptoms trigger next-day prompts 8. **Template learning:** Remember structure from first entry 9. **Previous values:** Pre-fill from last entry of same type 10. **Grouping:** Collapse multiple meds into "took all" 11. **Multi-dossier:** Parse who, confirm, route 12. **Onboarding prompts:** Medications, supplements, goals 13. **Summary generation:** /api/summary 14. **Family history flow:** Guided questions ### Phase 2 — Pretty UI + Mobile 1. **Flutter scaffold:** Navigation, screens 2. **API integration:** Same endpoints 3. **Prompt rendering:** All input types 4. **Voice input:** On-device STT → server parse 5. **Photo input:** Camera, OCR, send to server 6. **Barcode:** On-device scan → server lookup 7. **Local notifications:** Schedule from prompt times 8. **Offline support:** Cache prompts, queue responses 9. **Push fallback:** Firebase integration 10. **Polish:** Design system, animations, accessibility --- *Document version: 1.0* *Last updated: January 5, 2025* --- ## Phase 1b: Provider Chat ### Goal Secure messaging between patients/caregivers and healthcare providers. Replace Spruce for basic communication. FIPS 140-3 encrypted. ### Why Providers Switch | Spruce | Inou | |--------|------| | $24-49/user/month | Free | | Just messages | Messages + patient's complete dossier | | HIPAA | HIPAA + FIPS 140-3 | ### Data Model (now live) **Messages table:** ```sql messages ( message_id INTEGER PRIMARY KEY, conversation_id INTEGER NOT NULL, dossier_id INTEGER NOT NULL, -- which patient dossier this relates to sender_id INTEGER NOT NULL, recipient_id INTEGER NOT NULL, body TEXT, -- encrypted attachments TEXT, -- encrypted JSON sent_at INTEGER NOT NULL, read_at INTEGER, auto_reply INTEGER DEFAULT 0 ) CREATE INDEX idx_messages_conversation ON messages(conversation_id, sent_at); CREATE INDEX idx_messages_recipient_unread ON messages(recipient_id, read_at); ``` **Conversations table:** ```sql conversations ( conversation_id INTEGER PRIMARY KEY, dossier_id INTEGER NOT NULL, -- the patient dossier provider_id INTEGER NOT NULL, -- the provider's dossier last_message_at INTEGER, unread_count INTEGER DEFAULT 0, created_at INTEGER ) CREATE INDEX idx_conversations_dossier ON conversations(dossier_id); CREATE INDEX idx_conversations_provider ON conversations(provider_id); ``` **Provider fields (added to dossiers table):** ```sql -- See Phase 1 dossier additions for: -- is_provider, provider_name, away_message, away_enabled ``` ### API Endpoints **GET /api/conversations?dossier=X** List all conversations for a dossier (as patient or provider). ```json { "conversations": [ { "id": "conv_123", "patient": { "id": "xxx", "name": "Sophia" }, "provider": { "id": "yyy", "name": "Dr. Patel", "practice": "Kids First Pediatrics" }, "last_message": { "body": "See you at the appointment tomorrow", "sent_at": 1704369600, "sender": "provider" }, "unread_count": 0 } ] } ``` **GET /api/messages?conversation=X&limit=50&before=timestamp** Get messages in a conversation (paginated). ```json { "messages": [ { "id": "msg_456", "sender": { "id": "xxx", "name": "Johan", "role": "caregiver" }, "body": "Sophia's leg trainer went well today. See attached notes.", "attachments": [ { "type": "entry", "id": "entry_789", "name": "Leg trainer session" } ], "sent_at": 1704369600, "read_at": 1704369700 } ] } ``` **POST /api/messages** Send a message. ```json { "conversation_id": "conv_123", "body": "Quick question about her medication dosage", "attachments": [] } ``` Response: ```json { "id": "msg_789", "sent_at": 1704369600, "auto_reply": { "id": "msg_790", "body": "Thank you for your message. I'm currently unavailable but will respond within 24 hours. For urgent matters, please call 555-1234.", "sent_at": 1704369601 } } ``` **POST /api/messages/:id/read** Mark message as read. **PUT /api/provider/settings** Update provider settings (away message, etc). ```json { "away_enabled": true, "away_message": "Thank you for your message. I typically respond within 24 hours. For urgent matters, call 555-1234." } ``` ### Features **Core:** - Text messages (encrypted at rest, FIPS) - Attach entries from dossier (labs, imaging, notes) - Attach photos - Read receipts - Auto-responder when provider unavailable **Notifications:** - Push notification on new message - Email notification if app not opened in 24h **Provider View:** - List of patient conversations - Unread count badge - Click patient → see conversation + dossier summary - Quick access to recent entries, labs, imaging ### Provider Onboarding **Invited by patient:** 1. Patient sends invite to provider email 2. Provider receives: "Johan invited you to view Sophia's health dossier" 3. Provider signs up (free): name, email, practice name 4. Provider linked to patient's dossier with role = medical 5. Provider can message, view dossier **Provider invites patients:** 1. Provider creates account (free) 2. Provider uploads patient list (email CSV) or invites one by one 3. Patient receives: "Dr. Patel invited you to connect on inou" 4. Patient signs up → linked to provider 5. Patient can message, optionally upgrade to full tracking ### Patient Tiers | Tier | Cost | Features | |------|------|----------| | Passive | Free | Receive messages, basic profile, view shared docs | | Active | Paid | Full dossier: intake AI, tracking, prompts, summaries, imaging, labs, genome | Provider brings patients in free. Some upgrade. That's the revenue. ### Auto-Responder Logic ```go func sendMessage(msg Message) { save(msg) notify(recipient) if recipient.is_provider && recipient.away_enabled { autoReply := Message{ sender: recipient, recipient: msg.sender, body: recipient.away_message, auto_reply: true, } save(autoReply) notify(msg.sender) } } ``` ### Security - All messages encrypted with FIPS 140-3 (AES-256-GCM) - TLS 1.3 in transit - Messages only visible to conversation participants - Providers can only see dossiers they're invited to - Audit log for all access ### Implementation Order 1. **Database:** messages, conversations tables; provider fields on dossier 2. **API:** conversations, messages, send, read 3. **Web UI:** conversation list, message thread, compose 4. **Auto-responder:** provider settings, auto-reply logic 5. **Notifications:** push (Firebase), email fallback 6. **Provider invite flow:** patient invites provider 7. **Bulk invite:** provider imports patient list 8. **Provider dashboard:** patient list, unread counts, dossier access --- *Document version: 1.1* *Last updated: January 5, 2025* --- ## Appendix E: Entry Categories Complete list of entry categories supported by the system. ### Core (Daily Logging) | Category | Description | Example Types | |----------|-------------|---------------| | `medication` | Medications taken or prescribed | Lisinopril, Metoprolol, anti-seizure | | `vital` | Vital signs and measurements | BP, weight, temperature, SpO2 | | `exercise` | Physical activity and therapy sessions | leg_trainer, walking, gym_session | | `symptom` | Symptoms and complaints | headache, seizure, fatigue | | `supplement` | Supplements and vitamins | Vitamin D3, magnesium, iron | | `note` | Free-form notes | daily observations | ### Events | Category | Description | Example Types | Nesting | |----------|-------------|---------------|--------| | `surgery` | Surgical procedures | shunt_placement, shunt_revision, ETV | Parent with child `procedure` entries | | `hospitalization` | Hospital stays | NICU, inpatient, ER | Parent with child entries for daily events | | `consultation` | Doctor visits and consults | video_call, office_visit, second_opinion | Parent with child `finding` or `recommendation` entries | ### Conditions | Category | Description | Example Types | Notes | |----------|-------------|---------------|-------| | `diagnosis` | Medical diagnoses | IVH, hydrocephalus, epilepsy, ROP | Can have status: active, resolved, suspected | | `device` | Implanted or external devices | VP_shunt, Ommaya_reservoir, cochlear_implant | Track settings changes over time as new entries | ### Development | Category | Description | Example Types | Notes | |----------|-------------|---------------|-------| | `therapy` | Therapeutic interventions | Vojta, Bobath, Feldenkrais, ABM, speech_therapy | Include outcome: effective, ineffective, ongoing | | `assessment` | Developmental evaluations | motor, speech, cognitive, vision | Qualitative findings, milestones | ### Foundational | Category | Description | Example Types | Notes | |----------|-------------|---------------|-------| | `birth` | Birth and prenatal history | delivery, Apgar, gestational_age, complications | One-time entries, foundational context | | `history` | Past medical events without full documentation | surgery, illness, injury, allergy | Brief recollections: "appendectomy at age 12" | | `family_history` | Family medical history | mother, father, sibling, maternal_grandmother | Include condition, age at diagnosis, outcome | ### Findings (Interpretations) | Category | Description | Example Types | Notes | |----------|-------------|---------------|-------| | `imaging_finding` | Radiologist or AI interpretation | MRI_finding, CT_finding, XR_finding | Links to DICOM study via data.study_guid | | `eeg_finding` | EEG report findings | epileptiform_activity, sleep_pattern | From EEG monitoring reports | ### Meta | Category | Description | Example Types | Notes | |----------|-------------|---------------|-------| | `provider` | Healthcare providers | neurosurgeon, neurologist, therapist | Institution, contact, relationship period | | `question` | Open medical questions | surgical, diagnostic, treatment | Answer via child entry when resolved | | `upload` | Uploaded files | imaging, genetics, document, lab_report | Existing category | ### Nesting Examples **Complex surgery with sub-procedures:** ``` Parent: category: surgery type: shunt_revision value: "Complex Shunt Revision" timestamp: 2021-12-10 data: { location: "University Clinic Ulm", surgeon: "Dr. Aurelia Peraud", indication: "Isolated 4th ventricle with brainstem compression" } Children (parent_id → parent): category: procedure, type: shunt_replacement, data: {old: "Codman", new: "Miethke Blu"} category: procedure, type: catheter_placement, data: {target: "4th ventricle"} category: procedure, type: ETV, data: {location: "3rd ventricle floor"} category: procedure, type: catheter_placement, data: {from: "3rd ventricle", to: "anterior brain stem"} ``` **Device with settings history:** ``` -- Initial installation -- category: device type: miethke_blu_valve value: "installed" timestamp: 2021-12-10 data: {setting: "20 cmH2O", component: "M. blue plus", surgeon: "Dr. Peraud"} -- Setting adjustment -- category: device type: miethke_blu_valve value: "adjusted" timestamp: 2022-08-15 data: {setting: "30 cmH2O", adjusted_by: "Ulm team"} -- Suspected malfunction -- category: device type: miethke_blu_valve value: "malfunction" timestamp: 2024-10-21 data: {expected_setting: "30 cmH2O", actual_setting: "24 cmH2O", status: "suspected dysfunction"} ``` **Open question with answer:** ``` Parent: category: question type: surgical value: "Is there opportunity for endoscopy to rearrange natural CSF flow?" timestamp: 2025-01-01 data: {status: "unanswered", raised_by: "parent"} Child (when answered): parent_id: [question entry] category: answer type: specialist_opinion value: "Dr. Peraud recommends shunt revision over endoscopy due to..." timestamp: 2025-02-15 data: {source: "video consultation", provider: "Dr. Peraud"} ``` **Consultation with findings:** ``` Parent: category: consultation type: video_call value: "Ulm Neurosurgery Follow-up" timestamp: 2024-10-21 data: { institution: "University Clinic Ulm", provider: "Prof. Dr. Aurelia Peraud", interpreter: "Frau Natalya Kazmina" } Children: category: finding, type: imaging, value: "Ventricular enlargement progression" category: finding, type: device, value: "Suspected valve dysfunction" category: recommendation, type: surgical, value: "Shunt and valve revision recommended" category: recommendation, type: screening, value: "MRSA/MRGN testing required pre-op" ``` **Personal medical history (undocumented past events):** ``` category: history type: surgery value: "Appendectomy" data: {age: 12, approximate_year: 2005, notes: "no complications"} category: history type: illness value: "Chickenpox" data: {age: 6, severity: "normal"} category: history type: injury value: "Broke left arm" data: {year: 2015, treatment: "cast 6 weeks"} category: history type: allergy value: "Penicillin" data: {reaction: "rash", severity: "moderate", discovered: "childhood"} ``` **Family history:** ``` category: family_history type: mother value: "Breast cancer" data: {age_at_diagnosis: 58, outcome: "survived", treatment: "mastectomy + chemo"} category: family_history type: father value: "Type 2 diabetes" data: {age_at_diagnosis: 52, status: "ongoing", management: "metformin"} category: family_history type: maternal_grandmother value: "Alzheimer's disease" data: {age_at_onset: 72, age_at_death: 81} category: family_history type: brother value: "Healthy" data: {age: 35, notes: "no known conditions"} category: family_history type: family_pattern value: "Heart disease" data: {notes: "Multiple paternal relatives with early heart attacks"} ```