diff options
| -rw-r--r-- | README.md | 696 | ||||
| -rw-r--r-- | docs/configuration.md | 517 | ||||
| -rw-r--r-- | docs/development.md | 52 |
3 files changed, 629 insertions, 636 deletions
@@ -1,673 +1,97 @@ -# ETL-Processor für das MV gem. §64e und DNPM:DIP -[](https://github.com/pcvolkmer/etl-processor/actions/workflows/test.yml) +# ETL-Prozessor für das Modellvorhaben Genomsequenzierung gem. §64e SGB V + +[](https://github.com/pcvolkmer/etl-processor/actions/workflows/ci.yml) +[](https://github.com/pcvolkmer/mv64e-etl-processor/actions/workflows/github-code-scanning/codeql) ETL-Anwendung zur Pseudonymisierung von klinischen Daten für das Modellvorhaben Genomsequenzierung gem. §64e SGB V -im DNPM-Datenmodell 2.1 unter Beachtung des Consents. +im DNPM-Datenmodell 2.1 unter Beachtung und Verwendung der Teilnahmeerklärung und des Broad-Consents. -Pseudonymisierte und mit Consent versehene Daten können sowohl an DNPM:DIP als auch an nNGM weitergeleitet werden. +Pseudonymisierte und mit Consent versehene Datensätze können sowohl an DNPM:DIP als auch an nNGM weitergeleitet werden. Eine Differenzierung anhand der Erkrankung und ICD10-Code ist dabei möglich. -So können zum Beispiel alle Lungenfälle an nNGM, sonstige Fällen an DNPM:DIP weitergeleitet werden. +So können zum Beispiel alle Lungenfälle an nNGM, sonstige Fällen an DNPM:DIP ausgeleitet werden. -Zur Pseudonymgenerierung und Consentverwaltung werden die [Greifswalder Tools gPAS und gICS](https://www.ths-greifswald.de/) +Zur Pseudonymgenerierung und Consentverwaltung werden +die [Greifswalder Tools gPAS und gICS](https://www.ths-greifswald.de/) unterstützt. -Diese Anwendung erlaubt das Entgegennehmen von Datensetzen im DNPM-Datenmodell 2.1 aus dem Onkostar-Plugin -**[mv64e-onkostar-plugin-export](https://github.com/pcvolkmer/mv64e-onkostar-plugin-export)**. +Diese Anwendung erlaubt das Entgegennehmen von Datensetzen im DNPM-Datenmodell 2.1 aus +dem [Onkostar](https://www.it-choice.de/produkte/onkostar/)-Plugin +[mv64e-onkostar-plugin-export](https://github.com/pcvolkmer/mv64e-onkostar-plugin-export).  -## Wichtige Änderungen in den letzten Versionen - -### 🔥 Wichtige Änderungen in Version 0.18 - -Ab Version 0.18 kann diese Anwendung zur Datenausleitung über die nNGM-REST-API verwendet werden. -Dazu kann auch die Konfiguration des in dieser Version eingeführten [Routing-Mechanismus](#routed-rest) verwendet werden. - -### 🔥 Wichtige Änderungen in Version 0.17 - -Ab Version 0.17 verwendet diese Anwendung [pcvolkmer/mv64e-mtb-model](https://github.com/pcvolkmer/mv64e-mtb-model) und ersetzt -damit die bisher genutzte und veraltete Implementierung des DNPM-Datenmodells 2.1. - -### 🔥 Wichtige Änderungen in Version 0.16 - -#### Erkennung von Follow-Ups - -Ab Version 0.16 werden Meldungen als Follow-Ups erkannt und entsprechend weiterleiten, wenn - -* die zu bearbeitende Meldung Follow-Ups enthält und das neueste Follow-Up nach der letzten Meldung für den Patienten datiert ist. -* zuvor eine initiale Meldung bereits erfolgte, die akzeptiert wurde. - -Dies erfordert das Aktivieren der Funktion [Blockieren weiterer initialer Submissions](#blockieren-weiterer-initialer-submissions) - -#### Monitoring von ungültigen Anfragen - -Ungültige Anfragen werden nun protokolliert und können in der Übersicht eingesehen werden. -Zuvor wurden diese ignoriert. - -### 🔥 Wichtige Änderungen in Version 0.15 - -#### Konfiguration von Benutzern - -Zusätzlich zu einem Administrator-Account können nun [weitere Benutzer](#weitere-benutzer) -mit nicht administrativen Rechten in der Konfiguration angelegt werden. - -#### TAN-Speicherung - -Ab Version 0.15 wird zu jeder Anfrage die generierte TAN zusätzlich zur Request-ID gespeichert. -Die TAN wird nur für MTB-Anfragen gespeichert, da sie für Lösch-Anfragen nicht relevant ist. - -Hierdurch wird es möglich, die in Version 0.14 eingeführte Blockierung weiterer Submissions anhand der TAN -(z.B. aus der Meldebestätigung) für einen Patienten freizugeben. - -## Funktionsweise - -### Duplikaterkennung - -Die Erkennung von Duplikaten ist normalerweise immer aktiv, kann jedoch über den -Konfigurationsparameter -`APP_DUPLICATION_DETECTION=false` deaktiviert werden. - -### Modelvorhaben genomDE §64e - -#### Vorgangsummern -Zusätzlich zur Patienten Identifier Pseudonymisierung müssen Vorgangsummern generiert werden, die -jede Übertragung eindeutig identifizieren aber gleichzeitig dem Patienten zugeordnet werden können. -Dies lässt sich durch weitere Pseudonyme abbilden, allerdings werden pro Originalwert mehrere -Pseudonyme benötigt. -Zu diesem Zweck muss in gPas eine **Multi-Pseudonym-Domäne** konfiguriert werden (siehe auch -*APP_PSEUDONYMIZE_GPAS_CCDN*). - -**WICHTIG:** Deaktivierte Pseudonymisierung ist nur für Tests nutzbar. Vorgangsummern sind zufällig -und werden anschließend verworfen. - -#### Blockieren weiterer initialer Submissions - -Diese Anwendung blockiert weitere initiale Submissions nach der ersten erfolgreichen Übertragung in DNPM:DIP. -Sobald für einen Patienten eine Übertragung ohne Issues oder mit maximal Warnungen erfolgte und damit von -DNPM:DIP akzeptiert wurde, werden weitere Meldungen solange verworfen, bis ein Administrator den Patienten -wieder freigegeben hat. - -**ACHTUNG**: Diese Funktionalität ist ab Version 0.14 verfügbar, jedoch nicht standardmäßig aktiviert und -muss erst aktiviert werden. - -`APP_POST_INITIAL_SUBMISSION_BLOCK` -> `true` | `false` (falls fehlt, wird `false` angenommen) - -Nach Aktivierung des Features wird es für ältere Meldungen erforderlich sein, bereits durchgeführte -Initialmeldungen als solche zu kennzeichnen. Dies **muss** manuell in der Datenbank gemacht werden. - -Gezielt Meldungen kennzeichnen: - -```sql -UPDATE request SET submission_type = "INITIAL" - WHERE id IN (...); -``` - -Alle MTB-File Meldungen (ohne Lösch-Request) kennzeichnen, die erfolgreich an DNPM:DIP gesendet wurden: - -```sql -UPDATE request SET submission_type = "INITIAL" - WHERE (status = "WARNING" OR status = "SUCCESS") - AND type = "MTB_FILE"; -``` - -#### Test Betriebsbereitschaft -Um die volle 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-Submission-Kennung -übertragen, unabhängig vom ursprünglichen Wert. - -`APP_GENOM_DE_TEST_SUBMISSION` -> `true` | `false` (falls fehlt, wird `false` angenommen) - -**ACHTUNG**: Diese Einstellung funktioniert nur, wenn, wie in Marburg, eine vollständige Consent-Abfrage über gICS für -MV-Consent und Broad Consent erfolgt. - -Soll eine Testsubmission ohne diese Anbindung durchgeführt werden, kann eine Transformation als Work-Around umgesetzt werden: - -``` -APP_TRANSFORMATION_0_PATH: "metadata.type" -APP_TRANSFORMATION_0_FROM: "initial" -APP_TRANSFORMATION_0_TO: "test" -``` - -### Datenübermittlung über HTTP/REST - -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: - -| HTTP-Request | URL | Bemerkung | -|--------------|-----------------------------------------|----------------------------------------------------------------| -| `POST` | `https://dnpm.example.com/mtb` | Die Anwendung verarbeitet den eingehenden Datensatz | -| `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. Siehe auch: https://github.com/pcvolkmer/mv64e-etl-processor/pull/196 - -### 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. - -Siehe hierzu auch: https://github.com/pcvolkmer/mv64e-rest-to-kafka-gateway und https://github.com/pcvolkmer/mv64e-kafka-to-rest-gateway. - -## Konfiguration - -### Pseudonymisierung der Patienten-ID - -Wenn eine URI zu einer gPAS-Instanz (Version >= 2023.1.0) angegeben ist, wird diese verwendet. -Ist diese nicht gesetzt. wird intern eine Anonymisierung der Patienten-ID vorgenommen. - -* `APP_PSEUDONYMIZE_PREFIX`: Standortbezogenes Präfix - `UNKNOWN`, wenn nicht gesetzt -* `APP_PSEUDONYMIZE_GENERATOR`: `BUILDIN` oder `GPAS` - `BUILDIN`, wenn nicht gesetzt -* `APP_PSEUDONYMIZE_HMAC_KEY`: Wenn gesetzt, wird anstelle `SHA256` nun `SHA256-HMAC` mit diesem Key verwendet. - -**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 -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 Base32-codiert - hierzu werden die ersten 42 Zeichen des Hashes -ohne endende "=" - zuzüglich des konfigurierten Präfixes als Patienten-Pseudonym verwendet. - -Beispiel für ID `123` und Prefix `123`: - -`UNKNOWN_uzs2iwjaiixz2ql6jbt67xcpxcqeuhz774p2a7uzr2` - -Wird `APP_PSEUDONYMIZE_HMAC_KEY` konfiguriert, wird der Hash mit diesem Wert als HMAC-Key gebildet. -Auch hier werden die ersten 42 Zeichen Base64-codiert verwendet. -Hierdurch wird die Nutzung von Rainbow-Tables erschwert, solange der HMAC-Key geheim gehalten wird. - -Beispiel für ID `123` und HMAC-Key `TEST` (gleichzeitig HMAC-Key): - -`UNKNOWN_3u2nc3hzwbe2kylbmcrhoahgkisxl5jfbcwr3wonr3` - -#### Pseudonymisierung mit gPAS - -Wurde die Verwendung von gPAS konfiguriert, so sind weitere Angaben zu konfigurieren. - -Ab Version 2025.1 (Multi-Pseudonym Support) - -* `APP_PSEUDONYMIZE_GPAS_URI`: URI der gPAS-Instanz REST API (e.g. http://127.0.0.1:9990/ttp-fhir/fhir/gpas) -* `APP_PSEUDONYMIZE_GPAS_USERNAME`: gPas Basic-Auth Benutzername -* `APP_PSEUDONYMIZE_GPAS_PASSWORD`: gPas Basic-Auth Passwort -* `APP_PSEUDONYMIZE_GPAS_PATIENT_DOMAIN`: gPas Domänenname für Patienten ID (ebenfalls gültig: `APP_PSEUDONYMIZE_GPAS_PID_DOMAIN`) -* `APP_PSEUDONYMIZE_GPAS_GENOM_DE_TAN_DOMAIN`: gPAS Multi-Pseudonym-Domäne für genomDE Vorgangsnummern ( - Clinical data node) - -Soll anstelle der REST-Schnittstelle von gPAS die SOAP-Schnittstelle verwendet werden, -so ist nicht die URI der gPAS-Instanz anzugeben, sondern der SOAP-Endpoint: - -* `APP_PSEUDONYMIZE_GPAS_SOAP_ENDPOINT`: SOAP-Endpoint der gPAS-Instanz (e.g. http://127.0.0.1:9990/gpas/gpasService) - -### (Externe) Consent-Services - -Consent-Services können konfiguriert werden. - -* `APP_CONSENT_SERVICE`: Zu verwendender (externer) Consent-Service: - * `NONE`: Verwende Consent-Angaben im MTB-File v1 und ändere diese nicht. Für MTB-File v2 wird - die Prüfung übersprungen. - * `GICS`: Verwende gICS der Greiswalder Tools (siehe unten). - -#### Einwilligung gICS - -Ab gIcs Version 2.13.0 kann im ETL-Processor -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* (MTB-File v1) und *currentPolicyStatesForPerson* (MTB-File v2) 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. - -##### 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. - -##### Konfiguration - -* `APP_CONSENT_SERVICE`: Folgende Werte sind möglich: - * Der Wert `GICS` aktiviert die Standard-Abfrage bei gICS - * Der Wert `GICS_GET_BC` aktiviert die **experimentelle** Abfrage per HTTP-GET Request **nur** für Broad-Consent. - * Der Wert `NONE` deaktiviert die Abfrage in gICS. -* `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_GENOMDECONSENTDOMAINNAME`: Domäne in der gIcs GenomDE Modelvorhaben §64e - Einwilligungen verwaltet. Falls Wert leer, wird keine Consent-Information abgerufen. -* `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_POLICYURI`: Die Version der Einwilligung. Falls leer wird Version 1.6d - (`urn:oid:2.16.840.1.113883.3.1937.777.24.2.1790`) angenommen. - -Die **experimentelle* Abfrage über `GICS_GET_BC` setzt voraus, dass bereits ein MV-Consent im eingehenden Datensatz -vorhanden ist und ergänzt nur den Broad-Consent. - -### Anmeldung mit einem Passwort - -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. -* `APP_SECURITY_ADMIN_PASSWORD`: Das Passwort für den Administrator (Empfohlen). - -Ein Administrator-Passwort muss inklusive des Encoding-Präfixes vorliegen. - -Hier Beispiele für das Beispielpasswort `very-secret`: - -* `{noop}very-secret` (Das Passwort liegt im Klartext vor - nicht empfohlen!) -* `{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 angezeigt. - -#### Weitere Benutzer - -Ab Version 0.15.0 können weitere Benutzer-Accounts konfiguriert werden, ohne OpenID Connect zu verwenden. -Diese haben lediglich Benutzerrechte und können keine Konfigurationen einsehen oder ändern. - -Beispiele: - -``` -APP_SECURITY_USERS[0]_USERNAME=myuser -APP_SECURITY_USERS[0]_PASSWORD={noop}very-secret -APP_SECURITY_USERS[1]_USERNAME=otheruser -APP_SECURITY_USERS[1]_PASSWORD={bcrypt}$2y$05$CCkfsMr/wbTleMyjVIK8g.Aa3RCvrvoLXVAsL.f6KeouS88vXD9b6 -... -``` - -#### Weitere (nicht administrative) Nutzer mit OpenID Connect - -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. -* `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_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 - enthält. - Oft verwendet: `preferred_username` - -Ist die Nutzung von OpenID Connect konfiguriert, erscheint ein zusätzlicher Login-Button zur Nutzung -mit OpenID Connect -und dem konfigurierten `CLIENT_NAME`. - - - -Weitere Informationen zur Konfiguration des OIDC-Providers -sind [hier](https://docs.spring.io/spring-security/reference/servlet/oauth2/index.html#oauth2-client) -zu finden. - -#### Rollenbasierte Berechtigungen - -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. -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 -einzelne Benutzer als vollwertige Nutzer zuzulassen. - - - -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 -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. - -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 -zur Nutzung des MTB-File-Endpunkts eine HTTP-Basic-Authentifizierung voraussetzen. - - - -In diesem Fall kann der Endpunkt für das Onkostar-Plugin * -*[mv64e-onkostar-plugin-export](https://github.com/pcvolkmer/mv64e-onkostar-plugin-export)** 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. - -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, -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 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_TO`: Angabe des neuen Werts. - -### Mögliche Endpunkte zur Datenübermittlung - -Für REST-Requests als auch zur Nutzung von Kafka-Topics können Endpunkte konfiguriert werden. - -Es ist dabei nur die Konfiguration eines Endpunkts zulässig. -Werden sowohl REST als auch Kafka-Endpunkt konfiguriert, wird nur der REST-Endpunkt verwendet. - -#### REST - -Folgende Umgebungsvariablen müssen gesetzt sein, damit ein MTB-File an DNPM:DIP gesendet wird: - -* `APP_REST_URI`: URI der zu benutzenden API der Backend-Instanz. Zum Beispiel `http://localhost:9000/api` -* `APP_REST_TYPE`: Mögliche Werte `dip` (Standard) für DNPM:DIP und `nngm` für die nNGM-API. -* `APP_REST_USERNAME`: Basic-Auth-Benutzername für den REST-Endpunkt -* `APP_REST_PASSWORD`: Basic-Auth-Passwort für den REST-Endpunkt -* `APP_REST_API_KEY`: Angabe eines API-Keys zur Verwendung mit `APP_REST_TYPE=nngm` für die nNGM-API - -#### Routed REST - -Seit Version 0.18 ist eine Konfiguration des neu eingeführten **Routing**-Mechanismus möglich. -Damit kann für bestimmte Entitäten und Diagnosen ein abweichender REST-Endpunkt definiert werden. - -Beispiel: - -* `APP_ROUTING_NNGM_URI`: URI der nNGM-REST-API. -* `APP_ROUTING_NNGM_API_KEY`: API-Key zur Nutzung der nNGM-REST-API. -* `APP_ROUTING_NNGM_ICD10[0]`: Erster ICD-Code - weitere möglich. - -Mit dieser Konfiguration wird jeder `PatientRecord`, dessen (letzte) Diagnose einen ICD-10-Code hat, dessen Anfang -konfiguriert ist, nicht über den Standard-Weg versendet, sondern an den für nNGM konfigurierten API-Endpunkt. - -Wird zum Beispiel `APP_ROUTING_NNGM_ICD10[0] = C34` konfiguriert, werden Diagnosen wie "C34.0", "C34.1", etc. an das nNGM -übermittelt. - -#### Kafka-Topics - -Folgende Umgebungsvariablen müssen gesetzt sein, damit ein 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_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`. - -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 -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. - -Soll eine SSL-gesicherte Verbindung zu Kafka verwendet werden, so sind die SSL-Zertifikate in -der Spring-Konfiguration anzugeben. -Ein Beispiel findet sich in [`application-dev.yml`](src/main/resources/application-dev.yml). -Dies kann auch mit Umgebungsvariablen wie `SPRING_KAFKA_SECURITY_...` und `SPRING_KAFKA_SSL_...` -umgesetzt 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. - -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, -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] - -Beispiele für ein Topic `test`, hier bitte an die verwendeten Topics anpassen. - -``` -kafka-configs.sh --bootstrap-server localhost:9092 --alter --topic test --add-config retention.ms=10000 -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 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 -ein Consent-Widerspruch erfolgte. - -Dieses Vorgehen empfiehlt sich, wenn Sie gespeicherte Records nachgelagert für andere Auswertungen -verwenden möchten. - -### Antworten und Statusauswertung - -Seit 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 | -|------------------|-----------| -| `info` | `SUCCESS` | -| `warning` | `WARNING` | -| `error`, `fatal` | `ERROR` | - ## Docker-Images -Diese Anwendung ist auch als Docker-Image -verfügbar: https://github.com/pcvolkmer/mv64e-etl-processor/pkgs/container/mv64e-etl-processor - -### Images lokal bauen - -```bash -./gradlew bootBuildImage -``` - -### 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. - -Hier bietet es sich an, das Root CA Zertifikat in das Image zu integrieren. - -#### Integration beim Bauen des Images +Docker-Images dieser Anwendung werden hier bereitgestellt und sollen das lokale Deployment vereinfachen: +https://github.com/pcvolkmer/mv64e-etl-processor/pkgs/container/mv64e-etl-processor -Hier muss die Zeile `"BP_EMBED_CERTS" to "true"` in der Datei `build.gradle.kts` verwendet werden -und darf nicht als Kommentar verwendet werden. +## Wichtige Änderungen -Die PEM-Datei mit dem/den Root CA Zertifikat(en) muss dabei im vorbereiteten Verzeichnis [ -`bindings/ca-certificates`](bindings/ca-certificates) enthalten sein. +### 🔥 Wichtige Änderungen in Version 0.18 -#### Integration zur Laufzeit +Ab Version 0.18 kann diese Anwendung zur Datenausleitung über die nNGM-REST-API verwendet werden. +Dazu kann auch die Konfiguration des in dieser Version eingeführten [Routing-Mechanismus](#routed-rest) verwendet +werden. -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 und der -Datei [`bindings/ca-certificates/type`](bindings/ca-certificates/type) als Docker-Volume eingebunden werden. +### Weitere Änderungen -Beispiel für Docker-Compose: +Siehe [CHANGELOG.md](CHANGELOG.md) -``` -... - environment: - SERVICE_BINDING_ROOT: /bindings - ... - volumes: - - "/path/to/bindings/ca-certificates/:/bindings/ca-certificates/:ro" -... -``` +## Wesentlichen Funktionen für das Modellvorhaben Genomsequenzierung -## Deployment +Diese Anwendung unterstützt die wesentlichen Funktionen für den Betrieb einer ETL-Strecke für das Modellvorhaben +Genomsequenzierung nach der Datenextraktion: -*Ausführen als Docker Container:* +* Generierung von Vorgangsnummern +* Pseudonymisierung der Patienten-ID +* Einbetten von Consent-Informationen -```bash -cd ./deploy -cp env-sample.env .env -``` +Dies ist nach einem Export aus dem Primärsystem (z.B. Onkostar) in der Regel noch nicht erfolgt und kann mit dieser +Anwendung realisiert werden. -Wenn gewünscht, Änderungen in der `.env` vornehmen. +### Vorgangsummern -```bash -docker compose up -d -``` +Jede Datenübertragung benötigt eine eindeutige Vorgangsnummer. +Diese Anwendung stellt die erforderlichen Schnittstellen bereit, um eine Vorgangsnummer zu generieren und in den +Datensatz +zu integrieren. -### Einfaches Beispiel für ein eigenes Docker-Compose-File +Weitere Informationen zur Konfiguration der Generierung von Vorgangsnummern gibt es hier: +[docs/configuration.md - Vorgangsnummern](docs/configuration.md#vorgangsnummern). -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. +### Pseudonymisierung der Patienten-ID -### Betrieb hinter einem Reverse-Proxy +Diese Anwendung nutzt die Pseudonymisierungsfunktion von gPAS. Wenn eine URI zu einer gPAS-Instanz (Version >= 2023.1.0) +angegeben ist, wird diese verwendet. +Ist diese nicht gesetzt, wird intern eine Anonymisierung der Patienten-ID vorgenommen. -Die Anwendung verarbeitet `X-Forwarded`-HTTP-Header und kann daher auch hinter einem Reverse-Proxy -betrieben werden. +Weitere Informationen zur Konfiguration der Pseudonymisierung gibt es hier: +[docs/configuration.md - Pseudonymisierung der Patienten-ID](docs/configuration.md#pseudonymisierung-der-patienten-id). -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. +### Einbetten von Consent-Informationen -#### Beispiel *Traefik* (mit Docker-Labels): +Einbettung von Consent-Informationen kann optional mithilfe von gICS geschehen. -Das folgende Beispiel zeigt die Konfiguration in einer Docker-Compose-Datei mit Service-Labels. +Weitere Informationen zur Konfiguration der Integration und Einbettung von Consent-Informationen gibt es hier: +[docs/configuration.md - Teilnahmeerklärung und Broad Consent mit gICS](docs/configuration.md#teilnahmeerklärung-und-broad-consent-mit-gics). -``` -... - deploy: - labels: - - "traefik.http.routers.etl.rule=PathPrefix(`/etl-processor`)" - - "traefik.http.routers.etl.middlewares=etl-path-strip" - - "traefik.http.middlewares.etl-path-strip.stripprefix.prefixes=/etl-processor" -... -``` +## Weitere Funktionen -#### Beispiel *nginx* +Neben den wesentlichen Funktionen unterstützt diese Anwendung zudem: -Das folgende Beispiel zeigt die Konfiguration einer _location_ in einer nginx-Konfigurationsdatei. +* Konfiguration der Datenein- und Ausgabe zur Unterstützung von REST-Schnittstellen und Message-oriented Middleware + (MoM) mit Apache Kafka. +* Absicherung des Zugriffs durch Anmeldung und Authentifizierung – inklusive der Nutzung von OpenID-Connect. +* Ausleitung von Datensätzen sowohl an DNPM:DIP, als auch die nNGM-API für das Modellvorhaben Genomsequenzierung. +* Duplikaterkennung zum Verhindern von mehrmaliger Übertragung unveränderter Datensätze. +* Blockieren von weiteren Übertragungen ohne bestätigte, initiale Meldung mit Meldebestätigung. +* Automatische FollowUp-Erkennung (nach einer initialen Meldung). +* Eine einfache Weboberfläche zur Nachverfolgung von Datensätzen. -``` -... - location /etl-processor { - set $upstream http://<beispiel:8080>/; - proxy_set_header Host $host; - proxy_set_header X-Forwarded-Scheme $scheme; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Forwarded-For $remote_addr; - proxy_set_header X-Real-IP $remote_addr; - proxy_pass $upstream; - } -... -``` +Alle Informationen zur Konfiguration dieser Funktionen gibt es hier: +[docs/configuration.md](docs/configuration.md). ## Entwicklungssetup -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. - -Zum Bereitstellen von JavaScript- und CSS-Bundles muss der Befehl `npm run build` ausgeführt werden. -Ein kontinuierliches Neubauen bei Änderungen in CSS und JS-Dateien ist mit `npm run dev` möglich. -Dies setzt eine NodeJS-Umgebung voraus. - -Beim Start der Anwendung mit dem Profil `dev` wird die in `dev-compose.yml` definierte Umgebung beim -Start der Anwendung mit gestartet: - -```bash -SPRING_PROFILES_ACTIVE=dev ./gradlew bootRun -``` - -Die Datei `application-dev.yml` enthält hierzu die Konfiguration für das Profil `dev`. - -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. +Informationen für ein Entwicklungssetup sind in [docs/development.md](docs/development.md) zu finden. +Dort sind auch Informationen zur Anpassung des Docker-Images zu hinterlegt. diff --git a/docs/configuration.md b/docs/configuration.md new file mode 100644 index 0000000..50707b8 --- /dev/null +++ b/docs/configuration.md @@ -0,0 +1,517 @@ +# Konfigurationsübersicht + +## Inhalt + +1. Wesentliche Funktionen für das Modellvorhaben Genomsequenzierung + 1. [Vorgangsnummern](#vorgangsnummern) + 2. [Pseudonymisierung der Patienten-ID](#pseudonymisierung-der-patienten-id) + 3. [Teilnahmeerklärung und Broad-Consent mit gICS](#teilnahmeerklärung-und-broad-consent-mit-gics) +2. Anmeldung und Authentifizierung + 1. [Anmeldung mit einem Passwort](#anmeldung-mit-einem-passwort) + 2. [Nutzung eines Authentifizierungsservers und OpenID Connect](#nutzung-eines-authentifizierungsservers-und-openid-connect) + 3. [Tokenbasierte Authentifizierung für MTBFile-Endpunkt](#tokenbasierte-authentifizierung-für-mtbfile-endpunkt) +3. Konfiguration der Datenein- und ausgabe + 1. [Dateneingang über HTTP/REST](#dateneingang-über-httprest) + 2. [Dateneingang mit Apache Kafka](#dateneingang-mit-apache-kafka) + 3. [Mögliche REST-Endpunkte zur Datenausgabe](#mögliche-rest-endpunkte-zur-datenausgabe) + 4. [Datenübermittlung mit Apache Kafka](#datenübermittlung-mit-apache-kafka) +4. [Duplikaterkennung](#duplikaterkennung) +5. [Blockieren weiterer initialer Submissions](#blockieren-weiterer-initialer-submissions) +6. [FollowUp-Erkennung](#followup-erkennung) +7. [Transformation von Werten](#transformation-von-werten) +8. [Deployment mit Docker-Compose](#deployment-mit-docker-compose) +9. [Test der Betriebsbereitschaft](#test-der-betriebsbereitschaft) + +## Essenzielle Funktionen für das Modellvorhaben Genomsequenzierung + +### Vorgangsnummern + +Für jede Datenübermittlung muss eine neue Vorgangsummer generiert werden, die +jede Übertragung eindeutig identifizieren, aber gleichzeitig dem Patienten zugeordnet werden kann. +Dies lässt sich durch weitere Pseudonyme abbilden, allerdings werden pro Originalwert mehrere +Pseudonyme benötigt. +Zu diesem Zweck muss in gPas eine **Multi-Pseudonym-Domäne** konfiguriert werden (siehe auch +*APP_PSEUDONYMIZE_GPAS_CCDN*). + +**WICHTIG:** Deaktivierte Pseudonymisierung ist nur für Tests nutzbar. Vorgangsummern sind zufällig +und werden anschließend verworfen. + +### Pseudonymisierung der Patienten-ID + +Wenn eine URI zu einer gPAS-Instanz (Version >= 2023.1.0) angegeben ist, wird diese verwendet. +Ist diese nicht gesetzt, wird intern eine Anonymisierung der Patienten-ID vorgenommen. + +* `APP_PSEUDONYMIZE_PREFIX`: Standortbezogenes Präfix - `UNKNOWN`, wenn nicht gesetzt +* `APP_PSEUDONYMIZE_GENERATOR`: `BUILDIN` oder `GPAS` - `BUILDIN`, wenn nicht gesetzt +* `APP_PSEUDONYMIZE_HMAC_KEY`: Wenn in Verbindung mit `BUILDIN` gesetzt, wird anstelle `SHA256` nun `SHA256-HMAC` mit + dem angegebenen Key verwendet. + +**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 vergleichbare IDs bereitzustellen. + +#### Pseudonymisierung mit gPAS + +Wurde die Verwendung von gPAS konfiguriert, so sind weitere Angaben zu konfigurieren. + +Ab Version 2025.1 (Multi-Pseudonym Support) + +* `APP_PSEUDONYMIZE_GPAS_URI`: URI der gPAS-Instanz REST API (e.g. http://127.0.0.1:9990/ttp-fhir/fhir/gpas) +* `APP_PSEUDONYMIZE_GPAS_USERNAME`: gPas Basic-Auth Benutzername +* `APP_PSEUDONYMIZE_GPAS_PASSWORD`: gPas Basic-Auth Passwort +* `APP_PSEUDONYMIZE_GPAS_PATIENT_DOMAIN`: gPas Domänenname für Patienten ID (ebenfalls gültig: + `APP_PSEUDONYMIZE_GPAS_PID_DOMAIN`) +* `APP_PSEUDONYMIZE_GPAS_GENOM_DE_TAN_DOMAIN`: gPAS Multi-Pseudonym-Domäne für genomDE Vorgangsnummern (Clinical data + node) + +Soll anstelle der REST-Schnittstelle von gPAS die SOAP-Schnittstelle verwendet werden, +so ist nicht die URI der gPAS-Instanz anzugeben, sondern der SOAP-Endpoint: + +* `APP_PSEUDONYMIZE_GPAS_SOAP_ENDPOINT`: SOAP-Endpoint der gPAS-Instanz (e.g. http://127.0.0.1:9990/gpas/gpasService) + +#### 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 Base32-codiert - hierzu werden die ersten 42 Zeichen des Hashes +ohne endende "=" - zuzüglich des konfigurierten Präfixes als Patienten-Pseudonym verwendet. + +Beispiel für ID `123` und Prefix `123`: + +`UNKNOWN_uzs2iwjaiixz2ql6jbt67xcpxcqeuhz774p2a7uzr2` + +Wird `APP_PSEUDONYMIZE_HMAC_KEY` konfiguriert, wird der Hash mit diesem Wert als HMAC-Key gebildet. +Auch hier werden die ersten 42 Zeichen Base64-codiert verwendet. +Hierdurch wird die Nutzung von Rainbow-Tables erschwert, solange der HMAC-Key geheim gehalten wird. + +Beispiel für ID `123` und HMAC-Key `TEST` (gleichzeitig HMAC-Key): + +`UNKNOWN_3u2nc3hzwbe2kylbmcrhoahgkisxl5jfbcwr3wonr3` + +### Teilnahmeerklärung und Broad-Consent mit gICS + +Externe Consent-Services können konfiguriert werden. + +* `APP_CONSENT_SERVICE`: Zu verwendender (externer) Consent-Service: + * `NONE`: Verwende Consent-Angaben im MTB-File v1 und ändere diese nicht. + * `GICS`: Verwende gICS der [Greifswalder Tools gPAS und gICS](https://www.ths-greifswald.de/). + +Ab gIcs Version 2.13.0 kann im ETL-Processor +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 +*currentPolicyStatesForPerson* (MTB-File v2) 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. + +#### 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. + +#### Konfiguration + +* `APP_CONSENT_SERVICE`: Folgende Werte sind möglich: + * Der Wert `GICS` aktiviert die Standard-Abfrage bei gICS + * Der Wert `GICS_GET_BC` aktiviert die **experimentelle** Abfrage per HTTP-GET Request **nur** für Broad-Consent. + * Der Wert `NONE` deaktiviert die Abfrage in gICS. +* `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_GENOMDECONSENTDOMAINNAME`: Domäne in der gIcs GenomDE Modelvorhaben §64e + Einwilligungen verwaltet. Falls Wert leer, wird keine Consent-Information abgerufen. +* `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_POLICYURI`: Die Version der Einwilligung. Falls leer wird Version 1.6d + (`urn:oid:2.16.840.1.113883.3.1937.777.24.2.1790`) angenommen. + +Die **experimentelle* Abfrage über `GICS_GET_BC` setzt voraus, dass bereits ein MV-Consent im eingehenden Datensatz +vorhanden ist und ergänzt nur den Broad-Consent. + +## Anmeldung und Authentifizierung + +### Anmeldung mit einem Passwort + +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. +* `APP_SECURITY_ADMIN_PASSWORD`: Das Passwort für den Administrator (Empfohlen). + +Ein Administrator-Passwort muss inklusive des Encoding-Präfixes vorliegen. + +Hier Beispiele für das Beispielpasswort `very-secret`: + +* `{noop}very-secret` (Das Passwort liegt im Klartext vor - nicht empfohlen!) +* `{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 angezeigt. + +#### Weitere Benutzer + +Ab Version 0.15.0 können weitere Benutzer-Accounts konfiguriert werden, ohne OpenID Connect zu verwenden. +Diese haben lediglich Benutzerrechte und können keine Konfigurationen einsehen oder ändern. + +Beispiele: + +``` +APP_SECURITY_USERS[0]_USERNAME=myuser +APP_SECURITY_USERS[0]_PASSWORD={noop}very-secret +APP_SECURITY_USERS[1]_USERNAME=otheruser +APP_SECURITY_USERS[1]_PASSWORD={bcrypt}$2y$05$CCkfsMr/wbTleMyjVIK8g.Aa3RCvrvoLXVAsL.f6KeouS88vXD9b6 +... +``` + +### Nutzung eines Authentifizierungsservers und OpenID Connect + +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. +* `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_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 + enthält. + Oft verwendet: `preferred_username` + +Ist die Nutzung von OpenID Connect konfiguriert, erscheint ein zusätzlicher Login-Button zur Nutzung +mit OpenID Connect +und dem konfigurierten `CLIENT_NAME`. + + + +Weitere Informationen zur Konfiguration des OIDC-Providers +sind [hier](https://docs.spring.io/spring-security/reference/servlet/oauth2/index.html#oauth2-client) +zu finden. + +#### Rollenbasierte Berechtigungen + +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. +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 +einzelne Benutzer als vollwertige Nutzer zuzulassen. + + + +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 +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. + +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 +zur Nutzung des MTB-File-Endpunkts eine HTTP-Basic-Authentifizierung voraussetzen. + + + +Hierzu kann der Endpunkt für das Onkostar-Plugin inklusive HTTP-Basic-Authentifizierung +konfiguriert werden. +Ist die Verwendung von Tokens aktiv, werden Anfragen ohne die Angabe der Token-Information abgelehnt. + +## Konfiguration der Datenein- und ausgabe + +### Dateneingang über HTTP/REST + +Anfragen werden, wenn nicht als Duplikat behandelt, nach der Pseudonymisierung und Consenteinbettung direkt an DNPM:DIP +gesendet. + +Ein HTTP-Request kann, angenommen die Installation erfolgte auf dem Host `dnpm.example.com` an +nachfolgende URLs gesendet werden: + +| HTTP-Request | URL | Bemerkung | +|--------------|-----------------------------------------|----------------------------------------------------------------| +| `POST` | `https://dnpm.example.com/mtb` | Die Anwendung verarbeitet den eingehenden Datensatz | +| `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. Siehe auch: https://github.com/pcvolkmer/mv64e-etl-processor/pull/196 + +### Dateneingang mit Apache Kafka + +Anfragen werden, wenn nicht als Duplikat behandelt, nach der Pseudonymisierung und Consenteinbettung 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/pcvolkmer/mv64e-rest-to-kafka-gateway +und https://github.com/pcvolkmer/mv64e-kafka-to-rest-gateway. + +### Mögliche REST-Endpunkte zur Datenausgabe + +Für REST-Requests als auch zur Nutzung von Kafka-Topics können Endpunkte konfiguriert werden. + +Es ist dabei nur die Konfiguration eines Endpunkts zulässig. +Werden sowohl REST als auch Kafka-Endpunkt konfiguriert, wird nur der REST-Endpunkt verwendet. + +#### REST + +Folgende Umgebungsvariablen müssen gesetzt sein, damit ein MTB-File an DNPM:DIP gesendet wird: + +* `APP_REST_URI`: URI der zu benutzenden API der Backend-Instanz. Zum Beispiel `http://localhost:9000/api` +* `APP_REST_TYPE`: Mögliche Werte `dip` (Standard) für DNPM:DIP und `nngm` für die nNGM-API. +* `APP_REST_USERNAME`: Basic-Auth-Benutzername für den REST-Endpunkt +* `APP_REST_PASSWORD`: Basic-Auth-Passwort für den REST-Endpunkt +* `APP_REST_API_KEY`: Angabe eines API-Keys zur Verwendung mit `APP_REST_TYPE=nngm` für die nNGM-API + +#### Routed REST + +Seit Version 0.18 ist eine Konfiguration des neu eingeführten **Routing**-Mechanismus möglich. +Damit kann für bestimmte Entitäten und Diagnosen ein abweichender REST-Endpunkt definiert werden. + +Beispiel: + +* `APP_ROUTING_NNGM_URI`: URI der nNGM-REST-API. +* `APP_ROUTING_NNGM_API_KEY`: API-Key zur Nutzung der nNGM-REST-API. +* `APP_ROUTING_NNGM_ICD10[0]`: Erster ICD-Code - weitere möglich. + +Mit dieser Konfiguration wird jeder `PatientRecord`, dessen (letzte) Diagnose einen ICD-10-Code hat, dessen Anfang +konfiguriert ist, nicht über den Standard-Weg versendet, sondern an den für nNGM konfigurierten API-Endpunkt. + +Wird zum Beispiel `APP_ROUTING_NNGM_ICD10[0] = C34` konfiguriert, werden Diagnosen wie "C34.0", "C34.1", etc. an das +nNGM +übermittelt. + +### Datenübermittlung mit Apache Kafka + +Folgende Umgebungsvariablen müssen gesetzt sein, damit ein 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_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`. + +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 +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. + +Soll eine SSL-gesicherte Verbindung zu Kafka verwendet werden, so sind die SSL-Zertifikate in +der Spring-Konfiguration anzugeben. +Ein Beispiel findet sich in [`application-dev.yml`](src/main/resources/application-dev.yml). +Dies kann auch mit Umgebungsvariablen wie `SPRING_KAFKA_SECURITY_...` und `SPRING_KAFKA_SSL_...` +umgesetzt werden. + +### Antworten und Statusauswertung + +Seit 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 | +|------------------|-----------| +| `info` | `SUCCESS` | +| `warning` | `WARNING` | +| `error`, `fatal` | `ERROR` | + +## Duplikaterkennung + +Die Erkennung von Duplikaten ist normalerweise immer aktiv, kann jedoch über den +Konfigurationsparameter +`APP_DUPLICATION_DETECTION=false` deaktiviert werden. + +## Blockieren weiterer initialer Submissions + +Diese Anwendung blockiert weitere initiale Submissions nach der ersten erfolgreichen Übertragung in DNPM:DIP. +Sobald für einen Patienten eine Übertragung ohne Issues oder mit maximal Warnungen erfolgte und damit von +DNPM:DIP akzeptiert wurde, werden weitere Meldungen solange verworfen, bis ein Administrator den Patienten +wieder freigegeben hat. + +`APP_POST_INITIAL_SUBMISSION_BLOCK` -> `true` | `false` (falls fehlt, wird `false` angenommen) + +Nach Aktivierung des Features wird es für ältere Meldungen erforderlich sein, bereits durchgeführte +Initialmeldungen als solche zu kennzeichnen. Dies **muss** manuell in der Datenbank gemacht werden, +da der Typ der Meldung nicht verfügbar ist. + +Gezielt Meldungen kennzeichnen: + +```sql +UPDATE request +SET submission_type = "INITIAL" +WHERE id IN (...); +``` + +Alle MTB-File Meldungen (ohne Lösch-Request) kennzeichnen, die erfolgreich an DNPM:DIP gesendet wurden: + +```sql +UPDATE request +SET submission_type = "INITIAL" +WHERE (status = "WARNING" OR status = "SUCCESS") + AND type = "MTB_FILE"; +``` + +## FollowUp-Erkennung + +Ab Version 0.16 werden Meldungen als Follow-Ups erkannt und entsprechend weiterleiten, wenn + +* die zu bearbeitende Meldung Follow-Ups enthält und das neueste Follow-Up nach der letzten Meldung für den Patienten datiert ist. +* zuvor eine initiale Meldung bereits erfolgte, die akzeptiert wurde. + +## Transformation von Werten + +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 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_TO`: Angabe des neuen Werts. + +## Deployment mit Docker-Compose + +Ausführen als Docker Container: + +```bash +docker compose up -d +``` + +### Einfaches Beispiel für ein eigenes Docker-Compose-File + +Die Datei [`docs/docker-compose.yml`](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. + +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): + +Das folgende Beispiel zeigt die Konfiguration in einer Docker-Compose-Datei mit Service-Labels. + +``` +... + deploy: + labels: + - "traefik.http.routers.etl.rule=PathPrefix(`/etl-processor`)" + - "traefik.http.routers.etl.middlewares=etl-path-strip" + - "traefik.http.middlewares.etl-path-strip.stripprefix.prefixes=/etl-processor" +... +``` + +#### Beispiel *nginx* + +Das folgende Beispiel zeigt die Konfiguration einer _location_ in einer nginx-Konfigurationsdatei. + +``` +... + location /etl-processor { + set $upstream http://<beispiel:8080>/; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-Scheme $scheme; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-For $remote_addr; + proxy_set_header X-Real-IP $remote_addr; + proxy_pass $upstream; + } +... +``` + +### Integration einer Root-CA zur Laufzeit + +Zur Integration einer Root-CA zur Laufzeit 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 und der +Datei [`bindings/ca-certificates/type`](bindings/ca-certificates/type) als Docker-Volume eingebunden werden. + +Beispiel für Docker-Compose: + +``` +... + environment: + SERVICE_BINDING_ROOT: /bindings + ... + volumes: + - "/path/to/bindings/ca-certificates/:/bindings/ca-certificates/:ro" +... +``` + +## Test der Betriebsbereitschaft +Um die volle 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-Submission-Kennung +übertragen, unabhängig vom ursprünglichen Wert. + +`APP_GENOM_DE_TEST_SUBMISSION` -> `true` | `false` (falls fehlt, wird `false` angenommen) + +**ACHTUNG**: Diese Einstellung funktioniert nur, wenn, wie in Marburg, eine vollständige Consent-Abfrage über gICS für +MV-Consent und Broad Consent erfolgt. + +Soll eine Testsubmission ohne diese Anbindung durchgeführt werden, kann eine Transformation als Work-Around umgesetzt werden: + +``` +APP_TRANSFORMATION_0_PATH: "metadata.type" +APP_TRANSFORMATION_0_FROM: "initial" +APP_TRANSFORMATION_0_TO: "test" +``` diff --git a/docs/development.md b/docs/development.md new file mode 100644 index 0000000..a55aead --- /dev/null +++ b/docs/development.md @@ -0,0 +1,52 @@ +# Entwicklungssetup + +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. + +Zum Bereitstellen von JavaScript- und CSS-Bundles muss der Befehl `npm run build` ausgeführt werden. +Ein kontinuierliches Neubauen bei Änderungen in CSS und JS-Dateien ist mit `npm run dev` möglich. +Dies setzt eine NodeJS-Umgebung voraus. + +Beim Start der Anwendung mit dem Profil `dev` wird die in `dev-compose.yml` definierte Umgebung beim +Start der Anwendung mit gestartet: + +```bash +SPRING_PROFILES_ACTIVE=dev ./gradlew bootRun +``` + +Die Datei `application-dev.yml` enthält hierzu die Konfiguration für das Profil `dev`. + +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. + +## Docker-Images lokal bauen + +Ein Docker-Image kann mit dem folgenden Befehl lokal gebaut werden: + +```bash +./gradlew bootBuildImage +``` + +### 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. + +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. + +Die PEM-Datei mit dem/den Root CA Zertifikat(en) muss dabei im vorbereiteten Verzeichnis [ +`bindings/ca-certificates`](bindings/ca-certificates) enthalten sein. |
