Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 44 additions & 59 deletions docs/install/diagrams/deployment_diagram_pie.puml
Original file line number Diff line number Diff line change
Expand Up @@ -18,33 +18,23 @@ Deployment_Node(hospital, "Hospital", "Hospital Network") {
Deployment_Node(opal, "Opal PIE", "Hospital data centre") {
Deployment_Node(apps, "Application Server", "CentOS Stream9 or Ubuntu LTS") {
Deployment_Node(apps_runtime, "Container Runtime", "Docker Engine") {
Container(traefik, "Reverse Proxy", "traefik", "Takes care of TLS termination and path rewrites\nRedirects all HTTP to HTTPS")
Container(backend, "Backend", "", "Web application exposing APIs and providing new OpalAdmin interface")
Container(opaladmin, "Opal Admin", "Apache, PHP", "Web application for clinicians and staff to set up and manage data")
Container(traefik, "Reverse Proxy", "traefik", "Takes care of TLS termination and path rewrites\nRedirects all HTTP requests to HTTPS")
Container(admin, "Opal Admin", "", "Web application exposing APIs and providing new OpalAdmin interface")
Container(admin_legacy, "Opal Admin Legacy", "Apache, PHP", "Web application for clinicians and staff to set up and manage data")
Container(listener, "Listener", "Node.js", "Handles requests from the user applications to access patient data")
Container(labs, "opal-labs", "Apache, PHP", "Responsible for retrieving lab result history via VSign-WS")
Container(orms, "ORMS", "Apache, PHP", "Opal Room Management Software that provides the virtual waiting room and live clinician dashboard")
Container(pdfgen, "PDF Generator", "Apache, PHP", "Generates PDFs for questionnaires")
Container(memcached, "Memcached", "", "Stores user sessions")
Container(highcharts, "Highcharts Export Server", "", "Generates images of charts")
Container(redis, "redis", "", "Caches patients being processed to avoid sending push notifications when batch processing")
Container(alembic, "alembic", "", "Database migrations\nRun at initialization or upgrade time to migrate DBs", $tags="init")
' Container(orms, "ORMS", "Apache, PHP", "Opal Room Management Software that provides the virtual waiting room and live clinician dashboard")
Container(redis, "redis", "", "Caches patients being processed to avoid sending push notifications when batch processing lab results")
Container(db_management, "db-management", "", "Database migrations\nRun at initialization or upgrade time to migrate DBs", $tags="init")
Container(ofelia, "ofelia", "", "Sidecar to run tasks periodically on containers")
Container_Boundary(db, "MariaDB", "MariaDB") {
ContainerDb(legacy_dbs, "Legacy Databases", "RDS", "DBs for legacy components\n(OpalDB, QuestionnaireDB)")
ContainerDb(admin_db, "Backend Database", "RDS", "DB for admin")

}
}
}

Deployment_Node(dbs, "Database Server", "CentOS Stream9 or Ubuntu LTS") {
Deployment_Node(db, "MariaDB", "MariaDB") {
ContainerDb(legacy_dbs, "Legacy Databases", "RDS", "DB(s) for legacy components")
ContainerDb(backend_db, "Backend Database", "RDS", "DB for backend")
}
}
Deployment_Node(integration, "Integration Server", "CentOS Stream9 or Ubuntu LTS") {
Deployment_Node(integration_runtime, "Container Runtime", "Docker Engine") {
Container(mirth, "Integration Engine", "Mirth Connect", "Interfaces with hospital source systems")
Container(nginx, "Reverse Proxy", "nginx", "Takes care of TLS termination and forwards paths to APIs exposed on integration engine ports")
ContainerDb(oie_dbs, "OIE Databases", "RDS", "DB(s) for Mirth and integration engine specifics")
}
}
Container_Ext(integration_engine, "Integration Engine", "", "Interfaces with source systems\nExposes API endpoints")
}
}

Expand All @@ -53,49 +43,44 @@ Deployment_Node(firebase, "Firebase") {

}

