Skip to content

jupyterhealth/jupyterhealth-exchange

Repository files navigation

JupyterHealth Exchange

JupyterHealth Exchange is a Django web application that facilitates sharing patient-consented health data with authorized users via a Web UI and REST, MCP, and FHIR APIs.

Features include:

Documentation

What It Does

Typical User Flow

Researchers create studies and recruit patients, who consent and submit observations via client applications, and the data is then stored in JupyterHealth Exchange and queried by researchers using Jupyter Notebooks or other systems.

Typical Data Flow

Users manage the system via the Web UI, and data producers receive invitation credentials by email, manage consents through the Admin API, and upload data to JupyterHealth Exchange using the FHIR API. Data consumers such as Jupyter Notebooks or other systems then query and read the data through REST and MCP APIs.

Getting Started

Note

Getting started with Docker is in the works!

  1. Set up your Python environment and install dependencies from Pipfile - this project uses Django version 5.2 which requires python 3.12

    • NB: If using pipenv it is recommended to run pipenv sync against the lock file to match package versions
  2. Create a new Postgres DB (currently only Postgres is supported)

  3. Copy dot_env_example.txt to .env and update the DB_* parameters to match (2) above.

    • Optionally you can add a Django SECRET_KEY by running the command below or you can leave this for now to use a randomly generated value at runtime (this will not work with more than one worker) $ openssl rand -base64 32
  4. Ensure the .env is loaded into your Python environment, eg for pipenv run $ pipenv shell

  5. Run the Django migration $ python manage.py migrate to create the database tables.

  6. Seed the database by running the Django management command $ python manage.py seed

  7. Start the server with $ python manage.py runserver

  8. Browse to http://localhost:8000/admin and enter the credentials sam@example.com Jhe1234!

  9. Under Django OAuth Toolkit > Applications you should see the seeded OAuth2 application named JHE Admin UI with a Redirect URI for http://localhost:8000/auth/callback - this is used for the Web UI OAuth 2.0 login.

  10. Click the LOG OUT button at the top

  11. Finally, we need to create an RS256 Private Key for signing the JWT

    • Run openssl genrsa -out oidc.key 4096

    • Run awk '{printf "%s%s", (NR==1?"":"\\n"), $0}' oidc.key to remove line breaks Note: some python environments and OS combinations do not handle the "\n" so you may need to include line breaks in the .env file.

    • Return to the .env file and update the OIDC_RSA_PRIVATE_KEY

    • Keep the oidc.key somewhere safe

  12. Browse to http://localhost:8000/ and log in with the credentials mary@example.com Jhe1234! and you should be directed to the /portal/organizations path with some example Organizations is the dropdown

  13. New users can be signed up from the base URL (eg http://localhost:8000/) with the default invitation code "jhe" which is set from the REGISTRATION_INVITE_CODE in .env

Note

Due to browser security restrictions and the oidc-client-ts used for authentication, the web app must be accessed over HTTPS for any hostname other than localhost - see Running in Production below.

Who and What the App Manages

Entities are based on the HL7 FHIR model, a widely used healthcare standard for organizing and exchanging clinical information between systems.

Patients & Practitioners

  • Any user accessing the Web UI is a Practitioner by default. In practice this might be a researcher, a clinician, an administrator or even an individual setting up JupyterHealth Exchange to view their own health data.
  • Patient users are registered by Practitioners and are sent a link to authenticate and upload data.
  • The same OAuth 2.0 strategy is used for both Practitioners and Patients, the only difference being that the authorization code is provided out-of-band for Patients (ie invitation links).

Organizations

  • An Organization is a group of Practitioners, Patients and Studies (FHIR Groups) and is used to manage access to data.
  • An Organization is typically hierarchical with sub-Organizations like Institutions, Departments, Labs etc.
  • A Practitioner belongs to one or more Organization.
  • A Patient belongs to one or more Organization.
  • A Study belongs to one single Organization.

Studies

  • A Study is a Group of Patients and belongs to a single Organization.
  • A Study has one or more Clients (apps that talk to JupyterHealth Exchange), one or more matching Data Sources (anything that produces data) and one or more Scope Requests (eg Blood Pressure, Heart Rate, etc)
  • When a Patient is added to a Study, they must explicitly consent to sharing the requested Scopes before any personal data (Observations) can be uploaded or shared.

Observations

  • An Observation is Patient data and belongs to a single Patient.
  • An Observation must reference a Patient ID as the subject and a Data Source ID as the device.
  • Personal device data is expected to be in the Open mHealth (JSON) format however the system can be easily extended to support any binary data attachments or discrete Observation records.
  • Observation data is stored as a valueAttachment in Base 64 encoded JSON binary.
  • Authorization to view Observations depends on the relationship of Organization, Study and Scopes/consents as described above.

Data Sources

  • A Data Source is anything that produces Observations (typically a device app eg iHealth). An Observation references a Data Source ID in the device field.
  • A Data Source supports one or more Scopes (types) of Observations (eg Blood Glucose).
  • A Study has one or more associated Data Sources.
  • A Data Source has one Client. In some cases a single app may be both a Data Source and a Client, in which case a record is created for each and both are added to the Study.

Clients

  • Clients are apps that talk to JupyterHealth Exchange.
  • Each Client has its own OAuth 2.0 Client ID.
  • A Study has one or more associated Clients.
  • A Client has one or more associated Data Sources. In some cases a single app may be both a Data Source and a Client, in which case a record is created for each and both are added to the Study.

Quick Start Walkthrough

  1. Sign up as a new user from the Web UI.
  2. Create a new Organization (your user is automatically added to the Organization with a Manager role).
  3. Create a new Study for the Organization (View Organization → Studies+).
  4. Create a new Patient for the Organization using a different email than step 1 (Patients → Add Patient).
  5. Add Data Sources and Scopes to the Study (View Study → Data Sources+, Scope Requests+).
  6. Add the Patient to the Study (Patients → Select patient → Add Patient(s) to Study).
  7. Create an Invitation Link for the Patient (View Patient → Generate Invitation Link).
  8. Use the code in the invitation link with the Auth API to exchange it for an access token.
  9. Upload Observations using the FHIR API and access token.
  10. View the Observations from the Web UI.

Contributing

See doc for test requirements, coding standards, and PR checklist.

Packages

 
 
 

Contributors