# SanteSuite Help Portal

Welcome to the SanteSuite Help Portal!

Welcome to the SanteSuite help portal. This portal provides detailed information about the design, configuration and operation of the SanteSuite family of products.&#x20;

{% hint style="info" %}
This site is a living document, and the documentation often changes. If you'd like to participate, documenting SanteDB code or creating help manuals on this site, please let us know!
{% endhint %}

### What is SanteSuite?

SanteSuite is the collection of software solutions built upon the highly scalable and standards compliant SanteDB Clinical Data Repository (CDR). SanteSuite is designed to operate in an "offline-first" fashion, ideal for frequently disconnected, geographically disperse or low-resource environments. SanteSuite products are also platform agnostic and can be run using common open source infrastructure. SanteSuite solutions provide key digital health infrastructure components for regional or national health systems such as Master Patient/Person Index (MPI) (sometimes known as Client Registry), Master Facility Index (MFI), Master Provider Registry (MPR), National Health Identity Management and Immunization Management Systems (IMS).&#x20;

### What is SanteDB?

SanteDB is a general purpose clinical data repository based loosely on the HL7 Reference Information Model (RIM) which we call the Reduced Reference Information Model (RRIM). SanteDB's CDR has four major platform components:

* iCDR - A centralized service for managing data from clinics, tablets, etc. The iCDR provides an implementation of the Reference Information Model (RIM) and offers robust features such as an OAUTH IdP, Audit Repository, versioning, master data management, etc.
* dCDR - We call this one a "baby CDR", and provides disconnected access to SanteDB's functions. The dCDR operates completely on its own and offers almost 75% of the functionality of the iCDR. It is the same implementation of the RIM-based information model, and can operate many of the plugins which are developed for the iCDR.&#x20;
* dCDR Gateway - The **Disconnected Gateway** is a specialized version of the dCDR which combines plugins for HL7v2, ATNA, (and in the future FHIR) and allows clinics who are using third party software such as OpenMRS or OSCAR to leverage dCDR features with standards based interfaces.&#x20;
* Android / Windows / Linux Apps - These applications are built on the dCDR and provide an extensible user interface platform based on HTML5 and JavaScript. By default, AngularJS is the bundled UI framework, however these applications (and applets) may override this and implement their own interfaces to SanteDB's dCDR services.

## Topics

{% content-ref url="/pages/u7zir3iBTIiNXFWhXmlI" %}
[Product Overview](/product-overview/santesuite-products)
{% endcontent-ref %}

{% content-ref url="/pages/-LZBNtZENgNDNP3oXPQF" %}
[Architecture](/santedb/architecture)
{% endcontent-ref %}

{% content-ref url="/pages/-LZqIPeYP52pYSmIJjPs" %}
[Operationalizing SanteDB](/installation/installation-1)
{% endcontent-ref %}

{% content-ref url="/pages/1dPRYMBlcBLGP0ddijYH" %}
[Operations](/operations/santedb-operations)
{% endcontent-ref %}

{% content-ref url="/pages/Si8SWdtwBR8su3JfK52M" %}
[User Guides & Training](/user-guides-and-training/santedb-user-guides)
{% endcontent-ref %}

{% content-ref url="/pages/f6VyCdlPlATqED8DQK7G" %}
[Developers](/developers/extending-santesuite)
{% endcontent-ref %}

{% content-ref url="/pages/-La7y4IKCf\_fhUYT78bN" %}
[Knowledgebase](/knowledgebase/sdb-kb)
{% endcontent-ref %}

{% content-ref url="/pages/-Le6mcRriam6Zd2CbGzY" %}
[OpenIZ](/openiz/about-openiz)
{% endcontent-ref %}


# Disclaimer

Disclaimer and Consent

## Disclaimers for SanteSuite Inc.

All the information on this website is published in good faith and for general information purpose only. SanteSuite Inc. does not make any warranties about the completeness, reliability or accuracy of this information. Any action you take upon the information you find on this website and/or in related documents is strictly at your own risk. SanteSuite Inc. will not be liable for any losses and/or damages in connection with the use of the content.

## Consent

By using our website and/or related content, you hereby consent to our disclaimer and agree to its terms.&#x20;

## Licenses

Unless otherwise noted, linked from another author, or hosted/linked on a third party site - all content on this site is licensed under the Creative Commons Share-alike + Attribution (CC-BY-SA) 4.0 license. \
\
![](/files/2sTLRZg1DL4s7ZHGQG09)

For more information see - [Creative Commons — Attribution-ShareAlike 4.0 International — CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)


# SanteSuite Products


# Introducing SanteDB CDR

This section provides documentation related to the SanteDB Clinical Data Repository (CDR) and related technologies.

### What is SanteDB?

SanteDB is the foundational clinical data repository (CDR) developed by SanteSuite Inc. and leveraged by SanteSuite products. SanteDB is standards-based and highly scalable and is designed for large-scale (regional and national) digital health application deployments.&#x20;

SanteDB forms the core of the SanteSuite product line and provides a robust, secure, repository for modeling and sharing clinical data.

![Figure 1 - SanteDB and SanteSuite](/files/-LZtldi4bxbpwXX-S2_B)

### Features

Although each of the products built upon SanteDB provide the most clinical value, the platform itself provides the fundamental building blocks required to create disconnected, intelligent health applications. Features of SanteDB include:

* Openness
  * 100% Open Architecture, any application can play in the SanteDB ecosystem.
  * Core platform components and community applets are openly documented and source code provided.
* Private & Secure
  * Privacy and security architecture based on XACML building blocks (though XACML is not used)
  * Authentication of application, device and users
  * Break the glass and permission override supported
  * Full auditing on all platform components (even disconnected clients)
* Intelligent Services
  * Full decision support system provided for expressing care protocols and composing care plans.
  * Business rules can be customized using data triggers
  * Full reporting / ad-hoc warehouse available for custom reports
* Integrated
  * Integrated with a variety of services to assist operationalization
    * Integrated bug submission and tracking with Atlassian JIRA
    * Integrated SMS delivery with Twilio
  * Open interfaces provide 1:1 function access to underlying functionality.
* Interoperable
  * Supports HL7 v2.5 and provides customization interfaces for messages
  * HL7 FHIR STU3 support on select resources
  * Select support for GS1 BMS XML 3.3 (over REST or AS.2)
  * Support for IHE ATNA (RFC 3881 or DICOM)
  * OPENID Connect / OAUTH 2.0 compatible authentication services (password, client\_credential, authorization\_code and refresh grants) with JWT identity tokens


# SanteDB Solutions

The SanteDB Clinical Data Repository (CDR) is designed for large-scale regional/national digital health applications. Solutions running on SanteDB may be deployed in dozens, hundreds or even thousands of clinics across a widespread region. In these scenarios, there will be times where individual clinics or points of service will lose connectivity, and this is especially true in geographically sparse and/or low resource environments. SanteDB was designed from the ground up to support this highly distributed scenario and is equipped with a robust synchronization engine that allows individual clinics to go online and offline as they require, while still allowing users to continue to work in their applications without being uninterrupted and without losing any clinical data. When clinics are able to re-establish connectivity, all transactions are synchronized seamlessly between local data stores and the central repository. Each remotely deployed application instance (for example in a clinic, mobile, or anywhere "out on the field") maintains a local version of SanteDB referred to as the distributed clinical data repository or "dCDR". The main central clinical data repository is referred to as the integrated clinical data repository or "iCDR". There is no predefined limit as to how long dCDR apps are able to work offline before they reconnect with the iCDR.    &#x20;

SanteDB solutions run on top of the CDR and are pre-configured, pre-packaged plugins which extend SanteDB to provide a solution to a clinical problem. SanteDB has several solutions targeted to individual clinical domains and use cases, including national health identifiers, master patient index/client registry solutions, national immunization planning and tracking solutions, a distributed EMR and more. The following diagram illustrates how applications make use of SanteDB by extending the base functionality of the SanteDB Core:&#x20;

![](/files/-MOJDZrGFoqRt098gyrk)

* **SanteGuard** : The SanteGuard solution is a complete audit repository solution. The SanteGuard solution contains:
  * .NET Based Plugins for the SanteDB dCDR and iCDR which allow SanteDB to accept IHE ATNA messages.
  * Applet Widgets which extend the other SanteDB solution user interfaces to add detailed auditing information for system administrators.
  * Extended data storage schemas and plugins to store information related to audit log review workflows.
* **SanteEMR** : The SanteEMR solution is a framework which provides basic EMR functionality such as scheduling, registration, patient management, clinical templates, etc. Included:
  * Patient Registration and Search Management Workflows
  * Clinical Templates for birth, death, and basic primary care events.
* **SanteIMS** : The SanteIMS solution provides extended user interfaces and clinical protocol support related specifically to immunizaiton clinics. Included in SanteIMS:
  * Stock management functionality including adjustments, current balances, and order/fulfillment
  * Pre-built clinical decision support related to immunization activities.
* **SanteMPI** : The SanteMPI solution provides a combination of pre-configured plugins for the SanteDB CDR to work as an MPI. Inlcuded:
  * .NET based plugins which modify the behavior of the HL7v2 and FHIR interfaces to implement IHE PIX, PDQ constraints.
  * Plugins for name aliasing&#x20;

These solutions provide a basis for community extensions to create branded versions of the underlying applications.


# Master Patient Index - SanteMPI

This section describes the SanteSuite Master Patient Index SanteMPI

SanteMPI is a next generation, fully functional, open-source and standards-compliant Client Registry that was originally developed to support the Canadian national digital health program beginning in 2006. SanteMPI has been enhanced and refined over decades of investment from governments, private sector companies and non-governmental organizations. SanteMPI has been designed to support the longitudinal management of patient data in jurisdictions around the world and has several proven field deployments in low and middle income countries.

A Master Patient Index (MPI), sometimes called a Client Registry (CR), is a foundational piece of any regional or national health system. Fundamentally, a MPI solution seeks to create a single master list of patients across a jurisdiction and to provide a cross-reference of the various identifiers used by local systems in a region to identify a patient. For example, if a patient is registered in Hospital A as patient number 123 and is registered in Primary Clinic B as patient number 456, a Master Patient Index configured in the region will keep track of these various identifiers and provide a list of them to any system on demand. This enables health care providers to see a "longitudinal view" of a patient, that is, all interactions of the patient with various components of the health care system over time.&#x20;

SantéMPI is a fully functional, national scale, open-source, and standards-compliant Master Patient Index (MPI) / Client Registry (CR) designed for regional and national health system use. SantéMPI was originally developed as a reference implementation to support the Canadian national digital health program administered by Canada Health Infoway ([infoway.ca](http://www.infoway.ca)) beginning in 2006. SantéMPI has been enhanced and refined over decades of investment from various government agencies, private sector companies and non-governmental organizations. SantéMPI has been designed to support the longitudinal management of patient data in jurisdictions around the world and has several proven field deployments in low and middle income countries. SantéMPI has proven to be secure, scalable, reliable, performant, fully featured, standards-compliant, inexpensive and easy to support.

The SantéSuite team that developed SantéMPI have also made significant contributions to the underlying international standards used for MPI/CR systems, including the HL7 v2/v3 and HL7 FHIR standards, the OpenHIE Architecture Specification Client Registry solution, and the IHE patient identity mobile profiles (PIXm and PDQm). These contributions have enhanced the standards to allow for the efficient unique identification of patients even while using low resource mobile devices.

SantéMPI implements all existing interoperable specifications and requirements related to Client Registry in the OpenHIE specification. SantéMPI is fully compliant to operate within a health information exchange (HIE) environment as a Client Registry. SantéMPI has been field tested with millions of successful transactions in multiple jurisdictions, and can operate standalone or as a launching point into a health information exchange. By implementing both modern HL7 FHIR standards and the widely deployed existing legacy HL7v2 standards, SantéMPI provides a platform for integrating existing solutions and future solutions. In this context, SantéMPI has demonstrated integrations with WorldVistA EHR, OpenMRS and OSCAR EMR.

SantéMPI leverages the unique online/offline capability and data architecture of SantéDB by building on our lessons learned developing and implementing the MEDIC CR, especially in low resource environments. SantéMPI meets the stated functional requirements of the OpenHIE Specification for a client registry. Key features of SantéMPI that directly address these requirements include:

Online/Offline Capability – Leveraging SantéDB’s Disconnected Clinical Data Repository (dCDR), SantéMPI is unique in being able to operate offline when and where needed via an online/offline MPI gateway to/from a centrally hosted server or cloud hosted CR service. Clients on the offline gateway can use HL7 v2.5 or HL7 FHIR to perform MPI functions while offline. This offline capability has been proven to be incredibly important in low resource environment where brownouts, blackouts and lack of connectivity situations are commonplace.

Privacy & Security by Design – SantéMPI leverages the SantéDB CDR, which implements a robust privacy and security solution allowing for access control and privacy controls based on role, device, and third-party application via a policy based access control scheme. Security and Privacy are designed into the solution, not bolted on as an afterthought.

Interoperability Standards Support – SantéMPI supports a variety of standards for patient registration including IHE PIX/PDQ (for HL7v2) and HL7 FHIR. It also provides a completely open API for further extension. The SantéSuite team has made significant contributions to health information standards, including being early contributors to HL7 FHIR, as well as authoring the IHE profiles for mobile access to patient identifiers and this platform has previously passed IHE and HL7 Connectathons.

Probabilistic Matching – SantéMPI leverages a customizable record linkage algorithm for detecting whether two or more existing records are the same.

Master Data Management – SantéMPI provides basic master data management functionality, allowing a single record of truth to be synthesized from data submitted from local sources.

Administration Management – SantéMPI provides extensive administrative user interfaces to provide a robust administrative solution.

Mobile Registration App – A mobile registration app has been developed to support search and registration of patients in real time in the field, offering the ability to issue a health identifier to a new client. This app also leverages QR codes as temporary health identifier for easy generation and recognition of a health identifier.

SanteMPI bundles together existing functions of SanteDB (MDM, Matching, Entity Linking, etc.) and exposes additional logic on top of those interfaces to ensure it is a PIX/PDQ compliant product. SanteMPI works in both the SanteDB iCDR and the dCDR, that's right, you can run a mini-MPI offline in a local clinic between systems.

## Related Topics

{% content-ref url="/spaces/-LZ0\_pjgTp\_kx4hqTZ3a/pages/-LitL86ymvp4p8KqZj8M" %}
[SanteDB Architecture](/santedb/architecture)
{% endcontent-ref %}

{% content-ref url="/spaces/-LZ0\_pjgTp\_kx4hqTZ3a/pages/-LZqIPeYP52pYSmIJjPs" %}
[Operationalizing SanteDB](/installation/installation-1)
{% endcontent-ref %}

{% content-ref url="/spaces/-LZ0\_pjgTp\_kx4hqTZ3a/pages/n0HwBktYJrbuPjIQsEGK" %}
[SanteMPI](/user-guides-and-training/santempi)
{% endcontent-ref %}


# Immunization Management System - SanteIMS

SantéIMS, a Digital Public Goods Alliance (DPGA) nominated “global good” (<https://digitalpublicgoods.net/registry/>), is a proven, purpose-built, person-centered, national-scale immunization management platform that supports planning, end-to-end delivery and realtime reporting of any type or scale of mass vaccination program. SantéIMS comes pre-configured with the standard WHO vaccine schedule but can be configured for any type of program, such as pandemic response for COVID-19 vaccination or HIV inoculation. Its unique, fully integrated design and functionality automates end-to-end vaccination workflows, decision support, and stock management, while at the same time seamlessly automates immunization data feedback loops, aggregate reporting and analytics from local clinic to regional and national levels and beyond. This complete, dedicated vaccination workflow solution has demonstrated significant improvement in efficiency of administering vaccine clinics, simplifies training requirements for staff operating a clinic, speeds up interactions with patients and provides a near real-time national dashboard view of vaccination activity from local clinic to regional and national levels. A purpose-built immunization system such as SantéIMS also enables the implementation of advanced clinical workflows, clinical decision support rules and computable guidelines not often found in general purpose EMRs.

SantéIMS comes pre-configured with the complete WHO vaccine schedule as default, however the schedule and clinical guideline rules are completely customizable to local country or regional needs. SantéIMS supports new clinical workflows such as COVID-19 protocols and can easily be configured support emerging immunization workflows such as HIV and malaria. SantéIMS’s first version (OpenIZ) was funded by PATH ([www.PATH.org](http://www.PATH.org)) in 2016 as part of the Better Immunization Data (BID) initiative and is currently nationally deployed in Tanzania as the Tanzania Immunization Registry (TImR).


# Privacy & Security - SanteGuard

SanteGuard is a centralized audit and security repository which is compatible with SanteDB products and as well as any product using OAUTH and IHE ATNA.

## What is SanteGuard?

SanteGuard is a plugin to SanteDB that integrates a powerful audit trail into the SanteDB system. SanteGuard provides several system interfaces, user interfaces, reports, and an enhanced implementation of the IAuditRepository service. At a high level, SanteGuard:

* Allows SanteDB to receive Audit events from external systems using IETF RFC3881 or NEMA DICOM format audits over SYSLOG (TCP, UDP, and STCP).
* Allows SanteDB to receive Audit events over HTTP using the IETF RFC3881 or DICOM audit format (POX service)
* (Future) Allows SanteDB to receive Audit Events using HL7 FHIR
* Stores additional information about audits not captured in the default SanteDB audit repository such as SIEM attribute son the incoming Syslog message, versioning of audit events, etc.
* Adds several "widgets" to key areas of SanteDB (the patient summary screen for example) which allow administrators to quickly identify who has been accessing a particular patient's data.
* (In-Progress) An enhanced audit repository dashboard.

## Related Topics

{% content-ref url="/spaces/-LZ0\_pjgTp\_kx4hqTZ3a/pages/tCLiaUwAA82pGGJMgFn2" %}
[Reviewing Audits](/operations/cdr-administration/santedb-administration-panel/security-administration/reviewing-audits)
{% endcontent-ref %}

{% content-ref url="/spaces/-LZ0\_pjgTp\_kx4hqTZ3a/pages/AIwFa93GyDS287tiDeus" %}
[SanteGuard](/user-guides-and-training/santeguard)
{% endcontent-ref %}


# SanteDB Versions

SanteDB releases have two versions associated with them:

* Semantic Version -> Which is used for determining compatibility of assemblies within the SanteDB solutions, dependencies, etc.
* Informational Version -> Which is used to describe the overall release.

## Versioning Information (1.x and 2.x)

### Semantic Versions

The semantic versions of SanteDB look similar to this:

```
[major].[minor].[revision].[build]
```

Where:

* **Major:** Describes the major release.&#x20;
  * ***Even*** numbered major versions are release versions
  * ***Odd*** numbered major versions are development versions between releases
* **Minor:** Describes the overall patch level within the particular version of SanteDB
* **Revision:** Is used to describe patch level. These are usually random (but increasing) values.

### Legacy Versions (1.x)

SanteDB originally was implemented as a revision of the core OpenIZ backend. This was implemented on .NET Framework 4.5.2, Xamarin and PCL Profile7 assemblies. These versions begin with the major revision 1.x , ending 1.128.0 (Iqaluit).

Since PCL has been deprecated for some time, a refactor of the code to .NET Standard 2.0 was recently performed.

### .NET Standard Versions (2.x)

Starting with SanteDB named version Jasper , the entire shared assembly infrastructure has been ported to .NET Standard 2.0. Since these assemblies are incompatible with the PCL infrastructure and .NET 4.5.2,  the entire project was upgraded to .NET 4.7 and the major version rev'd to 2.x series.&#x20;

{% hint style="info" %}
We're still in the process of updating our documentation to reflect this change of underlying frameworks.
{% endhint %}

### Version 3.0&#x20;

SanteDB version 3.0 and its related solutions (SanteMPI 3.0, SanteIMS 3.0, SanteEMR 3.0) have many enhancements which improve the efficiency and maintainability of SanteDB products. These features are documented in detail throughout the wiki and tagged with:

{% hint style="info" %}
This Page Documents a feature in SanteDB v3.0
{% endhint %}

In summary the enhancements are detailed in [3.0 Releases](/installation/releases/3.0-releases)


# SanteDB Architecture

This page provides a summary of the SanteDB architecture. A more detailed description of this architecture can be found in the SanteDB Functional Design Specification (<http://santesuite.org/assets/uploads/sdb-arch-1.11.pdf>)

## Overall Architecture

A general overview and introduction to SanteDB is provided [here](/product-overview/santesuite-products/santedb/santedb-solutions).&#x20;

SanteDB is a comprised of several software components which operate together to form the basis of a cohesive digital health infrastructure.&#x20;

![](/files/-LitLhslaCOQi3qkkcnk)

## iCDR Server

The iCDR server is the central integrated clinical data repository which is used to coordinate the many connected clients in an implementation. Typically an implementation of SanteDB will only ever have one logical iCDR instance (i.e. many physical servers are often deployed for scalability however the logical grouping of iCDR servers is acting as a single iCDR).

The primary responsibilities of the iCDR are:

* Maintain a master dataset for the entire deployment of SanteDB in a particular health role.
* Facilitate the synchronization and sharing of data between sites within the deployment.
* Integrate with upstream services such as audit repositories, client registries, etc.
* Distribute "over the air" (OTA) software updates to connected clients and apps
* Provide a centralized authentication and privacy information distribution point.

## dCDR Clients

The dCDR clients are the disconnected clients which connect to the central iCDR and are typically embedded in applications used by clinics or mobile applications used by end users. The term dCDR client is used loosely to describe any client which is implemented on the dCDR technology. dCDR clients are deployed in data centers, in clinics, on tablets, etc. A deployment of SanteDB will have multiple, potentially hundreds or thousands of, dCDR clients.

No matter the implementation, the dCDR clients are primarily responsible for:

* Providing offline access to relevant subsets of data synchronized and replicated from the central iCDR server
* Caching centralized credentials, and providing local clinic-level authentication
* Serving out the user interface, reports, and other end-user facing elements
* Providing a federation point for other dCDR instances
* Executing data quality checks, business rules, clinical decision support rules, etc. while the central iCDR server is not available

### dCDR Android Application

The dCDR Android Application is an implementation of the dCDR services on the Google Android operating system. The dCDR Android application is used whenever tablet or phone users will require access to the SanteDB infrastructure while operating on poor/slow/unavailable cellular internet connections.

The dCDR Android application only exposes the user interface services, offline gateway services such as FHIR, HL7v2, and ATNA are disabled, as is off-host UI access. When the Android host process launches the dCDR service core, it generates a unique secret for that application run, and expects this in the `SDB-Magic` header on all requests.

### dCDR Windows / Linux Applications

The dCDR Windows and Linux applications are self-contained applications which run the SanteDB user interface, and provide a known web-browser component to render them. Like the Android client, these desktop applications disable all API access and generate unique key which is shared between the web-view control and the dCDR services, and is required to access those services.

### dCDR Gateway

The dCDR Gateway is a network service which implements the dCDR functionality and is intended for use in environments where third party applications (or users in a shared local network) require access to offline functionality.&#x20;

The dCDR Gateway exposes FHIR, HL7v2, ATNA, and API calls to any connected client on a local network. The Gateway provides the services of a SanteDB iCDR instance, where clients connected on the local network have no knowledge of the overall connectivity of the clinic or environment they're operating within. This allows applications to continue to operate in local clinic environments even when connectivity to the iCDR is not available.&#x20;

{% hint style="info" %}
Care should be taken in planning the local network security environment when using the dCDR gateway.
{% endhint %}

### dCDR Web Portal

The dCDR Web Portal is a specialized dCDR environment which has no offline capability. It is primarily designed to operate as a daemon and to serve out, on the internet, the user interfaces directly connected to the central iCDR. This is the technology used to host the administrative panels, any shared/central infrastructure, etc.

## Topics

{% content-ref url="/pages/uyhcrDEWXBWrilxH3Dk7" %}
[Broken mention](broken://pages/uyhcrDEWXBWrilxH3Dk7)
{% endcontent-ref %}

{% content-ref url="/pages/-MN31G-kle1bTxoVMHI-" %}
[Software Architecture](/santedb/software-architecture)
{% endcontent-ref %}

{% content-ref url="/pages/-LrVCqMU7uvi2pidWnMQ" %}
[Data & Information Architecture](/santedb/data-and-information-architecture)
{% endcontent-ref %}

{% content-ref url="/pages/-MFla\_YxU1vKxg\_XUEuf" %}
[Security Architecture](/santedb/security-architecture)
{% endcontent-ref %}

{% content-ref url="/pages/-MYD52LcR-11YKpuBDnj" %}
[Privacy Architecture](/santedb/privacy-architecture)
{% endcontent-ref %}


# SanteDB History

This page describes the history of the SanteDB project.

SanteDB is the evolution of a reference implementation of the Canadian national digital health platform that originated in a post-secondary institution research lab beginning in 2007. SanteDB was designed with national scale, standards-based digital health applications in mind from the beginning.&#x20;

The SanteDB suite of products incorporates the full functionality of previous research products such as the MEDIC CR client registry and the OpenIZ immunization management system into a deployment-ready, commercially supported package. A brief summary of the evolution of the products is provided in the following section. &#x20;

## Evolution of SanteDB

SanteDB is really an evolution of OpenIZ ([http://openiz.org](http://openiz.org\\)) which itself was an evolution of the MARC-HI SHR RI. The table below illustrates the relative features of each solution.

| Feature                                          | MARC-HI SHR RI                                         | OpenIZ                                                 | SanteDB iCDR                                                                  |
| ------------------------------------------------ | ------------------------------------------------------ | ------------------------------------------------------ | ----------------------------------------------------------------------------- |
| **Platform Information**                         |                                                        |                                                        |                                                                               |
| Original Release Year                            | 2011                                                   | 2016                                                   | 2019                                                                          |
| MARC-HI Service Core Generation                  | V1                                                     | V2                                                     | N/A                                                                           |
| Technologies / Frameworks                        | .NET 2.0                                               | .NET 4.0, Xamarin, AngularJS 1.5                       | .NET 4.5, Xamarin, AngularJS 1.7                                              |
| Primary Role(s)                                  | Clinical Data Repository (CDR)                         | Electronic Immunization Record (EIR)                   | Clinical Data Repository (CDR)                                                |
| **Deployment / Operationalization**              |                                                        |                                                        |                                                                               |
| Server Environment(s)                            | Windows Server 2003+                                   | Windows Server 2008R2+                                 | Windows Server 2008R2+, Linux, MacOS                                          |
| Client Environments                              |                                                        | Android 4.4+, Windows 7+, Linux, MacOS                 | Android 5.0+, Windows 8+, Linux, MacOS                                        |
| RDBMS Support                                    | PostgreSQL 9.2                                         | PostgreSQL 9.4, SQLite, MSSQL 2008+                    | PostgreSQL 10, FirebirdSQL 3.3, Oracle 11g,   SQLite                          |
| Scale-Out                                        | DB: Streaming Replication, App Server: Round-Robin DNS | DB: Streaming Replication, App Server: Round-Robin DNS | DB: Streaming Replication,  App Server: Round-Robin DNS, Role-Based Scale-out |
| **Information Model**                            |                                                        |                                                        |                                                                               |
| Model                                            | Component Model                                        | HL7 RIM                                                | HL7 RIM                                                                       |
| Encounters                                       |                                                        | X                                                      | X                                                                             |
| Substance Administrations                        | X                                                      | X                                                      | X                                                                             |
| Observations                                     | X                                                      | X                                                      | X                                                                             |
| Clinical Procedures                              | X                                                      |                                                        | X                                                                             |
| Finance (Account, Invoice, etc.)                 |                                                        |                                                        | X                                                                             |
| Patient Administration                           |                                                        | X                                                      | X                                                                             |
| Administrative Units (Place, Organization, etc.) |                                                        | X                                                      | X                                                                             |
| Versioning                                       | X                                                      | X                                                      | X                                                                             |
| **Extendibility**                                |                                                        |                                                        |                                                                               |
| Clinical Decision Support Engine                 |                                                        | X                                                      | X                                                                             |
| Business Rules / Data Triggers                   |                                                        | X                                                      | X                                                                             |
| Plugins (.NET)                                   | X                                                      | X                                                      | X                                                                             |
| **Security / Accountability**                    |                                                        |                                                        |                                                                               |
| ACL Paradigm                                     |                                                        | Policy-Based                                           | Policy Based w/Override                                                       |
| Authentication Methods                           | X509 PKI                                               | OAUTH, HTTP BASIC                                      | OAUTH, HTTP-BASIC, X509 PKI                                                   |
| Auditing                                         | RFC3881                                                | RFC3881, NEMA DICOM                                    | RFC3881, NEMA DICOM, HL7 FHIR STU3                                            |
| **Standards & Interoperability**                 |                                                        |                                                        |                                                                               |
| HL7v2.x                                          | X                                                      | X                                                      | X                                                                             |
| HL7v3                                            | X                                                      |                                                        |                                                                               |
| HL7 CDA                                          | X                                                      |                                                        |                                                                               |
| HL7 FHIR                                         | DSTU1                                                  | DSTU2                                                  | R3                                                                            |
| Other Interfaces                                 |                                                        | GS1 BMS XML 3.3                                        | GS1 BMS XML 3.3                                                               |
| **Optimization / Extra**                         |                                                        |                                                        |                                                                               |
| HTTP Compression                                 | Responses Only                                         | Bi-Directional BZ2, GZ, DF, LZMA                       | Bi-Directional BZ2, GZ, DF, LZMA                                              |
| Data Caching                                     | Memory Cache Only                                      | Memory Cache, REDIS                                    | Memory Cache, REDIS                                                           |
| Matching / Merging Engine                        |                                                        |                                                        | Probabilistic Matching Engine                                                 |
| Master-Data-Model Management                     |                                                        |                                                        | X                                                                             |
| Reporting                                        | 3rd Party                                              | Jasper Reports, ReportR 1.0                            | ReportR 2.0                                                                   |


# Solution Architecture

There are a variety of ways in which SanteDB can be deployed within your architecture. You can use any of the SanteDB technologies to fill any one of a number of logical roles within your broader e-health strategy.

This page discusses the ways in which SanteDB can be operationalized. It is important to note that these patterns can be mixed, as they leverage common user interface and messaging frameworks.

## Online Only Patterns

### Interoperable Registry

You can deploy many of the SanteDB solutions to operate as a standalone interoperable registry / repository of information. In this deployment pattern, SanteDB is used as a headless repository of information and user-facing interaction is provided by third party applications which connect to SanteDB using any one of the standards supported by SanteDB.

In this deployment, the iCDR interface can be interacted with directly (as shown below) or can operate with an intermediary such as EAI/ESB engine.

This model is most effectively used when leveraging SanteDB within a single organization, or within a single site (like a hospital). You can also leverage this solution over the internet, however it is recommended laying the iCDR infrastructure behind an application firewall or integration services.&#x20;

![SanteDB Operating as an Interoperable Repository/Registry](/files/-M9jXE4FL-KppmUDanBw)

Examples of third party applications which may integrate with the iCDR engine may include:

* Logistics Management Information Systems (LMIS)  using the GS1 BMS XML interfaces
* Electronic Medical Records (EMR) Systems using the HL7 Version 2x or HL7 FHIR interfaces
* Personal Health Records (PHR) using the HL7 FHIR interfaces
* Mobile Applications using the HL7 FHIR interfaces
* Any connected system requiring central authentication using the OpenID Connect interface
* Hospital Information Systems (HIS) using the HL7v2 or FHIR interfaces
* Picture Archiving Communication Systems (PACS) using HL7v2 interfaces

### Online Clinical Portal

In this deployment pattern SanteDB's iCDR is bundled with a web portal solution which allows end-users to directly leverage the SanteDB iCDR features using a web browser.&#x20;

This solution is most useful when you have robust internet infrastructure and users can easily access internet based resources.

![](/files/-M9jZ5TMR56KLIexySo5)

## Disconnected / Offline Patterns

### Disconnected Registry

In this deployment pattern, SanteDB acts as a disconnected integrator and CDR for solutions that otherwise lack the ability to interoperate in a disconnected way.

&#x20;Here, end users within the clinic use already existing software tooling that they are familiar with. These third party systems communicate with the SanteDB dCDR which has been configured to synchronize with the central iCDR interface using a variety of subscription methods.&#x20;

These clinic systems may require no additional software updates, since the dCDR behaves like a remote endpoint using any one of the standards supported (HL7 v2, HL7 FHIR, etc.). Additionally, the dCDR will execute any business rules which have been configured from the central server while offline. The connection to the iCDR is not necessary to support the operation of the solution.

![](/files/-M9j_WZlmJJXDAk0q3Oj)

### Disconnected Clinical Portal

In this deployment, clinic users leverage the dCDR applications to directly interact with the iCDR interface in an online/offline manner, using the end-user portal written in the SanteDB UI framework.&#x20;

![](/files/-M9jb3VBn6UCPvoA8cIQ)

The software / portal use in this environment can be:

* Users using laptops/tablets within a single clinic connected to any configured dCDR instance operating in that clinic (for example, over Wi-Fi), the dCDR interface then communicates with the central iCDR.
  * Larger clinics with multiple users and devices
  * Clinics/Hospitals which require a mix of the user portal and third party applications.
* Users using the disconnected portal on an Android tablet or phone. The phone/tablet directly synchronizes its data with the iCDR interface when there is an available internet connection.
  * Community health workers that operate independently offline
  * Small clinics with only one staff member on one device giving care to patients at a time.
* Users using the Windows or Linux user interface. Here the portal operates as a self-contained application on the client and the laptop directly synchronizes with the central iCDR service.
  * Small clinics with only one staff member giving care to patients
* Users connecting using the Android application whereby they may operate in a clinic environment (Wi-Fi against the dCDR) or in the field (offline from the clinic's dCDR). This is a chained synchronization deployment pattern whereby the Android/Windows/Linux app synchronizes against a clinic dCDR, which in turn, synchronizes against the master.&#x20;
  * Larger clinic/hospitals where WI-FI may drop in areas of the clinic
  * Clinics which perform outreach programmes in the community

## Related Topics

{% content-ref url="/pages/-LitL86ymvp4p8KqZj8M" %}
[SanteDB Architecture](/santedb/architecture)
{% endcontent-ref %}

{% content-ref url="/pages/-LZqIPeYP52pYSmIJjPs" %}
[Operationalizing SanteDB](/installation/installation-1)
{% endcontent-ref %}


# Software Architecture

The SanteDB iCDR, dCDR and its related components are designed in a modular fashion. These modules are intended to maximize code reuse, and provide consistent services across the iCDR and dCDR environments.&#x20;

## Software Component / Services

The overall architecture of the SanteDB iCDR and dCDR repositories illustrated below along with some of the service classifications.

![](/files/-MNxkSJnYdYkXlIUJdCk)

## Service Architecture

There are two methods of using services in SanteDB:

* Service Locator Pattern (<https://en.wikipedia.org/wiki/Service_locator_pattern>) - Whereby service instances are located at runtime
* Dependency Injection Pattern (<https://en.wikipedia.org/wiki/Dependency_injection>) - Whereby services instances are injected into the class when constructed.

### Service Locator Pattern

SanteDB classically used the service locator pattern via the IServiceProvider instance called  the ApplicationContext. The application context is responsible for loading the appropriate implementation (or provider) of a particular strategy (or contract) based on the configuration of the environment.&#x20;

Take, for example, the auditing which is implemented as:

![](/files/-MN36hTG61_c5WUlg2pn)

Here, the SecretClass instance relies on the contract IRepositoryService, which may be implemented by an ADO.NET implementation, an RFC3881 implementation and a FHIR implementation. At runtime, when SecretClass wishes to send an audit, it will call the ApplicationServiceContext instance, which will return an appropriate implementation based on the runtime environment.

![](/files/-MN3765wOz0rz64PGBF4)

This means that the implementer of SecretClass doesn't need to worry about which audit service is being used, it merely executes the business function for auditing.

This service pattern, and the fact the solution is implemented in .NET Standard, means that most service implementations can be used in the iCDR and dCDR environments without re-compiling.

### Dependency Injection

Services can also use dependency injection pattern. In this pattern, the service's constructor defines the dependent services which are required for the service implementation to function. The ApplicationContext will inject the current service implementations into the instance on construction.

## Service Relationships

SanteDB's overall architecture is really a composition of services which have been configured by the developer of the SanteDB solution. For example, SanteMPI may have a different series of services configured to act as an MPI whereas SanteIMS will have different services configured to behave as an EIR (however the two would share services).

Most SanteDB services are implemented assuming a service relationship as illustrated below:

![](/files/-MN38ck4MHjwH8fn-9T9)

### Messaging Services

Messaging services represent the primary presentation layer for SanteDB. These services are responsible for:

* Handling transport layer security (authentication of clients, tokens, decrypting network traffic, etc.)
* Translating messages from a wire-level format (like HL7, FHIR, GS1) into the common information model (RIM)
* Performing auditing based on the requirements of the transport standard
* Translating responses into appropriate behaviors (like a NACK in HL7v2 or a 422 in HTTP)

### Auditing Services

The auditing services in SanteDB are responsible for facilitating the audit process. This process in SanteDB includes:

* Storing a local copy of the audit information within the SanteDB service (this is really a repository service)
* Shipping appropriate audits to centralized infrastructure as required

### Repository Services

In SanteDB, the repository service layer is responsible for the "behaviors", or the coordination activities to accomplish a particular task. Repository services:

* Ensure that the appropriate authentication context is established and used / shared
* Use the policy enforcement mechanism to demand appropriate permission to perform an action
* Call necessary business rule triggers for the action being executed
* Raise pre/post events which event listeners may use to perform extended behaviors (for example, the MDM layer is implemented in this manner)
* Interacting with the data persistence services to store/read data

Messaging services primarily interact with repository services as these services are responsible for abstracting the individual data layer calls.

### Policy Enforcement Services

The policy services in SanteDB consist of:

* Policy Information Service - Which stores information about security and data policies in SanteDB such as whether the policy can be overridden, and its place in the policy hierarchy.
* Policy Decision Service - Which determines appropriate access decisions (GRANT, ELEVATE, DENY) given a securable (the thing which is being done or acted on) and the principal (the user, app, and device being used).
* Policy Enforcement Service - Which takes appropriate actions based on the outcome of the policy decision made. This might be masking data, throwing an exception, etc.

{% hint style="info" %}
SanteDB is based on OpenIZ which was written in .NET PCL. This means some interfaces in SanteDB use declarative policy demands (via CAS) while others use imperative policy demands (via the IPolicyEnforcementService).&#x20;
{% endhint %}

### Business Rule Services

Business rule services are specialized interfaces which can be chained together and act on data before and after a repository service actions it. Business rule services are user defined behaviors and have the ability to:

* Validate an object before it is acted on
* Modify an object prior to an action (insert, update, etc.) being performed
* Call other services (like notifying another system, etc.)&#x20;
* Modify and/or manipulate an object prior to the object being returned to the caller of the repository action (after persisted but before returning).

### Data Persistence Services

The data persistence services are typically the "last place" where services in SanteDB can interact with data. Unless services require direct access to the underlying storage technology, all interactions occur via these services. Data persistence services are responsible for:

* Translating object to and from the information model into appropriate storage models (SQL tablets, FHIR objects, etc.)
* Transactional control of the underlying storage technology (commit, rollback, etc.)
* Managing and interacting with the caching services to reduce load on the persistence technology

### Caching Services

The caching services are responsible for providing rapid access to cached objects, these services (like REDIS or Memory Caching) reduce load on the persistence layer as they typically provide rapid, non-relational access to models in the information object.

### ORM Providers

The object-relational-model providers are specialized classes which are used (optionally) by services which must directly interact with database software, however require abstraction on the persistence technology. ORM providers which exist in SanteDB include: PostgreSQL, Firebird, and SQLite, and are responsible for:

* Translating object/relational LINQ queries into appropriate SQL syntax for the storage technology
* Mapping logical keywords and operators to physical operators in SQL (for example: .Contains() becomes ILIKE in PostgreSQL but LIKE in Firebird)
* Committing and rolling back transactions with the database provider
* Constructing dynamic SQL operations for result sets for order, count, etc.

### Business Intelligence Services

The BI services in SanteDB are responsible for interacting with the ORM providers to execute business intelligence assets (queries, views, parameters, reports, etc.) directly with the various connected SQL databases for the service.

### Synchronization Services

Synchronization services are responsible for integrating the SanteDB iCDR and dCDR with upstream services. These services:

* Manage the inbound/outbound and dead letter queues for synchronizations
* Interact with the persistence layer (bypassing business rules which may already be executed) directly
* Manage the retry and conflict resolution notifications process

### Additional Services

SanteDB contains hundreds of service contracts for various system tasks which are not covered at a high level on this page. These services can be found on the [Service Definitions](/developers/server-plugins/implementing-.net-features/service-definitions) page.


# Publish / Subscribe Architecture

SanteDB iCDR and dCDR supports basic subscription management. This facility allows external parties to subscribe (via a subscription) to data persistence events, at which they they will receive a notification (via a channel) using one of the available dispatch formats.

![](/files/hpC6Brg2E9pxWQ0Yew5H)

The components of the publish and subscribe architecture are:

| Repository Service     | The primary persistence repositories. These are responsible for the persisting and loading of data to/from the primary data persistence layer.                                                                                                                             |                                                                                                                  |
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| Record Merging Service | The service which is responsible for merging and unmerging records, detecting duplicates, etc.                                                                                                                                                                             | <p>MDM Record Merging <br>SIM Record Merging</p>                                                                 |
| PubSub Broker          | The publish/subscribe broker is responsible for brokering the publish and subscribe events to/from the manager service. The broker subscribes to events from the repository and merging service, ad then queues these messages on the configured `IDispatcherQueueService` |                                                                                                                  |
| Dispatcher Queue       | The dispatcher queue service is responsible for interacting with a persistent queue technology and enqueueing and dequeuing those messages.                                                                                                                                | <p>MSMQ Dispatcher Queue<br>File Dispatcher Queue</p>                                                            |
| PubSub Manager         | The pub/sub manager service is responsible for maintaining the registration of subscriptions and the related channel configuration.                                                                                                                                        | Ado PubSubManager                                                                                                |
| Dispatcher Factory     | The dispatcher factory is responsible for constructing dispatcher instances based on a particular outbound message format.                                                                                                                                                 | <p>FHIR Message Dispatcher Factory<br>FHIR Rest Hook Dispatcher Factory<br>(coming) HL7v2 Dispatcher Factory</p> |
| Dispatcher             | The dispatcher is the class which is responsible for converting the RIM based internal formatted notification to an appropriate notification in the format specified for the receiver.                                                                                     | <p>FHIR Message Dispatcher<br>FHIR RestHook Dispatcher</p>                                                       |

## Publish/Subscribe Manager Schema

The PubSubManager stores data for subscriptions and channels in a concise schema.&#x20;

![](/files/BA4beKoSdg9bDPdg5Vyi)

### Subscriptions

Subscriptions are defined with a target resource (such as Patient, Act, Entity, Person, Place, etc.). The subscription defines one or more events and a series of filters which will trigger the issuance of a notification to the receiver.

The following notification events can be subscribed.

| Create   | Triggered when a subscribed resource's `Inserted` event is fired.                    |
| -------- | ------------------------------------------------------------------------------------ |
| Update   | Triggered when the subscribed resource's `Updated` event is fired.                   |
| Delete   | Triggered when the subscribed resource's `Obsoleted` event is fired.                 |
| Merge    | Triggered when the subscribed resource's merging service fires the `Merged` event.   |
| UnMerged | Triggered when the subscribed resource's merging service fires the `UnMerged` event. |

{% hint style="info" %}
The notifications for each event are triggered by any internal update/change to data in the iCDR. This means that updates, merges, etc. received via FHIR, HL7v2, or even the user interfaces will trigger notifications.
{% endhint %}

### Channels

A channel defines the mechanism to notify the receiver of the publish notification. The channel specifies the endpoint URL (mailto:, sms:, http:, llp:, etc.) the dispatcher to be used, and any settings. Settings are stored as key/value pairs which, depending on the dispatcher will be used to determine the channel format, authorization, etc.


# New ADO (nuado)

The persistence layer in SanteDB is largely a maintenance codebase of the OpenIZ persistence layer, which itself was originally written in 2009 for the MEDIC CR and MEDIC SHR. This data layer has over a decade of modifications, changes, etc. to it from a variety of authors during its lifetime.

This has lead to several performance issues with SanteDB, namely:

* The intended use of the OpenIZ persistence layer was for synchronization, so objects are deep-loaded in the persistence layer, regardless of whether the caller will use the information. There was no way for the caller to convey to the persistence layer that loading data is not needed.
* The persistence layer requires joining of non-versioned attributes to load data (i.e. versioned attributes and non-versioned attributes were stored as a master/detail view). This impacts query performance as the database needs to perform an extra join.
* There have been several technology enhancements to the .NET platform since the original design of the persistence layer which would optimize the manner in which database calls can be made.
* Missed properties via `.LoadProperty()` require duplicate hits to the database, regardless if the data persistence layer already made this query and determined there was no matching entries.

To fix this, a new persistence layer (on branch `feature/nuado` ) has been in development for several months. This new persistence layer:

* Performs lazy-loading of records from the database when the caller requests them (i.e. calling `Skip()`, `Take()`, `Count()`, etc. translates directly to SQL statements in the database rather than deep loading
* Allows the caller to use the `QueryPersistenceContext` to control the manner in which properties are loaded based on the caller's use case.
* Uses a pipeline architecture, where MDM, privacy, and other modifications to data are performed as a pipeline of steps rather than against pre-loaded enumerations.

{% hint style="info" %}
The refactoring of the entire SanteDB iCDR to the new ADO patterns is approximately 50% complete, and will be released as part of the 2.3.x series of SanteDB iCDR. The dCDR will follow refactoring to these new interfaces after the iCDR is stabilized.
{% endhint %}

## Query Result Set

The new persistence layer modifies all the data access classes to use the `IQueryResultSet<T>` interface. These interfaces support methods for skipping and taking records from the underlining data store in a method which reduces the data loaded from the SQL database.

The code below illustrates the modification of the SQL statement sent to the database by using the result set methods.

```
var dpe = ApplicationServiceContext.GetService<IRepositoryService<Patient>>();

// Prepares the statement SELECT * FROM pat_tbl....
var patients = dpe.Find(o=>o.DateOfBirth <= DateTime.Now);

// Executes a SELECT EXISTS (....) rather than loading patients
if(patients.Any()) {

    // Modifies the statement above to SELECT * FROM pat_tbl OFFSET 10 ROW TAKE FIRST 10 ROWS ONLY
    patients = patients.Skip(10).Take(10);
    
    // Modifies statement above to SELECT COUNT(*) FROM (....)
    var patientCount = patients.Count();
}
```

Additionally, the application of any data modification processes (such as MDM or policy enforcement) is pipelined. This means that as records are read from the database, each record is operated on by the interested services.

### Result Set Implementations

| MemoryQueryResultSet    | Implementation of the `IQueryResultSet` which operates on an `IEnumerable` instance. This result set just passes any calls to the underlying enumerable object.                                                                                                                                          |
| ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| NestedQueryResultSet    | Implementation of the `IQueryResultSet` where a function is called for each retrieved object. This type of result set wrapper is useful when the yield function wishes to modify the result loaded from the wrapped result set.                                                                          |
| TransformQueryResultSet | Implementation of a `IQueryResultSet` which transforms a source record type to a destination record type using a transform function (`Func<TSource, TDestination>`) to map an object (in a pipelined manner) from A to B.                                                                                |
| MappedQueryResultSet    | A query result set which wraps an `IOrmResultSet` . When constructing this instance, the persistence layer should pass an instance of a `IMappedQueryProvider` which can be called by the ORM layer to skip/take/count and convert records from the data model layer to the business object model layer. |
| MappedStatefulResultSet | A specialized `MappedQueryResultSet` which operates on stateful query results from `IQueryPersistenceProvider`.                                                                                                                                                                                          |

&#x20;


# Roadmap

SanteDB 1.x was a near direct refactor of the original OpenIZ core, which had components from the MEDIC Service Core project dating back to 2008/2009. While SanteDB 2.x was a refactor off this .NET Framework and PCL code to .NET Standard, there are still many components and patterns (ghosts) of the original service core code from 2008.&#x20;

The SanteDB Version 3.x roadmap seeks to fully remove these patterns and re-implement many of the core services. However, this presents a problem in that it makes incremental change difficult, and will break the services. For this reason, much of the Version 3.x roadmap is currently in the design / wishlist phase.

## Refactor Persistence Layer (done)

{% hint style="info" %}
The persistence layer refactor is currently underway and the code for these features can be found at: <https://github.com/santedb/santedb-server/tree/feature/nuado>
{% endhint %}

The persistence layer is quite messy, and sub-optimal. It was written (as mentioned) starting in 2009 and has over a decade of modifications, changes, etc. to it. A major refactor of the persistence layer could be performed as part of a v2.5 version which cleans the implementation up. The goals of this work item would be:

* Refactor all current persistence classes to use yield returns so on-demand mapping and loading of data is performed.
* Refactor process of loading, so that only direct properties are loaded either:
  * At the persistence layer, do not load any associated properties and rely on callers calling : patient.LoadProperty(o=>o.Names) , which is sub-optimal since it requires establishing a new connection rather than loading on an existing connection (this point may be moot)
  * At the persistence layer, only load direct associated properties that are commonly used directly. Refactor the current LoadState property to an internal value which allows the persistence layer to indicate a value was loaded and needn't be re-checked.
* Refactor and clean up the query writer in OrmLite to use only LINQ mapping and expression tree mapping, rather than converting to/from the HTTP representation.
  * This would require a complete rewrite of the IQueryHack interfaces which currently allow for the optimization by manually creating SQL. Such an IQueryHack would need to be changed to accept an Expression\<T> with the desired filters.

## Refactor I/O Calls to TAP Pattern

Currently all I/O calls, from the REST layer, to the data access layer are using legacy .NET patterns. This work items seeks to correct this by refactoring all I/O calls to the Task Async Pattern. This will require a complete refactoring of the following core components:

#### RestSrvr

The lightweight REST API I/O calls will need to be refactored to support async/await service implementations. Some work has been done to experiment with this in the v2.x core. The changes made to this layer would not be breaking as the RestSrvr layer is the entry point to much of the iCDR and dCDR core functions.

Notes from the experimentation:

* The OperationDispatcher should detect if the bound behavior returns a Task or Task\<T> and executes the operation as an await(ed) call.
* The OperationDispatcher detected if any of the parameters of the operation were a CancellationToken, and if so, it would pass the cancellation token form the WinHTTP API to the method to indicate a cancel down the call chain.
* The actual binding implementation should be added (similar to NancyFX) to allow for piggy-backing on either the WinHTTP , Mono HTTP  (used by the dCDR on RPi, Docker, and Android) or Kestrel server (for web-hosting only). Currently the RestSrvr only uses the HttpServer implementation which does not pass the CancellationToken

#### Repository and DataPersistence Services

The entire Repository and DataPersistence service layer would need to be refactored such that they return IAsyncEnumerable\<T>. The notes for this feature are:

* All I/O calls for insert, save, etc. should return Task\<T> and allow the passing of a CancellationToken to allow for cancellation of I/O operations.
* Query calls (such as Find and Query) should return IAsyncEnumerable\<T> to permit async streams of data from the underlying layer.
  * The query calls should also be refactored to use yield returns minimizing the computational resources required to process results from the database.
  * The interface should also permit callers to indicate whether a count of total results is required, or whether simple fuzzy paging (i.e. "there is another page") should be called

Unfortunately this refactor will change the service calls such that any existing code and plugins would break. There are two options the team has discussed:

* Create IAsyncX versions of each of the service interfaces (not ideal)
  * This would mean the creation of an IAsyncDataPersistenceService\<T> interface which contains only async versions of the call
  * This would allow existing plugins to operate, however would add burden to maintenance as each implementer must implement both the regular service provider and the IAsyncX version.
* Add Async methods to the existing service definitions
  * This would add allow existing plugins to continue to operate as normal, however would require any implementations of the existing services to be refactored to add async methods.
  * This has the same maintenance issues as the IAsyncX method

## Add Complex Guard Expressions (done)

Currently within SanteDB, simple guard classifications can be done on a classifier property, for example:

```
Patient?telecom[WorkPlace].value=john@johnstuff.com
```

However, there is a need to support more complex guard expressions wherein a full HDSI guard expression can be placed into the query builder. For example:

```
Patient?telecom[type.mnemonic=EMAIL&use.mnemonic=WorkPlace].value=john@johnstuff.com
```

The requirements of this nested guard are:

* The builder should be able to express simple guards (the current format) as the current LINQ translation of `Telecoms.Where(guard=>guard.UseConcept.Mnemonic == WorkPlace).Any()`&#x20;
* The builder should be able to process the complex guards (the new format) as a similar LINQ expression of: `Telecoms.Where(guard=>guard.TypeConcept.Mnemonic == "EMAIL" && guard.UseConcept.Mnemonic == "WorkPlace").Any(v=>v.Value == "john@johnstuff.com")`&#x20;
* The persistence layer and SQL translators will also need to be updated to support this type of expression

## Improved FHIR Support

### FHIR PATH

There has been discussion within the community to support HL7 FHIR PATH as a mechanism for querying data on the FHIR interfaces. The current implementation of FHIR PATH in C# requires passing of FHIR instances to the filter criteria which acts as a delegate.

This is an inefficient design, rather, the goal of the FHIR PATH implementation is, where possible, to map the expression tree generated by the C# `HL7.Fhir.FhirPath` assembly into a .NET expression tree. This expression tree should then be passed to the persistence layer to be transformed into SQL, where indexing can be performed.&#x20;

### ValueSet and ConceptMap Import

Currently in SanteDB, it is not possible to import terminology sets via a FHIR interface. The goal is to implement import of ValueSet codes into the SanteDB host. There are several complexities with this:

1. The value set import would merely result in a series of ReferenceTerms being created in the SanteDB database, these reference terms would not be directly useful by the SanteDB system without a person subsequently mapping these terms to a concept (or creating a concept).
2. The concept map resource would be difficult to import as they represent maps between reference terms. The concept map resource would require that two reference terms be mapped to one concept, or that the two reference terms, already mapped to difference concepts establish as concept association link.

### Implementation of CQL&#x20;

Currently in SanteDB, the CDSS engine requires expression of business rules logic in HDSI, LINQ, or C# for the when conditions. The rationale for this is that on load these expressions are compiled into delegates in C# which improves execution performance.&#x20;

The implementation of a CQL interpreter in SanteDB would require one of the following implementation patterns:

1. The CQL expressions would need to be converted to HDSI or equivalent logic. This is difficult since the structure of a FHIR message is completely different than the structure of a RIM object in the SanteDB database.
2. The resource in question would need to be converted to FHIR to execute the logic, and the activity definition returned would need to be converted back to RIM. This is also not feasible since the translation of these objects can be slow, additionally it requires the implementation of FHIR activity definitions in the SanteDB platform which is a large undertaking.

Compounding the difficulty of implementing CQL in SanteDB is that there are no implementations of CQL in C# or .NET. This means the SanteDB team would need to implement the entire ANTLR4 grammar of CQL into C# logic.&#x20;


# Data & Information Architecture

Architecturally, SanteDB's data architecture is based around the RIM. SanteDB has a conceptual information model which is implemented in 3 different ways:

* Message Models - The representation of the SanteDB Conceptual Information Model  as JSON or XML objects which appear on the wire or when using functions from third party technologies like JavaScript. Message models in SanteDB include:
  * RIM-based XML model (1:1 with conceptual model)
  * RIM-based JSON model (1:1 with conceptual model)
  * JSON based View-Model (conceptual model with expanded properties to prevent round-trips to the server)
* Business Object Model - The BOM in SanteDB is a series of .NET classes which are implementations of the conceptual information model used by all C# plugins
* Physical Model - The representation of SanteDB's conceptual data model in a variety of RDMS systems including Firebird, Postgres, and SQLite.&#x20;

By realizing the SanteDB conceptual model as these three layers, we observe the following benefits:

* New physical persistence layers can be added without impacting the XML or JSON objects.
* Message formats can be adapted to best suit a message format's strengths without introducing kludge  from the persistence / RDBMS layer.
* Tracking fields used at the physical layer don't pollute the business object model or message models
* We can easily swap each layer independent of one another (add features, remove features, etc.)

## Data Lifecycle

SanteDB iCDR and dCDR never store or or directly with external messaging formats inside of the core components. All communications are transformed between components and their destined system software.&#x20;

Take, for example, a client which is querying the SanteDB iCDR using HL7 FHIR (the pattern is identical regardless of message format).

![](/files/-MNxkvTQR7XbkXPKvwxz)

In this example, the objects are passed as.

<table data-header-hidden><thead><tr><th width="150">Component</th><th width="150">Input</th><th width="150">Output</th><th>Description</th></tr></thead><tbody><tr><td>Component</td><td>Input</td><td>Output</td><td>Description</td></tr><tr><td>FHIR Service</td><td>FHIR</td><td>BOM</td><td><ul><li>Convers the incoming FHIR message or query to RIM</li><li>Converts and resulting response from RIM BOM back to FHIR</li><li>Performs necessary actions for privacy enforcement, auditing, etc.</li></ul></td></tr><tr><td>Local Repository</td><td>BOM</td><td>BOM</td><td><ul><li>Checks configuration/context for applicable storage provider.</li><li>Calls triggers for business rules and connected services</li></ul></td></tr><tr><td>Master Data Manager</td><td>BOM</td><td>BOM</td><td><ul><li>Locates local copy of object for subsequent calls</li><li>Isolates the data fields which the caller is permitted to update.</li><li>Calls the matching service to detect candidate MASTER records which the record may belong.</li><li>Re-writes the object on the persistence pipeline</li></ul></td></tr><tr><td>Matching Service</td><td>BOM</td><td>BOM</td><td><ul><li>Uses the matcher configuration to establish matches.</li><li>Queries / Blocks against the underlying, configured persistence service.</li></ul></td></tr><tr><td>ADO Persistence</td><td>BOM</td><td>Physical</td><td><ul><li>Translate the business object model into the physical model objects.</li><li>Interacts with the underlying storage technology to reliably store, and retrieve data.</li><li>Transaction control (appropriate rollback/commit infrastructure)</li><li>Performs final data layer check (uniqueness, semantic meaning, etc.)</li></ul></td></tr><tr><td>PostgreSQL</td><td>Physical</td><td>SQL</td><td><ul><li>Translates the physical object model in SQL INSERT/UPDATE/SELECT statements</li><li>Maps query expression trees into SQL</li></ul></td></tr></tbody></table>


# Conceptual Information Model

The SanteDB conceptual data model is based on several different resources:

* **HL7 Reference Information Model (RIM)** forms the basis of the core clinical storage engine. SanteDB's implementation keeps the paradigm of Entities Participating in Acts, however removes many of the complex datatypes.
* **HL7 FHIR** forms the basis for the conceptual data model's extension and tagging capabilities, which are used to extend the SanteDB data model.
* **OpenMRS Concept Dictionary** was used as the basis of SanteDB's concept tables.

## Clinical Data

Clinical data in SanteDB is represented as Entities playing Roles Participating in Acts. This is illustrated in Figure 1.

![Figure 1 - Conceptual Data Model](/files/-LZu-S_y7uPZdlW4nOfo)

* **Entities:** An entity represents a person, place, organization, or thing (syringe, antigen, vaccine, etc.). Entities can be related to one another via an entity relationship such as place belonging to an organization or series of materials belonging to a vaccination kit.
* **Roles:** Roles represent a type of part an entity plays. For example, a Person entity may play the role of a provider or a patient.
* **Participations:** Participations are the link between an act and an entity via a role. A participation is used to describe how an entity participates in the carrying out of an act.
* **Acts:** An act represents an action performed. An example of an Act may be an encounter the patient has with a provider to receive a weight or immunization. Acts may be related to one another, for example an encounter may fulfill an appointment, or an observation may be a part of an encounter.

In this context we can represent many different clinical scenarios. In order to make conceptualizing data elements in the SanteDB persistence store easier, much data documentation leverages an information model cards as illustrated in Figure 2.

![Figure 2 - Information Model Cards](/files/-LZu-tOmh8fLbkTQdkUI)

### Templates

SanteDB Acts and Entities can be templated to ease the creation and reuse of common structures. A template is a particular set of rules and pre-set data elements which are used to perform some use case with the underlying base type.

For example, weight and height are two separate types of a QuantityObservation. By creating a “weight” and “height” template, we allow any business processes or user interface elements to understand the rules for a particular entity. It allows software to understand “what kind” of element it is looking at without having to guess based on type/class/mood/determiner/etc.


# Concept Dictionary

SanteDB's concept dictionary is based heavily on the work done in [OpenMRS' Concept Dictionary](https://wiki.openmrs.org/display/docs/Concept+Dictionary+Basics), the SanteDB concept dictionary is logically made up of four fundamental concepts, described in this page.

![Relationship of Concept Dictionary](/files/-MJi-sIPsENR8Fi3XyXI)

### Concepts

In SanteDB, a "concept" is a logical construct for representing the idea of something. Concepts are used within the SanteDB core models to represent these ideas on particular attributes. Examples of concepts may be:

* The concept of a "Male", or "Female"&#x20;
* The concept of a "Syringe" (an object used to inject a substance)
* The concept of "Oral Polio Vaccine" (an antigen administered orally which protects against polio)

Concepts are assigned a unique mnemonic (a human readable term) and a UUID. Additionally concepts may carry one or more display names.&#x20;

#### Concept Relationships&#x20;

Concepts can be related to one another via a relationship. The relationship of one concept to another is used to indicate parent/child relationships, specification/generalization, etc. A relationship applies to two concepts and carries a concept relationship classification which can be one of:

| Relationship  | Description                                                                                                                                                                                                                          |
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Same As       | Indicates that concept A is the same as concept B. The two concepts can be considered interchangeable (i.e. if a system uses concept A and another system queries using concept B, then concept A and B should be considered equal). |
| Narrower Than | Indicates that concept A represents an idea which is narrower in scope than concept B. For example, a concept of "Diagnosis-YellowFever" would be narrower than "Diagnosis-Fever"                                                    |
| Wider Than    | Indicates that concept A is a broader idea than concept B. This is the inverse of the Narrower-Than relationship.                                                                                                                    |
| Negation Of   | Indicates that concept A negates concept B.                                                                                                                                                                                          |
| Inverse Of    | Indicates that concept A has the opposite semantic meaning of concept B.                                                                                                                                                             |
| Member Of     | Indicates that concept A is a member or sub-concept of concept B. For example, a concept for "Ebola" may be a member of the concept "Hemorrhagic Fever".                                                                             |

### Concept Sets

Concept sets represent a logical grouping of multiple concepts into a single list of related ideas. Concept sets are useful for driving user interface inputs, or allowing the searching/selection of ideas.&#x20;

For example, a deployment may use the AdministrativeGender concept set to drive their inputs for selecting gender. Jurisdictions can customize those concepts which are members of this set based on their business requirements.&#x20;

{% hint style="info" %}
Some fields in the SanteDB database are bound to concept sets using the ck\_set\_mem() function. This ensures that semantic integrity of data is maintained within the DBMS.
{% endhint %}

### Reference Terms

Reference terms are used for the expression of concept within an external codification system. Reference terms are used to translate concept sets into wire-level codifications of those concepts. This design allows the SanteDB internal data model to maintain integrity with a known internal series of concepts, while mapping those concepts to external code systems which may or may not be subjected to changes (for example: ICD9, ICD10 and ICD11 can be implemented by simply mapping).

{% hint style="info" %}
If you're implementing an interface which mandates the use of a separate code list, it is recommended to use the [Concept Repository ](broken://pages/-MDKigCNubPqrqqpTHds)and register your wire-level codes as reference terms.
{% endhint %}


# Data Dictionary

The data dictionary for entities which store the SanteDB concept dictionary are illustrated below.

![](/files/-MK1g8VMMn-vEH1KMIv_)

### Concept Class

The concept class table stores a complete list of concept classifications.

| Property                          | Type    | Description                                                                                                                   |
| --------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------- |
| <p>ConceptClassId<br> \[1..1]</p> | UUID    | Represents a unique identifier for the concept classification.                                                                |
| <p>Name<br> \[1..1]</p>           | VARCHAR | Represents a human readable name for the concept classification. Example: Class Codes                                         |
| <p>Mnemonic<br> \[1..1]</p>       | VARCHAR | Represents a system mnemonic for the concept class. The mnemonic does not change even if the human readable Name column does. |

### Concept

The Concept table stores the key data related to a concept. The Concept table represents immutable concept properties that cannot be changed once a concept is created.

| Property                                   | Type | Description                                                                                                                                 |
| ------------------------------------------ | ---- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| <p>ConceptId<br> \[1..1]</p>               | UUID | A unique identifier for the concept.                                                                                                        |
| <p>IsSystemConcept<br> \[1..1] = false</p> | BIT  | An indicator which identifies whether the concept is a system concept (i.e. no further versions can be created, cannot be obsoleted, etc.). |

### Concept Version

The concept version table is used to store mutable properties of a concept. All edits to a concept’s attributes result in a new version being created in the ConceptVersion table.

| Property                                               | Type     | Description                                                                                                                                                                                                           |
| ------------------------------------------------------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| <p>ConceptVersionId<br> \[1..1]</p>                    | UUID     | A unique identifier for the concept version.                                                                                                                                                                          |
| <p>VersionSequenceId<br> \[1..1]</p>                   | INT      | A sequence identifier for the version which allows for establishing a time-independent record of version order.                                                                                                       |
| <p>ConceptId</p><p>\[1..1]</p>                         | UUID     | The concept to which the version applies.                                                                                                                                                                             |
| <p>CreationTime</p><p>\[1..1]</p>                      | DATETIME | The instant in time when the concept version became active (was created). Should default to the current database timestamp.                                                                                           |
| <p>CreatedBy</p><p>\[1..1]</p>                         | UUID     | The user who was responsible for the creation of the version, or the system user if the installation process created the concept version.                                                                             |
| <p>ObsoletionTime</p><p>\[0..1] ? (> CreationTime)</p> | DATETIME | When present, identifies the time when the concept version did become obsolete. This is used whenever a new version is created, the old version is obsoleted.                                                         |
| <p>ObsoletedBy<br> \[0..1] ?(ObsoletionTime)</p>       | UUID     | Indicates the user who was responsible for the obsoletion of the record.                                                                                                                                              |
| <p>ReplacesVersionId<br> \[0..1]</p>                   | UUID     | Identifies the concept version that the current version of the concept replaces.                                                                                                                                      |
| <p>ConceptClassId<br> \[1..1] = Other</p>              | UUID     | Identifies the classification of the concept as of the version tuple.                                                                                                                                                 |
| <p>Mnemonic<br> \[0..1]</p>                            | VARCHAR  | A unique mnemonic used by the system to lookup the concept. The system mnemonic is primarily used for validation purposes where a concept’s identifier does not represent a consistent identifier across deployments. |

### Concept Set

The concept set entity is used to represent logical groupings of concepts which are related in some manner. These typically are used to drive validation (i.e. gender field must be bound to a concept in the gender concept set) or data-entry fields.

| Property                        | Type    | Description                                                                                                   |
| ------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------- |
| <p>ConceptSetId<br> \[1..1]</p> | UUID    | A unique identifier for the concept set                                                                       |
| <p>Mnemonic<br> \[1..1]</p>     | VARCHAR | The codified name of the concept set (without spaces) used to reference the concept set in queries and paths. |
| <p>Name<br> \[1..1]</p>         | VARCHAR | The human readable name of the concept set.                                                                   |
| <p>Url</p><p>\[1..1]</p>        | VARCHAR | The URL which defines the concept set.                                                                        |
| <p>Oid</p><p>\[1..1]</p>        | VARCHAR | The OID which defines the concept set.                                                                        |

### Concept Name

The concept name table represents a series of human readable names for the concept at a particular version. This facilitates searches as well as translation.

| Property                                               | Type    | Description                                                                                                                                                                   |
| ------------------------------------------------------ | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| <p>ConceptNameId<br> \[1..1]</p>                       | UUID    | A unique identifier for the concept name                                                                                                                                      |
| <p>ConceptId<br> \[1..1]</p>                           | UUID    | The concept to which the concept name applies.                                                                                                                                |
| <p>EffectiveVersionSequenceId<br> \[1..1]</p>          | UUID    | The version of the concept when the name did become active.                                                                                                                   |
| <p>ObsoleteVersionSequenceId<br> \[0..1]</p>           | UUID    | The version of the concept when the concept name was obsoleted.                                                                                                               |
| <p>Name<br> \[1..1]</p>                                | VARCHAR | The human readable display name for the concept.                                                                                                                              |
| <p>LanguageCode<br> \[1..1] \~ ISO639-2 = en</p>       | CHAR    | The ISO639-2 language code for the concept display name.                                                                                                                      |
| <p>PhoneticCode<br> \[0..1]</p>                        | VARCHAR | The phonetic code for the display name. This is used for phonetic “sounds-like” searches of concepts.                                                                         |
| <p>PhoneticAlgorithmId<br> \[0..1] ?(PhoneticCode)</p> | UUID    | The phonetic algorithm used to generate the phonetic code. This allows deployments to use METAPHONE, SOUNDEX or custom phonetic algorithms appropriate for the language used. |

### Concept Relationship

The concept relationship table is used to link concepts to one another. Concept relationships can represent equivalency between concepts, parent/child relationships, etc.

| Property                                     | Type | Description                                                                              |
| -------------------------------------------- | ---- | ---------------------------------------------------------------------------------------- |
| <p>ConceptRelationshipId<br> \[1..1]</p>     | UUID | The unique identifier for the relationship.                                              |
| <p>SourceConceptId<br> \[1..1]</p>           | UUID | The concept that represents the source of the relationship.                              |
| <p>TargetConceptId<br> \[1..1]</p>           | UUID | The concept which represents the target of the relationship                              |
| <p>EffectiveVerisonId<br> \[1..1]</p>        | UUID | Identifies the version of the source concept where the relationship did become active.   |
| <p>ObsoleteVersionSequenceId<br> \[0..1]</p> | UUID | Identifies the version of the source concept where the relationship is no longer active. |
| <p>RelationshipTypeId<br> \[1..1]</p>        | UUID | Identifies the type of relationship the concepts have.                                   |

### Concept Relationship Type

The concept relationship type represents allowed types of relationships that a concept can have.

| Property                                     | Type    | Description                                                                                        |
| -------------------------------------------- | ------- | -------------------------------------------------------------------------------------------------- |
| <p>ConceptRelationshipTypeId<br> \[1..1]</p> | UUID    | The unique identifier for the concept relationship                                                 |
| <p>Name<br> \[1..1]</p>                      | VARCHAR | The human readable name of the concept relationship type.                                          |
| <p>Mnemonic<br> \[1..1]</p>                  | VARCHAR | An invariant value that represents the type of relationship typically used by software components. |

### Reference Term

A reference term represents a wire level code that can be used to represent the concept.

| Property                           | Type    | Description                                          |
| ---------------------------------- | ------- | ---------------------------------------------------- |
| <p>ReferenceTermId<br> \[1..1]</p> | UUID    | A unique identifier for the reference term.          |
| <p>CodeSystemId<br> \[1..1]</p>    | UUID    | The code system in which the reference term belongs. |
| <p>Mnemonic<br> \[1..1]</p>        | VARCHAR | The wire level code mnemonic for the reference term. |

### Concept Reference Term

An associative entity that links a concept to one or more reference terms and indicates the strength of the map.

| Property                                      | Type | Description                                                                                                                         |
| --------------------------------------------- | ---- | ----------------------------------------------------------------------------------------------------------------------------------- |
| <p>ConceptReferenceTermId<br> \[1..1]</p>     | UUID | A unique identifier for the concept reference term map                                                                              |
| <p>ConceptId<br> \[1..1]</p>                  | UUID | The concept to which the reference term is linked.                                                                                  |
| <p>EffectiveVersionSequenceId<br> \[1..1]</p> | UUID | The version of the concept where the reference term map became effective.                                                           |
| <p>ObsoleteVersionSequenceId<br> \[0..1]</p>  | UUID | The version of the concept where the reference term map became obsolete.                                                            |
| <p>ReferenceTermId<br> \[1..1]</p>            | UUID | The reference term which is associated with the concept.                                                                            |
| <p>RelationshipTypeId<br> \[1..1]</p>         | UUID | Identifies the relationship (or strength) that the reference term has with the concept. For example: SAME\_AS, NARROWER\_THAN, etc. |

### Code System

The code system table represents a master list of all code systems from which a reference term can be drawn.

| Property                                                | Type     | Description                                                                                                                |
| ------------------------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------- |
| <p>CodeSystemId<br> \[1..1]</p>                         | UUID     | A unique identifier for the code system entry.                                                                             |
| <p>Name<br> \[1..1]</p>                                 | VARCHAR  | A human readable name for the code system. For example: ICD10                                                              |
| <p>Oid<br> \[1..1]</p>                                  | VARCHAR  | The object identifier that identifies the code system in an interoperable manner.                                          |
| <p>Authority</p><p>\[1..1]</p>                          | VARCHAR  | The unique assigning authority of the particular code system. Example CVX or SNOMEDCT                                      |
| <p>CreationTime<br> \[1..1]</p>                         | DATETIME | The time when the code system entry was created. Default to the current timestamp in the RDBMS.                            |
| <p>CreatedBy<br> \[1..1]</p>                            | UUID     | The user that was responsible for the creation of the code system.                                                         |
| <p>ObsoletionTime<br> \[0..1] ? (>CreationTime)</p>     | DATETIME | When populated, indicates the time when the code system record is obsolete.                                                |
| <p>ObsoletedBy<br> \[0..1] ?(ObsoletionTime)</p>        | UUID     | Identifies the user who was responsible for obsoleting the record.                                                         |
| <p>ObsoletionReason<br> \[0..1] ?(ObsoletionReason)</p> | VARCHAR  | The textual description as to why the record was obsoleted.                                                                |
| <p>Url<br> \[1..1]</p>                                  | VARCHAR  | A URI that uniquely identifies the code system. This is primarily used when exposing the code system over REST interfaces. |
| <p>Version<br> \[0..1]</p>                              | VARCHAR  | A textual description of the version of the code system that this record represents.                                       |

### Reference Term Display Name

Like the ConceptName table, the reference term display name table is used to identify human readable display names associated with the reference term.

| Property                                               | Type     | Description                                                                                                                                                                              |
| ------------------------------------------------------ | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| <p>ReferenceTermDisplayNameId<br> \[1..1]</p>          | UUID     | The unique identifier for the reference term.                                                                                                                                            |
| <p>ReferenceTermId<br> \[1..1]</p>                     | UUID     | The reference term to which the display name applies.                                                                                                                                    |
| <p>LanguageCode<br> \[1..1] \~ ISO639-2 = en</p>       | CHAR     | The ISO639-2 language code that identifies the language in which the display name is represented.                                                                                        |
| <p>DisplayName<br> \[0..1]</p>                         | VARCHAR  | The human readable name for the reference term.                                                                                                                                          |
| <p>CreationTime<br> \[1..1]</p>                        | DATETIME | The time when the display name became active.                                                                                                                                            |
| <p>CreatedBy<br> \[1..1]</p>                           | UUID     | Identifies the user that was responsible for the creation of the reference term display name.                                                                                            |
| <p>ObsoletionTime<br> \[0..1] ?(>CreationTime)</p>     | DATETIME | When present, identifies the time when the record should no longer be used.                                                                                                              |
| <p>ObsoletedBy<br> \[0..1] ?(CreationTime)</p>         | UUID     | Identifies the user that was responsible for obsoleting the display name.                                                                                                                |
| <p>ObsoletionReason<br> \[0..1] ?(CreationTime)</p>    | VARCHAR  | A textual description as to why the display name was obsoleted.                                                                                                                          |
| <p>PhoneticCode<br> \[0..1]</p>                        | VARCHAR  | Represents a phonetic code that can be used in “sounds-like” queries.                                                                                                                    |
| <p>PhoneticAlgorithmId<br> \[0..1] ?(PhoneticCode)</p> | UUID     | Identifies the phonetic algorithm that was used to generate the phonetic code. This allows METAPHONE or SOUNDEX or some other custom language appropriate phonetic algorithm to be used. |


# Acts

Acts in the SanteDB data model represent actions taken by entities to other entities. In this lens, we can say that an act represents everything that “happens” to entities. This mechanism of storage allows the SanteDB data model to adapt to different jurisdictions with relative ease.

There are five different types of acts that are supported by the default SanteDB schema (Figure 1).

![Figure 1 - Act Classes](/files/-LZu2X8qNzseBjzsZ4-7)

* **Patient Encounters:** Represent an act whereby a patient presents, or is intended to present for care.
* **Observations:** Represent an act whereby an entity observes something. Observations can include codified observations such as diagnoses, textual values such as a free-text description of an event, or a quantity such as weight or heart rate.
* **Substance Administrations:** A substance administration is representing an act whereby a substance, such as a vaccine is administered to a patient.
* **Order:** An order is a special type of stock act and represents a request by an entity to transfer stock from one place to another.
* **Procedures:** A procedure is a type of act in which the physical state of the record target or target entity is changed.
* **Financial Transaction:** Which is used whenever a financial transaction, or an exchange of financial goods occurs.


# State Machine

SanteDB Act support attribution of the current status of an act using the state machine illustrated in Figure 2.&#x20;

![Figure 2 - Act States](/files/-LZu6d8imLRTdSnIJeIV)

The states of an act are:

* **New :** Indicates that the act has yet to be reviewed and//or that business processing rules have yet to be executed.
* **Active :** Indicates that an act is currently occurring or being actioned. This state is used, for example, if an encounter is still occurring however has not completed.
* **Complete :** Indicates that the act has occurred. If the act is of a mood code such as intent, request, etc, the *complete* status indicates that the request or intent is complete and has been fulfilled.
* **Nullified :** Indicates that the act was created in error, and never occurred.
* **Obsolete :** Indicates that the act did occur, however the information is no longer accurate, or has been amended.


# Act Relationships

Often time acts are related to one another via the ActRelationship entity. Act relationships are important, as typically acts cannot be standalone. For example, one cannot simply “Observe” something without having an encounter. An example of several types of interactions within SanteDB are described below:

1. **Patient Presents to receive an Immunization:**\
   &#x20;In this use case the primary act is a PatientEncounter whereby participants include the clinician performing the vaccination (performer), the patient (record target), the clinic (service delivery location). The patient may be weighed prior to receiving the immunization that represents a component act of type Observation, and the administration of the vaccine represents a substance administration with relations to one or materials administered&#x20;

   <img src="/files/-LZu5OFsb9o1jU5-hfif" alt="" data-size="original">
2. **Scheduling a second dose of an antigen:**\
   &#x20;In this use case the primary act is a PatientEncounter with mood of Intent (i.e. I intend to have an encounter) and date in the future. The PatientEncounter may have one or more substance administrations with mood of Intent that represent the vaccinations that are intended to be given at the appointment. &#x20;

   <img src="/files/-LZu65CILmPiiHDUHXIl" alt="" data-size="original">
3. **Patient Presents for Appointment:** In this use case, the patient presents for the scheduled appointment. The encounter fulfills the appointment request.  <br>

   <img src="/files/-LZu6JC-GduZwtFfRUzz" alt="" data-size="original">
4. **Forecasted vaccination:**\
   &#x20;In this use case a decision support system identifies a patient which needs to receive a vaccine. The forecasting engine may create a PatientEncounter with mood of Proposed that indicates that a computer system is proposing an action to occur. When the patient presents for their vaccination the clinician creates a new PatientEncounter with mood of Event that fulfills the PatientEncounter with mood of Proposed (i.e. the clinician is saying “I am acting on your proposal”).


# Mood Concepts

Additionally, Acts are classified by Mood via the MoodConceptId. The mood of an act identifies the mood or method of operation of the act, moods include:

| Mood     | Code | Description                                                                                            |
| -------- | ---- | ------------------------------------------------------------------------------------------------------ |
| Proposal | PRPS | Indicates that the act was proposed by a system process such as a business rule, or clinical protocol. |
| Intent   | INT  | Indicates that a human intends to perform the act in the future, however the act has not yet occurred. |
| Event    | EVN  | Indicates that the act has actually occurred, or is occurring.                                         |
| Request  | RQO  | Indicates that a person is requesting that the act occur. It is used to support order workflows.       |
| Promise  | PRMS | Indicates that the act represents the promise to fulfill a request.                                    |


# Class Concepts

Acts are classified into one of these four types based upon their ClassConcept code. This dictates what type of Act the particular tuple in the database represents.&#x20;

| Act Class                | Code   | Description                                                                                            |
| ------------------------ | ------ | ------------------------------------------------------------------------------------------------------ |
| Observation              | OBS    | Indicates that the act represents a value which was observed.                                          |
| Substance Administration | SBADM  | Indicates that the act represents the administration of a substance to an entity.                      |
| Patient Encounter        | ENC    | The act represents an encounter between one or more providers of care and one or more clients of care. |
| Registration             | REG    | The act represents a registration whereby new data was collected about an entity.                      |
| Account Management       | ACCM   | The act represents the management (adjustment) of an account.                                          |
| Supply                   | SPLY   | The act represents the supply of one or more materials to/from one or more entities.                   |
| Condition                | COND   | The act represents a chronic or recurring problem or health condition.                                 |
| Procedure                | PROC   | The act represents a clinical procedure which was performed on the client of care.                     |
| Battery                  | BAT    | The act represents a series of procedures, observations, administrations, etc.                         |
| Transport                | TRANS  | The act represents the physical transporting of materials to/from one or more entities.                |
| Account                  | ACCT   | The act represents an active account (financial, stock, etc.) on which transactions can be performed.  |
| Financial Transaction    | FTRANS | The act represents a financial transaction where monies are exchanged between one or more entities.    |
| Invoice Element          | INVE   | The act represents a sub-element of a financial transaction.                                           |

The class concept list is extensible.


# Data Dictionary

The act data model describes the tables and fields required for the tracking of acts in the SanteDB logical model.

![](/files/-MK1gEGbdFVBqmBhygsU)

### Act Entity

The act table is represents the immutable attributes of an act.

| Column                                        | Type | Description                                                                                                                       |
| --------------------------------------------- | ---- | --------------------------------------------------------------------------------------------------------------------------------- |
| <p>ActId<br> \[1..1]</p>                      | UUID | A unique identifier for the act.                                                                                                  |
| <p>TemplateDefinitionId<br> \[1..1]</p>       | UUID | Identifies the template definition that the particular act implements.                                                            |
| <p>ClassConceptId<br> \[1..1] \~ ActClass</p> | UUID | Identifies a concept that classifies the act. This determines the type of act, for example an Observation, PatientEncounter, etc. |
| <p>MoodConceptId<br> \[1..1] \~ ActMood</p>   | UUID | Identifies the mood, or method of the act’s performance.                                                                          |

### ActTag Entity

A table for storing tags related to acts. A tag represents a version independent piece of data attached to a tag.

| Column                                             | Type      | Description                                                                                  |
| -------------------------------------------------- | --------- | -------------------------------------------------------------------------------------------- |
| <p>ActTagId<br> \[1..1]</p>                        | UUID      | A unique identifier for the tag.                                                             |
| <p>ActId<br> \[1..1]</p>                           | UUID      | Identifies the act to which the tag is applied.                                              |
| <p>Key<br> \[1..1]</p>                             | VARCHAR   | A unique key identifier for the type of tag. A tag’s key is used to convey the type of data. |
| <p>Value<br> \[1..1]</p>                           | VARBINARY | Contains the binary data of the tag.                                                         |
| <p>CreationTime<br> \[1..1]</p>                    | DATETIME  | Identifies the time when the tag became active, or was created.                              |
| <p>CreatedBy<br> \[1..1]</p>                       | UUID      | Identifies the user that was responsible for the creation of the tag.                        |
| <p>ObsoletionTime<br> \[0..1] ?(>CreationTime)</p> | DATETIME  | When present, identifies the time that the tag data is no longer valid.                      |
| <p>ObsoletedBy<br> \[0..1] ?(ObsoletionTime)</p>   | UUID      | Identifies the user who obsoleted the act tag.                                               |

### ActVersion Entity

| Column                                              | Type         | Description                                                                                                                                                                                             |          |                                                              |
| --------------------------------------------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------------------------------------------------------------ |
| <p>ActVersionId<br> \[1..1]</p>                     | UUID         | A unique identifier for the version.                                                                                                                                                                    |          |                                                              |
| <p>VersionSequenceId<br> \[1..1]</p>                | INT          | A sequence identifier for the version which allows for a time independent mechanism for establishing version order.                                                                                     |          |                                                              |
| <p>ActId<br> \[1..1]</p>                            | UUID         | Identifies the act to which the version data applies.                                                                                                                                                   |          |                                                              |
| <p>CreationTime<br> \[1..1]</p>                     | DATETIME     | Identifies the time when the act version became active (was created)                                                                                                                                    |          |                                                              |
| <p>CreatedBy<br> \[1..1]</p>                        | UUID         | Identifies the user that was responsible for creating the version.                                                                                                                                      |          |                                                              |
| <p>ObsoletionTime<br> \[0..1] ? (>CreationTime)</p> | DATETIME     | When present, identifies the time when the version of the act is no longer active.                                                                                                                      |          |                                                              |
| <p>ObsoletedBy</p><p>\[0..1] ?(ObsoletionTime)</p>  | UUID         | Identifies the user who was responsible for the obsoletion of the version.                                                                                                                              |          |                                                              |
| <p>NegationInd<br> \[1..1] = false</p>              | BIT          | When present, indicates that the act’s value is not true. For example, when attempting to convey that a vaccine was not given, the negationInd would be set to true.                                    |          |                                                              |
| <p>TypeConceptId</p><p>\[0..1]</p>                  | UUID         | Identifies the type of act. This is a type that is a subclass within the major classification. For example, if the class is a substance administration, the type concept may represent an Immunization. |          |                                                              |
| <p>StatusConceptId<br> \[1..1] \~ActStatus</p>      | UUID         | Identifies the status of the act as of the current version.                                                                                                                                             |          |                                                              |
| <p>ActTime<br> \[0..1] ?(ActTime                    | ActStartTime | ActStopTime)</p>                                                                                                                                                                                        | DATETIME | Identifies the time that the act did occurred, should occur. |
| <p>ActStartTime<br> \[0..1] ?(ActTime               | ActStartTime | ActStopTime)</p>                                                                                                                                                                                        | DATETIME | Identifies the start time of the act.                        |
| <p>ActStopTime<br> \[0..1] ?(ActTime                | ActStartTime | ActStopTime)</p>                                                                                                                                                                                        | DATETIME | Identifies the stop time of the act.                         |

### ActRelationship Entity

The act relationship table is used to track the relationship of acts to one another.

| Column                                                             | Type | Description                                                                           |
| ------------------------------------------------------------------ | ---- | ------------------------------------------------------------------------------------- |
| <p>ActRelationshipId<br> \[1..1]</p>                               | UUID | Uniquely identifies the act relationship.                                             |
| <p>SourceActId<br> \[1..1]</p>                                     | UUID | Identifies the source act of the relationship.                                        |
| <p>TargetActId<br> \[1..1]</p>                                     | UUID | Identifies the target act of the relationship.                                        |
| <p>EffectiveVersionSequenceId<br> \[1..1]</p>                      | UUID | Identifies the version of the source act where this relationship did become active.   |
| <p>ObsoleteVersionSequenceId<br> \[0..1]</p>                       | UUID | Identifies the version of the source act where this relationship is no longer active. |
| <p>RelationshipTypeConceptId<br> \[1..1] \~ActRelationshipType</p> | UUID | Identifies the type of relationship that the two acts have to one another.            |

### ActParticipation Entity

The ActParticipation table is used to track how entities participate in a particular act.

| Column                                                               | Type | Description                                                                                 |
| -------------------------------------------------------------------- | ---- | ------------------------------------------------------------------------------------------- |
| <p>ActParticipationId<br> \[1..1]</p>                                | UUID | Uniquely identifies the act participation.                                                  |
| <p>ActId<br> \[1..1]</p>                                             | UUID | Identifies the act that the participation is for.                                           |
| <p>EffectiveVersionSequenceId<br> \[1..1]</p>                        | UUID | Identifies the version of the act when the participation is active.                         |
| <p>ObsoleteVersionSequenceId<br> \[0..1]</p>                         | UUID | When present, identifies the version of the act when the participation is no longer active. |
| <p>ParticipationRoleConceptId<br> \[1..1] \~ActParticipationType</p> | UUID | Qualifies what role the entity played in the carrying out of the act.                       |
| <p>Quantity<br> \[1..1] = 1</p>                                      | INT  | Identifies the number of entities that are included in the playing of the role.             |

### ActIdentifier Entity

The act identifier table is used to store alternate identifiers for the act. This may include vaccine event identifiers, external order identifiers, etc.

| Column                                        | Type    | Description                                                                                           |
| --------------------------------------------- | ------- | ----------------------------------------------------------------------------------------------------- |
| <p>ActIdentifierId<br> \[1..1]</p>            | UUID    | Uniquely identifies the alternate act identifier.                                                     |
| <p>IdentifierTypeId<br> \[0..1]</p>           | UUID    | Identifies the type of identifier this particular identifier instance represents (order #, etc.)      |
| <p>AssigningAuthorityId<br> \[1..1]</p>       | UUID    | Identifies the authority that assigned the identifier.                                                |
| <p>IdentifierValue<br> \[1..1]</p>            | VARCHAR | The actual external identifier value.                                                                 |
| <p>EffectiveVersionSequenceId<br> \[1..1]</p> | UUID    | Identifies the version of the act where the alternate identifier became active.                       |
| <p>ObsoleteVersionSequenceId<br> \[0..1]</p>  | UUID    | When present, identifies the version of the act whereby the alternate identifier is no longer active. |

### ActExtension Entity

The act extension table is used to store extensions attached to acts.

| Column                                        | Type      | Description                                                                                                                                          |
| --------------------------------------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| <p>ActExtensionId<br> \[1..1]</p>             | UUID      | A unique identifier for the act extension.                                                                                                           |
| <p>ExtensionTypeId<br> \[1..1]</p>            | UUID      | Identifies the type of extension represented. This includes information on how the extension should be serialized to/from the ExtensionValue column. |
| <p>ExtensionValue<br> \[1..1]</p>             | VARBINARY | Carries the value of the extension.                                                                                                                  |
| <p>ExtensionDisplay<br> \[1..1]</p>           | VARCHAR   | A human comprehendible display value for the extension.                                                                                              |
| <p>EffectiveVersionSequenceId<br> \[1..1]</p> | UUID      | Indicates the version of the act where this extension became active.                                                                                 |
| <p>ObsoleteVersionSequenceId<br> \[0..1]</p>  | UUID      | When present, indicates the version of the act where the extension is no longer active.                                                              |

### Observation Entity

The observation table is used to store extended values related to observation act types.

| Column                                                         | Type | Description                                                                   |
| -------------------------------------------------------------- | ---- | ----------------------------------------------------------------------------- |
| <p>ActVersionId<br> \[1..1]</p>                                | UUID | Identifies the act version to which this extended data applies.               |
| <p>InterpretationConceptId<br> \[0..1] \~ActInterpretation</p> | UUID | Identifies the concept that represents the interpretation of the observation. |

### QuantityObservation Entity

The quantity observation table is used to store extended information related to the observations that carry quantified values.

| Column                                                    | Type    | Description                                                                              |
| --------------------------------------------------------- | ------- | ---------------------------------------------------------------------------------------- |
| <p>ActVersionId<br> \[1..1]</p>                           | UUID    | Identifies the observation act version to which the quantified observation data applies. |
| <p>Quantity<br> \[1..1]</p>                               | DECIMAL | A decimal value that contains the value of the observation quantity.                     |
| <p>QuantityPrecision<br> \[1..1]</p>                      | INT     | Identifies the precision of the Quantity field.                                          |
| <p>UnitOfMeasureConceptId<br> \[1..1] \~UnitOfMeasure</p> | UUID    | Identifies the concept that identifies the units of measurement.                         |

### TextObservation Entity

The text observation table is used to store additional information related to a text valued observation.

| Column                          | Type | Description                                                                           |
| ------------------------------- | ---- | ------------------------------------------------------------------------------------- |
| <p>ActVersionId<br> \[1..1]</p> | UUID | Identifies the observation version id that this text observation data is attached to. |
| <p>TextValue<br> \[1..1]</p>    | TEXT | A textual field that contains the observation data.                                   |

### CodedObservation Entity

The coded observation table is used to store additional data related to observations that are coded. Problems and Allergies would qualify as coded observations.

| Column                            | Type | Description                                                                               |
| --------------------------------- | ---- | ----------------------------------------------------------------------------------------- |
| <p>ActVersionId<br> \[1..1]</p>   | UUID | Identifies the version of the observation that this coded observation value data applies. |
| <p>ConceptValueId<br> \[1..1]</p> | UUID | Identifies the concept that represents the value of observation.                          |

### SubstanceAdministration Entity

The substance administration table is used to store data related to substance administrations to a patient. This include vaccines or any type of Epupin injections for

| Column                                               | Type    | Description                                                                                                                                           |
| ---------------------------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| <p>ActVersionId<br> \[1..1]</p>                      | UUID    | Identifies the act version to which the substance administration data applies.                                                                        |
| <p>RouteConceptId<br> \[0..1] \~RouteConcept</p>     | UUID    | Identifies the concept that describes the route that was taken to administer the substance. This may be drawn from the default route if not supplied. |
| <p>DoseQuantity<br> \[1..1]</p>                      | DECIMAL | Identifies the dosage that was given to the patient.                                                                                                  |
| <p>DoseQuantityPrecision<br> \[1..1]</p>             | INT     | Identifies the precision of the dose quantity.                                                                                                        |
| <p>DoseUnitConceptId<br> \[1..1] \~UnitOfMeasure</p> | INT     | Identifies the dose unit of measure that was given to the patient.                                                                                    |
| <p>SequenceId<br> \[0..1]</p>                        | INT     | Identifies the sequence of this dose if it is a part of a sequence of doses.                                                                          |

### PatientEncounter Entity

The patient encounter table is used to store additional data related to an act that represents a patient encounter.

| Column                                                                  | Type | Description                                                              |
| ----------------------------------------------------------------------- | ---- | ------------------------------------------------------------------------ |
| <p>ActVersionId<br> \[1..1]</p>                                         | UUID | Identifies the act to which the extended patient encounter data applies. |
| <p>DischargeDispositionConceptId<br> \[0..1] \~DischargeDisposition</p> | UUID | Identifies the disposition in which the patient left the encounter.      |

### ActNote Entity

The act note table is used to store notes associated with an act.

| Column                                        | Type | Description                                                                          |
| --------------------------------------------- | ---- | ------------------------------------------------------------------------------------ |
| <p>ActNoteId<br> \[1..1]</p>                  | UUID | A unique identifier for the note.                                                    |
| <p>EffectiveVersionSequenceId<br> \[1..1]</p> | UUID | The version whereby the note became effective                                        |
| <p>ObsoleteVersionSequenceId<br> \[0..1]</p>  | UUID | When populated, indicates the version of the act where the note is no longer active. |
| <p>AuthorEntityId<br> \[1..1]</p>             | UUID | The identifier of the entity that wrote the note.                                    |
| <p>NoteText<br> \[1..1]</p>                   | TEXT | The textual content of the note.                                                     |

### Procedure Entity

Used to track acts which alter the physical state of an entity (i.e. surgeries, etc.)

| Column                                                       | Type | Description                                                                      |
| ------------------------------------------------------------ | ---- | -------------------------------------------------------------------------------- |
| <p>ActVersionId<br> \[1..1]</p>                              | UUID | Points to the version of the Act which this procedure is describing.             |
| <p>MethodCodeId<br> \[0..1] \~ProcedureTechniqueCode</p>     | UUID | Identifies the formal method for performing the procedure.                       |
| <p>ApproachSiteCodeId<br> \[0..1] \~BodySiteOrSystemCode</p> | UUID | Identifies the manner in which the target site was approached for the procedure. |
| <p>TargetSiteCodeId<br> \[0..1] \~BodySiteOrSystemCode</p>   | UUID | Identifies the body system/part which was the target of the procedure.           |


# Entities

An entity within the SanteDB data model is used to represent a person, place, or thing. Entities represent the who, which and where aspects of an action. Entities are further classified into several sub classes illustrated in Figure 1.

![Figure 1 - Entity Classes](/files/-LZu03EaziAaAvb6y76c)


# State Machine

Entities also support a basic series of states which identify the current status of the entity in the SanteDB data model. Figure 7 illustrates the states of an entity and the valid transitions.

![Figure 7 - Entity State Diagram](/files/-LZu1aFpVAtACCgeqc3N)

The states of the entity are:

* **New :** The entity instance was just created, and no processing, storage, or business rules have been executed.
* **Active :** The entity has been persisted, any necessary review and/or processing has occurred, and the entity record is active.
* **Nullified :** Indicates that the entity was created in error, the entity never existed.
* **Obsolete :** Indicates that the entity did exist, however it no longer is active.


# Entity Relationships

Figure 2 represents a sample information model of a kit of BCG vaccine. The model illustrates how a single tuples in the SanteDB model are related to one another to represent a kit. The material “BCG Vaccine” is comprised of one dose of “BCG Antigen”, one “Syringe”, and one dose of “BCG Diluent”. A box of “BCG Vaccine” represents 25 single doses of “BCG Vaccine” (meaning 25 syringes, 25 antigen and 25 diluent). Finally, from this we can order (via instantiation or inheriting a kind) a kit of GSK 5ml BCG vaccine. This derivation will have the same rules applied (in that this vaccine must have a syringe, antigen, and diluent.

![Figure 2 - Kitting of BCG](/files/-LZu0Kz4kiwGot20IQ18)

Figure 3 represents a complex scenario of kitting a vaccine and then deriving a specific type of kit. The relationship between the instantiation and the generic concepts of the material would have a type of “Manufactured” meaning the “GSK 5 ml BCG” is a manufactured representation of the generic BCGvaccine.

![Figure 3 - Instantiating BCG Vaccine kit to Manufactured Materials ](/files/-LZu0OQpgqOq-ly1_bmO)

The SanteDB model also supports more simplistic representation of a “BCG Vaccine” if kits are not required by the jurisdiction that is implementing SanteDB. Figure 4 illustrates a valid representation of BCG in a jurisdiction where only the antigen is tracked.

![Figure 4 - Representing an instance of a KIND of Entity](/files/-LZu0Y7lhF6ARt2MC9z3)

### Type and Classification

An entity relationship has two codes which dictate the nature of the relationship between the holder (the entity which owns the relationship) and the target (the entity to which the holder is related). These are the relationshipType and the classificationType.

The relationshipType dictates the primary nature of the relationship, or the role that the target plays in related to the holder. Common relationship types are listed below (the full set is derived from the Concept Set `EntityRelationshipType`).

| Relationship Type                                                          | Use                                                                                                                                                                    |
| -------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| <p>Family Members (Mother, Father, <br>Sister, Brother, Sibling, etc.)</p> | <p>Indicates that the target has a familial relationship with the</p><p>holder. In these relationships the target IS A (mother, father, etc.)</p><p>to the holder.</p> |
| Parent / Child                                                             | <p>Indicates that the target is a parent or the target is a child of the </p><p>holder.</p>                                                                            |
| <p>DedicatedServiceDeliveryLocation,</p><p>ServiceDeliveryLocation</p>     | Indicates that the target is the primary facility at which services are rendered for the holder.                                                                       |
| Replaces                                                                   | The target replaces the holder                                                                                                                                         |

The classification of the relationship indicates the nature of the target in relation to the holder. The classification is derived from `RelationshipClass.` If a classification is not specified, then it is assumed the relationship  is not classified caller to interpret the context.

| Classification Type | Use                                                                                                                                                                                                                                                                                                                                                |
| ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ContainedObjectLink | <p>Indicates that the target object adds further context to the holder,</p><p>and that the contained object should not be used on its own without </p><p>context of the holder.</p>                                                                                                                                                                |
| ReferenceObjectLink | <p>Indicates that the target object is merely a reference of an independently</p><p>submitted source object. These relationships classifications are used, for example, when the target was submitted and can exist independently of the holder (could be in the same same transaction)</p>                                                        |
| PrivateLink         | Indicates that the relationship was established for a system purpose, and not by a user or calling solution. Private links are used by the MDM layer, the matching layer, and others to indicate a "do not remove" condition to the persistence layer (i.e. the MDM layer has established this relationship and only the MDM layer can remove it). |
| PublicContactLink   | Indicates that the holder and the target have a direct contact link, that is that the calling system (or an end user using the calling system) may use the relationship to directly contact the source. This is used often in the HL7v2 and FHIR layer for "contacts" (i.e. Mother relationship which can be Contacted)                            |


# Determiner Codes

Determiner codes are used to classify whether a tuple in the entity table represents an actual thing or a classification of things. There are three types of determiner classifications for objects listed in .

| **Determiner**  | **Description**                                                              | **Example**                                                   |
| --------------- | ---------------------------------------------------------------------------- | ------------------------------------------------------------- |
| Specific        | The entry in the database represents a one or more occurrences of an entity. | A patient, a facility, an organization, etc.                  |
| Kind            | The entry represents a classification of entities.                           | A type of material, a type of organization, a type of device. |
| Quantified Kind | Represents a kind of object which is quantified such as X number of Y.       | A dose of vaccine (5ml, etc.)                                 |


# Class Codes

Entities are further classified by their class code and determiner code. The determiner code of an entity is responsible from differentiating a type of an entity (i.e. antigen, dose number, material type, etc.) and an instance or series of instances of an entity (an actual vial of vaccine, a box of syringes, etc.). Most entities within the SanteDB system are expected to be stored as instances of entities, classes of entities will primarily be restricted to materials whereby a class of antigens (OPV for example) will have both instances (vials of OPV) and sub-classes of representing dose numbers (OPV0 – OPV3). Provides a summary of the entity classes and how they are classified in the data model.

| **Entity Class**      | **Class Code** | **Description**                                                                                                                      |
| --------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| Entity                | ENT            | An entity is the base class used to represent a person/place/thing in the SanteDB data model.                                        |
| Material              | MAT            | A material represents a physical thing to which participates in the delivery of care. For example: a syringe, a box of vaccine, etc. |
| Manufactured Material | MMAT           | A manufactured material represents a material which is manufactured such as diluent, vaccine, syringes, etc.                         |
| Place                 | PLC            | A place represents a physical location where health services are provided.                                                           |
| Organization          | ORG            | An organization represents an administrative structure which employs providers, operates clinics, etc.                               |
| Person                | PSN            | A person represents a human being.                                                                                                   |
| Patient               | PAT            | Represents a person who receives health services.                                                                                    |
| Provider              | PVD            | Represents a person who provides health services.                                                                                    |
| User                  | USR            | Represents a person who actively uses the system.                                                                                    |
| Device                | DEV            | Represents a physical object on which health services data is entered, stored, etc.                                                  |
| Application           | APP            | Represents a piece of software which is used to access, record or update medical data.                                               |


# Data Dictionary

The SanteDB entity model represents a series of tables which are responsible for the tracking of entities within the SanteDB data model. Entities represent people, places, organizations, things, etc. and are responsible for participating within acts in some capacity.

![](/files/-MK1gMuTJzJK3dYBDtyv)

### Entity

The entity table is responsible for the storage of immutable attributes of an entity.

| Column                                                           | Type | Description                                                                                                                                                                                                              |
| ---------------------------------------------------------------- | ---- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| <p>EntityId</p><p>\[1..1]</p>                                    | UUID | Uniquely identifies the entity within the context of the SanteDB implementation.                                                                                                                                         |
| <p>TemplateDefinitionId<br> \[0..1]</p>                          | UUID | Identifies the template which the entity instance implements.                                                                                                                                                            |
| <p>ClassConceptId<br> \[1..1] \~EntityClassConcept</p>           | UUID | Identifies the concept that classifies the entity by a type. The classifier is used to determine “WHAT TYPE” of entity the tuple represents such as a person, material, manufactured material, organization, place, etc. |
| <p>DeterminerConceptId<br> \[1..1] \~EntityDeterminerConcept</p> | UUID | Identifies the concept that classifies or determines the type of entity. This is either an INSTANCE or CLASS concept identifier.                                                                                         |

### Entity Tag

The entity tag table is used to store version independent tags associated with an entity. A tag does not result in new versions of the entity and is used to track additional data related to security and/or workflow related metadata.

| Column                                             | Type     | Description                                                                                                                      |
| -------------------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------- |
| <p>EntityTagId<br> \[1..1]</p>                     | UUID     | Uniquely identifies the entity tag.                                                                                              |
| <p>EntityId<br> \[1..1]</p>                        | UUID     | Identifies the entity to which the tag is associated.                                                                            |
| <p>Key<br> \[1..1]</p>                             | VARCHAR  | Qualifies the type of tag associated with the entity. That is to say, type of tag is represented in the tuple of the determiner. |
| <p>Value<br> \[1..1]</p>                           | VARCHAR  | A value that carries the data associated with the tag value.                                                                     |
| <p>CreationTime<br> \[1..1]</p>                    | DATETIME | Indicates the date/time at which time the tag was created.                                                                       |
| <p>CreatedBy<br> \[1..1]</p>                       | UUID     | Identifies the user that was responsible for the creation of the tag.                                                            |
| <p>ObsoletionTime<br> \[0..1] ?(>CreationTime)</p> | DATETIME | When populated, indicates the time when the tag is no longer associated with the entity.                                         |
| <p>ObsoletedBy<br> \[0..1] ?(ObsoletionTime)</p>   | UUID     | Identifies the user that was responsible for obsoleting the tag.                                                                 |

### Entity Version

The entity version table is used to store the mutable attributes of an entity, that is to say, any fields associated with an entity that may evolve over the lifespan of the entity are tracked in this table.

| Column                                                   | Type     | Description                                                                                                                                              |
| -------------------------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| <p>EntityVersionId<br> \[1..1]</p>                       | UUID     | Uniquely identifies the version of the entity represented in the tuple.                                                                                  |
| <p>EntityId<br> \[1..1]</p>                              | UUID     | Identifies the entity to which this version applies.                                                                                                     |
| <p>ReplacesVersionId<br> \[0..1]</p>                     | UUID     | Identifies the version of the entity that the current tuple is responsible for replacing.                                                                |
| <p>StatusConceptId<br> \[1..1] \~EntityStatusConcept</p> | UUID     | Identifies the status of the entity as of the version represented in the tuple.                                                                          |
| <p>CreationTime<br> \[1..1]</p>                          | DATETIME | Indicates the time when the entity was created.                                                                                                          |
| <p>CreatedBy<br> \[1..1]</p>                             | UUID     | Identifies the user that was responsible for the creation of the entity.                                                                                 |
| <p>ObsoletionTime<br> \[0..1] ?(>CreationTime)</p>       | DATETIME | When populated, indicates the time when the entity version became obsolete.                                                                              |
| <p>ObsoletedBy<br> \[0..1] ?(ObsoletionTime)</p>         | UUID     | Identifies the user that was responsible for the obsoleting of the record.                                                                               |
| <p>TypeConceptId<br> \[0..1]</p>                         | UUID     | Indicates the concept that classifies the subtype of entity. For example, an entity may be a provider; however, the sub-type may be a “physiotherapist”. |

### Entity Relationship

The entity association table is used to associate two or more entities together. An association is made between a source entity and a target entity.

| Column                                                                | Type | Description                                                                                                                                                              |
| --------------------------------------------------------------------- | ---- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| <p>EntityRelationshipId<br> \[1..1]</p>                               | UUID | Uniquely identifies the entity association.                                                                                                                              |
| <p>SourceEntityId<br> \[1..1]</p>                                     | UUID | Identifies the source of the entity association.                                                                                                                         |
| <p>TargetEntityId<br> \[1..1]</p>                                     | UUID | Identifies the target of the entity association.                                                                                                                         |
| <p>EffectiveVersionSequenceId<br> \[1..1]</p>                         | UUID | Indicates the version of the source entity at which time this entity association was created or became effective.                                                        |
| <p>ObsoleteVersionSequenceId<br> \[0..1]</p>                          | UUID | When populated, indicates that the entity association is no longer active, and indicates the version of the source entity where the association ceased to be applicable. |
| <p>RelationshipTypeConceptId<br> \[1..1] \~EntityRelationshipType</p> | UUID | Classifies the relationship between the two entities. Can indicate ownership roles such as “Place OWNS Material”, or relationship “Patient CHILD OF Person”.             |
| <p>Quantity<br> \[1..1] = 1</p>                                       | INT  | Indicates the quantity of target entities contained within the source entity.                                                                                            |

### Entity Note

The entity note table is used to store textual notes related to an entity.

| Column                                        | Type | Description                                                                               |
| --------------------------------------------- | ---- | ----------------------------------------------------------------------------------------- |
| <p>EntityNoteId<br> \[1..1]</p>               | UUID | Uniquely identifies the note.                                                             |
| <p>EffectiveVersionSequenceId<br> \[1..1]</p> | UUID | Identifies the version of the entity to which the note applies.                           |
| <p>ObsoleteVersionSequenceId<br> \[0..1]</p>  | UUID | When populated, indicates the version of the entity where the note is no longer relevant. |
| <p>AuthorEntityId<br> \[1..1]</p>             | UUID | Identifies the entity that was responsible for the authoring of the note.                 |
| <p>NoteText<br> \[1..1]</p>                   | TEXT | Indicates the textual content of the note.                                                |

### Entity Address

The entity address table is used to store address information (physical addresses) related to an entity.

| Column                                                  | Type | Description                                                                                                      |
| ------------------------------------------------------- | ---- | ---------------------------------------------------------------------------------------------------------------- |
| <p>EntityAddressId<br> \[1..1]</p>                      | UUID | Uniquely identifies the entity address.                                                                          |
| <p>EffectiveVersionSequenceId<br> \[1..1]</p>           | UUID | Identifies the version of the entity whereby the address information became active.                              |
| <p>ObsoleteVersionSequenceId<br> \[0..1]</p>            | UUID | When populated, indicates the version of the entity whereby the address is no longer applicable.                 |
| <p>AddressUseConceptId<br> \[1..1] \~AddressUseType</p> | UUID | Indicates the desired use of the address. Examples include physical visit, vacation home, contact, mailing, etc. |

### Entity Address Component

The entity address component table is used to store the address components associated with a particular entity address.

| Column                                                        | Type    | Description                                                                                                                         |
| ------------------------------------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| <p>EntityAddressComponentId<br> \[1..1]</p>                   | UUID    | Uniquely identifies the entity address component.                                                                                   |
| <p>Value<br> \[1..1]</p>                                      | VARCHAR | Identifies the value of the of the address component                                                                                |
| <p>ComponentTypeConceptId<br> \[1..1] \~NameComponentType</p> | UUID    | Classifies the type of address component represented in the value field. For example: street name, city, country, postal code, etc. |
| <p>EntityAddressId<br> \[1..1]</p>                            | UUID    | Identifies the entity address to which the entity address component applies.                                                        |

### Entity Name

The entity name table is used to store master list of names associated with an entity.

| Column                                        | Type | Description                                                                                                        |
| --------------------------------------------- | ---- | ------------------------------------------------------------------------------------------------------------------ |
| <p>EntityNameId<br> \[1..1]</p>               | UUID | Uniquely identifies the entity name.                                                                               |
| <p>EntityNameUseId<br> \[1..1]</p>            | UUID | Classified the intended use of the entity name. Examples: maiden name, legal name, license name, artist name, etc. |
| <p>EffectiveVersionSequenceId<br> \[1..1]</p> | UUID | Identifies the version of the entity when this name became active.                                                 |
| <p>ObsoleteVersionSequenceId<br> \[0..1]</p>  | UUID | When populated, identifies the version of the entity where the name is no longer active.                           |

### Entity Name Component

The entity name component table is responsible for the storage of name components that comprise an entity name.

| Column                                                              | Type | Description                                                                                       |
| ------------------------------------------------------------------- | ---- | ------------------------------------------------------------------------------------------------- |
| <p>NameComponentId<br> \[1..1]</p>                                  | UUID | Uniquely identifies the name component.                                                           |
| <p>ValueId<br> \[1..1]</p>                                          | UUID | Indicates the phonetic value tuple that stores the name value.                                    |
| <p>NameComponentTypeConceptId<br> \[1..1] \~EntityComponentType</p> | UUID | Classifies the type of name component represented. Examples: first name, title, family name, etc. |
| <p>EntityNameId<br> \[1..1]</p>                                     | UUID | Indicates the entity name to which the name component applies.                                    |

### Entity Identifier

The entity identifier is table is responsible for the storage of alternate identifies associated with the entity.

| Column                                        | Type    | Description                                                                                                                                  |
| --------------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| <p>EntityIdentifierId<br> \[1..1]</p>         | UUID    | Uniquely identifies the entity identifier.                                                                                                   |
| <p>IdentifierTypeId<br> \[1..1]</p>           | UUID    | Classifies the type of identifier that is represented by the entity identifier. Examples: business identifier, mrn, primary identifier, etc. |
| <p>EffectiveVersionSequenceId<br> \[1..1]</p> | UUID    | Indicates the version of the entity when the identifier became active.                                                                       |
| <p>ObsoleteVersionSequenceId<br> \[0..1]</p>  | UUID    | When populated, indicates the version of the entity where the identifier is no longer active.                                                |
| <p>AssigningAuthorityId<br> \[1..1]</p>       | UUID    | Identifies the authority that was responsible for the assigning of the identifier.                                                           |
| <p>IdentifierValue<br> \[1..1]</p>            | VARCHAR | Indicates the value of the entity identifier.                                                                                                |

### Entity Extension

The entity extension table is used to store additional, clinically relevant, versioned data attached to an entity that cannot be stored in the native data model.

| Column                                        | Type      | Description                                                                                                 |
| --------------------------------------------- | --------- | ----------------------------------------------------------------------------------------------------------- |
| <p>EntityExtensionId<br> \[1..1]</p>          | UUID      | Uniquely identifies the extension.                                                                          |
| <p>EffectiveVersionSequenceId<br> \[1..1]</p> | UUID      | Indicates the version of the entity when the extension data did become active.                              |
| <p>ObsoleteVersionSequenceId<br> \[0..1]</p>  | UUID      | When populated, indicates the version of the entity where the extension value is no longer applicable.      |
| <p>ExtensionTypeId<br> \[1..1]</p>            | UUID      | Indicates the type, or handler, for the extension data.                                                     |
| <p>ExtensionData<br> \[1..1]</p>              | VARBINARY | Serialized data that contains the raw value of the extension (serialized and de-serialized by the handler). |
| <p>ExtensionDisplay<br> \[1..1]</p>           | VARCHAR   | A textual, human readable expression of the extension value which can be displayed on reports, etc.         |

### Entity Telecom Address

The entity telecommunications address table is used to store data related to telecommunications addresses (email, fax, phone, etc.) for an entity.

| Column                                                     | Type    | Description                                                                                        |
| ---------------------------------------------------------- | ------- | -------------------------------------------------------------------------------------------------- |
| <p>EntityTelecomId<br> \[1..1]</p>                         | UUID    | Uniquely identifies the telecommunications address.                                                |
| <p>TelecomAddressType<br> \[1..1] \~TelecomAddressType</p> | UUID    | Classifies the type of address represented (example: phone, fax, email, etc.)                      |
| <p>TelecomAddress<br> \[1..1]</p>                          | VARCHAR | The value of the telecommunications address in RFC-2396 format.                                    |
| <p>TelecomUseConceptId<br> \[0..1] \~TelecomAddressUse</p> | UUID    | Identifies the intended use of the telecom address. (Example: home, work, etc.)                    |
| <p>EffectiveVersionSequenceId<br> \[1..1]</p>              | UUID    | Identifies the version of the entity whereby the telecom address became effective.                 |
| <p>ObsoleteVersionSequenceId<br> \[0..1]</p>               | UUID    | When populated, identifies the version of the entity where the telecom address is no longer valid. |

### Place

The place table represents a specialization of the Entity table which is used to represent physical places such as clinics, outreach activity sites, etc.

| Column                               | Type  | Description                                                            |
| ------------------------------------ | ----- | ---------------------------------------------------------------------- |
| <p>EntityVersionId<br> \[1..1]</p>   | UUID  | Identifies the version of the entity to which the place data applies.  |
| <p>MobileInd<br> \[1..1] = False</p> | BIT   | Indicator that is used to identify that a place is mobile.             |
| <p>Lat<br> \[0..1]</p>               | FLOAT | The latitudinal position of the place expressed in degrees latitude.   |
| <p>Lng<br> \[0..1]</p>               | FLOAT | The longitudinal position of the place expressed in degrees longitude. |

### Place Service

The place service table is used to identify the services that are provided at a particular place. Services may include stocking, transfer depots, immunization.

| Column                                            | Type    | Description                                                                                           |
| ------------------------------------------------- | ------- | ----------------------------------------------------------------------------------------------------- |
| <p>PlaceServiceId<br> \[1..1]</p>                 | UUID    | A unique identifier for the place service.                                                            |
| <p>EffectiveVersionSequenceId<br> \[1..1]</p>     | UUID    | The version of the place entity where the service entry is active.                                    |
| <p>ObsoleteVersionSequenceId<br> \[0..1]</p>      | UUID    | When populated, indicates the version of the place entity where the service entry is no longer valid. |
| <p>ServiceConceptId<br> \[1..1] \~ServiceType</p> | UUID    | Indicates a concept that describes the service offered.                                               |
| <p>ServiceSchedule<br> \[0..1]</p>                | XML     | An XML expression of the service schedule.                                                            |
| <p>ServiceScheduleType<br> \[0..1]</p>            | VARCHAR | Identifies the type of data stored in the service schedule column (iCal, GTS, etc.)                   |

### Application Entity

The application entity table is used to store entity data related to an application. An application is a software program that runs on a device. This differs from a security application, in that an application may be referenced clinically without needing access to the SanteDB system. For example: The patient uses MyPHR

| Column                             | Type    | Description                                                                             |
| ---------------------------------- | ------- | --------------------------------------------------------------------------------------- |
| <p>EntityVersionId<br> \[1..1]</p> | UUID    | Identifies the version of the entity to which the application data applies.             |
| <p>SoftwareName<br> \[0..1]</p>    | VARCHAR | Identifies the name of the software package (“EMR Package” is an example)               |
| <p>VersionName<br> \[0..1]</p>     | VARCHAR | Identifies the version of the software (example: “1.0”)                                 |
| <p>VendorName<br> \[0..1]</p>      | VARCHAR | The name of the vendor which distributes the software application (example: “ABC Corp”) |
| <p>ApplicationId<br> \[0..1]</p>   | UUID    | When populated, links the application entity to a security application.                 |

### Device Entity

The device table is used to store clinical information related to a physical device. Like an application entity, this table is used to describe the clinical attributes of a device used in the provisioning of care. Example: Bob’s Insulin Pump. The insulin pump itself may have no security device as it doesn’t require access to SanteDB.

| Column                                 | Type    | Description                                                                       |
| -------------------------------------- | ------- | --------------------------------------------------------------------------------- |
| <p>EntityVersionId<br> \[1..1]</p>     | UUID    | Indicates the version of the entity to which the device data applies.             |
| <p>ManufacturerModel<br> \[0..1]</p>   | VARCHAR | Indicates the name of the manufacturer of the device.                             |
| <p>OperatingSystemName<br> \[0..1]</p> | VARCHAR | Indicates the name of the operating system installed on the device.               |
| <p>DeviceId<br> \[0..1]</p>            | UUID    | When populated, identifies the security device associated with the device entity. |

### Material

A material represents a physical thing (syringe, drug, etc.) which participates in an act or is assigned to a person.

| Column                                               | Type     | Description                                                                                                                                                                                |
| ---------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| <p>EntityVersionId<br> \[1..1]</p>                   | UUID     | Identifies the version of the entity to which the material data applies.                                                                                                                   |
| <p>ExpiryTime<br> \[1..1]</p>                        | DATETIME | Indicates the time when the material will expire.                                                                                                                                          |
| <p>ExpiryTimePrecision<br> \[1..1]</p>               | CHAR     | Indicates the precision that the expiry time has.                                                                                                                                          |
| <p>FormConceptId<br> \[0..1] \~MaterialForm</p>      | UUID     | Identifies a concept that denotes the form that the material takes. Examples: capsule, injection, nebulizer, etc. For drugs and vaccines, the form will imply the route of administration. |
| <p>QuantityConceptId<br> \[0..1] \~UnitOfMeasure</p> | UUID     | Indicates the unit of measure for a single unit of the material. Examples: dose, mL, etc.                                                                                                  |
| <p>Quantity<br> \[0..1] = 1</p>                      | NUMERIC  | Indicates the reference quantity in UOM. For example, BCG MMAT is 5 mL of BCG Antigen                                                                                                      |
| <p>IsAdministrative<br> \[1..1] = false</p>          | BIT      | An indicator that is used to identify whether the material is a real material or an administrative material for the purpose of management.                                                 |

### Manufactured Material

A manufactured material is a specialization of a material that is manufactured.&#x20;

| Column                             | Type    | Description                                                                  |
| ---------------------------------- | ------- | ---------------------------------------------------------------------------- |
| <p>EntityVersionId<br> \[1..1]</p> | UUID    | Indicates the version of the material to which the specialized data applies. |
| <p>LotNumber<br> \[1..1]</p>       | VARCHAR | Indicates the manufacturer lot for the material.                             |

### Person

A person is a specialization of Entity that is used to represent a human.

| Column                                  | Type | Description                                                 |
| --------------------------------------- | ---- | ----------------------------------------------------------- |
| <p>EntityVersionId<br> \[1..1]</p>      | N/A  | The version of the entity to which the person data applies. |
| <p>DateOfBirth<br> \[0..1]</p>          | DATE | Indicates the date on which the person entity was born.     |
| <p>DateOfBirthPrecision<br> \[0..1]</p> | CHAR | Indicates the precision of the date of birth field.         |

### Person Communication Language

The person language communication table is used to store information related to the person’s language preferences. This can be used by the user interface to determine which language to display, however is also clinically relevant to indicate the language in which a patient wishes to receive communciations.

| Column                                               | Type    | Description                                                                                                          |
| ---------------------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------- |
| <p>PersonLanaugeCommunication<br> Id<br> \[1..1]</p> | UUID    | Uniquely identifies the language of communication.                                                                   |
| <p>EffectiveVersionSequenceId<br> \[1..1]</p>        | UUID    | Indicates the version of the person entity whereby the language of communication is effective.                       |
| <p>ObsoleteVersionSequenceId<br> \[0..1]</p>         | UUID    | When present, indicates the version of the person entity where the language of communication is no longer effective. |
| <p>LanguageCommunication<br> \[1..1] \~ISO639-2</p>  | VARCHAR | An ISO-639-2 language code indicating the language preference.                                                       |
| <p>PreferenceIndicator<br> \[0..1] = False</p>       | BIT     | Indicates whether the person prefers the language for communications.                                                |

### Organization

The organization table represents a specialization of an entity representing a logical organization.

| Column                                                 | Type | Description                                                                                      |
| ------------------------------------------------------ | ---- | ------------------------------------------------------------------------------------------------ |
| <p>EntityVersionId<br> \[1..1]</p>                     | UUID | Indicates the version of the entity to which the organization specialization applies.            |
| <p>IndustryConceptId<br> \[0..1] \~IndustryConcept</p> | UUID | Indicates the industry in which the organization operates. Examples: logistics, healthcare, etc. |

### Provider

A provider is a specialization of the Person table which is used to store provider related information about a person.

| Column                                  | Type | Description                                                                       |
| --------------------------------------- | ---- | --------------------------------------------------------------------------------- |
| <p>EntityVersionId<br> \[1..1]</p>      | UUID | Indicates the version of the entity to which the provider specialization applies. |
| <p>SpecialtyConceptId</p><p>\[1..1]</p> | UUID | Indicates the primary specialty of the provider at this version of the record.    |

### Patient

The patient entity is a specialization of the Person table which is used to track primary attributes related to a patient.

| Column                                                              | Type     | Description                                                                                                                                                                                                                   |
| ------------------------------------------------------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| <p>EntityVersionId<br> \[1..1]</p>                                  | UUID     | Indicates the version of the entity to which the patient specialization applies.                                                                                                                                              |
| <p>GenderConceptId</p><p>\[1..1] \~AdministrativeGender</p>         | UUID     | Identifies the logical gender concept of the patient. These values are drawn from the administrative gender concept set.                                                                                                      |
| <p>DeceasedTime</p><p>\[0..1]</p>                                   | DATETIME | When populated, indicates the date/time that the patient was indicated as deceased.                                                                                                                                           |
| <p>DeceasedTimePrecision</p><p>\[0..1]</p>                          | INT      | When populated, controls the precision of the value in DeceasedTime                                                                                                                                                           |
| <p>MultipleBirthOrder</p><p>\[0..1]</p>                             | INT      | When populated, indicates the order of the patient in a multiple birth. A non-null value in this column (0 or -1) indicates special indicators that the exact order is unknown, however the patient is part of a multi-birth. |
| <p>MaritalStatusConceptId</p><p>\[0..1] \~MaritalStatus</p>         | UUID     | The codified status of the patient's marital state (example: single, married, divorced, etc.). Drawn from the MaritalStatus concept set.                                                                                      |
| <p>EducationLevelConceptId</p><p>\[0..1] \~EducationLevel</p>       | UUID     | The codified value indicating the patient's highest level of education obtained (college, high school, etc.)                                                                                                                  |
| <p>LivingArrangementConceptId</p><p>\[0..1] \~LivingArrangement</p> | UUID     | The codified value indicating the patient's living arrangement (cohabitating, supervised care, etc.)                                                                                                                          |
| <p>ReligionConceptId</p><p>\[0..1] \~Religion</p>                   | UUID     | The codified value indicating the patient's religion. Note that the religion concept may be blocked based on national profiles and local legislation.                                                                         |
| <p>EthnicGroupConceptId</p><p>\[0..1] \~EthnicGroup</p>             | UUID     | The codified value indicating the patient's ethnicity.                                                                                                                                                                        |


# Null Reasons

Whenever submitting data to SanteDB's CDR where an element is marked as required, you may submit a null reason (also known as a null flavor). The allowed null flavors are:U

| Mnemonic           | Description                                                                                                                                       |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| AskedUnknown       | The value was asked for, however the known value could not be collected.                                                                          |
| Derived            | The value was not supplied because it can be calculated from other data provided.                                                                 |
| Invalid            | The value was not supplied because the known value would violate business rules.                                                                  |
| Masked             | The value is not supplied because the value is sensitive and disclosure may violate privacy.                                                      |
| NotApplicable      | The value is not supplied because it is not applicable (for example: Last menstrual period for a man)                                             |
| NotAsked           | The value is not supplied because it was not asked for.                                                                                           |
| Unavailable        | The value is not available at the time of data capture.                                                                                           |
| NoInformation      | The value is not supplied because there is no information supplied. This is the default null flavor to use.                                       |
| NegativeInfinity   | The value is not supplied because it is negative infinity.                                                                                        |
| Other              | The value was not supplied for some other reason.                                                                                                 |
| PositiveInfinity   | The value was not supplied because it is positive infinity.                                                                                       |
| SufficientQuantity | The value is of sufficient quantity to meet a clinical trigger, however the exact value could not be measured (i.e. off-scale 0 or off-scale max) |
| Trace              | The value is above 0, however the exact value is unknown or the equipment could not measure the quantity.                                         |
| UnEncoded          | The value could not be encoded into the message.                                                                                                  |
| Unknown            | The value is unknown (not asked, not measured, etc.)                                                                                              |


# Extended Data

The SanteDB CDR requires that any data provided to it by callers conform to the logical information either in XML, JSON or ViewModel formats.&#x20;

If you need to store data which cannot be captured in the primary information model you can add it with either an extension or a tag.

## Extensions

Extensions are versioned pieces of information which semantically change or modify the data structure, or capture complex data which changes over time. Extensions:

* Must have a registered extension type (a valid extension type UUID)
* Have effective/obsolete dates which means that they are subject to versioning and may need pruning
* Store the extension valid as a serialized BLOB

### Extension Data Type

SanteDB provides several built-in serializers for handling extension data which are used based on the type of data you'll be storing. SanteDB extension data types included within the solution are:

| Data Type | Handler                    | Description                                         |
| --------- | -------------------------- | --------------------------------------------------- |
| Binary    | BinaryExtensionHandler     | Stores a variable length byte array as a blob       |
| Boolean   | BooleanExtensionHandler    | Stores a 1 byte representation of a binary value    |
| Date      | DateExtensionHandler       | 64-bit (8 byte) ticks from UTC of the time stored   |
| Decimal   | DecimalExtensionHandler    | 128-bit (16 byte) decimal number                    |
| Dynamic   | DictionaryExtensionHandler | A JSON structure of any data object                 |
| Reference | ReferenceExtensionHandler  | A 128-bit UUID pointer to an Entity, Act or Concept |
| String    | StringExtensionHandler     | A variable length string stored in the database     |
| Uuid      | UuidExtensionHandler       | A 128-bit byte array representing a UUID            |

You can create additional extension data types by implementing the `IExtensionHandler` interface in a .NET plugin.&#x20;

### Extension Type Registration

SanteDB provides built extension types which are enumerated below.

{% hint style="info" %}
All extensions are in the <http://santedb.org/extensions> URL base.
{% endhint %}

| URL                                      | Type       | Use                                                                                           |
| ---------------------------------------- | ---------- | --------------------------------------------------------------------------------------------- |
| /core/jpegPhoto                          | Binary     | Stores a JPG photograph of an entity/act                                                      |
| /core/originalDate                       | Date       | Stores the original or amended date an action was supposed to occur.                          |
| /core/contactRole                        | Dictionary |                                                                                               |
| /core/detectedIssue                      | Dictionary | A structured list of business rules/data quality issues that were detected with an object.    |
| /stock/contrib/gs1/estimatedDeliveryDate | Date       | The original time (from the sender of a GS1 message) of estimated delivery date of an object. |
| /stock/contrib/gs1/shipmentDate          | Date       | The original shipment date of an action                                                       |
| /stock/contrib/gs1/packgingType          | String     | The type of packaging (crate, box, etc.) from the GS1 sender                                  |

You can register your own extensions by using the [HDSI interface](/developers/service-apis/health-data-service-interface-hdsi) and POSTing a new ExtensionType resource.

## Tags

Tags are another extension point which can be used to attach metadata to an object during processing, disclosure, or to control some operational process. Tags are not versioned and live throughout the lifetime of the object. Tags can be removed and updated, however the history of these changes are not tracked.

Tags require no formal definition of the tag type, and represent a simple key/value pair on the object.&#x20;

{% hint style="info" %}
Tag keys starting with $ are transient, meaning they aren't persisted to the database and are intended to control operational processes within the CDR and its plugins/business rules.
{% endhint %}

### SanteDB Core Tags&#x20;

SanteDB's core plugins affix tags to objects based on the plugins enabled and the status of the object. These tags are described below.

| Tag            | Values                                                                       | Use                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| -------------- | ---------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| $mdm.type      | <p>M = Master</p><p>L = Local</p><p>T = Record of Truth</p><p>O = Orphan</p> | <p>The MDM service uses the type tagging to convey the type <br>of master data record being provided. It is also used by </p><p>callers to instruct the MDM record to perform certain <br>behaviors. For example, sending an update with $mdm.type</p><p>of T would instruct the MDM layer that the resource being</p><p>pushed is a designated record of truth.</p>                                                                                                                                      |
| $mdm.processed | True \| False                                                                | <p>Indicates that the MDM layer has already processed the </p><p>object. This prevents duplicate processing of records.</p>                                                                                                                                                                                                                                                                                                                                                                               |
| $mdm.resource  | Patient \| Place ..                                                          | <p>Indicates the original type of resource the MDM record is</p><p>conveying. This is because MDM Masters are generic Entity</p><p>or Act resources with no clearly identified type. The <br>$mdm.resource tag allows callers to understand the original</p><p>type of data the master is representing</p>                                                                                                                                                                                                |
| $generated     | True \| False                                                                | <p>When retrieving data that was synthesized from other data</p><p>records this flag will be TRUE. This indicates that the result</p><p>is not an *actual* record, rather it is combined from multiple</p><p>local records.</p>                                                                                                                                                                                                                                                                           |
| $alt.keys      | UUID List                                                                    | <p>A list of other keys which the resource references may use.</p><p>Deprecated.</p>                                                                                                                                                                                                                                                                                                                                                                                                                      |
| $pep.masked    | True \| False                                                                | <p>When present in a resource, informs the caller that the </p><p>PolicyEnforcementService or PrivacyEnforcementService</p><p>has masked/redacted or removed sensitive data from the<br>resource returned. This is an indicator to the caller that they</p><p>may need to perform an elevation to unlock all the data. </p><p><strong>Note</strong>: If the PEP is set to HIDE sensitive data then the <br>resource is not returned in any disclosures, and the <br>$pep.masked flag will not appear.</p> |
| $pep.method    | hash \| hide \| redact                                                       | <p>When present in a resource, informs the caller that the policy </p><p>enforcement service took destructive action on the resource </p><p>using the specified privacy enforcement method.</p><p><strong>Note:</strong> The $pep.method of hide on a resource indicates <br>that part of the resource was hidden (usually identifiers)</p><p>if the entire resource is hidden, then the tag wouldn't appear</p><p>on a resource tag.</p>                                                                 |
| $bre.error     | String                                                                       | <p>Used by the BRE engine to convey non-fatal errors to </p><p>callers. This is used for diagnosing / logging and catching</p><p>upstream errors in business rules.</p>                                                                                                                                                                                                                                                                                                                                   |
| $sys.reclass   | True \| False                                                                | <p>Used by the persistence layer to determine whether an <br>object is being re-classified (having its type changed). </p><p>Normally this would cause an error in the persistence layer</p><p>however setting $sys.reclass=true instructs the persistence</p><p>layer to change the object's class. This is how, for example,</p><p>a Person may be re-classified as a Patient.</p>                                                                                                                      |
| $match.score   | 0.0 .. 1.0                                                                   | When the resource being conveyed is in the context of another (for example: a sub-resource or link resource) the match score will be added to indicate the strength of the relationship of the resource to the container.                                                                                                                                                                                                                                                                                 |


# Physical Model

In SanteDB, the physical model is used to express the concrete tables which are created in a SQL based RDBMS to store data on a physical media (disk). Implementers of new SQL based persistence services should try to re-use these mappings in their expression to the physical model.&#x20;

SanteDB uses the [ORM Lite](https://github.com/santedb/santedb-orm) data mapping technology, and the `SanteDB.Persistence.Data.Ado` assembly contains the ORM lite physical model classes.

{% hint style="info" %}
Version 2.5 of SanteDB is undergoing a major code refactor. The physical model classes in the 2.5.x series of SanteDB will reside in the `SanteDB.Persistence.Data` assembly.
{% endhint %}

\
Data Providers

SanteDB includes an implementation of a persistence layer which includes support for generic ADO based databases. This provider uses the ADO.NET wrapper to invoke necessary functions and select data from tables. In order to leverage the ADO.NET persistence service, the ADO.NET provider must support:

* SQL92 syntax&#x20;
* Limit and offset queries in the form of `SELECT FOO FROM BAR OFFSET x LIMIT y`
* Invoke of Stored Procedures and Functions or equivalent C# logic which implements the functions
* Pooled and thread-safe access to the underlying disk structure.

Currently SanteDB iCDR works with the following OrmLite data providers:

| **Database System**   | **Invariant** |
| --------------------- | ------------- |
| PostgreSQL 9.4 – 10.0 | npgsql        |
| FirebirdSQL 3.0       | FirebirdSQL   |
| SQLite 3.3            | Sqlite        |

&#x20;Regardless of the RDBMS system feeding the ADO provider, it must follow the schema specified in this section.

### Implementing new Data Providers

To implement a new ADO.NET based data provider, implementers will need to:

1. Write an ORM Lite `IDbProvider` instance (see an example of the [FirebirdSQL provider](https://github.com/santedb/santedb-orm/blob/master/SanteDB.OrmLite/Providers/Firebird/FirebirdSQLProvider.cs))
2. Write an ORM Lite `IDbConfigurationProvider` instance (see an example of the [FirebirdSQL Configuration provider](https://github.com/santedb/santedb-orm/blob/master/SanteDB.OrmLite/Providers/Firebird/FirebirdSQLConfigurationProvider.cs))
3. The DDL and DML classes for the most recent SanteDB physical model (see an example of the [FirebirdSQL DDL files](https://github.com/santedb/santedb-server/tree/master/SanteDB.Persistence.Data.ADO/Data/SQL/FBSQL))
   * You should include these as embedded resources in your plugin
   * You should include all updates , translated to your SQL dialect as well
   * You should include your own provider's invariant in the header
4. Implementations of any supported extended functions (such as SOUNDEX, LEVENSHTEIN, etc.) as `IDbFilterFunction` implementations (see an example [FirebirdSQL String Matching Functions](https://github.com/santedb/santedb-orm/blob/master/SanteDB.OrmLite/Providers/Firebird/StrMatchFunctions.cs))

## Patching SQL Tables

See: [Database Patching ](/developers/server-plugins/database-patching)article for information on patching SQL structures.

## Conventions

The physical schema of the ADO provider is designed such that many different ADO providers can support the data structures. Because of the limitations on some RDBMS systems, the ADO schema uses a short-hand for table names.&#x20;

### Suffixes

The following suffixes are placed on entities in the schema:

| Suffix   | Used For               | Example             |
| -------- | ---------------------- | ------------------- |
| \_TBL    | Tables                 | `ENT_VRSN_TBL`      |
| \_VW     | Views                  | `ENT_CUR_VRSN_VW`   |
| \_CDTBL  | Code Lookup Tables     | `ENT_REL_CLS_CDTBL` |
| \_SYSTBL | Internal System Tables | `PATCH_DB_SYSTBL`   |

### General Naming Conventions

Most tables in the SanteDB physical model carry common abbreviations of names. Because of the varied contributors some tables break these rules, however the general principal applies:

* Names less than four characters should be represented in full (example: `NAME` or `TAG`)
* Names which represent a classified object carry their classification, for example:
  * `OBS_TBL` => Observation Table
  * `SUB_ADM_TBL` => Substance Administration Table
* Association tables which exist only to link together two other tables should have `ASSOC` in their name
* Longer table names are usually acronyms:
  * `CD_TBL` => **C**oncept **D**efinition Table&#x20;
  * `CS_TBL` => **C**ode **S**ystem Table
* Table and columns should remove vowels where the removal of vowels do no interfere with understanding the meaning of the column or table:
  * `ENT_TBL` => Entity Table
  * `CLS_CD_ID` => **Cl**a**s**s **C**oncept **D**efinition ID

### Inherited Tables

Tables which represent an inheritance are created as discrete tables. Each class in the hierarchy maps to one table in the schema and contain only the attributes of the class.&#x20;

As an example:

```csharp
// Entity 
public class Entity 
{
}

// Person IS A Entity
public class Person : Entity
{
}

// Patient IS A Person
public class Patient : Person
{
}
```

In the database schema this inheritance structure is represented as:

```sql
CREATE TABLE ENT_TBL
(
    ENT_ID UUID NOT NULL,
    ...
    CONSTRAINT PK_ENT_TBL PRIMARY KEY (ENT_ID)
);

-- PERSON IS A ENTITY
CREATE TABLE PSN_TBL
(
    ENT_ID UUID NOT NULL,
    ...
    CONSTRAINT PK_PSN_TBL PRIMARY KEY (ENT_ID)
    CONSTRAINT FK_PSN_ENT_TBL FOREIGN KEY (ENT_ID) REFERENCES ENT_TBL(ENT_ID)
);

-- PATIENT IS A PERSON
CREATE TABLE PAT_TBL
(
    ENT_ID UUID NOT NULL,
    ...
    CONSTRAINT PK_PAT_TBL PRIMARY KEY (ENT_ID)
    CONSTRAINT FK_PAT_PSN_TBL FOREIGN KEY (ENT_ID) REFERENCES PSN_TBL(ENT_ID)
);

```

{% hint style="info" %}
On a versioned database each class down the hierarchy should point to the version identification of the superclass rather than the identifier of the superclass - this is to track versioned changes to first class properties.
{% endhint %}

### Versioning

On persistence services which provide versioning (such as those in the iCDR) the tables can be split into two categories:

* Versioned Tables -> Acts, Entities and Concepts which track changes to data over time.
* Non-Versioned Tables -> Any other class which does not track changes over time.

{% hint style="info" %}
The legacy dCDR SQLite provider is un-versioned. This means all of its tables are not versioned.
{% endhint %}

Because version data is required for interfaces in the iCDR the structures are broken into a primary table and a versioning table, where:

* Primary Table: Contains the unchanging attributes of the object
* Version Table: Contains the attributes which may be changed on the object. This table contains:
  * Sequence Identification (used for tracking the order of versions)
  * Creation time and provenance (who created the version)
  * Obsolete time and provenance (who rendered this version obsolete)
  * Replaced version id (the version that this version replaces)

For example, `ENT_TBL` and `ENT_VRSN_TBL` are related in this manner:

```sql
CREATE TABLE ENT_TBL (
    ENT_ID UUID NOT NULL,
    -- NON-VERSIONED PROPERTIES
    CONSTRIANT PK_ENT_TBL PRIMARY KEY (ENT_ID)
);

-- ENTITY VERSION TABLE
CREATE TABLE ENT_VRSN_TBL (
    ENT_VRSN_ID UUID NOT NULL,
    VRSN_SEQ_ID BIGINT NOT NULL, -- THE VERSION SEQUENCEING IDENTIFIER
    ENT_ID UUID NOT NULL, -- THE ENTITY THIS VERSION APPLIES TO 
    CRT_UTC TIMESTAMP NOT NULL, -- THE TIME THE VERSION WAS CREATED
    CRT_PROV_ID UUID NOT NULL, -- THE PROVENANCE THAT CREATED THIS
    OBSLT_UTC TIMESTAMP, -- THE TIME THE VERSION IS NO LONGER VALID
    OBSLT_PROV_ID UUID, -- THE PROVENANCE OF WHAT OBSOLETED THIS
    RPLC_VRSN_ID UUID, -- THE REPLACED VERSION
    ... -- VERSIONED DATA FIELDS
    CONSTRAINT PK_ENT_VRSN_TBL PRIMARY KEY (ENT_VRSN_ID),
    CONSTRAINT FK_ENT_VRSN_ENT_TBL FOREIGN KEY (ENT_ID) REFERENCES ENT_TBL(ENT_ID),
    CONSTRAINT FK_ENT_VRSN_RPLC FOREIGN KEY (RPLC_VRSN_ID) REFERENCE ENT_VRSN_TBL(ENT_VRSN_ID)
);

CREATE UNIQUE INDEX ENT_VRSN_SEQ_UQ_IDX ON ENT_VRSN_TBL(VRSN_SEQ_ID);
```

Tables which are associated with a versioned entity should be linked to the primary key of the non-versioned portion of the data, and carry an `Effective Version Seq` and an `Obsolete Version Seq.` For example, identifiers for an entity:

```sql
-- ENTITY IDENTIFIER
CREATE TABLE ENT_ID_TBL (
    ENT_ID_ID UUID NOT NULL, -- SURROGATE PRIMARY KEY
    ENT_ID UUID NOT NULL, -- THE ENTITY TO WHICH THIS IDENTIFIER IS RELATED
    EFFT_VRSN_SEQ_ID BIGINT NOT NULL, -- THE VERSION OF THE ENTITY WHERE THIS ID WAS VALID
    OBSLT_VRSN_SEQ_ID BIGINT, -- THE VERSION OF THE ENTITY WHERE THIS ID IS NO LONGER VALID
    ... -- DATA FIELDS
    CONSTRAINT PK_ENT_ID_TBL PRIMARY KEY (ENT_ID_ID),
    CONSTRAINT FK_ENT_ID_ENT_TBL FOREIGN KEY (ENT_ID) REFERENCES ENT_TBL(ENT_ID),
    CONSTRAINT FK_ENT_ID_EFFT_VRSN_TBL FOREIGN KEY (EFFT_VRSN_SEQ_ID) REFERENCES ENT_VRSN_TBL(VRSN_SEQ_ID),
    CONSTRAINT FK_ENT_ID_OBSLT_VRSN_TBL FOREIGN KEY (OBSLT_VRSN_SEQ_ID) REFERENCES ENT_VRSN_TBL(VRSN_SEQ_ID)
) 
```


# Act Data Dictionary

The [Conceptual Act Data Dictionary](/santedb/data-and-information-architecture/conceptual-data-model/acts/act-data-dictionary) expressed in ADO.NET tables.

![](/files/-MlR8vllCypMiFQEZe5p)

| **Physical Table**  | **Conceptual Entity**                                                                                                                                 | **Description**                                                                                                                                                                                            |
| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `act_tbl`           | [Act](/santedb/data-and-information-architecture/conceptual-data-model/acts/act-data-dictionary#act-entity)                                           | This table is used to store the non-versioned aspects of an act. These are things that are not supposed to change over the lifespan of an act                                                              |
| `act_vrsn_tbl`      | [Act (Versions)](/santedb/data-and-information-architecture/conceptual-data-model/acts/act-data-dictionary#actversion-entity)                         | This table is used to store the versioned portions of an act. The version sequence column should be a sequence which increments for each tuple (at minimum) or each new version of an object (best option) |
| `act_id_tbl`        | [Act Identifiers](/santedb/data-and-information-architecture/conceptual-data-model/acts/act-data-dictionary#actidentifier-entity)                     | This is an associative table which is used to store identifiers by which an act is referenced externally.                                                                                                  |
| `act_ext_tbl`       | [Act Extensions](/santedb/data-and-information-architecture/conceptual-data-model/acts/act-data-dictionary#actextension-entity)                       | Extensions table.                                                                                                                                                                                          |
| `act_proto_tbl`     | Act Protocols                                                                                                                                         | Act protocol implementation table.                                                                                                                                                                         |
| `act_ptcpt_tbl`     | [Act Participation](/santedb/data-and-information-architecture/conceptual-data-model/acts/act-data-dictionary#actparticipation-entity)                | Act participation table (links acts to entities)                                                                                                                                                           |
| `act_tag`           | [Act Tags](/santedb/data-and-information-architecture/conceptual-data-model/acts/act-data-dictionary#acttag-entity)                                   | Act tags table                                                                                                                                                                                             |
| `act_ext_tbl`       | [Act Extensions](/santedb/data-and-information-architecture/conceptual-data-model/acts/act-data-dictionary#actextension-entity)                       | Act extensions table (value should be a binary array or BLOB)                                                                                                                                              |
| `act_note_tbl`      | [Act Notes](/santedb/data-and-information-architecture/conceptual-data-model/acts/act-data-dictionary#actnote-entity)                                 | Act notes                                                                                                                                                                                                  |
| `act_pol_assoc_tbl` | Act Policies                                                                                                                                          | Policies which apply to the act.                                                                                                                                                                           |
| `act_rel_tbl`       | [Act Relationships](/santedb/data-and-information-architecture/conceptual-data-model/acts/act-data-dictionary#actrelationship-entity)                 | Relationships table. Note that effective/obsolete sequence columns refer to the source act.                                                                                                                |
| `sub_adm_tbl`       | [Substance Administrations](/santedb/data-and-information-architecture/conceptual-data-model/acts/act-data-dictionary#substanceadministration-entity) | Substance administration child table which is linked directly to the act table.                                                                                                                            |
| `obs_tbl`           | [Observation](/santedb/data-and-information-architecture/conceptual-data-model/acts/act-data-dictionary#observation-entity)                           | Observation child table which is linked to the act table.                                                                                                                                                  |
| `qty_obs_tbl`       | [Quantity Observations](/santedb/data-and-information-architecture/conceptual-data-model/acts/act-data-dictionary#quantityobservation-entity)         | Quantity Observation table which is linked with the observation table.                                                                                                                                     |
| `txt_obs_tbl`       | [Text Observations](/santedb/data-and-information-architecture/conceptual-data-model/acts/act-data-dictionary#textobservation-entity)                 | Text observations table which is linked with the observation table.                                                                                                                                        |
| `cd_obs_tbl`        | [Coded Observations](/santedb/data-and-information-architecture/conceptual-data-model/acts/act-data-dictionary#codedobservation-entity)               | Coded observations table which is linked to the observation table.                                                                                                                                         |
| `pat_enc_tbl`       | [Patient Encounters](/santedb/data-and-information-architecture/conceptual-data-model/acts/act-data-dictionary#patientencounter-entity)               | Patient encounters table which is linked to the act table.                                                                                                                                                 |
| `proc_tbl`          | [Procedures](/santedb/data-and-information-architecture/conceptual-data-model/acts/act-data-dictionary#procedure-entity)                              | Procedures tablet which is linked to the act table.                                                                                                                                                        |


# Entity Data Dictionary

The [Conceptual Entity Data Dictionary](/santedb/data-and-information-architecture/conceptual-data-model/entities/data-dictionary) expressed in ADO.NET tables.<br>

![](/files/-MlR7PIsoiK53uz2Tixl)

| **Physical Table**     | **Conceptual Entity**                                                                                                                          | **Description**                                                                                                                                                                                                                                                                                               |
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `app_ent_tbl`          | [Application Entity](/santedb/data-and-information-architecture/conceptual-data-model/entities/data-dictionary#application-entity)             | This table is used to describe the clinical attributes of an application such as vendor, version etc. This differs from the security definition of an application. A security application may exist without a clinical application existing.                                                                  |
| `dev_ent_tbl`          | [Device Entity](/santedb/data-and-information-architecture/conceptual-data-model/entities/data-dictionary#device-entity)                       | This table is used to describe the clinical attributes of a device. For example an insulin pump. Like an application, a clinical device may not be a security device or vice versa. For example when describing an event in which a device was involved , but that device does not need access to the system. |
| `ent_addr_cmp_tbl`     | [Entity Address Component](/santedb/data-and-information-architecture/conceptual-data-model/entities/data-dictionary#entity-address-component) | This table is used to store entity address components. In order to normalize addresses, the values of the addresses themselves are not stored in this table, rather, stored in a unique datatable.                                                                                                            |
| `ent_addr_cmp_val_tbl` | N/A                                                                                                                                            | This table stores the unique values of all address components found in the SanteDB system.                                                                                                                                                                                                                    |
| `ent_addr_tbl`         | [Entity Address](/santedb/data-and-information-architecture/conceptual-data-model/entities/data-dictionary#entity-address)                     | Stores information related to an entity’s physical, mailing or other postal addresses                                                                                                                                                                                                                         |
| `ent_ext_tbl`          | [Entity Extension](/santedb/data-and-information-architecture/conceptual-data-model/entities/data-dictionary#entity-extension)                 | Stores the data related to entity extensions. Entity extensions are versioned, additional values for a particular entity.                                                                                                                                                                                     |
| `ent_id_tbl`           | [Entity Identifier](/santedb/data-and-information-architecture/conceptual-data-model/entities/data-dictionary#entity-identifier)               | The entity identifier table is used to store alternate, external identifiers associated with a particular entity                                                                                                                                                                                              |
| `ent_name_cmp_tbl`     | [Entity Name Component](/santedb/data-and-information-architecture/conceptual-data-model/entities/data-dictionary#entity-name-component)       | The entity name component table is used to store the individual components (family, given, prefix, suffix) of an entity’s name.                                                                                                                                                                               |
| `ent_name_tbl`         | [Entity Name](/santedb/data-and-information-architecture/conceptual-data-model/entities/data-dictionary#entity-name)                           | The entity name table is used to store the names associated with a particular entity. For example, a patient may have a married and maiden name.                                                                                                                                                              |
| `ent_note_tbl`         | [Entity Notes](/santedb/data-and-information-architecture/conceptual-data-model/entities/data-dictionary#entity-note)                          | The entity note table is used to store freetext notes about a patient.                                                                                                                                                                                                                                        |
| `ent_rel_tbl`          | [Entity Relationship](/santedb/data-and-information-architecture/conceptual-data-model/entities/data-dictionary#entity-relationship)           | Entity relationships are relationships between one or more entities with one another. For example, a service delivery location may have one or more employees.                                                                                                                                                |
| `ent_tag_tbl`          | [Entity Tags](/santedb/data-and-information-architecture/conceptual-data-model/entities/data-dictionary#entity-tag)                            | Entity tags are non-versioned extensions of an entity. That is their value can change however changes are not tracked over time.                                                                                                                                                                              |
| `ent_tbl`              | [Entity](/santedb/data-and-information-architecture/conceptual-data-model/entities/data-dictionary#entity)                                     | Represents a non-versioned parts of the core entity such as class, determiner, etc.                                                                                                                                                                                                                           |
| `ent_tel_tbl`          | [Entity Telecom Addresses](/santedb/data-and-information-architecture/conceptual-data-model/entities/data-dictionary#entity-telecom-address)   | Stores telecommunications addresses related to the entity and their associated type (phone, email, etc) and use (work, home, mobile, etc.)                                                                                                                                                                    |
| `ent_vrsn_tbl`         | [Entity Versions](/santedb/data-and-information-architecture/conceptual-data-model/entities/data-dictionary#entity-version)                    | This table is used to store the data which can change over time for an entity such as status, additional classifier, etc.                                                                                                                                                                                     |
| `mat_tbl`              | [Material](/santedb/data-and-information-architecture/conceptual-data-model/entities/data-dictionary#material)                                 | This table is used to store information related to materials.                                                                                                                                                                                                                                                 |
| `mmat_tbl`             | [Manufactured Materials](/santedb/data-and-information-architecture/conceptual-data-model/entities/data-dictionary#manufactured-material)      | This table is used to store information related to manufactured materials.                                                                                                                                                                                                                                    |
| `org_tbl`              | [Organization](/santedb/data-and-information-architecture/conceptual-data-model/entities/data-dictionary#organization)                         | This table is used to store information related to organizations, which are groupings of people, places for administrative purposes.                                                                                                                                                                          |
| `pat_tbl`              | [Patient](/santedb/data-and-information-architecture/conceptual-data-model/entities/data-dictionary#patient)                                   | This table is used to store information related to patients, or those who are receiving care.                                                                                                                                                                                                                 |
| `plc_svc_tbl`          | [Place Services](/santedb/data-and-information-architecture/conceptual-data-model/entities/data-dictionary#place-service)                      | This table is used to store information related to the services which occur at a particular place.                                                                                                                                                                                                            |
| `plc_tbl`              | [Place](/santedb/data-and-information-architecture/conceptual-data-model/entities/data-dictionary#place)                                       | This table is used to store information about a physical place. In Open IZ places can represent delivery locations (hospitals, clinics, etc.) or administrative units (states, cities, etc.)                                                                                                                  |
| `psn_lng_tbl`          | [Person Languages](/santedb/data-and-information-architecture/conceptual-data-model/entities/data-dictionary#person-communication-language)    | This table is used to store information related to the languages which a person (including patients) speak.                                                                                                                                                                                                   |
| `psn_tbl`              | [Person](/santedb/data-and-information-architecture/conceptual-data-model/entities/data-dictionary#person)                                     | This table is used to store information related to persons (including patients and providers).                                                                                                                                                                                                                |
| `pvdr_tbl`             | [Provider](/santedb/data-and-information-architecture/conceptual-data-model/entities/data-dictionary#provider)                                 | This table is used to store information related to providers (persons who deliver care).                                                                                                                                                                                                                      |
| `usr_ent_tbl`          | [User Entity](/santedb/data-and-information-architecture/conceptual-data-model/entities/data-dictionary#person)                                | This table is used to link the security subsystem for users to the clinical subsystem of entities (as entities are the ones who participate in Acts rather than Security Users).                                                                                                                              |


# Concept Dictionary Data Dictionary

The [Conceptual Concept Dictionary](/santedb/data-and-information-architecture/conceptual-data-model/concept-dictionary/data-dictionary) expressed in the physical data model in ADO.NET providers is illustrated below.

![](/files/-MlR4-77tT4utaqaNwKg)

| Physical Table          | Conceptual Entity                                                                                                                                          | Description                                                                                     |
| ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
| `cd_tbl`                | [Concept](/santedb/data-and-information-architecture/conceptual-data-model/concept-dictionary/data-dictionary#concept)                                     | Non-versioned properties of the concept table.                                                  |
| `cd_vrsn_tbl`           | [Concept Version](/santedb/data-and-information-architecture/conceptual-data-model/concept-dictionary/data-dictionary#concept-version)                     | Versioned properties of the concept table.                                                      |
| `cd_name_tbl`           | [Concept Name](/santedb/data-and-information-architecture/conceptual-data-model/concept-dictionary/data-dictionary#concept-name)                           | Human readable names of the concept in various languages.                                       |
| `cd_rel_assoc_tbl`      | [Concept Relationship](/santedb/data-and-information-architecture/conceptual-data-model/concept-dictionary/data-dictionary#concept-relationship)           | Concept relationships table.                                                                    |
| `cd_rel_typ_cdtbl`      | [Concept Relationship Type](/santedb/data-and-information-architecture/conceptual-data-model/concept-dictionary/data-dictionary#concept-relationship-type) | Concept Relationship types reference code table.                                                |
| `cd_set_tbl`            | [Concept Set](/santedb/data-and-information-architecture/conceptual-data-model/concept-dictionary/data-dictionary#concept-set)                             | Concept Set definition table.                                                                   |
| `cd_set_mem_assoc_tbl`  | Concept Set Member                                                                                                                                         | Concept Set <> Concept relationship associative table.                                          |
| `cd_ref_term_assoc_tbl` | [Concept Reference Term](/santedb/data-and-information-architecture/conceptual-data-model/concept-dictionary/data-dictionary#concept-reference-term)       | Concept <> Reference Term associated table.                                                     |
| `ref_term_tbl`          | [Reference Term](/santedb/data-and-information-architecture/conceptual-data-model/concept-dictionary/data-dictionary#reference-term)                       | Reference term definition table.                                                                |
| `ref_term_name_tbl`     | [Reference Term Name](/santedb/data-and-information-architecture/conceptual-data-model/concept-dictionary/data-dictionary#reference-term-display-name)     | Preferred display names of the reference term (when being represented on a standards interface) |
| `cd_sys_tbl`            | [Code System](/santedb/data-and-information-architecture/conceptual-data-model/concept-dictionary/data-dictionary#code-system)                             | Code system table                                                                               |


# Data Storage Patterns

Exploring SanteDB's patterns of data storage

SanteDB's iCDR and dCDR platforms are designed to operate like any regular CDR. By default, when you install SanteDB's CDR software, the solution will permit the storage and retrieval of the data. This method of operation is sufficient for deployments where SanteDB is servicing a single purpose, for example: a national immunization registry, where only SanteDB is contributing data to / from the central server.&#x20;

However, when you want to run SanteDB as an integrator of data (for example, as an MPI or a Shared Health Record (SHR)) this mode of operation is no longer optimal. In the field you will have multiple data sources contributing a variety of information.&#x20;

SanteDB ships with a matching engine that operates in either deterministic or probabilistic modes, these functions are described in the Matching engine documentation. However, once a match is detected, one of two storage patterns can be used.

### Single-Instance Mode

When SanteDB's SIM data storage pattern service is enabled, the SIM service will handle the matching and merging of records. In single instance mode, SanteDB's storage engine will flag duplicates (or merge them, depending on your configuration) however will only ever keep one copy of a known good record.

This means, for example, if one system reports a Facility Registration for a facility name "Good Health Hospital", and another reports a facility "Good Health Hospital" that is determined to be a duplicate, SanteDB will flag the two records as duplicates. Once merged, one record is subsumed into the other, the subsumed record is nullified and no longer appears in searches.&#x20;

### Multi-Instance / Master Data Management Mode&#x20;

When SanteDB's MIM data storage pattern service is enabled, the behavior of the software is quite different. In MIM mode, SanteDB will store all records as a "local" record and tag them as mdm.type=L. The solution then searches for other records which might be duplicated in its data store.

If SanteDB determines no other records match the local record created, it will generate a new master record and tag it as mdm.type=M. Master records aren't really records, rather they are pointers (or an anchor point) where local records are attached.&#x20;

If the matching system determines that there are potential matches, depending on configuration, it will either link the newly inserted local record to the existing master record which matches, or it will simply mark the record as a candidate local (for later merging).

The sending system has complete authority to update its local records however it wants, it may change names, dates of birth, etc. When an update occurs on a local, the MIM pattern service will re-run the matching rules to determine if the local is still, indeed a match with the master, or if the record could be linked to another master.

When in MIM mode, and a query is run, the MIM persistence service will query for local records which match the specified criteria, and will synthesize a master based on the data elements the requesting system has appropriate access permission for.

Multi-instance mode is very useful for central registries like MPI, MFR, and MPR. It has several benefits over SIM:

* Merged records can subsequently be un-merged
* It is possible to flag / compartmentalize local records based on their access policies (for example, you can prevent an immunization registry from seeing an HIV programme information)
* It allows complete versioning and tracking of updates made to the local record.

#### Records of Truth

When running in MIM mode, it is possible to assign attributes of the various local records into a record of truth. For example, if you collect patient information from several hospitals about a particular patient (say: William Butler in hospital A, Bill Butler from hospital B), it is possible to designate an official record of truth for that patient. A record of truth will always be returned to callers, and prevents the synthesizing of master data records (or rather, it overrides the local fields which have been promoted to record of truth status).

Records of truth cannot be edited by local systems, records of truth can only be edited by the iCDR in which the record resides.


# Master Data Storage

The Master Data Management plugin permits your SanteDB CDR instance to store multiple copies of a single record based on the source system which provided the data. The MDM services are available on the following resources:

* Patient
* Place
* Provider
* Materials (and Manufactured Materials)
* Device Entities
* Persons

{% hint style="info" %}
The use of Master Data Management services require a compatible [Matching and Merge](broken://pages/-MDKigCduY4LFGruHO_w) service to operate. This is how the MDM solution detects candidate master records.
{% endhint %}

## MDM Data Storage Pattern

Within the data storage persistence layer, the MDM plugin will update/create locals using whatever underlying class was sent from the caller. Each caller is provided a complete copy of the record which they can update/edit.

The MDM plugin then determines:

* Is there a MASTER record which the IRecordMatching service has identified as positive match?
* Is the configuration enabled to automatically link these records?

If no MASTER is found, or the configuration does not permit auto-linking then a new MASTER of the base type is constructed (Entity in case of Patient, Place, Material, etc. or Act in the case of Administration, Procedure, Observation, etc.) and links the LOCAL record to this newly created master instance using the relationship type `MDM-MasterRecord`.

![](/files/-MNyH9m7RyawnSmmVkGr)

The master record should have **no data** associated with it. It is merely an anchor which is used to collect the local records. Typically a master record can have extensions, notes, identifiers, names, etc. associated with it, however these attributes should apply to the anchor point rather than for establishing ROT data.

### Candidate Links

In the case where a match between a LOCAL and MASTER record is ambiguous (i.e. does is a Probable match or when Auto-Link is disabled) the link between records is considered a candidate and the local is related to the MASTERs which it is a candidate for using the `MDM-CandidateLocal` relationship type.

In the scenario below, Good Health Clinic has registered John Doe born Jan 1 1980 with ID 1230493. The MDM layer has constructed a master record. A subsequent registration by HIV Health Clinic for John Doe, born sometime in 1980 with ID 3029402 as registered after.

Assuming that the match configuration was setup such that the HIV record had a match score below "DEFINITE" match, the MDM plugin would establish a new MASTER which contains one LOCAL. That LOCAL would also be related to the MASTER from Good Health Clinic with relationship type `MDM-CandidateLocal`.<br>

![](/files/-MNyK96CSRWZIkVrvakw)

This candidate link exists until:

* A subsequent update from either the HIV Health Clinic (to record 3029402) or Good Health Clinic (to record 1230493) means that the patients no longer meet threshold for match.
* The match configuration is updated, which scores the link below the threshold for probable match.
* An administrator establishes a new link between the HIV Clinic and the MASTER of `MDM-IgnoreCandidate` (which indicates a known false-match).
* An administrator manually indicates that the HIV Health Clinic record is a known match to the MASTER (in which case the MDM-MasterRecord link is removed and updated (as shown below).

![](/files/-MNyKQcgU84eFGArvcUG)

### Record of Truth

The MDM solution permits the establishing of a Record Of Truth (ROT). The Record Of Truth is a new local instance which belongs to the SYSTEM and can only be updated when the security principal is permitted MDM Record Of Truth.&#x20;

A ROT record is a special pointer at a LOCAL whereby the LOCAL points to the MASTER record, and the MASTER points at the ROT with relationship type of `MDM-RecordOfTruth`.&#x20;

{% hint style="info" %}
It is possible to manually elevate an existing LOCAL as a ROT record, however this is not yet supported on user interfaces available.
{% endhint %}

![](/files/-MNyMZYB3dALnJmi9deu)

### Privacy Masking

It is a commonly asked how the solution operates when a sensitive LOCAL record is shared with common health infrastructure. In the case of SanteDB's iCDR, when a MASTER record has multiple LOCALS the information returned to a caller is a synthesized copy of data within the LOCAL records.

The synthetization process uses a most-restrictive policy enforcement mechanism before considering a local for inclusion in the result. In the example illustrated above, the information sourced from the HIV Health Clinic is tagged as TABOO information.&#x20;

When a caller asks the CDR for the MASTER, the MDM service will call the `IPolicyDecisionService` and ask for a decision on each of the flagged policies in each of the locals and will return either:

* The UNION of data from both Good Health Clinic and HIV Health Clinic when TABOO has a **GRANT**, or
* Only data from Good Health Clinic when TABOO policy outcome is **DENY**, or
* Only the data from Good Health Clinic and an indicator of elevation required (i.e. indicator more data is present) when the TABOO policy outcome is **ELEVATE.**

## MDM Service Relationships

The MdmDataManagementService should be configured in your application context. Upon start, this daemon will read the contents of the `ResourceMergeConfigurationSection` to determine the appropriate instances of `MdmResourceListener<T>` to construct and register with the provider.

![](/files/-MNyEXVR0rzLashYjSKN)

For example, given a configuration as provided below

```markup
<section xsi:type="ResourceMergeConfigurationSection">
  <resources>
    <add type="Patient" matchConfiguration="org.santedb.smpi.matching.default" autoMerge="false" />
    <add type="Place" matchConfiguration="org.santedb.shfr.matching.default" autoMerge="false" />
  </resources>
</section>
```

The MdmDataManagementService on start would register two resource listeners for Patient and Place. It would furthermore, instruct each resource listener to use the specified match configuration for detecting candidate local<>master linkages.

### MDM Resource Listener

The resource listener instances created by the data management service subscribe to the repository events for the indicated type. The resource listener receives an event broadcast from the repository service whenever an event occurs and takes appropriate actions.

#### Data Update Operations

The `Saving` and `Inserting` events of the repository service are subscribed on service start. Whenever data through a repository is being actioned the events are raised and the following actions occur on the MDM Resource Listener:

* The instances are validated through OnPrePersistenceValidate() method. Here the process ensures:
  * The caller is not attempting to update a MASTER record. If it is, the appropriate LOCAL for that principal is exchanged.
  * If the caller is attempting to create a RECORD OF TRUTH , it has appropriate permission to do so
* The Saving() and Inserting() event handlers are called next. These methods:
  * Call the matching service and attempt to establish whether the LOCAL is a candidate for an existing record
  * Appropriately obsolete/create resource links between the objects.
  * Cancels the caller (i.e. overwrites the default call path)
  * Returns a BUNDLE which is treated as a transaction on the persistence layer.

#### Data Query / Retrieval Operations

When a repository's `Find()` or `Get()` methods are called the repository will call the `Retrieving` and `Querying` event handlers. The MDM resource listener for that repository will perform the following operations:

* Cancel the default path of the repository
* Re-write the HDSI expression tree to query attributes related to the ROT or a LOCAL

The resource listener also subscribes to the Retrieved and Queried event handlers where any local objects which were fetched from the underlying data persistence layer are synthesized using their MASTER links (and appropriate policies applied).

## Behaviors

The following section outlines several common behaviors and patterns to assist in understanding how MDM works in SanteDB.

### Case 1: New Object Registered

When the CDR receives a request to create a new entity which is under MDM control, as shown below.&#x20;

![](/files/-M_XTQkSafXb6vFL33us)

1. The source record is issued a new UUID
2. The MDM layer will attempt to determine if the source record matches any MASTER records that currently exist within the database (using the resource merge configuration).
3. If no matching MDM MASTER is found, then the a new MASTER record is created and the SOURCE linked to the MASTER with its own UUID.
   1. The relationship is indicated with RelationshipType MDM-MASTER
   2. The classification of this relationship is AUTO

![](/files/-M_XTui6mkiRbRfK4kWD)

Any future queries based on the demographics will result in the MASTER\_A record being returned and synthesized from the source records according to the synthesization rules.&#x20;

![](/files/-M_XVAMp3OyvUsNGqVoV)

### Case 2: Duplicate Object Created (AutoLink Enabled)

When the CDR receives a registration request for a new object which is under MDM control, such as shown below:

![](/files/-M_XUPEdLNRP9hjwK3I4)

1. The source record is issued as new UUID
2. The IRecordMatchService is called with the specified configurations. If this process classifies a record as MATCH and AutoLink is turned on for that match configuration
   1. The SORUCE is linked to the MASTER with relationship MDM-Master&#x20;
   2. The classification of this relationship is AUTO
   3. The weighting of the match is stored

![](/files/-M_XVNF4vTZOV8tyvGZH)

A query for EID A123 would now result in a single result with the synthesized data from both sources and links to the sources where the data was obtained.<br>

![](/files/-M_XVZ0mt25mAHleiPFZ)

### Case 3: Suspected Duplicate Object Created (or AutoLink disabled)

When the CDR receives a request to create an object with similar attributes however as above, however:

* The attribute score from the fuzzy matching engine falls below the threshold of a definite match, or
* The automatic linking feature for the match configuration is disabled

Such as the patient illustrated below.

![](/files/-M_XWCfuX_w-06dUIBoZ)

The behavior is as follows:

1. The SOURCE is issued a new UUID
2. A new MASTER is created with a new UUID
3. The SOURCE is linked to the new MASTER&#x20;
   1. The relationship type is MDM-Master
   2. The classification of the relationship is AUTO
4. The SOURCE is linked to the suspected MASTER&#x20;
   1. The relationship type is MDM-CandidateLocal
   2. The classification of the relationship is AUTO
   3. The score of the match is stored as the relationship strength

![](/files/-M_XWtnEU7ESi6KpOhqy)

### Case 4: Object is Updated to Match MASTER

When the CDR receives a request to update a source record, it does so against the source (or if the update was attempted against the MASTER the SOURCE is created or located). When this occurs, the matching is re-run and if determined that the records now match the relationships are re-calculated.&#x20;

For example, given this update to SOURCE\_C.

![](/files/-M_XXVg6fA0XuFzX-1Nh)

The `SOURCE_C` record would be updated to match and the matching re-run, it may be determined that `SOURCE_C` is in fact the same person as `MASTER_A`

![](/files/-M_XXzU_ZNdtmnEUTKfA)

In this case, `SOURCE_C` is DETACHED from `MASTER_C` and then attached to `MASTER_A`.

### Case 5: Manual Reconciliation

The CDR also provides interfaces for manually reconciling candidate matches. Take for example, an instruction to reconcile `SOURCE_C` and `MASTER_A`.

![](/files/-M_XYQeGOOnwzJgRclzV)

In this method (also known as a LOCAL>MASTER merge) the MDM-Candidate link is translated into a MDM-Master and the classification set to VERIFIED.

![](/files/-M_XZ3_X5FGLEQRPnZmW)

{% hint style="info" %}
Any operation which removes all MDM-Master links from a MASTER record will result in the automatic obsolete of the MASTER record.
{% endhint %}

## Merging / Linking

Callers can directly manipulate the relationships using the `IRepositoryService<EntityRelationship>` services to implement custom logic for merging and linking. By default the MDM layer registers `IRecordMergeService<T>` instances which implement a default behavior for external calls to MERGE data.

| Victim Type | Survivor Type | No Permission | Write MDM           | Merge MDM           |
| ----------- | ------------- | ------------- | ------------------- | ------------------- |
| LOCAL       | LOCAL         | Local Merge   | Local Merge         | Local Merge         |
| LOCAL       | MASTER        | Local Merge   | Local/Master Relink | Local/Master Relink |
| MASTER      | MASTER        | Local Merge   | Local/Master Relink | Master Merge        |
|             |               |               |                     |                     |

### Local/Master Re-Link

A LOCAL>MASTER link operation is initiated by calling `Merge()` in `IRecordMergeService<T>` , and passing a UUID of a MASTER record and the linked duplicate UUIDs that are either:

* The explicit UUIDs of local records (i.e. the UUID pointing at the local record), or
* The UUID of masters where the caller does not have `Merge MDM Master` permission

This operation works by unlinking the local/duplicate record relationships (of `MDM-Master` ) and re-establishing the link on the locals to the surviving master. This is a form of linking where neither the master nor the local records are merged.&#x20;

For example, if a principal has `Write MDM Master` permission, and issues the following `ADT^A40` :

```markup
MSH|^~\&|TEST_HARNESS^^|TEST^^|CR1^^|MOH_CAAT^^|20141104174451|DEVICESECRET|ADT^A40^ADT_A39|TEST-CR-16-30|P|2.3.1
EVN||20101020
PID|||XXXXX^^^TEST||JONES^JENN^^^^^L||198401|F|||||||||||
MRG|YYYYY^^^TEST
```

The process would be:

* Load the record `XXXXX` in domain TEST (MASTER)
* Load the record `YYYYY` in domain TEST (MASTER)
* Call `Merge()` for MASTER>MASTER
* Client has `Write MDM Master` so record `XXXXX` remains the target of the merge.
* Client does not have `Merge MDM Master` so record `YYYYY` is resolved to LOCAL record for TEST\_HARNESS at site TEST (`LYYYY`)
* Merge proceeds as LOCAL>MASTER
  * `LYYYY` is disconnected from master `YYYY`
  * `LYYYY` is attached to master `XXXX`
  * If no further locals point at `YYYY` it is obsoleted.

### Master Merge

A MASTER to MASTER merge is the process whereby one master record is merged into another, and all associated LOCAL relationships are migrated to the survivor. Callers may only initiate a master merge when the principal carries the `Merge MDM Master` policy permission, otherwise an alternate merge strategy is used.

{% hint style="info" %}
Giving applications using the HL7v2 or HL7 FHIR interfaces permission for Merge MDM Master is not recommended as any use of a business identifier in those messages would result in a master merge, since the query stage loads master records on those interfaces.
{% endhint %}

The process for performing a master merge is:

* Load record `XXXX` in domain TEST (MASTER)
* Load record `YYYY` in domain TEST (MASTER)
* Call `Merge()` for MASTER>MASTER
* Client has `Write MDM Master` so record `XXXX` remains target of merge
* Client has `Merge MDM Master` so record `YYYY` remains source of merge
* Merge proceeds:
  * All `MDM-Master` associations previously pointing at `YYYY` are rewritten to `XXXX`
  * All identifiers directly on `YYYY` master record are copied to `XXXX`
  * `YYYY` is obsoleted&#x20;

### Local Merge

A local merge occurs when a source system indicates it has resolved duplicates in its own database issues an appropriate merge request to the iCDR. The local merge is the default operation whenever the caller is not granted explicit permission to perform MDM merges on the server.&#x20;

The process for performing a local merge is:

* Load record `XXXX` in domain TEST (MASTER)
* Load record `YYYY` in domain TEST (MASTER)
* Call `Merge()` for MASTER>MASTER
* Client does not have`Write MDM Master` so a local record for `XXXX` is resolved (`LXXXX`)
* Client does not have `Merge MDM Master` so a local record for `YYYY` is resolved (`LYYYY`)
* If `LYYYY` and `LXXXX` were resolved, then the merge occurs:
  * The record `LYYYY` is obsoleted
  * All identifiers from `LYYYY` are copied to `LXXXX` so that any query to `LYYYY` are resolved to the survivor


# SanteDB Object Identifiers (OIDs)

SanteDB uses object identifiers (OIDs) in one of two registered IANA Private Enterprise Number (PEN) namespaces. The use of these PEN roots depends on the timeframe when the feature was designed:

* Features from OpenIZ (SanteDB v1) and SanteDB v2 reside in the PEN for Mohawk College of Applied Arts and Technology / Applied Research: `1.3.6.1.4.1.33349.3.1.5.9`
* Features from SanteDB v2 and v3 reside in the Fyfe Software Inc. PEN: `1.3.6.1.4.1.52820.5`

The root of SanteDB OIDs from  the OpenIZ root `1.3.6.1.4.1.33349.3.1.5.9`

## OID Namespaces

| Root                      | Child |                                 |
| ------------------------- | ----- | ------------------------------- |
| 1.3.6.1.4.1.33349.3.1.5.9 | 0     | Services                        |
| 1.3.6.1.4.1.33349.3.1.5.9 | 2     | Privacy & Security              |
| 1.3.6.1.4.1.33349.3.1.5.9 | 3     | Concepts & Vocabulary           |
| 1.3.6.1.4.1.52820.5       | 1     | Deployments                     |
| 1.3.6.1.4.1.52820.5       | 2     | Clinical Templates              |
| 1.3.6.1.4.1.52820.5       | 3     | Clinical Protocols & CDSS Rules |
| 1.3.6.1.4.1.52820.5       | 4     | Identity Domains                |

## Privacy & Security OIDs

Privacy and security OIDs assigned in the `1.3.6.1.4.1.33349.3.1.5.9.2` namespace represent policies. These policies are expressed in OIDs as they are hierarchical in nature. The default OIDs in this namespace are:

| OID                                   | Policy                                                          |
| ------------------------------------- | --------------------------------------------------------------- |
| 1.3.6.1.4.1.33349.3.1.5.9.2           | Unrestricted All                                                |
| 1.3.6.1.4.1.33349.3.1.5.9.2.0         | Unrestricted Administrative Function                            |
| 1.3.6.1.4.1.33349.3.1.5.9.2.0.1       | Change Password                                                 |
| 1.3.6.1.4.1.33349.3.1.5.9.2.0.2       | Create Role                                                     |
| 1.3.6.1.4.1.33349.3.1.5.9.2.0.3       | Alter Role                                                      |
| 1.3.6.1.4.1.33349.3.1.5.9.2.0.4       | Create Identity                                                 |
| 1.3.6.1.4.1.33349.3.1.5.9.2.0.4.1     | Create Local Users                                              |
| 1.3.6.1.4.1.33349.3.1.5.9.2.0.5       | Create Device                                                   |
| 1.3.6.1.4.1.33349.3.1.5.9.2.0.6       | Create Application                                              |
| 1.3.6.1.4.1.33349.3.1.5.9.2.0.7       | Administer Concept Dictionary                                   |
| 1.3.6.1.4.1.33349.3.1.5.9.2.0.8       | Alter Identity                                                  |
| 1.3.6.1.4.1.33349.3.1.5.9.2.0.8.1     | Alter Local Users                                               |
| 1.3.6.1.4.1.33349.3.1.5.9.2.0.9       | Alter Policy                                                    |
| 1.3.6.1.4.1.33349.3.1.5.9.2.0.10      | Administer Data Warehouse                                       |
| 1.3.6.1.4.1.33349.3.1.5.9.2.0.11      | Access Audit Log                                                |
| 1.3.6.1.4.1.33349.3.1.5.9.2.0.12      | Administer Applets                                              |
| 1.3.6.1.4.1.33349.3.1.5.9.2.0.13      | Assign Policy                                                   |
| 1.3.6.1.4.1.33349.3.1.5.9.2.0.14      | Unrestricted PubSub Administration                              |
| 1.3.6.1.4.1.33349.3.1.5.9.2.0.14.1    | Create/Alter PubSub Subscriptions                               |
| 1.3.6.1.4.1.33349.3.1.5.9.2.0.14.2    | Disable/Enable PubSub Subscriptions                             |
| 1.3.6.1.4.1.33349.3.1.5.9.2.0.14.3    | Delete PubSub Subscriptions                                     |
| 1.3.6.1.4.1.33349.3.1.5.9.2.0.14.4    | Read PubSub Subscriptions                                       |
| 1.3.6.1.4.1.33349.3.1.5.9.2.0.15      | Alter System Configuration                                      |
| 1.3.6.1.4.1.33349.3.1.5.9.2.0.15.1    | Unrestricted Match Configuration                                |
| 1.3.6.1.4.1.33349.3.1.5.9.2.0.15.1.1  | Alter Match Configurations                                      |
| 1.3.6.1.4.1.33349.3.1.5.9.2.0.15.1.2  | Disable/Enable Match Configurations                             |
| 1.3.6.1.4.1.33349.3.1.5.9.2.0.15.2    | Unrestricted Clinical Protocol Configuration                    |
| 1.3.6.1.4.1.33349.3.1.5.9.2.0.15.2.0  | Create Clinical Protocol                                        |
| 1.3.6.1.4.1.33349.3.1.5.9.2.0.15.2.1  | Alter Clinical Protocol                                         |
| 1.3.6.1.4.1.33349.3.1.5.9.2.0.15.2.2  | Delete Clinical Protocol                                        |
| 1.3.6.1.4.1.33349.3.1.5.9.2.0.15.3    | Alter Clinical Data Templates                                   |
| 1.3.6.1.4.1.33349.3.1.5.9.2.0.16      | Unrestricted Dispatcher Queue                                   |
| 1.3.6.1.4.1.33349.3.1.5.9.2.0.17      | Administer Internal Mail / Messages                             |
| 1.3.6.1.4.1.33349.3.1.5.9.2.0.18      | Manage System Backups                                           |
| 1.3.6.1.4.1.33349.3.1.5.9.2.0.18.1    | Create System Backup on (Private or Public)                     |
| 1.3.6.1.4.1.33349.3.1.5.9.2.0.18.1.1  | Create Private System Backup                                    |
| 1.3.6.1.4.1.33349.3.1.5.9.2.0.19      | Unrestricted Security Certificate Management                    |
| 1.3.6.1.4.1.33349.3.1.5.9.2.0.19.1    | Issue New Certificates                                          |
| 1.3.6.1.4.1.33349.3.1.5.9.2.0.19.2    | Revoke Certificates                                             |
| 1.3.6.1.4.1.33349.3.1.5.9.2.0.19.3    | Assign Certificate to Security Identity                         |
| 1.3.6.1.4.1.33349.3.1.5.9.2.0.20      | Manage Foreign Data                                             |
| 1.3.6.1.4.1.33349.3.1.5.9.2.0.21      | Unrestricted Access to Service Logs                             |
| 1.3.6.1.4.1.33349.3.1.5.9.2.0.21.1    | Read Service Logs                                               |
| 1.3.6.1.4.1.33349.3.1.5.9.2.0.21.2    | Delete Service Logs                                             |
| 1.3.6.1.4.1.33349.3.1.5.9.2.0.22      | Unrestricted Job Management                                     |
| 1.3.6.1.4.1.33349.3.1.5.9.2.0.22.0    | Read System Jobs                                                |
| 1.3.6.1.4.1.33349.3.1.5.9.2.0.22.1    | Start/Run System Job                                            |
| 1.3.6.1.4.1.33349.3.1.5.9.2.0.22.2    | Alter System Job Schedule                                       |
| 1.3.6.1.4.1.33349.3.1.5.9.2.0.22.3    | Register New System Job                                         |
| 1.3.6.1.4.1.33349.3.1.5.9.2.1         | Login                                                           |
| 1.3.6.1.4.1.33349.3.1.5.9.2.1.0       | Login as a Service                                              |
| 1.3.6.1.4.1.33349.3.1.5.9.2.1.0.0     | OAUTH Login                                                     |
| 1.3.6.1.4.1.33349.3.1.5.9.2.1.0.0.1   | OAUTH client\_credentials flow permission                       |
| 1.3.6.1.4.1.33349.3.1.5.9.2.1.0.0.1.0 | OAUTH client\_credentials flow permission no device cred        |
| 1.3.6.1.4.1.33349.3.1.5.9.2.1.0.0.2   | OAUTH password flow permission                                  |
| 1.3.6.1.4.1.33349.3.1.5.9.2.1.0.0.2.0 | OAUTH password flow permission no device cred                   |
| 1.3.6.1.4.1.33349.3.1.5.9.2.1.0.0.3   | OAUTH authoization code grant flow permission                   |
| 1.3.6.1.4.1.33349.3.1.5.9.2.1.0.0.3.0 | OAUTH authoization code grant flow permission no device cred    |
| 1.3.6.1.4.1.33349.3.1.5.9.2.1.0.0.4   | OAUTH Password Reset grant (extended permission)                |
| 1.3.6.1.4.1.33349.3.1.5.9.2.1.0.0.4.0 | OAUTH Password Reset grant (extended permission) no device cred |
| 1.3.6.1.4.1.33349.3.1.5.9.2.1.0.1     | Login for Password Reassignment                                 |
| 1.3.6.1.4.1.33349.3.1.5.9.2.1.0.2     | Allow Impersonation of Application                              |
| 1.3.6.1.4.1.33349.3.1.5.9.2.2         | Unrestricted Clinical Data                                      |
| 1.3.6.1.4.1.33349.3.1.5.9.2.2.0       | Query Clinical Data                                             |
| 1.3.6.1.4.1.33349.3.1.5.9.2.2.1       | Write Clinical Data                                             |
| 1.3.6.1.4.1.33349.3.1.5.9.2.2.2       | Delete Clinical Data                                            |
| 1.3.6.1.4.1.33349.3.1.5.9.2.2.3       | Read Clinical Data                                              |
| 1.3.6.1.4.1.33349.3.1.5.9.2.2.4       | Export Clinical Data (PHI)                                      |
| 1.3.6.1.4.1.33349.3.1.5.9.2.2.5       | Elevate Clinical Data                                           |
| 1.3.6.1.4.1.33349.3.1.5.9.2.2.6       | Unrestricted Non-PHI CDR Acts                                   |
| 1.3.6.1.4.1.33349.3.1.5.9.2.2.6.1     | Write Non-PHI CDR Acts                                          |
| 1.3.6.1.4.1.33349.3.1.5.9.2.2.6.2     | Read Non-PHI CDR Acts                                           |
| 1.3.6.1.4.1.33349.3.1.5.9.2.4         | Unrestricted Metadata                                           |
| 1.3.6.1.4.1.33349.3.1.5.9.2.4.0       | Read Metadata                                                   |
| 1.3.6.1.4.1.33349.3.1.5.9.2.4.0.1.2   | Read Materials                                                  |
| 1.3.6.1.4.1.33349.3.1.5.9.2.4.0.1.3   | Query Materials                                                 |
| 1.3.6.1.4.1.33349.3.1.5.9.2.4.0.2.2   | Read Places & Orgs                                              |
| 1.3.6.1.4.1.33349.3.1.5.9.2.4.0.2.3   | Query Places & Orgs                                             |
| 1.3.6.1.4.1.33349.3.1.5.9.2.4.1.0     | Write Materials                                                 |
| 1.3.6.1.4.1.33349.3.1.5.9.2.4.1.1     | Delete Materials                                                |
| 1.3.6.1.4.1.33349.3.1.5.9.2.4.2.0     | Write Places & Orgs                                             |
| 1.3.6.1.4.1.33349.3.1.5.9.2.4.2.1     | Delete Places & Orgs                                            |
| 1.3.6.1.4.1.33349.3.1.5.9.2.5         | Unrestricted Data Warehouse                                     |
| 1.3.6.1.4.1.33349.3.1.5.9.2.5.0       | Write Warehouse Data                                            |
| 1.3.6.1.4.1.33349.3.1.5.9.2.5.1       | Delete Warehouse Data                                           |
| 1.3.6.1.4.1.33349.3.1.5.9.2.5.2       | Read Warehouse Data                                             |
| 1.3.6.1.4.1.33349.3.1.5.9.2.5.3       | Query Warehouse Data                                            |
| 1.3.6.1.4.1.33349.3.1.5.9.2.6         | Unrestricted MDM                                                |
| 1.3.6.1.4.1.33349.3.1.5.9.2.6.1       | Write MDM Master                                                |
| 1.3.6.1.4.1.33349.3.1.5.9.2.6.2       | Read MDM Locals                                                 |
| 1.3.6.1.4.1.33349.3.1.5.9.2.6.3       | Merge MDM Master                                                |
| 1.3.6.1.4.1.33349.3.1.5.9.2.6.4       | Establish MDM Record of Truth                                   |
| 1.3.6.1.4.1.33349.3.1.5.9.2.6.4.1     | Edit Existing MDM Record of Truth                               |
| 1.3.6.1.4.1.33349.3.1.5.9.2.10        | Access Client Administrative Function                           |
| 1.3.6.1.4.1.33349.3.1.5.9.2.100       | Access All SanteDB Tools                                        |
| 1.3.6.1.4.1.33349.3.1.5.9.2.100.1     | Access SanteDB Administrator Panel                              |
| 1.3.6.1.4.1.33349.3.1.5.9.2.100.2     | Access SanteEMR Clinical Interface                              |
| 1.3.6.1.4.1.33349.3.1.5.9.2.200       | Unrestricted EMR Functions                                      |
| 1.3.6.1.4.1.33349.3.1.5.9.2.200.1     | Clinic Reporting                                                |
| 1.3.6.1.4.1.33349.3.1.5.9.2.300       | Unrestricted IMS Functions                                      |
| 1.3.6.1.4.1.33349.3.1.5.9.2.300.1     | Unrestricted Stock Management                                   |
| 1.3.6.1.4.1.33349.3.1.5.9.2.300.1.0   | View Clinic Stock Information                                   |
| 1.3.6.1.4.1.33349.3.1.5.9.2.300.1.1   | Alter Clinic Stock Stores                                       |
| 1.3.6.1.4.1.33349.3.1.5.9.2.300.1.2   | Perform Stock Count                                             |
| 1.3.6.1.4.1.33349.3.1.5.9.2.300.1.3   | Manage Clinic Vaccination Sessions                              |
| 1.3.6.1.4.1.33349.3.1.5.9.2.300.1.4   | Perform Stock Adjustment                                        |
| 1.3.6.1.4.1.33349.3.1.5.9.2.300.1.5   | Perform Stock Store Temperature Monitoring                      |
| 1.3.6.1.4.1.33349.3.1.5.9.2.300.2     | Unrestricted Order Management                                   |
| 1.3.6.1.4.1.33349.3.1.5.9.2.300.2.1   | Create or Cancel Order Request                                  |
| 1.3.6.1.4.1.33349.3.1.5.9.2.300.2.2   | Accept and Despatch Order Requests                              |
| 1.3.6.1.4.1.33349.3.1.5.9.2.300.2.3   | Accept Order Despatch                                           |
| 1.3.6.1.4.1.33349.3.1.5.9.2.500       | Export CDR Metadata                                             |
| 1.3.6.1.4.1.33349.3.1.5.9.2.600       | Special Security Elevation                                      |
| 1.3.6.1.4.1.33349.3.1.5.9.2.600.1     | Change Security Challenge Question                              |
| 1.3.6.1.4.1.33349.3.1.5.9.2.900       | Login Any Facility                                              |
| 1.3.6.1.4.1.33349.3.1.5.9.2.999       | Override Disclosure                                             |
| 1.3.6.1.4.1.33349.3.1.5.9.3           | Restricted Information / Confidential                           |

## Concept & Vocabulary OIDs

Concept sets and code systems which are specific to SanteDB existing in the root `1.3.6.1.4.1.33349.3.1.5.9.3` these concept sets are:

| OID                               | Concept Set                              |
| --------------------------------- | ---------------------------------------- |
| 1.3.6.1.4.1.33349.3.1.5.9.3.0     | Concept Status                           |
| 1.3.6.1.4.1.33349.3.1.5.9.3.1     | Act Class                                |
| 1.3.6.1.4.1.33349.3.1.5.9.3.10    | Address Component Type                   |
| 1.3.6.1.4.1.33349.3.1.5.9.3.103   | Patient Status Observation Types         |
| 1.3.6.1.4.1.33349.3.1.5.9.3.104   | Condition Indication Concepts            |
| 1.3.6.1.4.1.33349.3.1.5.9.3.104.1 | Condition Negation Indicator Concepts    |
| 1.3.6.1.4.1.33349.3.1.5.9.3.105   | Equipment Functional Status              |
| 1.3.6.1.4.1.33349.3.1.5.9.3.106   | Unit of Measure (Temperatures)           |
| 1.3.6.1.4.1.33349.3.1.5.9.3.107   | Equipment Failure Reason                 |
| 1.3.6.1.4.1.33349.3.1.5.9.3.108   | Pregnancy Complications                  |
| 1.3.6.1.4.1.33349.3.1.5.9.3.109   | EMR Encounter Tags                       |
| 1.3.6.1.4.1.33349.3.1.5.9.3.11    | Name Use                                 |
| 1.3.6.1.4.1.33349.3.1.5.9.3.111   | Tetanus Immunity Status Codes            |
| 1.3.6.1.4.1.33349.3.1.5.9.3.115   | Narrative Note Types                     |
| 1.3.6.1.4.1.33349.3.1.5.9.3.12    | Telecom Address Use                      |
| 1.3.6.1.4.1.33349.3.1.5.9.3.120   | Patient Condition Trigger Codes          |
| 1.3.6.1.4.1.33349.3.1.5.9.3.120.1 | Patient Multi-Condition Codes            |
| 1.3.6.1.4.1.33349.3.1.5.9.3.124   | Pediatric Developmental Disorders        |
| 1.3.6.1.4.1.33349.3.1.5.9.3.13    | Telecom Address Type                     |
| 1.3.6.1.4.1.33349.3.1.5.9.3.13.1  | Human Telecom Address Type               |
| 1.3.6.1.4.1.33349.3.1.5.9.3.14    | Service Code                             |
| 1.3.6.1.4.1.33349.3.1.5.9.3.149   | Vaccine Support Materials                |
| 1.3.6.1.4.1.33349.3.1.5.9.3.15    | Industry Code                            |
| 1.3.6.1.4.1.33349.3.1.5.9.3.16    | Administrative Genders                   |
| 1.3.6.1.4.1.33349.3.1.5.9.3.165   | Confidential Observation Types           |
| 1.3.6.1.4.1.33349.3.1.5.9.3.17    | Role Status                              |
| 1.3.6.1.4.1.33349.3.1.5.9.3.18    | Name Component Type                      |
| 1.3.6.1.4.1.33349.3.1.5.9.3.19    | Reason Codes                             |
| 1.3.6.1.4.1.33349.3.1.5.9.3.2     | Act Mood                                 |
| 1.3.6.1.4.1.33349.3.1.5.9.3.23    | Family members of children               |
| 1.3.6.1.4.1.33349.3.1.5.9.3.24    | Spousal Family Members                   |
| 1.3.6.1.4.1.33349.3.1.5.9.3.25    | Vaccines                                 |
| 1.3.6.1.4.1.33349.3.1.5.9.3.26    | Administration Act Type Codes            |
| 1.3.6.1.4.1.33349.3.1.5.9.3.27    | Container Type                           |
| 1.3.6.1.4.1.33349.3.1.5.9.3.27.1  | Cold Storage Containers                  |
| 1.3.6.1.4.1.33349.3.1.5.9.3.28    | AdministrableDrugForm                    |
| 1.3.6.1.4.1.33349.3.1.5.9.3.29    | Route of administration                  |
| 1.3.6.1.4.1.33349.3.1.5.9.3.3     | Act Status                               |
| 1.3.6.1.4.1.33349.3.1.5.9.3.30    | Subset of Discharge Disposition (HL7)    |
| 1.3.6.1.4.1.33349.3.1.5.9.3.31    | Drug Administration Units                |
| 1.3.6.1.4.1.33349.3.1.5.9.3.32    | AdministrationSite                       |
| 1.3.6.1.4.1.33349.3.1.5.9.3.33    | Drug Administration Units                |
| 1.3.6.1.4.1.33349.3.1.5.9.3.34    | Vital Signs                              |
| 1.3.6.1.4.1.33349.3.1.5.9.3.35    | Units of Measure                         |
| 1.3.6.1.4.1.33349.3.1.5.9.3.36    | Units of Measure for Weight              |
| 1.3.6.1.4.1.33349.3.1.5.9.3.37    | Protocol Violation Reason                |
| 1.3.6.1.4.1.33349.3.1.5.9.3.38    | Stock Adjustment Reasons                 |
| 1.3.6.1.4.1.33349.3.1.5.9.3.38.0  | Stock Act Reasons - Decrease             |
| 1.3.6.1.4.1.33349.3.1.5.9.3.38.1  | Stock Act Reason Codes - Increase        |
| 1.3.6.1.4.1.33349.3.1.5.9.3.38.2  | Vaccination Session Adjustment Reasons   |
| 1.3.6.1.4.1.33349.3.1.5.9.3.39    | Allergies and Intolerance Types          |
| 1.3.6.1.4.1.33349.3.1.5.9.3.4     | Act Relationship Type                    |
| 1.3.6.1.4.1.33349.3.1.5.9.3.40    | SupplementCodes                          |
| 1.3.6.1.4.1.33349.3.1.5.9.3.41    | Act Types                                |
| 1.3.6.1.4.1.33349.3.1.5.9.3.42    | Null Reason                              |
| 1.3.6.1.4.1.33349.3.1.5.9.3.43    | Severity Observation Values              |
| 1.3.6.1.4.1.33349.3.1.5.9.3.44    | Causes of Death                          |
| 1.3.6.1.4.1.33349.3.1.5.9.3.45    | Observation Act Types                    |
| 1.3.6.1.4.1.33349.3.1.5.9.3.46    | Reaction Observations                    |
| 1.3.6.1.4.1.33349.3.1.5.9.3.47    | Subset of Disposition (HL7)              |
| 1.3.6.1.4.1.33349.3.1.5.9.3.48    | Security Audit Codes                     |
| 1.3.6.1.4.1.33349.3.1.5.9.3.49    | Material Type Codes                      |
| 1.3.6.1.4.1.33349.3.1.5.9.3.5     | Act Interpretation                       |
| 1.3.6.1.4.1.33349.3.1.5.9.3.50    | Protocol Violation - Don't Reschedule    |
| 1.3.6.1.4.1.33349.3.1.5.9.3.51    | Diagnosis Codes                          |
| 1.3.6.1.4.1.33349.3.1.5.9.3.52    | Problem or Concern Observation Types     |
| 1.3.6.1.4.1.33349.3.1.5.9.3.53    | Adverse Event Types                      |
| 1.3.6.1.4.1.33349.3.1.5.9.3.54    | Place Type Concepts (Sub-Classes)        |
| 1.3.6.1.4.1.33349.3.1.5.9.3.54.1  | Facility Type Concepts (Sub-Classes)     |
| 1.3.6.1.4.1.33349.3.1.5.9.3.55    | Organization Type Concept                |
| 1.3.6.1.4.1.33349.3.1.5.9.3.55.1  | Educational Organization Types           |
| 1.3.6.1.4.1.33349.3.1.5.9.3.56    | Place Entity Class Code Concepts         |
| 1.3.6.1.4.1.33349.3.1.5.9.3.59    | Language Codes                           |
| 1.3.6.1.4.1.33349.3.1.5.9.3.6     | Entity Class                             |
| 1.3.6.1.4.1.33349.3.1.5.9.3.60    | Living Arrangement                       |
| 1.3.6.1.4.1.33349.3.1.5.9.3.61    | Marital Status                           |
| 1.3.6.1.4.1.33349.3.1.5.9.3.62    | Ethnicities                              |
| 1.3.6.1.4.1.33349.3.1.5.9.3.63    | Religions                                |
| 1.3.6.1.4.1.33349.3.1.5.9.3.64    | Education Levels                         |
| 1.3.6.1.4.1.33349.3.1.5.9.3.65    | Master Data Model Relationship Types     |
| 1.3.6.1.4.1.33349.3.1.5.9.3.66    | Place Classifications                    |
| 1.3.6.1.4.1.33349.3.1.5.9.3.67    | Name Prefix                              |
| 1.3.6.1.4.1.33349.3.1.5.9.3.68    | Name Suffix                              |
| 1.3.6.1.4.1.33349.3.1.5.9.3.69    | Purposes of Use                          |
| 1.3.6.1.4.1.33349.3.1.5.9.3.7     | Entity Status                            |
| 1.3.6.1.4.1.33349.3.1.5.9.3.70    | Encounter Type Codes                     |
| 1.3.6.1.4.1.33349.3.1.5.9.3.71    | Registration Event Type Codes            |
| 1.3.6.1.4.1.33349.3.1.5.9.3.72    | Delivery Outcome Codes                   |
| 1.3.6.1.4.1.33349.3.1.5.9.3.73    | Delivery Method Codes                    |
| 1.3.6.1.4.1.33349.3.1.5.9.3.74    | Delivery Location Codes                  |
| 1.3.6.1.4.1.33349.3.1.5.9.3.75    | Units of Measure for Height              |
| 1.3.6.1.4.1.33349.3.1.5.9.3.76    | Verification Status                      |
| 1.3.6.1.4.1.33349.3.1.5.9.3.77    | Occupation Types                         |
| 1.3.6.1.4.1.33349.3.1.5.9.3.78    | VIP Status Codes                         |
| 1.3.6.1.4.1.33349.3.1.5.9.3.79    | Relationship Classification              |
| 1.3.6.1.4.1.33349.3.1.5.9.3.8     | Entity Relationship Type                 |
| 1.3.6.1.4.1.33349.3.1.5.9.3.80    | Identifier Type Codes                    |
| 1.3.6.1.4.1.33349.3.1.5.9.3.82    | Pregnancy Outcomes                       |
| 1.3.6.1.4.1.33349.3.1.5.9.3.84    | Country Codes                            |
| 1.3.6.1.4.1.33349.3.1.5.9.3.85    | Nationality Codes                        |
| 1.3.6.1.4.1.33349.3.1.5.9.3.86    | Detected Issue Type                      |
| 1.3.6.1.4.1.33349.3.1.5.9.3.87    | Procedure Technique Codes                |
| 1.3.6.1.4.1.33349.3.1.5.9.3.88    | Body Site Codes                          |
| 1.3.6.1.4.1.33349.3.1.5.9.3.9     | Address Use                              |
| 1.3.6.1.4.1.33349.3.1.5.9.3.90    | Provider Types for Individuals           |
| 1.3.6.1.4.1.33349.3.1.5.9.3.91    | HIV Status Codes                         |
| 1.3.6.1.4.1.33349.3.1.5.9.3.92    | Syphilis Diagnosis Codes                 |
| 1.3.6.1.4.1.33349.3.1.5.9.3.94    | Herpes Simplex Virus                     |
| 1.3.6.1.4.1.33349.3.1.5.9.3.95    | Sexually Transmitted Infectious Diseases |
| 1.3.6.1.4.1.33349.3.1.5.9.3.99    | Contact Role                             |

## Community Deployments

Community deployments undertaken by SanteSuite Inc. or SanteSuite partners typically will require OIDs for custom policies, templates, CDSS rules, etc. These OIDs are assigned off the root branch for the deployment in the `1.3.6.1.4.1.52820.5.1` namespace and are.

<table><thead><tr><th>OID</th><th width="146">Jurisdiction</th><th>Uses</th></tr></thead><tbody><tr><td>1.3.6.1.4.1.52820.5.1.0</td><td>ELB</td><td>Elbonia MPI</td></tr><tr><td>1.3.6.1.4.1.52820.5.1.1</td><td>MY</td><td>Myanmar National MPI<br>Myanmar OpenMRS Identifiers</td></tr><tr><td>1.3.6.1.4.1.52820.5.1.2</td><td>SB</td><td>Solomon MPI &#x26; IIS</td></tr><tr><td>1.3.6.1.4.1.52820.5.1.3</td><td>FJ</td><td>Fiji MPI &#x26; IIS</td></tr><tr><td>1.3.6.1.4.1.52820.5.1.4</td><td>KI</td><td>Kiribati MPI &#x26; IIS</td></tr><tr><td>1.3.6.1.4.1.52820.5.1.5</td><td>DL</td><td>Demoland (new Demonstration Jurisdiction)</td></tr></tbody></table>

## Clinical Templates

Clinical templates are structures which dictate the format, entry, and display of clinical data primarily from SanteEMR derivatives (such as SanteIMS). These templates are assigned OIDs from the `1.3.6.1.4.1.52820.5.2` namespace which has five children:

* `1.3.6.1.4.1.52820.5.2.0` - Templates for `Patients`
* `1.3.6.1.4.1.52820.5.2.1` - Templates for `Observations`
* `1.3.6.1.4.1.52820.5.2.2` - Templates for `Act`&#x20;
* `1.3.6.1.4.1.52820.5.2.3` - Templates for `SubstanceAdminsitration`&#x20;
* `1.3.6.1.4.1.52820.5.2.4` - Templates for `Procedure`
* `1.3.6.1.4.1.52820.5.2.5` - Templates for `PatientEncounter`
* `1.3.6.1.4.1.52820.5.2.6` - Templates for stock related data

The clinical templates defined by SanteDB community implementations are:

<table><thead><tr><th width="257">OID</th><th width="259">Mnemonic</th><th width="335">Name</th></tr></thead><tbody><tr><td>1.3.6.1.4.1.52820.5.2.0.1</td><td>org.santedb.emr.patient</td><td>Patient Registration</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.0.2</td><td>org.santedb.emr.patient.baby</td><td>Newborn Information</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.1.0</td><td>org.santedb.emr.observation.verification</td><td>Observation Verification State</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.1.1</td><td>org.santedb.emr.observation.cod</td><td>Cause Of Death</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.1.10</td><td>org.santedb.emr.observation.weight</td><td>Weight Entry</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.1.11</td><td>org.santedb.ims.problem.aefi</td><td>Adverse Event Following Immunization (AEFI)</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.1.12</td><td>org.santedb.emr.hiv.status</td><td>HIV Status</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.1.13</td><td>org.santedb.emr.pregnancy.status</td><td>Pregnancy Status</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.1.13.1</td><td>org.santedb.emr.pregnancy.lmp</td><td>Last Menstrual Period</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.1.13.2</td><td>org.santedb.emr.pregnancy.edd</td><td>Estimated Delivery Date</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.1.13.3</td><td>org.santedb.emr.pregnancy.aof</td><td>Estimated Age of Fetus</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.1.13.4</td><td>org.santedb.emr.pregnancy.confirm</td><td>Confirmation of Pregnancy</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.1.13.5</td><td>org.santedb.emr.pregnancy.complication</td><td>Pregnancy Complication(s)</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.1.14</td><td>org.santedb.emr.pregnancy.history</td><td>Pregnancy History</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.1.15</td><td>org.santedb.emr.infant.feeding</td><td>Breast Feeding Status</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.1.16</td><td>org.santedb.emr.hiv.mothersStatus</td><td>Mother's HIV Status</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.1.17</td><td>org.santedb.emr.observation.headCircumference</td><td>Head Circumference</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.1.18</td><td>org.santedb.emr.observation.vitalSigns</td><td>Vital Signs</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.1.18.1</td><td>org.santedb.emr.observation.heartRate</td><td>Heart Rate</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.1.18.2</td><td>org.santedb.emr.observation.respirationRate</td><td>Respiration Rate</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.1.19</td><td>org.santedb.emr.observation.temperature</td><td>Body Temperature</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.1.20</td><td>org.santedb.emr.observation.bloodPressure</td><td>Blood Pressure Reading</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.1.21</td><td>org.santedb.emr.condition.allergy</td><td>Allergy / Intolerance Entry</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.1.30</td><td>org.santedb.emr.pregnancy.conclude</td><td>Pregnancy Completion/Termination</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.1.40</td><td>org.santedb.emr.organizer.sti.panel</td><td>Sexually Transmitted Diseases (Current &#x26; Historical)</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.1.40.1</td><td>org.santedb.emr.act.sti.infection</td><td>Sexually Transmited Infectious Disease</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.1.6</td><td>org.santedb.emr.observation.height</td><td>Height Entry</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.1.60</td><td>org.santedb.emr.observation.pediatric.developmentDisability</td><td>Developmental Disability</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.1.8</td><td>org.santedb.emr.observation.death</td><td>Death Report</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.1.8.1</td><td>org.santedb.emr.observation.timeofdeath</td><td>Time of Death</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.2.1</td><td>org.santedb.emr.act.registration.birth</td><td>Birth Registration</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.2.1.1</td><td>org.santedb.emr.observation.birthWeight</td><td>Birth Weight Entry</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.2.1.2</td><td>org.santedb.emr.observation.birthSex</td><td>Birth Sex</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.2.1.3</td><td>org.santedb.emr.observation.birthDeliveryLocation</td><td>Birth Delivery Location</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.2.1.4</td><td>org.santedb.emr.observation.birthDeliveryMethod</td><td>Birth Delivery Method</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.2.1.5</td><td>org.santedb.emr.observation.birthDeliveryOutcome</td><td>APGAR Panel</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.2.1.6</td><td>org.santedb.emr.observation.deliveryDateAndTime</td><td>Birth Date &#x26; Time</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.2.1.7</td><td>org.santedb.emr.observation.gestationalAgeAtBirth</td><td>Gestational Age at Birth</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.2.1.8</td><td>org.santedb.emr.observation.apgarScore.panel</td><td>APGAR Scores</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.2.1.8.1</td><td>org.santedb.emr.observation.apgarScore.1Minute</td><td>1 Minute APGAR Score</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.2.1.8.10</td><td>org.santedb.emr.observation.apgarScore.10Minute</td><td>10 Minute APGAR Score</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.2.1.8.5</td><td>org.santedb.emr.observation.apgarScore.5Minute</td><td>5 Minute APGAR Score</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.2.1.9</td><td>org.santedb.emr.observation.birthLength</td><td>Birth Length Entry</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.2.2</td><td>org.santedb.emr.act.registration.death</td><td>Death Registration</td></tr><tr><td>1.3.5.1.4.1.52820.5.2.3.1</td><td>org.santedb.emr.sbadm.supplement</td><td>Supplements</td></tr><tr><td>1.3.5.1.4.1.52820.5.2.3.2</td><td>org.santedb.emr.sbadm.immunization</td><td>Scheduled / Routine Immunization</td></tr><tr><td>1.3.5.1.4.1.52820.5.2.3.2.1</td><td>org.santedb.emr.sbadm.immunization.booster</td><td>Immunization (Booster/AdHoc)</td></tr><tr><td>1.3.5.1.4.1.52820.5.2.3.2.2</td><td>org.santedb.emr.sbadm.immunization.embedded</td><td>Immunization Inline</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.5.1</td><td>org.santedb.emr.act.visit.lds</td><td>Labour &#x26; Delivery Visit</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.5.2</td><td>org.santedb.emr.act.visit.anc</td><td>ANC Visit</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.5.3</td><td>org.santedb.emr.act.visit.general</td><td>General / Primary Care Visit</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.5.6</td><td>org.santedb.emr.act.visit.neonatal</td><td>Neonatal Visit</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.5.8</td><td>org.santedb.ims.pediatric.routineVacc</td><td>Routine Vaccination (Pediatric)</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.6.1</td><td>org.santedb.ims.container.functionalStatus</td><td>Functional Status</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.6.2</td><td>org.santedb.ims.container.temperature</td><td>Temperature Reading</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.6.3</td><td>org.santedb.ims.container.monitoring</td><td>Routine Monitoring of Cold Storage</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.6.4</td><td>org.santedb.ims.container.count</td><td>Stock count &#x26; assignment</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.6.5</td><td>org.santedb.ims.container.adjust</td><td>Stock adjustment</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.6.6</td><td>org.santedb.ims.container.transfer</td><td>Stock transfer</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.6.7.1</td><td>org.santedb.ims.session.start</td><td>Start Vaccination Session</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.6.7.2</td><td>org.santedb.ims.session.issue</td><td>Issue More Stock to Vaccination Session</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.6.7.3</td><td>org.santedb.ims.session.return</td><td>Return Stock from Vaccination Session</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.6.7.4</td><td>org.santedb.ims.session.end</td><td>End Vaccination Session</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.6.7.5</td><td>org.santedb.ims.session.openVialWaste</td><td>Session Open Vial Wastage</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.6.8</td><td>org.santedb.ims.stock.vvm</td><td>Vaccine Vial Monitoring</td></tr><tr><td>1.3.6.1.4.1.52820.5.2.999</td><td>org.santedb.core.masked</td><td>Confidential / Restricted Entry</td></tr></tbody></table>

## Clinical Protocol OIDs

Clinical protocols and libraries exist in the `1.3.5.1.4.1.52820.5.3` namespace, with the following child namespaces:

* `1.3.5.1.4.1.52820.5.3.1` - Childhood Nutrition, Care & Immunization Decision Support (typically applied only to patients under the age of 5)
* `1.3.5.1.4.1.52820.5.3.2` - Antenatal Care Decision Support

| OID                           | Type              | Name                                                                                                                                                                                                      |
| ----------------------------- | ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 1.3.5.1.4.1.52820.5.3.1.1     | Clinical Protocol | Collect weight of children under 5 years of age at minimum, once per month.                                                                                                                               |
| 1.3.5.1.4.1.52820.5.3.1.2     | Clinical Protocol | Collect height and/or length of children under 5 years of age at minimum, once per month.                                                                                                                 |
| 1.3.5.1.4.1.52820.5.3.1.3     | Clinical Protocol | Administration of routine Vitamin A supplements.                                                                                                                                                          |
| 1.3.5.1.4.1.52820.5.3.1.4     | Clinical Protocol | Administration of routine mabendazole treatment.                                                                                                                                                          |
| 1.3.5.1.4.1.52820.5.3.2.1     | Clinical Protocol | Administer Bacillus Calmette-Guerin Vaccine to children within 2 days of birth.                                                                                                                           |
| 1.3.5.1.4.1.52820.5.3.2.2     | Clinical Protocol | Administer DTP-Hib-HepB trivalent to children three times. First dose occurring 42 days after birth (recommended between 42-49 days), second and third doses administered 28-35 days after previous dose. |
| 1.3.5.1.4.1.52820.5.3.2.3     | Clinical Protocol | When child is under 18 months of age, administer MR1 dose at 274 days after birth, with second dose on or after 18th birthday                                                                             |
| 1.3.5.1.4.1.52820.5.2.3.2.3.1 | Clinical Protocol | Accelerated MR Schedule: When child is older than 18 months and has not received MR1, administer MR1 immediately and administer MR2 1 months after first dose.                                            |
| 1.3.5.1.4.1.52820.5.2.3.2.4   | Clinical Protocol | Regular PCV13 vaccination schedule for children under 5 years old.                                                                                                                                        |
| 1.3.5.1.4.1.52820.5.2.3.2.5   | Clinical Protocol | Regular Oral Polio Vaccination Computation Schedule                                                                                                                                                       |
| 1.3.5.1.4.1.52820.5.2.3.2.6   | Clinical Protocol | Oral Polio Vaccine Birth Dose Computation Protocol                                                                                                                                                        |
| 1.3.5.1.4.1.52820.5.2.3.2.7   | Clinical Protocol | Administration of Human Papilloma Virus (HPV) vaccine after 9 years of age                                                                                                                                |
| 1.3.5.1.4.1.52820.5.2.3.2.8   | Clinical Protocol | Administration of Inactivated Polio Virus Vaccine (IPV)                                                                                                                                                   |

## Identity Domain OIDs

Identity domain oids reside in the root `1.3.6.1.4.1.52820.5.4` and are further subdivided into:

* `.1` - Patient domains
* `.2` - Organization domains
* `.3` - Material Identity&#x20;
* `.4` - Place Identity&#x20;
* `.5` - Act Identity

| OID                       | Domain             | Name                                        |
| ------------------------- | ------------------ | ------------------------------------------- |
| 1.3.6.1.4.1.52820.5.4.2.1 | SIMS\_MANUFACTURER | SanteIMS Manufacturer Code                  |
| 1.3.6.1.4.1.52820.5.4.4.1 | PDH\_FAC\_UNIT\_ID | Pacific Data Hub Facility Import Identifier |
|                           |                    |                                             |


# Security Architecture

## Authentication Architecture

The figure below illustrates how a remote client can obtain a token from a federated security token service (STS) representing an IPrincipal and pass it to the SanteDB HDS. The creation of a local IPrincipal is controlled by a local IIdentityProviderService implementation. It is imperative that the ACS generate a token format which is suitable for the HDS messaging interface to consume (i.e. the configurations match), otherwise the HDS will have no mechanism for verifying tokens.

![](/files/-MFlbT0TTHKSL6XHwPDY)

Any ACS service can be used with SanteDB, however it is recommended that the ACS being used support the OAuth token service’s password grant and provide client/device authentication via TLS and/or HTTP basic auth.

### Principals and Identities

When a authentication request is made against the ACS, depending on the type of authentication request (see [OpenID Connect](/developers/service-apis/openid-connect#grant-types)) the ACS will call the identity providers to authenticate the identity information provided. The identity providers called are one of:

* Application Identity Provider - Authenticates a single piece of software to establish an `ApplicationIdentity` which identifies the scope of grants permitted to the application identity.
* Device Identity Provider - Authenticates the physical device (computer, server, phone, etc.) using either:
  * Node Based Authentication -> Like an X509 Client Certificate , or
  * Shared Secret Authentication -> Such as those generated by the secret generator (typically a signed, random 128 bit key)
* Identity Provider - Which authenticates the human user which is attempting to establish an interactive session with the server.&#x20;

The three identities (which are standalone principals in their own right) is then passed to the session provider service which establishes a principal as a combination of the three identities. The session principal contains:

* The final list of grants (policies) that the session is permitted to access
* The purpose of use, and elevation data (if applicable)
* The expiration, establishment time

Depending on the configuration of the iCDR or dCDR the session identity is serialized as either a JSON Web Token (<http://jwt.io>) or a simple web token which consists of the session identifier and a digital signature (used to validate the session id is not tampered with or guessed).

#### Interactive Sessions

An interactive session is established when a user enters their username, password and MFA secret. An interactive session will have three identities within the principal:

* User Identity representing the authenticated user account&#x20;
* Application Identity representing the authenticated secure client the user used to obtain the session
* Device Identity representing the authenticated secure node from which the user authenticated

#### Non-Interactive Sessions

A non-interactive session is established when a device or application authenticates without the intervention of a user. Non-interactive session may carry either an Application Identity and a Device Identity or simply an Application Identity.

### Credential Storage

Secrets for all objects in the SanteDB iCDR and dCDR (applications, devices, and users) are [**peppered**](https://nordpass.com/blog/pepper-password/).&#x20;

> A pepper is a secret value added to a password before hashing. It can be considered a second salt — another input to change the hash outcome completely. Yet, unlike a salt, it’s not stored in the database along with the hashes.

Whenever you generate a secret (like creating a device, resetting your password, etc.) in SanteDB the authentication architecture will grab a random series of password pepper characters and will add it to your secret, then hash it using the configured hasher, and store the result.

When you authenticate in SanteDB, all possible combinations of pepper are added to your entered credential and hashed, the SanteDB server then compares the peppered hashes with the stored hash to verify your login credentials.&#x20;

Additionally, your password is re-peppered and re-hashed. This means that the password hashes in SanteDB's security tables change with each authentication.

## Policy / Access Control Architecture

The enforcement of privacy and policies is handled through a series of services within the SanteDB solution. From a high level, three different types of services are involved:

* **Policy Information Provider (PIP) -**[ **IPolicyInformationService**](/developers/server-plugins/implementing-.net-features/service-definitions/policy-information-provider-pip) – Is responsible for storing information related to the policies. The information point is responsible for maintaining a list of IPolicy objects which contain the name, oid, handler (C# class which is executed upon policy decision), and elevation control.
* **Policy Decision Provider (PDP)** -[ IPolicyDecisionService](/developers/server-plugins/implementing-.net-features/service-definitions/policy-decision-provider-pdp) – Is responsible for making a decision related to a policy (or series of policies) for a given securable. The decision outcome is one of the following options:
  * **Deny** – The principal has no authorization to access the requested securable or policy.
  * **Elevate** – The principal can access the securable or policy however they require additional authentication (such as 2nd level password, TFA, etc.)
  * **Grant** – The principal is granted access to the specified securable or policy.
* **Policy Enforcement Provider (PEP)** -[ IPolicyEnforcementService](/developers/server-plugins/implementing-.net-features/service-definitions/policy-enforcement-provider-pep) – Is responsible for listening to events from the SanteDB system and leveraging the decision and information points to enforce the policy decision. This implementation can vary between jurisdictions however by default involves either the masking (i.e. there is something here you can’t see), redaction (i.e. removal of information), or partial disclosure of records.

The process for enforcement is illustrated below.

![](/files/-MFlbrmRMhj3st_Tc2xv)

### Most-Restrictive Policy Enforcement

SanteDB’s default policy decision service provider operates on a basis of most-restrictive with default DENY. In this evaluation scheme policy decisions are created as follows:

* If the principal has no data associated with the policy, the result of the decision is DENY,
* If the principal has one rule associated with the policy via role, device, or application then the result of the decision is the rule’s configuration,
* If the principal has multiple rule instances configured via role, device or application then the result of the decision is the most restrictive option.

For example, if user jsmith is a member of USERS, CLINICAL and is accessing SanteDB from application ReaderApp.

| **Policy**                         | **From USERS** | **From CLINICAL** | **From ReaderApp** | **Effective Set** |
| ---------------------------------- | -------------- | ----------------- | ------------------ | ----------------- |
| **Access Administrative Function** |                |                   |                    | **DENY**          |
| Change Password                    |                |                   |                    | DENY              |
| Create Role                        |                |                   |                    | DENY              |
| Alter Role                         |                |                   |                    | DENY              |
| Create Identity                    |                |                   |                    | DENY              |
| Login                              | GRANT          |                   | GRANT              | GRANT             |
| **Unrestricted Clinical Data**     |                | **GRANT**         |                    | **GRANT**         |
| Query Clinical Data                |                | GRANT (implied)   |                    | GRANT (implied)   |
| Write Clinical Data                |                | GRANT (implied)   | DENY               | DENY              |
| Delete Clinical Data               |                | GRANT (implied)   | DENY               | DENY              |
| Read Clinical Data                 |                | GRANT (implied)   |                    | GRANT (implied)   |
| Override Disclosure                |                | GRANT             | DENY               | DENY              |


# Privacy Architecture

SanteDB's [Policy Access Control](/santedb/security-architecture#policy-access-control-architecture) components can be used to enable basic data privacy controls on data stored within the SanteDB solution. SanteDB allows objects such as Entities, Acts and identifiers to be tagged with one or more policies which apply to that particular object.&#x20;

## Privacy Enforcement Service

Whenever an Entity, Act or Assigning Authority (identity domain) is tagged with an access policy (such as provided in the [Adding Security Policy based on Occupation](/developers/applets/recipes/adding-security-policy-based-on-occupation)) the configured Privacy Enforcement Service is called and validate access to the record and to apply any actions to the outgoing (or incoming) data.

### Entity/Act Disclosure

The disclosure validation on the enforcement compares the current security principals effective permission policy set and takes appropriate action (based on configuration) for the disclosure of the record. The actions which may be taken on objects like Entities (Person, Patient, Organization, Place, etc.) or Acts (Substance Administrations, Tests, etc.) are:

| Enforcement Action | Description                                                                                                                                                                                                                                                                                                                                                              |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Audit              | <p>The data is disclosed to the caller, however a high priority audit is created and</p><p>persisted (and shipped to the central audit repository) indicating the record was</p><p>disclosed.</p>                                                                                                                                                                        |
| Hide               | <p>The data is removed from the result set. There is no indication to the caller that</p><p>the data exists. For example: If a search for everyone named John were to return</p><p>10 results, however one was protected, then only 9 results would be returned in </p><p>the result set.</p>                                                                            |
| Redact             | <p>Only the data's primary UUID, the status, applicable policies are disclosed to the<br>caller. This means the caller can *see* there is data present, however the caller</p><p>cannot determine *what* the data is (note: if the caller determines, based on<br>the policies listed in the object it can BTG then it can take appropriate action to</p><p>elevate)</p> |
| Nullify            | Only the data's primary UUID is disclosed. No policy, or status is disclosed.                                                                                                                                                                                                                                                                                            |
| Error              | <p>The CDR will throw a privacy violation error, indicating to the caller that they</p><p>have attempted to access information which they do not have appropriate</p><p>access permission to.</p>                                                                                                                                                                        |
| None               | No Action is taken                                                                                                                                                                                                                                                                                                                                                       |

### Identity Disclosure

In addition to entire objects like patients, immunizations, procedures, etc. carrying privacy policies, it is possible to flag identity domains with access/disclosure policies. These policies are enforced on both disclosure and on write, meaning that reading and editing/inserting identities in protected domains is restricted to only principals with appropriate access permissions.

| Action          | Description                                                                                                                                                                                                                                                                                 |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Hide or Nullify | <p>The identifier is removed from the object and is never disclosed to the caller. <br>The caller is unaware that the identifier exists.</p>                                                                                                                                                |
| Hash            | <p>The identifier is disclosed in a hashed form to the caller. The caller is aware of the<br>authority and is presented with a hash which can be used for matching with identifiers <br>in its own data store.</p>                                                                          |
| Redact          | <p>The identifier is disclosed in a redacted form. The caller is aware the identifier exists</p><p>in the identity domain, and is aware of the length of the identifier, however all<br>characters within the identifier are replaced with X. (example: HIV-30493 becomes<br>XXXXXXXXX)</p> |
| Audit           | <p>The identifier is disclosed to the caller in plain form, the caller can see the specific</p><p>identifier assigned to the patient. The CDR will dispatch an audit to its internal audit</p><p>repository and will ship an audit to the central audit repository for follow up.</p>       |


# Matching Engine

{% hint style="info" %}
SanteMPI uses the SanteDB matching engine. This page may be moved in the future to a common page as the SanteDB matching engine supports more than just Patient resources.
{% endhint %}

The matching engine in SanteDB is a multi-stage process whereby an inbound (or a target record) is compared with the current dataset within the CDR. The matching process occurs in three stages:

* **Blocking :** In the blocking phase records are queried from the CDR's database infrastructure. The blocking phase is used to reduce the total number of records being scored, which can be more computationally expensive.
* **Scoring :** In the scoring stage, the target record is compared to those records retrieved from the blocking phase. Each attribute configured is transformed/normalized and then a score applied for each attribute. Furthermore there are API hooks for implementing partial weighting/partial scoring of an attribute (based on frequency of data in database, NLP, or other future methods)
* **Classification :**  In the classification stage, each record's score (the sum of each attribute's score) is grouped into Match, NonMatch, and ProbableMatch. These thresholds are configured.

SanteDB allows for the configuration of multiple match configurations, and allows configuration for the "default" match configuration to be used for regular operation (whenever data is inserted, updated, etc.).

## Blocking

In the blocking phase of the matching execution, the candidate record (named `$input`) is compared with records persisted in the database using one or more blocking configurations.

A blocking configuration is expressed using the [HDSI Query Syntax](/developers/service-apis/health-data-service-interface-hdsi/hdsi-query-syntax) which is translated into SQL. Blocking instructions can use any supported [Filter Functions](/developers/service-apis/health-data-service-interface-hdsi/hdsi-query-syntax/filter-functions) for the selected database.&#x20;

Records are read from the database (as blocks) with multiple blocks being combined with either an intersect or union function. Blocks can be loaded as either:&#x20;

* SOURCE Records: Whereby the source records are loaded from the database as they were sent. Blocking in this mode is less CPU intensive and less database intensive, however relies on source information as a "picture" of what data is available for a patient.
* MASTER Records: Where by the blocks are loaded using the MDM layer and are computed based on existing known and suspected links. This method of blocking more closely resembles what users see in the UI when MDM is enabled, however it does slow down matching performance as each record must be cross-referenced with the master data record. It also allows for matching based on records of truth.

Blocks from each statement are combined together to form a result set (in C# an `IEnumerable<T>`) which are passed into the scoring stage.

In the example below, the SanteDB matching engine will load records for an `$input` record by:

* If the input record contains an `SSN` identifier , it will filter records in the database by matching SSN. It will then perform an MDM gather (i.e. the matching mode is performed on MASTER records) , these records will be UNION with
* The results of a local query whereby:
  * If the `$input` has Given name, then the given name must match, AND
  * If the `$input` has a Family name, then the family name must match, AND
  * If the `$input` has a dateOfBirth then the date of birth must match, AND
  * If the `$input` has a gender concept then the gender must match

![](/files/S5QZ4cbO7fa8VLMe3F1Y)

In pseudocode terms, the blocking query for an `$input` of John Smith, Male, SSN 203-204-3049 born 1980-03-02 would resemble:

```sql
SELECT * 
FROM 
    masters AS master
    LEFT JOIN locals AS local
WHERE
    local.identifier[SSN].value = '203-204-3049'
UNION ALL 
SELECT * 
FROM 
    locals AS local
WHERE 
    local.name.component[Given].value = 'John'
    AND local.name.component[Family].value = 'Smith'
    AND local.dateOfBirth = '1980-03-02' 
    AND local.gender = 'Male'
```

{% hint style="info" %}
The actual SQL generated by the SanteDB iCDR is must more complex, this example illustrates the concept.
{% endhint %}

## Scoring

During the scoring phase, the records from the blocking stage are compared to the `$input` record on an attribute by attribute basis using a collection of assertions about the attribute. If all assertions on an attribute evaluate to TRUE then the `matchWeight` score is added to that records total score, if the assertions are FALSE then the `nonMatchWeight` score (a negative score) is added to the record's total score.

Overall, the process of comparing a blocked record (named `$block`) with the `$input` record is:

![](/files/9N9M7jL06laMlDJKnBuH)

1. The scoring attribute may declare that it depends on another attribute being scored (i.e. don't evaluate the `city` attribute unless `state` attribute has passed. If the dependent attribute was not scored as a positive (match) then the current attribute is assigned the whenNull() score.
2. The attribute path on the configuration is read from both `$block` and `$input`.&#x20;
3. The matching engine determines if either the `$block` or `$input` attribute value extracted is null. If either is null then the the [#when-null-actions](#when-null-actions "mention") is taken.
4. The matching engine then determines if any transforms have been configured (see: [#transforming-data](#transforming-data "mention")). This is a process whereby data is extracted, tokenized, shifted, padded, etc. on both the `$input` and `$block` variables. The result of each transform is stored as the new attribute value in memory and the next transform is applied against the output of the previous.
5. Finally the actual assertion is applied. The assertion is usually a binary logical operator (less than, equal, etc.) the result of which results in the `matchWeight` or `nonMatchWeight` being applied.

### When Null Actions

There can occur instances of either the inbound record or the source records from the database which are missing the specified attribute. When this is the case the attribute's `whenNull` attribute controls the behavior of the evaluation of that attribute. The behaviors are:

| @whenNull  | Description                                                                                                                                                                                                                                                                                                                                                            |
| ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| match      | <p>When the value is null in <code>$block</code> or <code>$input</code>, treat the attribute as a "match" <br>(i.e. assume the missing data matches)</p>                                                                                                                                                                                                               |
| nonmatch   | <p>When the value is null in either <code>$block</code> or <code>$input</code>, treat the attribute as a non-match</p><p>(i.e. assume the missing data would not match)</p>                                                                                                                                                                                            |
| ignore     | <p>When the value is null in <code>$block</code> or <code>$input</code>, don't evaluate the attribute. <br>(i.e. neither the non-match or match scores should be considered). This is similar to <code>zero</code> however, the entire attribute is removed from consideration. The absolute score is added no value, however the total possible score is reduced.</p> |
| disqualify | <p>When the value is null in <code>$block</code> or <code>$input</code> disqualify the entire record from consideration</p><p>(i.e. it doesn't matter what the other attribute scores are, the record is considered </p><p>not a match)</p>                                                                                                                            |
| zero       | When the value is null in `$block` or `$input` the attribute should be scored a 0. This is different than applying the match or non-match weight which will be a positive or negative number respectively. This is similar to the `ignore` setting except `zero` does not impact the denominator of the score.                                                         |

### Transforming Data

The date\_extract is applied to both records and then the assertion of "eq" is applied. The following data transforms are available in SanteDB.

| Transform            | Applies        | Action                                                                                                                                                                 |
| -------------------- | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| addresspart\_extract | Entity Address | Extracts a portion of an address for consideration                                                                                                                     |
| date\_difference     | Date           | Extracts the difference (in weeks, months, years, etc.) between the A record and B record.                                                                             |
| date\_extract        | Date           | Extracts a portion of the date from both records.                                                                                                                      |
| name\_alias          | Entity Name    | Considers any of the configured aliases for the name meeting a particular threshold of relevance (i.e. Will = Bill is stronger than Tess = Theresa)                    |
| abs                  | Number         | Returns the absolute value of a number                                                                                                                                 |
| dmetaphone           | Text           | Returns the double metaphone code (with configured code length) from the input string                                                                                  |
| length               | Text           | Returns the length of text string                                                                                                                                      |
| levenshtein          | Text           | Returns the levenshtein string difference between the A and B values.                                                                                                  |
| sorensen\_dice       | Text           | Returns the Sorensen Dice coefficient of text content A and B values.                                                                                                  |
| jaro\_winkler        | Text           | Returns the Jaro-Winkler (with default threshold of 0.7) between A and B values.                                                                                       |
| metaphone            | Text           | Returns the metaphone phonetic code for the attribute                                                                                                                  |
| similarity           | Text           | Returns a %'age (based on levenshtein difference) of string A to string B (i.e. 80% similar or 90% similar)                                                            |
| soundex              | Text           | Extracts the soundex codification of the input values.                                                                                                                 |
| substr               | Text           | Extracts a portion of the input values                                                                                                                                 |
| tokenize             | Text           | Tokenizes the input string based on splitting characters, the tokenized values can then be transformed independently using any of the transforms listed in this table. |
| timespan\_extract    | TimeSpan       | Extracts a portion of a timespan such as minutes, hours, seconds.                                                                                                      |

## Classification

The scores for each of the scored attributes are then summed for each `$block` record and the block is classified as:

* Match: The two records are determined to agree with one another according to configuration. the matching engine is instructing whatever called it (the MDM, MPI, etc.) that the two should be linked/merged/combined/etc.&#x20;
* Possible: The two records are not "non-matches" however there is insufficient confidence that the two are definite matches. Whatever called the matching operation should flag the two for manual reconciliation.
* Non-Match: The two records are definite non-matches.

## Bulk / Batch Matching

Each data type which is registered in the [Master Data Management](/santedb/data-and-information-architecture/data-storage-patterns/master-data-storage) pattern has a corresponding [Match Job](/operations/cdr-administration/santedb-administration-panel/system-administration/jobs) registered. This job resets the suspected ground truth using the following rules:

| Remove / Delete:                                                                              | Keep:                                                                                  |
| --------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
| <ul><li>Suspected Client Links (MDM-Candidate links)</li><li>Automatic Master Links</li></ul> | <ul><li>Verified Ignore</li><li>Verified Matches</li><li>System Master Links</li></ul> |

After the suspected truth is cleared, the job will begin the process of re-matching the registered dataset for SanteDB. The matching process is multi-threaded, and designed to ensure that the machine on which the match process is as efficient as possible. To do this, the following pattern is used:

![](/files/kp8pVNmZ7oZI1Rlxhd1J)

The batch matching process registers 4 primary threads on the actively configured thread pool to control the match process:

* Gather Thread: This worker is responsible for querying data from the source dataset in 1,000 record batches. The rate at which the records are loaded will depend on the speed of the persistence layer (SanteDB 2.1.x or 2.3.x) as well as the disk performance of the storage technology.
* Match Thread: This worker is responsible for breaking the 1,000 record batches into smaller partitions of records (depending on CPU of host machine). The configured matching algorithm is then launched for each record in the batch on independent threads (i.e. matching is done concurrently on the host machine).&#x20;
* Writer Thread: Once the match thread workers have completed their matching task, the results are queued for the writer thread. The writer thread is responsible for committing the matches to the read/write database.&#x20;
* Monitor Thread: The monitoring thread is responsible for updating the status of the job.

The performance of the batch matching will depend on the speed of the host machine as well as the version of SanteDB that is being used.&#x20;

SanteSuite's community server  was used for testing in the following configuration:

* Application Server:&#x20;
  * 4 VCPU&#x20;
  * 4 GB RAM&#x20;
  * Non-persistent (ram-only) REDIS Cache
* Database Server:&#x20;
  * 12 VCPU&#x20;
  * 12 GB RAM&#x20;
  * RAID 1+0 SSD disk infrastructure (4+4 SSD)

The versions of SanteDB tested yielded the following results:

* Version < 2.1.160 of SanteDB: \~28,000 records per hour
* Version > 2.1.165 of SanteDB: \~50,000 records per hour
* Version 2.3.x of SanteDB (internal alpha): \~100,000 records per hour

{% hint style="info" %}
It is important to ensure that your host system is configured such that the thread pool (accessed through the Probes administrative panel) has at minimum, 5 available worker threads to complete batch matching.&#x20;
{% endhint %}


# HIE & Interoperability

SanteDB is designed with a variety interoperability interfaces and standards, including:

* [HL7 Version 2.3 and Version 2.5 messaging](/developers/service-apis/hl7v2/santedb-hl7v2-implementation)
* [HL7 FHIR](/developers/service-apis/hl7-fhir/santedb-fhir-implementation)&#x20;
* [GS1 BMS 3.3](/developers/service-apis/gs1-bms-xml)
* IHE ATNA / UDP
* [OpenID Connect Identity Provider](/developers/service-apis/openid-connect)
* OpenAPI / Swagger 2.0 Metadata Exchange

Each of these interfaces are enabled/disabled based on the role that SanteDB is operating in. For example, if SanteDB needs to act as an MPI then the GS1 and ATNA interfaces are disabled (along with related user interface platforms).

{% hint style="info" %}
While SanteDB can be integrated into any standards compliant HIE (including OpenHIE), it doesn't require a full HIE infrastructure to operate properly and securely. It can be used as a launch point into a broader e-health infrastructure (i.e. it is possible to launch SanteDB based solutions without an HIE and then build an HIE around it)
{% endhint %}

###


# Installation

SanteDB solutions such as SanteMPI, SanteIMS, and the generic CDR are installed in a similar manner. This section provides resources on the planning, preparation, installation and securing of SanteDB iCDR and dCDR software packages.

{% hint style="info" %}
It is recommended that readers review the [Architecture](/santedb/architecture) documentation to become familiar with the high level concepts of SanteDB architecture.
{% endhint %}

## Installation for Development&#x20;

When installing SanteDB in a development environment, we recommend[Using Docker Containers](/installation/installation-1/deployment/installing-software/santedb-server/installation-using-appliances/docker-containers)for your iCDR instance and then [Installing the dCDR SDK](/installation/installation-1/deployment/installing-software/disconnected-gateway/installing-the-dcdr-sdk).

You can then [clone the starter code project](https://github.com/santedb/applet-starter) and follow the [Getting Started](/developers/getting-started) article to start developing SanteDB applications!

## Production Deployments

Installing SanteDB in a production environment is an involved process which is dependent on the nature of the environment (hospital, province, national, etc.) as well as the specific requirements of the project management office involved.&#x20;

The SanteDB has collected a high-level guide to the deployment of the SanteDB services like SanteMPI in our [Operationalizing SanteDB](/installation/installation-1) guide.

## Related Topics

{% content-ref url="/pages/h9bHu9CmLtkOxLwg5ElZ" %}
[Quick Start Guide](/installation/quick-start-guide)
{% endcontent-ref %}

{% content-ref url="/pages/-MUJboL32vKrSeAbFtXJ" %}
[Releases](/installation/releases)
{% endcontent-ref %}

{% content-ref url="/pages/-LZqIPeYP52pYSmIJjPs" %}
[Operationalizing SanteDB](/installation/installation-1)
{% endcontent-ref %}

{% content-ref url="/pages/n60WauAMGNvim8P6eIPx" %}
[Securing SanteDB APIs](/installation/installation-1/deployment/securing-the-apis)
{% endcontent-ref %}

{% content-ref url="/pages/-MBu-qNl-wwrvMb6fD1w" %}
[Demonstration Environments](/installation/demonstration-environment)
{% endcontent-ref %}


# Releases

SanteDB software can be downloaded via the GitHub pages for each of the projects.

## Downloads

| Download Link                                                                      | Contents                                                                                                        | Installation Instructions                                                                                                                       |
| ---------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| [SanteDB iCDR](https://github.com/santedb/santedb-server/releases)                 | <ul><li>SanteDB iCDR Server</li><li>SanteDB Administration Console</li></ul>                                    | [SanteDB iCDR Server](/installation/installation-1/deployment/installing-software/santedb-server)                                               |
| [SanteMPI iCDR](https://github.com/santedb/santempi/releases)                      | <ul><li>SanteMPI Server</li></ul>                                                                               | [SanteDB iCDR Server](/installation/installation-1/deployment/installing-software/santedb-server)                                               |
| [SanteDB dCDR Web Access Gateway](https://github.com/santedb/santedb-www/releases) | <ul><li>Web Access Gateway Service</li></ul>                                                                    | [Installing Web Access Gateway](/installation/installation-1/deployment/installing-software/disconnected-gateway/installing-web-access-gateway) |
| [SanteDB dCDR SDK](https://github.com/santedb/santedb-sdk/releases)                | <ul><li>Applet Debugger</li><li>Business Rules Debugger</li><li>Data Importer</li><li>Package Manager</li></ul> | [Installing the dCDR SDK](/installation/installation-1/deployment/installing-software/disconnected-gateway/installing-the-dcdr-sdk)             |

{% hint style="info" %}
You can download the latest versions (even if release notes aren't prepared for them on GitHub) from the [SanteDB Experimental Releases](http://santesuite.org/assets/uploads/santedb/community/releases/) repository.
{% endhint %}

## SanteDB iCDR Server&#x20;

### Installers

The following iCDR server releases can be found via the [santedb-server project ](https://github.com/santedb/santedb-server/releases)on GitHub:

* Microsoft Windows Installation Package
* Linux Distribution (manual install via tarball)
* MacOS (manual install via zip)

### Virtual Appliances

Additionally, you can download a virtual appliance via an Open Virtual Appliance file:

* [Headless Virtual Appliance](http://santesuite.org/assets/uploads/santedb/community/ova/santempi-latest-headless.ova) (useful for running SanteDB in a production environment)
* [Developer Virtual Appliance ](http://santesuite.org/assets/uploads/santedb/community/ova/santempi-latest-developer.ova)(useful for developers working with SanteDB)

### Docker Containers

You can also run SanteDB iCDR products in a Docker or Kubernetes environment. For more details see the [Docker Containers ](/installation/installation-1/deployment/installing-software/santedb-server/installation-using-appliances/docker-containers)documentation.

## SanteDB dCDR

### Android Application

Typically a SanteDB dCDR instance is customized and branded for a particular context. You can download the vanilla (whitelabel) dCDR Android Applications via the [santedb-dc-android GitHub ](https://github.com/santedb/santedb-dc-android/releases)project.

{% hint style="info" %}
You can use the generic SanteDB dCDR Android application to connect to any SanteDB iCDR server - the generic dCDR will download the latest application packages from the iCDR after joining.
{% endhint %}

### Windows Application

The self-contained Windows Application is useful for disconnected environments where larger datasets are required offline and higher burden of data entry is necessary. The Windows Application can be installed via the installers available on the [santedb-dc-win32 GitHub](https://github.com/santedb/santedb-dc-win32/releases) project.

### Disconnected Gateway Service

The disconnected gateway service provides a common dCDR instance running on a local area network and allows multiple web-browsers, Android apps, and third party systems (via HL7 or FHIR) to connect to the disconnected environment.

The dCDR can be installed and is tested on:

* Microsoft Windows via an installer
* Linux or MacOS via a tarball/zip distribution (requires Mono framework)
* Raspbian or MacOS M1 ARM processors (requires Mono for ARM)

The dCDR Gateway can be downloaded from the [santedb-dcg GitHub](https://github.com/santedb/santedb-dcg/releases) project.

### dCDR Web Access Gateway

The dCDR WWW service allows operators of SanteDB infrastructure to host dCDR applications (which are typically designed for offline use) to operate in an online-only fashion and allows for access to the user interfaces for broad internet hosting environments.

The dCDR web host is typically used to host administrative panels, reporting portals, etc. The service can be installed on:

* Microsoft Windows (via installer)
* Linux or MacOS (via tarball - requires Mono Framework)
* Docker Containers

The installers can be accessed via the [santedb-www GitHub](https://github.com/santedb/santedb-www/releases) project. The docker instance can be spun up using the `santedb-www:latest` docker image.

## Software Development Kit

The SanteDB SDK is used by developers to simulate the offline dCDR in a debug-friendly environment. The SDK is documented on the [Installing the dCDR SDK](/installation/installation-1/deployment/installing-software/disconnected-gateway/installing-the-dcdr-sdk) wiki page.&#x20;

The SDK runs on:

* Microsoft Windows (via installer)
* Linux or MacOS (via tarball - requires Mono Framework)

It can be downloaded from the [santedb-sdk GitHub](https://github.com/santedb/santedb-sdk/releases) project page.


# 3.0 Releases

Version 3.0 of the SanteDB iCDR, dCDR and related solutions (SanteGuard and SanteMPI) represent a large series of changes from the 2.2x series. Some of the changes have been incorporated from our Version 3 [Roadmap](/santedb/software-architecture/version-3.x-roadmap).

## Refactored Persistence Layer

The larges and perhaps most impactful change in the version 3.0 is a complete refactoring of the entire persistence layer in SanteDB. This refactoring has allowed the SanteDB 3.0 version not only to use the database much more efficiently, but allows callers on the REST APIs to exert more control over how data is loaded.

### Pipeline Loading of Results

The new persistence layer interfaces which load data to/from a data source now return an instance of `IQueryResultSet`. This is a delay expanded IEnumerable. Whenever a sort is applied, or a key is selected a new instance of IQueryResultSet is wrapped around the original. The database command is only executed when data is read from the reader. This also cleans up the calling structure, for example, in version 2.0 to determine if a record exists or to select a single field:

```csharp
var exists = persistence.Find(o=>o.UserName == "BOB", 0, 1, AuthenticationContext.SystemPrincipal).Any();

// Executed SQL:
// SELECT * FROM SEC_USR_TBL WHERE USR_NAME = 'BOB' OFFSET 0 LIMIT 1;

var key = persistence.Find(o=>o.UserName == "BOB", 0, 1, AuthenticationContext.SystemPrincipal).FirstOrDefault(o=>o.Key);
// Executed SQL:
// SELECT * FROM SEC_USR_TBL WHERE USR_NAME = 'BOB' OFFSET 0 LIMIT 1;
```

This pattern forced the persistence layer to load the object just to determine a detection.

In the new pattern this is now alleviated with IQueryResultSet:

```csharp
var resultSet = persistence.Find(o=>o.UserName == "BOB", AuthenticationContext.SystemPrincipal);

// No SQL is executed

var exists = resultSet.Any();

// SQL Executed:
// SELECT EXISTS 1 FROM SEC_USR_TBL WHERE USR_NAME = "BOB";

var key = resultSet.Select(o=>o.Key).FirstOrDefault();

// SQL Executed:
// SELECT SEC_USR_ID FROM SEC_USR_TBL WHERE USR_NAME = "BOB" LIMIT 1;
```

### Client Controlled Data Loading Strategies

Callers may also instruct to the data persistence layer the type of load strategy to be used when loading data from the database depending on the intended use of the data.

Data load strategies are:

* QuickLoad - Load only core properties, no related entities
* SyncLoad - Load only properties which are needed for synchronization
* FullLoad - Load all properties directly from the data persistence layer

Loading stratgies are controlled by the `DataPersistenceContext` :

```csharp
using(DataPersistenceContext.Create(LoadStrategy.QuickLoad)) {
   // Any data events here will only load core properties#
}
```

This method can also be used to control the way that data is deleted from the database.

### Harmonization of Persistence Providers

3.0 introduces new persistence provider which have allowed us to harmonize the dCDR and iCDR persistence layers into a common framework. This means that the iCDR can be run on SQLite, or the dCDR can be run on PostgreSQL!

### Customizable Relationship Validation

You can now customize the validation rules used to validate [Entity Relationships](/santedb/data-and-information-architecture/conceptual-data-model/entities/entity-relationships), [Act Relationships](/santedb/data-and-information-architecture/conceptual-data-model/acts/act-relationships), and Act Participations on the REST API. This makes it easier to create custom context-specific relationship types and enforce data persistence layer validation of those rules.

## Refactoring of OAUTH Infrastructure

The OAUTH infrastructure has been refactored completed to better adhere to OpenID concepts. This refactoring includes:

* Separation of the grant type into extendable implementations so users can create custom grant flows or override the SanteDB flows more readily
* Separation of token serialization, and encoding allowing for more robust access and identity token passing
* Implementation of standardized MFA secret generation using time and hash based one time passwords.

## Harmonization of the dCDR into the iCDR&#x20;

The interfaces which differentiated the iCDR and dCDR have now been combined into a common platform. This completes the refactoring of Portable Class Library code to a common code base. This means that any iCDR code can run (theoretically) in a dCDR or vice versa. It also means that iCDRs can be synchronized with other iCDR instances.

## Data Marts & Pipelines for BI

The BI layer has been refactored to include a new feature allowing applets to define [Data Marts](/developers/applets/business-intelligence-bi-assets/bi-asset-definitions/data-marts). A data mart is a new database (separate from the primary database) which has de-normalized data which can be used for integrating with SanteDB for reporting purposes at the database layer. Uses for data marts include:

* Exposing a simpler set of tables for third party reporting tools to consume (such as PowerBI, Jasper, or Tableau)
* Isolating BI reports from the primary database allowing for better load balancing on the data infrastructure in SanteDB
* Producing regular snapshots of your primary database over time.

BI data marts define a target schema, and data flows to populate that schema witin your applets and are applied on the dCDR and iCDR in the same manner (whether you're using PostgreSQL or SQLite).&#x20;

## User Customizable Data Quality Rules

Previous versions of SanteDB required system administrators to configure the rules in the primary configuration file. SanteDB 3.0 includes a new function which allows for the export, import and synchornization of data quality rules in the user interface. For more information see: [Data Quality Rules](/operations/cdr-administration/santedb-administration-panel/cdr-administration/data-quality-rules).

## User Customizable CDSS Rules

Previously SanteDB v1.0, and v2.0 required CDSS rules to be written in an XML grammar and to place those into applet files. This process was tedious and meant that adding new CDSS rules was difficult for end-users and administrators. SanteDB 3.0 enhances this by:

* Providing an administrative UI for creating CDSS rules (see: [Decision Support Library](/operations/cdr-administration/santedb-administration-panel/cdr-administration/decision-support-library))
* Providing a new text-based CDSS grammar that is easier for clinical analysts to write (see: [CDSS Definitions](/developers/applets/cdss-protocols/cdss-definitions))
* REST operations to execute CDSS rules against HDSI objects

## User Customizable Concept Dictionary

SanteDB v1.0 and v2.0 required importing of concept terminologies via console tooling which was cumbersome and difficult to write. SanteDB 3.0 introduces a new concept dictionary management tooling in the administration panel (see: [Concept Dictionary Administration](/operations/cdr-administration/santedb-administration-panel/concept-dictionary-administration)) and includes the ability to bulk create reference terminologies and concept sets via CSV uploads.

## CDR Metadata Export

SanteDB v1.0 and v2.0 used [Dataset Files](/developers/applets/distributing-data) to import data between projects and servers, however creation of these files was cumbersome and required manual editing of XML bundles. SanteDB v3.0 now allows export of any result set directly to a dataset file via the `$export` operation. Additionally, many of the user interfaces in the administrative panel allow for the export of data directly  into a dataset from the UI.&#x20;

## Certificate Mapping

It is now possible in SanteDB 3.0 to map any credential (user, application or device) with one or more certificates for either data signatures or authentication. This greatly streamlines the administration of PKI certificates in the SanteDB solution (see:  [Managing Devices](/operations/cdr-administration/santedb-administration-panel/security-administration/managing-devices#certificate-mapping))

## Improved HDSI Parsing

SanteDB 3.0's HDSI parsing routines have been completely refactored, and allow for many enhanced queries, including:

* Complex guard expressions, for example:
  * A Consumable relationship with at least 2 doses: `participation[relationshipType.mnemonic=Consumable&quantity=>2].player=XXXXX`
  * Either next of kin or any family member: `relationship[NextOfKin|relationshipType.conceptSet.mnemonic=FamilyMember].target.name.component.value=Bob`
* URI friendly operators: `eq`, `ne`, `gt`, `gte`, `lt`, `lte`, `ap`
* Multi-path OR semantics (rather than the default AND semants) - Example: Patient name or Mother's name: `name.component.value||relationship[Mother].name.component.value=Maria`

## Improvements to dCDR

In Version 2.x, the dCDR, while similar in function to the iCDR, was a completely different codebase. Along with harmonizing of the data layer, the SanteSuite team has also harmonized the entire service layer of the dCDR. This means, for example, that the administration console can be connected to a dCDR instance, or, for example, that the web interface can be run directly on the iCDR (we still recommend separating these concerns between iCDR and dCDR). This improvement means it is much easier to write plugins in C# or other .NET technologies.

## Built-In Data Import

SanteDB 3.0 introduces a new feature for [External Data Maps](/developers/applets/external-data-maps), which allow developers to specify a simple transform which ingests data from an external file format (CSV, XLS, etc.) and translates data from that external file format into the RIM for import.

The administration panel also includes a UI for [Importing External Data](/operations/cdr-administration/santedb-administration-panel/cdr-administration/importing-data) to allow administrators to use their UI to import. See: [Importing Data](/operations/cdr-administration/santedb-administration-panel/cdr-administration/importing-data)

## Improved Administration Panel

The administration panel now supports a variety of improvements which make the administration of Places, Facilities, Organizations, and Materials much easier. These improvements allow an adminsitrator to:

* Define a political division hierarchy (which can then be used for structured address inputs)
* Define facility hierarchy, services, schedules, etc.
* Define material classification types, manufacturers, etc.

## Improved Identity Domain Controls

Whereas version 2.x only permitted a single identity domain scope and assigner to be allocated to an identity domain, version 3.x allow administrators to specify multiple. Additionally, it is now possible for an administrator to configure whether information from a particular application is **authoritative** in nature or **informative** for a particular identity domain.

## Better Development Tools

The development of applets has been greatly improved with the new `SanteDB.DevTools` package. This plugin allows the iCDR to act like the applet debugger in the v2 iCDR. Meaning that you can edit BI reports, business rules, etc. directly in Visual Studio Code and your iCDR instance will load them in real time. We have also added options to the package manager to inspect created packages, making it easier to debug and diagnose packaging issues.


# Queenston Release

As part of improving documentation of the SanteDB release documentation, each code named release will have its development versions (odd number minor versions) on a single page with the official versions (even number minor versions).&#x20;

Since this new method of documenting releases has only started with 2.1.170, this page is partial. One should consult the GitHub release schedules for more information.

## Version 2.2.3

Release Assets: <http://santesuite.org/assets/uploads/santedb/community/releases/2.2.3/>

* Fixes bug with the deletion of pub-sub subscriptions from the user interface
* Fixes un-delete operation on the pub-sub subscription manager
* Adds persistent job state service
* Adds default implementation of job state service (local XML file - work is being performed on the shared state service).

## Version 2.2.1

Release Assets: <http://santesuite.org/assets/uploads/santedb/community/releases/2.2.1.10/>

This release of SanteDB builds on the fixes in 2.2.0 and corrects adds the following enhancements:

* Fixes bug with blocking on `metaphone` and `dmetaphone` on PostgreSQL (improper parameter exception)
* Adds better descriptions to the SanteGuard view screens for user activity and audit trail.
* Updates to the audit detail view which uses the registered resource viewer (in order to open more types of data)
* Adds link to the detailed audit entry in the audit trail and activity tabs
* Fixes issue with job scheduling (present in 2.2.0) setting the appropriate type of schedule in the `xcron.xml` file.
* Adds ability to download match configuration source files in XML to port the configuration over to other systems.

## Version 2.2.0 (Official)  / 2.1.180 (CTP)

Release Assets: [http://santesuite.org/assets/uploads/santedb/community/releases/2.2.0/ ](http://santesuite.org/assets/uploads/santedb/community/releases/2.2.0/)

This is the second official stable release of the .NET Standard version of the SanteDB platform and related assets. The products which are included in the 2.2.0 release of SanteDB are:

* SanteDB iCDR Server 2.2.0
* SanteMPI iCDR Server 2.2.0
* SanteDB dCDR Web Access Gateway 2.2.0
* SanteDB dCDR Software Development Kit 2.2.0

This release includes all major upgrades and updates to the SanteDB platform from the 2.1.x Community Technology Preview release streams and is suitable for testing. There will be a normalization period for this release, however, since it is an official release of SanteDB iCDR it will receive an official maintenance branch and will have generally, more stable APIs.

Following the release of the 2.2.0 all future 2.1.x Community Technology Previews will be for the Regina release.&#x20;

### Enhancements

* SanteDB/SanteMPI Core iCDR Enhancements
  * Enhancements to HL7 FHIR interface:
    * Support for FHIR operations (`$operation`)
    * Implementations of `$match`, `$validate`, `$ihe-pix`, `$process-message` operations
    * Support for FHIR messaging bundles and transaction bundles
    * Support for FHIR subscriptions and FHIR push notifications
    * Enhanced support for FHIR resources `Patient`, `RelatedPerson`, `Organization`, `Practitioner`
    * Implementation of IHE PMIR messaging
  * Enhancements to HL7 Version 2 Interface:
    * Enhanced support for HL7 Z-Segments in messages
    * Enhanced processing of HL7 datatypes and handling of errors
  * New MDM Layer
    * Refactored complete MDM layer to support establishment of ROT from determiner codes
    * Improved functions for MDM auto-linking and candidate resolution
    * Support for unlink and re-link operations
    * Implementation of MDM enhanced HDSI operations `$mdm-link`, `$mdm-rematch`, `$mdm-ignore`.
  * Enhancements to HDSI
    * Support for HDSI operations via `$operation` name
    * Support for HDSI deep-linked child records (cleaned up implementation to be pluggable)
    * Enhanced HTTP caching for `If-None-Match`
  * Enhancements to matching engine
    * Implementation of update/save configuration files over HTTP APIs
    * New blocking algorithms for `similarity` and `similartiy_lev`
    * Added new blocking logic to allow for specifying ignore keys on master or sources
    * Added diagnostics / debugging / tracing collectors
  * Enhancements to probes interfaces
    * New probes implemented for CPU, Memory, ADO.ET connection, thread pooling, etc.
  * Enhanced thread pools for REST APIs and core functions which can scale-up or scale-down threads (without polluting the .NET threadpool)
  * Updated documentation of core API classes and interfaces
  * Automatically seed/create and update/patch database schemas
  * Enhanced BIS functions for storing materialized
  * Enhanced `IJob` management, scheduling and control
  * New Configuration Tool which can be used for setting/modifying settings on the iCDR host in Windows or Linux
  * Added classification, strength, and role codes to entity, act relationships and participations.
  * Implementation of MSMQ queue provider
* SanteDB Administrative Interface Enhancements
  * System Administration Screen Additions
    * System Probes manager screen
    * Dispatcher queue management screen
    * Pub/Sub management screen
  * Security Administration Enhancements
    * User, group, device, and application screens now modular (have extension points)
    * Re-envisioned audit viewing screen and audit center
  * MPI Management Screens
    * Enhanced entity relationship diagrams
    * Master Data Management screens for match/merge/unlink
    * SanteMPI matches panel
      * Detailed match overview screen
      * Resolve/Ignore functions on summary view
      * Reports for match details including full match export (< 10k rows)
    * SanteMPI Match Configuration
      * Edit/View match configuration metadata
      * Edit/View match blocking configuration&#x20;
      * Edit/View match scoring with compete algorithm selection for each attribute
      * Edit/View match classification stage for classifying results
      * Test match configuration functions
    * New free-text and advanced (per-field) search
    * New power search function
* SanteDB dCDR Web Access Gateway Enhancements
  * Self-restart of web access gateway after configuration
  * Ability to run in Docker, Linux or Windows service environments
* SanteDB dCDR SDK Enhancements
  * Enhanced pakman.exe manager
    * Supports local package repository resolution for applet debugger
    * Supports publish to remote package repository / server
  * Enhanced applet debugger environment which can load references by name
  * New vocabulary import tool which can import FHIR>Dataset or CSV>Dataset (for reference terms only)
  * New patient importer which can import ONC or FEBRL datasets

## Version 2.1.175 (CTP)

**Release Assets:** <http://santesuite.org/assets/uploads/santedb/community/releases/2.1.175/>

This is a minor release which correct small performance and caching issues. Included in this fix are:

* Addresses over-threading of the rest and internal background job thread pool (adds option to use .NET thread pool for all services)
* Addresses under-caching issues where client using `If-None-Match` would not receive a cached version but would hit the database.
* Fixes issues with the new version of NPGSQL related to handing of DateTime and DateTimeOffset
* Adds units of measure to the dCDR Web Access Gateway admin portal on probes
* Fixes issue where scheduled tasks (starting before date of startup) are executed on start rather than waiting until the next execution window
* Adds performance probes for:
  * .NET Thread Pool I/O and Worker Threads
  * ADO.NET Database Connections (active read/write, statements being executed)
* Adds ability to change blocking instructions to operate on MASTER or SOURCE mode
  * Fixes issues with ignored records when blocking is performed in SOURCE mode
* Adds new `date_trunc` filter expression for HDSI queries. This is more efficient than `date_diff` in that it allows date column indexes to be used.
* Increases performance of `levenshtein` filter function on PostgreSQL by changing logic from : `where levenshtein(column_name, ?) < value` to `where column_name % ? and levenshtein(column_name, ?) < value` which allows PostgreSQL to use the GIN indexing to reduce the number of rows passed to levenshtein function.

## Version 2.1.170.1 (CTP)

**Release Assets:** <http://santesuite.org/assets/uploads/santedb/community/releases/2.1.170.1/>

This version is a patch for the 2.1.170 release. It fixes the following issues found in 2.1.170:

* Fixes logic for timer jobs based on calendar to reduce the "greedyness" of the jobs
* Fixes display caching issue (was an issue with the BulkPurge function) so new data is properly rendered.
* Fixes some threading issues with the .NET ThreadPool on background matching

## Version 2.1.170 (CTP)

Release Assets: <http://santesuite.org/assets/uploads/santedb/community/releases/2.1.170/>

### Features / Fixes:

* Added ability to schedule `IJob` jobs within the administrative panel
* Added job descriptions to the job screen
* Added ability to more efficient background matching on the match job
* Added default .NET thread pool as the default implementation of `IThreadPoolService` and changed the way that the probe data is displayed.
* Added `useLowerLayer` attribute to the `<blocking>` instructions in match configuration. This allows for configurations to bypass master synthesization (see notes below)
* Added configuration to the match screens in the administrative panel to allow for selection of absolute scoring or normalized scoring.
* Added ability to customize the free-text algorithm used for translating search terms into `tsquery` results (see:&#x20;
* Fixed matching engine bug where the record's self was not excluded from result.
* Fixed matching `auto-merge` bug (see above fix for cause)

### Known Issues:

* The entity relationship graph on the patient profile screen will show duplicate links
* Caching of some entities shows erroneous data on the relationship graphs. Validation of the state at database reveals this is a caching issue.&#x20;
* Running the background matching task in Linux or Docker can result in CPU use at 100% as the `ThreadPool` and `ConcurrentQueue<T>` implementations in Mono framework appear to be implemented in a slightly, less efficient manner.
* There is a display bug for entities which have been auto-merged using the `$mdm.auto-link` flag where the resulting source record will display multiple relationships (indicating they are active when they are not).&#x20;

### PostgreSQL FreeText Search

The new version of the SanteDB `_any` parameter handling uses the free-text engine. In PostgreSQL this method calls the function `fti_tsquery` function. This function is passed a single text parameter and is expected to return a `tsquery` structure.&#x20;

By default, 2.1.170 uses the `websearch_to_tsquery` method. This search method was introduced in PostgreSQL 11 and converts a search string into a tsquery method. Implementers may wish to change this behavior if:

* They are using PostgreSQL < 11&#x20;
* They wish to use other free-text search configurations (other than English)
* They wish to support other lexeme or advanced functions.

#### Using Plain Free-Text Searches

Implementers can use plain free-text search parsing by altering the function `fti_tsquery` to use `plainto_tsquery` as:

```
CREATE OR REPLACE FUNCTION public.fti_tsquery(search_term_in text)
 RETURNS tsquery
 LANGUAGE plpgsql
 IMMUTABLE
AS $function$
BEGIN
	RETURN PLAINTO_TSQUERY('english', search_term_in);
END;
$function$
;

```

#### Using Full-Featured Searches / PostgreSQL 10

Implementers can allow users to access advanced features supported by the PostgreSQL freetext search engine. The method below illustrates taking a search term and splitting the term by spaces and appending each back to a query.&#x20;

```
CREATE OR REPLACE FUNCTION public.fti_tsquery(search_term_in text)
 RETURNS tsquery
 LANGUAGE plpgsql
 IMMUTABLE
AS $function$
BEGIN
	RETURN TO_TSQUERY('english', ARRAY_TO_STRING(STRING_TO_ARRAY(SEARCH_TERM_IN, ' '), ' & '));
END;
$function$
;

```

The method above would convert `John Smith Lincoln FR-403` to the TSQUERY expression: `John & Smith & Lincoln & FR-403` . This simple implementation permits search by prefix/wildcard: `Joh:* Sm:*` converted to `Joh:* & Sm:*`.&#x20;

Users can implement custom search term parsing/filtering based on their use case and context.

### Matching Job Notes

The SanteDB matching job has been updated to modify the behavior of the job based on the configuration of the environment it is running in. The table below provides a summary of this change:&#x20;

<table><thead><tr><th>OS</th><th width="182.377245508982">CPU</th><th>Matching / Strategy</th></tr></thead><tbody><tr><td>Windows</td><td>&#x3C; 4 Cores</td><td>Multi-Threaded Load (PLINQ)<br>Single Threaded Match</td></tr><tr><td></td><td>4+ Cores</td><td>Multi-Threaded Load (PLINQ)<br>Multi-Threaded Match</td></tr><tr><td>Docker / Mono</td><td>&#x3C; 4 Cores</td><td>Single-Threaded Load<br>Single Threaded Match</td></tr><tr><td></td><td>4+ Cores</td><td>Single-Threaded Load<br>Multi-Threaded Match</td></tr></tbody></table>

When running the background matching job in Docker , users may experience periods of time where the available threads in the thread pool are consumed by the worker tasks. This appears to be the Mono implementation of `ConcurrentQueue` and/or the method in which Mono allocates threads.&#x20;

Users may experiment with the `MONO_THREADS_PER_CPU` environment variable to tune the performance of their deployment.


# Quick Start Guide

This tutorial will provide an overview of how to install and run the SanteDB iCDR MPI solution (SanteMPI) using Docker for a demonstration environment.

{% hint style="info" %}
Do not use these instructions to deploy SanteMPI in a production environment. These instructions are intended to provide a quick start for demonstration or evaluation only.&#x20;
{% endhint %}

{% hint style="info" %}
The code for the quick-start guide can be found on the SanteDB GitHub page at: <https://github.com/santedb/hello-mpi>
{% endhint %}

## Pre-Requisites

This tutorial uses Docker as a basis for illustrating SanteMPI functions. In order to complete this tutorial, users should:

* Have Docker installed on the host system (on Windows or Linux)
* Have a text editor which can be used to edit the docker YML files
* Installed SOAP UI (<https://www.soapui.org/downloads/latest-release/>)
* Downloaded the Installation Qualification Test Suite (<https://github.com/santedb/santempi/blob/master/SanteMPI-Test-Cases-soapui-project.xml>)

## Create the Docker Application

In a text editor, create a new directory and create a new text file called `docker-compose.yml` in that directory.

```
mkdir quickstart
notepad docker-compose.yml
```

First, you will need to create a postgresql service, this is where the SanteMPI database will be stored.

```yaml
version: "3.3"

services:
  db:
    image: postgres
    container_name: sdb-postgres
    ports:
      - "5432:5432"
    environment:
      POSTGRES_USER: santedb
      POSTGRES_PASSWORD: SanteDB123
    restart: always

```

This section:

* Creates a new docker service called `db` from the `postgres:latest` tag
* Exposes the PostgreSQL database on the host on port 5432
* Sets the initial postgresql user to `santedb` with password `SanteDB123`

Next, declare the `santedb-mpi` service , this service will host the the actual iCDR which has SanteMPI:

```yaml
  santedb:
    image: santesuite/santedb-mpi:latest
    container_name: santedb-mpi
    environment:
      - SDB_FEATURE=LOG;DATA_POLICY;AUDIT_REPO;ADO;PUBSUB_ADO;RAMCACHE;SEC;SWAGGER;OPENID;FHIR;FHIR_AUDIT;HL7;HDSI;AMI;BIS;MDM;MATCHING;IHE_PIXM;IHE_PDQM;IHE_PMIR;IHE_PIX;IHE_PDQ
      - SDB_HL7_AUTHENTICATION=Msh8
      - SDB_MATCHING_MODE=WEIGHTED
      - SDB_MDM_RESOURCE=Patient
      - SDB_MDM_AUTO_MERGE=false
      - SDB_DB_MAIN=server=sdb-postgres;port=5432; database=santedb; user id=santedb; password=SanteDB123; pooling=true; MinPoolSize=5; MaxPoolSize=15; Timeout=60;
      - SDB_DB_AUDIT=server=sdb-postgres;port=5432; database=auditdb; user id=santedb; password=SanteDB123; pooling=true; MinPoolSize=5; MaxPoolSize=15; Timeout=60;
      - SDB_DB_MAIN_PROVIDER=Npgsql
      - SDB_DB_AUDIT_PROVIDER=Npgsql
      - SDB_DATA_POLICY_ACTION=HIDE
      - SDB_DELAY_START=5000
    ports:
      - "8080:8080"
      - "2100:2100"
    depends_on:
      - db
    restart: always
```

This section of the file:

* Creates a service named `santedb-mpi` in the docker environment
* Enables feature via the `SDB_FEATURE` environment variable (for reference see: [Feature Configuration](/installation/installation-1/deployment/installing-software/santedb-server/installation-using-appliances/docker-containers/feature-configuration)
* Instructs the iCDR to enable [Master Data Storage](/santedb/data-and-information-architecture/data-storage-patterns/master-data-storage) for `Patient` resources
* Connects the main database to `santedb` on the `db` container.
* Connects the audit database to `auditdb` on the db container
* Instructs the iCDR to `hide` any data which is tagged with a privacy policy (other options are `redact`, `audit, none`
* Instructs the iCDR to wait 5 seconds before starting (to allow the database to initialize)
* Forward/expose the iCDR APIs on port 8080

Finally, create a container which will run the web access gateway using `santedb-www:latest`

```yaml
  www:
    image: santesuite/santedb-www:latest
    container_name: santedb-www
    ports:
      - "9200:9200"
    depends_on:
      - santedb
    restart: alwaysyaml
```

This section:

* Creates a service named `www` which uses the `santedb-www` image
* Forward traffic to the web portal on port 9200

## Start the Docker Application

After saving the text file, return to your command prompt and type:

```
docker compose -f docker-compose.yml up
```

This will start the SanteDB iCDR (running SanteMPI), the web access gateway and database. Initial startup of the SanteMPI container can take upwards of 5 minutes. You will see a log entry which indicates that startup was successful after this time.

## Configure the Web Access Gateway

You can now configure the web-access gateway, the [Configuring the Web Access Gateway ](/installation/installation-1/deployment/installing-software/disconnected-gateway/installing-web-access-gateway#configure-the-web-access-gateway)article contains detailed instructions on how this is performed.&#x20;

### Join the Realm

Once startup is completed, navigate to [http://127.0.0.1:9200](http://127.0.0.1:9200/) in your web browser. You will be prompted for connection details. For the quick start use:

* Device ID: quick-web
* Realm: santedb-mpi

The rest of the settings can be left as their defaults.

![](/files/D1aOZYv0JLTu2AuVvZuT)

Pressing the `Join` button will prompt you for a user name and password, use `Administrator` and `Mohawk123` as the password.

![](/files/463SOtPEooqqqwW6LrOu)

### Select the MPI Role

You will be managing a SanteMPI server, therefore you will need to instruct the web access gateway that this gateway will be acting in the "SanteDB Master Patient Index Functions" solution.

![](/files/24gJQTzGIDcsktHpFwY8)

{% hint style="info" %}
Ensure you select the option to automatically download updates for applet files. This will ensure new applets uploaded to the iCDR will be downloaded by the dCDR gateway.
{% endhint %}

### Set Online Only Function Level

Since the web access gateway will be acting as an administration panel, you should set the dCDR in online only mode (no disconnected use)<br>

![](/files/SeqV1Wx8wileYjEEp7QV)

{% hint style="danger" %}
The `santedb-www` and Web Access Gateway in general lack the SQLite binaries needed to operate in offline mode. If you select offline mode your web container will most likely not start up.
{% endhint %}

### Accept Defaults

You can accept the defaults for the following screens:

* Logging - This screen sets the verbosity of the output to your Docker host log
* Application Services - This screen allows for the enabling of third party or additional services which are not required by the web access gateway.
* Network - This screen allows you to configure the optimization between the dCDR and iCDR

Full documentation of these settings can be found on the [Installing Web Access Gateway](/installation/installation-1/deployment/installing-software/disconnected-gateway/installing-web-access-gateway) and [Installing Disconnected Gateway](/installation/installation-1/deployment/installing-software/disconnected-gateway/installing-disconnected-gateway) wiki articles.

### Customize the User Interface

You can customize the manner in which the SanteMPI user interface behaves by setting one or more [User Interface App Settings](/installation/installation-1/deployment/installing-software/disconnected-gateway/app-settings). For example, the configuration below will only require given and family names to be registered, and will show the normally hidden fields for collecting patient Religion.

&#x20;

![](/files/1Qv0h7ROminN3i7cUk3y)

### Wait for Refresh

Once your settings are saved, the web access gateway will save the settings and restart itself.

![](/files/9U4So8OVxPtj1S7JwtIe)

## Customize the MPI

You can now log into the web administration console for the Master Patient Index. You can use the administrator/Mohawk123 account to log into the administrative panel.

![](/files/tu7uLjKLDMrYxpfWE2QK)

{% hint style="info" %}
Full documentation for the Administrative panel is available at the [Broken mention](broken://pages/VjO9ryB6V5Hr1y5izsr4) page.
{% endhint %}

### Give Administrators Access to MDM and Clinical Data

Since this is a demonstration environment, you will probably want to change the default access policies for `Administrators` to allow them to see clinical data and perform MDM tasks. This is done by navigating to `Security -> Groups` and pressing edit on the `Administrators` group.

![](/files/3k9B2oQBFwVYpJXFUISe)

You can scroll to `Policies` and add the following policies to the group:

* Unrestricted MDM
* Unrestricted Clinical Data

![](/files/sWanesH9knw7j3URtBJj)

After adding these policies you should observe the policies in the master list of permissions.

![](/files/Y90kiCMSesEBkn7dShe2)

{% hint style="info" %}
You do not need to SAVE policy assignments, they are applied immediately.
{% endhint %}

### Re-Authenticate

The policies associated with your session for Administrator were established when you logged in, you've changed the policy set, however, your session will still have the old policy assignments for your user role. You will need to log out of the user interface to obtain a new session with the new policies.

![](/files/ZaGIDayZoGRep9Uwg8WP)

## Perform Installation Qualification

An easy way to get patients into the SanteMPI instance is to run the [Master Patient Index / Client Registry Qualification](/installation/installation-1/deployment/installing-software/santedb-server/installation-qualification/fhir-interface-validation). These tests will ensure that the MPI is operating correctly (using the default options) and in the process, will create a few test patients.

### Open the SOAP UI Project

In the pre-requisites, a link was provided to the SanteMPI Installation Qualification SOAP-UI project. You can launch SOAP UI on your system and import this project.

![](/files/K1WJIY6dR5MNQ7yBcv0N)

This will expose a new project in your SOAP UI project with the SanteMPI endpoints (restricted from the Swagger documentation) shown and a test case called `Installation Qualification`

![](/files/IcZeV1t9foU1ieFzKcYh)

### Start FHIR Mock Service

The installation qualification tool uses PMIR notifications and subscriptions, it is a good idea to start the FHIR Mock service so that your docker container has an endpoint to send these messages to.

![](/files/q3EFcpvYCnOsQk1WeXhs)

### Run Installation Qualification Tests

Double clicking on the `Installation Qualification` test suite will open the test steps for the SanteMPI installation qualification. There are 10 tests (all of which are documented in detail on the [MPI/CR Test Cases for FHIR](/installation/installation-1/deployment/installing-software/santedb-server/installation-qualification/fhir-interface-validation/mpi-cr-test-cases-for-fhir)page).

![](/files/8kq5M3k4Hh4Pdv6eUhgB)

If all tests return green status, it indicates that your copy of SanteMPI is operating as expected for baseline FHIR functions.

## Validate the User Interface

After the qualification tooling has been executed, you can now use the SanteMPI Dashboard to navigate the recent patients that were created in the installation qualification tool.

![](/files/akrTZ23jfwYLgVI7cjCD)


# Seeding ONC Patient Matching Data

Once a docker image is setup - it can now be seeded or populated with data. In addition to running the installation qualification tool, you can seed the ONC dataset into the SanteMPI server which has just been setup.&#x20;

{% hint style="info" %}
It is recommended seeding the entire ONC dataset be done on a host machine with at least 8 GB of RAM, 4 CPU cores, and an SSD
{% endhint %}

## Download Resources

In order to complete this tutorial you will require the following tools:

* A setup version of SanteMPI (you can use the [Quick Start Guide](/installation/quick-start-guide))
* The ONC Patient Matching Challenge Data (<https://github.com/onc-healthit/patient-matching>)
* The SanteDB SDK (you can see [Operationalizing SanteDB](/installation/installation-1))

## SanteMPI Version 3.x

### Import ONC Dataset

SanteMPI Version 3.x contains the necessary configuration for the ONC patient matching data in a dataset file which can be downloaded from our GitHub page: <https://github.com/santedb/santempi/blob/master/data/090-ONC%20Patient%20Matching%20Domains.dataset>

Once downloaded, visit the SanteMPI administration console and import the dataset file via **CDR Administration > Import Data**

Once uploaded - administrators will see the dataaset scheduled for import:

<figure><img src="/files/hglClftlREtxnafGJ9e0" alt=""><figcaption></figcaption></figure>

Pressing the **Run Scheduled** will setup the identity domains.

Following this step, the ONC dataset files can be uploaded, when uploading a dataset file, be sure to set the type of file to **ONC Patient Matching Challenge** as pictured below:

<figure><img src="/files/7PHuDrXQJ0CPCFYu8RYE" alt=""><figcaption></figcaption></figure>

Once the files are uploaded, you can run the import.

<figure><img src="/files/NfVZA08lQD51UZVw8EQ4" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
The seeding of the entire ONC patient dataset can take upwards of 12 hours depending on the complexity of your matching configuration.
{% endhint %}

## SanteMPI Version 2.x

### Prepare SanteMPI for ONC Data

First, we're going to need to prepare our SanteDB server to accept the ONC data, this includes:

* Creating the necessary identity domains for the ONC spreadsheets
* Setting the matching configuration appropriately&#x20;

#### Creating Identity Domains

The ONC dataset has two identity domains which need to be created in the SanteDB server. To do this, log into the administrative portal and click on **Reference Data** then **Identity Domains** and press **Create**.

You will need to register two identity domains:

<table><thead><tr><th width="150">Namespace</th><th>URL</th><th width="193">OID</th><th>Unique</th></tr></thead><tbody><tr><td>ONC </td><td>http://onc.org/eid</td><td>2.25.4949384934</td><td>true</td></tr><tr><td>MRN</td><td>http://onc.org/mrn</td><td>2.25.17237262721</td><td>false</td></tr></tbody></table>

#### Optimizing Match Configuration

The ONC dataset is a large dataset where the source records (provided in the CSV files) can reliably represent a patient, because of this we can get an added performance bonus by changing our match configuration to source/source mode rather than source/master (since there is nothing that a master record would add in blocking).

To change the match configuration, click on **SanteMPI** then **Match Settings** locate the `org.santedb.matching.patient.default` entry and click **View.**

On the **Blocking** tab if we expand a blocking instruction we see the default method of matching is Source/Master:

![](/files/JFBSMezEhbtF7u4OQNuB)

We can change this by pressing **Edit** (pencil) and modifying both blocking instructions. After this step the configuration should appear as:

![](/files/swQQ5VZhz1w8Vl9PFtsC)

#### Prepare ONC Dataset

Now that our MPI is setup correctly we should navigate to the directory where the ONC patient source data was cloned. To seed the data more easily, create a new batch file (if on Windows - if on Unix you should create an equivalent shell file) to call the SDK:

{% code title="seed-onc.bat" %}

```batch
@echo off
for %%F in (*.csv) do (
	start "Seeding %%F" "c:\Program Files\SanteSuite\SanteDB\SDK\importer.exe" --realm=http://127.0.0.1:8080 --user=Allison --password=Mohawk123 --source="%%F" --dataset=ONC --eid=ONC --mrn=MRN --ssn=SSN
)batch
```

{% endcode %}

The batch file will look at all the CSV files in the current directory and for each one it will:

* Start a new process
* Call the importer from the SDK with
  * The CSV file to be seeded
  * The realm on the local computer
  * Logged in as "Allison" and "Mohawk123" as password (i.e. this is Allison sending the data to the MPI)
  * Source format is ONC (opposed to FEBRL)
  * Enterprise ID is the ONC domain
  * Medical Record Number field maps to MRN domain
  * Social Security Number field maps to SSN domain

Now you can open a command prompt and type `seed-onc.bat` to start the seeding process. There will 9 consoles opened and 9 clients will begin seeding data to the MPI.

![](/files/euMlXPFb1ndfgDtuEJM0)

The overall health of your deployment can be monitored on the Probes page.

![](/files/S8hjfCg4OyUKkuYnjvTv)


# Operationalizing SanteDB

Operationalizing SanteDB (or any SanteDB solution) is not a trivial task, any large scale deployment of the solution requires planning and coordination between stakeholders. Implementers are encouraged to use formal methodologies for enterprise projects and architecture (examples: [CMMI](https://www.pmi.org/learning/library/cmmi-bring-pm-process-next-level-7538) , [TOGAF](https://www.opengroup.org/togaf), [DAD](https://www.pmi.org/disciplined-agile/process/introduction-to-dad), etc.) to manage the operationalization of the MPI projects.

Because operationalization is specific to the problem domain, local jurisdiction, size requirements, and other factors, the SanteDB wiki merely provides high level activities for operationalization as a reference. Any of the articles or templates found on the SanteSuite wiki are expected to be adapted by implementers, or to provide SanteDB specific considerations within their existing project management methodology.

The overall operationalization of a SanteDB service can be illustrated with 5 major activities.

![](/files/KCW9FIlV7KfxD7p0p3F8)

{% hint style="info" %}
This guide is intended to supplement internal project management procedures and activities of the implementing organization. The sections focus primarily on the SanteDB specific aspects of project planning and analysis. Templates, worksheets, and other toolkits are provided on an as-is basis and should be adapted for appropriateness in the local context into which SanteDB is being deployed.
{% endhint %}

## Information Gathering

Many implementations don't start with a concrete idea of what the deployment of SanteDB will be achieving beyond "we need X". The information gathering phase of an operationalization project is intended to establish a concrete consensus among stakeholder of **what** the SanteDB CDR will be used for.

See: [Information Gathering & Analysis](/installation/installation-1/information-gathering-and-analysis)

## Planning

After the vision for your SanteDB deployment project has been established, and relevant stakeholders are on board, it is time to begin the planning phase of the SanteDB/SanteMPI solution. Depending on how the target context's project management office operates, the process may differ.&#x20;

See: [Planning & Preparation Work](/installation/installation-1/planning-and-preparation-work)

## Development / Integration

Once the project boundaries and overall planning/architecture work has been performed, the task of customizing SanteDB can commence.&#x20;

See: [Developers](/developers/extending-santesuite)

## Deployment

The deployment phase of SanteDB involves the installation, configuration, validation and testing of the environment.

See: [Deployment](/installation/installation-1/deployment) for detailed information about deploying SanteDB software.

## Rollout

The rollout phase of SanteDB involves the actual onboarding of users and using the solution in an operational context.&#x20;

See: [Rollout](/installation/installation-1/rollout) for more information about activities related to rollout of the SanteDB solution.


# Information Gathering & Analysis

The first step to deploying SanteDB solutions is to gather information about problem domain and jurisdiction in which the solution will be deployed.&#x20;

## Identify Stakeholders

Identify the people and organizations within the implementation context. Stakeholders include:

1. Relevant department(s) of the organization
2. Vendors of existing software solutions within the context
3. Subject matter experts for the problem domain, relevant standards and SanteDB products
4. Owners / Operators of health solutions (such as funders, NGOs, hospitals, etc.)

## Establish a Vision

Identify the reason why SanteDB or a SanteDB solution is needed in the context, and what clinical problem is being solved. It is helpful to indicate:

1. What problems are being solved?
2. Why do we need to solve them?
3. What are the timelines in which a solution should/needs to be found?
4. What are the [Solution Architecture](/santedb/deployment-models) which apply to the project?

It is useful to prepare a vision statement for the overall deployment of SanteDB project. This vision statement is a short (1 - 2 sentences) statement which encapsulates the project and can be referenced as a guiding raison d'être as the project progresses.&#x20;

An example for Demoland might be:

> The National Client Registry (NCR) will facilitate the implementation of our National Health Identifier Programme (NHIP). NHIP is a keystone to supporting better care through health information exchange throughout Demoland.   &#x20;

### Establish a Team

Identify a team of people who will be responsible for the process of operationalizing SanteDB in the context. The team which is identified/established ad their roles/responsibilities on the team will be highly variable (based on project).

SanteDB has had some success using the RACI methodology (<https://en.wikipedia.org/wiki/Responsibility_assignment_matrix>) which identifies team members who are:

* **R**esponsible - Completes the tasks or work described&#x20;
* **A**ccountable - Answerable to the project owner/sponsor for the accurate and thorough delivery of the work
* **C**onsulted - Subject matter experts or other persons/groups whose opinions are sought
* **I**nformed - Receives updates on progress (typically one way communication)

RACI charts are often defined using deliverables/tasks as rows and an organizational chart as columns. This makes it easy for project team members to know what their obligations are for each phase of the project delivery.

{% hint style="info" %}
The SanteSuite community cannot provide concrete RACI templates since they are highly variable based on roles of team members. However, we have provided a minimal template which may be of use to implementing partners.
{% endhint %}

{% file src="/files/wmsGjrvWyrbtnOq5tfyX" %}

### Team Makeup & Roles

The explicit makeup of a SanteDB deployment team will vary, however the community has prepared a list of logical "roles" which should be filled (these may be filled by the same person with the required skills) throughout the project lifecycle.

| Role                     | Responsibilities                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Project Sponsor / Owner  | <ul><li>Makes final decisions for project</li><li>Provides local/business context and conveys needs</li><li>Liaises with Ministry of Health and other administrators</li><li>Promotes the project to peers</li><li>Obtains approvals and commitments to plans. </li></ul>                                                                                                                                                                                                                                                                                                                                                                                                   |
| Project Management       | <ul><li>Planning and Coordination of Tasks</li><li>Shepherding other team members</li><li>Gathering status updates</li><li>Liaise with project sponsors/owner </li></ul>                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| Business Analyst         | <ul><li>Liaising with in-country vendors / suppliers</li><li>Documenting current workflows/data</li><li>Performing assessments and documenting requirements.</li><li>Producing the Business Requirements Document</li></ul>                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| Legal Counsel            | <ul><li>Provides guidance existing legislation and policies</li><li>Writes / Performs Privacy Impact Assessments against integration partners</li><li>Creates policy documents and governance procedures.</li><li>Reviews/ensures compliance of delivered environment against local legislation.</li></ul>                                                                                                                                                                                                                                                                                                                                                                  |
| Administrative Assistant | <ul><li>Scheduling team meetings and events</li><li>Coordinates schedules of other team members</li><li>Produces meeting notes and records decisions.</li></ul>                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| User Champion            | <ul><li>Represents the users of the system (clinicians for integrated systems)</li><li>Provides insights into on-the-ground practice and workflows</li><li>Promotes the project to clinical staff and other users</li><li>Supports users through deployment and use.</li><li>Reviews development activities and training materials for appropriateness.</li></ul>                                                                                                                                                                                                                                                                                                           |
| Enterprise Architect     | <ul><li>Follows established processes (CMMI, TOGAF, etc.) to produce overall architecture.</li><li><a data-mention href="/pages/vwvb42ANNVSWLn7OvFrJ">/pages/vwvb42ANNVSWLn7OvFrJ</a> including use cases, system interactions, business processes, etc.</li><li> <a data-mention href="/pages/GxueEip8KPJEPbXuXvJP">/pages/GxueEip8KPJEPbXuXvJP</a>including appropriate structural and content standards, minimum data sets, identification schemes, etc.</li><li>Liaise with other team members to validate architecture is being followed through duration of project.</li><li>Validate the deployed/operationalized system matches documented architecture. </li></ul> |
| Solutions Architect      | <ul><li>Designs software architecture for extensions to the SanteDB solution.</li><li>Designs software architecture for local systems to integrate with the national (or regional) SanteDB systems.</li><li>Liaises with Security, Network and Database personnel to <a data-mention href="/pages/GWAgWdH7wKqCI3BNWdEA">/pages/GWAgWdH7wKqCI3BNWdEA</a></li></ul>                                                                                                                                                                                                                                                                                                           |
| Developer                | <ul><li>Performs code enhancements to SanteDB software (see: <a data-mention href="/pages/f6VyCdlPlATqED8DQK7G">/pages/f6VyCdlPlATqED8DQK7G</a>)</li><li>Works with user champions to gather feedback on changed user-facing elements.</li><li>Writes tests and validates software modifications are non-breaking.</li></ul>                                                                                                                                                                                                                                                                                                                                                |
| Technical Writer         | <ul><li>Create user-facing documentation for new screens.</li><li>Adapt / Create standard operating procedures to local context</li><li>Create training materials (documents, cheat sheets, job aides, videos, etc.) to support local users.</li><li>Validates training materials with other team members.</li></ul>                                                                                                                                                                                                                                                                                                                                                        |
| Localization Specialists | <ul><li>Uses the <a data-mention href="/pages/-Lx5_RARCi5WkUpv8jzA#mozilla-pontoon">/pages/-Lx5\_RARCi5WkUpv8jzA#mozilla-pontoon</a> service to translate SanteDB to local language if needed.</li><li>Adapts/designs the user interface to match cultural references/norms (iconography, layout, etc.)</li></ul>                                                                                                                                                                                                                                                                                                                                                           |
| Security Analyst         | <ul><li>Creates and performs the Threat Risk Assessment </li><li>Liaises with the Solution Architect in  <a data-mention href="/pages/GWAgWdH7wKqCI3BNWdEA">/pages/GWAgWdH7wKqCI3BNWdEA</a></li><li>Validates the production environment after deployment</li><li>Designs the users/groups/application policy environment (permissions, data policies, etc.)</li><li>Performs routine penetration testing against the production environment</li><li>Manages/Maintains security access to physical and/or virtual infrastructure. </li></ul>                                                                                                                                |
| Network Administrator    | <ul><li>Installs and configures physical hardware including servers, storage arrays, switches, routers.</li><li>Configures network firewalls and appropriate software firewalls.</li><li>Installs and patches bare-metal and virtual operating environments (POSE and VOSE)</li><li>Installs monitoring infrastructure (SIEM and APM)</li><li>Documents and configures server backup and recovery procedures.</li></ul>                                                                                                                                                                                                                                                     |
| Database Administrator   | <ul><li>Installs and configures the SanteDB database environment.</li><li>Monitors and modifies database software settings to tune operational environment.</li><li>Documents and configures database backup and recovery procedures.</li><li>Modifies and monitors ETL, reports, and BI components.</li></ul>                                                                                                                                                                                                                                                                                                                                                              |
| User Success Associate   | <ul><li>Monitors the helpdesk and ticketing software for issues.</li><li>Provides front-line support to end-users, administrators, and monitors tickets through the lifecycle.</li><li>Populates the local deployment knowledgebase to reduce future reliance on helpdesk services.</li><li>Promotes / escalates front-line help tickets to appropriate resources</li><li>Handles onsite support issues such as basic networking and hardware issues in clinic.</li></ul>                                                                                                                                                                                                   |

## Perform Environmental Scan

Engage with relevant stakeholders to perform an environmental scan of the current environment in which the SanteDB system is being deployed. It is important to observe/collect:

1. &#x20;Which systems are being used in the context?
2. What types of data do those systems collect?
3. What are the processes used by those systems and their users?
4. What are the operational difficulties that are being encountered? (lack of data, timeliness of access, etc.)
5. How are users authenticated or identified?&#x20;
6. What non-technical (business) processes are enforced?&#x20;
7. Perform Policy / Legislative Scan - Identify, collect, and document the relevant legal statutes, policies, laws, culture norms, etc. which may impact the project.&#x20;

### Unique Health Identifier Assessment Toolkit

The Asian Development Bank (ADB) has prepared a useful unique health identifier assessment toolkit which may be of use in performing an environmental scan of the current identities and policy frameworks in your jurisdiction.

See: [Unique Health Identifier Assessment Toolkit from ADB](https://www.adb.org/documents/unique-health-identifier-assessment-toolkit)


# Planning & Preparation Work

A SanteDB deployment is not like installing Microsoft Office, or a video game. SanteDB is responsible for storing very sensitive personal health information (PHI) and the deployment of SanteDB in any role (MPI, MFR, MPR, SHR, etc.) warrants careful planning and consideration.&#x20;

{% hint style="info" %}
It is recommended that you reach out the SanteSuite community prior to performing a deployment of any SanteSuite product. Our partners can assist with planning and deployment services.
{% endhint %}

This section will guide your through some of the common planning activities that should be undertaken prior to deploying any of the SanteDB solutions/components in your environment. &#x20;

## Contents

{% content-ref url="/pages/vwvb42ANNVSWLn7OvFrJ" %}
[Develop a Business Architecture](/installation/installation-1/planning-and-preparation-work/develop-a-business-architecture)
{% endcontent-ref %}

{% content-ref url="/pages/GxueEip8KPJEPbXuXvJP" %}
[Develop an Information Architecture](/installation/installation-1/planning-and-preparation-work/develop-an-information-architecture)
{% endcontent-ref %}

{% content-ref url="/pages/GWAgWdH7wKqCI3BNWdEA" %}
[Develop Operational Technology Architecture](/installation/installation-1/planning-and-preparation-work/develop-operational-technology-architecture)
{% endcontent-ref %}


# Pre-flight Checklist

This page provides a convenient pre-flight checklist to ensure that you have sufficient assets in place to proceed with planning your deployment of a SanteDB solution.&#x20;

* [ ] [Project Vision Statement Established](/installation/installation-1/information-gathering-and-analysis#establish-a-vision)
* [ ] [Project Team Established and Responsibilities Assigned](/installation/installation-1/information-gathering-and-analysis#establish-a-team)
* [ ] Consensus and Commitment Obtained relevant stakeholders
  * [ ] Leadership (Ministry of Health, Hospital Administrators, etc.)
  * [ ] Implementation Partners (NGOs, Vendors, etc.)
  * [ ] End-User Groups
* [ ] [Current State Analysis / Environment Scan Complete](/installation/installation-1/information-gathering-and-analysis#perform-environmental-scan)
  * [ ] Understand which systems collect patient identity
  * [ ] Understand/Document workflows or business processes in use&#x20;


# Develop a Business Architecture

SanteDB, SanteIMS and SanteMPI are interoperable software solutions for managing clinical data. While a software solution is a means to implement business use cases, it is not the end in itself. Typically the software implements or realizes business processes.&#x20;

It is important, therefore, to develop a business architecture which describes the human and organizational architecture. This includes:

* Documenting new business processes to be used in clinic among the various connected systems.
* Document data capture standards, and agreement between organizations on the format and use of each data element (establish a common understanding of data elements from a business use).
* Formalize inter-departmental or inter-organization processes for sharing, accessing, and disclosing data stored in the common SanteDB infrastructure.&#x20;

{% hint style="info" %}
Implementers of SanteDB, SanteMPI or SanteIMS are encouraged to follow practices established by their own project management office (PMO) and local country patterns. This article serves as general guidance to the contents/structure of the business level architecture.
{% endhint %}

## Developing User Journeys

User stories are a great tool for describing how users interact with each system and how each system interacts with each other. User journeys may be documented using BPMN activity diagrams or using a user journey map.

Regardless of the format, the user journey should:

* Identify the major steps of the business process being performed.
* Identify the goals of the user and the system (what is the user and/or system trying to accomplish?)&#x20;
* Identify the humans involved (or organizations, departments, ministries, etc.)
* Identify the systems involved&#x20;
* Illustrate how the humans interact with the systems, and how humans and systems interact with one another.&#x20;

For example, consider the user journey to issue a new national health identifier to patient for Demoland.&#x20;

![](/files/LfsYuMc1R31JYiz3mnWl)


# Develop an Information Architecture

SanteDB is designed to have a common [Conceptual Information Model](/santedb/data-and-information-architecture/conceptual-data-model). Because of this, it is important that any jurisdiction adapt this model for their local context, and establish a common understanding of the information which will be captured, shared, and stored in the SanteDB instance.&#x20;

* Develop a minimum dataset for data elements in the CDR, establish common use and definitions, common mappings within the context (i.e. what constitutes a "valid" patient record?)&#x20;
* Identify the identity which can be used in the CDR instance (how are patients identified? how are immunizations identified? etc.) this includes:
  * What are the medical (MRNs, insurance, etc.) and non-medical identification (drivers licenses, citizen identifiers, etc.)
  * Which organizations have the authority to assign/change these identifiers?
  * What are the validation criteria, patterns, expiration, and versioning policies for each?
* Identify standards to be used. It is useful to declare "use FHIR" , however this may not be the best option given the current state of systems. Consider:
  * What information standards are currently used by existing systems?
  * What data elements are easily available in each standard?
* Identify secondary use and indicators for the software. Understand how the data may be aggregated, reported, shared, or compared over time and plan to implement these as reports or measures.

## Contents

{% content-ref url="/pages/ESVJJWYPq1rLhbE1rOGf" %}
[Establishing Minimum Datasets](/installation/installation-1/planning-and-preparation-work/develop-an-information-architecture/establishing-minimum-datasets)
{% endcontent-ref %}

{% content-ref url="/pages/ndnrU5Kfz3HI12lSnSlj" %}
[Developing Privacy Impact Assessments](/installation/installation-1/planning-and-preparation-work/developing-privacy-impact-assessments)
{% endcontent-ref %}

{% content-ref url="/pages/-M7Ak1ChW6NLwl8pzZZE" %}
[Identity Environment](/installation/installation-1/planning-and-preparation-work/develop-an-information-architecture/configuring-identity-domains)
{% endcontent-ref %}


# Establishing Minimum Datasets

## Resources

The SanteDB team has provided a template which lists all the data elements captured in SanteDB for Patients, Places, Organizations, and Persons.&#x20;

{% file src="/files/eJzS3VTz0rVtN0iPfhIn" %}

To complete this worksheet:

1. Review the readme for the meaning of each column and type of data which should be present.
2. For each data element in the provided SanteDB information model, review:
   1. The commonality of the data element in your context (how often is it captured? is it useful information to be captured? If asked, would a patient know the information? etc.)
   2. Relevant legislation in the context (is it illegal to capture? if not are there any protections which need to be in place?)
   3. The sensitivity of the information (if we ask patients for this information will they lie? will they offer the information?)
   4. Mapping to local semantics (is the data known as a different name? is there a mapping of semantics?). For example, many implementing jurisdictions may need to map the address hierarchy to match their country context, or some countries may not use family names, etc.&#x20;
3. Document the context specific use of each field.

Once complete, the information on this worksheet will make its way into formal specifications (such as IHE ITI TF Volume 4 content, FHIR implementation guides, etc.). This process is not covered on the community wiki.

### Demoland Example Dataset Worksheet

The SanteDB team has provided a completed worksheet which illustrates the minimum dataset and mappings for Demoland. Changes from the template are highlighted in green.

{% file src="/files/1gFlP0H5OnFzyFsskBoQ" %}


# Identity Environment

The primary duty of a centralized CDR (and more specifically an MPI) is to maintain records from various sources of information. Identity of that information (patient identity, place identity, event identity, etc.) within a health enterprise (a hospital, province or state, country, etc.) is of paramount importance.&#x20;

Furthermore, the governing of those identities should also be considered. For example:

* Your Immunization System shouldn't be the source of truth for LTC programme identifiers (correct issuing authority)
* You may not want to disclose mental health identifiers to a community outreach application (correct disclosure)
* You don't want facility associated identifiers being mistakenly assigned to patients  (correct usage)

## Surveying Identity

It is important in any SanteDB deployment (especially for SanteMPI) to perform a survey of identifiers which are used in the context in which the solution will be deployed.&#x20;

Implementers should note:

* The types of medical and non-medical identifiers which are currently in use.
* Which organizations are responsible for the maintenance and issuing of the identifier.
* The lifecycle of the identifier (i.e. how is a new identifier issued, are the holders authenticated, etc.)
* The format and requirements of the identifier (are there check digits, if so what are they?)
* The use of the identifier (billing, identification, tagging, etc.)
* The scope of the identifier (what type of objects carry this identifier? Patients, vials, boxes etc.)
* Commonality of the identifier
  * What proportion of the population carries this identifier?&#x20;
  * Is it normal for the identifier to be readily available?
  * Is it culturally acceptable (or legally acceptable) to use this identifier? (for example: disclosure of Social Security Number to a pharmacist)

## Operationalizing Identity Domains

SanteDB (and by extension SanteMPI) supports a variety of standards, each of which use different labels to identify an identity domain. For example, in FHIR an identity may appear as:

```markup
<identifier> 
    <use value="usual"/> 
    <type> 
      <coding> 
        <system value="http://terminology.hl7.org/CodeSystem/v2-0203"/> 
        <code value="MR"/> 
      </coding> 
    </type> 
    <system value="http://emrs.elbonia.elb/programme/hiv"/> 
    <value value="123457"/> 
  </identifier> 
```

Whereas that same identifier in an HL7v2 message would appear as:

```markup
123457^^^MOHS_EMR_HIV&&ISO^^P
```

Or in HL7v3 the identifier may appear as:

```markup
<id authority="1.2.3.4.5.6.7.8.9" value="123457" />
```

To properly ensure cross referencing between each of these interfaces, SanteDB will need to know the URL (used primarily in FHIR), the namespce ID (used primarily in HL7v2) and the OID/Universal ID (used primarily in HL7v3).

Since these all need to be unique, it is a good practice that your scheme for these values encompass the entity which owns the identifier, the programme area or department, and the system. For example, if the Ministry of Health runs an infectious disease programme in which an HIV EMR is used, a good Namespace ID for the MRN form that system may be: **MOH\_ID\_HIV\_EMR\_MRN**&#x20;

## Resources

An identity domain worksheet has been created and shared below. This worksheet contains instructions and example data which should assist implementers in the organization of their identity domain planning work.

{% file src="/files/WcyGmrDcyH6RwVVupbcs" %}

To use the spreadsheet:

1. Enumerate the issuing organizations in the implementation context (organizations, ministries, etc.) and complete the **Issuing Authority** sheet.
2. Enumerate each of the identification domains which are used in the context to which SanteDB or SanteMPI will be deployed.
3. Update the cover sheet of your worksheet with relevant metadata about the sheet.

###


# Develop Operational Technology Architecture

An operational technology architecture differs slightly from a software requirements specification or functional design specification for software. The operational technology architecture is primarily concerned with the operational environment in which SanteDB services will be running.

## Writing your Operational Architecture Document

The documentation prepared for the operational architecture should aim to:

* Provide a high-level summary of how users interact with the system, and the purpose of the system (this is helpful for network and server operators to understand what types of operational issues may arise)
* Document the physical architecture of the servers, virtual machines, networks, etc. of the operational deployment
* Describe the disaster recovery options, backup requirements, and security environment (remote access requirements, etc.)
* Enumerate the IP addresses, host names, and network infrastructure of where components of the SanteDB software is operating
* Describe the business continuity plans&#x20;
* Describe how the SanteDB infrastructure interfaces with other local systems (peer network addresses, data formats, type of data, etc.)
* Describe specific data configurations, concept sets, extensions, locations, etc. found in the country deployment
* Document SanteDB server configuration settings.

### Summarize Software Environment

The operational architecture documentation should summarize the software environment in which the SanteDB server is being operationalized (in the example document, note the summarization of the software components).&#x20;

The operational documentation should keep discussion of software components and business processes to a brief overview (the majority of your software modifications and flows should be captured in a FDS).&#x20;

Consider, for example, the software architecture for the Demoland example. <br>

![Demoland Operational System Architecture](/files/BrSIgCttjRGnUhthnUdk)

You will note that the software summary is concerned about the overall deployment of the software components onto various server infrastructure, and illustrating how data is shared and flows between these components.

The operational architecture of your SanteDB deployment will be highly variable, based on the intended goals and current ground truth (availability of internet, local system capabilities, clinics, workflows, etc.)&#x20;

### Describe the Physical Environment

The operational architecture should describe the operational environment on which the SanteDB software solution will be running. Regardless if the system is hosted in an on-premise data centre, as a managed service, in cloud or as Software-as-a-Service (SaaS), system administrators will still require detailed descriptions of the physical environment in order to manage the system.&#x20;

The system description should include a server deployment diagram (see below for an example), or if using cloud services, how those services are deployed. If the solution is deployed in clinics with special software or hardware, those deployments should also be documented. The goal is the clearly illustrate how the software is deployed so the operators can maintain the system.

![Demoland Production Server Environment](/files/ZvZggmrw1SVfKNluNiLN)

Additionally, any hardware specifications or network specifications should be clearly enumerated in the operational documentation. This includes:

* The brand name of any equipment being used (example: Lenovo ThinkServer ST550) - this helps maintainers understand how to get support for the hardware.
* The configuration of the equipment including any options which were configured (example: 2x Intel Xeon Silver 4220 , 128 GB RAM, 1 PCIe nVME Boot Drive, 2x GBe NIC, etc.). This helps maintainers understand the scope and size of the deployment, as well as providing a concrete list of parts which can (or need) to be reordered in case of failure.
* The software environment of the physical equipment such as any operating systems, Security Information and Event Management (SIEM) or Application Performance Management (APM) software, antivirus configuration, etc. This helps maintainers understand the third party software in use in the operational deployment.

{% hint style="info" %}
SanteSuite documentation examples refer to POSE and VOSE, which is the Microsoft Licensing nomenclature for Physical Operating System Environment and Virtual Operating System Environment respectively.&#x20;
{% endhint %}

#### Sizing a Server Environment

The sizing of your physical environment will depend heavily on a variety of factors such as the type of use of the SanteDB product, whether offline mode is leveraged, how many users and systems are connecting to the system, etc.

As a general rule, when deploying SanteDB on a physical environment the iCDR components can be computed as:

| Component             | SIzing                                 | Example                                                            |
| --------------------- | -------------------------------------- | ------------------------------------------------------------------ |
| iCDR Server CPU       | $$n\_{vcpu} = \frac{n\_{clients}}{4}$$ | 20 concurrent clients = 5 VCPU minimum                             |
| iCDR Server RAM       | 4GB - 8GB                              |                                                                    |
| PostgreSQL Server CPU | $$n\_{vcpu} = icdr\_{vcpu}\* 2$$       | 5 VCPU on iCDR = 10 VCPU                                           |
| PostgreSQL RAM        | $$n\_{ram}=n\_{vcpu} \* 512{MB}$$      | 10 VCPU = 5 GB RAM minimum (more is better to tune `max_work_mem`) |
| PostgreSQL Disk       | As fast as possible                    |                                                                    |

Additional hints for sizing a physical environment:

* Buy two of everything instead of one physical server, buy two smaller ones - this is beneficial because:
  * It provides load balancing opportunities
  * It provides a failover environment when the hardware fails
* Always purchase SSD or NVMe based storage for your database servers (as opposed to spinning/spindle disk types)
* Always run your storage in a redundant mode (i.e. run in RAID1, RAID1+0, RAID5+0 or RAID6)
* Where possible use PostgreSQL streaming replication on the primary CDR database to balance queries and writes
* Where possible use a Storage Area Network with the highest possible Input/Output Operations (IOPS) ratings for throughput
  * If using a SAN ensure the storage network is on a different NIC than other network traffic
  * A SAN allows hypervisors to move Virtual Machines (VMs) between hosts to balance load or to provide rapid failover (using technologies such as VMotion)
* Always buy spare parts (disks, RAM, network cards, etc.) matching the configuration of the hardware in the original equipment (this provides quick replacement for failed hardware)

### Describe the Network Environment

Your operational documentation should describe the networking environment used in the deployment. This includes:

* IP addresses and host names of each POSE and VOSE in use in your deployment
* All ports which are opened on the operating system firewalls (if any) including their port number, protocol and type of data flowing through the port (including if they are secured or not)
* How load balancers, SSL termination, or application firewalls are to be configured to handle traffic (example: external host `https://mpi.gov.demoland.com:8443` is routed to `http://mpi-prod:8080`) Tip: offloading encryption to a dedicated endpoint can free application server resources -- for more information see <https://www.nginx.com/blog/nginx-ssl/>&#x20;
* Any remote access ports which are opened for system administration. This could include SSH access points, Microsoft Remote Desktop, VNC, or even VPN settings which will be used to access the console or host operating systems.

### Describe Service Availability Requirements

SanteDB often acts as an integration point for many different systems and often plays vital roles in a health system. What happens, however, when that infrastructure is not available?

It is fact of life that servers fail, networks are unreachable, or other any other combination of issues can arise. The operational architecture should at least identify how this will impact business users. For each component in your deployment, the availability section should describe:

* The observed impact of an outage of the particular component (for example: how does the system behave when the database server is offline?)
* Mitigations that can be taken to prevent or recover from the outage condition
* Descriptions of what the business impact of a component being absent would have on users (example: If the one of the SanteMPI host servers is unavailable, what impact would it have on users? What options are there to continue doing business?)

### Describe Service Contacts and Responsibilities

Large deployments often involve a large number of staff, companies, agencies and ministries. It is important that a clear set of responsibilities be established for each. This is important as it allows readers of the operational architecture to understand:

* Which partner in the deployment is responsible for which maintenance or corrective activities?
* What are the hours of operation (or expected availability) of each partner?
* What are the escalation procedures and tiers for supporting the deployment?

In general, we recommend using information technology service management frameworks and best practices published by organizations such as ITIL, ITSM and COBIT to establish a Service Desk process and supporting tools for the ongoing support of the end-users of your solution.  &#x20;

### Describe Business Continuity Procedures

When an issue is detected that impacts business users, they will often need to continue doing their work (even though the software is unavailable). Your operational architecture document should include a business continuity plan. The continuity plan should identify:

* What should users do when the system is unavailable? (use a paper based process? replace devices? change sites to a backup installation? etc.)
* How should users report their issues when they experience an outage? (Is there a helpdesk? A bug tracker? A support line to call? etc.)
* What are the RPO, RTO and MTO values for the deployment? (see below)
* What are the procedures (for each component) to recover from a failure condition?

#### RPO, RTO and MTO

* Recovery Time Objective (RTO) – The maximum amount of time that could be tolerated between unexpected failure and the resumption of normal service. (i.e. How long can clinics operate without the system?). RTO dictates the goal for recovering the service operation.
* Recovery Point Objective (RPO) – The maximum period of time which data might be lost if service unexpectedly fails. (i.e. How far back can you fail without being a catastrophic loss to business?). RPO usually informs the frequency of your backups and impacts the cost of your backup infrastructure.
* Maximum Tolerable Outage (MTO) – The maximum amount of time that the business can tolerate complete outage of the system during normal business days before it becomes impossible to continue doing work.

### Describe Update Procedures

Software is a living product and evolves over time and it is important to ensure that operating systems, clinical systems, antivirus software, firewalls, etc. are regularly updated to ensure that the latest security and features are present in the environment.

Typically, updates require organizational planning to ensure that maintenance windows do not overlap with business operations, and that any special processes (like backups, snapshots, service stop/start, upgrades, etc.) are done in a particular order.

The operational architecture should describe all of these impacts on the environment, as well as any special procedures that must be followed. For example:

> Prior to updating the SanteDB dCDR software in clinics, ensure:
>
> * Any OpenMRS servers are shut down and users logged out.
> * The SanteDB dCDR synchronization center indicates no conflicts and no remaining upload data (in the outbox)
> * The backup job is run to produce a recent copy of data in the dCDR
>
> &#x20;

### Describe the Security Environment

Your operational architecture document should describe the security environment which is being used in your deployment. This should include:

* How are new devices or applications integrated into the SanteDB infrastructure? What approvals are required and/or sign offs?
* How are new users added to the SanteDB infrastructure? What groups are they assigned to? What access controls do they have over the solution and hardware?
* What firewalls are in place and/or configured?
* How is data encrypted in transit between systems and at rest, including via intermediaries? (example: How are the HL7v2 messages encrypted between a Hospital Information System and the SanteDB iCDR?)
* How are systems and users authenticated? What are the policies in the deployment for password and account expiration?
* What are the custom policies applied or configured in the operational environment?

## Resources

The SanteDB team has prepared a template which may be helpful for organizing your Operational Architecture. The document contains instructions and a limited example of content for Demoland to get writers started in authoring operational architectures.&#x20;

As always, please refer to the [Disclaimer](/readme/disclaimer).&#x20;

{% file src="/files/A6xvFXtDUc18ixv7UU3t" %}


# Developing Privacy Impact Assessments

A Privacy Impact Assessment (PIA) is a risk management process that helps institutions ensure they meet regulatory requirements and identify the risks and potential impacts their programs and activities will have on an individuals’ privacy.

Conducting a PIA is a means of helping to ensure compliance with any legal requirements set out in jurisdictional legislation, and the requirements of any organizational policies and directives. Adhering to the requirements will reduce the risk of improper or unauthorized collection, use, disclosure, retention or disposal of personal information.

While programs and activities must comply with legal and policy requirements, they should also be designed to incorporate best practices and to minimize negative impacts on the privacy of individuals. For example, you should work to reduce the risk that an individual may suffer harm, such as identity theft, reputational damage, physical harm or distress, as a result of your program’s handling of their personal information. A PIA may not eliminate such risks altogether, but should help to identify and manage them.

PIAs allow institutions to identify and mitigate risks as early and as completely as possible. They are a key tool for decision-makers, enabling them to deal with issues internally and proactively rather than waiting for complaints, external intervention or bad press.

Each jurisdiction will have a unique privacy landscape and may have specific requirements for PIAs, but we have provided a sample PIA guide and template here that should at least help to start the privacy conversation in your project.

As always, before making use of any of our resources, please read and accept our disclaimer:

{% content-ref url="/pages/yISHK295LBHaSE2ldAob" %}
[Disclaimer](/readme/disclaimer)
{% endcontent-ref %}

{% file src="/files/5ZxenwkqVVneWHhS7q0n" %}
Privacy Impact Assessment Template
{% endfile %}

{% file src="/files/SnmLLvfM8A9aWunG2Cv1" %}
Privacy Impact Assessment Guide
{% endfile %}


# Develop Threat / Risk Assessments

Security Threat and Risk Assessment What are Security Threat and Risk Assessments (TRAs)?

A Threat Risk Assessment (TRA) is the overall activity of assessing and reporting security risks for an information system to help make well informed risk-based decisions. A TRA also documents risk ratings and planned treatments of the risks.

Each risk assessed must consider the likelihood to which a threat may leverage a weakness, the potential impact, and an acknowledgement of what this could mean to the organization. The criticality of an information system and security classification of information stored and handled by the system should be reviewed and considered when conducting a TRA. For each risk that is identified, a planned treatment or acceptance must be documented. Risk findings from the TRA activity should be communicated to the appropriate project sponsors and stakeholders.

TRAs should be completed for new or significantly modified information systems and during planning, development and implementation of an information system. A review and updated TRA should be conducted throughout the life of an existing information system for any significant or material change(s) and must also consider any previously identified risks. For critical systems, a review schedule should also be maintained to ensure that TRAs are periodically conducted throughout the life of an information system.

Each jurisdiction will have a unique security threat landscape and may have specific requirements for TRAs, but we have provided a sample TRA template here that should at least help to start the security conversation in your project.

As always, before making use of any of our resources, please read and accept our disclaimer:

{% content-ref url="/pages/yISHK295LBHaSE2ldAob" %}
[Disclaimer](/readme/disclaimer)
{% endcontent-ref %}

{% file src="/files/H1YekYDD8DNI8rVVodK8" %}
Threat Risk Assessment&#x20;
{% endfile %}


# Deployment

Deployment of SanteDB onto any infrastructure will first involve the the setup of underlying infrastructure assets. SanteDB can run on:

* Modern Linux Distributions (installer is written for Ubuntu)
* Docker Containers
* Microsoft Windows Operating Systems
* Android

These installation procedures assume that readers are familiar with the mechanics of their operational environment of choice such as:

* Installation and Removal of Software
* Use of the command line
* Comfort editing configuration files (XML and JSON)

## Topics

{% content-ref url="/spaces/-LZ0\_pjgTp\_kx4hqTZ3a/pages/2TlhHfF0UAu2t4jRv065" %}
[Pre-Flight Checklist](/installation/installation-1/deployment/pre-flight-checklist)
{% endcontent-ref %}

{% content-ref url="/spaces/-LZ0\_pjgTp\_kx4hqTZ3a/pages/knChbhxliIhn3CVUrl5i" %}
[Installing Software](/installation/installation-1/deployment/installing-software)
{% endcontent-ref %}

{% content-ref url="/spaces/-LZ0\_pjgTp\_kx4hqTZ3a/pages/ml3MT6vqft6sAGXrTPvG" %}
[Post Deployment Tuning](/installation/installation-1/deployment/production-installation-notes)
{% endcontent-ref %}

{% content-ref url="/spaces/-LZ0\_pjgTp\_kx4hqTZ3a/pages/c0UjabWQ0jDT6zqo71bg" %}
[Broken mention](broken://spaces/-LZ0_pjgTp_kx4hqTZ3a/pages/c0UjabWQ0jDT6zqo71bg)
{% endcontent-ref %}

{% content-ref url="/spaces/-LZ0\_pjgTp\_kx4hqTZ3a/pages/n60WauAMGNvim8P6eIPx" %}
[Securing SanteDB APIs](/installation/installation-1/deployment/securing-the-apis)
{% endcontent-ref %}


# Pre-Flight Checklist

* [ ] [Business Architecture Developed](/installation/installation-1/planning-and-preparation-work/develop-a-business-architecture)
  * [ ] Use Cases understood and documented
  * [ ] Requirements documented ("what is success?")
  * [ ] New Processes Mapped
  * [ ] Document Sign-Off Obtained
* [ ] [Information Architecture / Profiles Developed](/installation/installation-1/planning-and-preparation-work/develop-an-information-architecture)
  * [ ] [Data Dictionary / Minimum Dataset based on local policy/environments documented](/installation/installation-1/planning-and-preparation-work/develop-an-information-architecture/establishing-minimum-datasets)
  * [ ] [Identity Environment / Sources Documented](/installation/installation-1/planning-and-preparation-work/develop-an-information-architecture/configuring-identity-domains)
  * [ ] Document Sign-Off Obtained
* [ ] [Operational Architecture / Plan Documented](/installation/installation-1/planning-and-preparation-work/develop-operational-technology-architecture)
  * [ ] Document Sign-Off Obtained
* [ ] Protection of Patient Information Documented
  * [ ] [Privacy Impact Assessment Drafted](/installation/installation-1/planning-and-preparation-work/developing-privacy-impact-assessments) / Reviewed
  * [ ] [Threat / Risk Assessment Drafted / Reviewed](/installation/installation-1/planning-and-preparation-work/develop-threat-risk-assessments)
* [ ] [Modifications to SanteDB Developed and Tested](/developers/extending-santesuite)
* [ ] Deployment Pre-Requisites Procured
  * [ ] Physical, Virtual or Cloud Resources Purchased and Installed
  * [ ] Operating Systems Installed and up to date
  * [ ] Antivirus Software Installed and up to date
  * [ ] Monitoring Software (SIEM or APM) Installed and up to date
  * [ ] Responsible Persons, Initial User Lists, etc. Available
  * [ ] Backup Infrastructure Available and configured
  * [ ] Security Certificates (SSL), Domain Name Registrations, and IP addresses obtained
  * [ ] Network packages / bandwidth obtained
  * [ ] Third party integration services credentials obtained (i.e. network operator services, external registries, e-mail or SMS services, etc.)&#x20;


# Installing Software

SanteDB software packages support many different environments and use cases. The underlying software is attempting to provide a common structure into which data/processes can be realized. Because of this there are two different distributions of SanteDB software, which can be installed in an operational environment.

## iCDR - Integrated CDR

The iCDR is typically installed once per application role in a jurisdiction. (See:[SanteDB Architecture](/santedb/architecture#icdr-server)).&#x20;

{% content-ref url="/pages/-LZqIYdfYJYaD7MsKNY2" %}
[SanteDB iCDR Server](/installation/installation-1/deployment/installing-software/santedb-server)
{% endcontent-ref %}

## dCDR - Disconnected CDR

The dCDR is installed on the client side or in an aggregate setting as a gateway (or mini CDR). The distribution of the dCDR software and its installation is unique to each platform. This wiki covers the configuration of the dCDR to an iCDR instance.

{% content-ref url="/spaces/-LZ0\_pjgTp\_kx4hqTZ3a/pages/-LyIrhWCH7kYpBZuMLgc" %}
[SanteDB dCDR Instances](/installation/installation-1/deployment/installing-software/disconnected-gateway)
{% endcontent-ref %}


# SanteDB iCDR Server

This page describes the planning stages and various deployment scenarios which SanteDB supports.

Every deployment of SanteDB requires an iCDR Server instance. The iCDR instance is responsible for aggregation and central administration functions. This article covers the installation procedure for the SanteDB iCDR server. The process for installation is common across all SanteDB solutions.

{% hint style="info" %}
If you're deploying SanteDB iCDR in a production environment, or are planning on using SanteDB in a large scale project, please review the [Broken mention](broken://pages/-M9jS2Rkd5xs2XeTCI6i)article.
{% endhint %}

## Table of Contents

* [Installation on Virtual or Physical Environments](/installation/installation-1/deployment/installing-software/santedb-server/installation-on-virtual-or-physical-environments)
  * [Installation on Microsoft Windows](/installation/installation-1/deployment/installing-software/santedb-server/installation-on-virtual-or-physical-environments/installing-a-development-demo-environment)
  * [Installation on Linux and Unix](/installation/installation-1/deployment/installing-software/santedb-server/installation-on-virtual-or-physical-environments/installation-on-linux-and-unix)
* [Installation using Appliances](/installation/installation-1/deployment/installing-software/santedb-server/installation-using-appliances)
  * [Using Docker Containers](/installation/installation-1/deployment/installing-software/santedb-server/installation-using-appliances/docker-containers)
  * [Using Virtual Appliances](/installation/installation-1/deployment/installing-software/santedb-server/installation-using-appliances/virtual-appliances)

## Minimum Requirements

SanteDB Server can be a light process, and requirements for running SanteDB Server will vary depending on your deployment and purpose. At minimum, SanteDB Server requires:

* **Operating System:** Windows Server 2008R2 SP1, Windows 7 SP2, Linux (varies), MacOS 10.9+
* **RAM:** 1 GB RAM minimum (more if using Memory Caching)
* **CPU:** Any (multi-core system recommended)
* **HDD:** 300 MB recommended

### Database Support

SanteDB Server runs on a variety of operating systems and a variety of RDBMS however not all RDBMS modules are available on all platforms.

| OS      | PostgreSQL | FirebirdSQL   |
| ------- | ---------- | ------------- |
| Windows | 9.6+, 10   | 3.0+          |
| MacOS   | 9.6+, 10   | Not Supported |
| Linux   | 9.6+, 10   | Not Supported |

#### PostgreSQL

PostgreSQL 9.6 or 10 are recommended for use with SanteDB, and are the only two versions of PostgreSQL with which SanteDB server is tested. Earlier versions of PostgreSQL may be supported, however some features or unexpected behaviors may occur.

Use PostgreSQL when:

* You are deploying to a training, testing, or production environment
* Your SanteDB server will be accessed by multiple clients
* You require the use of third party reporting, ETL, or query tools
* You need to support or scale out of your application server&#x20;

#### **FirebirdSQL**

FirebirdSQL 3.0 is also supported on Microsoft Windows based machines (it could be supported on Linux with a few modifications). FirebirdSQL provides a fully ACID compliant RDBMS solution while also being embedded within the SanteDB host process. This allows SanteDB Server to run without requiring setup of a third party database server.

Use FirebirdSQL when:

* You are setting up a development or testing server
* You need to easily wipe/backup/restore test datasets (you can copy your FDB file and restart the service)
* You need to setup a demonstration on a lower powered laptop
* You are evaluating a new SanteDB based product and want a quick solution for deployment

### Cache Support

SanteDB supports a caching as a query optimization strategy. The SanteDB cache is used to prevent further retrieval of resources from the database system, which is slower than system memory. In SanteDB there are two solutions for caching.

#### In-Process Memory Cache

The in-process memory cache is the easiest to setup. It requires no additional software services to be running and allows SanteDB Server to store objects in its own memory space.&#x20;

Use in-process memory caching when:

* You are setting up a development or testing server
* You don't want to setup a REDIS environment
* You don't need to scale out your application servers.

#### REDIS Cache

SanteDB Server also supports connecting to the NoSQL database REDIS. SanteDB Server uses REDIS as a cache solution which can be persisted or in-memory only.

Use REDIS caching when:

* You may need to scale out your application servers (i.e. multiple servers accessing the shared REDIS cache)
* You are setting up a production, training or staging environment and don't want a cold-start of the SanteDB server to result in cache misses.

## Security Certificate Notice

SanteDB's iCDR uses code signing in order to verify the identity of publishers of Applets and Plugins. Many community partners use publishing certificates issued by the SanteDB Community Certificate Authority.&#x20;

When you install the iCDR or dCDR the software needs to register these certificates.

* On Microsoft Windows the Configuration Tool registers these certificates into the Local Machine Trusted Authorities store.
* On Linux and MacOS you must manually run `mono SanteDB.exe --install-certs` which will register the certificates into the Mono's Trust Store
* On Docker the registration occurs on service startup
* On Android the certificates are installed into the device Trust Store


# Installation on Virtual or Physical Environments

You can install SanteDB iCDR on Microsoft Windows or Linux / Unix operations on x86 or ARM. The option to install SanteDB iCDR services on a full operating system is well suited for environments where:

* There is a need to finely tune the SanteDB configuration files
* There is a predefined TRA and PIA process which requires hardened / vetted operating system installations.
* There is existing Operating System environments in place, examples include:
  * Existing Application Performance Monitoring software which relies on a specific Operating System
  * Existing authentication/administration infrastructure (such as Active Directory)
  * Existing event log / notification shipping in infrastructure.
* There are requirements for hardware level isolation of the SanteDB services
* There are complex scaling requirements (such as using Windows scaling or clustered file servers)
* The environment's use of Windows only features in SanteDB. Windows only features include:
  * Using Microsoft Message Queue (MSMQ) dispatcher queues
  * Using Microsoft Windows Event Log notifications for central event monitoring
  * Using Microsoft Operation Manager to coordinate update and software package installation.

SanteDB supports  [Installation on Microsoft Windows](/installation/installation-1/deployment/installing-software/santedb-server/installation-on-virtual-or-physical-environments/installing-a-development-demo-environment) and [Installation on Linux and Unix](/installation/installation-1/deployment/installing-software/santedb-server/installation-on-virtual-or-physical-environments/installation-on-linux-and-unix).

## Pre-Requisites

If installing SanteDB iCDR on a native or virtualized operating system environments administrators will need to ensure the following pre-requisites are met:

* An appropriate operating system version is installed, patched and ready for installation of the SanteDB iCDR Application Server.
* An appropriate database environment (primarily PostgreSQL) is installed, patched and can accept connections from the SanteDB iCDR Application Server. &#x20;


# Installation on Microsoft Windows

When installing SanteDB iCDR server on a Microsoft Windows Server environment you should use the installation package for the latest version of the SanteDB iCDR server. Each solution within SanteDB iCDR Server has its own distribution which can be downloaded for their own source repository.&#x20;

* [SanteDB iCDR Releases](https://github.com/santedb/santedb-server/releases)
* [SanteMPI Releases](https://github.com/santedb/santempi/releases)

The installation process for SanteDB on Microsoft Windows is a three step process:

1. [Install the software](#installation)
   * Copy software program files and pre-requisites&#x20;
   * Initiate the configuration process
2. [Configuration of the software](#configuration)
   * Customizing the behavior of the installed plugins
   * Entering implementation specific details about the deployment
3. Running/Initializing the Server

## System Requirements

When running SanteDB iCDR server on Microsoft Windows you will require, at minimum:

* Microsoft Windows Server 2012 Standard or Microsoft Windows 10
* 2 Core CPU (4 to 8 Cores recommended)
* 2 GB RAM (8 or 16 GB of RAM recommended)
* 300 MB of disk space (1 GB recommended)

Users should be familiar with basic Microsoft Windows concepts such as:

* Basic familiarity with the Windows Command Line
* Basic familiarity with Microsoft Management Console (MMC)
* Basic familiarity with Windows Networking

## Installation

The installation programs on Windows will:

* Install the Visual C++ 2010 redistributable (for C++ libraries)
* Install Microsoft .NET Framework 4.8 (if not already installed)
* Copies the required files for the selected options to the Installation&#x20;
* Opens Firewall port 8080 and 2100 (for HL7v2) on the Windows Firewall
* Create an un-installer which will clean the directory on uninstall

The installation process is a standard Windows installer experience, administrators can elect to install particular plugins that meet their needs.&#x20;

![](/files/xhRfbhEIY2lPFOK1gqMJ)

The plugins available at the time of writing are enumerated below.

{% hint style="info" %}
You should reduce the attack surface area of SanteDB iCDR by only installing the plugins which your deployment and use case requires. For example, installing the MDM plugin on an IMS may not make sense in that context - and installation of the MDM plugin would expose new API endpoints over REST which may increase the attack surface area of the iCDR server.
{% endhint %}

#### SanteDB Core

The SanteDB Core option installs the core Windows Service executable (`santedb.exe`), as well as baseline files such as the API libraries, etc.

#### JINT Business Rules Engine

The JINT business rules engine allows applets to customize the iCDR and dCDR application behavior by writing [JavaScript Business Rules](/developers/applets/business-rules#introduction).

#### XML Clinical Support Decision Engine

If your installation of the iCDR will be [using clinical decision support ](/developers/applets/cdss-protocols#introduction)(CDSS) via the built-in XML protocol format, you should enable CDSS support.

#### Messaging Interfaces

The messaging interfaces option installs the core REST APIs for the iCDR server. These messaging interfaces allow administrators to customize their deployment for scale-out by assigning servers to dedicated roles. For example, in a scaled-out solution an administrator may only install the [Administrative Management Interface](/developers/service-apis/administration-management-interface-ami) to the server which controls the cluster, whereas other servers may only install the [Health Data Services Interfaces](/developers/service-apis/health-data-service-interface-hdsi#controlling-response-format) for clinical data access.

#### Business Intelligence Services

When installed, the SanteDB core business intelligence services for rendering and executing reports from applets will be enabled. The BIS should be installed on servers where you'd like the clients to be able to access shared report definitions.&#x20;

If you're using a third party reporting tool like Jasper Reports, Crystal Reports, SQL Server Report Services, etc. you do not need to enable this.

#### Integration Interfaces

Installation of the integration interfaces will allow SanteDB iCDR to interact with third party services using one of the standards based APIs such as:

* [HL7 Fast Health Interoperability Resources](/developers/service-apis/hl7-fhir)
* [HL7 Version 2](/developers/service-apis/hl7v2)&#x20;
* [GS1 Business Messaging Standard (BMS)](/developers/service-apis/gs1-bms-xml#gs1-stock-messaging-workflows)
* JIRA Integration (which allow submission of Diagnostic reports from dCDR instances directly into JIRA)
* ATNA & DICOM Messaging (which allows for dispatch of audits via NEMA DICOM over Syslog)

#### Two-Factor Authentication

Installation of a TFA provider allows the iCDR to leverage multi-factor authentication workflows using either E-Mail based TFA codes or SMS based TFA codes (via Twilio)

#### Master Data Management

Installation of the MDM plugin copies the necessary plugins to enable the Master Data Management Resource Manager.

#### Data Persistence

The data persistence plugins enable the one or more of the persistence services in SanteDB on the server. The persistence layer plugins supported are:

* PostgreSQL Server Plugin
* Firebird Plugin

#### Caching Services

You should install , at a minimum the **Memory Caching** service plugin to improve the performance of your installation. If you're running SanteDB in a shared environment with multiple servers in a cluster environment, installation of REDIS is recommended.

#### Elbonia Quickstart

Installing the Elbonia Quickstart pack will seed your SanteDB instance with sample data from the fake jurisdiction (from Dilbert) of Elbonia.

## Configuration

Configuration of the SanteDB service is covered in a series of discrete wiki articles which cover each configuration option in the platform and their impact on the system.

Configuration of the SanteDB server should be done prior to the first start of the software. The option to start the configuration tool for SanteDB is provided at the end of the SanteDB installation process.

See: [Configuration Tool](/operations/server-administration/configuration-tool)

When first configuring SanteDB iCDR server on a Windows environment you will need to select the database persistence technology the server will be using, the options are:

* PostgreSQL 9+ :  If you're running SanteDB with full functionality, select this option.
* Firebird : If you're running SanteDB for a quick demonstration or test, select this option.

#### PostgreSQL Configuration

Selecting the PostgreSQL provider will expose the connection parameters for PostgreSQL. See [Database Connections](/operations/server-administration/configuration-tool/persistence-settings/database-connections#postgresql-configuration) for more information on these settings.

![](/files/HRuifm0swZfEwb6hyeuO)

#### Firebird Configuration

Selecting the Firebird provider will expose the connection parameter for Firebird 3.x provider, SanteDB iCDR will assume you're using the embedded version of Firebird. This database connector has three parameters. See [Database Connections](/operations/server-administration/configuration-tool/persistence-settings/database-connections#firebird) connection details in the configuration tool documentation.

![](/files/D50DZPiXbA1R31tjTj6d)

#### Multiple Instances of SanteDB on the Same Server

If you're running multiple instances of SanteDB on the same server, you will need to install the software in different file locations. When configuring the iCDR on the Windows host you can then set an instance name to isolate the Windows Services and event logs.

![](/files/1XAW75Z4EWlV5RJV6xTD)

#### Configuration Template

SanteDB iCDR server packages may be shipped with one ore more [SanteDB Solutions](/product-overview/santesuite-products/santedb/santedb-solutions) included, you should select an appropriate template for the software solution that this instance of the iCDR will fulfill.

![](/files/f69bwnVG7QkqkxSy1Hfj)

#### Initial Configuration Tasks

Once you've completed the installation options for the SanteDB server and press `Continue` you will be prompted to confirm the initial configuration tasks.

![](/files/yBGTGxELv6HUy2NIo04l)

#### Finish Configuration&#x20;

You can use the configuration tooling to customize your installation of the SanteDB server. These settings are documented in [Configuration Tool](/operations/server-administration/configuration-tool)

![](/files/qDPRhVlBNp9nhQQjaUUP)

Recommended configuration panels and settings to change include:

* Changing the Performance/Caching to REDIS caching and setting up REDIS
* Turning down the Diagnostics/Logging setting to Warning or Error

## Initial Run / Initialization

After you have applied the configuration from the Configuration Tool, the SanteDB service will automatically restart.&#x20;

{% hint style="info" %}
If you're using the Firebird based database for SanteDB iCDR you will need to exit the configuration tool after applying your configuration (since the configuration tool locks the database file). After this you may restart the service manually (see [#service-management](#service-management "mention"))
{% endhint %}

### Validating Installation

Once started you can validate connectivity to the SanteDB iCDR server by accessing the Start menu and running `SanteDB Server Console (localhost)` . You should be prompted with a login prompt.

{% hint style="info" %}
If the window closes immediately, the server may not be completed startup. Check the `C:\Program Files\SanteSuite\SanteDB\Server\Data` directory. You should see the files have been initialized if the directory contains no `.dataset` files , and instead contains `.completed` files.
{% endhint %}

Once the login prompt is available you can login with `Administrator` and password `Mohawk123`.

```
SanteDB Administration & Security Console v2.1.131.0 (Queenston)
Copyright (C) 2015 - 2020, SanteSuite Community Partners (see NOTICES)
Access denied, authentication required.
Username:administrator
Password:************
* http://localhost:8080/ami -> v.2.1.116.0 (Queenston)
Ready...
>
```

### Service Management

SanteDB runs as a Windows service (equivalent of a daemon). These can be accessed using the `services.msc` plugin an finding the `SanteDB Host Process` service. Additionally the service can be restarted from an elevated command prompt using:

```
C:\Users\user> NET STOP santedb
C:\Users\user> NET START santed
```

{% hint style="info" %}
If you're running multiple instances of SanteDB on the same server as named instances, each instance of the host process will be `SanteDB Host Process -` name
{% endhint %}


# Installation on Linux and Unix

{% hint style="info" %}
This section is currently being written. Check back soon for instructions on installing on Linux physical and virtual environments.&#x20;
{% endhint %}

When installing SanteDB iCDR server on Linux or Unix based environment you should use the tarballs for the latest version of the SanteDB iCDR server. Each solution within SanteDB iCDR Server has its own distribution which can be downloaded for their own source repository.&#x20;

* [SanteDB iCDR Releases](https://github.com/santedb/santedb-server/releases)
* [SanteMPI Releases](https://github.com/santedb/santempi/releases)

The installation process for SanteDB on Linux is the same process as installation on Windows::

1. Install the software
   * Copy software program files and pre-requisites&#x20;
   * Initiate the configuration process
2. Configuration of the software
   * Customizing the behavior of the installed plugins
   * Entering implementation specific details about the deployment
3. Running/Initializing the Server

The tarballs provided have been written for and test on Debian based distributions, manual installation for non-Debian based distributions is required.

## System Requirements

When running SanteDB iCDR server on Unix based operating systems you will require, at minimum:

* One of the following Unix operating systems:
  * MacOS X 10.9 on M1 or x86 (manual installation)
  * Ubuntu 16.04 or later (install script)
  * Debian 9 or later (install script)
  * CentOS or RHEL 6 or better (manual installation)
* 2 Core CPU (4 to 8 Cores recommended)
* 2 GB RAM (8 or 16 GB of RAM recommended)
* 300 MB of disk space (1 GB recommended)

Users should be familiar with basic Unix concepts such as:

* Un-taring archive files
* Basic familiarity with Unix commands

## Installation

### Using the Install Script

{% hint style="info" %}
The installation script has been tested on Ubuntu 18.04 and 20.04 and Debian 10
{% endhint %}

To install the SanteDB iCDR 2.1.140 or higher via the installation script provided, you should first extract the tarball contents:

```
$ tar -xjvf santedb-server-2.1.140.tar.bz2
```

This will extract the software to the `./santedb-server-2.1.140` directory. You can enter that directory and run the `install.sh` script:

```
$ cd santedb-server-2.1.140/
santedb-server-2.1.140 $ chmod +x install.sh
santedb-server-2.1.140 $ ./install.sh 
```

If you are not running the script as root, the installer will prompt if you would like it to use SUDO. The script will then detect pre-requisites for mono and postgresql. The install script will install mono for you.

{% hint style="info" %}
If you're installing SanteDB iCDR with postgresql running on a different host, you can decline the installation of PostgreSQL. Installation of `mono` is required.
{% endhint %}

{% hint style="info" %}
If you receive an error `cannot find package mono-complete` you may need to run an `apt update` on your system to include the mono packages on Ubuntu. If running Ubuntu 18.04 or prior or Debian 9 you can follow the [Mono Framework Installation](https://www.mono-project.com/download/stable/#download-lin-ubuntu) guide.
{% endhint %}

Finally, you'll be prompted for an installation target, the default location is `/opt/santesuite/santedb/server/`, you can accept the default or change the location of installation to suit your policy.

After installation is complete, the default SanteDB publisher certificates will be registered with the Mono trust store and you'll be provided the option to setup SanteDB as a daemon.&#x20;

### Manual Installation

When installing the SanteDB iCDR server manually, administrators should ensure that the pre-requisites for SanteDB are installed on their preferred Unix environment:

* [Mono Framework 5](https://www.mono-project.com/download/stable/#download-lin-ubuntu)
* [PostgreSQL 10](https://www.postgresql.org/?&)

Once installed, users should create their target installation directory (this tutorial will use `/opt/santedb` , and should unzip the tarball or zip file to that location.

```
tar xjvf santedb-server-2.1.140.tar.bz2
mkdir -p /opt/santedb
mv santedb-server-2.1.140 /opt/santedb
cd /opt/santedb
```

You then need to install the SanteDB publisher certificates into the Mono certificate store:

```
sudo mono SanteDB.exe --install-certs
```

Finally, you can run the configuration tool in your installation directory with

```
sudo mono ConfigTool.exe
```

#### Setting SanteDB as a Daemon

You can register SanteDB as a daemon on your distribution of Linux by creating a service definition file. This is done by creating a new file at `/etc/systemd/system/santedb.service` and using the contents:

```ini
[Unit]
Description=SanteDB iCDR Server

[Service]
Type=simple
RemainAfterExit=yes
ExecStart=/usr/bin/mono-service -d:$INSTALL_ROOT /opt/santesuite/santedb/server/SanteDB.exe --console 
ExecStop=kill \`cat /tmp/SanteDB.exe.lock\`

[Install]
WantedBy=multi-user.target
```

After this time you can run `systemctl reload-daemons` to load your service definition.

## Configuring SanteDB iCDR

SanteDB's configuration tool on linux uses the Mono to GTK+ WinForms implementation. The application is the same application as documented in the [Configuration Tool](/operations/server-administration/configuration-tool) documentation.

![](/files/dW2Q9eVXKw8w3KwL3S4Y)

Details on the initial configuration of SanteDB can be followed from the [Windows Installation](/installation/installation-1/deployment/installing-software/santedb-server/installation-on-virtual-or-physical-environments/installing-a-development-demo-environment) guide.

{% hint style="info" %}
While the configuration tool runs on Linux it is not regularly tested and has known rendering and incompatibilities. Linux users can use the configuration tool to generate basic configurations, however advanced operations (like certificate binding, service control, etc.) may not function as expected. Linux users are encouraged to use the [Server Configuration File](/operations/server-administration/host-configuration-file)
{% endhint %}

## Initial Run / Initialization

Like the Windows installation, the SanteDB, the SanteDB iCDR on Linux needs to be initialized, unlike windows this requires manual stop/start of the service.

If you've installed SanteDB as a daemon the command to stop or start the daemon is:

```
systemctl stop santedb
```

If you are running SanteDB on a console, you can run:

```
mono /opt/santesuite/santedb/server/SanteDB.exe --console
```

### Validating Installation

Once started you can validate connectivity to the SanteDB iCDR server running the SanteDB Administration Console. The Administration console is executed using:

```
mono /opt/santesuite/santedb/server/sdbac.exe
```

Once the login prompt is available you can login with `Administrator` and password `Mohawk123`.

```
SanteDB Administration & Security Console v2.1.131.0 (Queenston)
Copyright (C) 2015 - 2020, SanteSuite Community Partners (see NOTICES)
Access denied, authentication required.
Username:administrator
Password:************
* http://localhost:8080/ami -> v.2.1.116.0 (Queenston)
Ready...
>
```

### Service Management

If the option to install the SanteDB iCDR as a Linux daemon was selected during install, then the service can be controlled with `systemctl` for example:

```
sudo systemctl start santedb
sudo systemctl status santedb
```

Stopping the service is done with the same command:

```
sudo systemctl stop santedb
sudo systemctl status santedb
```

The service can be enabled on startup using:

```
sudo systemctl enable santedb
```

{% hint style="info" %}
The `/tmp/SanteDB.exe.lock` file contains the PID of the running SanteDB instance. Kill commands such as `SIGHUP` , `SIGKILL` and `SIGSEV` can be sent to this PID to terminate the SanteDB daemon.
{% endhint %}


# Installation using Appliances

The SanteSuite community provides ready to deploy virtualization containers for users who wish to use them. Using these images and appliances is well suited when:

* A basic installation of SanteDB iCDR is required to perform an evaluation
* Development, training or testing environments are desired.
* The organization already leverages Docker or Virtualization environments, or does not require vetting/validation of underlying operating system configuration.
* Small installations or localized installations of the software are desired
* Users are deploying to Software-as-a-service (SaaS) environments and need to quickly roll out instances of the SanteDB infrastructure.

One of the benefits of using an appliance over a native or virtual operating system environment, is the bundling of pre-requisites within the deployment.


# Using Docker Containers

SanteDB provides several docker containers for SanteDB solutions and services. The docker containers are structured as illustrated.

![](/files/-MWUkjYXhWIVwR78OFG2)

The docker containers all use the mono:latest as their root container.

* santedb\_icdr: The generic SanteDB iCDR project running as a docker container with FHIR, HL7, caching, PostgreSQL database support, and everything needed to get the iCDR running quickly.
* santedb\_mpi: The generic iCDR project with the SanteGuard and SanteMPI plugins enabled.
* santedb\_dcdr: The disconnected dCDR project

{% hint style="info" %}
SanteDB iCDR and dCDR images use the Mono Framework to operate. Depending on your host environment, you may need to modify the `MONO_THREADS_PER_CPU` environment variable for the iCDR and dCDR if the default thread pool (accessed via the [Probes](/operations/cdr-administration/santedb-administration-panel/system-administration/probes)screen in the portal) indicates a small number of threads available.
{% endhint %}

## Configuring the Docker Containers

### Container Directory/File Structures

The container structure is as follows:

* `/santedb` - Directory which contains the application code for SanteDB
* `/santedb/docker.lastconfig` - The configuration file (in XML form) which represents the computed configuration file for the last run of the docker host.
* `/santedb/data` - Data seeding directory in Dataset format
* `/santedb/data/fhir` - Data seeding for FHIR files (JSON or XML)
* `/santedb/applets` - Application directory (where compile applets files should be)
* `/santedb/match` - Directory for match configuration source files
* `/var/log/santedb_yyyyMMdd.log` - SanteDB log file for current date

### Enabling or Disabling Features

The docker containers are configured using environment variables. Features can be turned on/off using the environment variable SDB\_FEATURE environment variable, for example, to enable the core features and ATNA audit shipping:

```
SDB_FEATURE=AUDIT_SHIPPING;ADO;AUDIT_REPO
```

The features which are available for the default SanteDB docker container are:

| Code         | Feature                                                                                                                                                                                                                                                                         |
| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| LOG          | Core data logging (see: [Configuration Notes](/installation/installation-1/deployment/installing-software/santedb-server/installation-using-appliances/docker-containers/feature-configuration#diagnostic-logging))                                                             |
| DATA\_POLICY | Data privacy enforcement (see: [Configuration Notes](/installation/installation-1/deployment/installing-software/santedb-server/installation-using-appliances/docker-containers/feature-configuration#data-privacy-controls))                                                   |
| AUDIT\_REPO  | Internal security audit repository (see: [Configuration Notes](/installation/installation-1/deployment/installing-software/santedb-server/installation-using-appliances/docker-containers/feature-configuration#audit-repository))                                              |
| ADO          | Core Application Data Objects (ADO.NET) data persistence (see: [Configuration Notes](/installation/installation-1/deployment/installing-software/santedb-server/installation-using-appliances/docker-containers/feature-configuration#ado-data-storage))                        |
| PUBSUB\_ADO  | Publish / Subscribe Subsystem (see: [Configuration Notes](/installation/installation-1/deployment/installing-software/santedb-server/installation-using-appliances/docker-containers/feature-configuration#publish-subscribe-functions))                                        |
| RAMCACHE     | In-Process Memory Cache (see: [Configuration Notes](/installation/installation-1/deployment/installing-software/santedb-server/installation-using-appliances/docker-containers/feature-configuration#in-memory-caching))                                                        |
| REDIS        | REDIS based shared cache (see: [Configuration Notes](/installation/installation-1/deployment/installing-software/santedb-server/installation-using-appliances/docker-containers/feature-configuration#redis-caching))                                                           |
| SEC          | Core Security Functions (PIP, PDP, PEP)                                                                                                                                                                                                                                         |
| SWAGGER      | OpenAPI / Swagger Metadata Endpoint (see: Configuration Notes)                                                                                                                                                                                                                  |
| OPENID       | OAUTH 2.0 / OpenID IdP Provider (see: [Configuration Notes](/installation/installation-1/deployment/installing-software/santedb-server/installation-using-appliances/docker-containers/feature-configuration#openid-connect-idp))                                               |
| MDM          | Master Data Management Functions (see: [Configuration Notes](/installation/installation-1/deployment/installing-software/santedb-server/installation-using-appliances/docker-containers/feature-configuration#master-data-management-and-record-linking))                       |
| FHIR         | HL7 FHIR Endpoint (see: [Configuration Notes](/installation/installation-1/deployment/installing-software/santedb-server/installation-using-appliances/docker-containers/feature-configuration#hl7-fast-health-interoperability-resources-fhir))                                |
| HL7          | HL7 Version 2.x Endpoint (see: [Configuration Notes](/installation/installation-1/deployment/installing-software/santedb-server/installation-using-appliances/docker-containers/feature-configuration#hl7-version-2-x))                                                         |
| HDSI         | Core Health Data Service Interface (see: [Configuration Notes](/installation/installation-1/deployment/installing-software/santedb-server/installation-using-appliances/docker-containers/feature-configuration#core-health-data-service-interface))                            |
| AMI          | Administrative Management Interface (see: [Configuration Notes](/installation/installation-1/deployment/installing-software/santedb-server/installation-using-appliances/docker-containers/feature-configuration#core-administrative-management-interface))                     |
| BIS          | Business Intelligence (reporting/query set/etc.) interface (see: [Configuration Notes](/installation/installation-1/deployment/installing-software/santedb-server/installation-using-appliances/docker-containers/feature-configuration#core-business-intelligence-interfaces)) |
| MATCHING     | Internal SanteDB Matching Engine (see: [Configuration Notes](/installation/installation-1/deployment/installing-software/santedb-server/installation-using-appliances/docker-containers/feature-configuration#record-matching-plugin))                                          |

### Database Connections

The location of your PostgreSQL server, and the database to use for the container can be specified with the connection string environment variables:&#x20;

```
SDB_DB_PSQL="server=location;user=user;password=password;database=db"
SDB_DB_PSQL_PROVIDER=Npgsql
SDB_DB_AUDIT=" ... "
```

If you are using plugins which require additional named configuration parameters, prefix the configuration with `SDB_DB_XXX` where XXX is the ID of the connection string the plugin is expecting.

### Configuring Components

Components within SanteDB iCDR can be configured using environment variables. The syntax of these environment variables is `SDB_FEATURE_SETTING` , for example, the CACHE feature is configured as:

```bash
SDB_FEATURE=CORE_CDR,CACHE
# Caching Mode = REDIS  | LOCAL
SDB_CACHE_MODE=REDIS
# Pointer to redis server
SDB_CACHE_REDIS_SERVER=sdb-redis:6379
# Expire cache entries after X timestamp
SDB_CACHE_EXPIRE=PT1H
```

### Minimal Application&#x20;

You can compose a minimal application with either the SanteDB-ICDR or SanteMPI instance using a docker-compose.yml file as shown.

```yaml
version: "3.3"

services:
  db:
    image: postgres
    container_name: sdb-postgres
    ports:
      - "5432:5432"
    environment:
      POSTGRES_USER: santedb
      POSTGRES_PASSWORD: SanteDB123
    restart: always

  santedb:
    image: santesuite/santedb-icdr:latest
    container_name: santedb-icdr
    environment:
      - SDB_FEATURE=LOG;DATA_POLICY;AUDIT_REPO;ADO;PUBSUB_ADO;RAMCACHE;SEC;SWAGGER;OPENID;FHIR;HL7;HDSI;AMI;BIS
      - SDB_DB_MAIN=server=sdb-postgres;port=5432; database=santedb; user id=santedb; password=SanteDB123; pooling=true; MinPoolSize=5; MaxPoolSize=15; Timeout=60;
      - SDB_DB_AUDIT=server=sdb-postgres;port=5432; database=auditdb; user id=santedb; password=SanteDB123; pooling=true; MinPoolSize=5; MaxPoolSize=15; Timeout=60;
      - SDB_DB_MAIN_PROVIDER=Npgsql
      - SDB_DB_AUDIT_PROVIDER=Npgsql
      - SDB_DELAY_START=1000
    ports:
      - "8080:8080"
      - "2100:2100"
    depends_on:
      - db
    restart: always
```

### Volumes

Some directories in the docker image are useful for development purposes. For example, you can configure a volume which exposes a common configuration file set, or common applets. The volumes which can be expose (and their directories) can be done via:

```yaml
services:

   # ... truncated for space ...
   
   santedb:
      image: santesuite/santedb-icdr:latest
      # .. truncated ...
      volumes:
         - santedb-data:/santedb/data

volumes:
   santedb-data:
```

The volumes which are of use for exposing to the host docker environment are:

| Path             | Use                                                                                                                                                                                                                   |
| ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| /santedb/data    | <p>Used for seeding data into the SanteDB instance. For example</p><p>if you have a development environment where you'd like the same data</p><p>seeded into the database on startup you can use this option.</p>     |
| /santedb/config  | <p>Used for direct access to the configuration files. You should use this option</p><p>if the environment variables for the docker instance are too restrictive. </p>                                                 |
| /santedb/applets | <p>Used for loading applet files which contain user interfaces, BI reports, </p><p>business rules, CDSS rules, etc. These applets should be digitally signed</p><p>PAK files.</p>                                     |
| /santedb/match   | <p>Stores the match configuration files for the SanteDB matching engine. These </p><p>match configuration files control the weight, blocking, and classification subsystem</p><p>for the default match algorithm.</p> |

## Advanced Configurations

You can import additional configuration files and/or use the XML configuration subsystem by creating a new container which is based off the `santedb-icdr` docker image and including additional configuration files. To do this, collect your configuration file as `myconfig.xml` in a directory and create a new Dockerfile which starts using this as configuration file:

```elixir
FROM santedb-icdr:latest
RUN mkdir /myproject
COPY myconfig.xml /myproject/myconfig.xml
WORKDIR /santedb
EXPOSE 2100/tcp
EXPOSE 8080/tcp
CMD ["mono","/santedb/SanteDB.Docker.Server.exe","/myproject/myconfig.xml"]
```

### Adding Sample Data

See the Adding Sample Data article for methods of seeding sample data into SanteMPI.

### Packaging Custom Business Rules

You can package [business rules](/developers/applets/business-rules), [business intelligence](/developers/applets/business-intelligence-bi-assets), and other [asset files](/developers/applets/assets) into your docker container by simply composing them into a PAK file and including them in the /santedb/applets/ directory.

```markup
FROM santedb-icdr:latest
COPY custom.pak /santedb/applets/custom.pak
```

Upon load, the SanteDB iCDR server will load your package files and will load any business rules files required.

## SanteMPI

In order to run a minimal SanteMPI application, you can exchange `santedb-icdr` with the `santedb-mpi` image, and apply the appropriate service configuration.

```yaml
version: "3.3"

services:
  db:
    image: postgres
    container_name: sdb-postgres
    ports:
      - "5432:5432"
    environment:
      POSTGRES_USER: santedb
      POSTGRES_PASSWORD: SanteDB123
    restart: always

  santedb:
    image: santesuite/santedb-mpi:latest
    container_name: santedb-mpi
    environment:
      - SDB_FEATURE=LOG;DATA_POLICY;AUDIT_REPO;ADO;PUBSUB_ADO;RAMCACHE;SEC;SWAGGER;OPENID;FHIR;HL7;HDSI;AMI;BIS;MDM;MATCHING;IHE_PIXM;IHE_PDQM;IHE_PMIR
      - SDB_MATCHING_MODE=WEIGHTED
      - SDB_MDM_RESOURCE=Patient=org.santedb.matching.patient.default
      - SDB_MDM_AUTO_MERGE=false
      - SDB_DB_MAIN=server=sdb-postgres;port=5432; database=santedb; user id=santedb; password=SanteDB123; pooling=true; MinPoolSize=5; MaxPoolSize=15; Timeout=60;
      - SDB_DB_AUDIT=server=sdb-postgres;port=5432; database=auditdb; user id=santedb; password=SanteDB123; pooling=true; MinPoolSize=5; MaxPoolSize=15; Timeout=60;
      - SDB_DB_MAIN_PROVIDER=Npgsql
      - SDB_DB_AUDIT_PROVIDER=Npgsql
      - SDB_DATA_POLICY_ACTION=HIDE
      - SDB_DELAY_START=5000
    ports:
      - "8080:8080"
      - "2100:2100"
    depends_on:
      - db
    restart: always
```

The SanteMPI container adds the following plugins to SanteDB which can be enabled/disabled with `SDB_FEATURE`:

| Code      | Feature                                                                                                    |
| --------- | ---------------------------------------------------------------------------------------------------------- |
| IHE\_PDQM | Enables the Patient Demographics Query for Mobile query parameters and extensions.                         |
| IHE\_PIXM | Enables the Patient Identity Cross Reference (`$ihe-pix`) FHIR operation                                   |
| IHE\_PMIR | Enables the Patient Master Identity Registry function (`urn:ihe:iti:pmir:2019:patient-feed` ) FHIR message |
| IHE\_PIX  | Enables the IHE PIX (ITI-8 and ITI-9) interfaces for the MPI                                               |
| IHE\_PDQ  | Enables the IHE PDQ profile (ITI-21) for HL7v2 interface on the MPI.                                       |


# Adding Sample Data

You can quickly add test/sample data by copying [dataset files](/developers/applets/distributing-data) into the `/santedb/data` directory of the docker container either using a custom dockerfile or by mounting a volume from the docker image.

## Dataset Files

These dataset files can be generated from the `sdbac` command prompt with the `cdr.query` command to produce dataset files. Dataset files provide a 1:1 mapping to the underlying CDR storage engine and are expressed in XML RIM objects. Dataset files can include:

* Infrastructure elements like Assigning Authorities, Concepts, Extension Types, etc.
* Clinical elements like Entities or Acts&#x20;

For example, to initialize an MPI with an identity domain, and an organization with a custom policy, for a particular use case, create a new dataset file containing the identity domain, organization and custom policy:

```markup
<?xml version="1.0"?>
<dataset id="Elbonia Identity Domains" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://santedb.org/data">
  <!-- National Health Identifier -->
  <insert skipIfError="false" skipIfExists="true">
    <AssigningAuthority xmlns="http://santedb.org/model">
      <name>Elbonia</name>
      <domainName>MOH_NHID</domainName>
      <oid>1.3.6.1.4.1.52820.5.0.1.1.1</oid>
      <url>http://mpi.moh.gov.elb/identity/moh/nhid</url>
      <isUnique>true</isUnique>
      <validation>^\d{12}$</validation>
      <scope>bacd9c6f-3fa9-481e-9636-37457962804d</scope>
    </AssigningAuthority>
  </insert>
  <update insertIfNotExists="true">
    <Organization xmlns="http://santedb.org/model">
      <id>fae7b5fb-ea49-4460-9149-f0952efe572a</id>
      <classConcept>7c08bd55-4d42-49cd-92f8-6388d6c4183f</classConcept>
      <determinerConcept>f29f08de-78a7-4a5e-aeaf-7b545ba19a09</determinerConcept>
      <statusConcept>c8064cbd-fa06-4530-b430-1a52f1530c27</statusConcept>
	    <industryConcept>fdeb2e4e-9e02-4ce3-ab69-cece5ffdee20</industryConcept>
      <name>
        <use>1ec9583a-b019-4baa-b856-b99caf368656</use>
        <component>
          <value>Elbonia National Health Insurnace Corporation</value>
        </component>
      </name>
    </Organization>
  </update>  
  <update insertIfNotExists="true">
    <SecurityPolicy xmlns="http://santedb.org/model">
      <id>fd8c0e00-82fb-11eb-8dcd-0242ac130004</id>
      <name>Elbonia Parlimentarian Health Record VIP Access Policy</name>
      <oid>2.25.40394829382872728372832</oid>
      <isPublic>true</isPublic>
      <canOverride>false</canOverride>
    </SecurityPolicy>
  </update>  
</dataset>
```

The file would be copied into the /santedb/data directory of the santedb-mpi or santedb-icdr container with the following Dockerfile.

```markup
FROM santedb-icdr:latest
COPY custom.dataset /santedb/data/custom.dataset
```

## FHIR Resources

You can also seed data into the `/santedb/data/fhir` directory of the container using a custom dockerfile or by mounting the volume from the docker container.

FHIR resources are limited to only those resources which have a IFhirResourceHandler implementation registered and configured. (TODO: Insert link)

FHIR resources can be in JSON or in XML format, and are simply placed in the directory. The seeder then processes these files on application start and will generate two files:

* A file with a .completed extension which indicates that the message contents were successfully processed and included into the SanteDB iCDR database.
* A file with a .response extension which is the FHIR response that would have been sent via the REST API. This is useful for diagnosing issues with your FHIR message being seeded.

{% hint style="info" %}
Seeding data via FHIR requires at least version 2.1.11 of the iCDR FHIR plugin.
{% endhint %}

## Deploying on Container

You can deploy either dataset files or FHIR files onto your running iCDR container by either including the files in a custom `Dockerfile` such as:

```
FROM santedb-icdr:latest
COPY patients.json /santedb/data/fhir/patients.json
COPY identity.dataset /santedb/data/identity.dataset
```

Alternately , you can mount the `/santedb/data` directory as a volume for your container and copy the files, or you can use a command line interface and `docker cp` such as:

```
docker cp patients.json santedb-icdr:/santedb/data
docker cp identity.dataset santedb-icdr:/santedb/data
```


# Feature Configuration

## Core Services (Recommended)

### Diagnostic Logging

The diagnostic logging feature allows for logging to files, the console, or even via the trace writer in Mono. These settings provide access to the [Diagnostics Configuration ](/operations/server-administration/host-configuration-file/diagnostics-configuration)subsystem.&#x20;

```
SDB_FEATURE=...;LOG;...
# Set the Logging Level
SDB_LOG_LEVEL=Error|Warning|Informational|LogAlways
```

### Data Privacy Controls

The privacy control services actively apply privacy policy protections on outbound messages, and ensure that inbound messages meet the minimum policy level for updating/creating records. For example, this service ensures that masked data, or sensitive data which may be inaccurate (given the submitter's policy set) cannot be recorded, and that any data is masked/hidden from the underlying repository.

```
SDB_FEATURE=...;DATA_POLICY;...
# Set the action to apply when sensitive data is disclosed
SDB_DATA_POLICY_ACTION=hide|redact|nullify|error|audit|none
# Set the resources on which policies should be applied
SDB_DATA_POLICY_RESOURCE=Resource=action;Resource=action;...
# Set forbidden properties (properties which should not be disclosed, queried, or collecected
# unless the user has the specified policy OID (if no policy is specified the attribute is forbidden
SDB_DATA_POLICY_FORBID=Resource.property;Resource.property=policyOID;...
```

{% hint style="info" %}
The `SDB_DATA_POLICY_FORBID` setting restricts the use of the indicated property in the RIM from users. For example, to restrict collection, querying, or disclosing of the religion property, and to only allow collection, querying and disclosing of vip status to users with policy 2.25.349398

```
SDB_DATA_POLICY_FORBID=Patient.religion;Patient.vipStatus=2.25.349498
```

{% endhint %}

### Audit Repository

The audit repository feature enables the local audit repository on SanteSuite, meaning that audits are stored in the specified audit database.

```
SDB_FEATURE=...;AUDIT_REPO;...
# Sets the RW connection
SDB_AUDIT_REPO_RW_CONNECTION=connection
# Create Connection Strings
SDB_DB_connection_PROVIDER=Npgsql
SDB_DB_connection=server=x;password=y;
```

### ADO Data Storage

The ADO data storage service should be enabled if you plan on using the PostgresSQL or another supported database to store data.&#x20;

```
SDB_FEATURE=...;ADO;...
# Sets the Read/Write Master Connection
SDB_ADO_RW_CONNECTION=rwconnection
SDB_DB_rwconnection_PROVIDER=Npgsql
SDB_DB_rwconnection=server=x;password=y
# Sets the Read only Secondary Connection
SDB_ADO_RO_CONNECTION=roconnection
SDB_DB_roconnection_PROVIDER=Npgsql
SDB_DB_roconnection=server=x;password=y
# Set whether the provider will use fuzzy totals
# using fuzzy totals increases performance and merely indicates "another page is available"
# rather than counting the total result set size
SDB_ADO_FUZZY_TOTAL=true|false
```

{% hint style="info" %}
You can swap the SanteDB core storage technology to another technology, in this case do not use the ADO data storage feature.
{% endhint %}

### ADO Freetext Search

The ADO freetext search service enables the full-text indexing feature on the docker container, and is available on SanteDB iCDR versions 2.1.155 and above.

```
SDB_FEATURE=...;ADO_FTS;...
```

{% hint style="info" %}
The ADO free-text search service refreshes the free-text index in real time as records are added to the SanteDB iCDR. If your deployment has no need of freetext search at the iCDR level (i.e. you are using the dCDR only for user interfaces) then you can disable this feature to improve performance.
{% endhint %}

### In-Memory Caching

The in-memory caching feature instructs the iCDR container to use a local RAM-based cache (non-shared) for data operations.

```
SDB_FEATURE=...;RAMCACHE;...
# The time that cache entries should remain cached before RAM is cleaned
# in the format DAYS.HOURS:MINUTES:SECS
SDB_RAMCACHE_TTL=0.1:0:0
```

### REDIS Caching

The REDIS caching feature instructs the iCDR container to use a shared REDIS cache for data operations.

```
SDB_FEATURE=...;REDIS;...
# The time that cache entries should remain cached before RAM is cleaned
SDB_REDIS_TTL=0.1:0:0
# The address/port of the REDIS server
SDB_REDIS_SERVER=server:port
```

### Core Security Services

The core security services should always be enabled, unless you're running a heavily customized version of the iCDR software which supplies its own security services.

```
SDB_FEATURE=...;SEC;...
# The password validation/complexity validation regex
SDB_SEC_PWD_REGEX=regular expression
# The length of sessions issued by the service
SDB_SEC_POL_SESSION=0.1:0:0
# The number of invalid authentications before a user/device/application is locked
SDB_SEC_POL_LOCK=4
# Sets the secrets for the SanteDB data signing services
# You can specify either HS256, RS256 or RS512 signing algorithms
# Note: You will need to customize your own SanteDB iCDR instance with a custom
#       dockerfile if you choose to use RS256 as the certs need to be installed
#       into the mono keystore.
SDB_SIG_default=hs256:A_SECRET_PASSPHRASE_FOR_HMAC256_DATA_SIGNATURES
SDB_SIG_other=rs256:THUMBPRINT_OF_YOUR_RSA_CERT

```

### OpenID Connect IDP

The OpenID Connect IDP service enables the [OpenID Identity Provider](/developers/service-apis/openid-connect) services.

```
SDB_FEATURE=...;OPENID;...
# One or more claims which client systems can send. Default are:
# scope;PolicyOverride;ResourceId;PurposeOfUse;FacilityId;OrganizationId
SDB_OPENID_CLAIMS=scope;PolicyOverride;PurposeOfUse
# If you need to use a custom token type
SDB_OPENID_TOKEN=bearer
# When true, allows client_credentials grant without sending an 
# X-Device-Authorization header or an X509 client certificate
SDB_OPENID_INSECURE_CLIENT_AUTH=true|false
# The issuer ID of this IdP
SDB_OPENID_ISSUER=myrealm
# The key to use for signing the JWT key. Note: When using HMAC256
# the client secret is used to sign the JWT
SDB_OPENID_JWT_SIG_KEY=xxxx
# Set the address (port/url) where OpenID should be available
SDB_OPENID_LISTEN=http://0.0.0.0:8080/auth
```

### Core Health Data Service Interface

The core HDSI interface should always be enabled if you plan on using any of the SanteDB dCDR services. If you are just using the iCDR for other interfaces, you can disable this interface.

```
SDB_FEATURE=...;HDSI;...
# The base URL where the HDSI should be bound
SDB_HDSI_LISTEN=http://0.0.0.0:8080/hdsi
# The authentication scheme to use for the HDSI
SDB_HDSI_AUTH=TOKEN|BASIC|NONE
# Enables or disables CORS
SDB_HDSI_CORS=true|false
```

### Core Administrative Management Interface

The core AMI interface should always be enabled if you plan on using any of the SanteDB dCDR services or services like the admin console which require API access. If you are just using the iCDR for other interfaces, and have no need to create users, policies, or other assets.

```
SDB_FEATURE=...;AMI;...
# The base URL where the AMI should be bound
SDB_AMI_LISTEN=http://0.0.0.0:8080/ami
# The authentication scheme to use for the AMI
SDB_AMI_AUTH=TOKEN|BASIC|NONE
# Enables or disables CORS
SDB_AMI_CORS=true|false
```

### Core Business Intelligence Interfaces

The core BI services allow third party solutions to query and execute reports on the SanteDB server, as well as FHIR MeasureReport resources.&#x20;

```
SDB_FEATURE=...;BIS;...
# The base URL where the AMI should be bound
SDB_BIS_LISTEN=http://0.0.0.0:8080/bis
# The authentication scheme to use for the BIS
SDB_BIS_AUTH=TOKEN|BASIC|NONE
# Enables or disables CORS
SDB_BIS_CORS=true|false
# Sets the maximum number of rows a single BIS report can retrieve from the database
SDB_BIS_MAX_RESULTS=50000
```

{% hint style="warning" %}
Setting `SDB_BIS_MAX_RESULTS` will impact server performance. The default size of BI report result sets is 10,000. For reports which require more than 10,000 results, it is recommended that the developer pass the `_count` parameter to the rendering API.&#x20;
{% endhint %}

## Optional Services

### HL7 Fast Health Interoperability Resources (FHIR)

SanteDB's FHIR resources are enabled using the FHIR feature. The FHIR feature controls the exposed resources (to minimize surface area), location and options for FHIR.

```
SDB_FEATURE=...;FHIR;...
# The base URL where the FHIR should be bound
SDB_FHIR_LISTEN=http://0.0.0.0:8080/fhir
# The authentication scheme to use for the FHIR
SDB_FHIR_AUTH=TOKEN|BASIC|NONE
# Enables or disables CORS
SDB_FHIR_CORS=true|false
# When emitting links for references, the external URL to use
SDB_FHIR_BASE=http://external-url/fhir
# The resources which should be exposed on the FHIR interface
SDB_FHIR_RESOURCE=Patient;Practitioner;Organization;...
# Extensions which should be enabled 
SDB_EXTENSION=http://hl7.org/fhir/StructureDefinition/patient-citizenship;http://hl7.org/fhir/StructureDefinition/patient-religion;...
```

{% hint style="info" %}
`SDB_FHIR_EXTENSION` is used to enable `IFhirExtensionHandler` implementations, these are responsible for querying or transforming data from the [Data & Information Architecture](/santedb/data-and-information-architecture) to FHIR. Extensions which are stored as extensions within the data architecture are always exposed in the FHIR objects. See: [Extending FHIR Functionality](/developers/service-apis/hl7-fhir/extending-fhir-interfaces#extension-handlers)
{% endhint %}

### HL7 Version 2.x&#x20;

The HL7 Version 2.x interface allows the iCDR docker container to expose HL7 LLP or SLLP traffic to trading partners.

```
SDB_FEATURE=...;HL7;...
# Indicates how the sending application should be authenticated.
# Note: When using SLLP the client certificate is used to authenticate the device
# .     this setting impacts how the application is authenticated.
# Note: When using regular LLP, the client and device are authenticated using this
#       mechanism
# Values:
#    MSH8 - Device authentication occurs via SSL
#           if regular LLP, device authentication occurs via MSH-3|MSH-4 and MSH-8
#    SFT4 - Device authentication occurs via SSL
#           if regular LLP, device authentication occurs via MSH-4 and MSH-8
#           and application authentication occurs via SFT-4 
SDB_HL7_AUTHENTICATION=MSH8|SFT4|NONE
# The namespace ID where internal UUIDs for patients are exposed (if opted)
SDB_HL7_LOCAL_DOMAIN=MY_DOMAIN
# If PID segment field for SSN is used, maps the value in that field to a domain
SDB_HL7_SSN_DOMAIN=SSN
# The port and protocol to listen on
#    LLP = Unsecure LLP
#    SLLP = SSL + LLP
#    TCP = TCP stream only
# The bind port is also specified here.
SDB_HL7_LISTEN=llp://0.0.0.0:2100
# The amount of time to keep the TCP channel open after sending a response
# this is used in batch or streaming mode.
SDB_HL7_TIMEOUT=100
# If using SLLP, this is thumbprint of the server's certificate
SDB_HL7_SERVER_CERT=thumbprint
# If using SLLP with client authentication via TLS, this is the thumbprint
# of a CA or chain to use for client authentication
SDB_HL7_CLIENT_AUTH=thumbprint
```

### Publish / Subscribe Functions

The pubsub feature enables the structured message notification system. This allows third party systems to setup standing queries which SanteDB will "notify" them of whenever new data becomes available.

```
SDB_FEATURE=...;PUBSUB_ADO;...
# If the pub-sub subscriptions are being stored in a database different
# than the main database , indicate the name of the connection string here
SDB_PUBSUB_ADO_RW_CONNECTION=connectionString
```

### Record Matching Plugin

The record matching plugin registers the [SanteDB Matcher ](/santedb/matching-engine)plugin in the container. This service is used by other services to match and/or merge data.

```
SDB_FEATURE=...;MATCHING;...
SDB_MATCHING_MODE=WEIGHTED|SIMPLE
```

The matching modes supported are:

* SIMPLE: Simple matching only performs block operations against the database, and performs no scoring. This mode is useful when your duplication detection is light. Records are given a score of 0.0 (not match) or 1.0 (match)
* WEIGHTED: Weighted matching uses the SanteDB Matching plugin to perform scoring.&#x20;

When composing your own image from SanteMPI you can copy match configurations to the ./match directory:

```
FROM santesuite/santedb-mpi:latest
COPY ./my_match_config.xml /santedb/match/my_match_config.xml
```

### Master Data Management & Record Linking

The MDM feature sets up the MDM resource persistence strategy and subscribes one or more resources to one or more match configurations.

{% hint style="info" %}
When enabling the MDM service, you must also enable the MATCHING service.
{% endhint %}

```
SDB_FEATURE=...;MDM;...
SDB_MDM_RESOURCE=Patient;Person;...
```

The supported resources for MDM management are:

| Resource             | Description                                                                                                                                                                   |
| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Person               | Places any entity of type Person or its subclasses (Provider / Patient) under MDM storage management.                                                                         |
| Patient              | Places any entity of type Patient into MDM storage management. This is useful for Master Patient Index or Client Registry scenarios.                                          |
| Provider             | Places any entity of type Provider into MDM storage management. This is useful for centralized Provider Registries.                                                           |
| Material             | Places any entity of Material or ManufacturedMaterial into MDM storage management. This includes kinds and instances of materials. Useful for centralized product registries. |
| ManufacturedMaterial | Places only ManufacturedMaterials into MDM storage management.                                                                                                                |
| Place                | Places the Place resource into MDM storage management. This is useful for centralized Geographic or Facility Registries                                                       |
| Organization         | Organizations (such as companies, government agencies, etc.) in MDM control.                                                                                                  |

### E-Mail Configuration

{% hint style="info" %}
This section documents a SanteDB 3.0 feature.
{% endhint %}

The e-mail configuration allows you to configure the SMTP settings for SanteDB to send e-mails. This option is used for MFA codes, administrative alerts, etc.

```
SDB_FEATURE=...;EMAIL;...
# The SMTP server to use for sending mail
EMAIL_SERVER=smtp://server.com:port
# The "from" address for all e-mails being sent by SanteDB
EMAIL_FROM=no-reply@example.com
# True if the STMP server requires TLS
EMAIL_TLS=true
# If the SMTP server requires authentication - the username
EMAIL_USER=key_to_authenticate_smtp_if_needed
# If the SMTP server requires authentication - the password
EMAIL_PASSWORD=password_to_authenticate_smtp_if_needed
# The Administrative contacts which should be CC'd on relevant admin events
EMAIL_ADMIN=admin@example.com;helpdesk@example.com
```

### Signing Configuration

{% hint style="info" %}
This section documents a SanteDB 3.0 feature.
{% endhint %}

The signing configuration allows administrators of the Docker server to change how the server software signs tokens.

```
SDB_FEATURE=...;SIGN;...
# Set the primary algorithm for the signing of data
SIGN_ALG=HS256|RS256
# Set the secret if using HMAC256 signing
SIGN_HS256_SECRET=A SECRET PASSPHRASE
# Set the subject name of a new self-signed certificate to generate
SIGN_RS256_GEN=SUBJECT_NAME_OF_CERTIFICATE
# Set the thumbprint of an existing certificate to use for signing
SIGN_RS256_CERT=thumbprint of existing cert
```

## SanteMPI Features

You can enable specific SanteMPI features by enabling the `IHE_*` interfaces on the `santedb-mpi` container.

### IHE PIX for Mobile

To enable the `$ihe-pix` operation in the container:

```
SDB_FEATURE=...;IHE_PIXM;...
```

### IHE PDQ for Mobile

To enable the PDQm behaviors on the `/Patient` resource:

```
SDB_FEATURE=...;IHE_PDQM;...
```

### IHE PMIR Feature

To enable the `urn:ihe:iti:pmir:2019:patient-feed` operation:

```
SDB_FEATURE=...;IHE_PMIR;...
```

### IHE PIX for HL7v2

To enable the specialized behaviors on ADT messages for IHE PIX for HL7v2

```
SDB_FEATURE=...;IHE_PIX;...
```

### IHE PDQ for HL7v2

To enable specialized behaviors on QBP messages for IHE PDQ for HL7v2

```
SDB_FEATURE=...;IHE_PDQ;...
```


# SanteDB within Instant OpenHIE

Instructions on how to integrate SanteDB with the instant openhie project

## Creating a Santedb package

### Pre-requisites:

* Clone the openhie/instant repo: <https://github.com/openhie/instant>
* Have docker installed - There is a prerequisite documentation on the openhie wiki which explains the docker requirements: <https://openhie.github.io/instant/docs/introduction/getting-started>
* Be familiar with how to create an Instant OpenHIE package: <https://openhie.github.io/instant/docs/how-to/creating-packages>

{% hint style="info" %}
Example project can be found at: <https://github.com/santedb/santempi-openhie-package>
{% endhint %}

### Create a fresh SanteDB Package

The minimum needed to create a package is an instant.json file, a Docker folder, and a Kubernetes folder. The instant.json file will look something like shown below. &#x20;

{% tabs %}
{% tab title="instant.json" %}

```
{
    "id": "santempi",
    "name": "client-registry",
    "description": "OpenHIE CR Based on SanteMPI",
    "type": "infrastructure",
    "version": "v2.1.3",
    "dependencies": ["client", "core"]
 }
```

{% endtab %}
{% endtabs %}

#### &#x20;Docker Folder

The docker folder will need the following items:&#x20;

* A **compose.sh** file&#x20;
* A **docker-compose.yml** file&#x20;
* Either **docker-compose.config.yml** files and/or a **docker-compose.dev.yml** file
* Potentially an **Importer** folder, which while not necessarily required, will make life easier - this would enable you to preconfigure channels, instead of having to manually create them.&#x20;

#### Kubernetes Folder

The Kubernetes folder will need the following items:

* A **k8s.sh** file
* Kubernetes resource files, in our example we have:
  * **db-deployment.yaml**
  * **db-service.yaml** (These are for the Postgres Image)
  * **santedb-deployment.yaml**
  * **santedb-service.yaml** (This are for the santedb-mpi image)
  * **santedb-mpi-app-persistentvolumeclaim.yaml, santedb-mpi-config-persistentvolumeclaim.yaml, santedb-mpi-seed-persistentvolumeclaim**
* Potentially an **Importer** folder, which while not necessarily required, will make life easier - this would enable you to preconfigure channels, instead of having to manually create them.&#x20;

{% hint style="info" %}
More information on the importer folder can be found: <https://openhie.github.io/instant/docs/how-to/configure-openhim-mapping-mediator>
{% endhint %}

## Running the SanteDB Package

### Run on Docker

Navigate to the OpenHIE/Instant repository. Type the following commands

```
yarn
yarn docker:build
```

Next we need to run the images

```
yarn docker:instant init -t docker santempi -c="<path to santedb package>"
```

The above command is specifying to run docker, specifying the package santempi (Which will link to the **id** property of the instant.json file), and specifying a path of where to find the image.&#x20;

It make take several minutes to build. And after it's complete, you may need to wait a couple more minutes for the santedb-mpi server to be fully initialized. Once it's done, you should see something that looks like the following:

```
whitet@Mohawks-MBP instant % docker container ls
CONTAINER ID   IMAGE                              COMMAND                  CREATED              STATUS              PORTS                                                                                                                                                                     NAMES
58d391d05922   santesuite/santedb-mpi:2.1.3       "mono /santedb/Sante…"   33 seconds ago       Up 28 seconds       0.0.0.0:2100->2100/tcp, :::2100->2100/tcp, 0.0.0.0:8082->8080/tcp, :::8082->8080/tcp                                                                                      santedb-mpi
c27b8358cd41   hapiproject/hapi:v5.2.1            "catalina.sh run"        57 seconds ago       Up 54 seconds       8080/tcp                                                                                                                                                                  hapi-fhir
3056b77f1a9b   mysql:5.7                          "docker-entrypoint.s…"   About a minute ago   Up 57 seconds       3306/tcp, 33060/tcp                                                                                                                                                       hapi-mysql
161a5071d2ca   jembi/openhim-core:5               "docker-entrypoint.s…"   About a minute ago   Up 47 seconds       0.0.0.0:5000-5001->5000-5001/tcp, :::5000-5001->5000-5001/tcp, 0.0.0.0:5050-5052->5050-5052/tcp, :::5050-5052->5050-5052/tcp, 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp   openhim-core
8903414d9b11   mongo:4.2                          "docker-entrypoint.s…"   About a minute ago   Up About a minute   27017/tcp                                                                                                                                                                 mongo-1
c1e4e3e15802   postgres                           "docker-entrypoint.s…"   22 hours ago         Up 33 seconds       5432/tcp                                                                                                                                                                  sdb-postgres
7874397ec2ae   intrahealth/opencr:6195bd8         "/bin/sh -c 'dockeri…"   22 hours ago         Up 37 seconds       0.0.0.0:3004->3000/tcp, :::3004->3000/tcp                                                                                                                                 opencr
e42421df077c   intrahealth/elasticsearch:latest   "/usr/local/bin/dock…"   22 hours ago         Up 42 seconds       0.0.0.0:9200->9200/tcp, :::9200->9200/tcp, 9300/tcp                                                                                                                       es
b79d9cd172fd   jembi/openhim-console:1.14         "/docker-entrypoint.…"   22 hours ago         Up 55 seconds       0.0.0.0:9000->80/tcp, :::9000->80/tcp                                                                                                                                     openhim-console
d2a1eb344eee   mongo:4.2                          "docker-entrypoint.s…"   22 hours ago         Up About a minute   27017/tcp                                                                                                                                                                 mongo-2
a53e45cd7c94   mongo:4.2                          "docker-entrypoint.s…"   22 hours ago         Up About a minute   27017/tcp                                                                                                                                                                 mongo-3
whitet@Mohawks-MBP instant % 

```

There are other containers available. These are the minimum required to use the santedb package with the instant openhie project.

You can navigate to <http://localhost:9000> and be brought to the login screen.&#x20;

* default username is: <root@openhim.org>
* default password is: instant101

#### Channels - If using the example project

If you've used the example project, or have used an Importer, you should be able to see santedb channels.&#x20;

![Currently the channels need to be public, in order to access SanteDB](/files/-MdTG1NR3tXy_hqFguu2)

#### Channels - If creating manually

If you are creating a channel manually, click on the green **+ Channel** near the bottom left.&#x20;

For **basic info** give a channel name, and a brief description. In this example we are going to use the admin API, so you could call the channel **Santedb MPI Admin**

For r**equest matching** there are two things you need to do

* enter a URL pattern (in our case **/ami**) - make sure you unclick Auto-add regex delimiters
* Make the channel public

![](/files/-MdTHNbHyAN2xCdFO9zH)

Finally, for **Routes**, add a new route with the following info:

* Route Name: SanteDB Admin
* Host: santedb-mpi (this is referencing the docker container name)
* Port: 8080 (this is referencing the **internal** docker port on the container)
* Forward existing Authorization Headers: yes

Click set route.&#x20;

![](/files/-MdTI6n9S-88PdvZL5mM)

####

### Run on Kubernetes

Navigate to the OpenHIE/Instant repository. Type the following commands

```
yarn
yarn docker:build
```

Next we need to run the images

```
yarn docker:instant init -t k8s santempi -c="<path to santedb package>"
```

The above command is specifying to run docker, specifying the package santempi (Which will link to the **id** property of the instant.json file), and specifying a path of where to find the image. The only difference between this and docker, is you're changing the keyword 'docker' to 'k8s'.

The kubernetes deployments will take much longer to build than the docker deployments. Afterwards it will look something like the following image (Note: This might change depending on what packages you're running)

![](/files/-MgQdrmlzXeHY6Vv4ljH)

You can navigate to <http://localhost:9000> and be brought to the login screen.&#x20;

* default username is: <root@openhim.org>
* default password is: instant101

**Manually Adding Channels**

To manually add a santedb channel, once logged in, click on the channel section and the green **Channel +** button.&#x20;

Adding a channel is almost identical to docker. (See above) - The differences is when adding a route, instead of using the container name, as in docker, you will need to use the IP Address of the pod.&#x20;

To obtain the pod:

```
kubectl get pods
```

The pod we want is the santeDB pod, **santedb-66bf68f744-xpsnh** (This will change as the name is dynamic, but it should be prefixed with santedb)

```
kubectl describe pod santedb-66bf68f744-xpsnh
```

The above command will display the details of this pod. At the top of the JSON blob you can see the IP Address.

![](/files/-MgQgt1WrQQ2iGV0h4zq)

Now you can add the IP Address as the **host** for the route.

![](/files/-MgQhCQ4M17Y91DK7KMh)

One quick note when manually adding channels, you may need to check to ensure the role has permission to access the channel. You can check by clicking on the **Clients** tab on the left hand side. Check the role you are attempting to use, if you see an X over the santedb channels, you can click the **x** and it will change the permission.

&#x20;

![](/files/-MgS-1ukm5iUO8bkpsfn)

![](/files/-MgS-FrE8K1QmU0ICibK)

## Testing, and viewing transactions

We will now test to make sure we can see SanteDB transactions in openHIM. You will need to generate a bearer token in order to successfully access santedb services. We will test with an administrator account, so we will be using the SanteMPI Admin Channel.&#x20;

**To generate a bearer token:**

SanteDB requires that you use a bearer token to access services on the SanteDB server. For full documentation see the [OpenID Connect Documentation](/developers/service-apis/openid-connect#discovery-configuration). A quick method to authenticate yourself with:

```
POST http://localhost:8082/auth/oauth2_token HTTP/1.1
Content-Type: application/x-www-form-urlencoded
X-SanteDBClient-Claim: PolicyOverride=1;PurposeOfUse=EMERG
Host: mpi-test.local:8080
Content-Length: 112

grant_type=password&scope=2.25.3049340304933&username=administrator&password=Mohawk123&client_id=fiddler&client_secret=fiddler
```

### Testing the channels

To test we are going to make API calls using something like **Postman**, or maybe **curl.** For this demo I will use postman.&#x20;

Under the **Authorization** tab for postman, select type as **Bearer Token** - In the value, enter the bearer token that you have generated.&#x20;

We are going to make a simple **get** request using <http://localhost:5001/ami/SecurityUser>

{% hint style="info" %}
We're targeting port 5001 here, as this is one of the ports open in the openhim-core container. If successful, our request should redirect through the openhim-core, to santedb. And a transaction should have been created.&#x20;
{% endhint %}

You should see a 200 response. Now, go back to the OpenHIM console. You should see transactions being displayed. It will look similar to the image below:

![Transactions](/files/-MdTK3kyUTWOx1eC9UQu)

#### Congratulations, you have now verified your santedb package within the instant openhim!


# Using Virtual Appliances

SanteDB provides a number of virtual appliances to assist in the rapid deployment of service environments using Open Virtualization Appliance (OVA) files.

## Virtual Appliance Types

### Headless Server Environment

You should use the headless server environment virtual appliance when deploying an instance of SanteDB (and related solutions) for light production duty, or development. These virtual appliances include:

* Ubuntu Server 20.04
* Mono Framework 6.2
* PostgreSQL 10
* SanteDB iCDR Server
* SanteDB Administrative Portal

### Developer Environment

You should use the developer environment virtual appliances when you need to rapidly onboard developers. These virtual appliances contain not only the SanteDB iCDR and dCDR environments, but the SanteDB SDK tooling, and related software including:

* Ubuntu 20.04
* XFCE4 Desktop Environment
* MonoDevelop&#x20;
* PostgreSQL 10
* Visual Studio Code&#x20;
* DBeaver Community Edition
* SanteDB iCDR Server
* SanteDB dCDR Server
* SanteDB SDK

## Configuring the Virtual Appliances

### **Shell Access**

**User:** sante\
**Password:** SanteDB123\
After deploying and setting up the OVA, you should either:

* Setup a host entry or DNS entry for **santempi.local** which points to the IP address of the appliance in your environment, or
* Edit the /etc/nginx/sites-available/santedb file and edit the server\_name to use your own DNS entries

The service requires that port 80 and 8080 be opened to allow for administrative and API access from other hosts respectively.

### Initial Settings & Directories

| Setting               | Value                    |
| --------------------- | ------------------------ |
| SanteDB iCDR Location | /opt/santedb/server      |
| SanteDB dCDR Location | /opt/santedb/dcdr-www    |
| iCDR API Port         | <http://127.0.0.1:18080> |
| dCDR API Port         | <http://127.0.0.1:9200>  |
| API User              | Administrator            |
| API Password          | Mohawk123                |


# Installation Qualification

After installing a SanteDB iCDR product, such as SanteMPI or SanteIMS, there is often a need to validate that the software is setup and functioning correctly. This page provides reference materials for running these installation qualification tests.

## User Interface Testing

The Security Administration Testing wiki article provides test steps that users can perform to validate that the security environment of SanteDB is running correctly.&#x20;

If you're running the iCDR and the web host portal you can use the [User Interface Test Cases ](/installation/installation-1/deployment/installing-software/santedb-server/installation-qualification/security-administration-testing/test-cases-for-ui-1), if you're operating SanteDB iCDR in a headless environment the [Admin Console tests](broken://pages/-MdSCYZjHgQ82FZkFTqY) provide equivalent tests using the `sdbac` tooling.

## SanteMPI Functional Testing

If you've installed the SanteMPI solution you can use the [Master Patient Index / Client Registry](/installation/installation-1/deployment/installing-software/santedb-server/installation-qualification/fhir-interface-validation) test cases to validate your configuration of SanteMPI.

The test cases cover:

* [HL7 FHIR Test Cases ](/installation/installation-1/deployment/installing-software/santedb-server/installation-qualification/fhir-interface-validation/mpi-cr-test-cases-for-fhir)
* [HL7 Version 2 Test Cases](/installation/installation-1/deployment/installing-software/santedb-server/installation-qualification/fhir-interface-validation/mpi-cr-test-cases-for-hl7v2)

{% hint style="info" %}
It is important that you use the default configurations for SanteMPI when running these tests. Changes in configuration should be performed after the qualification testing is completed. This applies to:

* Matching Configuration Changes
* Queueing or Dispatching Changes
* Pub-Sub Behavior Changes
  {% endhint %}

## Security Environment Qualification

It is recommended that, after [Securing SanteDB APIs](/installation/installation-1/deployment/securing-the-apis) is performed that a complete network scan be performed to ensure that the attack surface area of the environment is minimal.

* [ ] Perform a security scan of the applications involved (see: [OWASP ZAP](https://www.zaproxy.org/download/)) to ensure SSL, XSS, CORS, and other web security practices have been configured appropriately
  * [ ] Add any blocking scripts to browser headers your Application Firewall may be adding
  * [ ] Ensure proper caching policies and login policies are in place

* [ ] Perform a network port scan/attach tool to ensure that opened ports and services are minimal (see: [NMAP](https://nmap.org/))
  * [ ] Ensure that only ports you want opened are open
  * [ ] Ensure that ports that are open are secured.

![](/files/KGI3w0owdWFzMiWPkXJA)

* [ ] Use OpenSSL to validate that your SSL certificates are properly configured

```
openssl s_client -connect demompi.santesuite.net:443 -showcerts
CONNECTED(00000003)
depth=2 C = BE, O = GlobalSign nv-sa, OU = Root CA, CN = GlobalSign Root CA
verify return:1
depth=1 C = BE, O = GlobalSign nv-sa, CN = AlphaSSL CA - SHA256 - G2
verify return:1
depth=0 CN = *.santesuite.net
verify return:1
---
Certificate chain
 0 s:CN = *.santesuite.net
   i:C = BE, O = GlobalSign nv-sa, CN = AlphaSSL CA - SHA256 - G2
```


# Master Patient Index / Client Registry Qualification

SanteDB with the MPI plugin (SanteMPI solution) supports the following interfaces for integration:

* IHE Patient Identity Cross Referencing for HL7v2 (IHE PIX)
* IHE Patient Demographics Query for HL7v2 (IHE PDQ)
* IHE Patient Identity Cross Referencing for Mobile (IHE PIXm)
* IHE Patient Demographics Query for Mobile (PDQm)
* IHE Patient Master Identity Registry (PIMR)

These tests are based on the [OpenHIE testing framework](https://wiki.ohie.org/display/resources/Testing+and+Conformance) for Client Registry.

## Contents

{% content-ref url="/pages/-MV3vBjvRH-xzfl\_c5X\_" %}
[MPI/CR Test Cases for FHIR](/installation/installation-1/deployment/installing-software/santedb-server/installation-qualification/fhir-interface-validation/mpi-cr-test-cases-for-fhir)
{% endcontent-ref %}

{% content-ref url="/pages/-MV3vNbgM4b1XrA4jmN7" %}
[MPI/CR Test Cases for HL7v2](/installation/installation-1/deployment/installing-software/santedb-server/installation-qualification/fhir-interface-validation/mpi-cr-test-cases-for-hl7v2)
{% endcontent-ref %}


# MPI/CR Test Cases for HL7v2

These test cases are based on the OpenHIE CR tests for HL7v2 transactions, and contain specific hints for SanteMPI.

## Security Configuration

All tests for HL7v2 should ensure they are using either:

* [Node authentication ](/developers/service-apis/hl7v2/hl7-authentication#node-authentication-using-x-509-certificates)- Meaning that an X.509 certificate environment has been configured on the MPI. Note that all device configurations should map the certificate to the credential for the device.
* [Msh8 Authentication](/developers/service-apis/hl7v2/hl7-authentication#msh-8-authentication) - Meaning that `MSH-8` should carry necessary authentication information to authenticate the sending node.

For more information on how HL7v2 messages are authenticated in SanteDB, please consult the [HL7 Authentication](/developers/service-apis/hl7v2/hl7-authentication) wiki article.


# TEST: OHIE-CR-02-HL7v2

Patient Identity Feed – Auto-fill CX.4 data

This test validates that the Client Registry is capable of populating the CX.4.1 from CX.4.2 and CX.4.3 or vice-versa given partial data in the CX.4 field. If configured to allow auto-resolution, then the authority of a message missing CX.4 should be assigned.

## Discussion

The primary basis for this test case is based in the nots for implementing ITI-8 (Patient Identity Feed) from the [IHE Technical Framework Vol 2a](https://profiles.ihe.net/ITI/TF/Volume2/ITI-8.html), specifically section `3.8.4.1.3`:

> If the PID-3.4 (assigning authority) component is not included in the message (as described in Section 3.8.4.1.2.3) the Patient Identifier Cross-reference Manager shall fill PID-3.4 prior to storing the ID information and performing its cross-referencing activities. The information filled by the Patient Identifier Cross-reference Manager is based on the configuration associating each of the Patient Identity Source Actors with the subcomponents of the correct assigning authority (namespace ID, UID and UID type). (See Section 3.8.4.1.3.1 below for a list of required Patient Identifier Cross-reference Manager configuration parameters).

The cases which are tested in this test are:

* The client registry can cross reference PID-3-4-1 with PID-3-4-2 and PID-3-4-3 data
* Conversely, the client registry can cross reference PID-3-4-2 and PID-3-4-3 with PID-3-4-1
* The client registry, when configured, can auto-resolve PID-3-4 when it is missing.

## Pre-Conditions / Setup

Prior to executing this test, SanteMPI instances should configure:&#x20;

* The `TEST_HARNESS` application
* The `TEST_HARNESS|TEST` device
* The `TEST` identity domain is created and the authority to assign is set to `TEST_HARNESS`
* The SanteMPI instance is configured such that `strictCx4` is disabled

{% tabs %}
{% tab title="Dataset" %}

```markup
<dataset id="Test Domain" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://santedb.org/data">
  <insert skipIfError="false" skipIfExists="true">
    <SecurityApplication xmlns="http://santedb.org/model">
      <id>F0FC4322-948D-4986-A06C-DA603A77EDDE</id>
      <!-- Secret: TEST_HARNESS -->
      <applicationSecret>b5547020757c0efa3f320fbd2a0c43d0628e19b8cd81652523b87d31fc54f5ec</applicationSecret>
      <name>TEST_HARNESS</name>
    </SecurityApplication>
  </insert>
  <insert skipIfError="false" skipIfExists="true">
    <SecurityDevice xmlns="http://santedb.org/model">
      <id>508d9d71-54a3-4d67-897a-e2a395961395</id>
      <!-- Secret: TEST_HARNESS -->
      <deviceSecret>b5547020757c0efa3f320fbd2a0c43d0628e19b8cd81652523b87d31fc54f5ec</deviceSecret>
      <name>TEST_HARNESS|TEST</name>
    </SecurityDevice>
  </insert>
  <!-- TEST -->
  <insert skipIfError="false" skipIfExists="true">
    <AssigningAuthority xmlns="http://santedb.org/model">
      <name>OHIE TEST Domain</name>
      <domainName>TEST</domainName>
      <oid>2.16.840.1.113883.3.72.5.9.1</oid>
      <url>http://ohie.org/test/test</url>
      <isUnique>true</isUnique>
      <assigningApplication>F0FC4322-948D-4986-A06C-DA603A77EDDE</assigningApplication>
    </AssigningAuthority>
  </insert>
```

{% endtab %}

{% tab title="SDBAC" %}

```
> application.add TEST_HARNESS -s TEST_HARNESS
> device.add TEST_HARNESS|TEST -s TEST_HARNESS
> application.info TEST_HARNESS
> aa.add -n TEST -o 2.16.840.1.113883.3.72.5.9.1 -u http://ohie.org/test/test -d 'OpenHIE Test Domain' -a TEST_HARNESS 
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
If the SanteMPI instance is configured to use Msh8 security and not node authentication, then the `MSH-8` value of all test messages must contain `TEST_HARNESS+TEST_HARNESS`
{% endhint %}

## Register Patient with CX.4.2 and CX.4.3

Test harness sends ADT^A01 message where the CX.4.1 of the PID is missing but the message contains CX.4.2 and CX.4.3. The client registry should use the information in the registration of the authority to fill the other components on the validation step of this test.&#x20;

```
MSH|^~\&|TEST_HARNESS|TEST|CR1|MOH_CAAT|20141104174451||ADT^A01^ADT_A01|TEST-CR-02-10|P|2.3.1
EVN||20101020
PID|||RJ-438^^^&2.16.840.1.113883.3.72.5.9.1&ISO||JOHNSTON^ROBERT^^^^^L|MURRAY^^^^^^L|19830205|M|||1220 Centennial Farm Road^^ELLIOTT^IA^51532||^PRN^PH^^^712^7670867||||||481-27-4185
PV1||I
```

### Expected Behaviour

* Receiver Accepts Message with an AA
* Response is ACK^A01
* Response is version 2.3.1
* MSH-5 and MSH-6 matches `TEST_HARNESS|TEST`

## Validate Auto-Fill of CX.1

Test harness ensures that patient was registered and receiver has populated CX.4.1 from the CX.4.2 and CX.4.3 values executing.

```
MSH|^~\&|TEST_HARNESS|TEST|CR1|MOH_CAAT|20090223144546||QBP^Q23^QBP_Q21|TEST-CR-02-20|P|2.5
QPD|IHE PIX Query|Q0220|RJ-438^^^&2.16.840.1.113883.3.72.5.9.1&ISO^PI
RCP|I
```

### Expected Behaviour

* Receiver Accepts message with an `AA`
* Response is `RSP^K23`
* Response message contains exactly one PID segment
* `PID-3` of PID segment contains an identifier having:
  * `PID.3.4.1` = TEST
  * `PID.3.4.2` = 2.16.840.1.113883.3.72.5.9.1
  * `PID.3.4.3` = ISO

## Register Patient with CX.4.1

Test harness sends ADT^A01 message where the CX.4.2 and CX.4.3 of the PID are missing but the message contains CX.4.1

```
MSH|^~\&|TEST_HARNESS|TEST|CR1|MOH_CAAT|20141104174451||ADT^A01^ADT_A01|TEST-CR-02-30|P|2.3.1
EVN||20101020
PID|||RJ-439^^^TEST||JONES^JENNIFER^^^^^L|SMITH^^^^^^L|19840125|F|||123 Main Street West ^^NEWARK^NJ^30293||^PRN^PH^^^409^30495||||||
PV1||I
```

### Expected Behaviour

* Receiver Accepts Message with an AA
* MSH-5 and MSH-6 matches `TEST_HARNESS|TEST`

## Validate Patient with CX.4.2 and CX.4.3

Test harness ensures patient was registered and receiver has populated CX.4.2 and CX.4.3 from the CX.4.1 value provided by executing:

```
MSH|^~\&|TEST_HARNESS|TEST|CR1|MOH_CAAT|20090223144546||QBP^Q23^QBP_Q21|TEST-CR-02-40|P|2.5
QPD|IHE PIX Query|Q0220|RJ-439^^^TEST^PI
RCP|I
```

### Expected Behaviour

* Receiver Accepts message with an AA
* Response message contains exactly one PID segment
* PID-3 of PID segment contains an identifier having:
  * `PID.3.4.1` = TEST
  * `PID.3.4.2` = 2.16.840.1.113883.3.72.5.9.1
  * `PID.3.4.3` = ISO

## Register Patient with no CX.4

The test harness sends a patient registration request with no CX.4 populated. Since `TEST_HARNESS|TEST` is configured to be the only assigner of `TEST` the client registry must fill the missing components of CX.4.

```
MSH|^~\&|TEST_HARNESS|TEST|CR1|MOH_CAAT|20141104174451||ADT^A01^ADT_A01|TEST-CR-02-30|P|2.3.1
EVN||20101020
PID|||RJ-499^^^TEST||JONES^ROBERT^^^^^L|BUKOWSKI^^^^^^L|19390125|F|||123 Main Street East^^NEWARK^NJ^30293||^PRN^PH^^^409^0394938||||||
PV1||I
```

### Expected Behaviour

* Receiver accepts message with an `AA`
* MSH-5 and MSH-6 contain `TEST_HARNESS|TEST`

## Validate Auto-Fill of CX.4

Test harness ensures that the patient was registered on client registry an CX.4 is populated based on the sender.

```
MSH|^~\&|TEST_HARNESS|TEST|CR1|MOH_CAAT|20090223144546||QBP^Q23^QBP_Q21|TEST-CR-02-40|P|2.5
QPD|IHE PIX Query|Q0220|RJ-499^^^TEST^PI
RCP|I
```

### Expected Behaviour

* Receiver Accepts message with an AA
* Response message contains exactly one PID segment
* PID-3 of PID segment contains an identifier having:
  * `PID.3.4.1` = TEST
  * `PID.3.4.2` = 2.16.840.1.113883.3.72.5.9.1
  * `PID.3.4.3` = ISO


# TEST: OHIE-CR-03-HL7v2

Patient Identity Feed – Blocks unknown assigning authority

This test ensures that the receiver rejects messages which contain identifiers assigned from authorities which are unknown.

## Discussion

It is expected that a patient identity cross reference manager will ensure that data is valid prior to recording patient registrations and performing cross reference functions.&#x20;

The lack of configuration for an identity domain being received by an identity source indicates a misconfiguration of the MPI and/or the identity source. This test ensures that configuration is consistent within a jurisdiction.

## Pre-Conditions / Setup

In order to mimic a mis-configuration of the client registry, the environment should ensure that the domain `TEST_BLOCK` and OID `2.16.840.1.113883.3.72.5.9.4` are not present.

{% hint style="info" %}
If the SanteMPI instance is configured to use Msh8 security and not node authentication, then the `MSH-8` value of all test messages must contain `TEST_HARNESS+TEST_HARNESS`
{% endhint %}

## Attempt Registration with invalid OID

Test harness sends ADT^A01 message having the invalid OID in CX.4.2.

```
MSH|^~\&|TEST_HARNESS|TEST|CR1|MOH_CAAT|20141104174451||ADT^A01^ADT_A01|TEST-CR-03-10|P|2.3.1
EVN||20101020
PID|||RJ-999-2^^^&2.16.840.1.113883.3.72.5.9.4&ISO||THAMES^ROBERT^^^^^L| |1983|M|||1220 Centennial Farm Road^^ELLIOTT^IA^51532||^PRN^PH^^^712^7670867||||||481-27-4185
PV1||I
```

### Expected Behaviour

* Receiver rejects message with error code AE or AR
* MSH-5 and MSH-6 matches “TEST\_HARNESS|TEST”
* Meaning MSA or ERR segment is conveyed showing the error
* Response is ACK^A01
* Response Version is 2.3.1

## Attempt Registration with invalid NamespaceID

Test harness sends ADT^A01 message having invalid assigning authority name in CX.4.1

```
MSH|^~\&|TEST_HARNESS^^|TEST^^|CR1^^|MOH_CAAT^^|20141104174451||ADT^A01^ADT_A01|TEST-CR-03-20|P|2.3.1
EVN||20101020
PID|||RJ-999-2^^^TEST_BLOCK||THAMES^ROBERT^^^^^L| |1983|M|||1220 Centennial Farm Road^^ELLIOTT^IA^51532||^PRN^PH^^^712^7670867||||||481-27-4185
PV1||I
```

### Expected Behaviour

* Receiver rejects message with error code AE or AR
* MSH-5 and MSH-6 matches “TEST\_HARNESS|TEST”
* Meaning MSA or ERR segment is conveyed showing the error
* Response is ACK^A01
* Response Version is 2.3.1


# TEST: OHIE-CR-04-HL7v2

Patient Identity Feed – Blocks invalid assigning authority

This test ensures that two sources cannot assign identifiers from the other’s assigning domain. In this test, the harness mimics two authorities (TEST\_HARNESS\_A and TEST\_HARNESS\_B). They each register a patient and the harness then verifies that TEST\_HARNESS\_B does not assign an identifier from TEST\_HARNESS\_A’s identity domain.

## Discussion

While not a hard requirement of the IHE Patient Identity Cross Referencing specification, it is important to ensure that identity sources are governed in a manner which ensures that cross-domain registrations/merges/modifications are performed.&#x20;

[IHE ITI-8 TF Vol 2a](https://profiles.ihe.net/ITI/TF/Volume2/ITI-8.html) indicates that the association of identity sources with their assigning authority be a supported feature, particularly in section 3.8.4.1.3.1:

> Patient Identity Source for the domain. This is expected to be the MSH-3 Sending Application and the corresponding MSH-4 Sending Facility fields in the HL7 ADT message. (Alternative identification schemes might include IP address of the Patient Identity Source or Node Authentication if the Audit Trail and Node Authentication Integration Profile is used.)

{% hint style="info" %}
This test represents a test of the ability of the client registry to perform basic governance of data submissions. This test case may not be a requirement in all jurisdictions.&#x20;
{% endhint %}

## Pre-Conditions / Setup

Prior to executing the tests in this test case, the system under test should be configured such that:

* Application `TEST_HARNESS_A` is configured
* Application `TEST_HARNESS_B` is configured
* Device `TEST_HARNESS_A|TEST` is configured&#x20;
* Device `TEST_HARNESS_B|TEST` is configured
* Authority `TEST_A` with OID `2.16.840.1.113883.3.72.5.9.2` is configured and `TEST_HARNESS_A` is granted authority to assign identifiers in this domain
* Authority `TEST_B` with OID `2.16.840.1.113883.3.72.5.9.3` is configured and `TEST_HARNESS_B` is granted authority to assign identifiers in this domain.

{% tabs %}
{% tab title="Dataset" %}

```markup
<dataset id="Test Domain" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://santedb.org/data">
  <insert skipIfError="false" skipIfExists="true">
    <SecurityApplication xmlns="http://santedb.org/model">
      <id>DE5BEC1E-8C41-4FF1-8E65-A39AC1DDAE60</id>
      <!-- Secret: TEST_HARNESS -->
      <applicationSecret>b5547020757c0efa3f320fbd2a0c43d0628e19b8cd81652523b87d31fc54f5ec</applicationSecret>
      <name>TEST_HARNESS_A</name>
    </SecurityApplication>
  </insert>
  <!-- TEST -->
  <insert skipIfError="false" skipIfExists="true">
    <AssigningAuthority xmlns="http://santedb.org/model">
      <name>OHIE TEST Domain A</name>
      <domainName>TEST_A</domainName>
      <oid>2.16.840.1.113883.3.72.5.9.2</oid>
      <url>http://ohie.org/test/test_a</url>
      <isUnique>true</isUnique>
      <assigningApplication>DE5BEC1E-8C41-4FF1-8E65-A39AC1DDAE60</assigningApplication>
    </AssigningAuthority>
  </insert>
  <insert skipIfError="false" skipIfExists="true">
    <SecurityApplication xmlns="http://santedb.org/model">
      <id>58275680-5129-4832-9668-131F76E8DFB6</id>
      <!-- Secret: TEST_HARNESS -->
      <applicationSecret>b5547020757c0efa3f320fbd2a0c43d0628e19b8cd81652523b87d31fc54f5ec</applicationSecret>
      <name>TEST_HARNESS_FHIR_B</name>
    </SecurityApplication>
  </insert>
  <!-- TEST -->
  <insert skipIfError="false" skipIfExists="true">
    <AssigningAuthority xmlns="http://santedb.org/model">
      <name>OHIE TEST Domain B</name>
      <domainName>TEST_B</domainName>
      <oid>2.16.840.1.113883.3.72.5.9.3</oid>
      <url>http://ohie.org/test/test_b</url>
      <isUnique>true</isUnique>
      <assigningApplication>58275680-5129-4832-9668-131F76E8DFB6</assigningApplication>
    </AssigningAuthority>
  </insert>
  
```

{% endtab %}

{% tab title="SDBAC" %}

```
> application.add TEST_HARNESS_A -s TEST_HARNESS
> device.add TEST_HARNESS_A|TEST -s TEST_HARNESS
> aa.add -n TEST_A -o 2.16.840.1.113883.3.72.5.9.2 -u http://ohie.org/test/test_a -d 'OpenHIE Test Domain A' -a TEST_HARNESS_A
> application.add TEST_HARNESS_B -s TEST_HARNESS
> device.add TEST_HARNESS_B|TEST -s TEST_HARNESS
> aa.add -n TEST_B -o 2.16.840.1.113883.3.72.5.9.3 -u http://ohie.org/test/test_b -d 'OpenHIE Test Domain B' -a TEST_HARNESS_B
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
If the SanteMPI instance is configured to use Msh8 security and not node authentication, then the `MSH-8` value of all test messages must contain `TEST_HARNESS+TEST_HARNESS`
{% endhint %}

## Register Patient in TEST\_A

Test harness (as `TEST_HARNESS_A`) sends `ADT^A01` registering a new patient with an identifier from `TEST_A` domain.

```
MSH|^~\&|TEST_HARNESS_A^^|TEST^^|CR1^^|MOH_CAAT^^|20141104174451||ADT^A01^ADT_A01|TEST-CR-04-20|P|2.3.1
EVN||20101020
PID|||RJ-439^^^TEST_A||JONES^JENNIFER^^^^^L|SMITH^^^^^^L|19840125|F|||123 Main Street West ^^NEWARK^NJ^30293||^PRN^PH^^^409^30495||||||
PV1||I
```

### Expected Behaviour

* Receiver Accepts Message with an `AA`
* MSH-5 and MSH-6 matches `TEST_HARNESS_A|TEST`
* Response is `ACK^A01`
* Response version is `2.3.1`

## Cross-Domain Registration in TEST\_A

Test harness (as `TEST_HARNESS_B`) attempts to send an `ADT^A01` for authority A.

```
MSH|^~\&|TEST_HARNESS_B^^|TEST^^|CR1^^|MOH_CAAT^^|20141104174451||ADT^A01^ADT_A01|TEST-CR-04-30|P|2.3.1
EVN||20101020
PID|||NFD-3049542-23^^^TEST_A||JONES^JENNIFER^^^^^L|SMITH^^^^^^L|19840125|F|||123 Main Street West ^^NEWARK^NJ^30293||^PRN^PH^^^409^30495||||||
PV1||I
```

### Expected Behaviour

* Receiver rejects the message with an `AE` or `AR`
* An MSA message exists with an appropriate error code
* `MSH-5` and `MSH-6` matches `TEST_HARNESS_B|TEST`
* Response is `ACK^A01`
* Response Version is 2.3.1


# TEST: OHIE-CR-05-HL7v2

Patient Identity Feed – Minimal data set

This test ensures that the receiver does not reject a message containing only an identifier, and one of gender, date of birth, mother’s identifier. This test makes no assertion about merging/matching patients

## Discussion

This test mimics the environment whereby a newborn demographic with minimal patient information (gender and date of birth) can be stored by the client registry and faithfully returned with an appropriate query to the interface.

This test validates the MPI/CR's ability to link a mother's record with a newborn's record, and to query that data back from the MPI. This option uses the Pediatrics Demographics Option in section `8.2.1` of the [IHE Patient Demographics Query](https://profiles.ihe.net/ITI/TF/Volume1/ch-8.html)&#x20;

{% hint style="info" %}
This test is only required if the Client Registry is implementing the Pediatrics option and supports the ability to query/link mothers with children.
{% endhint %}

## Pre-Conditions / Setup

All conditions from [OHIE-CR-02](/installation/installation-1/deployment/installing-software/santedb-server/installation-qualification/fhir-interface-validation/mpi-cr-test-cases-for-hl7v2/test-ohie-cr-02-hl7v2#pre-conditions-setup) should be completed prior to running this test suite.

{% hint style="info" %}
If the SanteMPI instance is configured to use Msh8 security and not node authentication, then the `MSH-8` value of all test messages must contain `TEST_HARNESS+TEST_HARNESS`
{% endhint %}

## Register Mother's Demographic

The test harness sends an ADT^A01 message with the mother's patient demographics

```
MSH|^~\&|TEST_HARNESS^^|TEST^^|CR1^^|MOH_CAAT^^|20141104174451||ADT^A01^ADT_A01|TEST-CR-05-10|P|2.3.1
EVN||20101020
PID|||RJ-439^^^TEST||JONES^JENNIFER^^^^^M|SMITH^^^^^^L|19840125|F|||123 Main Street West ^^NEWARK^NJ^30293||^PRN^PH^^^409^30495||||||
PV1||I
```

## Register Patient with Minimal Demographics

Test harness sends an ADT^A01 message with minimal data set containing information for a newborn with only an identifier, gender and date of birth. The PID-6 (Mother's Maiden Name), PID-21 (Mother's Identifier), and PID-24 (Multiple Birth Indicator).

```
MSH|^~\&|TEST_HARNESS^^|TEST^^|CR1^^|MOH_CAAT^^|20141104174451||ADT^A01^ADT_A01|TEST-CR-05-20|P|2.3.1
EVN||20141001
PID|||RJ-441^^^TEST|||JONES^JENNIFER|20141001|M|||||||||||||RJ-439^^^TEST|||1 
PV1||I
```

### Expected Behaviour

* Receiver Accepts Message with an `AA`
* MSH-5 and MSH-6 matches `TEST_HARNESS|TEST`
* Response is `ACK^A01`
* Response is version `2.3.1`

## Query for Minimal Patient using Patient's Identifier

Test harness verifies the infant record was created in the receiver.

```
MSH|^~\&|TEST_HARNESS|TEST|CR1|MOH_CAAT|20090223144546||QBP^Q23^QBP_Q21|TEST-CR-05-30|P|2.5
QPD|IHE PIX Query|Q0530|RJ-441^^^TEST^PI
RCP|I
```

### Expected Behaviour

* Receiver responds with an `AA`
* Receiver sends exactly one `PID` segment with identifier `RJ-441` in domain `TEST` in PID-3

## Query for Newborn using Mother's Identifier

Test harness verifies the receiver can resolve the newborn demographic based on the identifier of the mother.

```
MSH|^~\&|TEST_HARNESS|TEST|CR1|MOH_CAAT|20090223144546||QBP^Q22^QBP_Q22|TEST-CR-05-30|P|2.5
QPD|Q22^Find Candidates^HL7|Q0540|@PID.21.1^RJ-439~@PID.21.3.4^TEST
RCP|I
```

### Expected Behaviour

* Receiver responds with an `AA`
* Receiver sends exactly one `PID` segment with identifier `RJ-441` in domain `TEST` in PID-3


# TEST: OHIE-CR-06-HL7v2

Patient Identity Feed – Update based on matching NID

This test ensures that the receiver is able to merge patient data from an assigning authority (TEST\_A) which has an national patient identifier (assigning authority NID). The demographics data does not match, this is to test that matching is done on explicit identifiers.

## References

## Pre-Conditions / Setup

#### Setup the receiver such that OID 2.16.840.1.113883.3.72.5.9.2 has assigning authority of TEST\_A which can be assigned from TEST\_HARNESS\_A

#### Setup the receiver such that OID 2.16.840.1.113883.3.72.5.9.9 has assigning authority of NID which can be assigned from NID\_AUTH

#### Ensure that the following patient is registered in the receiver (can be done with the ADT message provided). Name: John Smith, id: NID-000345435^^^NID^NNXXX, gender: M, dob: 1980

```
MSH|^~\&|NID_AUTH^^|TEST^^|CR1^^|MOH_CAAT^^|20141104174451||ADT^A01^ADT_A01|TEST-CR-06-20|P|2.3.1
EVN||20101020
PID|||NID-000345435^^^NID^NNXXX||SMITH^JOHN^^^^^L||1980|M|||||||||||
PV1||I
```

## Test Step 1:

Test harness (as TEST\_HARNESS\_A) sends a registration message for patient Jon \[sic] Smith having a more specific date of birth, with NID of NID-000345435 and local identifier of TEST\_A of RJ-449.

```
MSH|^~\&|TEST_HARNESS_A^^|TEST^^|CR1^^|MOH_CAAT^^|20141104174451||ADT^A01^ADT_A01|TEST-CR-06-30|P|2.3.1
EVN||20141001
PID|||RJ-449^^^TEST_A^PI~NID-000345435^^^NID^PI||SMITH^JON^^^^^L||198005|M|||||||||||||
PV1||I
```

### Expected Behaviour

* Receiver Accepts Message with an AA
* MSH-5 and MSH-6 matches “TEST\_HARNESS|TEST”

## Test Step 2

Test harness verifies the record was linked with the NID by executing a PIX query

```
MSH|^~\&|TEST_HARNESS_A|TEST|CR1|MOH_CAAT|20090223144546||QBP^Q23^QBP_Q21|TEST-CR-06-40|P|2.5 
QPD|IHE PIX Query|Q0640|NID-000345435^^^NID^PI
RCP|I
```

### Expected Behaviour

* Receiver responds with an AA
* Receiver sends exactly one PID segment with identifier RJ-449 in domain TEST\_A in one of the PID-3 repetitions


# TEST: OHIE-CR-07-HL7v2

Patient Identity Feed – Match with mother’s identifier

This test ensures that the receiver is able to match an incoming patient with their mother via the “Mother’s Identifier” property. In this test, the harness with register a patient (the mother) and subsequently will register an infant record (only dob, gender and id) with the mother’s identifier attached. The test will ensure that the link occurred by validating a demographic query contains the mother’s name.

## References

## Pre-Conditions / Setup

#### Setup the receiver such that OID 2.16.840.1.113883.3.72.5.9.1 has assigning authority of TEST which can be assigned from TEST\_HARNESS

#### Ensure that the following patient is registered in the receiver (can be done with the ADT message provided). Name: Jennifer Jones, id: RJ-439^^^TEST, gender: F, dob: 1984-01-25

```
MSH|^~\&|TEST_HARNESS^^|TEST^^|CR1^^|MOH_CAAT^^|20141104174451||ADT^A01^ADT_A01|TEST-CR-07-10|P|2.3.1
EVN||20101020
PID|||RJ-439^^^TEST||JONES^JENNIFER^^^^^L|SMITH^^^^^^L|19840125|F|||123 Main Street West ^^NEWARK^NJ^30293||^PRN^PH^^^409^30495||||||
PV1||I
```

### Test Step 1:

Test harness sends an ADT^A01 message with minimal data set containing information for a newborn with only an identifier, gender and date of birth with mother’s identifier.

```
MSH|^~\&|TEST_HARNESS^^|TEST^^|CR1^^|MOH_CAAT^^|20141104174451||ADT^A01^ADT_A01|TEST-CR-07-20|P|2.3.1
EVN||20101020
PID|||RJ-440^^^TEST||||20141001|M|||||||||||||RJ-439^^^TEST
PV1||I
```

### Expected Behaviour

* Receiver Accepts Message with an AA
* MSH-5 and MSH-6 matches “TEST\_HARNESS|TEST”

## Test Step 2:

Test harness verifies the infant record was created in the receiver.

```
MSH|^~\&|TEST_HARNESS|TEST|CR1|MOH_CAAT|20090223144546||QBP^Q23^QBP_Q21|TEST-CR-07-30|P|2.5 
QPD|IHE PIX Query|Q0530|RJ-440^^^TEST^PI
RCP|I
```

### Expected Behaviour

* Receiver responds with an AA
* Receiver sends exactly one PID segment with identifier RJ-440 in domain TEST in PID-3

## Test Step 3:

Test harness verifies the infant record has mother’s information attached to it by sending a PDQ message with infant’s identifier.

```
MSH|^~\&|TEST_HARNESS|TEST|CR1|MOH_CAAT|20090226131520-0600||QBP^Q22^QBP_Q21|TEST-CR-07-40|P|2.5
QPD|Q22^Find Candidates^HL7|Q0740|@PID.3.1^RJ-440~@PID.3.4.1^TEST
RCP|I|10^RD
```

### Expected Behaviour

* Receiver responds with an AA
* Receiver sends exactly one PID segment with identifier RJ-440 in domain TEST in PID-3
* Receiver conveys mother’s name in PID-6 with value of JONES^JENNIFER
* Receiver conveys mother’s identifier in PID-21 of RJ-439 in domain TEST


# TEST: OHIE-CR-08-HL7v2

Patient Identity Feed – Full patient record

This test ensures that the receiver is able to store and usefully convey (regurgitate) a more complete patient record having multiple names, addresses, telephone numbers, mother’s identifier, mother’s name, birth date, multiple birth order, etc.

## References

## Pre-Conditions / Setup

#### Setup the receiver such that OID 2.16.840.1.113883.3.72.5.9.1 has assigning authority of TEST which can be assigned from TEST\_HARNESS

## Test Step 1:

Test harness sends an ADT^A01 message with complex data set.

```
MSH|^~\&|TEST_HARNESS^^|TEST^^|CR1^^|MOH_CAAT^^|20141104174451||ADT^A01^ADT_A01|TEST-CR-08-10|P|2.3.1
EVN||20101020
PID|||RJ-442^^^TEST||FOSTER^FANNY^FULL^^^^L|FOSTER^MARY^^^^^L|1970|F|||123 W34 St^^FRESNO^CA^30495||^PRN^PH^^^419^31495|^^PH^^^034^059434|EN|S|||||
PV1||I
```

### Expected Behaviour

* Receiver Accepts Message with an AA
* MSH-5 and MSH-6 matches “TEST\_HARNESS|TEST”

## Test Step 2:

Test harness verifies demographics data matches by executing a PDQ query with the patient’s identifier.

```
MSH|^~\&|TEST_HARNESS|TEST|CR1|MOH_CAAT|20090226131520-0600||QBP^Q22^QBP_Q21|TEST-CR-08-30|P|2.5
QPD|Q22^Find Candidates^HL7|Q0740|@PID.3.1^RJ-442~@PID.3.4.1^TEST
RCP|I|10^RD
```

### Expected Behaviour

* Receiver responds with an AA
* Receiver sends exactly one PID segment with identifier RJ-442 in domain TEST in PID-3
* Receiver sends:
  * PID-5=FOSTER^FANNY^FULL^^^^L
  * PID-6=FOSTER^MARY^^^^^L
  * PID-7=1970
  * PID-8=F
  * PID-11=123 W34 St^^FRESNO^CA^20495
  * PID-13=^PRN^PH^^^419^31495
  * PID-14=^^PH^^^034^059434
  * PID-15=EN
  * PID-16=S


# TEST: OHIE-CR-09-HL7v2

Patient Identity Query – Identifier query

In this test, the test harness will register a patient with a local identifier (TEST domain) and will subsequently query the receiver to retrieve the identifiers linked to the newly registered patient.

## References

## Pre-Conditions / Setup

#### Setup the receiver so that OID 2.16.840.1.113883.3.72.5.9.1 has assigning authority of TEST

#### Setup the receiver so that OID 2.16.840.1.113883.3.72.5.9.9 has assigning authority of NID

## Test Step 1:

Test harness sends PIX query for identifier RJ-443 (an un-registered patient) and validates the receiver behaves appropriately.

```
MSH|^~\&|TEST_HARNESS|TEST|CR1|MOH_CAAT|20090223144546||QBP^Q23^QBP_Q21|TEST-CR-09-10|P|2.5 
QPD|IHE PIX Query|Q0910|RJ-443^^^TEST^PI
RCP|I
```

### Expected Behaviour

* Receiver accepts the message with AE
* Receiver conveys no data found with AE in QAK
* Receiver indicates error by sending an ERR segment with QPD^1^3^1^1

## Test Step 2:

Test harness sends PIX query for identifier RJ-443 (an un-registered patient) in domain RANDOM (an un-registered) domain

```
MSH|^~\&|TEST_HARNESS|TEST|CR1|MOH_CAAT|20090223144546||QBP^Q23^QBP_Q21|TEST-CR-09-20|P|2.5
QPD|IHE PIX Query|Q0920|RJ-443^^^RANDOM^PI
RCP|I
```

### Expected Behaviour

* Receiver rejects the message with AE
* Receiver conveys query error with AE in QAK
* Receiver indicates error by sending an ERR segment with QPD^1^3^4^1

## Test Step 3:

Test harness sends ADT^A01 message registering a patient.

```
MSH|^~\&|TEST_HARNESS^^|TEST^^|CR1^^|MOH_CAAT^^|20141104174451||ADT^A01^ADT_A01|TEST-CR-09-30|P|2.3.1
EVN||20101020
PID|||RJ-443^^^TEST||SMITH^STEPHANIE^^^^^L||198306|F|||
PV1||I
```

### Expected Behaviour

* Receiver Accepts Message with an AA
* MSH-5 and MSH-6 matches “TEST\_HARNESS|TEST”

## Test Step 4:

Test harness ensures that patient was registered by executing:

```
MSH|^~\&|TEST_HARNESS|TEST|CR1|MOH_CAAT|20090223144546||QBP^Q23^QBP_Q21|TEST-CR-09-40|P|2.5
QPD|IHE PIX Query|Q0940|RJ-443^^^TEST^PI
RCP|I
```

### Expected Behaviour

* Receiver Accepts message with an AA
* Response message contains exactly one PID segment
* QAK of OK
* PID-3 of PID segment contains an identifier having:
  * PID.3.1.1 = RJ-443
  * PID.3.4.1 = TEST
  * PID.3.4.2 = 2.16.840.1.113883.3.72.5.9.1
  * PID.3.4.3 = ISO


# TEST: OHIE-CR-10-HL7v2

Patient Identity Query – Identifier query with specific request response domains

In this test, the test harness will register a patient with a local identifier (TEST domain). The receiver is the assigning authority for the ECID domain and should generate an ECID by whatever means the software performs this task. The test harness will then ask the receiver to do a cross reference between the TEST domain and the ECID domain. This test ensures that the receiver adheres to the “What Domains Returned” query parameter.

## References

## Pre-Conditions / Setup

#### Setup the receiver so that OID 2.16.840.1.113883.3.72.5.9.1 has assigning authority of TEST

#### Setup the receiver so that OID 2.16.840.1.113883.3.72.5.9.9 has assigning authority of NID

#### Ensure a patient with the following information is registered in the receiver:Name: Betty Boop, ID: RJ-444 in domain TEST, DOB: 1935This can be registered by sending the following message to the recipient:

```
MSH|^~\&|TEST_HARNESS^^|TEST^^|CR1^^|MOH_CAAT^^|20141104174451||ADT^A01^ADT_A01|TEST-CR-09-30|P|2.3.1
EVN||20101020
PID|||RJ-444^^^TEST||BOOP^BETTY^^^^^L||1935|F|||
PV1||I
```

## Test Step 1:

Test harness requests the receiver to explicitly give it the TEST domain identifiers by sending:

```
MSH|^~\&|TEST_HARNESS|TEST|CR1|MOH_CAAT|20090223144546||QBP^Q23^QBP_Q21|TEST-CR-10-20|P|2.5 
QPD|IHE PIX Query|Q1020|RJ-444^^^TEST^PI|^^^TEST
RCP|I
```

### Expected Behaviour

* Receiver Accepts message with an AA
* QAK of OK
* Response message contains exactly one PID segment
* PID contains exactly one PID-3 having:
  * PID.3.1.1 = RJ-444
  * PID.3.4.1 = TEST
  * PID.3.4.2 = 2.16.840.1.113883.3.72.5.9.1

## Test Step 2:

Test harness requests the receiver to explicitly give it the domain identifiers from an invalid domain (RANDOM) by sending:

```
MSH|^~\&|TEST_HARNESS|TEST|CR1|MOH_CAAT|20090223144546||QBP^Q23^QBP_Q21|TEST-CR-10-30|P|2.5
QPD|IHE PIX Query|Q1030|RJ-444^^^TEST^PI|^^^RANDOM
RCP|I
```

### Expected Behaviour

* Receiver rejects the message with an AE
* Receiver indicates query error with QAK of AE
* Receiver indicates the error with ERR having QPD^1^4

## Test Step 3:

Test harness requests the receiver to explicitly give it the domain identifier from a valid domain (NID) for which no identifiers have been associated with the patient by sending:

```
MSH|^~\&|TEST_HARNESS|TEST|CR1|MOH_CAAT|20090223144546||QBP^Q23^QBP_Q21|TEST-CR-10-40|P|2.5
QPD|IHE PIX Query|Q1040|RJ-444^^^TEST^PI|^^^NID
RCP|I
```

### Expected Behaviour:

* Receiver accepts the message with AA
* Receiver indicates no data found with QAK of NF
* No PID segments are sent in the response message.


# TEST: OHIE-CR-11-HL7v2

Patient Demographics Query – Identifier query

This test case ensures that the recipient of the query can perform a patient demographics query based on the PID-3 values provided in an admit message.

## References

## Pre-Conditions / Setup

#### Setup the receiver so that OID 2.16.840.1.113883.3.72.5.9.1 has assigning authority of TEST

#### Setup the receiver so that OID 2.16.840.1.113883.3.72.5.9.9 has assigning authority of NID

#### Ensure that the following patient is registered in the receiver (can be done with the ADT message provided). Name: Jennifer Jones, id: RJ-439^^^TEST, gender: F, dob: 1984-01-25

```
MSH|^~\&|TEST_HARNESS^^|TEST^^|CR1^^|MOH_CAAT^^|20141104174451||ADT^A01^ADT_A01|TEST-CR-11-10|P|2.3.1
EVN||20101020
PID|||RJ-439^^^TEST||JONES^JENNIFER^^^^^L|SMITH^^^^^^L|19840125|F|||123 Main Street West ^^NEWARK^NJ^30293||^PRN^PH^^^409^30495||||||
PV1||I
```

## Test Step 1:

Test harness sends a PDQ message containing a patient identifier which is known to the receiver:

```
MSH|^~\&|TEST_HARNESS|TEST|CR1|MOH_CAAT|20090226131520-0600||QBP^Q22^QBP_Q21|TEST-CR-11-20|P|2.5
QPD|Q22^Find Candidates^HL7|Q1120|@PID.3.1^RJ-439~@PID.3.4.1^TEST
RCP|I|10^RD
```

### Expected Behaviour

* Receiver Accepts Message with an AA
* QAK segment contains OK
* Response contains a PID segment containing:
  * PID-3=439^^^TEST
  * PID-5=JONES^JENNIFER
  * PID-6=19840125

## Test Step 2:

Test harness sends a PDQ message containing a patient identifier which is unknown to the receiver:

```
MSH|^~\&|TEST_HARNESS|TEST|CR1|MOH_CAAT|20090226131520-0600||QBP^Q22^QBP_Q21|TEST-CR-11-30|P|2.5
QPD|Q22^Find Candidates^HL7|Q1130|@PID.3.1^RJ-9483~@PID.3.4.1^TEST
RCP|I|10^RD
```

### Expected Behaviour

* Receiver accepts the message with AA
* QAK segment contains NF
* Response contains no PID segments

## Test Step 3:

Test harness sends a PDQ message with an invalid query parameter of @PID.3.4.99

```
MSH|^~\&|TEST_HARNESS|TEST|CR1|MOH_CAAT|20090226131520-0600||QBP^Q22^QBP_Q21|TEST-CR-11-40|P|2.5
QPD|Q22^Find Candidates^HL7|Q1140|@PID.3.1^RJ-9483~@PID.3.4.99^NOVALUE
RCP|I|10^RD
```

### Expected Behaviour

* Receiver rejects the message with AR or AE
* QAK segment contains AE
* Response contains no PID segments

## Test Step 4:

Test harness sends a PDQ message and specifies what domains should be returned in the QPD-8 containing a valid domain of TEST

```
TESTMSH|^~\&|TEST_HARNESS|TEST|CR1|MOH_CAAT|20090226131520-0600||QBP^Q22^QBP_Q21|TEST-CR-11-50|P|2.5
QPD|Q22^Find Candidates^HL7|Q1150|@PID.3.1^RJ-439~@PID.3.4.1^TEST|||||^^^TEST
RCP|I|10^RD
```

### Expected Behaviour

* Receiver accepts message with an AA
* QAK segment contains OK
* Response contains exactly one PID segment
  * PID-3 (Exactly one)=439^^^TEST
  * PID-5=JONES^JENNIFER
  * PID-6=19840125

## Test Step 5:

Test harness sends a PDQ message and specifies what domains should be returned in QPD-8 with a valid domain of NID which has no matching identifiers.

```
MSH|^~\&|TEST_HARNESS|TEST|CR1|MOH_CAAT|20090226131520-0600||QBP^Q22^QBP_Q21|TEST-CR-11-60|P|2.5
QPD|Q22^Find Candidates^HL7|Q1160|@PID.3.1^RJ-439~@PID.3.4.1^TEST|||||^^^NID
RCP|I|10^RD
```

### Expected Behaviour

* Receiver accepts message with an AA
* QAK segment contains NF
* No PID segments are returned in the response

## Test Step 6:

Test harness sends a PDQ message and specifies what domains should be returned in QPD-8 with an invalid domain of RANDOM.

```
MSH|^~\&|TEST_HARNESS|TEST|CR1|MOH_CAAT|20090226131520-0600||QBP^Q22^QBP_Q21|TEST-CR-11-70|P|2.5
QPD|Q22^Find Candidates^HL7|Q1170|@PID.3.1^RJ-439~@PID.3.4.1^TEST|||||^^^RANDOM
RCP|I|10^RD
```

### Expected Behaviour

* Receiver rejects the message with AE
* Receiver indicates query error with QAK of AE
* No PID segments are returned
* Receiver indicates QPD^1^8 in the ERR segment


# TEST: OHIE-CR-12-HL7v2

Patent Demographics Query – Query by name

This test ensures that the recipient of the query can perform an exact match on a patient’s name as provided in an admit message. The test will additionally test partial matching using phonetics and patterns. The recipient must pass one of the phonetic or pattern matching cases.

## References

## Pre-Conditions / Setup

#### Setup the receiver so that OID 2.16.840.1.113883.3.72.5.9.1 has assigning authority of TEST

#### Setup the receiver so that OID 2.16.840.1.113883.3.72.5.9.9 has assigning authority of NID

#### Ensure that the following patient is registered in the receiver (can be done with the ADT message provided). Name: Jennifer Jones, id: RJ-439^^^TEST, gender: F, dob: 1984-01-25

```
MSH|^~\&|TEST_HARNESS^^|TEST^^|CR1^^|MOH_CAAT^^|20141104174451||ADT^A01^ADT_A01|TEST-CR-12-10|P|2.3.1
EVN||20101020
PID|||RJ-439^^^TEST||JONES^JENNIFER^^^^^L|SMITH^^^^^^L|19840125|F|||123 Main Street West ^^NEWARK^NJ^30293||^PRN^PH^^^409^30495||||||

```

## Test Step 1:

Test harness sends a PDQ message containing a name which is known to the receiver:

```
MSH|^~\&|TEST_HARNESS|TEST|CR1|MOH_CAAT|20090226131520-0600||QBP^Q22^QBP_Q21|TEST-CR-12-20|P|2.5
QPD|Q22^Find Candidates^HL7|Q1220|@PID.5.1^JONES~@PID.5.2^JENNIFER
RCP|I|10^RD
```

### Expected Behaviour

* Receiver Accepts Message with an AA
* QAK segment contains OK
* Response contains a PID segment containing:
  * Response contains a PID segment containing:
  * PID-5=JONES^JENNIFER
  * PID-6=19840125

## Test Step 2:

Test harness sends a PDQ message containing a patient name which is unknown to the receiver:

```
MSH|^~\&|TEST_HARNESS|TEST|CR1|MOH_CAAT|20090226131520-0600||QBP^Q22^QBP_Q21|TEST-CR-12-30|P|2.5
QPD|Q22^Find Candidates^HL7|Q1230|@PID.5.1^HOOD~@PID.5.2^ROBIN
RCP|I|10^RD
```

### Expected Behaviour

* Receiver accepts the message with AA
* QAK segment contains NF
* Response contains no PID segments

## Test Step 3:

Test harness sends a PDQ message containing a name which is known to the receiver, and indicates a domains to be returned of TEST in QPD-8.

```
MSH|^~\&|TEST_HARNESS|TEST|CR1|MOH_CAAT|20090226131520-0600||QBP^Q22^QBP_Q21|TEST-CR-12-40|P|2.5
QPD|Q22^Find Candidates^HL7|Q1240|@PID.5.1^JONES~@PID.5.2^JENNIFER|||||^^^TEST
RCP|I|10^RD
```

### Expected Behaviour

* Receiver Accepts Message with an AA
* QAK segment contains OK
* Response contains exactly one PID segment containing:
  * PID-3 (Exactly one)=439^^^TEST
  * PID-5=JONES^JENNIFER
  * PID-6=19840125

## Test Step 4:

Test harness sends a PDQ message containing a patient name which is known to the receiver and indicates a domains to be returned which is invalid in QPD-8:

```
MSH|^~\&|TEST_HARNESS|TEST|CR1|MOH_CAAT|20090226131520-0600||QBP^Q22^QBP_Q21|TEST-CR-12-45|P|2.5
QPD|Q22^Find Candidates^HL7|Q1245|@PID.5.1^JONES~@PID.5.2^JENNIFER|||||^^^RANDOM
RCP|I|10^RD
```

### Expected Behaviour:

* Receiver rejects the message with AE
* Receiver indicates query error with QAK of AE
* No PID segments are returned
* Receiver indicates QPD^1^8 in the ERR segment

## Test Step 5:

```
MSH|^~\&|TEST_HARNESS|TEST|CR1|MOH_CAAT|20090226131520-0600||QBP^Q22^QBP_Q21|TEST-CR-12-50|P|2.5
QPD|Q22^Find Candidates^HL7|Q1250|@PID.5.1^JO*~@PID.5.2^JEN*|||||
RCP|I|10^RD
```

### Expected Behaviour

* Receiver accepts the message with an AA
* Receiver indicates query success of OK in QAK
* Receiver returns at least one PID segment containing the match for Jennifer Jones
* Receiver sends a QRI segment with a QRI-3 indicating pattern match and strength of the match

## Test Step 6:

Test harness sends a PDQ message containing a phonetically equivalent name of a known patient to the receiver:Test harness sends a PDQ message containing a wildcard match which is known to the receiver:

```
MSH|^~\&|TEST_HARNESS|TEST|CR1|MOH_CAAT|20090226131520-0600||QBP^Q22^QBP_Q21|TEST-CR-12-60|P|2.5
QPD|Q22^Find Candidates^HL7|Q1260|@PID.5.1^JONEZ~@PID.5.2^JENIPHER|||||
RCP|I|10^RD
```

### Expected Behaviour

* Receiver accepts the message with an AA
* Receiver indicates query success of OK in QAK
* Receiver returns at least one PID segment containing the match for Jennifer Jones
* Receiver sends a QRI segment with a QRI-3 indicating phonetic match and strength of the match

## Test Step 7:

Test harness sends a PDQ message containing a name variant match which is known to the receiver:

```
MSH|^~\&|TEST_HARNESS|TEST|CR1|MOH_CAAT|20090226131520-0600||QBP^Q22^QBP_Q21|TEST-CR-12-70|P|2.5
QPD|Q22^Find Candidates^HL7|Q1270|@PID.5.1^JONES~@PID.5.2^JENN|||||
RCP|I|10^RD
```

### Expected Behaviour

* Receiver accepts the message with an AA
* Receiver indicates query success of OK in QAK
* Receiver returns at least one PID segment containing the match for Jennifer Jones
* Receiver sends a QRI segment with a QRI-3 indicating variant match and strength of the match


# TEST: OHIE-CR-13-HL7v2

Patient Demographics Query – Query by mother’s identifier

This test ensures that the recipient of the query can perform a query by the patient’s mother’s identifier.

## References

## Pre-Conditions / Setup

#### Setup the receiver such that OID 2.16.840.1.113883.3.72.5.9.1 has assigning authority of TEST which can be assigned from TEST\_HARNESS

#### Ensure that the following patient is registered in the receiver (can be done with the ADT message provided). Name: Jennifer Jones, id: RJ-439^^^TEST, gender: F, dob: 1984-01-25

```
MSH|^~\&|TEST_HARNESS^^|TEST^^|CR1^^|MOH_CAAT^^|20141104174451||ADT^A01^ADT_A01|TEST-CR-13-10|P|2.3.1
EVN||20101020
PID|||RJ-439^^^TEST||JONES^JENNIFER^^^^^L|SMITH^^^^^^L|19840125|F|||123 Main Street West ^^NEWARK^NJ^30293||^PRN^PH^^^409^30495||||||
PV1||I
```

#### Ensure that the following patient is registered in the receiver (can be done with the ADT message provided).RJ-440^^^TEST, gender: M, DOB: 2014-10-01

```
MSH|^~\&|TEST_HARNESS^^|TEST^^|CR1^^|MOH_CAAT^^|20141104174451||ADT^A01^ADT_A01|TEST-CR-13-15|P|2.3.1
EVN||20101020
PID|||RJ-440^^^TEST||||20141001|M|||||||||||||RJ-439^^^TEST
PV1||I
```

## Test Step 1:

Test harness sends a query with mother’s identifier components specified.

```
MSH|^~\&|TEST_HARNESS|TEST|CR1|MOH_CAAT|20090226131520-0600||QBP^Q22^QBP_Q21|TEST-CR-13-20|P|2.5
QPD|Q22^Find Candidates^HL7|Q1320|@PID.21.1^RJ-439~@PID.21.4.1^TEST
RCP|I|10^RD
```

### Expected Behaviour

* Receiver responds with an AA
* Receiver sends exactly one PID segment with identifier RJ-440 in domain TEST in PID-3

## Test Step 2:

Test harness verifies the infant record was created in the receiver.

```
MSH|^~\&|TEST_HARNESS|TEST|CR1|MOH_CAAT|20090226131520-0600||QBP^Q22^QBP_Q21|TEST-CR-13-30|P|2.5
QPD|Q22^Find Candidates^HL7|Q0740|@PID.6.1^JONES~@PID.6.2^JENNIFER
RCP|I|10^RD
```

### Expected Behaviour

* Receiver responds with an AA
* Receiver sends exactly one PID segment with identifier RJ-440 in domain TEST in PID-3


# TEST: OHIE-CR-14-HL7v2

Patient Demographics Query – Query by date of birth

This test ensures that the recipient supports the semantics of date matching and approximate matches by date range. This test case will query for an exact date of birth as provided in an admit message, and a fuzzy date of birth (year, and year/month).

## References

## Pre-Conditions / Setup

#### Setup the receiver such that OID 2.16.840.1.113883.3.72.5.9.1 has assigning authority of TEST which can be assigned from TEST\_HARNESS

#### Ensure that the following patient is registered in the receiver (can be done with the ADT message provided). Name: Jennifer Jones, id: RJ-439^^^TEST, gender: F, dob: 1984-01-25

```
MSH|^~\&|TEST_HARNESS^^|TEST^^|CR1^^|MOH_CAAT^^|20141104174451||ADT^A01^ADT_A01|TEST-CR-14-10|P|2.3.1
EVN||20101020
PID|||RJ-439^^^TEST||JONES^JENNIFER^^^^^L|SMITH^^^^^^L|19840125|F|||123 Main Street West ^^NEWARK^NJ^30293||^PRN^PH^^^409^30495||||||
PV1||I
```

## Test Step 1:

Test harness sends a query with date of birth precise to the year in which a patient’s date of birth falls.

```
MSH|^~\&|TEST_HARNESS|TEST|CR1|MOH_CAAT|20090226131520-0600||QBP^Q22^QBP_Q21|TEST-CR-14-20|P|2.5
QPD|Q22^Find Candidates^HL7|Q1420|@PID.7^1984
RCP|I|10^RD
```

### Expected Behaviour

* Receiver responds with an AA
* Receiver indicates records found with QAK of OK
* Receiver sends exactly one PID segment with identifier RJ-439 in domain TEST in PID-3

## Test Step 2:

Test harness sends a query with date of birth precise to the month in which the patient’s date of birth falls.

```
MSH|^~\&|TEST_HARNESS|TEST|CR1|MOH_CAAT|20090226131520-0600||QBP^Q22^QBP_Q21|TEST-CR-14-30|P|2.5
QPD|Q22^Find Candidates^HL7|Q1430|@PID.7^198401
RCP|I|10^RD
```

### Expected Behaviour

* Receiver responds with an AA
* Receiver indicates records found with QAK of OK
* Receiver sends exactly one PID segment with identifier RJ-439 in domain TEST in PID-3

## Test Step 3:

Test harness sends a query with date of birth precise to the day in which a patient’s date of birth falls.

```
MSH|^~\&|TEST_HARNESS|TEST|CR1|MOH_CAAT|20090226131520-0600||QBP^Q22^QBP_Q21|TEST-CR-14-40|P|2.5
QPD|Q22^Find Candidates^HL7|Q1440|@PID.7^19840125
RCP|I|10^RD
```

### Expected Behaviour

* Receiver responds with an AA
* Receiver indicates records found with QAK of OK
* Receiver sends exactly one PID segment with identifier RJ-439 in domain TEST in PID-3

## Test Step 4:

Test harness sends a query with date of birth precise to the year in which the patient’s date of birth does not fall.

```
MSH|^~\&|TEST_HARNESS|TEST|CR1|MOH_CAAT|20090226131520-0600||QBP^Q22^QBP_Q21|TEST-CR-14-50|P|2.5
QPD|Q22^Find Candidates^HL7|Q1450|@PID.7^1900
RCP|I|10^RD
```

### Expected Behaviour

* Receiver responds with an AA
* Receiver indicates no records found with QAK of NF
* Receiver sends no PID segments


# TEST: OHIE-CR-15-HL7v2

Patient Demographics Query – Query by multiple demographics fields

This test ensures that the recipient of the query can perform a query on a series of demographics fields. The test harness will perform a query on a series of combinations of parameters such as name + gender, name + date of birth, gender + date of birth.

## References

## Pre-Conditions / Setup

#### Setup the receiver such that OID 2.16.840.1.113883.3.72.5.9.1 has assigning authority of TEST which can be assigned from TEST\_HARNESS

#### Ensure that the following patient is registered in the receiver (can be done with the ADT message provided). Name: Jennifer Jones, id: RJ-439^^^TEST, gender: F, dob: 1984-01-25

```
Ensure that the following patient is registered in the receiver (can be done with the ADT message provided). Name: Jennifer Jones, id: RJ-439^^^TEST, gender: F, dob: 1984-01-25
EVN||20101020
PID|||RJ-439^^^TEST||JONES^JENNIFER^^^^^L|SMITH^^^^^^L|19840125|F|||123 Main Street West ^^NEWARK^NJ^30293||^PRN^PH^^^409^30495||||||
PV1||I
```

## Test Step 1:

Test harness sends a query with patient’s name and gender which results in a match.

```
MSH|^~\&|TEST_HARNESS|TEST|CR1|MOH_CAAT|20090226131520-0600||QBP^Q22^QBP_Q21|TEST-CR-15-20|P|2.5
QPD|Q22^Find Candidates^HL7|Q1520|@PID.8^F~@PID.5.1^JONES
RCP|I|10^RD
```

### Expected Behaviour

* Receiver responds with an AA
* Receiver indicates records found with QAK of OK
* Receiver sends exactly one PID segment with identifier RJ-439 in domain TEST in PID-3

## Test Step 2:

Test harness sends a query with fuzzy date of birth and patient’s name which results in a match.

```
MSH|^~\&|TEST_HARNESS|TEST|CR1|MOH_CAAT|20090226131520-0600||QBP^Q22^QBP_Q21|TEST-CR-15-30|P|2.5
QPD|Q22^Find Candidates^HL7|Q1530|@PID.7^1984~@PID.5.1^JONES~@PID.5.2^JENNIFER
RCP|I|10^RD
```

### Expected Behaviour

* Receiver responds with an AA
* Receiver indicates records found with QAK of OK
* Receiver sends exactly one PID segment with identifier RJ-439 in domain TEST in PID-3

## Test Step 3:

Test harness sends a query with date of birth precise to the day in which a gender which results in a match.

```
MSH|^~\&|TEST_HARNESS|TEST|CR1|MOH_CAAT|20090226131520-0600||QBP^Q22^QBP_Q21|TEST-CR-15-40|P|2.5
QPD|Q22^Find Candidates^HL7|Q1540|@PID.7^19840125~@PID.8^F
RCP|I|10^RD
```

### Expected Behaviour

* Receiver responds with an AA
* Receiver indicates records found with QAK of OK
* Receiver sends exactly one PID segment with identifier RJ-439 in domain TEST in PID-3

## Test Step 4:

Test harness sends a query with patient’s name and gender which results in no match.

```
MSH|^~\&|TEST_HARNESS|TEST|CR1|MOH_CAAT|20090226131520-0600||QBP^Q22^QBP_Q21|TEST-CR-15-50|P|2.5
QPD|Q22^Find Candidates^HL7|Q1550|@PID.8^M~@PID.5.1^JONES~@PID.5.2^JENNIFER
RCP|I|10^RD
```

### Expected Behaviour

* Receiver responds with an AA
* Receiver indicates no records found with QAK of NF
* Receiver sends no PID segments

## Test Step 5:

Test harness sends a query with fuzzy date of birth and patient’s name which results in no match.

```
MSH|^~\&|TEST_HARNESS|TEST|CR1|MOH_CAAT|20090226131520-0600||QBP^Q22^QBP_Q21|TEST-CR-15-60|P|2.5
QPD|Q22^Find Candidates^HL7|Q1560|@PID.7^1984~@PID.5.1^JONES~@PID.5.2^JASON
RCP|I|10^RD
```

### Expected Behaviour

* Receiver responds with an AA
* Receiver indicates no records found with QAK of NF
* Receiver sends no PID segments

###


# TEST: OHIE-CR-16-HL7v2

Valid Patient Identity Merge

This test will ensure that the client registry can appropriately handle a merge condition whereby a local assigning authority notifies the client registry of a local merge (two local identifiers are in fact the same person).

## References

## Pre-Conditions / Setup

#### Setup the receiver such that OID 2.16.840.1.113883.3.72.5.9.1 has assigning authority of TEST which can be assigned from TEST\_HARNESS

#### Ensure that the following patient is registered in the receiver (can be done with the ADT message provided). Name: Jennifer Jones, id: RJ-439^^^TEST, gender: F, dob: 1984-01-25

```
MSH|^~\&|TEST_HARNESS^^|TEST^^|CR1^^|MOH_CAAT^^|20141104174451||ADT^A01^ADT_A01|TEST-CR-16-10|P|2.3.1
EVN||20101020
PID|||RJ-439^^^TEST||JONES^JENNIFER^^^^^L|SMITH^^^^^^L|19840125|F|||123 Main Street West ^^NEWARK^NJ^30293||^PRN^PH^^^409^30495||||||
PV1||I
```

#### Ensure that the following patient is registered in the receiver (can be done with the ADT message provided). Name: Jenn Jones, id: RJ-999^^^TEST, gender: F, dob: 1984-01

```
MSH|^~\&|TEST_HARNESS^^|TEST^^|CR1^^|MOH_CAAT^^|20141104174451||ADT^A01^ADT_A01|TEST-CR-16-15|P|2.3.1
EVN||20101020
PID|||RJ-999^^^TEST||JONES^JENN^^^^^L||198401|F|||||||||||
PV1||I
```

## Test Step 1:

Test harness sends a query to verify there are two Jennifer Jones with identifiers assigned in TEST domain.

```
MSH|^~\&|TEST_HARNESS|TEST|CR1|MOH_CAAT|20090226131520-0600||QBP^Q22^QBP_Q21|TEST-CR-16-20|P|2.5
QPD|Q22^Find Candidates^HL7|Q1620|@PID.5.1^JONES|||||^^^TEST
RCP|I|10^RD
```

### Expected Behaviour

* Receiver responds with an AA
* Receiver indicates records found with QAK of OK
* Receiver sends two PID segments one having identifier RJ-439 in domain TEST in PID-3 and another having RJ-999 in domain TEST in PID-3

## Test Step 2:

Test harness sends a merge message and instructs the recipient to merge identifier RJ-999 into record RJ-439.

```
MSH|^~\&|TEST_HARNESS^^|TEST^^|CR1^^|MOH_CAAT^^|20141104174451||ADT^A40^ADT_A40|TEST-CR-16-30|P|2.3.1
EVN||20101020
PID|||RJ-439^^^TEST||JONES^JENN^^^^^L||198401|F|||||||||||
MRG|RJ-999^^^TEST
```

### Expected Behaviour

* Receiver responds with an AA

## Test Step 3:

Test harness verifies the identifier was merged using the following PIX query.

```
MSH|^~\&|TEST_HARNESS|TEST|CR1|MOH_CAAT|20090223144546||QBP^Q23^QBP_Q21|TEST-CR-16-40|P|2.5
QPD|IHE PIX Query|Q1640|RJ-439^^^TEST^PI|^^^TEST
RCP|I
```

### Expected Behaviour

* Receiver responds with an AA
* Receiver indicates data found by sending QAK of OK
* Receiver responds with exactly one PID segment having :
  * One PID-3 containing the RJ-439 identifier in domain TEST
  * One PID-3 containing the RJ-999 identifier in domain TEST

## Test Step 4:

Test harness verifies old identifier is de-referenced from patient record

```
MSH|^~\&|TEST_HARNESS|TEST|CR1|MOH_CAAT|20090223144546||QBP^Q23^QBP_Q21|TEST-CR-16-50|P|2.5
QPD|IHE PIX Query|Q1650|RJ-999^^^TEST^PI|^^^TEST
RCP|I
```

### Expected Behaviour

* Receiver accepts the message with AE
* Receiver conveys no data found with AE in QAK
* Receiver indicates error by sending an ERR segment with QPD^1^3^1^1

## Test Step 5:

Test harness may send a query to verify there are still two Jennifer Jones in the target (i.e. the old record still exists, but the identifiers were merely merged).

```
MSH|^~\&|TEST_HARNESS|TEST|CR1|MOH_CAAT|20090226131520-0600||QBP^Q22^QBP_Q21|TEST-CR-16-60|P|2.5
QPD|Q22^Find Candidates^HL7|Q1660|@PID.5.1^JONES
RCP|I|10^RD
```

### Expected Behaviour

* Receiver responds with an AA
* Receiver indicates records found with QAK of OK
* Receiver sends two PID segments one having identifier RJ-439 and RJ-999 in domain TEST in PID-3 and another having no identifiers in domain TEST in PID-3


# TEST: OHIE-CR-17-HL7v2

Patient Identity Merge No Assigning Authority

This test will ensure that the client registry appropriately handles a merge condition whereby the local authority has not assigning authority to perform or merge the identifiers provided. This test will also ensure that merges across assigning authorities cannot be performed

## References

## Pre-Conditions / Setup

#### Setup the receiver so that OID 2.16.840.1.113883.3.72.5.9.2 has assigning authority of TEST\_A which can be assigned from TEST\_HARNESS\_A

#### Setup the receiver so that OID 2.16.840.1.113883.3.72.5.9.3 has assigning authority of TEST\_B which can be assigned from TEST\_HARNESS\_B

#### Ensure that the following patient is registered in the receiver (can be done with the ADT message provided). Name: Sam Smith, id: RJ-203^^^TEST\_A, gender: F, dob: 1989-02-25

```
MSH|^~\&|TEST_HARNESS_A^^|TEST^^|CR1^^|MOH_CAAT^^|20141104174451||ADT^A01^ADT_A01|TEST-CR-17-15|P|2.3.1
EVN||20101020
PID|||RJ-203^^^TEST_A||SMITH^SAM^^^^^L||19890225|F|||||||||||
PV1||I
```

#### Ensure that the following patient is registered in the receiver (can be done with the ADT message provided). Name: Samantha Smith, id: RJ-292^^^TEST\_A, gender: F, dob: 1989-02

```
MSH|^~\&|TEST_HARNESS_A^^|TEST^^|CR1^^|MOH_CAAT^^|20141104174451||ADT^A01^ADT_A01|TEST-CR-17-20|P|2.3.1
EVN||20101020
PID|||RJ-292^^^TEST_A||SMITH^SAMANTHA^^^^^L||198902|F|||||||||||
PV1||I
```

#### Ensure that the following patient is registered in the receiver (can be done with the ADT message provided). Name: Samantha Smith, id: SJ-204^^^TEST\_B, gender: F, dob: 1989-02

```
MSH|^~\&|TEST_HARNESS_B^^|TEST^^|CR1^^|MOH_CAAT^^|20141104174451||ADT^A01^ADT_A01|TEST-CR-17-25|P|2.3.1
EVN||20101020
PID|||SJ-204^^^TEST_B||SMITH^SAMANTHA^^^^^L||198902|F|||||||||||
PV1||I
```

## Test Step 1:

Test harness (as TEST\_HARNESS\_B) sends ADT^A40 message attempting to merge identities from TEST\_A domain.

```
MSH|^~\&|TEST_HARNESS_B^^|TEST^^|CR1^^|MOH_CAAT^^|20141104174451||ADT^A40^ADT_A40|TEST-CR-17-30|P|2.3.1
EVN||20101020
PID|||RJ-203^^^TEST_A||SMITH^SAM^^^^^L||198902|F|||||||||||
MRG|RJ-292^^^TEST_A
```

### Expected Behaviour

* Receiver rejects message with an AE
* MSH-5 and MSH-6 matches “TEST\_HARNESS\_B|TEST”
* An ERR segment exists identifying the error

## Test Step 2:

Test harness (as TEST\_HARNESS\_B) sends ADT^A40 message attempting to merge across domains by instructing the receiver to merge an identifier from TEST\_A into TEST\_B.

```
MSH|^~\&|TEST_HARNESS_B^^|TEST^^|CR1^^|MOH_CAAT^^|20141104174451||ADT^A40^ADT_A40|TEST-CR-17-40|P|2.3.1
EVN||20101020
PID|||SJ-204^^^TEST_B||SMITH^SAM^^^^^L||198902|F|||||||||||
MRG|RJ-292^^^TEST_A
```

### Expected Behaviour

* Receiver rejects message with an AE or AR
* MSH-5 and MSH-6 matches “TEST\_HARNESS\_B|TEST”
* An ERR segment exists identifying the error

## Test Step 3:

Test harness (as TEST\_HARNESS\_B) sends ADT^A40 message attempting to merge a patient identifier which does not exist.

```
MSH|^~\&|TEST_HARNESS_B^^|TEST^^|CR1^^|MOH_CAAT^^|20141104174451||ADT^A40^ADT_A40|TEST-CR-17-50|P|2.3.1
EVN||20101020
PID|||SJ-204^^^TEST_B||SMITH^SAM^^^^^L||198902|F|||||||||||
MRG|RJ-292^^^TEST_B
```

### Expected Behaviour

* Receiver rejects message with an AE or AR
* MSH-5 and MSH-6 matches “TEST\_HARNESS\_B|TEST”
* An ERR segment exists identifying the error with HL7 code of 204 (key does not exist)


# TEST: OHIE-CR-18-HL7v2

Patient Identity Feed – Auto-merge between patients with matching NID (as non medical ID)

This test ensures that the receiver is able to merge patient data from an assigning authority (TEST\_A) which has an national identifier (not assigned by central authority as a PID). The demographics data does not match, this is to test that matching is done on explicit identifiers.

#### Setup the receiver such that OID 2.16.840.1.113883.3.72.5.9.2 has assigning authority of TEST\_A which can be assigned from TEST\_HARNESS\_A

#### Setup the receiver such that OID 2.16.840.1.113883.3.72.5.9.B has assigning authority of TEST\_A which can be assigned from TEST\_HARNESS\_B

#### Setup the receiver such that OID 2.16.840.1.113883.3.72.5.9.9 has assigning authority of NID

#### Perform necessary steps to ensure that the receiver is configured to merge patients based on the SSN field (PID-19)

## Test Step 1:

Test harness (as TEST\_HARNESS\_A) sends a registration message for patient Yannick Jones having a date of birth to the month, with NID of NID-000345439 and local identifier of TEST\_A of RJ-460.

```
MSH|^~\&|TEST_HARNESS_A^^|TEST^^|CR1^^|MOH_CAAT^^|20141104174451||ADT^A01^ADT_A01|TEST-CR-18-20|P|2.3.1
EVN||20141001
PID|||RJ-460^^^TEST_A||JONES^YANNICK^^^^^L||199004|M|||||||||||NID-000345439^^^NID
PV1||I
```

### Expected Behaviour

* Receiver Accepts Message with an AA
* MSH-5 and MSH-6 matches “TEST\_HARNESS\_A|TEST”

## Test Step 2:

Test harness (as TEST\_HARNESS\_B) sends a registration message for patient Yan Jones having a more specific date of birth, with NID of NID-000345439 and local identifier of TEST\_B of RB-469.

```
MSH|^~\&|TEST_HARNESS_B^^|TEST^^|CR1^^|MOH_CAAT^^|20141104174451||ADT^A01^ADT_A01|TEST-CR-18-30|P|2.3.1
EVN||20141001
PID|||RB-469^^^TEST_B||JONES^YAN^^^^^L||19900404|M|||||||||||NID-000345439^^^NID
PV1||I
```

### Expected Behaviour

* Receiver Accepts Message with an AA
* MSH-5 and MSH-6 matches “TEST\_HARNESS\_B|TEST”

## Test Step 3:

Test harness verifies the record from TEST\_B is linked with TEST\_A via the NID

```
MSH|^~\&|TEST_HARNESS_A|TEST|CR1|MOH_CAAT|20090223144546||QBP^Q23^QBP_Q21|TEST-CR-06-40|P|2.5
QPD|IHE PIX Query|RB-469^^^NID^PI
RCP|I
```

### Expected Behaviour

* Receiver responds with an AA
* Receiver sends exactly one PID segment with identifier RJ-449 in domain TEST\_A in one of the PID-3 repetitions


# TEST: OHIE-CR-01-HL7v2

Patient Identity Feed – Invalid register patient message

This test validates that the Client Registry rejects a poorly formed message lacking appropriate assigner information in PID-3.&#x20;

## Pre-Conditions / Setup

Prior to executing this test, SanteMPI instances should configure:&#x20;

* The `TEST_OTHER` application
* The `TEST_OTHER|TEST` device

{% tabs %}
{% tab title="Dataset" %}

```markup
<dataset id="Test Domain" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://santedb.org/data">
  <insert skipIfError="false" skipIfExists="true">
    <SecurityApplication xmlns="http://santedb.org/model">
      <id>F0FC4322-948D-4986-A06C-DA603A77EDDE</id>
      <!-- Secret: TEST_HARNESS -->
      <applicationSecret>b5547020757c0efa3f320fbd2a0c43d0628e19b8cd81652523b87d31fc54f5ec</applicationSecret>
      <name>TEST_HARNESS</name>
    </SecurityApplication>
  </insert>
  <insert skipIfError="false" skipIfExists="true">
    <SecurityDevice xmlns="http://santedb.org/model">
      <id>6746d4a7-7522-4334-8299-ffda8ea73202</id>
      <!-- Secret: TEST_HARNESS -->
      <deviceSecret>b5547020757c0efa3f320fbd2a0c43d0628e19b8cd81652523b87d31fc54f5ec</deviceSecret>
      <name>TEST_OTHER|TEST</name>
    </SecurityDevice>
  </insert>
</dataset>
```

{% endtab %}

{% tab title="SDBAC" %}

```
> application.add TEST_OTHER -s TEST_HARNESS
> device.add TEST_OTHER|TEST -s TEST_HARNESS
```

{% endtab %}
{% endtabs %}

## Patient Missing PID-3.4 With No Authority

Test harness sends ADT^A01 message where the CX.4 of the PID is missing.

```
MSH|^~\&|TEST_OTHER|TEST|CR1|MOH_CAAT|20141104174451||ADT^A01^ADT_A01| TEST-CR-01-10|P|2.3.1
EVN||20101020
PID|||RJ-438^^^&&||JOHNSTON^ROBERT^^^^^L|MURRAY^^^^^^L|19830205|M|||1220 Centennial Farm Road^^ELLIOTT^IA^51532||^PRN^PH^^^712^7670867||||||481-27-4185
PV1||I
```

### Expected Behaviour

* Receiver rejects the message with an AR or AE
* Response is ACK^A01
* Response version is 2.3.1
* MSA indicates that an assigning authority (PID-3-4) could not be resolved.

{% hint style="info" %}
If using MSH-8 security (i.e. not node authentication) you should ensure that the `MSH-8` value of the message sent from the test harness contains `TEST_HARNESS+TEST_HARNESS`
{% endhint %}


# HL7v2 Test Cases Instructions

Steps taken to run the hl7 test cases

{% file src="/files/SBfIAxaOw2chl1caA8Zc" %}

## Pull santempi:

Pull santempi repository from github : <https://github.com/santedb/santempi.git>

## Install docker containers:

Having docker installed, run the following command inside santempi/instant directory where the docker-compose.yml file exists to spin up docker containers.

```
 docker compose -f docker-compose.yml up
```

{% hint style="info" %}
It also can be done by running the "docker-compose.ui.yml" file but the ui component is not necessary here
{% endhint %}

## Get sdbac(santedb admin console) from latest release

Get the latest sdbac release from github: <https://github.com/santedb/santedb-server/releases>

Download the sdbac.zip and extract the files.&#x20;

## Configure santempi instances for pre-conditions setup

1-Run the following commands inside sdbac directory where the sdbac.exe is located or run the sdbac.exe directly.

{% hint style="info" %}
The command prompt should be run in administrative mode
{% endhint %}

```
sdbac
```

2-Insert the credentials for Username and Password.

3-Wait for the system to get ready

![](/files/Ox5tKIGSo8WMLvpsu5pE)

4-Run the following commands:

**To create TEST\_HARNESS application run:**

```
application.add TEST_HARNESS -s TEST_HARNESS
```

**To create TEST\_HARNESS|TEST device run:**

```
device.add TEST_HARNESS|TEST -s TEST_HARNESS
```

**To create TEST identity domain and set the assigned authority to TEST\_HARNESS run:**

```
aa.add -n TEST -o 2.16.840.1.113883.3.72.5.9.1 -u http://ohie.org/test/test -d 'OpenHIE Test Domain' -a TEST_HARNESS
```

![](/files/RvHsOnPZGoj8gtw0KU0q)

## Pull hl7-testing-tool:

Pull hl7-testing-tool from github: <https://github.com/santedb/hl7-testing-tool.git>

## Run hl7-testing-tool:

Run hl7-testing-tool solution with visual studio.

They can be run as an entire test suite or an individual test case or test step.

For a test step to pass all  mandatory assertions and at least one of alternate assertions for the same terserstring must pass.

{% hint style="info" %}
For more information about how the tool works please visit The README section in hl7-testing-tool repository at github: <https://github.com/santedb/hl7-testing-tool/blob/main/README.md>
{% endhint %}


# MPI/CR Test Cases for FHIR

## Summary

These tests are intended to allow for validation of the SanteMPI operating as a national scale client registry within an OpenHIE context. Although FHIR is used as an underlying standard, there are particular behaviors/requirements which are not captured in FHIR or even within IHE technical frameworks.

SanteMPI acts as a custodian of patient master identities, as such it is important to ensure that the FHIR interfaces are properly configured and behave. This test suite is based on the following underlying documents/assets:

* OpenHIE Test Framework for HL7v2 Messages
* IHE Technical Frameworks related to patient management:
  \*  [Patient Demographics Query for Mobile](https://www.ihe.net/uploadedFiles/Documents/ITI/IHE_ITI_Suppl_PDQm.pdf)
  * [Patient Identity Cross Referencing for Mobile](https://www.ihe.net/uploadedFiles/Documents/ITI/IHE_ITI_Suppl_PIXm.pdf)
  * [Patient Master Identity Registry](https://www.ihe.net/uploadedFiles/Documents/ITI/IHE_ITI_Suppl_PMIR.pdf) &#x20;

All implementations of FHIR interfaces in SanteDB are subject to the [FHIR Implementation Notes ](/developers/service-apis/hl7-fhir#fhir-implementation)provided, including limitations on `fullUrl` , identifiers, and offsite resources.&#x20;

## SOAP-UI Test Cases

All of the test cases expressed on the wiki using FHIR have been expressed in a SOAP-UI project available on the [SanteMPI GitHub](https://github.com/santedb/santempi/blob/master/SanteMPI-Test-Cases-soapui-project.xml) project page. You can use [SmartBear SOAP-UI](https://www.soapui.org/downloads/latest-release/) to execute these tests.&#x20;

By default the test  cases use `http://localhost:8080` as the iCDR binding.

## Patient Registration Test Cases

The test cases which involve the merging/creation/updating of patient can be submitted to SanteMPI in three ways. The create tests only specify the contents of a bundle/patient being tested, and do not include any wrapper (such as MessageHeader) specifications.&#x20;

### POST Patient Resource

For simple registration of patients in SanteMPI, the patient resource may be used and POSTed directly. This is the simplest way to execute the transactions.&#x20;

```http
POST http://sut:8080/fhir/Patient HTTP/1.1
Content-Type: application/fhir+json
Authorization: bearer XXXXXXX

{
    "resourceType" : "Patient"
    ...
```

### POST Transaction Bundle

A transaction bundle can be POST(ed) directly to the FHIR Bundle endpoint with necessary information (such as related persons, organizations, etc.) as a transaction to the /fhir/Bundle endpoint. Such transactions are required to have the bundle type of "transaction" selected.

```http
POST http://sut:8080/fhir/Bundle HTTP/1.1
Content-Type: application/fhir+json
Authorization: bearer XXXXXX

{
    "resourceType": "Bundle",
    "type": "transaction",
    "entry": [
        {
            "fullUrl": "Patient/1",
```

{% hint style="info" %}
Any references in the bundle are resolved first from within the bundle using the local reference and then using existing internal data within the SanteMPI instance. It is recommended that senders of bundles include all necessary information and use local references, or query the SanteMPI instance for SanteMPI's UUID for these resources.
{% endhint %}

### Messaging / PMIR

You can also post a FHIR message bundle to either `/fhir/Bundle` or to `/fhir/$process-message`. When sending a request to `/fhir/$process-message` you must use a FHIR Parameters resource as specified in the [Process Message operation definition](https://www.hl7.org/fhir/R4/messageheader-operation-process-message.html). If using PMIR, you should post a message bundle to the `/fhir/Bundle` endpoint.

```http
POST http://sut:8080/fhir/Bundle HTTP/1.1
Content-Type: application/fhir+json
Authorization: bearer XXXXXXX

{
    "resourceType": "Bundle",
    "type": "message",
    "entry": [
        {
            "fullUrl": "MessageHeader/1",
            "resource": {
                "resourceType": "MessageHeader",
```

The minimal bundle which is required to process a PMIR message has:

* A `MessageHeader` with the appropriate PMIR operation type
* A single entry being a `Bundle`with type history

```javascript
{
    "resourceType": "Bundle",
    "type": "message",
    "entry": [
        {
            "fullUrl": "MessageHeader/1",
            "resource": {
                "resourceType": "MessageHeader",
                "id": "1",
                "eventUri": "urn:ihe:iti:pmir:2019:patient-feed",
                "source": {
                    "endpoint": "http://example.com/patientSource"
                },
                "focus": [
                    {
                        "reference": "Bundle/1"
                    }
                ],
                "destination": [
                    {
                        "endpoint": "http://sut:8080/fhir/Bundle"
                    }
                ]
            }
        },
        {
            "fullUrl": "Bundle/1",
            "resource": {
                "resourceType": "Bundle",
                "type": "history",
                "entry": [
                    {
                        "fullUrl": "Patient/1",
                        "resource": {
                            "resourceType": "Patient",
                         /* Other Patient Details Here */
                            
                        }
                    }
                ]
            }
        }
    ]
}
```

### PMIR Implementation Notes (Master Merge)

SanteMPI maintains strict authority over which systems are permitted to perform `MASTER->MASTER` merges. The SanteMPI implementation of PMIR allows callers (such as an EMR, LAB, HIS, etc.) to merge only their own LOCAL records in a `LOCAL->LOCAL` merge using the `replaces` relationship type.&#x20;

Attempting to merge two master identities together will result in a new LOCAL record being established for the caller's data domain and a LOCAL->LOCAL merge occurring. In order to permit EMRs or other callers to perform MASTER->MASTER merge you should add the `Unrestricted MDM` policy to the application or device credentials for that caller.&#x20;

{% hint style="info" %}
Allowing MASTER->MASTER merging from external callers is not actively tested or maintained by the SanteMPI team, and should be used with caution as it allows any user on that application to have unrestricted control over the master identities in your SanteMPI deployment.
{% endhint %}


# TEST: OHIE-CR-01-FHIR

Mobile Patient Identity Feed - Invalid Registration Message

This test validates that the MPI/Client Registry rejects a poorly formed message.

## References

* [Integrating the Health Enterprise Patient Master Identity Registry](https://www.ihe.net/uploadedFiles/Documents/ITI/IHE_ITI_Suppl_PMIR.pdf)
* [HL7 FHIR Patient Resource](http://hl7.org/fhir/patient.html)

## Discussion

The SanteMPI product solution, when configured properly, will perform basic validation in order to ensure that it can appropriately route and process FHIR registration messages to/from source systems. Because FHIR has very minimal requirements for patient information, this test merely ensures that minimal useful data is required including:

* Appropriate codification of objects (such as name, addresses, telecommunications addresses, etc.)
* Appropriate information to classify identity domains and assigning authority

## Pre-Conditions / Setup

None

## Register Incomplete Message

The test harness sends a patient which has a malformed identifier entry which is missing the system.

```javascript
{
  "resourceType": "Patient",
  "id": "1",
  "active": true,
  "identifier": [
    {
      "use": "usual",
      "value": "12345",
      "assigner": {
        "display": "Fake Domain"
      }
    }
  ],
  "name": [
    {
      "use": "official",
      "family": "JOHNSTON",
      "given": [
        "ROBERT"
      ]
    }
  ],
  "telecom": [
    {
      "use": "home"
    },
    {
      "system": "phone",
      "value": "(712) 767-0867",
      "use": "home",
      "rank": 1
    }
  ],
  "gender": "male",
  "birthDate": "1983-02-05",
  "deceasedBoolean": false,
  "address": [
    {
      "use": "home",
      "type": "both",
      "line": [
        "1220 Centennial Farm Road"
      ],
      "city": "ELLIOTT",
      "state": "IA",
      "postalCode": "51532"
    }
  ]
}
```

### Expected Behaviour

| Requirement | Option    | Description                                           |
| ----------- | --------- | ----------------------------------------------------- |
| MUST        | PMIR Only | Return MessageHeader with response.code = fatal-error |
| MUST        |           | Include an OperationOutcome entry in response         |
| MUST        |           | Indicate that the resource failed validation.         |
| MUST        |           | Carry an HTTP response code in the 400 series         |
| SHOULD      |           | Carry an HTTP response code of 422                    |

## Register Invalid / Unknown Reference

This test will ensure that the client registry rejects a message (such as a transaction or PMIR bundle) where a target of a relationship is unknown.&#x20;

{% hint style="info" %}
This test attempts to establish whether the Client Registry is capable of maintaining referential integrity between resources. This is important as, when configuring matching, data which is linked must be available to the matching engine at all times and missing or broken link data may result in partial / useless records.
{% endhint %}

```javascript
{
  "resourceType": "Patient",
  "id": "1",
  "active": true,
  "name": [
    {
      "use": "official",
      "family": "JOHNSTON",
      "given": [
        "ROBERT"
      ]
    }
  ],
  "telecom": [
    {
      "use": "home"
    },
    {
      "system": "phone",
      "value": "(712) 767-0867",
      "use": "home",
      "rank": 1
    }
  ],
  "gender": "male",
  "birthDate": "1983-02-05",
  "deceasedBoolean": false,
  "address": [
    {
      "use": "home",
      "type": "both",
      "line": [
        "1220 Centennial Farm Road"
      ],
      "city": "ELLIOTT",
      "state": "IA",
      "postalCode": "51532"
    }
  ],
  "managingOrganization" : {
    "reference" : "Organization/3930293029302923"
  }
}
```

### Expected Behaviour

| Requirement | Option    | Description                                                                                                                    |
| ----------- | --------- | ------------------------------------------------------------------------------------------------------------------------------ |
| MUST        | PMIR Only | Return MessageHeader with response.code = fatal-error                                                                          |
| MUST        |           | Include an OperationOutcome entry in response                                                                                  |
| MUST        |           | <p>Indicate that the resource failed validation and/or that the reason for </p><p>rejection was an unresolvable reference.</p> |
| MUST        |           | Carry an HTTP response code in the 400 series                                                                                  |
| SHOULD      |           | Carry an HTTP response code of 422 or 404                                                                                      |


# TEST: OHIE-CR-02-FHIR

Patient Identity Feed - Resolve Identity Domains

This test is a modified version of OHIE-CR-02 test case for HL7v2. Whereas the HL7v2 PIX behavior is intended to map missing identity domains to an authority, this test ensures that the solution can map between URL and OID identity systems.

## References

* [Integrating the Health Enterprise Patient Master Identity Registry](https://www.ihe.net/uploadedFiles/Documents/ITI/IHE_ITI_Suppl_PMIR.pdf)
* [HL7 FHIR Patient Resource](http://hl7.org/fhir/patient.html)

## Discussion

Jurisdictional deployments often use a heterogenous mixture of standards and software. Some software, such as those using HL7v2 or HL7v3/CDA may use OIDs and/or named identity domains for patient identification, whereas FHIR based systems may prefer URLs. These tests ensure that the SanteMPI solution maintains a consistent mapping between OID based identity domains and URL based identity domains.

## Pre-Conditions / Setup

### Create TEST Domain

Create an AssigningAuthority domain which has the following attributes:

* URL of <http://ohie.org/test/test>
* OID of 1.3.6.1.4.1.52820.3.72.5.9.1
* Device TEST-HARNESS with authoritative source for identifiers

#### SanteMPI Seed Data

```markup
<dataset id="Test Domain" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://santedb.org/data">
  <insert skipIfError="false" skipIfExists="true">
    <SecurityApplication xmlns="http://santedb.org/model">
      <id>F0FC4322-948D-4986-A06C-DA603A77EDDE</id>
      <!-- Secret: TEST_HARNESS -->
      <applicationSecret>b5547020757c0efa3f320fbd2a0c43d0628e19b8cd81652523b87d31fc54f5ec</applicationSecret>
      <name>TEST_HARNESS</name>
    </SecurityApplication>
  </insert>
  <!-- TEST -->
  <insert skipIfError="false" skipIfExists="true">
    <AssigningAuthority xmlns="http://santedb.org/model">
      <name>OHIE TEST Domain</name>
      <domainName>TEST_FHIR</domainName>
      <oid>2.16.840.1.113883.3.72.5.9.1</oid>
      <url>http://ohie.org/test/test</url>
      <isUnique>true</isUnique>
      <assigningApplication>F0FC4322-948D-4986-A06C-DA603A77EDDE</assigningApplication>
    </AssigningAuthority>
  </insert>
```

## Authenticate as TEST\_HARNESS

The test harness authenticates against the SanteMPI IdP using a client\_credentials grant for the test-harness.

```http
POST http://localhost:8080/auth/oauth2_token HTTP/1.1
Accept-Encoding: gzip,deflate
Content-Type: application/x-www-form-urlencoded;charset=UTF-8
Content-Length: 87
Host: localhost:8080
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.5.5 (Java/12.0.1)



grant_type=client_credentials&scope=*&client_secret=TEST_HARNESS&client_id=TEST_HARNESS
```

## Register Olly Oid

The test harness registers a patient using the OID for the TEST domain with the following additional data:

* Name: Olly Oid
* Gender: male
* Identifier: FHR-020 , system: urn:oid:1.3.6.1.4.1.52820.3.72.5.9.1

```javascript
{
  "resourceType": "Patient",
  "id": "ohie-cr-02-10-fhir",
  "active": true,
  "identifier": [
    {
      "system": "urn:oid:2.16.840.1.113883.3.72.5.9.1",
      "value": "FHR-020"
    }
  ],
  "name": [
    {
      "use": "official",
      "family": "OID",
      "given": [
        "OLLY"
      ]
    }
  ],
  "gender": "male",
  "birthDate": "1983-02-05"
}
```

### Expected Behaviour

| Requirement | Option    | Description                                             |
| ----------- | --------- | ------------------------------------------------------- |
| MUST        | PMIR Only | Return MessageHeader with response.code = ok            |
| MUST        |           | Return HTTP response code 201 Created                   |
| SHOULD      |           | Include created patient object in response              |
| SHOULD      |           | Indicate the identifier of the created patient with URL |
| SHOULD      |           | Contain a link to the local record created              |

## Query for Olly Oid using Url

The test harness executes a query against the receiver using the URL version of the TEST domain

```http
GET http://localhost:8080/fhir/Patient?identifier=http%3A%2F%2Fohie.org%2Ftest%2Ftest%7CFHR-020&_format=application%2Ffhir%2Bjson HTTP/1.1
Accept-Encoding: gzip,deflate
Authorization: BEARER xxxxxxx
Host: localhost:8080
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.5.5 (Java/12.0.1)
```

### Expected Behaviour

| Requirement | Option | Description                                                          |
| ----------- | ------ | -------------------------------------------------------------------- |
| MUST        |        | Accept the message with HTTP 200 OK                                  |
| MUST        |        | Include a bundle with exactly 1 patient result                       |
| MUST        |        | Contain a patient for Olly Oid                                       |
| MUST        |        | Have an identifier for FHR-020 in system <http://ohie.org/test/test> |
| SHOULD      |        | Contain one or more link entries with type seealso                   |

## Register Uma Url

The test harness registers a patient using the URL representation of the system for the TEST domain:

* Name: Uma Url
* Gender: female
* Identifier: FHR-021 , system: <http://ohie.org/test/test>

```javascript
{
			  "resourceType": "Patient",
			  "id": "ohie-cr-02-30-fhir",
			  "active": true,
			  "identifier": [
			    {
			      "system": "http://ohie.org/test/test",
			      "value": "FHR-021"
			    }
			  ],
			  "name": [
			    {
			      "use": "official",
			      "family": "URL",
			      "given": [
			        "UMA"
			      ]
			    }
			  ],
			  "gender": "female",
			  "birthDate": "1990-03-09"
			}
```

### Expected Behaviour

| Requirement | Option    | Description                                             |
| ----------- | --------- | ------------------------------------------------------- |
| MUST        | PMIR Only | Return MessageHeader with response.code = ok            |
| MUST        |           | Return HTTP response code 201 Created                   |
| SHOULD      |           | Include created patient object in response              |
| SHOULD      |           | Indicate the identifier of the created patient with URL |
| SHOULD      |           | Contain a link to the local record created              |

## Query for Uma Url using Oid

The test harness executes a query against the receiver using the OID version of the TEST domain

```http
GET http://localhost:8080/fhir/Patient?identifier=urn%3Aoid%3A2.16.840.1.113883.3.72.5.9.1%7CFHR-021&_format=application%2Ffhir%2Bjson HTTP/1.1
Accept-Encoding: gzip,deflate
Authorization: BEARER xxxxxxx
Host: localhost:8080
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.5.5 (Java/12.0.1)
```

### Expected Behaviour

| Requirement | Option | Description                                                          |
| ----------- | ------ | -------------------------------------------------------------------- |
| MUST        |        | Accept the message with HTTP 200 OK                                  |
| MUST        |        | Include a bundle with exactly 1 patient result                       |
| MUST        |        | Contain a patient for Uma Url                                        |
| MUST        |        | Have an identifier for FHR-021 in system <http://ohie.org/test/test> |
| SHOULD      |        | Contain one or more link entries with type seealso                   |




---

[Next Page](/llms-full.txt/1)

