eCR Viewer
    Preparing search index...

    eCR Viewer Setup Guide

    The eCR Viewer can be run in three modes.

    Mode Features Available Metadata Support Authentication Supported Environment Variables Needed
    INTEGRATED Viewer None NBS Base, eCR FHIR Storage, Integrated Authentication
    NON_INTEGRATED Viewer, Library SQL Server or Postgres External authentication provider Base, eCR FHIR Storage, Non-Integrated Authentication, Metadata Database
    DUAL Viewer, Library SQL Server or Postgres Both NBS and external authentication provider Base, eCR FHIR Storage, Integrated Authentication, Non-Integrated Authentication, Metadata Database
    %%{init:{"theme":"dark"}}%% flowchart LR user nbs["NBS - View eICR"] ingestion["Ingestion Service<br>(e.g. Rhapsody)"] subgraph service[Cloud] direction TB subgraph container["fab:fa-docker container"] viewer["fab:fa-node fab:fa-react <code>ecr-viewer<br>HTTP:3000/</code>"] end blobStorage["fab:fa-file Blob Storage"] container <--> |eCR FHIR Data| blobStorage end user --> nbs nbs -->|<code>/view-data</code><br>eCR Viewer<br>Authenticated by NBS| container ingestion -->|<code>/api/process-ecr</code>| container
    %%{init:{"theme":"default"}}%% flowchart LR user nbs["NBS - View eICR"] ingestion["Ingestion Service<br>(e.g. Rhapsody)"] subgraph service[Cloud] direction TB subgraph container["fab:fa-docker container"] viewer["fab:fa-node fab:fa-react <code>ecr-viewer<br>HTTP:3000/</code>"] end blobStorage["fab:fa-file Blob Storage"] container <--> |eCR FHIR Data| blobStorage end user --> nbs nbs -->|<code>/view-data</code><br>eCR Viewer<br>Authenticated by NBS| container ingestion -->|<code>/api/process-ecr</code>| container
    flowchart LR
      user
      nbs["NBS - View eICR"]
      ingestion["Ingestion Service<br>(e.g. Rhapsody)"]
      subgraph service[Cloud]
        direction TB
        subgraph container["fab:fa-docker container"]
          viewer["fab:fa-node fab:fa-react <code>ecr-viewer<br>HTTP:3000/</code>"]
        end
        blobStorage["fab:fa-file Blob Storage"]
    	container <--> |eCR FHIR Data| blobStorage
      end
      user --> nbs
      nbs -->|<code>/view-data</code><br>eCR Viewer<br>Authenticated by NBS| container
      ingestion -->|<code>/api/process-ecr</code>| container
    %%{init:{"theme":"dark"}}%% flowchart LR user ingestion["Ingestion Service<br>(e.g. Rhapsody)"] subgraph service[Cloud] direction TB subgraph container["fab:fa-docker container"] viewer["fab:fa-node fab:fa-react <code>ecr-viewer<br>HTTP:3000/</code>"] end blobStorage["fab:fa-file Blob Storage"] metadata["fab:fa-database Database"] identityProvider["Identity Provider<br>(e.g. Keycloak/Azure Ad)"] container <--> |eCR FHIR Data| blobStorage container <--> |eCR Metadata| metadata container -->|Validates User| identityProvider end user -->|<code>/view-data</code><br>eCR Viewer<br>Authenticated by identity provider| container user -->|<code>/</code><br>eCR Library<br>Authenticated By identity provider| container ingestion -->|<code>/api/process-ecr</code>| container
    %%{init:{"theme":"default"}}%% flowchart LR user ingestion["Ingestion Service<br>(e.g. Rhapsody)"] subgraph service[Cloud] direction TB subgraph container["fab:fa-docker container"] viewer["fab:fa-node fab:fa-react <code>ecr-viewer<br>HTTP:3000/</code>"] end blobStorage["fab:fa-file Blob Storage"] metadata["fab:fa-database Database"] identityProvider["Identity Provider<br>(e.g. Keycloak/Azure Ad)"] container <--> |eCR FHIR Data| blobStorage container <--> |eCR Metadata| metadata container -->|Validates User| identityProvider end user -->|<code>/view-data</code><br>eCR Viewer<br>Authenticated by identity provider| container user -->|<code>/</code><br>eCR Library<br>Authenticated By identity provider| container ingestion -->|<code>/api/process-ecr</code>| container
    flowchart LR
      user
      ingestion["Ingestion Service<br>(e.g. Rhapsody)"]
      subgraph service[Cloud]
        direction TB
        subgraph container["fab:fa-docker container"]
          viewer["fab:fa-node fab:fa-react <code>ecr-viewer<br>HTTP:3000/</code>"]
        end
        blobStorage["fab:fa-file Blob Storage"]
        metadata["fab:fa-database Database"]
        identityProvider["Identity Provider<br>(e.g. Keycloak/Azure Ad)"]
    	container <--> |eCR FHIR Data| blobStorage
    	container <--> |eCR Metadata| metadata
        container -->|Validates User| identityProvider
      end
      user -->|<code>/view-data</code><br>eCR Viewer<br>Authenticated by identity provider| container
      user -->|<code>/</code><br>eCR Library<br>Authenticated By identity provider| container
      ingestion -->|<code>/api/process-ecr</code>| container
    %%{init:{"theme":"dark"}}%% flowchart LR user nbs["NBS - View eICR"] ingestion["Ingestion Service<br>(e.g. Rhapsody)"] subgraph service[Cloud] direction TB subgraph container["fab:fa-docker container"] viewer["fab:fa-node fab:fa-react <code>ecr-viewer<br>HTTP:3000/</code>"] end blobStorage["fab:fa-file Blob Storage"] metadata["fab:fa-database Database"] identityProvider["Identity Provider<br>(e.g. Keycloak/Azure Ad)"] container <--> |eCR FHIR Data| blobStorage container <--> |eCR Metadata| metadata container -->|Validates User| identityProvider end user --> nbs nbs -->|<code>/view-data</code><br>eCR Viewer<br>Authenticated by NBS| container user -->|<code>/view-data</code><br>eCR Viewer<br>Authenticated by identity provider| container user -->|<code>/</code><br>eCR Library<br>Authenticated By identity provider| container ingestion -->|<code>/api/process-ecr</code>| container
    %%{init:{"theme":"default"}}%% flowchart LR user nbs["NBS - View eICR"] ingestion["Ingestion Service<br>(e.g. Rhapsody)"] subgraph service[Cloud] direction TB subgraph container["fab:fa-docker container"] viewer["fab:fa-node fab:fa-react <code>ecr-viewer<br>HTTP:3000/</code>"] end blobStorage["fab:fa-file Blob Storage"] metadata["fab:fa-database Database"] identityProvider["Identity Provider<br>(e.g. Keycloak/Azure Ad)"] container <--> |eCR FHIR Data| blobStorage container <--> |eCR Metadata| metadata container -->|Validates User| identityProvider end user --> nbs nbs -->|<code>/view-data</code><br>eCR Viewer<br>Authenticated by NBS| container user -->|<code>/view-data</code><br>eCR Viewer<br>Authenticated by identity provider| container user -->|<code>/</code><br>eCR Library<br>Authenticated By identity provider| container ingestion -->|<code>/api/process-ecr</code>| container
    flowchart LR
      user
      nbs["NBS - View eICR"]
      ingestion["Ingestion Service<br>(e.g. Rhapsody)"]
      subgraph service[Cloud]
        direction TB
        subgraph container["fab:fa-docker container"]
          viewer["fab:fa-node fab:fa-react <code>ecr-viewer<br>HTTP:3000/</code>"]
        end
        blobStorage["fab:fa-file Blob Storage"]
        metadata["fab:fa-database Database"]
        identityProvider["Identity Provider<br>(e.g. Keycloak/Azure Ad)"]
    	container <--> |eCR FHIR Data| blobStorage
    	container <--> |eCR Metadata| metadata
        container -->|Validates User| identityProvider
      end
      user --> nbs
      nbs -->|<code>/view-data</code><br>eCR Viewer<br>Authenticated by NBS| container
      user -->|<code>/view-data</code><br>eCR Viewer<br>Authenticated by identity provider| container
      user -->|<code>/</code><br>eCR Library<br>Authenticated By identity provider| container
      ingestion -->|<code>/api/process-ecr</code>| container

    The full list of environment variables can be found in NodeJS.ProcessEnv. Below, you'll find more information about the groups of environment variables supported by the Viewer.

    Base required variables are ones required for all deployments regardless of mode or cloud environment. If variables are not set, this may cause issues starting the app. The variables can be found in EnvironmentVariables.BaseRequired.

    A storage container for the eCRs must be created for all deployments. Depending on the storage container used additional variables may be required. The variables can be found in EnvironmentVariables.EcrStorage.

    Authentication is required when running any mode of the application.

    Integrated eCR Viewer will rely on NBS to authenticate the user. The variables can be found in EnvironmentVariables.Authentication.

    Non-Integrated/Dual rely on an external authentication provider, like Azure AD, Entra, or Keycloak. The variables can be found in EnvironmentVariables.Authentication.

    Most /ecr-viewer/api/ routes require authentication to be used. The exceptions are pubic routes such as the health check and authentication routes. If a user has a logged in browser session (non-integrated auth only), they can use the developer console of that browser to emit authenticated post routes. More often, a machine will be making the post requests to upload data to the viewer. To enable this, we allow tokens to be sent on the Authorization header of request and used to authenticate the request.

    For integrated auth, the token will be generated via a key pair, similar to how it is done for authentication to the /view-data page, but using a different private/public key pair. See EnvironmentVariables.Authentication for where to set the public key.

    For non-integrated auth, the token must be generated by the IDP service, typically using a service principal. The token will be validated using the authentication provider set up in EnvironmentVariables.Authentication.

    Non-Integrated/Dual require a database to store eCR metadata. The variables can be found in EnvironmentVariables.EcrMetadataStorage.

    These are variables that have been retired and no longer have a use in the app. These can be safely removed when installing the current version.

    Name Description Version Removed
    SQL_SERVER_HOST Replaced with DATABASE_URL 3.1
    SQL_SERVER_PASSWORD Replaced with DATABASE_URL 3.1
    SQL_SERVER_USER Replaced with DATABASE_URL 3.1

    A database user must be created and the credentials set in the corresponding environment variables described here EnvironmentVariables.EcrMetadataStorage. This user must have standard privileges (select, update, delete) as well as the ability to create and alter schemas and tables. All database setup after that point is handled via migrations performed by Kysely. If the latest migration has not been run the eCR Viewer will log an error and display an error page to the user. Migrations only need to be run once to bring the database up to date, even if there have been multiple updates added since your most recently installed version. They must be triggered manually by calling the /migrate-db endpoint. The migration secret required for this step may be set via the METADATA_DATABASE_MIGRATION_SECRET environment variable, but if it is not set then the eCR Viewer will generate a secret and output it to the server logs both at startup and when a request is made to the API without a valid secret included.

    Additionally, the optional field init_admin_email should be included when initializing the database in order to add an admin user for the first time. Please see the "User and Program Area Setup" section for more details.

    curl --location '<DIBBS_URL>/ecr-viewer/api/migrate-db' \
    --header 'Authorization: Bearer <TOKEN>'
    --form 'migration_secret=<your migration secret>' \
    --form 'init_admin_email=<email>'

    Data can be added to the eCR Viewer as a step in Rhapsody.

    See our Rhapsody examples for more information on using Rhapsody to load data with different configurations of the eCR viewer.

    Data can be added directly via API requeset to eCR Viewer's /process-ecr endpoint. See the API documentation for more details.

    # zip file
    curl --location '{URL}/ecr-viewer/api/process-ecr' \
    --form 'ecr=@"/path/to/eicr.zip";type=application/zip'
    # string contents
    curl --location '<DIBBS_URL>/ecr-viewer/api/process-ecr' \
    --form 'ecr=<"<PATH_TO_ECR_FILE>"' \
    --form 'rr=<"<PATH_TO_RR_FILE>"'

    Before using the app, you must initialize the database with an admin account. When making a POST request to the /migrate-db endpoint (see above), include the init_admin_email field in the form to designate which user (by email) should be granted admin access. This email must correspond to a real user in your IDP (e.g., Keycloak).

    Once initialized, your IDP handles authentication. The user with the email provided in init_admin_email will have admin privileges and can log in to the app set up further users.

    Admins: Have full access to manage program areas, user accounts, and to view all eCRs in the eCR Library.

    1. Program Area Management
    • Can create, edit, and delete program areas.
    • Each program area must have at least one condition, and each program area name must be unique.
    • A condition cannot belong to more than one program area.
    1. User Management
    • Can create, edit, and delete users.
    • Users must have unique emails and standard users should be added to program areas to be able to view any eCRs.
    • Deleting users will only remove them from the User management table and remove them from all assigned program areas, but will not delete them from the database and instead mark them as "deleted".
    1. Access
    • Can access both the User Management and Program Management pages.
    • Can access all eCRs in the eCR Library.

    Standard users: Have limited access to eCRs based on their assigned program areas.

    • Can view eCRs whose reportable conditions are included in their list of assigned program areas