# [Developer Version] Patient Portal
###### tags: `fhir-project` `PatientPortal` `developer-version`
:::info
:pushpin: **Source Code**: [Click here](https://github.com/victoriatjia/FHIR_PatientPortal)
:::
## Table of Contents
[TOC]
## Prerequisites
* [FHIR](https://www.hl7.org/fhir/)
* Some working knowledge of [HTML](https://www.w3schools.com/html/), [CSS](https://www.w3schools.com/css/default.asp), and [JavaScript](https://www.w3schools.com/js/default.asp)
## Required FHIR Resource

Before we start to jump into the program source code, it's better to have some understanding regarding the FHIR format we use in this system.
### [Organization](https://www.hl7.org/fhir/organization.html)
* Usage: Define the health care institution information
* Field format:
| Field Name | Definition | Example Value |
|-|-|-|
| resourceType | FHIR resource type | Organization |
| active | Whether the organization's record is still in active use | true|false |
| type | [Kind of organization](https://www.hl7.org/fhir/valueset-organization-type.html) | type.coding.code= "prov"; type.coding.display= "Healthcare Provider" |
| name | Organization name | Oxford Hospital |
| telecom | A contact detail for the organization | telecom.system= “phone”; telecom.value= “911” |
| address | An address for the organization | address.text= “21, Washington Street” |
:::spoiler [Organization/12](https://203.64.84.213:52883/binus/fhir/Organization/12)
```gherkin=
{
"resourceType": "Organization",
"active": true,
"type": [ {
"coding": [ {
"system": "http://terminology.hl7.org/CodeSystem/organization-type",
"code": "team",
"display": "Organizational team"
} ]
} ],
"name": "Oxford Hospital",
"telecom": [ {
"system": "phone",
"value": "911"
} ],
"address": [ {
"text": "21, Washington Street"
} ]
}
```
:::
<br>
### [Person](http://hl7.org/fhir/person.html)
* Usage: Define a person, where each person may have multiple role (patient or practitioner)
* Field format:
| Field Name | Definition | Example Value |
|-|-|-|
| resourceType | FHIR resource type | Person |
| identifier | A human identifier for this person. We also use this field to store other information related to this person (e.g. password, institution, etc.) | identifier.system= “Identity Card”; identifier.value= “0010001012”; |
| name | Person name | Elon Musk |
| telecom | A contact detail for the person | telecom.system= “phone”; telecom.value= “081234568” |
| active | This person's record is in active use | true|false |
| link | Link to \[Patient\] or \[Practitioner\] resource that concerns the same actual person. Since a person can have multiple role, e.g. they may be a patient from 2 different hospitals and a practitioner from 1 health care provider, then “link” field will reference to 2 \[Patient\] and 1 \[Practitioner\] | link.target.reference= “Patient/01” |
:::spoiler [Person/112](https://203.64.84.213:52883/binus/fhir/Person/112)
```gherkin=
{
"resourceType": "Person",
"identifier": [ {
"system": "UserID",
"value": "albertEinstein@gmail.com"
}, {
"system": "Password",
"value": "Njc4ZTgyZDkwN2QzZTZlNzFmODFkNWNmM2RkYWNjMzY3MWRjNjE4YzM4YTFiN2E5ZjkzOTNhODNkMDI1YjI5Ng=="
}, {
"system": "HighestEduDegree",
"value": "PhD"
}, {
"system": "Institution",
"value": "Oxford University"
} ],
"name": [ {
"text": "Albert Einstein"
} ],
"telecom": [ {
"system": "email",
"value": "albertEinstein@gmail.com"
} ]
}
```
:::
<br>
### [Patient](http://hl7.org/fhir/patient.html)
* Usage: Define the role of patient
* Field format:
| Field Name | Definition | Example Value |
|-|-|-|
| resourceType | FHIR resource type | Patient |
| identifier | Student ID | identifier.system= “MRN”; identifier.value= “000002234”; |
| active | Whether the patient's record is still in active use | true|false |
| name | Patient name | Elon Musk |
| managingOrganization | Health care institution where the patient belongs to | managingOrganization.reference= “Organization/2” |
:::spoiler [Patient/3](https://203.64.84.213:52883/binus/fhir/Patient/3)
```gherkin=
{
"resourceType": "Patient",
"identifier": [ {
"system": "StudentID",
"value": "111316001"
} ],
"active": true,
"name": [ {
"text": "Elon Musk"
} ],
"managingOrganization": {
"reference": "Organization/#ID"
}
}
```
:::
<br>
### [Practitioner](http://www.hl7.org/fhir/practitioner.html)
* Usage: Define the role of practitioner. This resource only store the information of practitioner, not included the organization where the practitioner belong to
* Field format:
| Field Name | Definition | Example Value |
|-|-|-|
| resourceType | FHIR resource type | Practitioner |
| active | Whether the practitioner's record is still in active use | true|false |
| name | Practitioner name | Albert Einstein |
### [PractitionerRole](https://www.hl7.org/fhir/practitionerrole.html)
* Usage: Define the organization where the practitioner belong to
* Field format:
| Field Name | Definition | Example Value |
|-|-|-|
| resourceType | FHIR resource type | PractitionerRole |
| identifier | Identifiers that are specific to a practitioner | Identifier.system = ”PractitionerID”; Identifier.value = ”P0001” |
| active | Whether the practitioner's record is still in active use | true|false |
| practitioner | \[Practitioner\] resource where the practitioner role belongs to | practitioner.reference= “Practitioner/5”; practitioner.display= “Albert Einstein”; |
| organization | Health care institution where the practitioner belongs to | organization.reference= “Organization/2”; organization.display= “Oxford Hospital”; |
| telecom | A contact detail for the practitioner | telecom.system= “email”; telecom.value= “albertEinstein@oxfuni.com” |
### [Bundle](https://build.fhir.org/bundle.html)
* Usage: Define the clinical report document where it bundle other clinical resources (e.g. Observation, Condition, DiagnosticReport)
* Field format:
| Field Name | Definition | Example Value |
|-|-|-|
| resourceType | FHIR resource type | Bundle |
| identifier | Unique identifier for this document | |
| identifier\[0\].system | Patient portal website url | [https://PatientPortal.com](https://patientportal.com/) |
| identifier\[0\].value | Certificate number using global unique identification code. Format suggestion: PP.\[Medical institution code\].\[Issue date, year, month, day, hour, minute, second, millisecond\].\[Serial no.\] or custom unique identification code | PP.0617060018.20210722143000888.001 |
| identifier\[0\].period.start | Document issue date (yyyy-mm-dd) | 2021-07-22 |
| identifier\[0\].period.end | Document expired date (yyyy-mm-dd) | 2022-07-22 |
| type | Bundle type | document |
| timestamp | Certificate created date | 2021-07-22T14:30:00+08:00 |
| entry\[0\] | Document's evidence (Must be Composition Resource) | Composition/id |
| entry\[1\] ~ \[n\] | Document's evidence Additional FHIR Resources (1st-nth resources) must contain FHIR Resource which referenced by the Composition Resource | Other resources : Organization, Patient, Immunization, Observation |
### [DocumentReference](https://build.fhir.org/documentreference.html)
* Usage: A reference to a document as a index for search
* Field format:
| Field Name | Definition | Example Value |
|-|-|-|
| resourceType | FHIR resource type | DocumentReference |
| status | Whether the document reference is still in active use | current |
| type | Document type | type.coding\[0\].system= "https://build.fhir.org/valueset-doc-typecodes.html"; type.coding\[0\].code= "11503-0"; type.coding\[0\].display= "Medical records" |
| subject | Patient reference (must reference to Patient Portal Patient ID) | Patient/id |
| date | DocumentReference created date | telecom.system= “phone”; telecom.value= “911” |
| authenticator | Practitioner who register this DocumentReference | PractitionerRole/id |
| custodian | Organization which maintains the document | Organization/id |
| content | Document referenced | content\[x\].attachment.url= "https://hapi.fhir.org/baseR5/Bundle/4773" content\[x\].attachment.title= "COVID-19 Vaccine Certificate April 04, 2022 14:30" |
<!--
:::spoiler Patient/id
```gherkin=
{
"resourceType": "DocumentReference",
"id": "3437",
"meta": {
"versionId": "10",
"lastUpdated": "2021-08-18T10:34:00.194+00:00",
"source": "#ZmsdGlqkQzI6JgN1"
},
"type": {
"coding": [
{
"system": "https://icd.codes/",
"code": "H02.60",
"display": "X RAY"
}
]
},
"subject": {
"reference": "Patient/?"
},
"date": "2021-08-15",
"authenticator": {
"reference": "PractitionerRole/1737"
},
"custodian": {
"reference": "Organization/1735"
},
"content": [
{
"attachment": {
"contentType": "fhir/json",
"url": "http://203.64.84.213:8080/fhir/DiagnosticReport/516",
"title": "Lung Mass Report"
}
},
{
"attachment": {
"contentType": "fhir/json",
"url": "http://203.64.84.213:8080/fhir/Observation/3441",
"title": "Respiratory Rate"
}
}
]
}
```
:::-->
### [Consent](https://build.fhir.org/consent.html)
* Usage: The purpose of this Resource is to be used to express a Consent regarding medical record sharing authorization
* Field format:
| Field Name | Definition | Example Value |
|-|-|-|
| resourceType | FHIR resource type | Consent |
| status | Whether the consent is still in active use | draft; active; inactive; |
| dateTime | Consent created date | 2022-04-04 |
| performer | The authenticator | PractitionerRole/id |
| organization | The authenticator's organization | Organization/id |
| provision.type | Allow type (deny or permit) | deny; permit; |
| provision.period | Timeframe for this rule | |
| provision.actor\[x\].role.coding.system | Identity of the terminology system | [https://terminology.hl7.org/2.1.0/CodeSystem-v3-ParticipationType.html](https://terminology.hl7.org/2.1.0/CodeSystem-v3-ParticipationType.html) |
| provision.actor\[x\].role.coding.code | Participation type | PRCP (primary information recipient) |
| provision.actor\[x\].reference.reference | To-be-authorized person reference ID | PractitionerRole/id |
| provision.actor\[x\].reference.display | To-be-authorized person name | Dr. Knowie |
| provision.action\[x\].coding\[x\].system | Identity of the terminology system | [http://hl7.org/fhir/http-verb](http://hl7.org/fhir/http-verb) |
| provision.action\[x\].coding\[x\].code | Type of access the Person who received authorization may had | POST; GET; PUT; DELETE; |
| provision.action\[x\].data\[x\].reference.reference | The authorize document | DocumentReference/id |
## Step-by-Step

First, we must have a concept that each health care provider will have **their own FHIR server** and our patient portal also has its own **Portal FHIR Server**
**A. Health Care Provider FHIR Server**
* Create Hospital and Department
* Organization
* Create Patient
* Person, Patient
* Create Practitioner
* Person, Practitioner, PractitionerRole
* Create patient medical record document, then bundle into FHIR Document
* Bundle (Observation, DiagnosticReport, Condition, etc)
**B. Portal FHIR Server**
**Health care provider**
* Create Organization
**Practitioner**
* Sign up
* Create Person
* Create Practitioner
* Create PractitionerRole
* Log in: Username password verification
* Register patients' medical record of their hospital into Patient Portal:
* Create DocumentReference based on Portal Patient ID
* Authorize page: Authorize specific data to be accessed by other practitioner. In this example, the authenticator practitioner will be called "main practitioner". The to-be-authorized practitioner will be called "secondary practitioner"
* Get all Practitioner (secondary practitioner) except main practitioner
* Get all Organization of the main practitioner
* Get all DocumentReference of this Organization (DocumentReference.custodian.reference= "Organization/id")
* Create Consent based on selected DocumentReference
* List Patient's resources information that authorized for this practitioner
* Get all Consent of this Practitioner
* Get all DocumentReference of this Consent
* Get all Document of this DocumentReference
* Get all resources of this Document
Patient
* Sign up
* Create Person
* Create Patient
* Log in: Username password verification (Person)
* List Patient's resources information
* Get all DocumentReference of this Patient
* Get all Document of this DocumentReference
* Get all resources of this Document
* When resources link is clicked, portal create JWT token and link to Hospital's FHIR Gateway to verify the token
* If token valid, then show the data
* Authorize page: Authorize specific practitioner to access patient's data
## Testing Scenario
We use below FHIR Server as:
* Oxford Hospital FHIR Server: https://hapi.fhir.org/baseR5
* Patient Portal FHIR Server: https://hapi.fhir.org/baseR4
### A. Create Organization for Patient Portal
**Step:**
1. Create FHIR Organization
:::spoiler [Organization/MIPatientPortal](https://hapi.fhir.org/baseR4/Organization/MIPatientPortal)
```gherkin=
{
"resourceType": "Organization",
"id" : "MIPatientPortal",
"active": true,
"type": [ {
"coding": [ {
"system": "http://terminology.hl7.org/CodeSystem/organization-type",
"code": "bus",
"display": "Non-Healthcare Business or Corporation"
} ]
} ],
"name": "Patient Portal",
"telecom": [ {
"system": "phone",
"value": "912"
} ],
"address": [ {
"text": "22, Washington Street"
} ],
"contact": [ {
"name": {
"text": "Victoria"
},
"telecom": [ {
"system": "email",
"value": "victoriatjiaa@gmail.com"
}, {
"system": "phone",
"value": "0812345678"
} ]
} ]
}
```
:::
<br>
### B. Suppose each health care provider already have patient's medical records store as FHIR Bundle in their own FHIR server
| Name | Role | Resource |
| -------- | -------- | -------- |
| Oxford Hospital | Hospital | [Organization/4764](https://hapi.fhir.org/baseR5/Organization/4764)|
| Dr. Elon Musk | Doctor | [Practitioner/4765](https://hapi.fhir.org/baseR5/Practitioner/4765) + [PractitionerRole/4766](https://hapi.fhir.org/baseR5/PractitionerRole/4766)|
| Will Smith | Patient | [Patient/4767](https://hapi.fhir.org/baseR5/Patient/4767)|
| COVID Immunization Record | Immunization | [Immunization/4768](https://hapi.fhir.org/baseR5/Immunization/4768)|
| Composition | Composition | [Composition/4769](https://hapi.fhir.org/baseR5/Composition/4769)|
| COVID Immunization Certificate | Bundle | [Bundle/4773](https://hapi.fhir.org/baseR5/Bundle/4773)|
### C. Health care provider who want to join our Patient Portal must register first.
**Step:**
1. Create FHIR Organization for Oxford Hospital
:::spoiler [Organization/2863475](https://hapi.fhir.org/baseR4/Organization/2863475)
```gherkin=
{
"resourceType": "Organization",
"active": true,
"type": [ {
"coding": [ {
"system": "http://terminology.hl7.org/CodeSystem/organization-type",
"code": "prov",
"display": "Healthcare Provider"
} ]
} ],
"name": "Oxford Hospital",
"telecom": [ {
"system": "phone",
"value": "911"
} ],
"address": [ {
"text": "21, Washington Street"
} ],
"contact": [ {
"name": {
"text": "Victoria"
},
"telecom": [ {
"system": "email",
"value": "victoriatjiaa@gmail.com"
}, {
"system": "phone",
"value": "0812345678"
} ]
} ]
}
```
:::
<br>
### D. Each registered health care provider will get 1 hospital admin account. Only this account may have authority to create doctor account of this registered health care provider
**Step:**
1. Create FHIR Person
:::spoiler [Person/2863580](https://hapi.fhir.org/baseR4/Person/2863580)
```gherkin=
{
"resourceType": "Person",
"identifier": [ {
"system": "UserID",
"value": "albertEinstein@gmail.com"
}, {
"system": "Password",
"value": "NzJkMDE2NmI1NzA3ZDEyOWRjMzIxZTU2NjkyZmU0NTRjMDM0NTUyZWU5ZTJiMzhmNWE3ZjFjMTMwNmE2MzJlYQ=="
}, {
"system": "HighestEduDegree",
"value": "PhD"
}, {
"system": "Institution",
"value": "Oxford University"
} ],
"name": [ {
"text": "Albert Einstein"
} ],
"telecom": [ {
"system": "email",
"value": "albertEinstein@gmail.com"
} ]
}
```
:::
<br>
2. Create FHIR Practitioner
:::spoiler [Practitioner/2863581](https://hapi.fhir.org/baseR4/Practitioner/2863581)
```gherkin=
{
"resourceType": "Practitioner",
"active": true,
"name": [
{
"text": [
"Albert Einstein"
]
}
]
}
```
:::
<br>
3. Create FHIR PractitionerRole
:::spoiler [PractitionerRole/2863582](https://hapi.fhir.org/baseR4/PractitionerRole/2863582)
```gherkin=
{
"resourceType": "PractitionerRole",
"identifier": [ {
"system": "PractitionerID",
"value": "P0001"
} ],
"active": true,
"code": [ {
"coding": [ {
"system": "http://hl7.org/fhir/R4/valueset-practitioner-role.html",
"code": "6868009",
"display": "Hospital administrator"
} ]
} ],
"practitioner": {
"reference": "Practitioner/2863581",
"display": "Albert Einstein"
},
"organization": {
"reference": "Organization/2863475",
"display": "Oxford Hospital"
},
"telecom": [ {
"system": "email",
"value": "albertEinstein@oxfuni.com",
"use": "work"
} ]
}
```
:::
<br>
4. Update FHIR Person
:::spoiler [Person/2863580](https://203.64.84.213:52883/binus/fhir/Person/2863580)
```gherkin=
"link": [ {
"target": {
"reference": "Practitioner/2863581"
}
} ]
```
:::
<br>
### E. Hospital admin create doctor account
**Step:**
1. Create FHIR Person
:::spoiler [Person/2865781](https://hapi.fhir.org/baseR4/Person/2865781)
```gherkin=
{
"resourceType": "Person",
"active": true,
"identifier": [ {
"system": "UserID",
"value": "elonmusk@gmail.com"
}, {
"system": "Password",
"value": "NThjYzgzZjViODBjYjUzY2U1Mzg1YWY5NTY0NThmYTllYWVkODk4MjVhZmY3NmE4MjQ5MTAzYzEwZGVlODY3ZQ=="
}, {
"system": "HighestEduDegree",
"value": "Master"
}, {
"system": "Institution",
"value": "Oxford University"
} ],
"name": [ {
"text": "Elon Musk"
} ],
"telecom": [ {
"system": "email",
"value": "elonmusk@gmail.com"
} ]
}
```
:::
<br>
2. Create FHIR Practitioner
:::spoiler [Practitioner/2865782](https://hapi.fhir.org/baseR4/Practitioner/2865782)
```gherkin=
{
"resourceType": "Practitioner",
"active": true,
"name": [
{
"text": [
"Elon Musk"
]
}
]
}
```
:::
<br>
3. Create FHIR PractitionerRole
:::spoiler [PractitionerRole/2865783](https://hapi.fhir.org/baseR4/PractitionerRole/2865783)
```gherkin=
{
"resourceType": "PractitionerRole",
"identifier": [ {
"system": "PractitionerID",
"value": "P0002"
} ],
"active": true,
"code": [ {
"coding": [ {
"system": "http://hl7.org/fhir/R4/valueset-practitioner-role.html",
"code": "doctor",
"display": "Doctor"
} ]
} ],
"practitioner": {
"reference": "Practitioner/2863581",
"display": "Elon Musk"
},
"organization": {
"reference": "Organization/2863475",
"display": "Oxford Hospital"
},
"telecom": [ {
"system": "email",
"value": "elonmusk@oxfuni.com",
"use": "work"
} ]
}
```
:::
<br>
4. Update FHIR Person
:::spoiler [Person/2865781](https://203.64.84.213:52883/binus/fhir/Person/2865781)
```gherkin=
"link": [ {
"target": {
"reference": "Practitioner/2865782"
}
} ]
```
:::
<br>
### F. Patient who want to join our Patient Portal can register on Patient Portal sign up page
**Step:**
1. Create Person
:::spoiler [Person/2869230](https://hapi.fhir.org/baseR4/Person/2869230)
```gherkin=
{
"resourceType": "Person",
"identifier": [ {
"system": "UserID",
"value": "willsmith@gmail.com"
}, {
"system": "Password",
"value": "ZTI1YjljNjhhOTYzN2I0ZTYxOTc5ZjlmZTY5YjdhZjhkMDcyNDRmMzgxNTU5NjU2OWQ1YWY2MDliNGRmZjE0Mg=="
} ],
"name": [ {
"text": "Will Smith"
} ],
"telecom": [ {
"system": "phone",
"value": "(03) 3410 5613",
"use": "mobile"
} ],
"gender": "male",
"birthDate": "1974-12-25",
"active": true,
"link": [ {
"target": {
"reference": "Patient/f2499d13-48f0-4b6d-b567-8fdb608d3e27"
}
} ]
}
```
:::
<br>
2. Create Patient
:::spoiler [Patient/f2499d13-48f0-4b6d-b567-8fdb608d3e27](https://hapi.fhir.org/baseR4/Patient/f2499d13-48f0-4b6d-b567-8fdb608d3e27)
```gherkin=
{
"resourceType": "Patient",
"id": "f2499d13-48f0-4b6d-b567-8fdb608d3e27",
"identifier": [ {
"system": "username",
"value": "111316001"
} ],
"active": true,
"name": [ {
"text": "Will Smith"
} ],
"managingOrganization": {
"reference": "Organization/MIPatientPortal"
}
}
```
:::
<br>
3. Update Person
:::spoiler [Person/2869230](https://hapi.fhir.org/baseR4/Person/2869230)
```gherkin=
"link": [ {
"target": {
"reference": "Patient/f2499d13-48f0-4b6d-b567-8fdb608d3e27"
}
} ]
```
:::
<br>
### G. Then, when patient seek medical service in one of the health care provider, they need to tell the practitioner their Portal Patient ID. So practitioner will register this patient's medical record into Portal FHIR Server as a DocumentReference
<!--- just
1. Add this in FHIR Patient
```gherkin=
"identifier": [ {
"use": "usual",
"type": {
"coding": [ {
"system": "http://terminology.hl7.org/CodeSystem/v2-0203",
"code": "CAAI"
} ]
},
"value": "urn:oid:f2499d13-48f0-4b6d-b567-8fdb608d3e27",
"period": {
"start": "2022-03-04"
}
} ],
```
--->
**Step:**
1. Create DocumentReference
:::spoiler [DocumentReference/2870422](https://hapi.fhir.org/baseR4/DocumentReference/2870422)
```gherkin=
{
"resourceType": "DocumentReference",
"status": "current",
"type": {
"coding": [ {
"system": "https://build.fhir.org/valueset-doc-typecodes.html",
"code": "11503-0",
"display": "Medical records"
} ]
},
"subject": {
"reference": "Patient/f2499d13-48f0-4b6d-b567-8fdb608d3e27"
},
"date": "2022-04-04",
"authenticator": {
"reference": "PractitionerRole/2865783"
},
"custodian": {
"reference": "Organization/2863475"
},
"content": [ {
"attachment": {
"url": "https://hapi.fhir.org/baseR5/Bundle/4773",
"title": "COVID-19 Vaccine Certificate April 04, 2022 14:30"
}
} ]
}
```
:::
<br>
### H. Patient then can see their medical record of specific health care provider in Patient Portal.
**Step:**
1. Get all DocumentReference of this Patient based on patient's portal ID (https://hapi.fhir.org/baseR4/DocumentReference?subject=Patient/f2499d13-48f0-4b6d-b567-8fdb608d3e27)
<!-- 8. They also can authorize practitioner from different health care provider to see their medical record
9. Practitioner may authorize other practitioner from different health care provider to access patient's medical record
-->
## What's next?
* Add OAuth mechanism to authenticate target health care provider API
* Create report template for other report type
* Radiology report
* Authorize medical record to other practitioner page