Thousands of Practices, One Dataset

A hard Pipeline Design interview practice problem on DataDriven. Design the pipeline on the canvas: sources, transforms, storage and checks, then get feedback on it.

Domain
Pipeline Design
Difficulty
hard
Seniority
L6

Problem

We run a cloud EHR platform for thousands of medical practices, all sharing one database where tenant isolation lives only in the application layer. Design the pipeline that serves both cross-practice population health analytics and each practice's own performance reporting from that database.

Patient records in, operational insights out.

Business requirements

Worked solution and explanation

The real problem

This is multi-tenant isolation wearing a healthcare costume. Anyone can draw a pipeline that lands the data. What separates candidates is whether the boundary survives once the data leaves the application. A WHERE practice_id = ... filter in the BI tool is one forgotten clause from a HIPAA breach. A single nightly job into one table fails on three fronts at once: the biggest practice runs long and starves the small ones, research reads real identifiers, and one unfiltered query returns another practice's patients.

Walk the requirements

Step 1: Capture changes per practice, in near real time

Stream changes out of the shared database with a sub-minute capture stage and partition the stream by practice. Large tenants generate most of the volume, and partitioning means their lag stays in their own lane. Also, no big nightly extract hammers the production database.

Step 2: Ingest each practice independently

The ingest job runs in parallel partitions, one practice per partition. A backed-up large practice delays only itself. The prior day lands for every tenant before the morning dashboards, not just for the big ones.

Step 3: Put the boundary in the warehouse

The practice warehouse sits behind a row-level security policy keyed on the practice, so a query for one practice cannot return another's rows. Without a warehouse tier there is nowhere to enforce it, and a BI filter is only a convention.

Step 4: De-identify before research data lands

A pseudonymizing transform replaces MRN, name and date of birth with tokens on the way to the population warehouse. Epidemiology queries a store that never held real identifiers. Real PHI stays only on the per-practice path.

The shape that fits

One fork after ingest: the practice path keeps real identifiers behind row-level security, and the research path is de-identified before it is stored.
  • shared oltp (source, PostgreSQL)
  • per practice change data capture (transform, Flink); freshness: < 1min
  • change stream (queue, Kafka); parallelism: 16 partitions
  • per practice ingest (transform, Spark); parallelism: 16 partitions
  • practice warehouse (storage, warehouse); freshness: < 24h
  • row level security policy (quality gate, custom)
  • practice dashboard (consumer, dashboard)
  • pseudonymizer (transform, Spark)
  • population warehouse (storage, warehouse); freshness: < 24h
  • research notebooks (consumer, Jupyter)
  • shared oltp -> per practice change data capture
  • per practice change data capture -> change stream
  • change stream -> per practice ingest
  • per practice ingest -> practice warehouse
  • practice warehouse -> row level security policy
  • row level security policy -> practice dashboard
  • per practice ingest -> pseudonymizer
  • pseudonymizer -> population warehouse
  • population warehouse -> research notebooks
  • Source and capture: shared oltp, per practice change data capture, change stream
  • Per-practice ingest: per practice ingest
  • Warehouses and de-identification: practice warehouse, row level security policy, pseudonymizer, population warehouse
  • Consumers: practice dashboard, research notebooks

Common follow-up questions