Drugs Management — Medication Catalog and Interaction Checking
Audiences: doctor, nurse, developer, internal
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:
- Medication Catalog — a system-wide library of
MedicationFHIR 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. - Drug-drug interaction checking —
PrescriptionInteractionServiceembeds a curated major-interaction database (warfarin/aspirin, aspirin/ibuprofen, methotrexate, etc.) that generates warnings at prescribing time. - Drug-allergy checking — cross-references the patient's
AllergyIntoleranceFHIR records against the medication being prescribed. - 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 withname/codequery 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 inprescription-interaction.service.ts— updates require code deployment. Seeding from JSON:MedicationsServicereads fromfs(disk-mounted drug data files).
Architecture
MedicationCatalogController (/api/v1/medication-catalog)
└── MedicationsService
├── IFhirClient (rawFhir) — Medication + MedicationKnowledge FHIR resources
├── PrismaService — audit rows, organization resolution
├── AuditService — CREATE/UPDATE/DELETE audit logs
└── OrganizationResolverService — slug → org entity
PrescriptionsService (at prescription write time)
└── PrescriptionInteractionService
├── FHIR_CLIENT — reads AllergyIntolerance for patient
├── AllergiesService — re-uses allergy lookup
└── MAJOR_INTERACTIONS map — embedded 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
| Layer | Technology | Notes |
|---|---|---|
| Catalog storage | HAPI FHIR R4 Medication (shared partition) | Tenant-agnostic — same catalog across all clinics |
| FHIR client | FHIR_CLIENT DI token, cast to RawFhirClient | Required for non-standard FHIR resource types |
| Drug-drug interactions | Hardcoded MAJOR_INTERACTIONS map (JS object) | Curated subset of major interactions; not a full formulary DB |
| Drug-allergy checking | FHIR AllergyIntolerance + AllergiesService | Reads patient's existing allergy records at prescribe time |
| Favorites | DrugFavoritesService (Prisma) | Per-doctor saved medication sets |
| Catalog seeding | fs.readFileSync on JSON files | Bulk create from structured drug datasets |
| Auth | DOCUMENT_VIEW_ROLES pattern; RequireSuperAdmin for admin operations | Catalog reads open to all clinical roles; writes restricted |
| Audit | AuditService.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:
GET /api/v1/medication-catalog?name=amox&language=dehitsMedicationCatalogController.MedicationCatalogController(medication-catalog.controller.ts:68) delegates toMedicationsService.MedicationsService.search()callsrawFhir.search('Medication', { name: 'amox', _language: 'de' }, slug)against HAPI FHIR shared partition.- 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:
PrescriptionsService.create()triggersPrescriptionInteractionService.checkInteractions(patientId, newMedicationName, organizationId).PrescriptionInteractionServicefetches patient's activeAllergyIntoleranceviaAllergiesService.- Normalizes
newMedicationNameto lowercase, looks up inMAJOR_INTERACTIONSmap (prescription-interaction.service.ts:19). - Cross-references all current active
MedicationRequestresources for the patient (FHIR search). - Returns
DrugInteractionsResultDtowith{ hasInteractions: boolean, warnings: DrugInteractionWarningDto[] }. - 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—@ResourceMetafor catalog — filterable fields:code,name,status,form,manufacturerddx-api/src/clinical-data/medications/medication-catalog.controller.ts:68—MedicationCatalogControllerclass — system-wide catalog, does NOT require explicit X-Clinic-ID for readsddx-api/src/clinical-data/medications/medications.service.ts:7—FhirMedicationResourceinterface — FHIR Medication resource shapeddx-api/src/clinical-data/medications/medications.service.ts:29—RawFhirClientinterface — escape hatch for non-standard FHIR typesddx-api/src/clinical-data/medications/medications.service.ts:69—MedicationsService— injectsFHIR_CLIENT,PrismaService,AuditService,OrganizationResolverServiceddx-api/src/clinical-data/prescriptions/prescription-interaction.service.ts:1—PrescriptionInteractionService— drug-drug + drug-allergy checkingddx-api/src/clinical-data/prescriptions/prescription-interaction.service.ts:19—MAJOR_INTERACTIONSmap — hardcoded curated interaction database (warfarin, aspirin, methotrexate, etc.)ddx-api/src/clinical-data/prescriptions/drug-favorites.service.ts:1—DrugFavoritesService— per-doctor saved medication sets (Prisma)
Operational Notes
- Interaction DB is hardcoded:
MAJOR_INTERACTIONSinprescription-interaction.service.tsis 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:
MedicationandMedicationKnowledgeuse theRawFhirClientcast. 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
_codefield. 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.readFileSyncinMedicationsService. In Docker deployments, ensure the volume is mounted before running the seed endpoint.
Related Topics
- Clinical Data — Prescriptions — Uses the catalog + interaction checker at prescribe time
- Clinical Data — Conditions — Allergy records feed the drug-allergy check
- Clinical Visits — Prescriptions and medications attach to visit context
- Medical Cards — Aggregates active medications for patient summary