Container_Ext(rtd_orms, "Realtime Database", "us-central1", "Temporarily stores shortened patient names to call patients via TV screens in the waiting rooms") {

}
' Container_Ext(rtd_orms, "Realtime Database", "us-central1", "Temporarily stores shortened patient names to call patients via TV screens in the waiting rooms") {
'
' }
}

Rel(browser, traefik, "Makes request\nvia browser", "HTTP/HTTPS")
Rel(traefik, backend, "Sends requests to / to")
Rel(traefik, opaladmin, "Sends requests to /opalAdmin to")
Rel(traefik, labs, "Sends requests to /opal-labs to")
Rel(traefik, orms, "Sends requests to /orms to")

Rel(nginx, mirth, "Forwards requests to", "HTTP")
Rel(mirth, oie_dbs, "Reads from and writes to")
Rel(mirth, backend, "Makes API calls to", "HTTPS")
Rel(mirth, opaladmin, "Makes API calls to", "HTTPS")
Rel(mirth, labs, "Makes API calls to", "HTTPS")
Rel(mirth, orms, "Makes API calls to", "HTTPS")

Rel(backend, nginx, "Makes API calls to", "HTTPS")
Rel(listener, nginx, "Makes API calls to", "HTTPS")
Rel(opaladmin, nginx, "Makes API calls to", "HTTPS")
Rel(orms, nginx, "Makes API calls to", "HTTPS")

' Rel(backend, pdfgen, "Makes API calls to", "HTTP")
Rel(pdfgen, highcharts, "Makes API calls to", "HTTP")
Rel(labs, redis, "Makes calls to")
Rel(orms, memcached, "Makes calls to")

Rel(backend, backend_db, "Reads from and writes to", "TLS")
Rel(backend, legacy_dbs, "Reads from and writes to", "TLS")
Rel(opaladmin, legacy_dbs, "Reads from and writes to", "TLS")
Rel(labs, legacy_dbs, "Reads from and writes to", "TLS")
Rel(listener, legacy_dbs, "Reads from and writes to", "TLS")
Rel(orms, legacy_dbs, "Reads from and writes to", "TLS")
Rel(pdfgen, legacy_dbs, "Reads from and writes to", "TLS")
Rel(alembic, legacy_dbs, "Reads from and writes to", "TLS", $tags="init")
Rel(traefik, admin, "Sends requests to / to")
Rel(traefik, admin_legacy, "Sends requests to /opalAdmin to")
' Rel(traefik, orms, "Sends requests to /orms to")

Rel(integration_engine, traefik, "Makes API calls to", "HTTPS")
'Rel(integration_engine, admin_legacy, "Makes API calls to", "HTTPS")
'Rel(integration_engine, orms, "Makes API calls to", "HTTPS")

Rel(admin, integration_engine, "Makes API calls to", "HTTPS")
Rel(listener, integration_engine, "Makes API calls to", "HTTPS")
Rel(admin_legacy, integration_engine, "Makes API calls to", "HTTPS")
'Rel(orms, integration_engine, "Makes API calls to", "HTTPS")

Rel(admin_legacy, redis, "Makes calls to")
' Rel(orms, memcached, "Makes calls to")

Rel(admin, admin_db, "Reads from and writes to", "")
Rel(admin, legacy_dbs, "Reads from and writes to", "")
Rel(admin_legacy, legacy_dbs, "Reads from and writes to", "")
Rel(listener, legacy_dbs, "Reads from and writes to", "")
' Rel(orms, legacy_dbs, "Reads from and writes to", "")
Rel(db_management, legacy_dbs, "Reads from and writes to", "", $tags="init")

Rel(listener, rtd_opal, "Connects to, reads from, and writes to")
Rel(orms, rtd_orms, "Connects to, reads from, and writes to")
' Rel(orms, rtd_orms, "Connects to, reads from, and writes to")

Lay_Left(admin_legacy, admin)
Lay_Up(redis, db)

