04-clinicalwave: W2filled11 citations

Drugs Management — Medication Catalog and Interaction Checking

Audiences: doctor, nurse, developer, internal

Drugs Management — Medication Catalog and Interaction Checking

A FHIR-backed medication catalog and an embedded drug-interaction / drug-allergy checker provide the pharmacological knowledge layer that makes Dudoxx prescriptions clinically safe.

Business Purpose

Safe prescribing requires two things: a searchable, coded drug catalog and automatic detection of dangerous combinations. Without these, doctors either consult paper formularies (slow, error-prone) or rely on memory for interaction warnings (risky).

Dudoxx HMS provides:

  1. Medication Catalog — a system-wide library of Medication FHIR resources (ATC, RxNorm, or SNOMED coded) stored in HAPI FHIR's shared clinic partition. Supports multilingual display names (en/de/fr) via FHIR Translation extensions.
  2. Drug-drug interaction checkingPrescriptionInteractionService embeds a curated major-interaction database (warfarin/aspirin, aspirin/ibuprofen, methotrexate, etc.) that generates warnings at prescribing time.
  3. Drug-allergy checking — cross-references the patient's AllergyIntolerance FHIR records against the medication being prescribed.
  4. Prescriber drug favorites — per-doctor saved medication sets for fast repeated prescribing.

The catalog is shared across all tenants (not per-clinic), sourced from the HAPI FHIR shared partition. Seeding from structured drug datasets (JSON files on disk) is supported via the medications service bulk-create path.

Audiences

  • Investor: Drug interaction checking and FHIR-coded medications are a clinical safety differentiator. They also enable future payer integrations that require coded prescriptions (e.g., German eRezept).
  • Clinical buyer (doctor/nurse/receptionist): Doctors search the catalog by name/code while writing prescriptions. The system auto-warns on dangerous combinations. Favorites allow one-click reuse of common prescriptions.
  • Developer/partner: GET /api/v1/medication-catalog (search with name/code query params), POST /api/v1/medication-catalog (admin create). Interaction check: embedded in prescriptions service — not a standalone endpoint. Requires X-Clinic-ID for tenant-aware FHIR calls.
  • Internal (ops/support): Catalog lives in HAPI FHIR shared partition. Search is FHIR-proxied via MedicationsService.rawFhir. Interaction database is hardcoded in prescription-interaction.service.ts — updates require code deployment. Seeding from JSON: MedicationsService reads from fs (disk-mounted drug data files).

Architecture

Entry pointServiceCollaboratorResponsibility
MedicationCatalogController (/api/v1/medication-catalog)MedicationsServiceIFhirClient (rawFhir)Medication + MedicationKnowledge FHIR resources
PrismaServiceaudit rows, organization resolution
AuditServiceCREATE/UPDATE/DELETE audit logs
OrganizationResolverServiceslug → org entity
PrescriptionsService (at prescription write time)PrescriptionInteractionServiceFHIR_CLIENTreads AllergyIntolerance for patient
AllergiesServicere-uses allergy lookup
MAJOR_INTERACTIONS mapembedded drug-drug interaction DB

Note on FHIR resource types: HAPI FHIR R4 Medication and MedicationKnowledge are non-standard types not included in the canonical FhirResourceType union in the project. MedicationsService casts the FHIR client to a RawFhirClient interface that accepts raw resource type strings (medications.service.ts:29). This is an intentional escape hatch noted in the code.

Medication catalog entries use FHIR Medication resource shape: code.coding (ATC/RxNorm/SNOMED), form.coding (tablet/capsule/etc.), ingredient[], manufacturer, batch. Multilingual names use FHIR _code Translation extensions.

Tech Stack & Choices

LayerTechnologyNotes
Catalog storageHAPI FHIR R4 Medication (shared partition)Tenant-agnostic — same catalog across all clinics
FHIR clientFHIR_CLIENT DI token, cast to RawFhirClientRequired for non-standard FHIR resource types
Drug-drug interactionsHardcoded MAJOR_INTERACTIONS map (JS object)Curated subset of major interactions; not a full formulary DB
Drug-allergy checkingFHIR AllergyIntolerance + AllergiesServiceReads patient's existing allergy records at prescribe time
FavoritesDrugFavoritesService (Prisma)Per-doctor saved medication sets
Catalog seedingfs.readFileSync on JSON filesBulk create from structured drug datasets
AuthDOCUMENT_VIEW_ROLES pattern; RequireSuperAdmin for admin operationsCatalog reads open to all clinical roles; writes restricted
AuditAuditService.log()All catalog mutations logged

