1
0
mirror of https://github.com/pcvolkmer/etl-processor.git synced 2025-07-17 21:02:54 +00:00

chore: prepare test submission for genomDe

This commit is contained in:
Jakub Lidke
2025-07-17 11:13:36 +02:00
parent 0475bed377
commit d34127701c
7 changed files with 229 additions and 102 deletions

279
README.md
View File

@ -1,30 +1,45 @@
# ETL-Processor for DNPM:DIP [![Run Tests](https://github.com/pcvolkmer/etl-processor/actions/workflows/test.yml/badge.svg)](https://github.com/pcvolkmer/etl-processor/actions/workflows/test.yml)
Diese Anwendung versendet ein bwHC-MTB-File im bwHC-Datenmodell 1.0 an DNPM:DIP und pseudonymisiert die Patienten-ID.
Diese Anwendung versendet ein bwHC-MTB-File im bwHC-Datenmodell 1.0 an DNPM:DIP und pseudonymisiert
die Patienten-ID.
## Einordnung innerhalb einer DNPM-ETL-Strecke
Diese Anwendung erlaubt das Entgegennehmen von HTTP/REST-Anfragen aus dem Onkostar-Plugin **[onkostar-plugin-dnpmexport](https://github.com/CCC-MF/onkostar-plugin-dnpmexport)**.
Diese Anwendung erlaubt das Entgegennehmen von HTTP/REST-Anfragen aus dem Onkostar-Plugin *
*[onkostar-plugin-dnpmexport](https://github.com/CCC-MF/onkostar-plugin-dnpmexport)**.
Der Inhalt einer Anfrage, wenn ein bwHC-MTBFile, wird pseudonymisiert und auf Duplikate geprüft.
Duplikate werden verworfen, Änderungen werden weitergeleitet.
Löschanfragen werden immer als Löschanfrage an DNPM:DIP weitergeleitet.
Zudem ist eine minimalistische Weboberfläche integriert, die einen Einblick in den aktuellen Zustand der Anwendung gewährt.
Zudem ist eine minimalistische Weboberfläche integriert, die einen Einblick in den aktuellen Zustand
der Anwendung gewährt.
![Modell DNPM-ETL-Strecke](docs/etl.png)
### Duplikaterkennung
Die Erkennung von Duplikaten ist normalerweise immer aktiv, kann jedoch über den Konfigurationsparameter
Die Erkennung von Duplikaten ist normalerweise immer aktiv, kann jedoch über den
Konfigurationsparameter
`APP_DUPLICATION_DETECTION=false` deaktiviert werden.
### Modelvorhaben genomDE §64e
Um die voll Betriebsbereitschaft herzustellen, muss eine erfolgreiche Übertragung mit dem
Submission-Typ *Test* erfolgt sein. Über die Umgebungsvariable wird dieser Übertragungsmodus
aktiviert. Alle Datensätze mit erteilter Teilnahme am Modelvorhaben werden mit der Test-Kennung
übertragen.
`APP_GENOM_DE_TEST_SUBMISSION` -> `true` | `false` (falls fehlt wird `true` angenommen)
### Datenübermittlung über HTTP/REST
Anfragen werden, wenn nicht als Duplikat behandelt, nach der Pseudonymisierung direkt an DNPM:DIP gesendet.
Anfragen werden, wenn nicht als Duplikat behandelt, nach der Pseudonymisierung direkt an DNPM:DIP
gesendet.
Ein HTTP Request kann, angenommen die Installation erfolgte auf dem Host `dnpm.example.com` an nachfolgende URLs gesendet werden:
Ein HTTP Request kann, angenommen die Installation erfolgte auf dem Host `dnpm.example.com` an
nachfolgende URLs gesendet werden:
| HTTP-Request | URL | Consent-Status im Datensatz | Bemerkung |
|--------------|-----------------------------------------|-----------------------------|---------------------------------------------------------------------------------|
@ -32,12 +47,15 @@ Ein HTTP Request kann, angenommen die Installation erfolgte auf dem Host `dnpm.e
| `POST` | `https://dnpm.example.com/mtb` | `REJECT` | Die Anwendung sendet einen Lösch-Request für die im Datensatz angegebene Pat-ID |
| `DELETE` | `https://dnpm.example.com/mtb/12345678` | - | Die Anwendung sendet einen Lösch-Request für Pat-ID `12345678` |
Anstelle des Pfads `/mtb` kann auch, wie in Version 0.9 und älter üblich, `/mtbfile` verwendet werden.
Anstelle des Pfads `/mtb` kann auch, wie in Version 0.9 und älter üblich, `/mtbfile` verwendet
werden.
### Datenübermittlung mit Apache Kafka
Anfragen werden, wenn nicht als Duplikat behandelt, nach der Pseudonymisierung an Apache Kafka übergeben.
Eine Antwort wird dabei ebenfalls mithilfe von Apache Kafka übermittelt und nach der Entgegennahme verarbeitet.
Anfragen werden, wenn nicht als Duplikat behandelt, nach der Pseudonymisierung an Apache Kafka
übergeben.
Eine Antwort wird dabei ebenfalls mithilfe von Apache Kafka übermittelt und nach der Entgegennahme
verarbeitet.
Siehe hierzu auch: https://github.com/CCC-MF/kafka-to-bwhc
@ -45,15 +63,19 @@ Siehe hierzu auch: https://github.com/CCC-MF/kafka-to-bwhc
### 🔥 Wichtige Änderungen in Version 0.10
Ab Version 0.10 wird [DNPM:DIP](https://github.com/dnpm-dip) unterstützt und als Standardendpunkt verwendet.
Soll noch das alte bwHC-Backend verwendet werden, so ist die Umgebungsvariable `APP_REST_IS_BWHC` auf `true` zu setzen.
Ab Version 0.10 wird [DNPM:DIP](https://github.com/dnpm-dip) unterstützt und als Standardendpunkt
verwendet.
Soll noch das alte bwHC-Backend verwendet werden, so ist die Umgebungsvariable `APP_REST_IS_BWHC`
auf `true` zu setzen.
### 🔥 Breaking Changes nach Version 0.10
In Versionen des ETL-Processors **nach Version 0.10** werden die folgenden Konfigurationsoptionen entfernt:
In Versionen des ETL-Processors **nach Version 0.10** werden die folgenden Konfigurationsoptionen
entfernt:
* `APP_KAFKA_TOPIC`: Nutzen Sie nun die Konfigurationsoption `APP_KAFKA_OUTPUT_TOPIC`
* `APP_KAFKA_RESPONSE_TOPIC`: Nutzen Sie nun die Konfigurationsoption `APP_KAFKA_OUTPUT_RESPONSE_TOPIC`
* `APP_KAFKA_RESPONSE_TOPIC`: Nutzen Sie nun die Konfigurationsoption
`APP_KAFKA_OUTPUT_RESPONSE_TOPIC`
Der Pfad zum Versenden von MTB-Daten ist nun offiziell `/mtb`.
In Versionen **nach Version 0.10** wird die Unterstützung des Pfads `/mtbfile` entfernt.
@ -69,57 +91,84 @@ Ist diese nicht gesetzt. wird intern eine Anonymisierung der Patienten-ID vorgen
**Hinweis**
Die Pseudonymisierung erfolgt im ETL-Prozessor nur für die Patienten-ID.
Andere IDs werden mithilfe des standortbezogenen Präfixes (erneut) anonymisiert, um für den aktuellen Kontext nicht
Andere IDs werden mithilfe des standortbezogenen Präfixes (erneut) anonymisiert, um für den
aktuellen Kontext nicht
vergleichbare IDs bereitzustellen.
#### Eingebaute Anonymisierung
Wurde keine oder die Verwendung der eingebauten Anonymisierung konfiguriert, so wird für die Patienten-ID der
entsprechende SHA-256-Hash gebildet und Base64-codiert - hier ohne endende "=" - zuzüglich des konfigurierten Präfixes
Wurde keine oder die Verwendung der eingebauten Anonymisierung konfiguriert, so wird für die
Patienten-ID der
entsprechende SHA-256-Hash gebildet und Base64-codiert - hier ohne endende "=" - zuzüglich des
konfigurierten Präfixes
als Patienten-Pseudonym verwendet.
#### Pseudonymisierung mit gPAS
Wurde die Verwendung von gPAS konfiguriert, so sind weitere Angaben zu konfigurieren.
* `APP_PSEUDONYMIZE_GPAS_URI`: URI der gPAS-Instanz inklusive Endpoint (z.B. `http://localhost:8080/ttp-fhir/fhir/gpas/$$pseudonymizeAllowCreate`)
* `APP_PSEUDONYMIZE_GPAS_URI`: URI der gPAS-Instanz inklusive Endpoint (z.B.
`http://localhost:8080/ttp-fhir/fhir/gpas/$$pseudonymizeAllowCreate`)
* `APP_PSEUDONYMIZE_GPAS_TARGET`: gPas Domänenname
* `APP_PSEUDONYMIZE_GPAS_USERNAME`: gPas Basic-Auth Benutzername
* `APP_PSEUDONYMIZE_GPAS_PASSWORD`: gPas Basic-Auth Passwort
### Einwilligung gICS
Ab gIcs Version 2.13.0 kann per [REST-Schnittstelle](https://simplifier.net/guide/ttp-fhir-gateway-ig/ImplementationGuide-markdown-Einwilligungsmanagement-Operations-isConsented?version=current) der Einwilligungsstatus abgefragt werden.
Vor der MTB-Übertragung kann der zum Sendezeitpunkt verfügbarer Einwilligungsstatus über Endpunkt *isConsented* abgefragt werden.
Ab gIcs Version 2.13.0 kann
per [REST-Schnittstelle](https://simplifier.net/guide/ttp-fhir-gateway-ig/ImplementationGuide-markdown-Einwilligungsmanagement-Operations-isConsented?version=current)
der Einwilligungsstatus abgefragt werden.
Vor der MTB-Übertragung kann der zum Sendezeitpunkt verfügbarer Einwilligungsstatus über Endpunkt
*isConsented* abgefragt werden.
Falls Anbindung an gICS aktiviert wurde, wird der Einwilligungsstatus der MTB Datei ignoriert.
Stattdessen werden vorhandene Einwilligungen abgefragt und in die MTB Datei eingebettet.
Es werden zwei Einwilligungsdomänen unterstützt, eine für Broad Consent und als zweites GenomDE Modelvorhaben §64e.
Es werden zwei Einwilligungsdomänen unterstützt, eine für Broad Consent und als zweites GenomDE
Modelvorhaben §64e.
#### Hinweise
1. Die aktuelle Impl. nimmt an, dass die hinterlegten Domänen der Einwilligungen ausschließlich für die genannten Art von Einwilligungen genutzt werden. Es finde keine weitere Filterung statt. Wir fragen pro Domäne die Schnittstelle `CurrentPolicyStatesForPerson` - siehe auch [IG TTP-FHIR Gateway
](https://www.ths-greifswald.de/wp-content/uploads/tools/fhirgw/ig/2024-3-0/ImplementationGuide-markdown-Einwilligungsmanagement-Operations-currentPolicyStatesForPerson.html) ab.
2. Die Einwilligung wird für den Patienten-Identifier der MTB abgerufen und anschließend durch das DNPM Pseudonym ersetzt.
3. Abfragen von Einwilligungen über gesonderte Pseudonyme anstatt des MTB-Identifiers fehlt in der ersten Implementierung.
1. Die aktuelle Impl. nimmt an, dass die hinterlegten Domänen der Einwilligungen ausschließlich für
die genannten Art von Einwilligungen genutzt werden. Es finde keine weitere Filterung statt. Wir
fragen pro Domäne die Schnittstelle `CurrentPolicyStatesForPerson` - siehe
auch [IG TTP-FHIR Gateway
](https://www.ths-greifswald.de/wp-content/uploads/tools/fhirgw/ig/2024-3-0/ImplementationGuide-markdown-Einwilligungsmanagement-Operations-currentPolicyStatesForPerson.html)
ab.
2. Die Einwilligung wird für den Patienten-Identifier der MTB abgerufen und anschließend durch das
DNPM Pseudonym ersetzt.
3. Abfragen von Einwilligungen über gesonderte Pseudonyme anstatt des MTB-Identifiers fehlt in der
ersten Implementierung.
4. Bei Verarbeitung von MTB Version 1.x Inhalten ist eine positive Einwilligung für die
Weiterverarbeitung notwendig. Das Fehlen einer Einwilligung löst die Löschung des Patienten im Brückenkopf aus.
Weiterverarbeitung notwendig. Das Fehlen einer Einwilligung löst die Löschung des Patienten im
Brückenkopf aus.
#### Konfiguration
* `APP_CONSENT_GICS_ENABLED`: Aktiviert oder deaktiviert `true` oder `false`, `false` wenn nicht gesetzt.
* `APP_CONSENT_GICS_CHECKGNOMEDE`: Aktiviert oder deaktiviert `true` oder `false`, `false` wenn nicht gesetzt. Versuche Einwilligungsdaten zu GENOM DE Modelvorhaben über gIcs abzurufen.
* `APP_CONSENT_GICS_CHECKBROADCONSENT`: Aktiviert oder deaktiviert `true` oder `false`, `false` wenn nicht gesetzt. Versuche Einwilligungsdaten zu Broad Consent über gIcs abzurufen.
* `APP_CONSENT_GICS_ENABLED`: Aktiviert oder deaktiviert `true` oder `false`, `false` wenn nicht
gesetzt.
* `APP_CONSENT_GICS_CHECKGNOMEDE`: Aktiviert oder deaktiviert `true` oder `false`, `false` wenn
nicht gesetzt. Versuche Einwilligungsdaten zu GENOM DE Modelvorhaben über gIcs abzurufen.
* `APP_CONSENT_GICS_CHECKBROADCONSENT`: Aktiviert oder deaktiviert `true` oder `false`, `false` wenn
nicht gesetzt. Versuche Einwilligungsdaten zu Broad Consent über gIcs abzurufen.
* `APP_CONSENT_GICS_URI`: URI der gICS-Instanz (z.B. `http://localhost:8090/ttp-fhir/fhir/gics`)
* `APP_CONSENT_GICS_USERNAME`: gIcs Basic-Auth Benutzername
* `APP_CONSENT_GICS_PASSWORD`: gIcs Basic-Auth Passwort
* `APP_CONSENT_GICS_PERSONIDENTIFIERSYSTEM`: Derzeit wird nur die PID unterstützt. wenn leer wird `https://ths-greifswald.de/fhir/gics/identifiers/Patienten-ID` angenommen
* `APP_CONSENT_GICS_BROADCONSENTDOMAINNAME`: Domäne in der gIcs Broad Consent Einwilligungen verwaltet. Falls Wert leer, wird `MII` angenommen.
* `APP_CONSENT_GICS_GNOMDECONSENTDOMAINNAME`: Domäne in der gIcs GenomDE Modelvorhaben §64e Einwilligungen verwaltet. Falls Wert leer, wird `GenomDE_MV` angenommen.
* `APP_CONSENT_GICS_POLICYCODE`: Die entscheidende Objekt-ID der zu prüfenden Einwilligung-Regel. Falls leer wird `2.16.840.1.113883.3.1937.777.24.5.3.6` angenommen.
* `APP_CONSENT_GICS_POLICYSYSTEM`: Das System der Einwilligung-Regel der Objekt-IDs. Falls leer wird `urn:oid:2.16.840.1.113883.3.1937.777.24.5.3` angenommen.
* `APP_CONSENT_GICS_PERSONIDENTIFIERSYSTEM`: Derzeit wird nur die PID unterstützt. wenn leer wird
`https://ths-greifswald.de/fhir/gics/identifiers/Patienten-ID` angenommen
* `APP_CONSENT_GICS_BROADCONSENTDOMAINNAME`: Domäne in der gIcs Broad Consent Einwilligungen
verwaltet. Falls Wert leer, wird `MII` angenommen.
* `APP_CONSENT_GICS_GNOMDECONSENTDOMAINNAME`: Domäne in der gIcs GenomDE Modelvorhaben §64e
Einwilligungen verwaltet. Falls Wert leer, wird `GenomDE_MV` angenommen.
* `APP_CONSENT_GICS_POLICYCODE`: Die entscheidende Objekt-ID der zu prüfenden Einwilligung-Regel.
Falls leer wird `2.16.840.1.113883.3.1937.777.24.5.3.6` angenommen.
* `APP_CONSENT_GICS_POLICYSYSTEM`: Das System der Einwilligung-Regel der Objekt-IDs. Falls leer wird
`urn:oid:2.16.840.1.113883.3.1937.777.24.5.3` angenommen.
### Anmeldung mit einem Passwort
Ein initialer Administrator-Account kann optional konfiguriert werden und sorgt dafür, dass bestimmte Bereiche nur nach
Ein initialer Administrator-Account kann optional konfiguriert werden und sorgt dafür, dass
bestimmte Bereiche nur nach
einem erfolgreichen Login erreichbar sind.
* `APP_SECURITY_ADMIN_USER`: Muss angegeben werden zur Aktivierung der Zugriffsbeschränkung.
@ -133,27 +182,34 @@ Hier Beispiele für das Beispielpasswort `very-secret`:
* `{bcrypt}$2y$05$CCkfsMr/wbTleMyjVIK8g.Aa3RCvrvoLXVAsL.f6KeouS88vXD9b6`
* `{sha256}9a34717f0646b5e9cfcba70055de62edb026ff4f68671ba3db96aa29297d2df5f1a037d58c745657`
Wird kein Administrator-Passwort angegeben, wird ein zufälliger Wert generiert und beim Start der Anwendung in den Logs
Wird kein Administrator-Passwort angegeben, wird ein zufälliger Wert generiert und beim Start der
Anwendung in den Logs
angezeigt.
#### Weitere (nicht administrative) Nutzer mit OpenID Connect
Die folgenden Konfigurationsparameter werden benötigt, um die Authentifizierung weiterer Benutzer an einen OIDC-Provider
Die folgenden Konfigurationsparameter werden benötigt, um die Authentifizierung weiterer Benutzer an
einen OIDC-Provider
zu delegieren.
Ein Admin-Benutzer muss dabei konfiguriert sein.
* `APP_SECURITY_ENABLE_OIDC`: Aktiviert die Nutzung von OpenID Connect. Damit sind weitere Parameter erforderlich
* `SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_CUSTOM_CLIENT_NAME`: Name. Wird beim zusätzlichen Loginbutton angezeigt.
* `APP_SECURITY_ENABLE_OIDC`: Aktiviert die Nutzung von OpenID Connect. Damit sind weitere Parameter
erforderlich
* `SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_CUSTOM_CLIENT_NAME`: Name. Wird beim zusätzlichen
Loginbutton angezeigt.
* `SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_CUSTOM_CLIENT_ID`: Client-ID
* `SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_CUSTOM_CLIENT_SECRET`: Client-Secret
* `SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_CUSTOM_CLIENT_SCOPE[0]`: Hier sollte immer `openid` angegeben werden.
* `SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_CUSTOM_CLIENT_SCOPE[0]`: Hier sollte immer `openid`
angegeben werden.
* `SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_CUSTOM_ISSUER_URI`: Die URI des Providers,
z.B. `https://auth.example.com/realm/example`
* `SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_CUSTOM_USER_NAME_ATTRIBUTE`: Name des Attributes, welches den Benutzernamen
* `SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_CUSTOM_USER_NAME_ATTRIBUTE`: Name des Attributes, welches
den Benutzernamen
enthält.
Oft verwendet: `preferred_username`
Ist die Nutzung von OpenID Connect konfiguriert, erscheint ein zusätzlicher Login-Button zur Nutzung mit OpenID Connect
Ist die Nutzung von OpenID Connect konfiguriert, erscheint ein zusätzlicher Login-Button zur Nutzung
mit OpenID Connect
und dem konfigurierten `CLIENT_NAME`.
![Login mit OpenID Connect](docs/login.png)
@ -166,60 +222,74 @@ zu finden.
Wird OpenID Connect verwendet, gibt es eine rollenbasierte Berechtigungszuweisung.
Die Standardrolle für neue OIDC-Benutzer kann mit der Option `APP_SECURITY_DEFAULT_USER_ROLE` festgelegt werden.
Die Standardrolle für neue OIDC-Benutzer kann mit der Option `APP_SECURITY_DEFAULT_USER_ROLE`
festgelegt werden.
Mögliche Werte sind `user` oder `guest`. Standardwert ist `user`.
Benutzer mit der Rolle "Gast" sehen nur die Inhalte, die auch nicht angemeldete Benutzer sehen.
Hierdurch ist es möglich, einzelne Benutzer einzuschränken oder durch Änderung der Standardrolle auf `guest` nur
Hierdurch ist es möglich, einzelne Benutzer einzuschränken oder durch Änderung der Standardrolle auf
`guest` nur
einzelne Benutzer als vollwertige Nutzer zuzulassen.
![Rollenverwaltung](docs/userroles.png)
Benutzer werden nach dem Entfernen oder der Änderung der vergebenen Rolle automatisch abgemeldet und müssen sich neu anmelden.
Benutzer werden nach dem Entfernen oder der Änderung der vergebenen Rolle automatisch abgemeldet und
müssen sich neu anmelden.
Sie bekommen dabei wieder die Standardrolle zugewiesen.
#### Auswirkungen auf den dargestellten Inhalt
Nur Administratoren haben Zugriff auf den Konfigurationsbereich, nur angemeldete Benutzer können die anonymisierte oder
Nur Administratoren haben Zugriff auf den Konfigurationsbereich, nur angemeldete Benutzer können die
anonymisierte oder
pseudonymisierte Patienten-ID sowie den Qualitätsbericht von DNPM:DIP einsehen.
Wurde kein Administrator-Account konfiguriert, sind diese Inhalte generell nicht verfügbar.
### Tokenbasierte Authentifizierung für MTBFile-Endpunkt
Die Anwendung unterstützt das Erstellen und Nutzen einer tokenbasierten Authentifizierung für den MTB-File-Endpunkt.
Die Anwendung unterstützt das Erstellen und Nutzen einer tokenbasierten Authentifizierung für den
MTB-File-Endpunkt.
Dies kann mit der Umgebungsvariable `APP_SECURITY_ENABLE_TOKENS` aktiviert (`true` oder `false`) werden
Dies kann mit der Umgebungsvariable `APP_SECURITY_ENABLE_TOKENS` aktiviert (`true` oder `false`)
werden
und ist als Standardeinstellung nicht aktiv.
Ist diese Einstellung aktiviert worden, ist es Administratoren möglich, Zugriffstokens für Onkostar zu erstellen, die
Ist diese Einstellung aktiviert worden, ist es Administratoren möglich, Zugriffstokens für Onkostar
zu erstellen, die
zur Nutzung des MTB-File-Endpunkts eine HTTP-Basic-Authentifizierung voraussetzen.
![Tokenverwaltung](docs/tokens.png)
In diesem Fall kann der Endpunkt für das Onkostar-Plugin **[onkostar-plugin-dnpmexport](https://github.com/CCC-MF/onkostar-plugin-dnpmexport)** wie folgt konfiguriert werden:
In diesem Fall kann der Endpunkt für das Onkostar-Plugin *
*[onkostar-plugin-dnpmexport](https://github.com/CCC-MF/onkostar-plugin-dnpmexport)** wie folgt
konfiguriert werden:
```
https://testonkostar:MTg1NTL...NGU4@etl.example.com/mtbfile
```
Ist die Verwendung von Tokens aktiv, werden Anfragen ohne die Angabe der Token-Information abgelehnt.
Ist die Verwendung von Tokens aktiv, werden Anfragen ohne die Angabe der Token-Information
abgelehnt.
Alternativ kann eine Authentifizierung über Benutzername/Passwort oder OIDC erfolgen.
### Transformation von Werten
In Onkostar kann es vorkommen, dass ein Wert eines Merkmalskatalogs an einem Standort angepasst wurde und dadurch nicht dem Wert entspricht,
In Onkostar kann es vorkommen, dass ein Wert eines Merkmalskatalogs an einem Standort angepasst
wurde und dadurch nicht dem Wert entspricht,
der von DNPM:DIP akzeptiert wird.
Diese Anwendung bietet daher die Möglichkeit, eine Transformation vorzunehmen. Hierzu muss der "Pfad" innerhalb des JSON-MTB-Files angegeben werden und
Diese Anwendung bietet daher die Möglichkeit, eine Transformation vorzunehmen. Hierzu muss der "
Pfad" innerhalb des JSON-MTB-Files angegeben werden und
welcher Wert wie ersetzt werden soll.
Hier ein Beispiel für die erste (Index 0 - weitere dann mit 1,2, ...) Transformationsregel:
* `APP_TRANSFORMATIONS_0_PATH`: Pfad zum Wert in der JSON-MTB-Datei. Beispiel: `diagnoses[*].icd10.version` für **alle** Diagnosen
* `APP_TRANSFORMATIONS_0_FROM`: Angabe des Werts, der ersetzt werden soll. Andere Werte bleiben dabei unverändert.
* `APP_TRANSFORMATIONS_0_PATH`: Pfad zum Wert in der JSON-MTB-Datei. Beispiel:
`diagnoses[*].icd10.version` für **alle** Diagnosen
* `APP_TRANSFORMATIONS_0_FROM`: Angabe des Werts, der ersetzt werden soll. Andere Werte bleiben
dabei unverändert.
* `APP_TRANSFORMATIONS_0_TO`: Angabe des neuen Werts.
### Mögliche Endpunkte zur Datenübermittlung
@ -242,43 +312,53 @@ Folgende Umgebungsvariablen müssen gesetzt sein, damit ein bwHC-MTB-File an DNP
#### Kafka-Topics
Folgende Umgebungsvariablen müssen gesetzt sein, damit ein bwHC-MTB-File an ein Kafka-Topic übermittelt wird:
Folgende Umgebungsvariablen müssen gesetzt sein, damit ein bwHC-MTB-File an ein Kafka-Topic
übermittelt wird:
* `APP_KAFKA_OUTPUT_TOPIC`: Zu verwendendes Topic zum Versenden von Anfragen.
* `APP_KAFKA_OUTPUT_RESPONSE_TOPIC`: Topic mit Antworten über den Erfolg des Versendens. Standardwert: `APP_KAFKA_TOPIC` mit Anhang "_response".
* `APP_KAFKA_GROUP_ID`: Kafka GroupID des Consumers. Standardwert: `APP_KAFKA_TOPIC` mit Anhang "_group".
* `APP_KAFKA_OUTPUT_RESPONSE_TOPIC`: Topic mit Antworten über den Erfolg des Versendens.
Standardwert: `APP_KAFKA_TOPIC` mit Anhang "_response".
* `APP_KAFKA_GROUP_ID`: Kafka GroupID des Consumers. Standardwert: `APP_KAFKA_TOPIC` mit Anhang "_
group".
* `APP_KAFKA_SERVERS`: Zu verwendende Kafka-Bootstrap-Server als kommagetrennte Liste
Wird keine Rückantwort über Apache Kafka empfangen und es gibt keine weitere Möglichkeit den Status festzustellen, verbleibt der Status auf `UNKNOWN`.
Wird keine Rückantwort über Apache Kafka empfangen und es gibt keine weitere Möglichkeit den Status
festzustellen, verbleibt der Status auf `UNKNOWN`.
Weitere Einstellungen können über die Parameter von Spring Kafka konfiguriert werden.
Lässt sich keine Verbindung zu dem Backend aufbauen, wird eine Rückantwort mit Status-Code `900` erwartet, welchen es
Lässt sich keine Verbindung zu dem Backend aufbauen, wird eine Rückantwort mit Status-Code `900`
erwartet, welchen es
für HTTP nicht gibt.
Wird die Umgebungsvariable `APP_KAFKA_INPUT_TOPIC` gesetzt, kann eine Nachricht auch über dieses Kafka-Topic an den ETL-Prozessor übermittelt werden.
Wird die Umgebungsvariable `APP_KAFKA_INPUT_TOPIC` gesetzt, kann eine Nachricht auch über dieses
Kafka-Topic an den ETL-Prozessor übermittelt werden.
##### Retention Time
Generell werden in Apache Kafka alle Records entsprechend der Konfiguration vorgehalten.
So wird ohne spezielle Konfiguration ein Record für 7 Tage in Apache Kafka gespeichert.
Es sind innerhalb dieses Zeitraums auch alte Informationen weiterhin enthalten, wenn der Consent später abgelehnt wurde.
Es sind innerhalb dieses Zeitraums auch alte Informationen weiterhin enthalten, wenn der Consent
später abgelehnt wurde.
Durch eine entsprechende Konfiguration des Topics kann dies verhindert werden.
Beispiel - auszuführen innerhalb des Kafka-Containers: Löschen alter Records nach einem Tag
```
kafka-configs.sh --bootstrap-server localhost:9092 --alter --topic test --add-config retention.ms=86400000
```
##### Key based Retention
Möchten Sie hingegen immer nur die letzte Meldung für einen Patienten und eine Erkrankung in Apache Kafka vorhalten,
Möchten Sie hingegen immer nur die letzte Meldung für einen Patienten und eine Erkrankung in Apache
Kafka vorhalten,
so ist die nachfolgend genannte Konfiguration der Kafka-Topics hilfreich.
* `retention.ms`: Möglichst kurze Zeit in der alte Records noch erhalten bleiben, z.B. 10 Sekunden 10000
* `cleanup.policy`: Löschen alter Records und Beibehalten des letzten Records zu einem Key [delete,compact]
* `retention.ms`: Möglichst kurze Zeit in der alte Records noch erhalten bleiben, z.B. 10 Sekunden
10000
* `cleanup.policy`: Löschen alter Records und Beibehalten des letzten Records zu einem
Key [delete,compact]
Beispiele für ein Topic `test`, hier bitte an die verwendeten Topics anpassen.
@ -287,17 +367,23 @@ kafka-configs.sh --bootstrap-server localhost:9092 --alter --topic test --add-co
kafka-configs.sh --bootstrap-server localhost:9092 --alter --topic test --add-config cleanup.policy=[delete,compact]
```
Da als Key eines Records die (pseudonymisierte) Patienten-ID verwendet wird, stehen mit obiger Konfiguration
der Kafka-Topics nach 10 Sekunden nur noch der jeweils letzte Eintrag für den entsprechenden Key zur Verfügung.
Da als Key eines Records die (pseudonymisierte) Patienten-ID verwendet wird, stehen mit obiger
Konfiguration
der Kafka-Topics nach 10 Sekunden nur noch der jeweils letzte Eintrag für den entsprechenden Key zur
Verfügung.
Da der Key sowohl für die Records in Richtung DNPM:DIP, als auch für die Rückantwort identisch aufgebaut ist, lassen sich so
auch im Falle eines Consent-Widerspruchs die enthaltenen Daten als auch die Offenlegung durch Verifikationsdaten in der
Da der Key sowohl für die Records in Richtung DNPM:DIP, als auch für die Rückantwort identisch
aufgebaut ist, lassen sich so
auch im Falle eines Consent-Widerspruchs die enthaltenen Daten als auch die Offenlegung durch
Verifikationsdaten in der
Antwort effektiv verhindern, da diese nach 10 Sekunden gelöscht werden.
Es steht dann nur noch die jeweils letzten Information zur Verfügung, dass für einen Patienten/eine Erkrankung
Es steht dann nur noch die jeweils letzten Information zur Verfügung, dass für einen Patienten/eine
Erkrankung
ein Consent-Widerspruch erfolgte.
Dieses Vorgehen empfiehlt sich, wenn Sie gespeicherte Records nachgelagert für andere Auswertungen verwenden möchten.
Dieses Vorgehen empfiehlt sich, wenn Sie gespeicherte Records nachgelagert für andere Auswertungen
verwenden möchten.
### Antworten und Statusauswertung
@ -309,10 +395,12 @@ Anfragen an das bwHC-Backend aus Versionen bis 0.9.x wurden wie folgt behandelt:
| `HTTP 201` | `WARNING` |
| `HTTP 400-...` | `ERROR` |
Dies konnte dazu führen, dass zwar mit einem `HTTP 201` geantwortet wurde, aber dennoch in der Issue-Liste die
Dies konnte dazu führen, dass zwar mit einem `HTTP 201` geantwortet wurde, aber dennoch in der
Issue-Liste die
Severity `error` aufgetaucht ist.
Ab Version 0.10 wird die Issue-Liste der Antwort verwendet und die darion enthaltene höchste Severity-Stufe als Ergebnis verwendet.
Ab Version 0.10 wird die Issue-Liste der Antwort verwendet und die darion enthaltene höchste
Severity-Stufe als Ergebnis verwendet.
| Höchste Severity | Status |
|------------------|-----------|
@ -322,7 +410,8 @@ Ab Version 0.10 wird die Issue-Liste der Antwort verwendet und die darion enthal
## Docker-Images
Diese Anwendung ist auch als Docker-Image verfügbar: https://github.com/pcvolkmer/etl-processor/pkgs/container/etl-processor
Diese Anwendung ist auch als Docker-Image
verfügbar: https://github.com/pcvolkmer/etl-processor/pkgs/container/etl-processor
### Images lokal bauen
@ -332,20 +421,25 @@ Diese Anwendung ist auch als Docker-Image verfügbar: https://github.com/pcvolkm
### Integration eines eigenen Root CA Zertifikats
Wird eine eigene Root CA verwendet, die nicht offiziell signiert ist, wird es zu Problemen beim SSL-Handshake kommen, wenn z.B. gPAS zur Generierung von Pseudonymen verwendet wird.
Wird eine eigene Root CA verwendet, die nicht offiziell signiert ist, wird es zu Problemen beim
SSL-Handshake kommen, wenn z.B. gPAS zur Generierung von Pseudonymen verwendet wird.
Hier bietet es sich an, das Root CA Zertifikat in das Image zu integrieren.
#### Integration beim Bauen des Images
Hier muss die Zeile `"BP_EMBED_CERTS" to "true"` in der Datei `build.gradle.kts` verwendet werden und darf nicht als Kommentar verwendet werden.
Hier muss die Zeile `"BP_EMBED_CERTS" to "true"` in der Datei `build.gradle.kts` verwendet werden
und darf nicht als Kommentar verwendet werden.
Die PEM-Datei mit dem/den Root CA Zertifikat(en) muss dabei im vorbereiteten Verzeichnis [`bindings/ca-certificates`](bindings/ca-certificates) enthalten sein.
Die PEM-Datei mit dem/den Root CA Zertifikat(en) muss dabei im vorbereiteten Verzeichnis [
`bindings/ca-certificates`](bindings/ca-certificates) enthalten sein.
#### Integration zur Laufzeit
Hier muss die Umgebungsvariable `SERVICE_BINDING_ROOT` z.B. auf den Wert `/bindings` gesetzt sein.
Zudem muss ein Verzeichnis `bindings/ca-certificates` - analog zum Verzeichnis [`bindings/ca-certificates`](bindings/ca-certificates) mit einer PEM-Datei als Docker-Volume eingebunden werden.
Zudem muss ein Verzeichnis `bindings/ca-certificates` - analog zum Verzeichnis [
`bindings/ca-certificates`](bindings/ca-certificates) mit einer PEM-Datei als Docker-Volume
eingebunden werden.
Beispiel für Docker-Compose:
@ -360,12 +454,14 @@ Beispiel für Docker-Compose:
```
## Deployment
*Ausführen als Docker Container:*
```bash
cd ./deploy
cp env-sample.env .env
```
Wenn gewünscht, Änderungen in der `.env` vornehmen.
```bash
@ -374,15 +470,19 @@ docker compose up -d
### Einfaches Beispiel für ein eigenes Docker-Compose-File
Die Datei [`docs/docker-compose.yml`](docs/docker-compose.yml) zeigt eine einfache Konfiguration für REST-Requests basierend
Die Datei [`docs/docker-compose.yml`](docs/docker-compose.yml) zeigt eine einfache Konfiguration für
REST-Requests basierend
auf Docker-Compose mit der gestartet werden kann.
### Betrieb hinter einem Reverse-Proxy
Die Anwendung verarbeitet `X-Forwarded`-HTTP-Header und kann daher auch hinter einem Reverse-Proxy betrieben werden.
Die Anwendung verarbeitet `X-Forwarded`-HTTP-Header und kann daher auch hinter einem Reverse-Proxy
betrieben werden.
Dabei werden, je nachdem welche Header durch den Reverse-Proxy gesendet werden auch Protokoll, Host oder auch Path-Präfix
automatisch erkannt und verwendet werden. Dadurch ist z.B. eine abweichende Angabe des Pfads problemlos möglich.
Dabei werden, je nachdem welche Header durch den Reverse-Proxy gesendet werden auch Protokoll, Host
oder auch Path-Präfix
automatisch erkannt und verwendet werden. Dadurch ist z.B. eine abweichende Angabe des Pfads
problemlos möglich.
#### Beispiel *Traefik* (mit Docker-Labels):
@ -418,13 +518,17 @@ Das folgende Beispiel zeigt die Konfiguration einer _location_ in einer nginx-Ko
## Entwicklungssetup
Zum Starten einer lokalen Entwicklungs- und Testumgebung kann die beiliegende Datei `dev-compose.yml` verwendet werden.
Zum Starten einer lokalen Entwicklungs- und Testumgebung kann die beiliegende Datei
`dev-compose.yml` verwendet werden.
Diese kann zur Nutzung der Datenbanken **MariaDB** als auch **PostgreSQL** angepasst werden.
Zur Nutzung von Apache Kafka muss dazu ein Eintrag im hosts-File vorgenommen werden und der Hostname `kafka` auf die lokale
IP-Adresse verweisen. Ohne diese Einstellung ist eine Nutzung von Apache Kafka außerhalb der Docker-Umgebung nicht möglich.
Zur Nutzung von Apache Kafka muss dazu ein Eintrag im hosts-File vorgenommen werden und der Hostname
`kafka` auf die lokale
IP-Adresse verweisen. Ohne diese Einstellung ist eine Nutzung von Apache Kafka außerhalb der
Docker-Umgebung nicht möglich.
Beim Start der Anwendung mit dem Profil `dev` wird die in `dev-compose.yml` definierte Umgebung beim Start der
Beim Start der Anwendung mit dem Profil `dev` wird die in `dev-compose.yml` definierte Umgebung beim
Start der
Anwendung mit gestartet:
```
@ -436,4 +540,5 @@ Die Datei `application-dev.yml` enthält hierzu die Konfiguration für das Profi
Beim Ausführen der Integrationstests wird eine Testdatenbank in einem Docker-Container gestartet.
Siehe hier auch die Klasse `AbstractTestcontainerTest` unter `src/integrationTest`.
Ein einfaches Entwickler-Setup inklusive DNPM:DIP ist mit Hilfe von https://github.com/pcvolkmer/dnpmdip-devenv realisierbar.
Ein einfaches Entwickler-Setup inklusive DNPM:DIP ist mit Hilfe
von https://github.com/pcvolkmer/dnpmdip-devenv realisierbar.

View File

@ -27,7 +27,8 @@ data class AppConfigProperties(
var bwhcUri: String?,
var transformations: List<TransformationProperties> = listOf(),
var maxRetryAttempts: Int = 3,
var duplicationDetection: Boolean = true
var duplicationDetection: Boolean = true,
var genomDeTestSubmission: Boolean = true
) {
companion object {
const val NAME = "app"

View File

@ -224,12 +224,14 @@ class AppConfiguration {
@Bean
@ConditionalOnProperty(name = ["app.consent.gics.enabled"], havingValue = "true")
fun gicsConsentProcessor(
configProperties: AppConfigProperties,
gIcsConfigProperties: GIcsConfigProperties,
getObjectMapper: ObjectMapper,
appFhirConfig: AppFhirConfig,
gicsConsentService: IGetConsent
): ConsentProcessor {
return ConsentProcessor(
configProperties,
gIcsConfigProperties,
getObjectMapper,
appFhirConfig.fhirContext(),

View File

@ -4,6 +4,7 @@ import ca.uhn.fhir.context.FhirContext
import com.fasterxml.jackson.core.JsonProcessingException
import com.fasterxml.jackson.core.type.TypeReference
import com.fasterxml.jackson.databind.ObjectMapper
import dev.dnpm.etl.processor.config.AppConfigProperties
import dev.dnpm.etl.processor.config.GIcsConfigProperties
import dev.dnpm.etl.processor.consent.ConsentDomain
import dev.dnpm.etl.processor.consent.IGetConsent
@ -25,6 +26,7 @@ import java.util.*
@Service
class ConsentProcessor(
private val appConfigProperties: AppConfigProperties,
private val gIcsConfigProperties: GIcsConfigProperties,
private val objectMapper: ObjectMapper,
private val fhirContext: FhirContext,
@ -177,8 +179,14 @@ class ConsentProcessor(
* fixme: currently we do not have information about submission type
*/
private fun setGenomDeSubmissionType(mtbFile: Mtb) {
if (appConfigProperties.genomDeTestSubmission) {
// fixme: uncomment when data model is updated
// mtbFile.metadata.type = MvhSubmissionType.Test
logger.info("genomeDe submission mit TEST")
} else {
mtbFile.metadata.type = MvhSubmissionType.INITIAL
}
}
/**
* @param consentBundle consent resource

View File

@ -16,6 +16,7 @@ spring:
content:
enabled: true
paths: /**/*.js,/**/*.css,/**/*.svg,/**/*.jpeg
app:
isGenomDeTestSubmission: true
server:
forward-headers-strategy: framework

View File

@ -23,6 +23,7 @@ import ca.uhn.fhir.context.FhirContext
import com.fasterxml.jackson.databind.ObjectMapper
import de.ukw.ccc.bwhc.dto.*
import de.ukw.ccc.bwhc.dto.Patient
import dev.dnpm.etl.processor.config.AppConfigProperties
import dev.dnpm.etl.processor.config.GIcsConfigProperties
import dev.dnpm.etl.processor.config.JacksonConfig
import dev.dnpm.etl.processor.services.ConsentProcessor
@ -249,7 +250,7 @@ class ExtensionsTest {
private fun addConsentData(mtbFile: Mtb) {
val gIcsConfigProperties = GIcsConfigProperties("", "", "", true)
val appConfigProperties = AppConfigProperties(null, emptyList())
val bundle = Bundle()
val dummyConsent = ConsentProcessorTest.getDummyGenomDeConsent()
@ -257,6 +258,7 @@ class ExtensionsTest {
bundle.addEntry().resource = dummyConsent
ConsentProcessor(
appConfigProperties,
gIcsConfigProperties,
JacksonConfig().objectMapper(),
FhirContext.forR4(),

View File

@ -2,6 +2,7 @@ package dev.dnpm.etl.processor.services
import ca.uhn.fhir.context.FhirContext
import com.fasterxml.jackson.databind.ObjectMapper
import dev.dnpm.etl.processor.config.AppConfigProperties
import dev.dnpm.etl.processor.config.GIcsConfigProperties
import dev.dnpm.etl.processor.config.JacksonConfig
import dev.dnpm.etl.processor.consent.GicsConsentService
@ -31,6 +32,7 @@ import java.util.*
@ExtendWith(MockitoExtension::class)
class ConsentProcessorTest {
private lateinit var appConfigProperties: AppConfigProperties
private lateinit var gicsConsentService: GicsConsentService
private lateinit var objectMapper: ObjectMapper
private lateinit var gIcsConfigProperties: GIcsConfigProperties
@ -47,9 +49,15 @@ class ConsentProcessorTest {
this.objectMapper = jacksonConfig.objectMapper()
this.fhirContext = JacksonConfig.fhirContext()
this.gicsConsentService = gicsConsentService
this.appConfigProperties = AppConfigProperties(null, emptyList())
this.consentProcessor =
ConsentProcessor(gIcsConfigProperties, objectMapper, fhirContext, gicsConsentService)
ConsentProcessor(
appConfigProperties,
gIcsConfigProperties,
objectMapper,
fhirContext,
gicsConsentService
)
}
@Test