← Back to projects

Personal project

Healthcare Realtime Monitoring

An Amazon Web Services (AWS) demonstration that combines synthetic Synthea patient records with replayed public Beth Israel Deaconess Medical Center (BIDMC) waveform-derived vital signs and synthetic bedside measures. Fast Healthcare Interoperability Resources (FHIR) observations feed a realtime dashboard with live National Early Warning Score 2 (NEWS2) and a governed lakehouse with daily scoring for a synthetic proxy of repeated extreme readings. A simulation study tests how well models recover a planted early-warning signal.

Replay

Watch One Recorded Demo Session.

A demonstration deployment streamed readings for 10 synthetic patients. The live dashboard's WebSocket feed was recorded for 31 minutes: 11,309 frames. Heart rate, breathing and oxygen saturation update every few seconds; blood pressure, temperature, inhaled oxygen and consciousness level arrive about every 5 minutes. Replay them here at up to 16 times speed, with no AWS resources running.

Recorded demonstration data: synthetic Synthea patients with replayed public BIDMC waveform-derived values, shown exactly as recorded. It is not live and not clinical.

Problem

One Event Stream for Monitoring and Analytics.

A realtime view needs timestamped readings; analysis needs history that can be checked and modeled. This demonstration builds both from one event stream containing fictional patient records and replayed public waveform-derived vital signs.

Role and scope

Built End to End and Released.

What I Built

The whole system, alone: simulator, FHIR ingestion, streaming services, lakehouse jobs, dbt models, quality checks, model training and scoring, dashboards, Terraform, CI, a local stack and the simulation study.

Complete

Realtime path, lakehouse, star schema, quality gates, lineage, daily scoring, bedside measures, live NEWS2 with real-time early-warning scoring, Grafana dashboards and an ingestion check, accepted in the release. All of it ran on AWS: the release checks, the replay above and separate checks of early warning, Grafana and ingestion. Grafana also runs locally, as does the simulation study.

Out of Scope

Identifiable patient records, clinical validation and an always-on service. The AWS stack runs for demos and tests, then is torn down.

Architecture

One Event Stream, Two Paths.

Open full-size diagramOpen full-size diagramSwipe or use arrow keys to explore the diagram.
Observations combine synthetic patient records with replayed public waveform-derived vital signs and synthetic bedside measures and enter Kinesis through HAPI FHIR and a webhook. The realtime path serves vitals, NEWS2 and an approved model probability through DynamoDB, APIs and Streamlit. The lakehouse serves prediction views to Streamlit model analytics and private Power BI reporting, while Grafana queries operational tables.Observations combine synthetic patient records with replayed public waveform-derived vital signs and synthetic bedside measures and enter Kinesis through HAPI FHIR and a webhook. The realtime path serves vitals, NEWS2 and an approved model probability through DynamoDB, APIs and Streamlit. The lakehouse serves prediction views to Streamlit model analytics and private Power BI reporting, while Grafana queries operational tables.

Two paths from one demonstration stream with fictional patient records and replayed public waveform-derived vital signs.

Read the diagram as text
  1. The simulator publishes FHIR observations using synthetic patient records and replayed public waveform-derived values. Every 5 minutes it adds blood pressure and synthetic temperature, inhaled oxygen and consciousness. A webhook Lambda validates each observation and sends an event envelope to Kinesis.
  2. The realtime processor merges state into DynamoDB, stores encounter readings with a two-day expiry and broadcasts through a WebSocket API protected by AWS Identity and Access Management (IAM). An IAM-authorized HTTP API serves the latest snapshot and early warning. NEWS2 uses current vitals; the approved model uses the encounter's first 15 minutes after that window closes plus a 60-second grace period. The Streamlit dashboard shows vitals, live NEWS2 and the model probability when available.
  3. Data Firehose writes normalized FHIR-derived events to versioned S3. Glue cleans and deduplicates the data into Iceberg tables and quarantines invalid records.
  4. The daily MWAA workflow runs Glue, Athena validation, Great Expectations and dbt before scoring with a pinned model. It refreshes Athena prediction views and runs Soda checks afterward.
  5. Athena views serve Streamlit model analytics and a private Power BI DirectQuery report. Optional Grafana dashboards cover pipeline operations, quality and capacity. Failed realtime events use Amazon Simple Queue Service (SQS) and replay back to Kinesis; exhausted retries enter a dead-letter queue. CloudWatch provides monitoring, an ingestion check runs every 30 minutes and OpenLineage records lineage with an S3 fallback.

Ingestion

Synthetic Synthea patient records, replayed public BIDMC waveform-derived vitals and synthetic bedside measures are published to HAPI FHIR. FHIR R4 provides a standard format for exchanging health records; Logical Observation Identifiers Names and Codes (LOINC) identifies each vital sign.

  • Synthea
  • HAPI FHIR
  • LOINC
  • Kinesis Data Streams

Storage

DynamoDB holds current patient state and encounter vitals with a two-day expiry, S3 keeps the raw event history and Iceberg tables in the Glue Data Catalog hold processed observations. A local PostgreSQL warehouse holds the simulation study's data.

  • DynamoDB
  • Amazon S3
  • Apache Iceberg
  • Glue Data Catalog
  • PostgreSQL

Transformation

Glue PySpark jobs clean and deduplicate events. dbt on Athena builds a Kimball star schema with Type 2 provider history, encounter feature tables, NEWS2 at the end of each feature window and per-vital trend slopes. The same models run on the local PostgreSQL warehouse.

  • AWS Glue
  • PySpark
  • Athena
  • dbt

