Full DFD (Level 0 → Level 3), database schema, and tech-stack breakdown for a functional AMR surveillance prototype targeting high-burden districts.
Level 0 shows the NIAMR system as a single process bubble, its external entities, and the high-level data flows between them. No internal detail is shown at this level.
Flutter mobile app (online) or USSD/SMS (offline/low-resource). Data is received by the PHP REST API.FHIR R4 compliant API layer built in PHP. NIAMR pushes standardized AMR bundles and pulls aggregate health metrics for context modeling.Python microservice receives preprocessed data from the ETL pipeline via internal API. Runs predictive models (scikit-learn, TensorFlow) and returns predictions stored in MySQL.HL7 FHIR bundles (MeasureReport, DiagnosticReport) mapped with LOINC and SNOMED CT codes for international compliance.Level 1 explodes the single NIAMR bubble into 6 major functional processes. Data stores and inter-process flows become visible.
PHP validation middleware. Queues records in Redis.DS2: Clean Data.FHIR R4 resources: DiagnosticReport, MedicationRequest. Applies LOINC (lab codes), SNOMED CT (organisms), ICD-11 (diagnoses). Syncs with DHIS2.DS4./api/resistance-trends, /api/geo-clusters, /api/prescriber-report. Role-based access (DHO, Clinician, Admin).Level 2 decomposes the two most complex processes: the ETL pipeline (P2) and the ML Analytics Engine (P4). Each sub-process maps to a specific module in the Python codebase.
Level 3 shows granular internal logic for data ingestion (P1) and the FHIR interoperability layer (P3), including specific API endpoints, transformation rules, and terminology mappings.
18769-0 (Microbial susceptibility), 664-3 (Culture), 29576-6 (Antimicrobial MIC). Lookup table stored in MySQL with versioning.59560006 (MRSA), 372687004 (E. coli), 88274000 (Klebsiella). Resistance mechanisms via SNOMED procedure codes.XN109 (MRSA infection), 1C3Y (resistant bacterial infection). Used in FHIR Condition resources linked to each encounter.DiagnosticReport, Observation (MIC values), MedicationRequest, Patient, Encounter, Organization (facility), MeasureReport (aggregates).All tables use UUID primary keys. Timestamps are stored as TIMESTAMPTZ. FHIR resources are also stored as JSONB for full-fidelity retrieval. Redis handles ephemeral queues and ML result caching.
| Column | Type | Notes |
|---|---|---|
| PKid | UUID | Primary key |
| mfl_code | VARCHAR(20) | Master Facility List code |
| name | VARCHAR(255) | Facility name |
| facility_type | ENUM | HC2/HC3/HC4/Hospital |
| district_id | UUID FK | → districts |
| latitude | DECIMAL(9,6) | GPS coordinate |
| longitude | DECIMAL(9,6) | GPS coordinate |
| dhis2_org_unit | VARCHAR(100) | DHIS2 UID for sync |
| fhir_organization_id | VARCHAR(100) | FHIR Organization.id |
| created_at | TIMESTAMPTZ | Auto-set |
| Column | Type | Notes |
|---|---|---|
| PKid | UUID | Primary key |
| patient_code | VARCHAR(50) | De-identified code |
| age_group | ENUM | 0-5,6-14,15-49,50+ |
| sex | ENUM | M/F/Unknown |
| district_id | UUID FK | → districts |
| facility_id | UUID FK | → facilities |
| fhir_patient_id | VARCHAR(100) | FHIR Patient.id |
| created_at | TIMESTAMPTZ | Auto-set |
| Column | Type | Notes |
|---|---|---|
| PKid | UUID | Primary key |
| name | VARCHAR(100) | District name |
| region | VARCHAR(100) | Region of Uganda |
| population | INTEGER | Latest census |
| risk_level | ENUM | green/yellow/red |
| geom | GEOMETRY | PostGIS polygon |
| Column | Type | Notes |
|---|---|---|
| PKid | UUID | Primary key |
| VARCHAR(255) | Unique | |
| phone | VARCHAR(20) | For SMS alerts |
| role | ENUM | admin/dho/clinician/lab |
| facility_id | UUID FK | → facilities |
| password_hash | VARCHAR(255) | bcrypt |
| last_login | TIMESTAMPTZ |
| Column | Type | Notes |
|---|---|---|
| PKid | UUID | Primary key |
| patient_id | UUID FK | → patients |
| facility_id | UUID FK | → facilities |
| specimen_type | VARCHAR(100) | Blood/Urine/Sputum… |
| loinc_code | VARCHAR(20) | LOINC specimen code |
| collection_date | DATE | |
| diagnosis_icd11 | VARCHAR(20) | ICD-11 code |
| fhir_specimen_id | VARCHAR(100) | FHIR Specimen.id |
| source | ENUM | live/atlas/glass/upload |
| Column | Type | Notes |
|---|---|---|
| PKid | UUID | Primary key |
| specimen_id | UUID FK | → lab_specimens |
| organism_name | VARCHAR(200) | e.g. E. coli |
| snomed_organism | VARCHAR(20) | SNOMED CT code |
| report_date | DATE | |
| fhir_diagnostic_id | VARCHAR(100) | FHIR DiagnosticReport |
| data_quality_score | DECIMAL(4,2) | 0-1 completeness score |
| Column | Type | Notes |
|---|---|---|
| PKid | UUID | Primary key |
| result_id | UUID FK | → microbiology_results |
| antibiotic_id | UUID FK | → antibiotics |
| mic_value | DECIMAL(8,3) | Minimum inhibitory conc. |
| interpretation | ENUM | S/I/R (EUCAST) |
| test_method | ENUM | disk/MIC/VITEK |
| loinc_test_code | VARCHAR(20) | LOINC 18769-0 |
| fhir_observation_id | VARCHAR(100) | FHIR Observation.id |
| Column | Type | Notes |
|---|---|---|
| PKid | UUID | Primary key |
| name | VARCHAR(200) | Generic name |
| atc_code | VARCHAR(20) | WHO ATC code |
| class | VARCHAR(100) | e.g. Cephalosporin |
| who_access_group | ENUM | ACCESS/WATCH/RESERVE |
| snomed_code | VARCHAR(20) | SNOMED substance code |
| Column | Type | Notes |
|---|---|---|
| PKid | UUID | Primary key |
| patient_id | UUID FK | → patients |
| prescriber_id | UUID FK | → users |
| antibiotic_id | UUID FK | → antibiotics |
| indication_icd11 | VARCHAR(20) | ICD-11 indication |
| dose_mg | DECIMAL(8,2) | |
| route | ENUM | oral/IV/IM |
| duration_days | INTEGER | |
| is_empiric | BOOLEAN | Before culture result |
| guideline_compliant | BOOLEAN | Auto-checked |
| fhir_med_request_id | VARCHAR(100) | FHIR MedicationRequest |
| prescription_date | DATE |
| Column | Type | Notes |
|---|---|---|
| PKid | UUID | Primary key |
| job_type | ENUM | ingestion/validation/load |
| source_name | VARCHAR(100) | ATLAS/GLASS/Live |
| status | ENUM | queued/running/done/failed |
| records_in | INTEGER | Records processed |
| records_accepted | INTEGER | |
| records_rejected | INTEGER | |
| started_at | TIMESTAMPTZ | |
| completed_at | TIMESTAMPTZ | |
| error_log | JSONB | Structured error details |
| Column | Type | Notes |
|---|---|---|
| PKid | UUID | Primary key |
| record_type | VARCHAR(100) | Table name of flagged row |
| record_id | UUID | FK to the flagged record |
| flag_type | ENUM | missing/outlier/duplicate |
| field_name | VARCHAR(100) | Column with issue |
| original_value | TEXT | |
| imputed_value | TEXT | After KNN/MICE |
| resolved | BOOLEAN | Default false |
| Column | Type | Notes |
|---|---|---|
| PKid | UUID | Primary key |
| model_name | VARCHAR(100) | e.g. resistance_rf_v3 |
| model_type | ENUM | classification/cluster/forecast |
| algorithm | VARCHAR(100) | RandomForest/DBSCAN/Prophet |
| version | VARCHAR(20) | Semantic version |
| accuracy | DECIMAL(5,4) | Test set score |
| auc_roc | DECIMAL(5,4) | |
| artifact_path | VARCHAR(500) | S3/local .pkl path |
| trained_at | TIMESTAMPTZ | |
| is_active | BOOLEAN | Currently serving |
| Column | Type | Notes |
|---|---|---|
| PKid | UUID | Primary key |
| model_id | UUID FK | → ml_models |
| organism_snomed | VARCHAR(20) | SNOMED CT code |
| antibiotic_atc | VARCHAR(20) | ATC code |
| district_id | UUID FK | → districts |
| predicted_resistance_rate | DECIMAL(5,4) | 0-1 probability |
| confidence_interval_low | DECIMAL(5,4) | |
| confidence_interval_high | DECIMAL(5,4) | |
| prediction_period | DATE | Month of prediction |
| shap_values | JSONB | Feature importance |
| Column | Type | Notes |
|---|---|---|
| PKid | UUID | Primary key |
| model_id | UUID FK | → ml_models |
| cluster_label | INTEGER | -1 = noise |
| centroid_lat | DECIMAL(9,6) | |
| centroid_lon | DECIMAL(9,6) | |
| radius_km | DECIMAL(8,3) | Cluster extent |
| resistance_rate | DECIMAL(5,4) | Avg within cluster |
| organism_snomed | VARCHAR(20) | |
| detected_at | TIMESTAMPTZ |
| Column | Type | Notes |
|---|---|---|
| PKid | UUID | Primary key |
| model_id | UUID FK | → ml_models |
| antibiotic_id | UUID FK | → antibiotics |
| district_id | UUID FK | → districts |
| forecast_month | DATE | First of month |
| forecasted_ddd_per_1000 | DECIMAL(10,3) | WHO DDD metric |
| lower_bound | DECIMAL(10,3) | 95% CI lower |
| upper_bound | DECIMAL(10,3) | 95% CI upper |
| Column | Type | Notes |
|---|---|---|
| PKid | UUID | Primary key |
| alert_type | ENUM | outbreak/prescribing/threshold |
| severity | ENUM | low/medium/high/critical |
| district_id | UUID FK | → districts |
| facility_id | UUID FK | → facilities (nullable) |
| trigger_value | DECIMAL(10,4) | Value that triggered |
| threshold_value | DECIMAL(10,4) | Configured threshold |
| message | TEXT | Human-readable message |
| notified_users | UUID[] | Array of user IDs |
| sms_sent | BOOLEAN | |
| push_sent | BOOLEAN | |
| resolved | BOOLEAN | |
| created_at | TIMESTAMPTZ |
| Column | Type | Notes |
|---|---|---|
| PKid | UUID | Internal PK |
| fhir_id | VARCHAR(100) | FHIR resource ID |
| resource_type | VARCHAR(50) | DiagnosticReport/Obs… |
| version_id | INTEGER | FHIR version |
| resource_json | JSONB | Full FHIR resource |
| synced_to_dhis2 | BOOLEAN | |
| synced_to_glass | BOOLEAN | |
| last_updated | TIMESTAMPTZ |
| Column | Type | Notes |
|---|---|---|
| PKid | UUID | Primary key |
| user_id | UUID FK | → users (nullable) |
| action | VARCHAR(100) | CREATE/UPDATE/DELETE/VIEW |
| resource_type | VARCHAR(100) | Table/endpoint name |
| resource_id | UUID | Affected record |
| ip_address | INET | |
| changes | JSONB | Before/after diff |
| created_at | TIMESTAMPTZ | Indexed |
| Column | Type | Notes |
|---|---|---|
| PKid | UUID | Primary key |
| prescriber_id | UUID FK | → users |
| period_month | DATE | First of month |
| total_prescriptions | INTEGER | |
| guideline_compliance_rate | DECIMAL(5,4) | 0-1 |
| watch_group_rate | DECIMAL(5,4) | WHO WATCH antibiotics % |
| empiric_rate | DECIMAL(5,4) | % without culture |
| amr_risk_score | DECIMAL(5,2) | Composite 0-100 |
Each technology layer has a clearly defined responsibility boundary. Data crosses boundaries via well-defined interfaces (REST APIs, message queues, shared MySQL).