mirror of
https://github.com/samply/bridgehead.git
synced 2025-07-01 00:30:20 +02:00
Compare commits
20 Commits
8b5c47174a
...
feature/ex
Author | SHA1 | Date | |
---|---|---|---|
f139651e97 | |||
a689a2f808 | |||
141f1f22d0 | |||
b4a788e010 | |||
c33fbfc8bc | |||
faa8abd4ee | |||
7693289d4d | |||
d482324361 | |||
b7a42f3d3b | |||
fd013232f5 | |||
eb52554892 | |||
08c695e960 | |||
1513fe1c6c | |||
af08a9fb08 | |||
b95f0efbe7 | |||
99567e2b40 | |||
96ff6043a1 | |||
844ce3386e | |||
9782bf66b6 | |||
87f0e8ad7f |
130
README.md
130
README.md
@ -22,11 +22,16 @@ This repository is the starting point for any information and tools you will nee
|
||||
- [TLS terminating proxies](#tls-terminating-proxies)
|
||||
- [File structure](#file-structure)
|
||||
- [BBMRI-ERIC Directory entry needed](#bbmri-eric-directory-entry-needed)
|
||||
- [Directory sync tool](#directory-sync-tool)
|
||||
- [Loading data](#loading-data)
|
||||
- [Teiler (Frontend)](#teiler-frontend)
|
||||
- [Data Exporter Service](#data-exporter-service)
|
||||
- [Data Quality Report](#data-quality-report)
|
||||
4. [Things you should know](#things-you-should-know)
|
||||
- [Auto-Updates](#auto-updates)
|
||||
- [Auto-Backups](#auto-backups)
|
||||
- [Non-Linux OS](#non-linux-os)
|
||||
- [FAQ](#faq)
|
||||
5. [Troubleshooting](#troubleshooting)
|
||||
- [Docker Daemon Proxy Configuration](#docker-daemon-proxy-configuration)
|
||||
- [Monitoring](#monitoring)
|
||||
@ -301,26 +306,38 @@ Once you have added your biobank to the Directory you got persistent identifier
|
||||
|
||||
### Directory sync tool
|
||||
|
||||
The Bridgehead's **Directory Sync** is an optional feature that keeps the Directory up to date with your local data, e.g. number of samples. Conversely, it also updates the local FHIR store with the latest contact details etc. from the Directory. You must explicitly set your country specific directory URL, username and password to enable this feature.
|
||||
The Bridgehead's **Directory Sync** is an optional feature that keeps the BBMRI-ERIC Directory up to date with your local data, e.g. number of samples. Conversely, it can also update the local FHIR store with the latest contact details etc. from the BBMRI-ERIC Directory.
|
||||
|
||||
You should talk with your local data protection group regarding the information that is published by Directory sync.
|
||||
|
||||
Full details can be found in [directory_sync_service](https://github.com/samply/directory_sync_service).
|
||||
|
||||
To enable it, you will need to set these variables to the ```bbmri.conf``` file of your GitLab repository. Here is an example config:
|
||||
To enable it, you will need to explicitly set the username and password variables for BBMRI-ERIC Directory login in the configuration file of your GitLab repository (e.g. ```bbmri.conf```). Here is an example minimal config:
|
||||
|
||||
```
|
||||
DS_DIRECTORY_USER_NAME=your_directory_username
|
||||
DS_DIRECTORY_USER_PASS=your_directory_password
|
||||
```
|
||||
Please contact your National Node to obtain this information.
|
||||
Please contact your National Node or Directory support (directory-dev@helpdesk.bbmri-eric.eu) to obtain these credentials.
|
||||
|
||||
Optionally, you **may** change when you want Directory sync to run by specifying a [cron](https://crontab.guru) expression, e.g. `DS_TIMER_CRON="0 22 * * *"` for 10 pm every evening.
|
||||
The following environment variables can be used from within your config file to control the behavior of Directory sync:
|
||||
|
||||
Once you edited the gitlab config, the bridgehead will autoupdate the config with the values and will sync the data.
|
||||
| Variable | Purpose | Default if not specified |
|
||||
|:-----------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------|:---------------------------------------|
|
||||
| DS_DIRECTORY_URL | Base URL of the Directory | https://directory-backend.molgenis.net |
|
||||
| DS_DIRECTORY_USER_NAME | User name for logging in to Directory **Mandatory** | |
|
||||
| DS_DIRECTORY_USER_PASS | Password for logging in to Directory **Mandatory** | |
|
||||
| DS_DIRECTORY_DEFAULT_COLLECTION_ID | ID of collection to be used if not in samples | |
|
||||
| DS_DIRECTORY_ALLOW_STAR_MODEL | Set to 'True' to send star model info to Directory | True |
|
||||
| DS_FHIR_STORE_URL | URL for FHIR store | http://bridgehead-bbmri-blaze:8080 |
|
||||
| DS_TIMER_CRON | Execution interval for Directory sync, [cron](https://crontab.guru) format | 0 22 * * * |
|
||||
| DS_IMPORT_BIOBANKS | Set to 'True' to import biobank metadata from Directory | True |
|
||||
| DS_IMPORT_COLLECTIONS | Set to 'True' to import collection metadata from Directory | True |
|
||||
|
||||
Once you have finished editing the config, the Bridgehead will autoupdate the config with the values and will sync data at regular intervals, using the time specified in DS_TIMER_CRON.
|
||||
|
||||
There will be a delay before the effects of Directory sync become visible. First, you will need to wait until the time you have specified in ```TIMER_CRON```. Second, the information will then be synchronized from your national node with the central European Directory. This can take up to 24 hours.
|
||||
|
||||
More details of Directory sync can be found in [directory_sync_service](https://github.com/samply/directory_sync_service).
|
||||
|
||||
### Loading data
|
||||
|
||||
The data accessed by the federated search is held in the Bridgehead in a FHIR store (we use Blaze).
|
||||
@ -340,6 +357,24 @@ The storage space on your hard drive will depend on the number of FHIR resources
|
||||
|
||||
For more information on Blaze performance, please refer to [import performance](https://github.com/samply/blaze/blob/master/docs/performance/import.md).
|
||||
|
||||
### Clearing data
|
||||
|
||||
The Bridgehead's FHIR store, Blaze, saves its data in a Docker volume. This means that the data will persist even if you stop the Bridgehead. You can clear existing data from the FHIR store by deleting the relevant Docker volume.
|
||||
|
||||
First, stop the Bridgehead:
|
||||
```shell
|
||||
sudo systemctl stop bridgehead@<PROJECT>.service
|
||||
```
|
||||
Now remove the volume:
|
||||
```shell
|
||||
docker volume rm <PROJECT>_blaze-data
|
||||
```
|
||||
Finally, restart the Bridgehead:
|
||||
```shell
|
||||
sudo systemctl start bridgehead@<PROJECT>.service
|
||||
```
|
||||
You will need to do this for example if you are using a VM as a test environment and you subsequently want to use the same VM for production.
|
||||
|
||||
#### ETL for BBMRI and GBA
|
||||
|
||||
Normally, you will need to build your own ETL to feed the Bridgehead. However, there is one case where a short cut might be available:
|
||||
@ -347,6 +382,39 @@ Normally, you will need to build your own ETL to feed the Bridgehead. However, t
|
||||
|
||||
You can find the profiles for generating FHIR in [Simplifier](https://simplifier.net/bbmri.de/~resources?category=Profile).
|
||||
|
||||
### Teiler (Frontend)
|
||||
|
||||
Teiler is the web-based frontend of the Bridgehead, providing access to its various internal, and external services and components.
|
||||
To learn how to integrate your custom module into Teiler, please refer to https://github.com/samply/teiler-dashboard.
|
||||
- To activate Teiler, set the following environment variable in your `<PROJECT>.conf` file:
|
||||
|
||||
```bash
|
||||
ENABLE_TEILER=true
|
||||
```
|
||||
[For further information](ccp/modules/teiler.md)
|
||||
|
||||
### Data Exporter Service
|
||||
|
||||
The Exporter is a dedicated service for extracting and exporting Bridgehead data in (tabular) formats such as Excel, CSV, Opal, JSON, XML, ...
|
||||
- To enable the Exporter service, set the following environment variable in your `<PROJECT>.conf` file:
|
||||
|
||||
```bash
|
||||
ENABLE_EXPORTER=true
|
||||
```
|
||||
|
||||
#### Data Quality Report
|
||||
To assess the quality and plausibility of your imported data, the Reporter component is pre-configured to generate Excel reports with data quality metrics and statistical analyses. Reporter is part of the Exporter and can be enabled by setting the same environment variable in your `<PROJECT>.conf` file:
|
||||
```bash
|
||||
ENABLE_EXPORTER=true
|
||||
```
|
||||
|
||||
For convenience, it's recommended to enable the Teiler web frontend alongside the Exporter to access export and quality control features via a web interface: set the following environment varibles in your `<PROJECT>.conf` file:
|
||||
```bash
|
||||
ENABLE_TEILER=true
|
||||
ENABLE_EXPORTER=true
|
||||
```
|
||||
[For further information](ccp/modules/exporter.md)
|
||||
|
||||
## Things you should know
|
||||
|
||||
### Auto-Updates
|
||||
@ -386,6 +454,54 @@ We have tested the installation procedure with an Ubuntu 22.04 guest system runn
|
||||
|
||||
Installation under WSL ought to work, but we have not tested this.
|
||||
|
||||
### FAQ
|
||||
|
||||
**Q: How is the security of GitHub pulls, volumes/containers, and image signing ensured?**
|
||||
|
||||
A: Changes to Git branches that could be delivered to sites (main and develop) must be accepted via a pull request with at least two positive reviews.
|
||||
Containers/images are not built manually, but rather automatically through a CI/CD pipeline, so that an image can be rolled back to a defined code version at any time without changes.
|
||||
**Note:** If firewall access for (outgoing) connections to GitHub and/or Docker Hub is problematic at the site, mirrors for both services are available, operated by the DKFZ.
|
||||
|
||||
**Q: How is authentication between users and components regulated?**
|
||||
|
||||
A: When setting up a Bridgehead, a private key and a so-called Certificate Sign Request (CSR) are generated locally. This CSR is manually signed by the broker operator, which allows the Bridgehead access to the network infrastructure.
|
||||
All communication runs via Samply.Beam and is therefore end-to-end encrypted, but also signed. This allows the integrity and authenticity of the sender to be technically verified (which happens automatically both in the broker and at the recipients).
|
||||
The connection to the broker is additionally secured using traditional TLS (transport encryption over https).
|
||||
|
||||
**Q: Are there any statistics on incoming traffic from the Bridgehead (what goes in and what goes out)?**
|
||||
|
||||
A: Incoming and outgoing traffic can only enter/leave the Bridgehead via a forward or reverse proxy, respectively. These components log all connections.
|
||||
Statistical analysis is not currently being conducted, but is on the roadmap for some projects. We are also working on a dashboard for all tasks/responses delivered via Samply.Beam.
|
||||
|
||||
**Q: How is container access controlled, and what permission level is used?**
|
||||
|
||||
A: Currently, it is not possible to run the Bridgehead "out-of-the-box" as a rootless Docker Compose stack. The main reason is the operation of the reverse proxy (Traefik), which binds to the privileged ports 80 (HTTP) and 443 (HTTPS).
|
||||
Otherwise, there are no known technical obstacles, although we don't have concrete experience implementing this.
|
||||
At the file system level, a "bridgehead" user is created during installation, which manages the configuration and Bridgehead folders.
|
||||
|
||||
**Q: Is a cloud installation (not a company-owned one, but an external service provider) possible?**
|
||||
|
||||
A: Technically, yes. This is primarily a data protection issue between the participant and their cloud provider.
|
||||
The Bridgehead contains a data storage system that, during use, contains sensitive patient and sample data.
|
||||
There are cloud providers with whom appropriately worded contracts can be concluded to make this possible.
|
||||
Of course, the details must be discussed with the responsible data protection officer.
|
||||
|
||||
**Q: What needs to be considered regarding the Docker distribution/registry, and how is it used here?**
|
||||
|
||||
A: The Bridgehead images are located both in Docker Hub and mirrored in a registry operated by the DKFZ.
|
||||
The latter is used by default, avoiding potential issues with Docker Hub URL activation or rate limits.
|
||||
When using automatic updates (highly recommended), an daily check is performed for:
|
||||
- site configuration updates
|
||||
- Bridgehead software updates
|
||||
- container image updates
|
||||
|
||||
If updates are found, they are downloaded and applied.
|
||||
See the first question for the control mechanism.
|
||||
|
||||
**Q: Is data only transferred one-way (Bridgehead/FHIR Store → Central/Locator), or is two-way access necessary?**
|
||||
|
||||
A: By using Samply.Beam, only one outgoing connection to the broker is required at the network level (i.e., Bridgehead → Broker).
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Docker Daemon Proxy Configuration
|
||||
|
@ -12,5 +12,7 @@ services:
|
||||
DS_DIRECTORY_MOCK: ${DS_DIRECTORY_MOCK}
|
||||
DS_DIRECTORY_DEFAULT_COLLECTION_ID: ${DS_DIRECTORY_DEFAULT_COLLECTION_ID}
|
||||
DS_DIRECTORY_COUNTRY: ${DS_DIRECTORY_COUNTRY}
|
||||
DS_IMPORT_BIOBANKS: ${DS_IMPORT_BIOBANKS:-true}
|
||||
DS_IMPORT_COLLECTIONS: ${DS_IMPORT_COLLECTIONS:-true}
|
||||
depends_on:
|
||||
- "blaze"
|
||||
|
@ -1,20 +1,20 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDNTCCAh2gAwIBAgIUE/wu6FmI+KSMOalI65b+lI3HI4cwDQYJKoZIhvcNAQEL
|
||||
BQAwFjEUMBIGA1UEAxMLQnJva2VyLVJvb3QwHhcNMjQwOTE2MTUyMzU0WhcNMzQw
|
||||
OTE0MTUyNDI0WjAWMRQwEgYDVQQDEwtCcm9rZXItUm9vdDCCASIwDQYJKoZIhvcN
|
||||
AQEBBQADggEPADCCAQoCggEBAOt1I1FQt2bI4Nnjtg8JBYid29cBIkDT4MMb45Jr
|
||||
ays24y4R3WO7VJK9UjNduSq/A1jlA0W0A/szDf8Ojq6bBtg+uL92PTDjYH1QXwX0
|
||||
c7eMo2tvvyyrs/cb2/ovDBQ1lpibcxVmVAv042ASmil3SdqKKXpv3ATnF9I7V4cv
|
||||
fwB56FChaGIov5EK+9JOMjTx6oMlBEgUFR6qq/lSqM9my0HYwUFbX2W+nT9EKEIP
|
||||
9UP1eyfRZR3E/+oticnm/cS20BGCbjoYrNgLthXKyaASuhGoElKs8EZ3h9MiI+u0
|
||||
DpR0KpePhAkMLugBrgYWqkMwwD1684LfC4YVQrsLwzo5OW8CAwEAAaN7MHkwDgYD
|
||||
VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFPbXs3g3lMjH
|
||||
1JMe0a5aVbN7lB92MB8GA1UdIwQYMBaAFPbXs3g3lMjH1JMe0a5aVbN7lB92MBYG
|
||||
A1UdEQQPMA2CC0Jyb2tlci1Sb290MA0GCSqGSIb3DQEBCwUAA4IBAQBM5RsXb2HN
|
||||
FpC1mYfocXAn20Zu4d603qmc/IqkiOWbp36pWo+jk1AxejyRS9hEpQalgSnvcRPQ
|
||||
1hPEhGU+wvI0WWVi/01iNjVbXmJNPQEouXQWAT17dyp9vqQkPw8LNzpSV/qdPgbT
|
||||
Z9o3sZrjUsSLsK7A7Q5ky4ePkiJBaMsHeAD+wqGwpiJ4D2Xhp8e1v36TWM0qt2EA
|
||||
gySx9isx/jeGGPBmDqYB9BCal5lrihPN56jd+5pCkyXeZqKWiiXFJKXwcwxctYZc
|
||||
ADHIiTLLPXE8LHTUJAO51it1NAZ1S24aMzax4eWDXcWO7/ybbx5pkYkMd6EqlKHd
|
||||
8riQJIhY4huX
|
||||
-----END CERTIFICATE-----
|
||||
MIIDNTCCAh2gAwIBAgIUFzdpDi1OLdXyogtCsktHFhCILtMwDQYJKoZIhvcNAQEL
|
||||
BQAwFjEUMBIGA1UEAxMLQnJva2VyLVJvb3QwHhcNMjUwNjEwMTQzNjE1WhcNMzUw
|
||||
NjA4MTQzNjQ1WjAWMRQwEgYDVQQDEwtCcm9rZXItUm9vdDCCASIwDQYJKoZIhvcN
|
||||
AQEBBQADggEPADCCAQoCggEBALpJCWE9Qe19R9DqotdkPV6jfiuJSKI3UYkCWdWG
|
||||
nRfkKB6OaY5t3JCHDqaEME9FwSd2nFXhTp5F6snG/K7g8MCLIEzGzuSnrdjGqINq
|
||||
zXLfgqnxvQpPR4ARLNNgnKxZaq7m4Q3T/l+QAshK6CnCUWFQ6q5x3g/pZHFP2USd
|
||||
/G2FtDHX6YK4bHbbnigIPG6PdY2RYy60i30XGdIPBNf82XGkAtPUBz731gHOV5Vg
|
||||
d+jfAqTwZAhYC2CcNmswFw1H9GrvTI/9KZWKcZNUIqemc0A/FyEyONUM18/vjQ7D
|
||||
lUwOcQsgAg44QTOUPgqXv3sJPQM5EnGuv3yYV9u6Y2i78M8CAwEAAaN7MHkwDgYD
|
||||
VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFPrDeNWgtEyZ
|
||||
VM0yeoRZdK2QGjyvMB8GA1UdIwQYMBaAFPrDeNWgtEyZVM0yeoRZdK2QGjyvMBYG
|
||||
A1UdEQQPMA2CC0Jyb2tlci1Sb290MA0GCSqGSIb3DQEBCwUAA4IBAQAD2S0kqL18
|
||||
laewh+qnyZ0WMq12mLV/Rwll6ZuShCx2uAu3UZuIGWk3l7gG5zlws+i+zbaNcn4o
|
||||
HsS3WG9kiNLOMKp8LXGkjErl6RaQr+kb8qgYFTPjOr6v0OdVn6ve9RDNYB5Hd+zE
|
||||
9jAWmS8PfS2AldE4VAd0C4pWTAinhnKGrKdn1YAX5x+LMq1y0lc1Pd4CDgsjD6SS
|
||||
3td7JtenXqCX0mN0XSeck7vvFGa6QpcQoVcN9tRENctHZTwyeGA21IkXylpFPUkE
|
||||
LT60k48fNC8TZkBlfvtVGRebpm5krXIKEaVy5LniEpSuOR4hTqsgoQDntBjW4zHA
|
||||
GeWQ1wQNTEBX
|
||||
-----END CERTIFICATE-----
|
||||
|
86
bbmri/modules/exporter-compose.yml
Normal file
86
bbmri/modules/exporter-compose.yml
Normal file
@ -0,0 +1,86 @@
|
||||
version: "3.7"
|
||||
|
||||
services:
|
||||
exporter:
|
||||
image: docker.verbis.dkfz.de/ccp/dktk-exporter:latest
|
||||
container_name: bridgehead-bbmri-exporter
|
||||
environment:
|
||||
JAVA_OPTS: "-Xms1G -Xmx8G -XX:+UseG1GC"
|
||||
LOG_LEVEL: "INFO"
|
||||
EXPORTER_API_KEY: "${EXPORTER_API_KEY}" # Set in exporter-setup.sh
|
||||
CROSS_ORIGINS: "https://${HOST}"
|
||||
EXPORTER_DB_USER: "exporter"
|
||||
EXPORTER_DB_PASSWORD: "${EXPORTER_DB_PASSWORD}" # Set in exporter-setup.sh
|
||||
EXPORTER_DB_URL: "jdbc:postgresql://exporter-db:5432/exporter"
|
||||
HTTP_RELATIVE_PATH: "/bbmri-exporter"
|
||||
SITE: "${SITE_ID}"
|
||||
HTTP_SERVLET_REQUEST_SCHEME: "https"
|
||||
OPAL_PASSWORD: "${EXPORTER_OPAL_PASSWORD}"
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.exporter_bbmri.rule=PathPrefix(`/bbmri-exporter`)"
|
||||
- "traefik.http.services.exporter_bbmri.loadbalancer.server.port=8092"
|
||||
- "traefik.http.routers.exporter_bbmri.tls=true"
|
||||
- "traefik.http.middlewares.exporter_bbmri_strip.stripprefix.prefixes=/bbmri-exporter"
|
||||
- "traefik.http.routers.exporter_bbmri.middlewares=exporter_bbmri_strip"
|
||||
# Main router
|
||||
- "traefik.http.routers.exporter_bbmri.priority=20"
|
||||
|
||||
# API router
|
||||
- "traefik.http.routers.exporter_bbmri_api.middlewares=exporter_bbmri_strip,exporter_auth"
|
||||
- "traefik.http.routers.exporter_bbmri_api.rule=PathRegexp(`/bbmri-exporter/.+`)"
|
||||
- "traefik.http.routers.exporter_bbmri_api.tls=true"
|
||||
- "traefik.http.routers.exporter_bbmri_api.priority=25"
|
||||
|
||||
# Shared middlewares
|
||||
- "traefik.http.middlewares.exporter_auth.basicauth.users=${EXPORTER_USER}"
|
||||
|
||||
volumes:
|
||||
- "/var/cache/bridgehead/bbmri/exporter-files:/app/exporter-files/output"
|
||||
|
||||
exporter-db:
|
||||
image: docker.verbis.dkfz.de/cache/postgres:${POSTGRES_TAG}
|
||||
container_name: bridgehead-bbmri-exporter-db
|
||||
environment:
|
||||
POSTGRES_USER: "exporter"
|
||||
POSTGRES_PASSWORD: "${EXPORTER_DB_PASSWORD}" # Set in exporter-setup.sh
|
||||
POSTGRES_DB: "exporter"
|
||||
volumes:
|
||||
# Consider removing this volume once we find a solution to save Lens-queries to be executed in the explorer.
|
||||
- "/var/cache/bridgehead/bbmri/exporter-db:/var/lib/postgresql/data"
|
||||
|
||||
reporter:
|
||||
image: docker.verbis.dkfz.de/ccp/dktk-reporter:latest
|
||||
container_name: bridgehead-bbmri-reporter
|
||||
environment:
|
||||
JAVA_OPTS: "-Xms1G -Xmx8G -XX:+UseG1GC"
|
||||
LOG_LEVEL: "INFO"
|
||||
CROSS_ORIGINS: "https://${HOST}"
|
||||
HTTP_RELATIVE_PATH: "/bbmri-reporter"
|
||||
SITE: "${SITE_ID}"
|
||||
EXPORTER_API_KEY: "${EXPORTER_API_KEY}" # Set in exporter-setup.sh
|
||||
EXPORTER_URL: "http://exporter:8092"
|
||||
LOG_FHIR_VALIDATION: "false"
|
||||
HTTP_SERVLET_REQUEST_SCHEME: "https"
|
||||
|
||||
# In this initial development state of the bridgehead, we are trying to have so many volumes as possible.
|
||||
# However, in the first executions in the bbmri sites, this volume seems to be very important. A report is
|
||||
# a process that can take several hours, because it depends on the exporter.
|
||||
# There is a risk that the bridgehead restarts, losing the already created export.
|
||||
|
||||
volumes:
|
||||
- "/var/cache/bridgehead/bbmri/reporter-files:/app/reports"
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.reporter_bbmri.rule=PathPrefix(`/bbmri-reporter`)"
|
||||
- "traefik.http.services.reporter_bbmri.loadbalancer.server.port=8095"
|
||||
- "traefik.http.routers.reporter_bbmri.tls=true"
|
||||
- "traefik.http.middlewares.reporter_bbmri_strip.stripprefix.prefixes=/bbmri-reporter"
|
||||
- "traefik.http.routers.reporter_bbmri.middlewares=reporter_bbmri_strip"
|
||||
- "traefik.http.routers.reporter_bbmri.priority=20"
|
||||
|
||||
- "traefik.http.routers.reporter_bbmri_api.middlewares=reporter_bbmri_strip,exporter_auth"
|
||||
- "traefik.http.routers.reporter_bbmri_api.rule=PathRegexp(`/bbmri-reporter/.+`)"
|
||||
- "traefik.http.routers.reporter_bbmri_api.tls=true"
|
||||
- "traefik.http.routers.reporter_bbmri_api.priority=25"
|
||||
|
8
bbmri/modules/exporter-setup.sh
Normal file
8
bbmri/modules/exporter-setup.sh
Normal file
@ -0,0 +1,8 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
if [ "$ENABLE_EXPORTER" == true ]; then
|
||||
log INFO "Exporter setup detected -- will start Exporter service."
|
||||
OVERRIDE+=" -f ./$PROJECT/modules/exporter-compose.yml"
|
||||
EXPORTER_DB_PASSWORD="$(echo \"This is a salt string to generate one consistent password for the exporter. It is not required to be secret.\" | sha1sum | openssl pkeyutl -sign -inkey /etc/bridgehead/pki/${SITE_ID}.priv.pem | base64 | head -c 30)"
|
||||
EXPORTER_API_KEY="$(echo \"This is a salt string to generate one consistent API KEY for the exporter. It is not required to be secret.\" | sha1sum | openssl pkeyutl -sign -inkey /etc/bridgehead/pki/${SITE_ID}.priv.pem | base64 | head -c 64)"
|
||||
fi
|
15
bbmri/modules/exporter.md
Normal file
15
bbmri/modules/exporter.md
Normal file
@ -0,0 +1,15 @@
|
||||
# Exporter and Reporter
|
||||
|
||||
|
||||
## Exporter
|
||||
The exporter is a REST API that exports the data of the different databases of the bridgehead in a set of tables.
|
||||
It can accept different output formats as CSV, Excel, JSON or XML. It can also export data into Opal.
|
||||
|
||||
## Exporter-DB
|
||||
It is a database to save queries for its execution in the exporter.
|
||||
The exporter manages also the different executions of the same query in through the database.
|
||||
|
||||
## Reporter
|
||||
This component is a plugin of the exporter that allows to create more complex Excel reports described in templates.
|
||||
It is compatible with different template engines as Groovy, Thymeleaf,...
|
||||
It is perfect to generate a document as our traditional CCP quality report.
|
69
bbmri/modules/teiler-compose.yml
Normal file
69
bbmri/modules/teiler-compose.yml
Normal file
@ -0,0 +1,69 @@
|
||||
version: "3.7"
|
||||
|
||||
services:
|
||||
|
||||
teiler-orchestrator:
|
||||
image: docker.verbis.dkfz.de/cache/samply/teiler-orchestrator:latest
|
||||
container_name: bridgehead-teiler-orchestrator
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.teiler_orchestrator_bbmri.rule=PathPrefix(`/bbmri-teiler`)"
|
||||
- "traefik.http.services.teiler_orchestrator_bbmri.loadbalancer.server.port=9000"
|
||||
- "traefik.http.routers.teiler_orchestrator_bbmri.tls=true"
|
||||
- "traefik.http.middlewares.teiler_orchestrator_bbmri_strip.stripprefix.prefixes=/bbmri-teiler"
|
||||
- "traefik.http.routers.teiler_orchestrator_bbmri.middlewares=teiler_orchestrator_bbmri_strip"
|
||||
environment:
|
||||
TEILER_BACKEND_URL: "/bbmri-teiler-backend"
|
||||
TEILER_DASHBOARD_URL: "/bbmri-teiler-dashboard"
|
||||
DEFAULT_LANGUAGE: "${TEILER_DEFAULT_LANGUAGE_LOWER_CASE}"
|
||||
HTTP_RELATIVE_PATH: "/bbmri-teiler"
|
||||
|
||||
teiler-dashboard:
|
||||
image: docker.verbis.dkfz.de/cache/samply/teiler-dashboard:develop
|
||||
container_name: bridgehead-teiler-dashboard
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.teiler_dashboard_bbmri.rule=PathPrefix(`/bbmri-teiler-dashboard`)"
|
||||
- "traefik.http.services.teiler_dashboard_bbmri.loadbalancer.server.port=80"
|
||||
- "traefik.http.routers.teiler_dashboard_bbmri.tls=true"
|
||||
- "traefik.http.middlewares.teiler_dashboard_bbmri_strip.stripprefix.prefixes=/bbmri-teiler-dashboard"
|
||||
- "traefik.http.routers.teiler_dashboard_bbmri.middlewares=teiler_dashboard_bbmri_strip"
|
||||
environment:
|
||||
DEFAULT_LANGUAGE: "${TEILER_DEFAULT_LANGUAGE}"
|
||||
TEILER_BACKEND_URL: "/bbmri-teiler-backend"
|
||||
TEILER_DASHBOARD_URL: "/bbmri-teiler-dashboard"
|
||||
OIDC_URL: "${OIDC_URL}"
|
||||
OIDC_CLIENT_ID: "${OIDC_PUBLIC_CLIENT_ID}"
|
||||
OIDC_TOKEN_GROUP: "${OIDC_GROUP_CLAIM}"
|
||||
TEILER_ADMIN_NAME: "${OPERATOR_FIRST_NAME} ${OPERATOR_LAST_NAME}"
|
||||
TEILER_ADMIN_EMAIL: "${OPERATOR_EMAIL}"
|
||||
TEILER_ADMIN_PHONE: "${OPERATOR_PHONE}"
|
||||
TEILER_PROJECT: "${PROJECT}"
|
||||
EXPORTER_API_KEY: "${EXPORTER_API_KEY}"
|
||||
TEILER_ORCHESTRATOR_URL: "/bbmri-teiler"
|
||||
TEILER_ORCHESTRATOR_HTTP_RELATIVE_PATH: "/bbmri-teiler"
|
||||
TEILER_USER: "${OIDC_USER_GROUP}"
|
||||
TEILER_ADMIN: "${OIDC_ADMIN_GROUP}"
|
||||
REPORTER_DEFAULT_TEMPLATE_ID: "bbmri-qb"
|
||||
EXPORTER_DEFAULT_TEMPLATE_ID: "bbmri"
|
||||
|
||||
|
||||
teiler-backend:
|
||||
image: docker.verbis.dkfz.de/ccp/bbmri-teiler-backend:latest
|
||||
container_name: bridgehead-teiler-backend
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.teiler_backend_bbmri.rule=PathPrefix(`/bbmri-teiler-backend`)"
|
||||
- "traefik.http.services.teiler_backend_bbmri.loadbalancer.server.port=8085"
|
||||
- "traefik.http.routers.teiler_backend_bbmri.tls=true"
|
||||
- "traefik.http.middlewares.teiler_backend_bbmri_strip.stripprefix.prefixes=/bbmri-teiler-backend"
|
||||
- "traefik.http.routers.teiler_backend_bbmri.middlewares=teiler_backend_bbmri_strip"
|
||||
environment:
|
||||
LOG_LEVEL: "INFO"
|
||||
APPLICATION_PORT: "8085"
|
||||
DEFAULT_LANGUAGE: "${TEILER_DEFAULT_LANGUAGE}"
|
||||
TEILER_ORCHESTRATOR_HTTP_RELATIVE_PATH: "/bbmri-teiler"
|
||||
TEILER_ORCHESTRATOR_URL: "/bbmri-teiler"
|
||||
TEILER_DASHBOARD_DE_URL: "/bbmri-teiler-dashboard/de"
|
||||
TEILER_DASHBOARD_EN_URL: "/bbmri-teiler-dashboard/en"
|
||||
HTTP_PROXY: "http://forward_proxy:3128"
|
8
bbmri/modules/teiler-setup.sh
Normal file
8
bbmri/modules/teiler-setup.sh
Normal file
@ -0,0 +1,8 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
if [ "$ENABLE_TEILER" == true ];then
|
||||
log INFO "Teiler setup detected -- will start Teiler services."
|
||||
OVERRIDE+=" -f ./$PROJECT/modules/teiler-compose.yml"
|
||||
TEILER_DEFAULT_LANGUAGE=EN
|
||||
TEILER_DEFAULT_LANGUAGE_LOWER_CASE=${TEILER_DEFAULT_LANGUAGE,,}
|
||||
fi
|
287
bbmri/modules/teiler.md
Normal file
287
bbmri/modules/teiler.md
Normal file
@ -0,0 +1,287 @@
|
||||
# Teiler
|
||||
|
||||
**Teiler** is the central frontend of the **bridgehead system**. It brings together multiple independent tools—each built as a **microfrontend**—into a single, unified web application.
|
||||
|
||||
Users interact with Teiler as one coherent interface, but behind the scenes, it dynamically integrates and displays self-contained modules developed with different technologies (**Angular**, **Vue**, **React**, etc.). This modular approach makes Teiler highly flexible, allowing teams to develop, deploy, and maintain features independently.
|
||||
|
||||
Teiler ensures:
|
||||
|
||||
* **A consistent look and feel** across tools.
|
||||
* **Smooth navigation** between components.
|
||||
* **Seamless user authentication** across the entire interface.
|
||||
|
||||
Each independent tool integrated into Teiler is called a **bridgehead app**. A bridgehead app can be:
|
||||
|
||||
- A fully standalone microfrontend with its own frontend and backend services.
|
||||
- An embedded service inside the Teiler Dashboard.
|
||||
- An external link to another service, possibly hosted on a central server or elsewhere in the federated research network.
|
||||
|
||||
The modularity of Teiler enables it to adapt easily to the evolving needs of the research federated network by simply adding, updating, or removing bridgehead apps.
|
||||
|
||||
Below is a breakdown of Teiler's internal components that make this orchestration possible.
|
||||
|
||||
- [Teiler Orchestrator](#teiler-orchestrator)
|
||||
- [Teiler Dashboard](#teiler-dashboard)
|
||||
- [Teiler Backend](#teiler-backend)
|
||||
|
||||
---
|
||||
|
||||
## Teiler Orchestrator
|
||||
|
||||
**GitHub repository:** [https://github.com/samply/teiler-orchestrator](https://github.com/samply/teiler-orchestrator)
|
||||
|
||||
The **Teiler Orchestrator** is the entry point of the **Single Page Application (SPA)**. It consists of:
|
||||
|
||||
- An **HTML root page**.
|
||||
- A **JavaScript layer** that:
|
||||
- **Retrieves microfrontend configurations** from the backend.
|
||||
- **Registers and manages** the microfrontends using [**Single-SPA**](https://single-spa.js.org/), the framework Teiler uses to create and coordinate its microfrontend environment.
|
||||
|
||||
Using this information, the orchestrator dynamically **loads the correct microfrontend** for a given route and manages its **lifecycle** (*init*, *mount*, *unmount*) in real time.
|
||||
|
||||
**Microfrontends** run in their own containers and can be implemented with any major frontend framework. To be compatible with Teiler, they must integrate with **Single-SPA**.
|
||||
|
||||
To encourage developers to create their own microfrontends and integrate them into Teiler, we provide **starter templates** for **Angular**, **Vue**, and **React**. Developing a new microfrontend is straightforward:
|
||||
|
||||
1. Use one of the templates.
|
||||
2. Extend it with your own functionality.
|
||||
3. Add its configuration in the **Teiler Backend**.
|
||||
|
||||
This modular approach accelerates development and fosters collaboration.
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Teiler Dashboard
|
||||
|
||||
**GitHub repository:** [https://github.com/samply/teiler-dashboard](https://github.com/samply/teiler-dashboard)
|
||||
|
||||
The **Teiler Dashboard** is the unified interface users interact with after logging in. It provides:
|
||||
|
||||
- A **single point of access** where various bridgehead apps are embedded as microfrontends.
|
||||
- **Central navigation** and **session management** for a smooth user experience.
|
||||
|
||||
### Authentication and Authorization
|
||||
|
||||
Teiler uses **OpenID Connect (OIDC)** for user authentication, accessible via the **top navigation bar**.
|
||||
|
||||
We consider three possible **application roles**:
|
||||
|
||||
| Role | Description |
|
||||
|--------|-----------------------------------------------------------|
|
||||
| Public | Accessible by any user without the need to log in |
|
||||
| User | Normal users working with various bridgehead applications |
|
||||
| Admin | Bridgehead system administrators |
|
||||
|
||||
It is possible to **deactivate OIDC authentication** entirely. In such cases, **all apps must have at least the public role** to allow access. While this may be suitable for development or testing, we **strongly encourage** at least some external authentication mechanism or network-level access control to secure the bridgehead environment.
|
||||
|
||||
Alternatively, basic authentication can be enforced through the existing **Traefik infrastructure** integrated with the bridgehead.
|
||||
|
||||
---
|
||||
|
||||
## Teiler Backend
|
||||
|
||||
**GitHub repository:** [https://github.com/samply/teiler-backend](https://github.com/samply/teiler-backend)
|
||||
|
||||
The **Teiler Backend** serves as the central configuration hub for all microfrontends and bridgehead apps. It defines:
|
||||
|
||||
- Which bridgehead apps are available.
|
||||
- Their loading URLs and routes.
|
||||
- Optional metadata such as display names, icons, roles, and activation status.
|
||||
|
||||
It enables the orchestrator to remain **generic and flexible**, adapting dynamically to whatever apps are defined in the backend configuration.
|
||||
|
||||
### Assets Directory
|
||||
|
||||
There is an **assets** directory where you can save images and other static files to be accessible to your microfrontends. This helps configure and customize apps more easily and quickly.
|
||||
|
||||
Assets can be referenced via:
|
||||
|
||||
```
|
||||
<Teiler Backend URL>/assets/<filename>
|
||||
```
|
||||
|
||||
### App Configuration via Environment Variables
|
||||
|
||||
Apps are configured using environment variables with the following structure:
|
||||
|
||||
```
|
||||
TEILER_APP<Number>_<suffix>
|
||||
Optional: TEILER_APP<Number>_<LanguageCode>_<suffix>
|
||||
```
|
||||
|
||||
- The **number** is just for grouping variables for a single app and has no intrinsic meaning.
|
||||
- The **app** is the unit within Teiler, shown as a box in the dashboard.
|
||||
- Apps can be:
|
||||
- Embedded apps inside the Teiler Dashboard (there is a helper Python script for generating embedded apps: [create-embedded-app.py](https://github.com/samply/teiler-dashboard/blob/main/create-embedded-app.py))
|
||||
- External links (e.g., central services outside the local bridgehead instance)
|
||||
- An app's frontend (microfrontend or embedded app) can either contain the entire functionality or serve as a frontend communicating with other backend microservices in the bridgehead.
|
||||
|
||||
Currently supported languages in the main projects DKTK and BBMRI are **English (EN)** and **German (DE)**, but the system can be extended to other languages.
|
||||
|
||||
The Teiler Dashboard requests variables from the backend for each app and passes the desired language code. If a language-specific variable is unavailable, the default language value is returned.
|
||||
|
||||
### Internationalization (i18n)
|
||||
#### ⚠️ Important
|
||||
|
||||
If you make any changes to the **Teiler Dashboard**, and those changes involve text elements (e.g., labels, buttons, messages), you must also update the **English translations**, since the application uses **internationalization (i18n)**.
|
||||
|
||||
The **default language** of the project is **German**, so any new text must be manually translated into English after extracting the updated i18n entries.
|
||||
|
||||
To extract new translation entries, run the following command:
|
||||
|
||||
```bash
|
||||
ng extract-i18n --output-path src/i18n --format=xlf2
|
||||
````
|
||||
|
||||
This will generate or update the file:
|
||||
`src/i18n/messages.xlf`
|
||||
|
||||
---
|
||||
|
||||
#### ✅ Requirements to Run the Extraction Command
|
||||
|
||||
| Program | Purpose | Linux Shell (Ubuntu/Debian) | Windows PowerShell |
|
||||
| -------------------------------- | ---------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- |
|
||||
| **Node.js** | JavaScript runtime required by Angular and npm | `sudo apt update && sudo apt install nodejs npm`<br>**or**<br>[Use NodeSource setup](https://github.com/nodesource/distributions) (recommended) | [Download from nodejs.org](https://nodejs.org) and install manually |
|
||||
| **npm** | Node package manager (comes with Node.js) | *(Included with Node.js)* | *(Included with Node.js)* |
|
||||
| **Angular CLI** | Command-line interface for Angular tooling | `npm install -g @angular/cli` | `npm install -g @angular/cli` |
|
||||
| **Angular project dependencies** | Required packages from `package.json` | `npm install` | `npm install` |
|
||||
|
||||
---
|
||||
|
||||
#### ✏️ Updating the English Translation
|
||||
|
||||
After running the extraction command, the file `src/i18n/messages.xlf` will contain any newly added i18n entries.
|
||||
|
||||
To provide English translations:
|
||||
|
||||
1. Open `src/i18n/messages.en.xlf`.
|
||||
2. Compare it with the updated `messages.xlf` to identify any new entries.
|
||||
3. Copy the new `<trans-unit>` blocks from `messages.xlf` into `messages.en.xlf`.
|
||||
4. For each entry, add the English translation inside the `<target>` tag (in `messages.en.xlf`):
|
||||
|
||||
```xml
|
||||
<trans-unit id="..." datatype="html">
|
||||
<source>Willkommen</source>
|
||||
<target>Welcome</target>
|
||||
</trans-unit>
|
||||
```
|
||||
|
||||
### App Availability Monitoring
|
||||
|
||||
The Teiler Backend regularly **pings apps** to check availability and displays status messages such as:
|
||||
|
||||
- "Frontend not available"
|
||||
- "Backend not available"
|
||||
- "Frontend and Backend not available"
|
||||
|
||||
### Accepted TEILER_APP Variable Suffixes
|
||||
|
||||
| Suffix | Description |
|
||||
|------------------|---------------------------------------------------------------------------------------------------------------|
|
||||
| NAME | Identifier of the app (no spaces). For embedded apps, must match the identifier defined in Teiler Dashboard. |
|
||||
| TITLE | Display title shown to users. |
|
||||
| DESCRIPTION | Brief description of the app. |
|
||||
| BACKENDURL | URL of the backend microservice (if applicable). |
|
||||
| BACKENDCHECKURL | URL that the backend pings to verify backend availability. Defaults to BACKENDURL if not specified. |
|
||||
| SOURCEURL | URL of the microfrontend or external link (not used for embedded apps). |
|
||||
| SOURCECHECKURL | URL to ping to check microfrontend or external link availability. Defaults to SOURCEURL if not specified. |
|
||||
| ROLES | Comma-separated roles allowed: `TEILER_PUBLIC`, `TEILER_USER`, `TEILER_ADMIN`. |
|
||||
| ISACTIVATED | `true` or `false`. Used to temporarily deactivate an app without deleting its config. |
|
||||
| ICONCLASS | Bootstrap icon class to display in app box (e.g., `"bi bi-search"`). |
|
||||
| ICONSOURCEURL | URL to an image icon. Prefer using local assets instead of external URLs. |
|
||||
| ORDER | Relative display order of the app in the dashboard. |
|
||||
| ISEXTERNALLINK | `true` or `false`. Indicates if the app is an external link outside the local bridgehead. |
|
||||
| ISLOCAL | `true` or `false`. Indicates if the app runs locally within the bridgehead site or on a central server. |
|
||||
|
||||
*Note:* Embedded apps often have many of these variables preconfigured and may not require manual specification. See the [Teiler Dashboard documentation](https://github.com/samply/teiler-dashboard) for details.
|
||||
|
||||
### Additional Teiler Backend Variables for Dashboard Configuration
|
||||
|
||||
| Variable Prefix | Description |
|
||||
|------------------------------------|--------------------------------------------------------------------------------------------------------------|
|
||||
| TEILER_DASHBOARD_ | General configuration of the dashboard. |
|
||||
| TEILER_DASHBOARD_<LangCode>_ | Language-specific configuration overrides. |
|
||||
|
||||
Important suffixes include:
|
||||
|
||||
| Suffix | Description |
|
||||
|------------------|-------------------------------------------------------------------------------------------|
|
||||
| WELCOME_TITLE | Title shown on the initial screen before login. |
|
||||
| WELCOME_TEXT | Welcome message or instructions before login. |
|
||||
| FURTHER_INFO | Additional informational text or links. |
|
||||
| BACKGROUND_IMAGE_URL | URL to a background image (SVG recommended for scalability). |
|
||||
| LOGO_URL | URL to the project or bridgehead logo. |
|
||||
| LOGO_HEIGHT | Height of the displayed logo. |
|
||||
| LOGO_TEXT | Title text of the bridgehead (e.g., "DKTK Bridgehead"). |
|
||||
| COLOR_PALETTE | JSON link to color palettes for text, lines, icons, and background (especially for SVGs). |
|
||||
| COLOR_PROFILE | Selected color profile from the palette. (color palette name) |
|
||||
| FONT | Font family for the dashboard text. |
|
||||
|
||||
### 🎨 Color Palette
|
||||
|
||||
Below is an example of a **color palette** definition in JSON format:
|
||||
|
||||
```json
|
||||
{
|
||||
"color-palettes": [
|
||||
{
|
||||
"name": "Grey",
|
||||
"colors": {
|
||||
"text": "grey",
|
||||
"line": "grey",
|
||||
"icon": "grey",
|
||||
"background": "grey"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Black",
|
||||
"colors": {
|
||||
"text": "black",
|
||||
"line": "black",
|
||||
"icon": "black",
|
||||
"background": "#F7ADAD"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Each palette contains a unique `name` and a set of color values for different UI elements.
|
||||
|
||||
#### 🔍 Palette Elements
|
||||
|
||||
| **Variable** | **Description** |
|
||||
| ------------ | --------------------------------------------------- |
|
||||
| `name` | Identifier of the color palette |
|
||||
| `text` | Color used for text |
|
||||
| `line` | Color used for lines (e.g., borders, dividers) |
|
||||
| `icon` | Color used for icons |
|
||||
| `background` | Background color (especially useful for SVG images) |
|
||||
|
||||
|
||||
---
|
||||
|
||||
### 🚀 Ready to Extend Teiler?
|
||||
|
||||
If you want to create your own **bridgehead app** and integrate it into **Teiler**, start by:
|
||||
|
||||
1. Selecting a template **or**
|
||||
2. Building a microfrontend compatible with [Single-SPA](https://single-spa.js.org/).
|
||||
|
||||
Then, register your app’s configuration in the **Teiler Backend** as described above.
|
||||
|
||||
> 💡 **Tip:** This flexible, modular design makes it easy to plug in your own features and services.
|
||||
|
||||
---
|
||||
|
||||
### 🔧 Build & Contribute Your App!
|
||||
|
||||
🧩 **Join the ecosystem!**
|
||||
Add your app to Teiler and expand its functionality for everyone.
|
||||
|
||||
Whether it’s a visualization tool, a data processing module, or a custom UI component — your contribution can help grow the platform. 💪
|
||||
|
||||
> 👉 **Get started today and shape the future of Teiler!**
|
||||
|
@ -1,3 +1,9 @@
|
||||
BROKER_ID=broker-test.bbmri-test.samply.de
|
||||
BROKER_URL=https://${BROKER_ID}
|
||||
PROXY_ID=${SITE_ID}.${BROKER_ID}
|
||||
PRIVATEKEYFILENAME=/etc/bridgehead/pki/${SITE_ID}.priv.pem
|
||||
BROKER_URL_FOR_PREREQ=$BROKER_URL
|
||||
|
||||
# Makes sense for all European Biobanks
|
||||
: ${ENABLE_ERIC:=true}
|
||||
|
||||
@ -5,7 +11,6 @@
|
||||
: ${ENABLE_GBN:=false}
|
||||
|
||||
FOCUS_RETRY_COUNT=${FOCUS_RETRY_COUNT:-64}
|
||||
PRIVATEKEYFILENAME=/etc/bridgehead/pki/${SITE_ID}.priv.pem
|
||||
|
||||
for module in $PROJECT/modules/*.sh
|
||||
do
|
||||
|
@ -45,7 +45,6 @@ services:
|
||||
OPAL_PRIVATE_KEY: "/run/secrets/opal-key.pem"
|
||||
OPAL_CERTIFICATE: "/run/secrets/opal-cert.pem"
|
||||
OIDC_URL: "${OIDC_URL}"
|
||||
OIDC_REALM: "${OIDC_REALM}"
|
||||
OIDC_CLIENT_ID: "${OIDC_PRIVATE_CLIENT_ID}"
|
||||
OIDC_CLIENT_SECRET: "${OIDC_CLIENT_SECRET}"
|
||||
OIDC_ADMIN_GROUP: "${OIDC_ADMIN_GROUP}"
|
||||
@ -141,7 +140,7 @@ services:
|
||||
--client-id="${OIDC_PRIVATE_CLIENT_ID}"
|
||||
--client-secret="${OIDC_CLIENT_SECRET}"
|
||||
--redirect-url="https://${HOST}${OAUTH2_CALLBACK}"
|
||||
--oidc-issuer-url="${OIDC_ISSUER_URL}"
|
||||
--oidc-issuer-url="${OIDC_URL}"
|
||||
--scope="openid email profile"
|
||||
--code-challenge-method="S256"
|
||||
--skip-provider-button=true
|
||||
|
@ -1,15 +1,345 @@
|
||||
# Exporter and Reporter
|
||||
|
||||
---
|
||||
|
||||
## Exporter
|
||||
The exporter is a REST API that exports the data of the different databases of the bridgehead in a set of tables.
|
||||
It can accept different output formats as CSV, Excel, JSON or XML. It can also export data into Opal.
|
||||
|
||||
**GitHub:** [https://github.com/samply/exporter](https://github.com/samply/exporter)
|
||||
|
||||
The Exporter is a **REST API** that enables the export of data from various **bridgehead databases** as **structured tables**. It currently supports only **FHIR sources** such as **Blaze**, but it is designed to be extended to **other types** of data sources. The Exporter provides multiple output formats, including **CSV, Excel, JSON, and XML**, and can also export data directly into **Opal (DataSHIELD)**.
|
||||
|
||||
### How it works
|
||||
|
||||
The **user** submits a **query** and specifies the desired **export template** and **output format**. The **query** acts like the `WHERE` clause in SQL, filtering data, while the **template** defines what data to select and how to format it, similar to the `SELECT` clause. The Exporter then processes this to generate the export files.
|
||||
|
||||
### Environment Variables
|
||||
|
||||
Below is a list of configurable environment variables used by the Exporter:
|
||||
|
||||
| Variable | Default | Description |
|
||||
| --------------------------------------------------------- | ------------------------------------------- | ---------------------------------------------------------- |
|
||||
| APPLICATION\_PORT | 8092 | Port on which the application runs. |
|
||||
| ARCHIVE\_EXPIRED\_QUERIES\_CRON\_EXPRESSION | `0 0 2 * * *` | Cron expression for archiving expired queries. |
|
||||
| CLEAN\_TEMP\_FILES\_CRON\_EXPRESSION | `0 0 1 * * *` | Cron expression for cleaning temporary files. |
|
||||
| CLEAN\_WRITE\_FILES\_CRON\_EXPRESSION | `0 0 2 * * *` | Cron expression for cleaning written files. |
|
||||
| CONVERTER\_TEMPLATE\_DIRECTORY | | Directory containing conversion templates. |
|
||||
| CONVERTER\_XML\_APPLICATION\_CONTEXT\_PATH | | Path to the XML application context used by the converter. |
|
||||
| CROSS\_ORIGINS | | Allowed CORS origins (comma-separated). |
|
||||
| CSV\_SEPARATOR\_REPLACEMENT | | Character to replace CSV separators within values. |
|
||||
| EXCEL\_WORKBOOK\_WINDOW | 30000000 | Memory window size for Excel workbook processing. |
|
||||
| EXPORTER\_API\_KEY | | API key for authenticating access to the exporter. |
|
||||
| EXPORTER\_DB\_FLYWAY\_MIGRATION\_ENABLED | true | Enable Flyway DB migrations on startup. |
|
||||
| EXPORTER\_DB\_PASSWORD | | Password for exporter database. |
|
||||
| EXPORTER\_DB\_URL | `jdbc:postgresql://localhost:5432/exporter` | JDBC URL for exporter DB. |
|
||||
| EXPORTER\_DB\_USER | | Username for exporter DB. |
|
||||
| FHIR\_PACKAGES\_DIRECTORY | | Directory where FHIR packages are stored. |
|
||||
| HAPI\_FHIR\_CLIENT\_LOG\_LEVEL | OFF | Log level for HAPI FHIR client. |
|
||||
| HIBERNATE\_LOG | false | Enable Hibernate SQL logging. |
|
||||
| HTTP\_RELATIVE\_PATH | | Relative base path for HTTP endpoints. |
|
||||
| HTTP\_SERVLET\_REQUEST\_SCHEME | http | Default HTTP scheme. |
|
||||
| LOG\_FHIR\_VALIDATION | | Enable logging of FHIR validation results. |
|
||||
| LOG\_LEVEL | INFO | Application log level. |
|
||||
| MAX\_NUMBER\_OF\_EXCEL\_ROWS\_IN\_A\_SHEET | 100000 | Max rows per Excel sheet. |
|
||||
| MAX\_NUMBER\_OF\_RETRIES | 10 | Max retry attempts. |
|
||||
| MERGE\_FILENAME | | Name of merged output file. |
|
||||
| SITE | | Site identifier for filenames/logs. |
|
||||
| TEMP\_FILES\_LIFETIME\_IN\_DAYS | 1 | Lifetime of temporary files (days). |
|
||||
| TEMPORAL\_FILE\_DIRECTORY | | Directory for temporary files. |
|
||||
| TIMEOUT\_IN\_SECONDS | 10 | Default timeout (seconds). |
|
||||
| TIMESTAMP\_FORMAT | | Timestamp format string. |
|
||||
| WEBCLIENT\_BUFFER\_SIZE\_IN\_BYTES | 8192 | Buffer size for web client. |
|
||||
| WEBCLIENT\_CONNECTION\_TIMEOUT\_IN\_SECONDS | 5 | Connection timeout (seconds). |
|
||||
| WEBCLIENT\_MAX\_NUMBER\_OF\_RETRIES | 10 | Max retries for web client. |
|
||||
| WEBCLIENT\_REQUEST\_TIMEOUT\_IN\_SECONDS | 10 | Request timeout (seconds). |
|
||||
| WEBCLIENT\_TCP\_KEEP\_CONNECTION\_NUMBER\_OF\_TRIES | 3 | TCP keepalive retry attempts. |
|
||||
| WEBCLIENT\_TCP\_KEEP\_IDLE\_IN\_SECONDS | 30 | TCP keepalive idle time (seconds). |
|
||||
| WEBCLIENT\_TCP\_KEEP\_INTERVAL\_IN\_SECONDS | 10 | TCP keepalive probe interval (seconds). |
|
||||
| WEBCLIENT\_TIME\_IN\_SECONDS\_AFTER\_RETRY\_WITH\_FAILURE | 1 | Wait time after failed retry (seconds). |
|
||||
| WRITE\_FILE\_DIRECTORY | | Directory for final output files. |
|
||||
| WRITE\_FILES\_LIFETIME\_IN\_DAYS | 30 | Lifetime of written files (days). |
|
||||
| XML\_FILE\_MERGER\_ROOT\_ELEMENT | Containers | Root element for XML file merging. |
|
||||
| ZIP\_FILENAME | `exporter-files-${SITE}-${TIMESTAMP}.zip` | Pattern for ZIP archive naming. |
|
||||
|
||||
---
|
||||
|
||||
### About Cron Expressions in Spring
|
||||
|
||||
Cron expressions configure scheduled tasks and consist of six space-separated fields representing second, minute, hour, day of month, month, and day of week. For example, the default `0 0 2 * * *` means “at 2:00 AM every day.” These expressions allow precise scheduling for maintenance tasks such as cleaning files or archiving data.
|
||||
|
||||
---
|
||||
|
||||
## Exporter-DB
|
||||
It is a database to save queries for its execution in the exporter.
|
||||
The exporter manages also the different executions of the same query in through the database.
|
||||
|
||||
**GitHub:** [https://github.com/samply/exporter-db](https://github.com/samply/exporter-db) (If exists; if not, just remove or adjust accordingly)
|
||||
|
||||
The Exporter-DB stores queries for execution by the Exporter and tracks multiple executions of the same query, managing versioning and scheduling.
|
||||
|
||||
---
|
||||
|
||||
## Reporter
|
||||
This component is a plugin of the exporter that allows to create more complex Excel reports described in templates.
|
||||
It is compatible with different template engines as Groovy, Thymeleaf,...
|
||||
It is perfect to generate a document as our traditional CCP quality report.
|
||||
|
||||
**GitHub:** [https://github.com/samply/reporter](https://github.com/samply/reporter)
|
||||
|
||||
The Reporter is a **plugin for the Exporter** designed for generating **complex Excel reports** based on **customizable templates**. It supports various template engines like **Groovy** and **Thymeleaf**, making it ideal for producing detailed documents such as the traditional CCP **data quality report**.
|
||||
|
||||
---
|
||||
|
||||
## Exporter Templates
|
||||
|
||||
An exporter template describes the **structure** and **content** of the **export output**.
|
||||
|
||||
### Main Elements
|
||||
|
||||
* **converter**: Defines the export job, specifying output files and data sources.
|
||||
* **container**: Represents a logical grouping of data rows (like a table).
|
||||
* **attribute**: Defines individual data fields/columns extracted from the data source.
|
||||
|
||||
### Other Elements
|
||||
|
||||
* **cql**: Contains Clinical Quality Language metadata used to enrich or filter data.
|
||||
* **fhir-rev-include**: Defines FHIR reverse includes to fetch related resources.
|
||||
* **fhir-package**: (To be detailed)
|
||||
* **fhir-terminology-server**: (To be detailed)
|
||||
|
||||
### Example Snippet
|
||||
|
||||
```xml
|
||||
<converter id="ccp" excel-filename="Export-${SITE}-${TIMESTAMP}.xlsx" source-id="blaze-store" >
|
||||
<container id="Patient" csv-filename="Patient-${SITE}-${TIMESTAMP}.csv" excel-sheet="Patient" xml-filename="Patient-${SITE}-${TIMESTAMP}.xml" xml-root-element="Patients" xml-element="Patient" json-filename="Patient-${SITE}-${TIMESTAMP}.json" json-key="Patients" >
|
||||
<attribute id="Patient-ID" default-name="PatientID" val-fhir-path="Patient.id.value" anonym="Pat" op="EXTRACT_RELATIVE_ID"/>
|
||||
|
||||
<attribute default-name="DKTKIDGlobal" val-fhir-path="Patient.identifier.where(type.coding.code = 'Global').value.value"/>
|
||||
<attribute default-name="DKTKIDLokal" val-fhir-path="Patient.identifier.where(type.coding.code = 'Lokal').value.value" />
|
||||
<attribute default-name="DateOfBirth" val-fhir-path="Patient.birthDate.value.toString().substring(0, 4) + '-01-01'"/>
|
||||
<attribute default-name="Gender" val-fhir-path="Patient.gender.value" />
|
||||
</container>
|
||||
|
||||
<container id="Diagnosis" csv-filename="Diagnosis-${SITE}-${TIMESTAMP}.csv" excel-sheet="Diagnosis" xml-filename="Diagnosis-${SITE}-${TIMESTAMP}.xml" xml-root-element="Diagnoses" xml-element="Diagnosis" json-filename="Diagnosis-${SITE}-${TIMESTAMP}.json" json-key="Diagnoses">
|
||||
<attribute id="Diagnosis-ID" default-name="DiagnosisID" val-fhir-path="Condition.id.value" anonym="Dia" op="EXTRACT_RELATIVE_ID"/>
|
||||
<attribute id="Patient-ID" link="Patient.Patient-ID" default-name="PatientID" val-fhir-path="Condition.subject.reference.value" anonym="Pat"/>
|
||||
|
||||
<attribute default-name="ICD10Code" val-fhir-path="Condition.code.coding.code.value"/>
|
||||
<attribute default-name="ICDOTopographyCode" val-fhir-path="Condition.bodySite.coding.where(system = 'urn:oid:2.16.840.1.113883.6.43.1').code.value"/>
|
||||
<attribute default-name="LocalizationSide" val-fhir-path="Condition.bodySite.coding.where(system = 'http://dktk.dkfz.de/fhir/onco/core/CodeSystem/SeitenlokalisationCS').code.value"/>
|
||||
</container>
|
||||
|
||||
<container id="Histology" csv-filename="Histology-${SITE}-${TIMESTAMP}.csv" excel-sheet="Histology" xml-filename="Histology-${SITE}-${TIMESTAMP}.xml" xml-root-element="Histologies" xml-element="Histology" json-filename="Histology-${SITE}-${TIMESTAMP}.json" json-key="Histologies" >
|
||||
<attribute id="Histology-ID" default-name="HistologyID" val-fhir-path="Observation.where(code.coding.code = '59847-4').id" anonym="His" op="EXTRACT_RELATIVE_ID"/>
|
||||
<attribute id="Diagnosis-ID" link="Diagnosis.Diagnosis-ID" default-name="DiagnosisID" val-fhir-path="Observation.where(code.coding.code = '59847-4').focus.reference.value" anonym="Dia"/>
|
||||
<attribute id="Patient-ID" link="Patient.Patient-ID" default-name="PatientID" val-fhir-path="Observation.where(code.coding.code = '59847-4').subject.reference.value" anonym="Pat" />
|
||||
|
||||
<attribute default-name="ICDOMorphologyCode" val-fhir-path="Observation.where(code.coding.code = '59847-4').value.coding.code.value"/>
|
||||
<attribute default-name="Grading" val-fhir-path="Observation.where(code.coding.code = '59542-1').value.coding.code.value" join-fhir-path="Observation.where(code.coding.code = '59847-4').hasMember.reference.value"/>
|
||||
</container>
|
||||
|
||||
<container id="Radiation-Therapy" csv-filename="RadiationTherapy-${SITE}-${TIMESTAMP}.csv" excel-sheet="RadiationTherapy" xml-filename="RadiationTherapy-${SITE}-${TIMESTAMP}.xml" xml-root-element="Radiation-Therapies" xml-element="Radiation-Therapy" json-filename="RadiationTherapy-${SITE}-${TIMESTAMP}.json" json-key="Radiation Therapies">
|
||||
<attribute id="Radiation-Therapy-ID" default-name="RadiationTherapyID" val-fhir-path="Procedure.where(category.coding.code = 'ST').id" anonym="Rad" op="EXTRACT_RELATIVE_ID"/>
|
||||
<attribute id="Diagnosis-ID" link="Diagnosis.Diagnosis-ID" default-name="DiagnosisID" val-fhir-path="Procedure.where(category.coding.code = 'ST').reasonReference.reference.value" anonym="Dia"/>
|
||||
<attribute id="Patient-ID" link="Patient.Patient-ID" default-name="PatientID" val-fhir-path="Procedure.where(category.coding.code = 'ST').subject.reference.value" anonym="Pat" />
|
||||
|
||||
<attribute default-name="RadiationTherapyRelationToSurgery" val-fhir-path="Procedure.extension('http://dktk.dkfz.de/fhir/StructureDefinition/onco-core-Extension-StellungZurOp').value.coding.code.value"/>
|
||||
<attribute default-name="RadiationTherapyIntention" val-fhir-path="Procedure.extension('http://dktk.dkfz.de/fhir/StructureDefinition/onco-core-Extension-SYSTIntention').value.coding.code.value" />
|
||||
<attribute default-name="RadiationTherapyStart" val-fhir-path="Procedure.where(category.coding.code = 'ST').performed.start.value"/>
|
||||
<attribute default-name="RadiationTherapyEnd" val-fhir-path="Procedure.where(category.coding.code = 'ST').performed.end.value"/>
|
||||
<attribute default-name="Nebenwirkung Grad" val-fhir-path="AdverseEvent.severity.coding.code.value" join-fhir-path="/AdverseEvent.suspectEntity.instance.reference.where(value.startsWith('Procedure')).value" />
|
||||
</container>
|
||||
|
||||
|
||||
<cql>
|
||||
<default-fhir-search-query>Patient</default-fhir-search-query>
|
||||
|
||||
<token key="DKTK_STRAT_MEDICATION_STRATIFIER" value="define MedicationStatement: if InInitialPopulation then [MedicationStatement] else {} as List <MedicationStatement> " />
|
||||
<token key="DKTK_STRAT_PRIMARY_DIAGNOSIS_NO_SORT_STRATIFIER" value="define PrimaryDiagnosis: First( from [Condition] C where C.extension.where(url='http://hl7.org/fhir/StructureDefinition/condition-related').empty()) " />
|
||||
|
||||
<measure-parameters>
|
||||
{
|
||||
"resourceType": "Parameters",
|
||||
"parameter": [
|
||||
{
|
||||
"name": "periodStart",
|
||||
"valueDate": "2000"
|
||||
},
|
||||
{
|
||||
"name": "periodEnd",
|
||||
"valueDate": "2030"
|
||||
},
|
||||
{
|
||||
"name": "reportType",
|
||||
"valueCode": "subject-list"
|
||||
}
|
||||
]
|
||||
}
|
||||
</measure-parameters>
|
||||
</cql>
|
||||
|
||||
|
||||
|
||||
<fhir-rev-include>Observation:patient</fhir-rev-include>
|
||||
<fhir-rev-include>Condition:patient</fhir-rev-include>
|
||||
<fhir-rev-include>ClinicalImpression:patient</fhir-rev-include>
|
||||
<fhir-rev-include>MedicationStatement:patient</fhir-rev-include>
|
||||
<fhir-rev-include>Procedure:patient</fhir-rev-include>
|
||||
<fhir-rev-include>Specimen:patient</fhir-rev-include>
|
||||
<fhir-rev-include>AdverseEvent:subject</fhir-rev-include>
|
||||
<fhir-rev-include>CarePlan:patient</fhir-rev-include>
|
||||
|
||||
</converter>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 1. **Converter**
|
||||
|
||||
Main tag of an exporter template grouping converters to find the best chain for data conversion.
|
||||
|
||||
| Tag | Description |
|
||||
| ------------- | --------------------------------------------------------------------------------------------- |
|
||||
| `<converter>` | Main tag for exporter template containing sources, metadata, and additional query information |
|
||||
|
||||
| Attribute | Description | Example | Default |
|
||||
| ------------------------ | --------------------------------------------------------------------------------------- | --------------------------------------------------- | ------- |
|
||||
| id | ID to reference a template | `id="ccp-opal"` | — |
|
||||
| default-name | Default name when output is in a single file format (no extension; added automatically) | — | — |
|
||||
| ignore | Deactivate template but keep accessible | `ignore="true"` | false |
|
||||
| excel-filename | Name of the Excel output file (supports variables `${SITE}`, `${TIMESTAMP}`) | `excel-filename="Export-${SITE}-${TIMESTAMP}.xlsx"` | — |
|
||||
| csv-separator | CSV separator character | — | `"\t"` |
|
||||
| source-id | ID of the data source | `source-id="blaze-store"` | — |
|
||||
| target-id | ID of a target server for file transfer (e.g., Opal for DataSHIELD) | `target-id="opal"` | — |
|
||||
| opal-project | Opal-specific: name of project | — | — |
|
||||
| opal-permission-type | Opal permission type (`user` or `group`) | — | — |
|
||||
| opal-permission-subjects | Opal permission subjects | — | — |
|
||||
| opal-permission | Opal permission (`administrate` or `use`) | — | — |
|
||||
|
||||
**Notes:**
|
||||
* You can use variables such as `${SITE}`, `${TIMESTAMP}`, and other environment variables within tags.
|
||||
* To define environment variables for a specific export, use the HTTP parameter **`CONTEXT`**.
|
||||
The value must be a Base64-encoded string containing comma-separated key-value pairs.
|
||||
* **Example:**
|
||||
Plain: `KEY1=VALUE1,KEY2=VALUE2`
|
||||
Base64: `S0VZMT1WQUxVRTEsS0VZMj1WQUxVRTI=`
|
||||
|
||||
**Allowed child elements:**
|
||||
|
||||
* `<container>`, `<cql>`, `<fhir-rev-include>`, `<fhir-package>`, `<fhir-terminology-server>`
|
||||
|
||||
---
|
||||
|
||||
### 2. **Container**
|
||||
|
||||
Represents a data table with columns (attributes).
|
||||
|
||||
| Tag | Description |
|
||||
| ------------- | --------------------------------------------------- |
|
||||
| `<container>` | Defines a container/table with attributes (columns) |
|
||||
|
||||
| Attribute | Description | Example | Default |
|
||||
| ---------------- | ------------------------------------------------------------ | --------------------------------------------- | ------- |
|
||||
| id | Container ID to reference | — | — |
|
||||
| default-name | Name of Excel sheet/file (no extension, added automatically) | — | — |
|
||||
| csv-filename | Name of CSV file | `csv-filename="Diagnosis-${TIMESTAMP}.csv"` | — |
|
||||
| json-filename | Name of JSON file | `json-filename="diagnosis-${TIMESTAMP}.json"` | — |
|
||||
| xml-filename | Name of XML file | `xml-filename="diagnosis-${TIMESTAMP}.xml"` | — |
|
||||
| xml-root-element | Root element name in XML | `xml-root-element="diagnoses"` | — |
|
||||
| xml-element | Element name for each entry in XML | `xml-element="diagnosis"` | — |
|
||||
| excel-sheet | Excel sheet name | `excel-sheet="diagnosis-${TIMESTAMP}.xlsx"` | — |
|
||||
| opal-table | Opal table name | `opal-name="Diagnosis"` | — |
|
||||
| opal-entity-type | Opal entity type | — | — |
|
||||
|
||||
---
|
||||
|
||||
### 3. **Attribute**
|
||||
|
||||
Represents a column in a container/table.
|
||||
|
||||
| Tag | Description |
|
||||
| ------------- | --------------------------- |
|
||||
| `<attribute>` | Defines an attribute/column |
|
||||
|
||||
| Attribute | Description | Example | Default |
|
||||
| ------------------------- | ---------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | ------- |
|
||||
| id | Attribute ID | `id="Patient-ID"` | — |
|
||||
| default-name | Default name of the attribute (used if no output-specific name provided) | — | — |
|
||||
| link | Reference to an attribute of another container (format: `<container-name>.<attribute-id>`) | `link="Patient.Patient-ID"` | — |
|
||||
| csv-column | Name of the CSV column | — | — |
|
||||
| excel-column | Name of the Excel column | — | — |
|
||||
| json-key | JSON key | — | — |
|
||||
| xml-element | XML element name | — | — |
|
||||
| opal-value-type | Opal-specific value type | — | — |
|
||||
| opal-script | Script to be applied to the field in Opal | — | — |
|
||||
| primary-key | Marks attribute as primary key | `primary-key="true"` | false |
|
||||
| validation | Marks attribute as syntactic validation field (ends with `-Validation` in DKTK/BBMRI reporter) | `validation="true"` | false |
|
||||
| val-fhir-path | FHIR path to extract value (if source is a FHIR server) | `val-fhir-path="Patient.gender.value"` | — |
|
||||
| join-fhir-path | FHIR path for joining secondary resources to main resource | `join-fhir-path="/AdverseEvent.suspectEntity.instance.reference.where(value.startsWith('Procedure')).value"` | — |
|
||||
| condition-value-fhir-path | Condition filtering for complex value extraction (FHIR path syntax) | `condition-value-fhir-path="Patient.birthDate <= today() - 18 'years'"` | — |
|
||||
| anonym | Anonymization prefix; replaces real value with `anonym` + number | `anonym="Pat"` | — |
|
||||
| mdr | Metadata repository ID in DKTK context | `mdr="dktk:dataelement:20:3"` | — |
|
||||
| op | Operation applied on value (e.g., `EXTRACT_RELATIVE_ID`) | `op="EXTRACT_RELATIVE_ID"` | — |
|
||||
|
||||
---
|
||||
|
||||
### Notes on **join-fhir-path**
|
||||
|
||||
* Used to join resources in FHIR queries when container references multiple resources.
|
||||
* Two join types:
|
||||
|
||||
* **Direct:** main resource points to secondary resource.
|
||||
* **Indirect:** secondary resource points back to main resource (path begins with `/`).
|
||||
* Joins can chain multiple resources, e.g., `R1 -> R2 -> R3`, with commas separating joins.
|
||||
|
||||
---
|
||||
|
||||
### 4. **CQL**
|
||||
|
||||
Contains metadata and details important for handling CQL queries.
|
||||
|
||||
| Tag | Description |
|
||||
| ------- | ---------------------------------------------------------------- |
|
||||
| `<cql>` | Container for CQL query metadata including tokens and parameters |
|
||||
|
||||
---
|
||||
|
||||
### 5. **Token (CQL)**
|
||||
|
||||
Replaces keys in CQL queries with specific values (commonly used for stratifiers).
|
||||
|
||||
| Tag | Description |
|
||||
| --------- | ------------------------------------- |
|
||||
| `<token>` | Contains `key` and `value` attributes |
|
||||
|
||||
| Attribute | Description | Example |
|
||||
| --------- | ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
|
||||
| key | Key to replace in CQL | `key="DKTK_STRAT_MEDICATION_STRATIFIER"` |
|
||||
| value | CQL code snippet that replaces key | `value="define MedicationStatement: if InInitialPopulation then [MedicationStatement] else {} as List <MedicationStatement>"` |
|
||||
|
||||
---
|
||||
|
||||
### 6. **Measure Parameters (CQL)**
|
||||
|
||||
Parameters for a CQL measure query, typically in JSON format.
|
||||
|
||||
| Tag | Description |
|
||||
| ---------------------- | ----------------------------------------------------------- |
|
||||
| `<measure-parameters>` | Parameters such as `periodStart`, `periodEnd`, `reportType` |
|
||||
|
||||
---
|
||||
|
||||
### 7. **Default FHIR Search Query (CQL)**
|
||||
|
||||
FHIR search query applied after obtaining measure reports from CQL.
|
||||
|
||||
| Tag | Description | Example |
|
||||
| ----------------------------- | ----------------------------------------------------- | --------- |
|
||||
| `<default-fhir-search-query>` | Defines a FHIR resource type to query (e.g., Patient) | `Patient` |
|
||||
|
||||
---
|
||||
|
||||
### 8. **FHIR Reverse Include**
|
||||
|
||||
Defines which resources should be reverse-included when using FHIR search as input or CQL\_DATA.
|
||||
|
||||
| Tag | Description |
|
||||
| -------------------- | ------------------------------------------------------------ |
|
||||
| `<fhir-rev-include>` | Specifies reverse include resources to simplify FHIR queries |
|
||||
|
||||
---
|
||||
|
||||
|
@ -23,7 +23,6 @@ services:
|
||||
OIDC_ADMIN_GROUP: "${OIDC_ADMIN_GROUP}"
|
||||
OIDC_CLIENT_ID: "${OIDC_PRIVATE_CLIENT_ID}"
|
||||
OIDC_CLIENT_SECRET: "${OIDC_CLIENT_SECRET}"
|
||||
OIDC_REALM: "${OIDC_REALM}"
|
||||
OIDC_URL: "${OIDC_URL}"
|
||||
|
||||
labels:
|
||||
|
@ -13,8 +13,8 @@ services:
|
||||
- "traefik.http.middlewares.teiler_orchestrator_ccp_strip.stripprefix.prefixes=/ccp-teiler"
|
||||
- "traefik.http.routers.teiler_orchestrator_ccp.middlewares=teiler_orchestrator_ccp_strip"
|
||||
environment:
|
||||
TEILER_BACKEND_URL: "https://${HOST}/ccp-teiler-backend"
|
||||
TEILER_DASHBOARD_URL: "https://${HOST}/ccp-teiler-dashboard"
|
||||
TEILER_BACKEND_URL: "/ccp-teiler-backend"
|
||||
TEILER_DASHBOARD_URL: "/ccp-teiler-dashboard"
|
||||
DEFAULT_LANGUAGE: "${TEILER_DEFAULT_LANGUAGE_LOWER_CASE}"
|
||||
HTTP_RELATIVE_PATH: "/ccp-teiler"
|
||||
|
||||
@ -30,9 +30,9 @@ services:
|
||||
- "traefik.http.routers.teiler_dashboard_ccp.middlewares=teiler_dashboard_ccp_strip"
|
||||
environment:
|
||||
DEFAULT_LANGUAGE: "${TEILER_DEFAULT_LANGUAGE}"
|
||||
TEILER_BACKEND_URL: "https://${HOST}/ccp-teiler-backend"
|
||||
TEILER_BACKEND_URL: "/ccp-teiler-backend"
|
||||
TEILER_DASHBOARD_URL: "/ccp-teiler-dashboard"
|
||||
OIDC_URL: "${OIDC_URL}"
|
||||
OIDC_REALM: "${OIDC_REALM}"
|
||||
OIDC_CLIENT_ID: "${OIDC_PUBLIC_CLIENT_ID}"
|
||||
OIDC_TOKEN_GROUP: "${OIDC_GROUP_CLAIM}"
|
||||
TEILER_ADMIN_NAME: "${OPERATOR_FIRST_NAME} ${OPERATOR_LAST_NAME}"
|
||||
@ -40,8 +40,7 @@ services:
|
||||
TEILER_ADMIN_PHONE: "${OPERATOR_PHONE}"
|
||||
TEILER_PROJECT: "${PROJECT}"
|
||||
EXPORTER_API_KEY: "${EXPORTER_API_KEY}"
|
||||
TEILER_ORCHESTRATOR_URL: "https://${HOST}/ccp-teiler"
|
||||
TEILER_DASHBOARD_HTTP_RELATIVE_PATH: "/ccp-teiler-dashboard"
|
||||
TEILER_ORCHESTRATOR_URL: "/ccp-teiler"
|
||||
TEILER_ORCHESTRATOR_HTTP_RELATIVE_PATH: "/ccp-teiler"
|
||||
TEILER_USER: "${OIDC_USER_GROUP}"
|
||||
TEILER_ADMIN: "${OIDC_ADMIN_GROUP}"
|
||||
@ -62,20 +61,12 @@ services:
|
||||
environment:
|
||||
LOG_LEVEL: "INFO"
|
||||
APPLICATION_PORT: "8085"
|
||||
APPLICATION_ADDRESS: "${HOST}"
|
||||
DEFAULT_LANGUAGE: "${TEILER_DEFAULT_LANGUAGE}"
|
||||
CONFIG_ENV_VAR_PATH: "/run/secrets/ccp.conf"
|
||||
TEILER_ORCHESTRATOR_HTTP_RELATIVE_PATH: "/ccp-teiler"
|
||||
TEILER_ORCHESTRATOR_URL: "https://${HOST}/ccp-teiler"
|
||||
TEILER_DASHBOARD_DE_URL: "https://${HOST}/ccp-teiler-dashboard/de"
|
||||
TEILER_DASHBOARD_EN_URL: "https://${HOST}/ccp-teiler-dashboard/en"
|
||||
CENTRAX_URL: "${CENTRAXX_URL}"
|
||||
TEILER_ORCHESTRATOR_URL: "/ccp-teiler"
|
||||
TEILER_DASHBOARD_DE_URL: "/ccp-teiler-dashboard/de"
|
||||
TEILER_DASHBOARD_EN_URL: "/ccp-teiler-dashboard/en"
|
||||
HTTP_PROXY: "http://forward_proxy:3128"
|
||||
ENABLE_MTBA: "${ENABLE_MTBA}"
|
||||
ENABLE_DATASHIELD: "${ENABLE_DATASHIELD}"
|
||||
secrets:
|
||||
- ccp.conf
|
||||
|
||||
secrets:
|
||||
ccp.conf:
|
||||
file: /etc/bridgehead/ccp.conf
|
||||
IDMANAGER_UPLOAD_APIKEY: "${IDMANAGER_UPLOAD_APIKEY}" # Only used to check if the ID Manager is active
|
||||
|
@ -1,19 +1,287 @@
|
||||
# Teiler
|
||||
This module orchestrates the different microfrontends of the bridgehead as a single page application.
|
||||
|
||||
**Teiler** is the central frontend of the **bridgehead system**. It brings together multiple independent tools—each built as a **microfrontend**—into a single, unified web application.
|
||||
|
||||
Users interact with Teiler as one coherent interface, but behind the scenes, it dynamically integrates and displays self-contained modules developed with different technologies (**Angular**, **Vue**, **React**, etc.). This modular approach makes Teiler highly flexible, allowing teams to develop, deploy, and maintain features independently.
|
||||
|
||||
Teiler ensures:
|
||||
|
||||
* **A consistent look and feel** across tools.
|
||||
* **Smooth navigation** between components.
|
||||
* **Seamless user authentication** across the entire interface.
|
||||
|
||||
Each independent tool integrated into Teiler is called a **bridgehead app**. A bridgehead app can be:
|
||||
|
||||
- A fully standalone microfrontend with its own frontend and backend services.
|
||||
- An embedded service inside the Teiler Dashboard.
|
||||
- An external link to another service, possibly hosted on a central server or elsewhere in the federated research network.
|
||||
|
||||
The modularity of Teiler enables it to adapt easily to the evolving needs of the research federated network by simply adding, updating, or removing bridgehead apps.
|
||||
|
||||
Below is a breakdown of Teiler's internal components that make this orchestration possible.
|
||||
|
||||
- [Teiler Orchestrator](#teiler-orchestrator)
|
||||
- [Teiler Dashboard](#teiler-dashboard)
|
||||
- [Teiler Backend](#teiler-backend)
|
||||
|
||||
---
|
||||
|
||||
## Teiler Orchestrator
|
||||
Single SPA component that consists on the root HTML site of the single page application and a javascript code that
|
||||
gets the information about the microfrontend calling the teiler backend and is responsible for registering them. With the
|
||||
resulting mapping, it can initialize, mount and unmount the required microfrontends on the fly.
|
||||
|
||||
**GitHub repository:** [https://github.com/samply/teiler-orchestrator](https://github.com/samply/teiler-orchestrator)
|
||||
|
||||
The **Teiler Orchestrator** is the entry point of the **Single Page Application (SPA)**. It consists of:
|
||||
|
||||
The microfrontends run independently in different containers and can be based on different frameworks (Angular, Vue, React,...)
|
||||
This microfrontends can run as single alone but need an extension with Single-SPA (https://single-spa.js.org/docs/ecosystem).
|
||||
There are also available three templates (Angular, Vue, React) to be directly extended to be used directly in the teiler.
|
||||
- An **HTML root page**.
|
||||
- A **JavaScript layer** that:
|
||||
- **Retrieves microfrontend configurations** from the backend.
|
||||
- **Registers and manages** the microfrontends using [**Single-SPA**](https://single-spa.js.org/), the framework Teiler uses to create and coordinate its microfrontend environment.
|
||||
|
||||
Using this information, the orchestrator dynamically **loads the correct microfrontend** for a given route and manages its **lifecycle** (*init*, *mount*, *unmount*) in real time.
|
||||
|
||||
**Microfrontends** run in their own containers and can be implemented with any major frontend framework. To be compatible with Teiler, they must integrate with **Single-SPA**.
|
||||
|
||||
To encourage developers to create their own microfrontends and integrate them into Teiler, we provide **starter templates** for **Angular**, **Vue**, and **React**. Developing a new microfrontend is straightforward:
|
||||
|
||||
1. Use one of the templates.
|
||||
2. Extend it with your own functionality.
|
||||
3. Add its configuration in the **Teiler Backend**.
|
||||
|
||||
This modular approach accelerates development and fosters collaboration.
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Teiler Dashboard
|
||||
It consists on the main dashboard and a set of embedded services.
|
||||
### Login
|
||||
user and password in ccp.local.conf
|
||||
|
||||
**GitHub repository:** [https://github.com/samply/teiler-dashboard](https://github.com/samply/teiler-dashboard)
|
||||
|
||||
The **Teiler Dashboard** is the unified interface users interact with after logging in. It provides:
|
||||
|
||||
- A **single point of access** where various bridgehead apps are embedded as microfrontends.
|
||||
- **Central navigation** and **session management** for a smooth user experience.
|
||||
|
||||
### Authentication and Authorization
|
||||
|
||||
Teiler uses **OpenID Connect (OIDC)** for user authentication, accessible via the **top navigation bar**.
|
||||
|
||||
We consider three possible **application roles**:
|
||||
|
||||
| Role | Description |
|
||||
|--------|-----------------------------------------------------------|
|
||||
| Public | Accessible by any user without the need to log in |
|
||||
| User | Normal users working with various bridgehead applications |
|
||||
| Admin | Bridgehead system administrators |
|
||||
|
||||
It is possible to **deactivate OIDC authentication** entirely. In such cases, **all apps must have at least the public role** to allow access. While this may be suitable for development or testing, we **strongly encourage** at least some external authentication mechanism or network-level access control to secure the bridgehead environment.
|
||||
|
||||
Alternatively, basic authentication can be enforced through the existing **Traefik infrastructure** integrated with the bridgehead.
|
||||
|
||||
---
|
||||
|
||||
## Teiler Backend
|
||||
In this component, the microfrontends are configured.
|
||||
|
||||
**GitHub repository:** [https://github.com/samply/teiler-backend](https://github.com/samply/teiler-backend)
|
||||
|
||||
The **Teiler Backend** serves as the central configuration hub for all microfrontends and bridgehead apps. It defines:
|
||||
|
||||
- Which bridgehead apps are available.
|
||||
- Their loading URLs and routes.
|
||||
- Optional metadata such as display names, icons, roles, and activation status.
|
||||
|
||||
It enables the orchestrator to remain **generic and flexible**, adapting dynamically to whatever apps are defined in the backend configuration.
|
||||
|
||||
### Assets Directory
|
||||
|
||||
There is an **assets** directory where you can save images and other static files to be accessible to your microfrontends. This helps configure and customize apps more easily and quickly.
|
||||
|
||||
Assets can be referenced via:
|
||||
|
||||
```
|
||||
<Teiler Backend URL>/assets/<filename>
|
||||
```
|
||||
|
||||
### App Configuration via Environment Variables
|
||||
|
||||
Apps are configured using environment variables with the following structure:
|
||||
|
||||
```
|
||||
TEILER_APP<Number>_<suffix>
|
||||
Optional: TEILER_APP<Number>_<LanguageCode>_<suffix>
|
||||
```
|
||||
|
||||
- The **number** is just for grouping variables for a single app and has no intrinsic meaning.
|
||||
- The **app** is the unit within Teiler, shown as a box in the dashboard.
|
||||
- Apps can be:
|
||||
- Embedded apps inside the Teiler Dashboard (there is a helper Python script for generating embedded apps: [create-embedded-app.py](https://github.com/samply/teiler-dashboard/blob/main/create-embedded-app.py))
|
||||
- External links (e.g., central services outside the local bridgehead instance)
|
||||
- An app's frontend (microfrontend or embedded app) can either contain the entire functionality or serve as a frontend communicating with other backend microservices in the bridgehead.
|
||||
|
||||
Currently supported languages in the main projects DKTK and BBMRI are **English (EN)** and **German (DE)**, but the system can be extended to other languages.
|
||||
|
||||
The Teiler Dashboard requests variables from the backend for each app and passes the desired language code. If a language-specific variable is unavailable, the default language value is returned.
|
||||
|
||||
### Internationalization (i18n)
|
||||
#### ⚠️ Important
|
||||
|
||||
If you make any changes to the **Teiler Dashboard**, and those changes involve text elements (e.g., labels, buttons, messages), you must also update the **English translations**, since the application uses **internationalization (i18n)**.
|
||||
|
||||
The **default language** of the project is **German**, so any new text must be manually translated into English after extracting the updated i18n entries.
|
||||
|
||||
To extract new translation entries, run the following command:
|
||||
|
||||
```bash
|
||||
ng extract-i18n --output-path src/i18n --format=xlf2
|
||||
````
|
||||
|
||||
This will generate or update the file:
|
||||
`src/i18n/messages.xlf`
|
||||
|
||||
---
|
||||
|
||||
#### ✅ Requirements to Run the Extraction Command
|
||||
|
||||
| Program | Purpose | Linux Shell (Ubuntu/Debian) | Windows PowerShell |
|
||||
| -------------------------------- | ---------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- |
|
||||
| **Node.js** | JavaScript runtime required by Angular and npm | `sudo apt update && sudo apt install nodejs npm`<br>**or**<br>[Use NodeSource setup](https://github.com/nodesource/distributions) (recommended) | [Download from nodejs.org](https://nodejs.org) and install manually |
|
||||
| **npm** | Node package manager (comes with Node.js) | *(Included with Node.js)* | *(Included with Node.js)* |
|
||||
| **Angular CLI** | Command-line interface for Angular tooling | `npm install -g @angular/cli` | `npm install -g @angular/cli` |
|
||||
| **Angular project dependencies** | Required packages from `package.json` | `npm install` | `npm install` |
|
||||
|
||||
---
|
||||
|
||||
#### ✏️ Updating the English Translation
|
||||
|
||||
After running the extraction command, the file `src/i18n/messages.xlf` will contain any newly added i18n entries.
|
||||
|
||||
To provide English translations:
|
||||
|
||||
1. Open `src/i18n/messages.en.xlf`.
|
||||
2. Compare it with the updated `messages.xlf` to identify any new entries.
|
||||
3. Copy the new `<trans-unit>` blocks from `messages.xlf` into `messages.en.xlf`.
|
||||
4. For each entry, add the English translation inside the `<target>` tag (in `messages.en.xlf`):
|
||||
|
||||
```xml
|
||||
<trans-unit id="..." datatype="html">
|
||||
<source>Willkommen</source>
|
||||
<target>Welcome</target>
|
||||
</trans-unit>
|
||||
```
|
||||
|
||||
### App Availability Monitoring
|
||||
|
||||
The Teiler Backend regularly **pings apps** to check availability and displays status messages such as:
|
||||
|
||||
- "Frontend not available"
|
||||
- "Backend not available"
|
||||
- "Frontend and Backend not available"
|
||||
|
||||
### Accepted TEILER_APP Variable Suffixes
|
||||
|
||||
| Suffix | Description |
|
||||
|------------------|---------------------------------------------------------------------------------------------------------------|
|
||||
| NAME | Identifier of the app (no spaces). For embedded apps, must match the identifier defined in Teiler Dashboard. |
|
||||
| TITLE | Display title shown to users. |
|
||||
| DESCRIPTION | Brief description of the app. |
|
||||
| BACKENDURL | URL of the backend microservice (if applicable). |
|
||||
| BACKENDCHECKURL | URL that the backend pings to verify backend availability. Defaults to BACKENDURL if not specified. |
|
||||
| SOURCEURL | URL of the microfrontend or external link (not used for embedded apps). |
|
||||
| SOURCECHECKURL | URL to ping to check microfrontend or external link availability. Defaults to SOURCEURL if not specified. |
|
||||
| ROLES | Comma-separated roles allowed: `TEILER_PUBLIC`, `TEILER_USER`, `TEILER_ADMIN`. |
|
||||
| ISACTIVATED | `true` or `false`. Used to temporarily deactivate an app without deleting its config. |
|
||||
| ICONCLASS | Bootstrap icon class to display in app box (e.g., `"bi bi-search"`). |
|
||||
| ICONSOURCEURL | URL to an image icon. Prefer using local assets instead of external URLs. |
|
||||
| ORDER | Relative display order of the app in the dashboard. |
|
||||
| ISEXTERNALLINK | `true` or `false`. Indicates if the app is an external link outside the local bridgehead. |
|
||||
| ISLOCAL | `true` or `false`. Indicates if the app runs locally within the bridgehead site or on a central server. |
|
||||
|
||||
*Note:* Embedded apps often have many of these variables preconfigured and may not require manual specification. See the [Teiler Dashboard documentation](https://github.com/samply/teiler-dashboard) for details.
|
||||
|
||||
### Additional Teiler Backend Variables for Dashboard Configuration
|
||||
|
||||
| Variable Prefix | Description |
|
||||
|------------------------------------|--------------------------------------------------------------------------------------------------------------|
|
||||
| TEILER_DASHBOARD_ | General configuration of the dashboard. |
|
||||
| TEILER_DASHBOARD_<LangCode>_ | Language-specific configuration overrides. |
|
||||
|
||||
Important suffixes include:
|
||||
|
||||
| Suffix | Description |
|
||||
|------------------|-------------------------------------------------------------------------------------------|
|
||||
| WELCOME_TITLE | Title shown on the initial screen before login. |
|
||||
| WELCOME_TEXT | Welcome message or instructions before login. |
|
||||
| FURTHER_INFO | Additional informational text or links. |
|
||||
| BACKGROUND_IMAGE_URL | URL to a background image (SVG recommended for scalability). |
|
||||
| LOGO_URL | URL to the project or bridgehead logo. |
|
||||
| LOGO_HEIGHT | Height of the displayed logo. |
|
||||
| LOGO_TEXT | Title text of the bridgehead (e.g., "DKTK Bridgehead"). |
|
||||
| COLOR_PALETTE | JSON link to color palettes for text, lines, icons, and background (especially for SVGs). |
|
||||
| COLOR_PROFILE | Selected color profile from the palette. (color palette name) |
|
||||
| FONT | Font family for the dashboard text. |
|
||||
|
||||
### 🎨 Color Palette
|
||||
|
||||
Below is an example of a **color palette** definition in JSON format:
|
||||
|
||||
```json
|
||||
{
|
||||
"color-palettes": [
|
||||
{
|
||||
"name": "Grey",
|
||||
"colors": {
|
||||
"text": "grey",
|
||||
"line": "grey",
|
||||
"icon": "grey",
|
||||
"background": "grey"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Black",
|
||||
"colors": {
|
||||
"text": "black",
|
||||
"line": "black",
|
||||
"icon": "black",
|
||||
"background": "#F7ADAD"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Each palette contains a unique `name` and a set of color values for different UI elements.
|
||||
|
||||
#### 🔍 Palette Elements
|
||||
|
||||
| **Variable** | **Description** |
|
||||
| ------------ | --------------------------------------------------- |
|
||||
| `name` | Identifier of the color palette |
|
||||
| `text` | Color used for text |
|
||||
| `line` | Color used for lines (e.g., borders, dividers) |
|
||||
| `icon` | Color used for icons |
|
||||
| `background` | Background color (especially useful for SVG images) |
|
||||
|
||||
|
||||
---
|
||||
|
||||
### 🚀 Ready to Extend Teiler?
|
||||
|
||||
If you want to create your own **bridgehead app** and integrate it into **Teiler**, start by:
|
||||
|
||||
1. Selecting a template **or**
|
||||
2. Building a microfrontend compatible with [Single-SPA](https://single-spa.js.org/).
|
||||
|
||||
Then, register your app’s configuration in the **Teiler Backend** as described above.
|
||||
|
||||
> 💡 **Tip:** This flexible, modular design makes it easy to plug in your own features and services.
|
||||
|
||||
---
|
||||
|
||||
### 🔧 Build & Contribute Your App!
|
||||
|
||||
🧩 **Join the ecosystem!**
|
||||
Add your app to Teiler and expand its functionality for everyone.
|
||||
|
||||
Whether it’s a visualization tool, a data processing module, or a custom UI component — your contribution can help grow the platform. 💪
|
||||
|
||||
> 👉 **Get started today and shape the future of Teiler!**
|
||||
|
||||
|
@ -1,2 +1,3 @@
|
||||
bGlicmFyeSBSZXRyaWV2ZQp1c2luZyBGSElSIHZlcnNpb24gJzQuMC4wJwppbmNsdWRlIEZISVJIZWxwZXJzIHZlcnNpb24gJzQuMC4wJwoKY29kZXN5c3RlbSBsb2luYzogJ2h0dHA6Ly9sb2luYy5vcmcnCgpjb250ZXh0IFBhdGllbnQKCgpES1RLX1NUUkFUX0dFTkRFUl9TVFJBVElGSUVSCgpES1RLX1NUUkFUX1BSSU1BUllfRElBR05PU0lTX05PX1NPUlRfU1RSQVRJRklFUgpES1RLX1NUUkFUX0FHRV9DTEFTU19TVFJBVElGSUVSCgpES1RLX1NUUkFUX0RFQ0VBU0VEX1NUUkFUSUZJRVIKCkRLVEtfU1RSQVRfRElBR05PU0lTX1NUUkFUSUZJRVIKCkRLVEtfUkVQTEFDRV9TUEVDSU1FTl9TVFJBVElGSUVSaWYgSW5Jbml0aWFsUG9wdWxhdGlvbiB0aGVuIFtTcGVjaW1lbl0gZWxzZSB7fSBhcyBMaXN0PFNwZWNpbWVuPgpES1RLX1NUUkFUX1BST0NFRFVSRV9TVFJBVElGSUVSCgpES1RLX1NUUkFUX01FRElDQVRJT05fU1RSQVRJRklFUgoKICBES1RLX1JFUExBQ0VfSElTVE9MT0dZX1NUUkFUSUZJRVIKIGlmIGhpc3RvLmNvZGUuY29kaW5nLndoZXJlKGNvZGUgPSAnNTk4NDctNCcpLmNvZGUuZmlyc3QoKSBpcyBudWxsIHRoZW4gMCBlbHNlIDEKREtUS19TVFJBVF9ERUZfSU5fSU5JVElBTF9QT1BVTEFUSU9OCnRydWU=
|
||||
bGlicmFyeSBSZXRyaWV2ZQp1c2luZyBGSElSIHZlcnNpb24gJzQuMC4wJwppbmNsdWRlIEZISVJIZWxwZXJzIHZlcnNpb24gJzQuMC4wJwoKY29kZXN5c3RlbSBsb2luYzogJ2h0dHA6Ly9sb2luYy5vcmcnCmNvZGVzeXN0ZW0gaWNkMTA6ICdodHRwOi8vZmhpci5kZS9Db2RlU3lzdGVtL2JmYXJtL2ljZC0xMC1nbScKY29kZXN5c3RlbSBtb3JwaDogJ3VybjpvaWQ6Mi4xNi44NDAuMS4xMTM4ODMuNi40My4xJwoKY29udGV4dCBQYXRpZW50CgoKREtUS19TVFJBVF9HRU5ERVJfU1RSQVRJRklFUgoKREtUS19TVFJBVF9QUklNQVJZX0RJQUdOT1NJU19OT19TT1JUX1NUUkFUSUZJRVIKREtUS19TVFJBVF9BR0VfQ0xBU1NfU1RSQVRJRklFUgoKREtUS19TVFJBVF9ERUNFQVNFRF9TVFJBVElGSUVSCgpES1RLX1NUUkFUX0RJQUdOT1NJU19TVFJBVElGSUVSCgpES1RLX1JFUExBQ0VfU1BFQ0lNRU5fU1RSQVRJRklFUmlmIEluSW5pdGlhbFBvcHVsYXRpb24gdGhlbiBbU3BlY2ltZW5dIGVsc2Uge30gYXMgTGlzdDxTcGVjaW1lbj4KREtUS19TVFJBVF9QUk9DRURVUkVfU1RSQVRJRklFUgoKREtUS19TVFJBVF9NRURJQ0FUSU9OX1NUUkFUSUZJRVIKCiAgREtUS19SRVBMQUNFX0hJU1RPTE9HWV9TVFJBVElGSUVSCiBpZiBoaXN0by5jb2RlLmNvZGluZy53aGVyZShjb2RlID0gJzU5ODQ3LTQnKS5jb2RlLmZpcnN0KCkgaXMgbnVsbCB0aGVuIDAgZWxzZSAxCkRLVEtfU1RSQVRfREVGX0lOX0lOSVRJQUxfUE9QVUxBVElPTihleGlzdHMgW0NvbmRpdGlvbjogQ29kZSAnQzYxJyBmcm9tIGljZDEwXSkgYW5kIAooKGV4aXN0cyBmcm9tIFtPYnNlcnZhdGlvbjogQ29kZSAnNTk4NDctNCcgZnJvbSBsb2luY10gTwp3aGVyZSBPLnZhbHVlLmNvZGluZy5jb2RlIGNvbnRhaW5zICc4MTQwLzMnKSBvciAKKGV4aXN0cyBmcm9tIFtPYnNlcnZhdGlvbjogQ29kZSAnNTk4NDctNCcgZnJvbSBsb2luY10gTwp3aGVyZSBPLnZhbHVlLmNvZGluZy5jb2RlIGNvbnRhaW5zICc4MTQ3LzMnKSBvciAKKGV4aXN0cyBmcm9tIFtPYnNlcnZhdGlvbjogQ29kZSAnNTk4NDctNCcgZnJvbSBsb2luY10gTwp3aGVyZSBPLnZhbHVlLmNvZGluZy5jb2RlIGNvbnRhaW5zICc4NDgwLzMnKSBvciAKKGV4aXN0cyBmcm9tIFtPYnNlcnZhdGlvbjogQ29kZSAnNTk4NDctNCcgZnJvbSBsb2luY10gTwp3aGVyZSBPLnZhbHVlLmNvZGluZy5jb2RlIGNvbnRhaW5zICc4NTAwLzMnKSk=
|
||||
bGlicmFyeSBSZXRyaWV2ZQp1c2luZyBGSElSIHZlcnNpb24gJzQuMC4wJwppbmNsdWRlIEZISVJIZWxwZXJzIHZlcnNpb24gJzQuMC4wJwoKY29kZXN5c3RlbSBsb2luYzogJ2h0dHA6Ly9sb2luYy5vcmcnCmNvZGVzeXN0ZW0gaWNkMTA6ICdodHRwOi8vZmhpci5kZS9Db2RlU3lzdGVtL2JmYXJtL2ljZC0xMC1nbScKY29kZXN5c3RlbSBtb3JwaDogJ3VybjpvaWQ6Mi4xNi44NDAuMS4xMTM4ODMuNi40My4xJwoKY29udGV4dCBQYXRpZW50CgoKREtUS19TVFJBVF9HRU5ERVJfU1RSQVRJRklFUgoKREtUS19TVFJBVF9QUklNQVJZX0RJQUdOT1NJU19OT19TT1JUX1NUUkFUSUZJRVIKREtUS19TVFJBVF9BR0VfQ0xBU1NfU1RSQVRJRklFUgoKREtUS19TVFJBVF9ERUNFQVNFRF9TVFJBVElGSUVSCgpES1RLX1NUUkFUX0RJQUdOT1NJU19TVFJBVElGSUVSCgpES1RLX1JFUExBQ0VfU1BFQ0lNRU5fU1RSQVRJRklFUmlmIEluSW5pdGlhbFBvcHVsYXRpb24gdGhlbiBbU3BlY2ltZW5dIGVsc2Uge30gYXMgTGlzdDxTcGVjaW1lbj4KREtUS19TVFJBVF9QUk9DRURVUkVfU1RSQVRJRklFUgoKREtUS19TVFJBVF9NRURJQ0FUSU9OX1NUUkFUSUZJRVIKCiAgREtUS19SRVBMQUNFX0hJU1RPTE9HWV9TVFJBVElGSUVSCiBpZiBoaXN0by5jb2RlLmNvZGluZy53aGVyZShjb2RlID0gJzU5ODQ3LTQnKS5jb2RlLmZpcnN0KCkgaXMgbnVsbCB0aGVuIDAgZWxzZSAxCkRLVEtfU1RSQVRfREVGX0lOX0lOSVRJQUxfUE9QVUxBVElPTihleGlzdHMgW0NvbmRpdGlvbjogQ29kZSAnQzYxJyBmcm9tIGljZDEwXSkgYW5kIAooKGV4aXN0cyBmcm9tIFtPYnNlcnZhdGlvbjogQ29kZSAnNTk4NDctNCcgZnJvbSBsb2luY10gTwp3aGVyZSBPLnZhbHVlLmNvZGluZy5jb2RlIGNvbnRhaW5zICc4MTQwLzMnKSBvciAKKGV4aXN0cyBmcm9tIFtPYnNlcnZhdGlvbjogQ29kZSAnNTk4NDctNCcgZnJvbSBsb2luY10gTwp3aGVyZSBPLnZhbHVlLmNvZGluZy5jb2RlIGNvbnRhaW5zICc4MTQ3LzMnKSBvciAKKGV4aXN0cyBmcm9tIFtPYnNlcnZhdGlvbjogQ29kZSAnNTk4NDctNCcgZnJvbSBsb2luY10gTwp3aGVyZSBPLnZhbHVlLmNvZGluZy5jb2RlIGNvbnRhaW5zICc4NDgwLzMnKSBvciAKKGV4aXN0cyBmcm9tIFtPYnNlcnZhdGlvbjogQ29kZSAnNTk4NDctNCcgZnJvbSBsb2luY10gTwp3aGVyZSBPLnZhbHVlLmNvZGluZy5jb2RlIGNvbnRhaW5zICc4NTAwLzMnKSk=
|
||||
ORGANOID_DASHBOARD_PUBLIC
|
||||
|
7
ccp/vars
7
ccp/vars
@ -12,14 +12,9 @@ OIDC_USER_GROUP="DKTK_CCP_$(capitalize_first_letter ${SITE_ID})"
|
||||
OIDC_ADMIN_GROUP="DKTK_CCP_$(capitalize_first_letter ${SITE_ID})_Verwalter"
|
||||
OIDC_PRIVATE_CLIENT_ID=${SITE_ID}-private
|
||||
OIDC_PUBLIC_CLIENT_ID=${SITE_ID}-public
|
||||
# Use "test-realm-01" for testing
|
||||
OIDC_REALM="${OIDC_REALM:-master}"
|
||||
OIDC_URL="https://login.verbis.dkfz.de"
|
||||
OIDC_ISSUER_URL="${OIDC_URL}/realms/${OIDC_REALM}"
|
||||
OIDC_URL="https://login.verbis.dkfz.de/realms/test-realm-01"
|
||||
OIDC_GROUP_CLAIM="groups"
|
||||
|
||||
POSTGRES_TAG=15.6-alpine
|
||||
|
||||
for module in $PROJECT/modules/*.sh
|
||||
do
|
||||
log DEBUG "sourcing $module"
|
||||
|
@ -8,8 +8,6 @@ PRIVATEKEYFILENAME=/etc/bridgehead/pki/${SITE_ID}.priv.pem
|
||||
|
||||
BROKER_URL_FOR_PREREQ=$BROKER_URL
|
||||
|
||||
POSTGRES_TAG=15.6-alpine
|
||||
|
||||
for module in ccp/modules/*.sh
|
||||
do
|
||||
log DEBUG "sourcing $module"
|
||||
|
@ -31,8 +31,8 @@ services:
|
||||
environment:
|
||||
DEFAULT_LANGUAGE: "${TEILER_DEFAULT_LANGUAGE}"
|
||||
TEILER_BACKEND_URL: "https://${HOST}/ccp-teiler-backend"
|
||||
TEILER_DASHBOARD_URL: "https://${HOST}/ccp-teiler-dashboard"
|
||||
OIDC_URL: "${OIDC_URL}"
|
||||
OIDC_REALM: "${OIDC_REALM}"
|
||||
OIDC_CLIENT_ID: "${OIDC_PUBLIC_CLIENT_ID}"
|
||||
OIDC_TOKEN_GROUP: "${OIDC_GROUP_CLAIM}"
|
||||
TEILER_ADMIN_NAME: "${OPERATOR_FIRST_NAME} ${OPERATOR_LAST_NAME}"
|
||||
@ -41,7 +41,6 @@ services:
|
||||
TEILER_PROJECT: "${PROJECT}"
|
||||
EXPORTER_API_KEY: "${EXPORTER_API_KEY}"
|
||||
TEILER_ORCHESTRATOR_URL: "https://${HOST}/ccp-teiler"
|
||||
TEILER_DASHBOARD_HTTP_RELATIVE_PATH: "/ccp-teiler-dashboard"
|
||||
TEILER_ORCHESTRATOR_HTTP_RELATIVE_PATH: "/ccp-teiler"
|
||||
TEILER_USER: "${OIDC_USER_GROUP}"
|
||||
TEILER_ADMIN: "${OIDC_ADMIN_GROUP}"
|
||||
@ -69,7 +68,6 @@ services:
|
||||
TEILER_ORCHESTRATOR_URL: "https://${HOST}/ccp-teiler"
|
||||
TEILER_DASHBOARD_DE_URL: "https://${HOST}/ccp-teiler-dashboard/de"
|
||||
TEILER_DASHBOARD_EN_URL: "https://${HOST}/ccp-teiler-dashboard/en"
|
||||
CENTRAX_URL: "${CENTRAXX_URL}"
|
||||
HTTP_PROXY: "http://forward_proxy:3128"
|
||||
ENABLE_MTBA: "${ENABLE_MTBA}"
|
||||
ENABLE_DATASHIELD: "${ENABLE_DATASHIELD}"
|
||||
|
@ -348,7 +348,7 @@ function secret_sync_gitlab_token() {
|
||||
fi
|
||||
|
||||
# Create a temporary directory for Secret Sync that is valid per boot
|
||||
secret_sync_tempdir="/tmp/secret-sync.boot-$(cat /proc/sys/kernel/random/boot_id)"
|
||||
secret_sync_tempdir="/tmp/bridgehead/secret-sync.boot-$(cat /proc/sys/kernel/random/boot_id)"
|
||||
mkdir -p $secret_sync_tempdir
|
||||
|
||||
# Use Secret Sync to validate the GitLab token in $secret_sync_tempdir/cache.
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
[ "$1" = "get" ] || exit
|
||||
|
||||
source "/tmp/secret-sync.boot-$(cat /proc/sys/kernel/random/boot_id)/gitlab-token"
|
||||
source "/tmp/bridgehead/secret-sync.boot-$(cat /proc/sys/kernel/random/boot_id)/gitlab-token"
|
||||
|
||||
# Any non-empty username works, only the token matters
|
||||
cat << EOF
|
||||
|
@ -49,6 +49,12 @@ if [ -z "$TRANSFAIR_AUTH" ]; then
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$ENABLE_EXPORTER" == "true" ] && [ -z "$EXPORTER_USER" ]; then
|
||||
log "INFO" "Now generating basic auth for the exporter and reporter (see adduser in bridgehead for more information)."
|
||||
generated_passwd="$(cat /proc/sys/kernel/random/uuid | sed 's/[-]//g' | head -c 32)"
|
||||
add_basic_auth_user $PROJECT $generated_passwd "EXPORTER_USER" $PROJECT
|
||||
fi
|
||||
|
||||
log "INFO" "Registering system units for bridgehead and bridgehead-update"
|
||||
cp -v \
|
||||
lib/systemd/bridgehead\@.service \
|
||||
|
@ -8,7 +8,8 @@ services:
|
||||
- TTP_URL
|
||||
- TTP_ML_API_KEY
|
||||
- TTP_GW_SOURCE
|
||||
- TTP_GW_DOMAIN
|
||||
- TTP_GW_EPIX_DOMAIN
|
||||
- TTP_GW_GPAS_DOMAIN
|
||||
- TTP_TYPE
|
||||
- TTP_AUTH
|
||||
- PROJECT_ID_SYSTEM
|
||||
@ -23,6 +24,8 @@ services:
|
||||
- RUST_LOG=${RUST_LOG:-info}
|
||||
- TLS_CA_CERTIFICATES_DIR=/conf/trusted-ca-certs
|
||||
- TLS_DISABLE=${TRANSFAIR_TLS_DISABLE:-false}
|
||||
- NO_PROXY=${TRANSFAIR_NO_PROXIES}
|
||||
- ALL_PROXY=http://forward_proxy:3128
|
||||
volumes:
|
||||
- /var/cache/bridgehead/${PROJECT}/transfair:/transfair
|
||||
- /etc/bridgehead/trusted-ca-certs:/conf/trusted-ca-certs:ro
|
||||
@ -60,9 +63,9 @@ services:
|
||||
|
||||
transfair-request-blaze:
|
||||
image: docker.verbis.dkfz.de/cache/samply/blaze:${BLAZE_TAG}
|
||||
container_name: bridgehead-transfair-requests-blaze
|
||||
container_name: bridgehead-transfair-request-blaze
|
||||
environment:
|
||||
BASE_URL: "http://bridgehead-transfair-requests-blaze:8080"
|
||||
BASE_URL: "http://bridgehead-transfair-request-blaze:8080"
|
||||
JAVA_TOOL_OPTIONS: "-Xmx1024m"
|
||||
DB_BLOCK_CACHE_SIZE: 1024
|
||||
CQL_EXPR_CACHE_SIZE: 8
|
||||
|
@ -15,7 +15,7 @@ function transfairSetup() {
|
||||
log INFO "TransFAIR request fhir store set to external $FHIR_REQUEST_URL"
|
||||
else
|
||||
log INFO "TransFAIR request fhir store not set writing to internal blaze"
|
||||
FHIR_REQUEST_URL="http://transfair-requests-blaze:8080"
|
||||
FHIR_REQUEST_URL="http://transfair-request-blaze:8080"
|
||||
OVERRIDE+=" --profile transfair-request-blaze"
|
||||
fi
|
||||
if [ -n "$TTP_GW_SOURCE" ]; then
|
||||
@ -27,5 +27,9 @@ function transfairSetup() {
|
||||
else
|
||||
log INFO "TransFAIR configured without ttp"
|
||||
fi
|
||||
TRANSFAIR_NO_PROXIES="transfair-input-blaze,blaze,transfair-requests-blaze"
|
||||
if [ -n "${TRANSFAIR_NO_PROXY}" ]; then
|
||||
TRANSFAIR_NO_PROXIES+=",${TRANSFAIR_NO_PROXY}"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
FOCUS_TAG=develop
|
||||
BEAM_TAG=develop
|
||||
BLAZE_TAG=main
|
||||
BLAZE_TAG=main
|
||||
POSTGRES_TAG=15.13-alpine
|
@ -1,3 +1,4 @@
|
||||
FOCUS_TAG=main
|
||||
BEAM_TAG=main
|
||||
BLAZE_TAG=0.32
|
||||
BLAZE_TAG=0.32
|
||||
POSTGRES_TAG=15.13-alpine
|
@ -1,3 +1,4 @@
|
||||
FOCUS_TAG=develop
|
||||
BEAM_TAG=develop
|
||||
BLAZE_TAG=main
|
||||
BLAZE_TAG=main
|
||||
POSTGRES_TAG=15.13-alpine
|
Reference in New Issue
Block a user