Clinical Data — Conditions, Allergies & Immunizations
Audiences: doctor, nurse, clinical-buyer, developer
Structured recording of diagnoses (FHIR
Condition), allergies (FHIRAllergyIntolerance), and diagnostic rule flows (PrismaDiagnosticFlow) forms the evidence base for AI-assisted diagnosis and clinical decision support.
Business Purpose
A clinician's ability to make accurate, rapid decisions depends on having a complete, structured patient medical history. Three key record types support this:
- Conditions — active and resolved diagnoses coded in SNOMED CT or ICD-10, stored as FHIR
Conditionresources. Enable medication contraindication checks, population health queries, and FHIR-based data exchange with external providers. - Allergies — documented sensitivities stored as FHIR
AllergyIntolerance. Critical for prescription safety (drug allergy checking). - Diagnostic rule flows — directed-graph rule definitions (
DiagnosticFlowPrisma model) authored by medical staff and attached toDiseaseCardentities. Used by the diagnosis engine to evaluate symptom evidence and recommend diagnoses.
Together, these three subsystems form the clinical knowledge layer that drives the TUCAN AI assistant's clinical tools and the diagnosis engine's rule evaluation.
Audiences
- Investor: Structured, coded diagnoses and allergy data differentiate Dudoxx from EMR systems that store free text. SNOMED/ICD-10 coding enables insurance claims automation and population analytics.
- Clinical buyer (doctor/nurse/receptionist): Doctors record diagnoses per visit; nurses document allergies at intake. The diagnostic rule flows are authored by senior clinicians and drive the AI's suggestion engine.
- Developer/partner: Conditions:
GET|POST|PATCH|DELETE /api/v1/conditions. Allergies: similar REST pattern. Diagnostic flows:GET|PUT /api/v1/diagnostic-flows/:diseaseCardId. All require valid X-Clinic-ID. - Internal (ops/support): Conditions and allergies live in HAPI FHIR; diagnostic flows and patient diagnoses live in Prisma
ddx_api_main. Hybrid troubleshooting required.
Architecture
Three subsystems with different storage patterns:
1. Conditions (clinical-data/conditions/)
Pure FHIR store — ConditionsController → ConditionsService → IFhirClient → HAPI FHIR Condition.
ConditionsController
└── ConditionsService
├── PatientIdResolverService — UUID → FHIR Patient ID
└── IFhirClient — FHIR Condition CRUD + search
2. Allergies (clinical-data/allergies/)
Same pattern as Conditions, targeting FHIR AllergyIntolerance resources.
AllergiesController
└── AllergiesService
├── PatientIdResolverService
└── IFhirClient — FHIR AllergyIntolerance CRUD
3. Diagnostic Rule Flows (diagnosis-engine/diagnostic-flows/)
Prisma-only store. DiagnosticFlow records are JSON graph structures (flowGraph JSON column) keyed by diseaseCardId. Validated by FlowValidatorService before save.
DiagnosticFlowsController
└── DiagnosticFlowsService
├── PrismaService — DiagnosticFlow CRUD (ddx_api_main)
└── FlowValidatorService — graph structure validation
4. Patient Diagnoses (diagnosis-engine/patient-diagnoses/)
Prisma table PatientDiagnosis — records the outcome of a diagnostic evaluation for a specific patient. Links to DiseaseCard and diagnosing practitioner.
See coding_context/ddx-hms-context.md §Clinical Data for the full module hierarchy.
Tech Stack & Choices
| Layer | Technology | Notes |
|---|---|---|
| Conditions / Allergies storage | HAPI FHIR R4 (Condition, AllergyIntolerance) | No Prisma mirror — interoperability-first |
| FHIR client | FHIR_CLIENT DI token (FhirClientService) | Canonical client; @Inject(FHIR_CLIENT) pattern |
| Diagnostic flows | Prisma DiagnosticFlow (ddx_api_main) | JSON graph column; one row per DiseaseCard |
| Patient diagnoses | Prisma PatientDiagnosis | Rich relational model: links to DiseaseCard, User (diagnosedBy), confidence, status |
| Auth | @RequireRole() per endpoint | Conditions: DOCTOR/NURSE/CLINIC_ADMIN/ORG_ADMIN/SUPER_ADMIN/STAFF/PATIENT for read; DOCTOR+ for write |
| Coding | SNOMED CT / ICD-10 for conditions; FHIR allergy category/criticality enums for allergies | DTO enforces code + display fields |
Key design decision: Conditions and allergies are FHIR-only, making them portable to any FHIR R4 consumer. Diagnostic flows are Prisma-only because they are internal rule authoring artifacts — not clinical records intended for external sharing.
Data Flow
Doctor records a new diagnosis
Business outcome: Doctor records "Type 2 Diabetes Mellitus" (SNOMED 73211009) during a visit; it appears in the patient's active conditions list and feeds the AI diagnosis engine.
Technical mechanism:
POST /api/v1/conditionswith{ patientId, code: "73211009", display: "Type 2 diabetes mellitus", clinicalStatus: "active", onsetDate: "2026-05-18" }.ConditionsController.create()(conditions.controller.ts:80) validates role (DOCTOR minimum).ConditionsService.create()(conditions.service.ts:29) resolves FHIR Patient ID, confirms patient exists viafhirClient.read<FhirConditionResource>('Patient', fhirPatientId, organizationId).- Builds FHIR
Conditionresource withcode.coding[0] = { system: "http://snomed.info/sct", code: "73211009", display: "Type 2 diabetes mellitus" },subject.reference = "Patient/{fhirId}",clinicalStatus.coding[0].code = "active". fhirClient.create<FhirConditionResource>('Condition', resource, organizationId)posts to HAPI FHIR.- Returns
ConditionResponseDto.
Clinician queries patient conditions
GET /api/v1/conditions?patientId=xxx → ConditionsService.findByPatient() → FHIR search { patient: fhirPatientId } → returns mapped ConditionResponseDto[].
Authoring a diagnostic rule flow
PUT /api/v1/diagnostic-flows/:diseaseCardId → DiagnosticFlowsService.saveFlow():
- Verifies
DiseaseCardexists in Prisma. FlowValidatorService.validate(dto.flowGraph)checks graph structure (nodes, edges, required fields) (flow-validator.service.ts).- If invalid: throws
UnprocessableEntityExceptionwith error list. prisma.diagnosticFlow.upsert(...)saves the validated JSON graph.
Patient diagnosis creation (from AI or manual)
POST /api/v1/patients/:patientId/diagnoses → PatientDiagnosesService.create() (patient-diagnoses.service.ts:52):
- Creates
PatientDiagnosisPrisma row with{ patientId, diseaseCardId, diagnosedById, confidence, status }. - Includes
DiseaseCardanddiagnosedByin the response viainclude.
Implicated Code
ddx-api/src/clinical-data/conditions/conditions.controller.ts:36—@ResourceMeta— declarescode,display,clinicalStatus,onsetDateas filterable fieldsddx-api/src/clinical-data/conditions/conditions.controller.ts:63—GET /conditions— requirespatientIdquery param (400 without it)ddx-api/src/clinical-data/conditions/conditions.service.ts:21—ConditionsService—@Inject(FHIR_CLIENT)+PatientIdResolverServiceddx-api/src/clinical-data/conditions/conditions.service.ts:29—create()— validates patient exists in FHIR before writing Conditionddx-api/src/clinical-data/conditions/conditions.service.ts:49—findByPatient()— FHIR search by patient referenceddx-api/src/diagnosis-engine/diagnostic-flows/services/diagnostic-flows.service.ts:13—DiagnosticFlowsService— Prisma-based flow CRUDddx-api/src/diagnosis-engine/diagnostic-flows/services/diagnostic-flows.service.ts:42—saveFlow()— validates graph, upsertsDiagnosticFlowPrisma rowddx-api/src/diagnosis-engine/diagnostic-flows/services/flow-validator.service.ts:1—FlowValidatorService— graph structure validation before persistenceddx-api/src/diagnosis-engine/patient-diagnoses/services/patient-diagnoses.service.ts:10—PatientDiagnosesService— Prisma-based patient diagnosis recordsddx-api/src/diagnosis-engine/patient-diagnoses/services/patient-diagnoses.service.ts:52—create()— writesPatientDiagnosisrow with disease card link
Operational Notes
- FHIR patient required: Both
ConditionsServiceandAllergiesServicerequire the patient to have a FHIR Patient record. Missing record →NotFoundException. Ensure FHIR Patient exists via seeder orPatientsService.ensureFhirPatient(). - No Prisma mirror for conditions/allergies: Troubleshoot via HAPI FHIR directly —
GET {HAPI_BASE}/fhir/Condition?patient=Patient/{id}— not via Prisma Studio. - Diagnostic flow validation: A
flowGraphthat failsFlowValidatorService.validate()returns HTTP 422 with a detailed error list. Check theerrorsarray in the response body to find malformed nodes/edges. - Patient diagnoses vs FHIR conditions: These are different models.
PatientDiagnosis(Prisma) records the outcome of a diagnostic evaluation (with confidence score, status, linkedDiseaseCard). FHIRConditionrecords the clinical fact (ICD/SNOMED coded, interoperable). Both may exist for the same clinical event. - Allergy criticality is safety-critical: Ensure
criticalityfield is set correctly (low,high,unable-to-assess) when creating allergies — the prescription drug-interaction service reads this field.
Related Topics
- Clinical Visits — Conditions recorded during visit context
- Clinical Data — Vitals — Abnormal vitals may prompt condition recording
- Diagnosis Engine — Evaluates diagnostic rule flows against patient data
- Drugs Management — Allergy records feed drug-interaction checking
- Medical Cards — Aggregates active conditions for patient summary