17 KiB
Entry Layout Specification
This is the authoritative reference for how entries are structured in inou. All import tools, API endpoints, MCP tools, and portal code MUST conform to this layout. If you change the schema or add a category, UPDATE THIS DOCUMENT.
Design Principles
- Type = level/kind name, never data. Type is always a structural identifier (
study,series,result,variant), never a data value like an rsID or test name. - Summary = structural/navigational only. NO opinions, findings, or diagnostic language. The LLM must read Data to form conclusions. "Brain MRI report, Dr. Smith, May 2022" is OK. "Brain MRI — mild white matter changes" is FORBIDDEN.
- SearchKey = primary machine lookup. Lowercase, packed. Used for exact-match queries (LOINC codes, gene names, rsIDs).
- SearchKey2 = secondary machine lookup. Same rules as SearchKey. For categories with two natural search dimensions.
- Value = measured/observed value. The actual data point (test result, genotype, measurement). Empty for container entries.
- Containers have no Value. Studies, orders, tiers, groups — these organize data, they don't hold measurements.
- Depth 1 = category root, RBAC anchor. One
rootentry per category per dossier. Access grants attach here. - No circular parents. On write, walk ancestors of proposed parent. Reject if the entry is already an ancestor of the target parent.
Removed Fields
- TimestampEnd — pushed to Data where needed (uploads, hospitalizations). Not a schema field.
- Tags — removed. All search needs covered by SearchKey + SearchKey2.
Field Definitions
| Field | Type | Encrypted | Queryable | Purpose |
|---|---|---|---|---|
| EntryID | string | No | Exact | 16-char hex primary key |
| DossierID | string | No | Exact | Whose data |
| ParentID | string | No | Exact | Parent entry (hierarchy) |
| Category | int | No | Exact, range | Category enum (0-27) |
| Type | string | Packed | Exact | Level/kind name — never data |
| Value | string | Packed | — | Measured/observed value or empty |
| Summary | string | Packed | — | Structural display text — no opinions |
| SearchKey | string | Packed | Exact | Primary machine lookup (lowercase) |
| SearchKey2 | string | Packed | Exact | Secondary machine lookup (lowercase) |
| Ordinal | int | No | Exact, range | Sort/sequence number |
| Timestamp | int64 | No | Range | Event date (Unix seconds) |
| Status | int | No | Exact | 0=active, 1=hidden/deleted |
| Data | string | Packed | — | JSON — everything else |
Complete Layout
| Depth | Cat | Type | Value | Summary | SearchKey | SearchKey2 | ParentID | Ordinal | Timestamp | Data |
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0 dossier | dossier |
— | full name / Sophia Jongsma |
email / sophia@example.com |
— | — (EntryID=DossierID) | 0 | created / 1708128000 | profile / {"dob":"2010-05-14","sex":2,"lang":"en"} |
| 1 | any | root |
— | — | — | — | dossier ID / 3b38234f2b0f7ee6 |
0 | created / 1708128000 | — (RBAC grants anchor here) |
| 2 | 1 imaging | study |
— | body+modality+date / Brain MRI (May 2022) |
— | — | cat root / f678901234567801 |
0 | study date / 1652616000 | {"study_uid":"...","body_part":"BRAIN","modality":"MR","institution":"City Medical"} |
| 3 | 1 imaging | series |
— | modality+desc / MR T2 FLAIR SAG BRAIN |
— | — | study / a1b2c3d4e5f67890 |
series# / 3 | study date / 1652616000 | {"series_uid":"...","protocol":"T2_SAG","manufacturer":"Siemens"} |
| 4 | 1 imaging | slice |
— | orient+pos+dims / AX #42 z=12.5mm 512x512 |
— | — | series / b2c3d4e5f6789012 |
slice# / 42 | study date / 1652616000 | {"sop_uid":"...","slice_location":12.5,"wc":40.0,"ww":400.0,"rows":512,"cols":512} |
| 2 | 2 document | subtype / radiology_report |
— | source+date only / MRI report, Dr. Smith, May 2022 |
— | — | cat root or parent entry / a1b2c3d4e5f67890 |
0 | doc date / 1652616000 | {"text":"Full text...","original_filename":"report.pdf"} |
| 2 | 3 lab | order |
— | order name / CBC with Differential |
source / mychart |
— | cat root / f678901234567802 |
0 | collection / 1708128000 | {"provider":"Dr. Smith","lab_name":"City Medical Lab","local_time":"2025-02-15T14:30:00-05:00"} |
| 3 | 3 lab | result |
test value / 14.2 |
name: value unit / Hemoglobin: 14.2 g/dL |
LOINC / 718-7 |
test name / hemoglobin |
order / e5f6789012345678 |
0 | collection / 1708128000 | {"unit":"g/dL","numeric_value":14.2,"si_factor":10.0} |
| 2 | 4 genome | extraction |
— | source+stats / 23andme (850K, 456 matched) |
source / 23andme |
— | cat root / f678901234567803 |
0 | import / 1708128000 | {"total":850000,"matched":5432,"positive":456} |
| 3 | 4 genome | tier |
— | category+count / Traits (100) |
tier name / traits |
— | extraction / c3d4e5f678901234 |
display order / 1 | import / 1708128000 | {"shown":100,"hidden":50} |
| 4 | 4 genome | variant |
genotype / CT |
SNPedia summary / 1.3x increased risk |
gene / mthfr |
rsID / rs1801133 |
tier / d4e5f67890123456 |
100-mag*10 / 75 | import / 1708128000 | {"mag":2.5,"rep":"Bad","sub":"Methylation"} |
| 2 | 5 upload | target / imaging |
filename / brain.dcm |
— | — | — | cat root / f678901234567804 |
0 | upload / 1708128000 | {"path":"/tank/inou/uploads/...","size":1234567,"status":"uploaded","expires":1708732800} |
| 2 | 6 journal | entry |
— | date / Feb 15, 2025 |
— | — | cat root / f678901234567805 |
0 | entry date / 1708128000 | {"mood":4,"energy":3,"sleep_hours":7.5,"notes":"Felt good today"} |
| 2 | 7 consultation | subtype / visit |
— | provider+date / Dr. Smith, Feb 2025 |
— | — | cat root / f678901234567806 |
0 | visit date / 1708128000 | {"provider":"Dr. Smith","specialty":"Cardiology","location":"City Medical"} |
| 2 | 8 diagnosis | subtype / active |
— | condition name / Hypertension |
ICD-10 / i10 |
— | cat root / f678901234567807 |
0 | diagnosed / 1708128000 | {"icd10":"I10","source":"patient_reported","status":"active"} |
| 2 | 9 vital | subtype / weight |
— | vital type label / Weight |
— | — | cat root / f678901234567808 |
0 | created / 1708128000 | {"unit":"kg"} (group container) |
| 3 | 9 vital | reading |
measurement / 75.5 |
value+unit / 75.5 kg |
— | — | group / aabbccdd11223344 |
0 | measured / 1708128000 | {"unit":"kg"} |
| 2 | 10 exercise | subtype / activity |
— | activity label / Running |
— | — | cat root / f678901234567809 |
0 | created / 1708128000 | (group container) |
| 3 | 10 exercise | entry |
measurement / 5.2 |
summary / 5.2 km, 30 min |
— | — | group / aabbccdd11223355 |
0 | activity date / 1708128000 | {"distance_km":5.2,"duration_min":30,"calories":320} |
| 2 | 11 medication | subtype / prescription |
— | med name+dose / Metformin 500mg |
— | — | cat root / f67890123456780a |
0 | started / 1708128000 | {"dosage":"500mg","frequency":"2x daily","prescriber":"Dr. Smith"} |
| 2 | 12 supplement | subtype / vitamin |
— | supplement name / Vitamin D3 2000 IU |
— | — | cat root / f67890123456780b |
0 | started / 1708128000 | {"dosage":"2000 IU","frequency":"daily"} |
| 2 | 13 nutrition | subtype / meal |
— | meal label / Lunch |
— | — | cat root / f67890123456780c |
0 | created / 1708128000 | (group container) |
| 3 | 13 nutrition | entry |
calories / 650 |
summary / Grilled chicken, rice, salad |
— | — | group / aabbccdd11223366 |
0 | meal time / 1708128000 | {"calories":650,"protein_g":45,"carbs_g":60,"fat_g":20} |
| 2 | 14 fertility | subtype / cycle |
— | cycle label / Menstrual Cycle |
— | — | cat root / f67890123456780d |
0 | created / 1708128000 | (group container) |
| 3 | 14 fertility | entry |
— | date / Feb 15, 2025 |
— | — | group / aabbccdd11223377 |
0 | date / 1708128000 | {"day":14,"bbt":36.7,"notes":"..."} |
| 2 | 15 symptom | subtype / chronic |
— | symptom name / Headache |
— | — | cat root / f67890123456780e |
0 | first reported / 1708128000 | {"severity":"mild","frequency":"weekly"} |
| 3 | 15 symptom | entry |
severity / 6 |
date+severity / Feb 15: severity 6/10 |
— | — | group / aabbccdd11223388 |
0 | reported / 1708128000 | {"severity":6,"trigger":"stress","duration_hours":4} |
| 2 | 16 note | subtype / general |
— | note title / Follow-up needed |
— | — | cat root / f67890123456780f |
0 | created / 1708128000 | {"text":"Full note text..."} |
| 2 | 17 history | subtype / medical |
— | condition / Appendectomy, age 12 |
— | — | cat root / f678901234567810 |
0 | event date / 1708128000 | {"age_at_event":12,"source":"patient_reported"} |
| 2 | 18 family_history | subtype / parent |
— | relation+condition / Father: Type 2 Diabetes |
— | — | cat root / f678901234567811 |
0 | reported / 1708128000 | {"relation":"father","condition":"Type 2 Diabetes","age_onset":55} |
| 2 | 19 surgery | subtype / inpatient |
— | procedure+date / Appendectomy, Mar 2020 |
— | — | cat root / f678901234567812 |
0 | surgery date / 1708128000 | {"procedure":"Appendectomy","surgeon":"Dr. Lee","facility":"City Hospital"} |
| 2 | 20 hospital | subtype / admission |
— | reason+facility / Chest pain, City Hospital |
— | — | cat root / f678901234567813 |
0 | admission / 1708128000 | {"reason":"Chest pain","facility":"City Hospital","discharge":1708300000} |
| 2 | 21 birth | subtype / delivery |
— | date+type / May 14 2010, vaginal |
— | — | cat root / f678901234567814 |
0 | birth date / 1708128000 | {"type":"vaginal","weight_g":3200,"apgar_1":8,"apgar_5":9} |
| 2 | 22 device | subtype / implant |
— | device name / Medtronic Micra AV |
— | — | cat root / f678901234567815 |
0 | implanted / 1708128000 | {"manufacturer":"Medtronic","model":"Micra AV","serial":"ABC123"} |
| 2 | 23 therapy | subtype / physical |
— | therapy+provider / Physical therapy, City Rehab |
— | — | cat root / f678901234567816 |
0 | started / 1708128000 | {"provider":"City Rehab","frequency":"2x weekly","goal":"Knee recovery"} |
| 2 | 24 assessment | subtype / screening |
— | assessment name / PHQ-9 Depression Screen |
— | — | cat root / f678901234567817 |
0 | date / 1708128000 | {"instrument":"PHQ-9","score":4} |
| 2 | 25 provider | subtype / physician |
— | name+specialty / Dr. Smith, Cardiology |
— | — | cat root / f678901234567818 |
0 | added / 1708128000 | {"name":"Dr. Smith","specialty":"Cardiology","phone":"+1..."} |
| 2 | 26 question | subtype / inquiry |
— | question / What does my MTHFR result mean? |
— | — | cat root / f678901234567819 |
0 | asked / 1708128000 | {"text":"Full question...","answer":"...","answered_by":"ai"} |
| 2 | 27 tracker | subtype / daily_checkin |
— | tracker name / Daily Check-in |
— | — | cat root / f67890123456781a |
0 | created / 1708128000 | (group container) |
| 3 | 27 tracker | response |
— | date / Feb 15, 2025 |
— | — | tracker / aabbccdd11223399 |
0 | response date / 1708128000 | {"mood":4,"energy":3,"sleep":7.5,"pain":2} |
Hierarchy Patterns
3-level: Imaging, Genome
cat root (depth 1) → study/extraction (depth 2) → series/tier (depth 3) → slice/variant (depth 4)
2-level: Labs
cat root (depth 1) → order (depth 2) → result (depth 3)
Group + entries: Vitals, Exercise, Nutrition, Fertility, Symptoms, Trackers
cat root (depth 1) → group container (depth 2) → readings/entries (depth 3)
Group containers hold metadata (units, labels). Individual readings hold values.
Flat: Everything else
cat root (depth 1) → entry (depth 2)
Cross-Category Linking
Documents can be children of entries from other categories:
- Lab report PDF → ParentID = lab order entry
- Radiology report → ParentID = imaging study entry
This creates cross-category parent/child relationships. Circular reference prevention is mandatory.
Special Rules
Genome Variant Ordinal
Ordinal = 100 - magnitude * 10 — higher magnitude (more significant) sorts first via ORDER BY Ordinal ASC.
Genome Variant Hiding
Variants with magnitude > 4.0 or repute = "Bad" get Status = 1 (hidden). Consumers filter by Status = 0 by default. An include_hidden flag allows showing all.
Devices vs Wearables
Category 22 (device) is for medical devices — pacemakers, insulin pumps, ventilators, O2 concentrators, CPAP machines. Consumer wearables (Apple Watch, Fitbit) are NOT device entries — they are data sources. Wearable data flows into the categories where it belongs: steps → vital/steps, heart rate → vital/heart_rate, blood oxygen → vital/oxygen. The data source is noted in the reading's Data field as {"source":"apple_watch"}.
Independent Analysis Protocol
This is a CORE ARCHITECTURAL PRINCIPLE of inou. It cannot be circumvented.
Why This Exists
The entire purpose of inou is to give LLMs raw health data so they can form independent medical opinions — not parrot existing doctors' conclusions. A user does not need inou to read back their own medical records. They need inou to independently analyze their imaging, labs, genome, and vitals, and potentially catch things that were missed, see cross-category patterns, or offer a different perspective.
If an LLM sees "Diagnosis: Hypertension" before analyzing blood pressure trends, it anchors on that conclusion. Independent analysis becomes impossible. This is not a theoretical concern — anchoring bias is well-documented in both humans and LLMs.
Data Tiers
All entry categories are classified into two tiers:
Tier 1 — Raw Data (always available):
| Cat | Name | Why |
|---|---|---|
| 1 | Imaging | Objective images — LLM looks and interprets |
| 3 | Lab | Objective numbers — LLM analyzes trends and ranges |
| 4 | Genome | Objective variants — LLM assesses risk factors |
| 9 | Vital | Objective measurements — LLM identifies patterns |
| 2 | Document | Source PDFs — LLM reads full context, not pre-digested summaries |
| 6 | Journal | Patient's own words — subjective but first-person |
| 18 | Family history | Factual family medical background |
| 17 | History | Factual past events (surgeries, conditions) |
Tier 2 — Medical Opinions (gated, requires prior raw data review):
| Cat | Name | Why gated |
|---|---|---|
| 7 | Consultation | Contains doctor's observations and conclusions |
| 8 | Diagnosis | Doctor's conclusion — strongest anchoring risk |
| 16 | Note | May contain clinical opinions |
| 24 | Assessment | Screening scores are raw; interpretations are opinions |
Ungated (no bias risk):
All other categories (medication, supplement, exercise, surgery, hospitalization, birth, device, therapy, provider, question, tracker, upload, nutrition, fertility, symptom) — these are factual records of events, treatments, or patient-reported data without diagnostic conclusions.
MCP Enforcement
The MCP server enforces the Independent Analysis Protocol:
-
System prompt tells the LLM upfront:
"You have access to raw health data (imaging, labs, genome, vitals) and medical opinions (diagnoses, assessments, consultation notes). Your role is independent analysis — form your own conclusions from raw data before consulting existing medical opinions. Opinion categories are unlocked after you've reviewed raw data."
-
Session state tracks which categories the LLM has queried (
queriedCategoriesset). -
Gating — when the LLM queries a Tier 2 category before reviewing raw data, the MCP tool returns:
"Opinion data requires prior review of raw data. Query at least one of: imaging, labs, vitals, or genome first."
-
After unlock — once the LLM has queried raw data, Tier 2 is available. The LLM can compare its independent analysis against existing medical opinions.
Rules for Contributors
- NEVER bypass the gating mechanism. It is equivalent to RBAC — a hard access control, not a suggestion.
- NEVER include diagnostic conclusions in Summary fields. Summary is structural/navigational only.
- NEVER pre-digest medical opinions into structured fields that the LLM sees by default. If a doctor's conclusion exists, it lives in a Tier 2 category or inside a document's full text.
- ALWAYS present raw data in a way that supports independent analysis: numbers, images, variants — not interpretations.
- When adding new categories, classify them as Tier 1 or Tier 2 and update this document.
Schema Changes Checklist
When modifying this layout:
- Update this document FIRST
- Update
lib/types.go(CategoryTypes, Entry struct) - Update import tools (import-dicom, import-genome, import-lab)
- Update
lib/dbcore.go(Filter struct, entryQuery) - Run migration on staging AND production
- Update MCP tools if query patterns changed
- Update portal display code