| features |
|
|||||
|---|---|---|---|---|---|---|
| languages |
|
This repository contains pre-configured Aidbox instance and implementation of $summary operation defined by IPS.
The IPS is intended to support the provision of essential healthcare information for a patient, regardless of where they are receiving care. It includes critical information such as allergies, medications, past surgeries, and other significant medical history details. See IPS Specification
Copy .env.tpl file into .env file:
cp .env.tpl .envIf you are hosting Aidbox on your local computer, obtain the self-hosted license as described in the documentation.
Add the license (AIDBOX_LICENSE) int the .env file.
docker compose up --buildOpen in browser http://localhost:8888
And log in witn username: admin and password: password
In the Aidbox admin window, navigate to the APIs section and choose REST Console.
The $summary operation requires either the logical ID (Patient.id) or a business identifier (Patient.identifier) of the patient.
You can use the following request to view all available patients:
GET /fhir/Patient?_elements=id,identifier
To request the IPS "document" Bundle for a specific patient using the REST Console, you can use the following request:
GET /fhir/Patient/[id]/$summary
Replace [id] with the logical ID of the patient you want to retrieve the IPS document for.
For example:
GET /fhir/Patient/2b90dd2b-2dab-4c75-9bb9-a355e07401e8/$summary
Or you can use request with identifier search parameter:
GET /fhir/Patient/$summary?identifier=<patient-identifier>
For example:
GET /fhir/Patient/$summary?identifier=574687583
If you're starting the Aidbox FHIR server for the first time, the initial step involves creating a Client resource with an ID and secret. Since the newly created client does not have default permissions to access the Aidbox REST API, the next step is to configure access policies. Refer to the documentation: Create and test access control
The easiest way to achieve this is by navigating to Auth > Sandbox in the Aidbox Web Admin UI and performing REST queries to create the 'basic' client and assign the AccessPolicy.
Once the client is created, you can perform the $summary operation using an HTTP tool, similar to the following example:
curl --location 'http://localhost:8888/fhir/Patient?_elements=id%2Cidentifier' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic YmFzaWM6c2VjcmV0' \
--data ''
This application works with aidbox running under the following settings (envs):
AIDBOX_FHIR_VERSION=4.0.1
AIDBOX_FHIR_SCHEMA_VALIDATION=true
AIDBOX_FHIR_PACKAGES=hl7.fhir.r4.core#4.0.1:hl7.fhir.uv.ips#1.1.0
AIDBOX_VALIDATE_BINDING_URL="https://r4.ontoserver.csiro.au/fhir/ValueSet/\$validate-code"It is possible to deploy Aidbox with Helm charts. To do so, follow the steps outlined below:
helm repo add aidbox https://aidbox.github.io/helm-charts
config: |-
listen_addresses = '*'
shared_buffers = '2GB'
max_wal_size = '4GB'
pg_stat_statements.max = 500
pg_stat_statements.save = false
pg_stat_statements.track = top
pg_stat_statements.track_utility = true
shared_preload_libraries = 'pg_stat_statements'
track_io_timing = on
wal_level = logical
wal_log_hints = on
archive_command = 'wal-g wal-push %p'
restore_command = 'wal-g wal-fetch %f %p'
env:
PGDATA: /data/pg
POSTGRES_DB: postgres
POSTGRES_PASSWORD: <your-postgres-password>
image.repository: healthsamurai/aidboxdb
image.tag: "16.1"
storage:
size: "10Gi"
className: <your-storage-className>helm upgrade --install aidboxdb aidbox/aidboxdb \
--namespace ips --create-namespace \
--values /path/to/db-config.yaml
host: <your-aidbox-host>
protocol: https
config:
PGHOST: aidboxdb.ips.svc.cluster.local
PGDATABASE: postgres
PGUSER: postgres
PGPASSWORD: <your-postgres-password>
AIDBOX_CLIENT_ID: <your-aidbox-client-id>
AIDBOX_CLIENT_SECRET: <your-aidbox-client-password>
AIDBOX_ADMIN_ID: <your-aidbox-admin-id>
AIDBOX_ADMIN_PASSWORD: <your-aidbox-admin-password>
AIDBOX_LICENSE: <aidbox-license>
AIDBOX_DEV_MODE: true
AIDBOX_FHIR_VERSION: 4.0.1
AIDBOX_FHIR_SCHEMA_VALIDATION: true
AIDBOX_FHIR_PACKAGES: hl7.fhir.r4.core#4.0.1:hl7.fhir.uv.ips#1.1.0
AIDBOX_VALIDATE_BINDING_URL: "https://r4.ontoserver.csiro.au/fhir/ValueSet/$validate-code"
AIDBOX_BASE_URL: <your-base-url>
AIDBOX_PORT: 8888
AIDBOX_COMPLIANCE: enabled
ingress:
annotations:
acme.cert-manager.io/http01-ingress-class: nginx
cert-manager.io/cluster-issuer: letsencrypt
kubernetes.io/ingress.class: nginxhelm upgrade --install aidbox aidbox/aidbox \
--namespace ips --create-namespace \
--values /path/to/aidbox-config.yaml
To deploy the application use prepared k8s config. Additionally, you have to add to the config resource Secret:
apiVersion: v1
kind: Secret
metadata:
name: ips-app
namespace: ips
stringData:
AIDBOX_CLIENT_ID: <your_aidbox_client_id>
AIDBOX_CLIENT_SECRET: <your_aidbox_client_secret>
APP_SECRET: <your_app_secret> # allows aidbox safely communicate with this app$summary issues GET /fhir/<Type>?patient=Patient/<id> for 13 clinical resource types. To make these fast, the bundled docker-compose.yaml runs Aidbox with BOX_FHIR_SEARCH_TOKEN_OPERATOR=#>> so that ?patient= compiles to (resource #>> '{...,id}') = '<id>', which can be served by a small per-type btree.
Create the indexes (one statement per POST /$sql — CONCURRENTLY cannot run inside a transaction):
-- SP `patient` resolves to .subject (10 types)
CREATE INDEX CONCURRENTLY IF NOT EXISTS observation_subject_id_idx ON observation ((resource #>> '{subject,id}'));
CREATE INDEX CONCURRENTLY IF NOT EXISTS condition_subject_id_idx ON condition ((resource #>> '{subject,id}'));
CREATE INDEX CONCURRENTLY IF NOT EXISTS procedure_subject_id_idx ON procedure ((resource #>> '{subject,id}'));
CREATE INDEX CONCURRENTLY IF NOT EXISTS diagnosticreport_subject_id_idx ON diagnosticreport ((resource #>> '{subject,id}'));
CREATE INDEX CONCURRENTLY IF NOT EXISTS medicationrequest_subject_id_idx ON medicationrequest ((resource #>> '{subject,id}'));
CREATE INDEX CONCURRENTLY IF NOT EXISTS medicationstatement_subject_id_idx ON medicationstatement ((resource #>> '{subject,id}'));
CREATE INDEX CONCURRENTLY IF NOT EXISTS careplan_subject_id_idx ON careplan ((resource #>> '{subject,id}'));
CREATE INDEX CONCURRENTLY IF NOT EXISTS deviceusestatement_subject_id_idx ON deviceusestatement ((resource #>> '{subject,id}'));
CREATE INDEX CONCURRENTLY IF NOT EXISTS flag_subject_id_idx ON flag ((resource #>> '{subject,id}'));
CREATE INDEX CONCURRENTLY IF NOT EXISTS clinicalimpression_subject_id_idx ON clinicalimpression ((resource #>> '{subject,id}'));
-- SP `patient` resolves to .patient (3 types)
CREATE INDEX CONCURRENTLY IF NOT EXISTS allergyintolerance_patient_id_idx ON allergyintolerance ((resource #>> '{patient,id}'));
CREATE INDEX CONCURRENTLY IF NOT EXISTS immunization_patient_id_idx ON immunization ((resource #>> '{patient,id}'));
CREATE INDEX CONCURRENTLY IF NOT EXISTS consent_patient_id_idx ON consent ((resource #>> '{patient,id}'));After building the indexes (and after any bulk load), refresh statistics so the planner picks them up:
ANALYZE observation;
ANALYZE condition;
ANALYZE procedure;
ANALYZE diagnosticreport;
ANALYZE medicationrequest;
ANALYZE medicationstatement;
ANALYZE careplan;
ANALYZE deviceusestatement;
ANALYZE flag;
ANALYZE clinicalimpression;
ANALYZE allergyintolerance;
ANALYZE immunization;
ANALYZE consent;