Orchestration

MWAA Serverless runs the daily workflow in dependency order: Glue, validation, the cohort reference extract, dbt, scoring, prediction views and Soda, with lineage recorded along the way. A second workflow checks ingestion every 30 minutes. Terraform defines the application's AWS resources; account prerequisites such as secrets and deployment policies are managed separately.

  • MWAA Serverless
  • OpenLineage
  • Marquez
  • Terraform

Serving

A Lambda processor merges each event into DynamoDB and pushes it over a WebSocket API. An IAM-authorized HTTP API returns the latest snapshot when a socket drops and serves NEWS2 with the model's early-warning score.

  • Lambda
  • API Gateway
  • WebSocket
  • Signature Version 4 (SigV4)

BI

A Streamlit realtime cohort dashboard shows vitals, live NEWS2 and the approved model probability when available. A separate Streamlit model analytics dashboard and a private Power BI DirectQuery report read Athena prediction views. The Power BI report uses Power Query and Data Analysis Expressions (DAX). Grafana queries operational tables for pipeline operations, quality and capacity.

  • Streamlit
  • Altair
  • Grafana
  • Power BI
  • DAX

Key decisions

Four Trade-Offs That Shaped the Build.

01

Serverless Orchestration, Portable DAG

I moved the workflow from a provisioned MWAA environment to MWAA Serverless. The Python DAG still runs on any Airflow; a generator converts it to the Serverless definition. Trade-off: that definition must be regenerated whenever the DAG changes.

  • MWAA Serverless
  • Apache Airflow
  • YAML
02

Score With One Approved Model

Scoring loads an explicitly approved, checksummed model version. Training refuses to run until both partitions contain both label classes. Trade-off: a new model needs a review step before it scores anything.

  • scikit-learn
  • Model approval
  • Checksums
03

Keep Raw History, Govern Processed Data

I retain raw event history for audit and replay. Glue quarantines rejected records and merges accepted, deduplicated observations into Iceberg. dbt staging selects the configured cohort and valid encounter IDs: 10 patients on AWS and up to 100 locally. Trade-off: row counts differ by layer, so each layer’s grain has to be documented.

  • Iceberg
  • dbt
  • Kimball
04

Test Models Against a Known Answer

The simulation study plants a seeded early-warning trend in most deterioration encounters and keeps a null control with none. A calibration on a separate seed set the signal's strength before the analysis plan was frozen. Trade-off: the results show how well a method recovers a planted signal, not clinical performance.

  • statsmodels
  • scikit-learn
  • Jupyter
  • PostgreSQL

Evidence

Where to Check the Work.

Repository

Code, Terraform, tests and runbooks in the repository.

Release Acceptance

Test, workflow, load-test, alarm and teardown results in the release notes.

Change History

Every change in the changelog, including the simulation study and its calibration.

Results and limits

What Was Measured and What It Does Not Claim.

The Release in Four Figures

  • 762

    Python tests passed

    Local validation passed 762 Python tests, Ruff, MyPy, the Soda contracts, the workflow tests, the Terraform plan tests and every repository hook.

    Source: release notes

  • 10

    workflow tasks in one run

    With an approved model, one MWAA Serverless run completed all ten tasks, including the cohort reference extract, dbt, scoring, the prediction refresh and Soda.

    Source: release notes

  • 1,381 ms

    WebSocket delivery at p95 under load

    The isolated load test passed with no missing observation in DynamoDB or over WebSocket; delivery took 241 ms at the median and 1,381 ms at the 95th percentile.

    Source: release notes

  • 12

    alarms OK after the run

    All 12 alarms were OK, both failure queues were empty and no replay policy remained. Teardown then destroyed every resource.

    Source: release notes

Measured at Release

762 Python tests passed with every repository check. One MWAA Serverless run completed all ten tasks with an approved model. Under an isolated load test, WebSocket delivery took 241 ms at the median and 1,381 ms at the 95th percentile, with no missing observation. Source: release notes.

Simulation Study Calibration

On the calibration seed, a logistic regression reached an area under the curve (AUC) of 0.802 and NEWS2 0.691; on the null control, with nothing planted, they reached 0.501 and 0.480. The study arm uses another seed. Source: changelog.

Data

Synthetic Synthea patient records are combined with replayed public BIDMC waveform-derived vital signs. The model predicts a synthetic deterioration proxy: repeated extreme readings of the same vital sign in the next 15 minutes, from features in the first 15. Source: model training guide and BIDMC dataset provenance.

Limits

Not clinically validated and not a production service. The release's model had four test encounters. This supports verification of the governed deployment path rather than a model-performance claim. The study's signal and bedside measures are synthetic by design. The load test measures one isolated run, not sustained production traffic. The Power BI report is private and no dashboard screenshots are published.

Lessons

What I Learned.

Keep Identifiers at the Edge

Keeping the encounter ID at the ingestion boundary mattered most: an identifier lost there cannot be rebuilt reliably later. See the star-schema guide.

Design for the Real Question

The first dashboard followed one patient. Rebuilding it around the whole cohort, with explicit stale states, answered the question that matters: who needs attention now?

Check the Data for Leaks Before the Model

The first planted signal turned waveform dropouts into valid readings, but only in deterioration encounters: 537 readings that marked the label. The changelog records the fix. A model could have learned the leak instead of the signal.

↑ ↓ to move · Enter to open · Esc to close