LAYOUT_WITH_LEGEND()
' LAYOUT_WITH_LEGEND()
SHOW_LEGEND()

footer drawn with PlantUML version %version() and C4-PlantUML version C4Version()
footer Relationships between components on the same host are left out for brevity (except those making use of third-party components).\n\ndrawn with PlantUML version %version() and C4-PlantUML version C4Version()

@enduml
88 changes: 88 additions & 0 deletions docs/install/diagrams/deployment_diagram_pie_db.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
' SPDX-FileCopyrightText: Copyright (C) 2024 Opal Health Informatics Group at the Research Institute of the McGill University Health Centre <john.kildea@mcgill.ca>
'
' SPDX-License-Identifier: CC-BY-SA-4.0

@startuml Opal PIE Deployment
!include <C4/C4_Deployment>

title Deployment diagram for the Opal PIE with a separate database server

AddElementTag("init", $bgColor="#c0c0c0", $legendText="init (used at deploy or upgrade time)")
AddRelTag("init", $textColor="#c0c0c0", $lineColor="#c0c0c0")

Deployment_Node(hospital, "Hospital", "Hospital Network") {
Deployment_Node(browser, "Browser", "Firefox, Chrome, or Edge", "Clinical staff use a browser to access the web applications") {

}

Deployment_Node(opal, "Opal PIE", "Hospital data centre") {
Deployment_Node(apps, "Application Server", "CentOS Stream9 or Ubuntu LTS") {
Deployment_Node(apps_runtime, "Container Runtime", "Docker Engine") {
Container(traefik, "Reverse Proxy", "traefik", "Takes care of TLS termination and path rewrites\nRedirects all HTTP requests to HTTPS")
Container(admin, "Opal Admin", "", "Web application exposing APIs and providing new OpalAdmin interface")
Container(admin_legacy, "Opal Admin Legacy", "Apache, PHP", "Web application for clinicians and staff to set up and manage data")
Container(listener, "Listener", "Node.js", "Handles requests from the user applications to access patient data")
' Container(orms, "ORMS", "Apache, PHP", "Opal Room Management Software that provides the virtual waiting room and live clinician dashboard")
Container(redis, "redis", "", "Caches patients being processed to avoid sending push notifications when batch processing lab results")
Container(db_management, "db-management", "", "Database migrations\nRun at initialization or upgrade time to migrate DBs", $tags="init")
Container(ofelia, "ofelia", "", "Sidecar to run tasks periodically on containers")
}
}
Deployment_Node(dbs, "Application Server", "CentOS Stream9 or Ubuntu LTS") {
Deployment_Node(db, "MariaDB", "MariaDB") {
ContainerDb(legacy_dbs, "Legacy Databases", "RDS", "DBs for legacy components\n(OpalDB, QuestionnaireDB)")
ContainerDb(admin_db, "Backend Database", "RDS", "DB for admin")

}
}

Container_Ext(integration_engine, "Integration Engine", "", "Interfaces with source systems\nExposes API endpoints")
}
}

Deployment_Node(firebase, "Firebase") {
Container_Ext(rtd_opal, "Realtime Database", "us-central1", "Temporarily stores requests and responses from the user applications") {

}

' Container_Ext(rtd_orms, "Realtime Database", "us-central1", "Temporarily stores shortened patient names to call patients via TV screens in the waiting rooms") {
'
' }
}

Rel(browser, traefik, "Makes request\nvia browser", "HTTP/HTTPS")
Rel(traefik, admin, "Sends requests to / to")
Rel(traefik, admin_legacy, "Sends requests to /opalAdmin to")
' Rel(traefik, orms, "Sends requests to /orms to")

Rel(integration_engine, traefik, "Makes API calls to", "HTTPS")
'Rel(integration_engine, admin_legacy, "Makes API calls to", "HTTPS")
'Rel(integration_engine, orms, "Makes API calls to", "HTTPS")

