04-clinicalwave: W2filled13 citations

Clinical Data — Conditions, Allergies & Immunizations

Audiences: doctor, nurse, clinical-buyer, developer

Clinical Data — Conditions, Allergies & Immunizations

Structured recording of diagnoses (FHIR Condition), allergies (FHIR AllergyIntolerance), and diagnostic rule flows (Prisma DiagnosticFlow) 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:

  1. Conditions — active and resolved diagnoses coded in SNOMED CT or ICD-10, stored as FHIR Condition resources. Enable medication contraindication checks, population health queries, and FHIR-based data exchange with external providers.
  2. Allergies — documented sensitivities stored as FHIR AllergyIntolerance. Critical for prescription safety (drug allergy checking).
  3. Diagnostic rule flows — directed-graph rule definitions (DiagnosticFlow Prisma model) authored by medical staff and attached to DiseaseCard entities. 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 — ConditionsControllerConditionsServiceIFhirClient → HAPI FHIR Condition.

ControllerServiceCollaboratorResponsibility
ConditionsControllerConditionsServicePatientIdResolverServiceUUID → FHIR Patient ID
IFhirClientFHIR Condition CRUD + search

2. Allergies (clinical-data/allergies/)

Same pattern as Conditions, targeting FHIR AllergyIntolerance resources.

ControllerServiceCollaboratorResponsibility
AllergiesControllerAllergiesServicePatientIdResolverService
IFhirClientFHIR 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.

ControllerServiceCollaboratorResponsibility
DiagnosticFlowsControllerDiagnosticFlowsServicePrismaServiceDiagnosticFlow CRUD (ddx_api_main)
FlowValidatorServicegraph 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

LayerTechnologyNotes
Conditions / Allergies storageHAPI FHIR R4 (Condition, AllergyIntolerance)No Prisma mirror — interoperability-first
FHIR clientFHIR_CLIENT DI token (FhirClientService)Canonical client; @Inject(FHIR_CLIENT) pattern
Diagnostic flowsPrisma DiagnosticFlow (ddx_api_main)JSON graph column; one row per DiseaseCard
Patient diagnosesPrisma PatientDiagnosisRich relational model: links to DiseaseCard, User (diagnosedBy), confidence, status
Auth@RequireRole() per endpointConditions: DOCTOR/NURSE/CLINIC_ADMIN/ORG_ADMIN/SUPER_ADMIN/STAFF/PATIENT for read; DOCTOR+ for write
CodingSNOMED CT / ICD-10 for conditions; FHIR allergy category/criticality enums for allergiesDTO 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:

  1. POST /api/v1/conditions with { patientId, code: "73211009", display: "Type 2 diabetes mellitus", clinicalStatus: "active", onsetDate: "2026-05-18" }.
  2. ConditionsController.create() (conditions.controller.ts:80) validates role (DOCTOR minimum).
  3. ConditionsService.create() (conditions.service.ts:29) resolves FHIR Patient ID, confirms patient exists via fhirClient.read<FhirConditionResource>('Patient', fhirPatientId, organizationId).
  4. Builds FHIR Condition resource with code.coding[0] = { system: "http://snomed.info/sct", code: "73211009", display: "Type 2 diabetes mellitus" }, subject.reference = "Patient/{fhirId}", clinicalStatus.coding[0].code = "active".
  5. fhirClient.create<FhirConditionResource>('Condition', resource, organizationId) posts to HAPI FHIR.
  6. Returns ConditionResponseDto.

Clinician queries patient conditions

GET /api/v1/conditions?patientId=xxxConditionsService.findByPatient() → FHIR search { patient: fhirPatientId } → returns mapped ConditionResponseDto[].

Authoring a diagnostic rule flow

PUT /api/v1/diagnostic-flows/:diseaseCardIdDiagnosticFlowsService.saveFlow():

  1. Verifies DiseaseCard exists in Prisma.
  2. FlowValidatorService.validate(dto.flowGraph) checks graph structure (nodes, edges, required fields) (flow-validator.service.ts).
  3. If invalid: throws UnprocessableEntityException with error list.
  4. prisma.diagnosticFlow.upsert(...) saves the validated JSON graph.

Patient diagnosis creation (from AI or manual)

POST /api/v1/patients/:patientId/diagnosesPatientDiagnosesService.create() (patient-diagnoses.service.ts:52):

  1. Creates PatientDiagnosis Prisma row with { patientId, diseaseCardId, diagnosedById, confidence, status }.
  2. Includes DiseaseCard and diagnosedBy in the response via include.

Implicated Code

  • ddx-api/src/clinical-data/conditions/conditions.controller.ts:36@ResourceMeta — declares code, display, clinicalStatus, onsetDate as filterable fields
  • ddx-api/src/clinical-data/conditions/conditions.controller.ts:63GET /conditions — requires patientId query param (400 without it)
  • ddx-api/src/clinical-data/conditions/conditions.service.ts:21ConditionsService@Inject(FHIR_CLIENT) + PatientIdResolverService
  • ddx-api/src/clinical-data/conditions/conditions.service.ts:29create() — validates patient exists in FHIR before writing Condition
  • ddx-api/src/clinical-data/conditions/conditions.service.ts:49findByPatient() — FHIR search by patient reference
  • ddx-api/src/diagnosis-engine/diagnostic-flows/services/diagnostic-flows.service.ts:13DiagnosticFlowsService — Prisma-based flow CRUD
  • ddx-api/src/diagnosis-engine/diagnostic-flows/services/diagnostic-flows.service.ts:42saveFlow() — validates graph, upserts DiagnosticFlow Prisma row
  • ddx-api/src/diagnosis-engine/diagnostic-flows/services/flow-validator.service.ts:1FlowValidatorService — graph structure validation before persistence
  • ddx-api/src/diagnosis-engine/patient-diagnoses/services/patient-diagnoses.service.ts:10PatientDiagnosesService — Prisma-based patient diagnosis records
  • ddx-api/src/diagnosis-engine/patient-diagnoses/services/patient-diagnoses.service.ts:52create() — writes PatientDiagnosis row with disease card link

Operational Notes

  • FHIR patient required: Both ConditionsService and AllergiesService require the patient to have a FHIR Patient record. Missing record → NotFoundException. Ensure FHIR Patient exists via seeder or PatientsService.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 flowGraph that fails FlowValidatorService.validate() returns HTTP 422 with a detailed error list. Check the errors array 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, linked DiseaseCard). FHIR Condition records the clinical fact (ICD/SNOMED coded, interoperable). Both may exist for the same clinical event.
  • Allergy criticality is safety-critical: Ensure criticality field is set correctly (low, high, unable-to-assess) when creating allergies — the prescription drug-interaction service reads this field.
    Clinical Data — Conditions, Allergies & Immunizations — Dudoxx Docs | Dudoxx