This repo is part of the HL7 FHIR DevDays 2023 tutorial FHIR x Nuts: How to combine FHIR and Nuts to create large-scale distributed networks for healthcare information exchange.
The code in this repo is the outcome of participating in the Hackathon FHIR x NUTS bij HL7 Working Group meeting. As such, this code is by no means production ready. It is solely intended as a PoC. It does not meet the necessary security standards and should not be used in a production environment.
However, due to the complexity of setting up and interacting with multiple Nuts nodes and FHIR servers, I believe that this repo can be of value to anyone wanting to learn more about/get started with the Toepassing op Nuts: BgZ.
The repo consists of:
- 1 Docker compose file that sets up 2 Nuts nodes, 2 Firely Server instances using SQLite and one instance of Seq.
- 1 exported Postman collection and 2 exported Postman environments for setting up the Nuts nodes and Firely Servers.
- 1 Visual Studio solution containing a Firely Server plugin that handles both the sending and receiving of a referral using a notified pull.
- This readme file containing detailed instructions on how to setup all of the above.
This repo was tested on both Ubuntu and Windows 10.
Part of the repo is based on the Nuts network local repo of the Nuts foundation.
For this demo we will be making use of Postman, Docker and an IDE that supports C# like Visual Studio or Rider.
The starting point of this tutorial is cloning the fhir-nuts-devdays Git repo:
git clone https://github.com/frank-olthuijsen/fhir-nuts-devdays.git
In the root of the repo you will find a folder named Postman
. In there are 1 exported Postman collection and 2 exported Postman environments. Please import all 3 of them. The Postman requests are grouped in folders similar to the chapters in this readme.
From now on we will refer to the Postman collection as Postman
and the environments as Nuts-1
and Nuts-2
.
The referral process, both sending and receiving, is implemented using a Firely Server-plugin. The plugin contains a custom operation named $refer to start the referral process and a prehandler that gets triggered when receiving a (notification) Task.
- Open
Nuts.sln
using your favorite C# IDE. - Build the solution.
The output is configured to be placed in:
./shared/config/fhir/plugins
Please confirm the plugins
-folder contains Nuts.Plugin.dll
. The nesting-level within the folder is irrelevant.
- Navigate to https://simplifier.net/downloads/firely-server, log in and download an evaluation license for Firely Server using the Download key-button. Do not change the name and store the license file in:
./shared/config/fhir
- Navigate to the root of the repo you cloned. It contains a file called
docker-compose.yml
. Run the following command:
docker-compose up
The following containers are now running:
- node-one: Nuts node instance
- node-two: Nuts node instance
- fhir-one: Firely Server instance
- fhir-two: Firely Server instance
- seq: Seq instance
- Inspect the status of each FHIR server:
- Inspect the status of each Nuts node:
Both Firely Server instances write their log output to Seq. Especially the output of the Nuts-plugin is useful since there is no UI to assist the referral process.
The events in Seq can be viewed by opening: http://localhost:8081/#/events. The username is admin
and the password is password
.
Please check the pricing page for the licensing details.
For this tutorial we will assume two vendors (Vendor-One and Vendor-Two) will each run their own node (node-one and node-two) to service one of their customers (Customer-One and Customer-Two).
Repeat the steps below for each Postman environment (i.e. Vendor): nuts-1
and nuts-2
.
- Create a new DID:
Postman: A1. Create a vendor DID
- Update the {{VENDORDID}} in the relevant Postman environment.
"id": "did:nuts:5gTvUacW5QVXW4hgFnJYe5gb5uEdo6WUSeYj5p6RABpJ",
- Open
./one/config/node/nuts.yaml
or./two/config/node/nuts.yaml
depending on the active Postman environment, update thenetwork
-setting and save the file:
network:
nodedid: did:nuts:5gTvUacW5QVXW4hgFnJYe5gb5uEdo6WUSeYj5p6RABpJ
Postman: A4. Add contact information to the vendor DID
Next we will add a number of services to the vendor DID documents. This will allow other us to reference these services from the customer DID documents that we will add later. This in turn will tell other nodes where to find these services for the relevant customer.
- Create a NutsComm service which specifies the gRPC address other nodes will use to connect to your node:
Postman: B1. Add a NutsComm service to the vendor DID
- Create a FHIR service:
Postman: B2. Add a FHIR service to the vendor DID
- Create an OAuth service
Postman: B3. Add an OAuth service to the vendor DID
- Create a notification service
For the BgZ use case using a notified pull, a notification service (endpoint) is required. For this demo we will use the fhir-server service as a notification endpoint. Therefore, we don't need to create a separate service on the vendor DID. A reference to the fhir-server service will be added to the organization DIDs.
Before continuing with the next steps:
- Please make sure you have added both vendors using the steps described above
- Change the environment in Postman from
Nuts-1
toNuts-2
- Go back to the step A1 and work through all of the steps
- Change the environment in Postman from
- Restart the containers:
Ctrl+C
docker-compose down
docker-compose up
As mentioned earlier, in this tutorial we will have two vendors with each one organization (or customer). Each organization must be registered with its own DID and DID Document.
Repeat the steps below for each Postman environment (i.e. Vendor): nuts-1
and nuts-2
.
- Create a new DID:
Postman: C1. Create an organization DID
- Update the {{CUSTOMERDID}} variable of the relevant environment.
"id": "did:nuts:31XVYF4urH86D8ok8wzm98Vz4YTsNd7jnJfKnhjd8nTv",
After registering a customer, its presence on the network and in the Nuts registry is only a DID. In order for other organizations to find the correct DID and connected services, credentials should be issued and published over the network. For this, the NutsOrganizationCredential can be issued.
- Create an organization credential
Postman: D1. Issue an organization credential
- Connect to NutsComm
Postman: E1. Connect to vendor NutsComm
- Search for all organization credentials to ensure the registrations have gone well.
Postman: y. Search for organization credentials
Organizations can be found on the network and endpoints have been defined. Now it’s time to enable specific bolts so users can start using data from other organizations. Every bolt requires its own configuration. This configuration is known as a Compound Service on the organization’s DID document. A Compound Service defines certain endpoint types and which endpoint to use for that type.
- Add a compound service for the bgz-sender
Postman: F1. Enabling a bolt: bgz-sender
- Add a compound service for the bgz-receiver
Postman: F2. Enabling a bolt: bgz-receiver
- Search for the relevant organization by its name and check that the compound services have been added.
Postman: z. Search for organization by name
Before continuing with the next steps:
- Please make sure you have added both vendors using the steps described above
- Change the environment in Postman from
Nuts-1
toNuts-2
- Go back to the step C1 and work through all of the steps
- Change the environment in Postman from
A node operator must not blindly trust all the data is published over the network. Before credentials can be found, the issuer has to be trusted. By default, no issuers are trusted.
- List the untrusted vendors
Postman: G1. List untrusted vendors
- Add the other node as a trusted vendor
Postman: G2. Trust the other vendor
-
Repeat step G1 to ensure that the vendor is trusted.
-
Repeat G1 to G3 for the other vendor (i.e. change the environment in Postman)
-
Change the Postman environment to
Nuts-1
. All of the steps below need to be executed forNuts-1
only. -
Load the resources to exchange into
fhir-one
:
Postman: 1. Load resources
- Load the workflow Task to exchange into
fhir-one
:
Postman: 2. Create workflow Task
- Check the contents of
fhir-two
to ensure it is empty:
- http://localhost:4081/Patient?_include=Patient:general-practitioner
- http://localhost:4081/Observation?code=http://snomed.info/sct|228273003
- Open Seq to see the referral steps listed.
- Send out the referral:
Postman: 1. Send out referral notification
- Rerun the queries from step 1. You will see that
fhir-two
now contains the same data asfhir-one
.
That concludes this tutorial.
The Nuts documentation contains a "Hello World" on Docker tutorial. Besides Nuts nodes and FHIR servers it also contains a UI for both a Demo EHR and a Nuts Admin interface.
In order to run a Nuts node in production, additional security steps are needed in the Nuts configuration.