Rel(admin, integration_engine, "Makes API calls to", "HTTPS")
Rel(listener, integration_engine, "Makes API calls to", "HTTPS")
Rel(admin_legacy, integration_engine, "Makes API calls to", "HTTPS")
'Rel(orms, integration_engine, "Makes API calls to", "HTTPS")

Rel(admin_legacy, redis, "Makes calls to")
' Rel(orms, memcached, "Makes calls to")

Rel(admin, admin_db, "Reads from and writes to", "TLS")
Rel(admin, legacy_dbs, "Reads from and writes to", "TLS")
Rel(admin_legacy, legacy_dbs, "Reads from and writes to", "TLS")
Rel(listener, legacy_dbs, "Reads from and writes to", "TLS")
' Rel(orms, legacy_dbs, "Reads from and writes to", "")
Rel(db_management, legacy_dbs, "Reads from and writes to", "TLS", $tags="init")

Rel(listener, rtd_opal, "Connects to, reads from, and writes to")
' Rel(orms, rtd_orms, "Connects to, reads from, and writes to")

Lay_Left(admin_legacy, admin)
Lay_Up(redis, db)

' LAYOUT_WITH_LEGEND()
SHOW_LEGEND()

footer Relationships between components on the same host are left out for brevity (except those making use of third-party components).\n\ndrawn with PlantUML version %version() and C4-PlantUML version C4Version()

@enduml
2 changes: 1 addition & 1 deletion docs/install/diagrams/deployment_diagram_user.puml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Deployment_Node(browser, "User browser", "Firefox, Chrome, Edge etc.") {
Container(registration_spa, "User Registration", "Single Page Application")
}

Deployment_Node(hosting, "Web Hosting", "Shared web hosting") {
Deployment_Node(hosting, "Web Hosting", "") {
Deployment_Node(apache, "Web Server", "Apache") {
Container(webapp, "Web app", "", "Delivers the static content and the web app single page application")
Container(registration, "User Registration", "", "Delivers the static content and the registration single page application")
Expand Down
34 changes: 31 additions & 3 deletions docs/install/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,46 @@ SPDX-License-Identifier: CC-BY-SA-4.0

# Deploying the Opal solution

The Opal PIE is typically deployed in a hospital and only accessible within the hospital's network.
The user applications are deployed and maintained by the Opal Health Informatics Group (O-HIG).
## High-level Architecture

<figure markdown="span">
![Opal High-Level Architecture](https://raw.githubusercontent.com/opalmedapps/.github/refs/heads/main/profile/architecture.png){ width=500 }
</figure>

The platform's primary goal is to securely share data across the perimeter of a healthcare institution's protected network between the Opal app and their medical record in the hospital's source systems.
This is achieved using a cloud-hosted authentication service and *Realtime Database* relay.
Currently, this service is provided by Google's [Firebase](https://firebase.google.com/) service.

The Opal PIE is typically deployed in a hospital (but does not have to be).
The user applications are deployed separately, on a web server and the mobile app stores.

## Deploying the Opal PIE

### Deployment diagram
### Deployment diagrams

We support different deployment scenarios for how the database is deployed.

For ease of deployment (such as when testing a deployment) you can deploy the database as a container:

```plantuml source="docs/install/diagrams/deployment_diagram_pie.puml"
```

Relationships between components on the same host are left out for brevity (except those making use of third-party components).

The database server can also be run on a separate server:

```plantuml source="docs/install/diagrams/deployment_diagram_pie_db.puml"
```

Relationships between components on the same host are left out for brevity (except those making use of third-party components).

### Automated deployment

We offer a semi-automated deployment via a [`copier`](https://copier.readthedocs.io/en/stable/) template.
This project template supports various deployment options and sets up the basic project structure to get the Opal PIE deployed in a few minutes.

Please follow the instructions in the [`deploy-pie`](https://github.com/opalmedapps/deploy-pie) repository.

## User Applications

### Deployment diagram
Expand Down