Data Flow

Doctor searches medication catalog

Business outcome: Doctor types "amox" in the prescription UI; matching medications appear instantly with ATC codes and dosage forms.

Technical mechanism:

  1. GET /api/v1/medication-catalog?name=amox&language=de hits MedicationCatalogController.
  2. MedicationCatalogController (medication-catalog.controller.ts:68) delegates to MedicationsService.
  3. MedicationsService.search() calls rawFhir.search('Medication', { name: 'amox', _language: 'de' }, slug) against HAPI FHIR shared partition.
  4. FHIR response is mapped to MedicationResponseDto[] (flat shape: id, code, name, form, manufacturer, status).

Interaction check at prescribe time

Business outcome: Doctor prescribes warfarin to a patient already on aspirin — the system generates a "Major Interaction: increased bleeding risk" warning before the prescription is saved.

Technical mechanism:

  1. PrescriptionsService.create() triggers PrescriptionInteractionService.checkInteractions(patientId, newMedicationName, organizationId).
  2. PrescriptionInteractionService fetches patient's active AllergyIntolerance via AllergiesService.
  3. Normalizes newMedicationName to lowercase, looks up in MAJOR_INTERACTIONS map (prescription-interaction.service.ts:19).
  4. Cross-references all current active MedicationRequest resources for the patient (FHIR search).
  5. Returns DrugInteractionsResultDto with { hasInteractions: boolean, warnings: DrugInteractionWarningDto[] }.
  6. If interactions exist, response includes structured warnings (description + recommendation) — prescribing is NOT blocked (warnings are advisory).

Seeding the drug catalog

POST /api/v1/medication-catalog/seed (SUPER_ADMIN only) → MedicationsService reads structured JSON files from disk (fs.readFileSync), batch-creates FHIR Medication resources in the shared partition.

Implicated Code

  • ddx-api/src/clinical-data/medications/medication-catalog.controller.ts:53@ResourceMeta for catalog — filterable fields: code, name, status, form, manufacturer
  • ddx-api/src/clinical-data/medications/medication-catalog.controller.ts:68MedicationCatalogController class — system-wide catalog, does NOT require explicit X-Clinic-ID for reads
  • ddx-api/src/clinical-data/medications/medications.service.ts:7FhirMedicationResource interface — FHIR Medication resource shape
  • ddx-api/src/clinical-data/medications/medications.service.ts:29RawFhirClient interface — escape hatch for non-standard FHIR types
  • ddx-api/src/clinical-data/medications/medications.service.ts:69MedicationsService — injects FHIR_CLIENT, PrismaService, AuditService, OrganizationResolverService
  • ddx-api/src/clinical-data/prescriptions/prescription-interaction.service.ts:1PrescriptionInteractionService — drug-drug + drug-allergy checking
  • ddx-api/src/clinical-data/prescriptions/prescription-interaction.service.ts:19MAJOR_INTERACTIONS map — hardcoded curated interaction database (warfarin, aspirin, methotrexate, etc.)
  • ddx-api/src/clinical-data/prescriptions/drug-favorites.service.ts:1DrugFavoritesService — per-doctor saved medication sets (Prisma)

Operational Notes

  • Interaction DB is hardcoded: MAJOR_INTERACTIONS in prescription-interaction.service.ts is not database-driven. Adding a new interaction requires a code change and deployment. This is a known limitation — a future task would load interactions from a structured formulary (OpenFDA, SNOMEDCT, etc.).
  • Catalog is shared-partition FHIR: All clinics see the same medication catalog. Per-clinic formulary restrictions are not yet implemented.
  • Non-standard FHIR types: Medication and MedicationKnowledge use the RawFhirClient cast. If HAPI FHIR is updated, verify these resource types still resolve correctly.
  • Multilingual support: Drug names in de/fr require FHIR Translation extensions on the _code field. If translations are missing, the response falls back to the default coding display.
  • Seeding JSON format: Drug seeding files must be mounted at the path expected by fs.readFileSync in MedicationsService. In Docker deployments, ensure the volume is mounted before running the seed endpoint.