diff --git a/.idea/modules.xml b/.idea/modules.xml
index b507f1bc5017a57b35b8890a6981c5cec9e6709c..b8776654896d4d1276d75b8ea0891a1231fab966 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -2,7 +2,6 @@
 <project version="4">
   <component name="ProjectModuleManager">
     <modules>
-      <module fileurl="file://$PROJECT_DIR$/server/antragsraum-server.iml" filepath="$PROJECT_DIR$/server/antragsraum-server.iml" />
       <module fileurl="file://$PROJECT_DIR$/.idea/modules/ozg-antragsraum.iml" filepath="$PROJECT_DIR$/.idea/modules/ozg-antragsraum.iml" />
       <module fileurl="file://$PROJECT_DIR$/.idea/modules/ozg-antragsraum.integrationTest.iml" filepath="$PROJECT_DIR$/.idea/modules/ozg-antragsraum.integrationTest.iml" />
       <module fileurl="file://$PROJECT_DIR$/.idea/modules/ozg-antragsraum.main.iml" filepath="$PROJECT_DIR$/.idea/modules/ozg-antragsraum.main.iml" />
diff --git a/Jenkinsfile b/Jenkinsfile
index 060d133e47c8fb006123792c8ca17e21a31b9f28..7b07a4ece7b627d206b78c68df7ae99585a35968 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -43,6 +43,27 @@ pipeline {
                 }
             }
         }
+        stage('Set Version') {
+          when {
+            not {
+                anyOf {
+                    branch 'dev'
+                    branch 'release'
+                }
+            }
+          }
+          steps {
+                script {
+                    FAILED_STAGE=env.STAGE_NAME
+                    JAR_TAG = getPomVersion('pom.xml').replace("SNAPSHOT", "${env.BRANCH_NAME}-SNAPSHOT")
+                }
+                configFileProvider([configFile(fileId: 'maven-settings', variable: 'MAVEN_SETTINGS')]) {
+                    sh "mvn -s $MAVEN_SETTINGS versions:set -DnewVersion=${JAR_TAG} -DprocessAllModules=true"
+                    
+                }
+          }
+        }   
+
         
         stage('Build Antragsraum-Server') {
           steps {
@@ -54,7 +75,7 @@ pipeline {
                         if (env.BRANCH_NAME == 'dev') {
                             try {
                                 withSonarQubeEnv('sonarqube-ozg-sh'){
-                                    sh 'mvn -s $MAVEN_SETTINGS sonar:sonar'
+                                sh 'mvn -s $MAVEN_SETTINGS sonar:sonar'
                                 }
                             } catch (Exception e) {
                                 unstable("SonarQube failed")
@@ -65,20 +86,14 @@ pipeline {
             }
         }
         
-        stage('Deploy to Nexus'){
-             when {
-                anyOf {
-                    branch 'dev'
-                    branch 'release'
-                }
-            }
-           
+        stage('Deploy to Nexus'){ 
             steps {
                 script {
                     FAILED_STAGE = env.STAGE_NAME
                 }
                 configFileProvider([configFile(fileId: 'maven-settings', variable: 'MAVEN_SETTINGS')]) {
                     sh 'mvn --no-transfer-progress -s $MAVEN_SETTINGS -DskipTests deploy -Dmaven.wagon.http.retryHandler.count=3'
+                      sh "mvn -s $MAVEN_SETTINGS versions:revert"
                 }
             }
         }
diff --git a/README.md b/README.md
index 303dae2be6915f8fd208c87a394ec9fe57b523c9..c25f5c5fbc4ea741cf1356f110c30f3ccf342da2 100644
--- a/README.md
+++ b/README.md
@@ -200,3 +200,18 @@ Whe using the local Profile the redirect url in the antragsraum-client must be c
 
 * [BayernId Implementation and configuration](documentation/BayernIdLogin.md)
 
+### Test Tools
+
+#### mujina idp
+
+Mujina ist eine konfigurierbarer SAML2 IdentityProvider für Testzwecke.
+Es ist voll über ein REST Interface konfigurierbar under verwendet Spring-Boot.
+Encryption von Assertions wird **nicht** unterstützt.
+
+Um den Container zu bauen sind folgende Schritte notwendig:
+
+* das Repository https://github.com/OpenConext/Mujina clonen
+* mit Maven den Container im Verzeichnis mujina-idp bauen. ```mvn spring-boot:build-image -DskipTests```
+* Tagge das Image ```docker tag mujina-idp:8.0.11 docker.ozg-sh.de/mujina-idp:8.0.11```
+* Push das Image ```docker push docker.ozg-sh.de/mujina-idp:8.0.11```
+
diff --git a/documentation/KeycloakSetup.md b/documentation/KeycloakSetup.md
new file mode 100644
index 0000000000000000000000000000000000000000..ac24121969edf7c997a800ba86104ec4c405f4a6
--- /dev/null
+++ b/documentation/KeycloakSetup.md
@@ -0,0 +1,122 @@
+# Setup Keycloak as SAML IDP for Antragsraum
+
+## Voraussetzungen:
+
+Damit der Antragsraum Keycloak als SAML IDP verwenden kann, müssen ersteinmal die passenden Keys und Zertifikate
+erstellt werden.
+
+Dazu müssen Zertifikate mit privaten Keys erstellt werden:
+
+Beispiel:
+
+```
+openssl req -newkey rsa:2048 -nodes -keyout bayernid-kc-sign.key -x509 -days 365 -out bayernid-test-sign.crt
+```
+
+## Realm erstellen
+
+In Keycloak eine neuen Realm erstellen, der für den Antragsraum benutzt werden soll.
+
+Als "Realm name" wird z.B. "by-antragsraum-idp" verwendet.
+Der Real name ist dann auch id des realms.
+
+Nach Erstellung des Realms findet man unter
+"Realm setting" → "General" Tab den Punkt "Endpoints", dort ist der Link zu den Metadaten für den SAML Login.
+
+## Client erstellen
+
+"Clients" → "Clients list" Tab den Button "Create Client" drücken.
+
+Diese Werte eintragen:
+
+"Client type" ist "SAML"
+"Client ID" ist am besten die EntityID aus den Metadaten.
+"Name" ist z.B. "Antragsraum"
+"Description" ist z.B. "SAML Client für Antragsraum"
+
+## Client Einstellungen
+
+Unter "Clients" den erstellten Client auswählen
+und im Tab "Settings" folgendes Eintragen:
+
+| Feld                            | Werte                                                                                                 |
+| --------------------------------|-------------------------------------------------------------------------------------------------------|
+| Root URL                        | https://dev.antragsraum.de                                                                            |
+| Home URL                        | https://dev.antragsraum.de                                                                            |
+| Valid redirect URIs             | http://localhost:8080/login/saml2/sso/bayernid, https://dev.antragsraum.de/login/saml2/sso/bayernid   |
+| Valid post logout redirect URIs | http://localhost:8080/logout/saml2/sso/bayernid, https://dev.antragsraum.de/logout/saml2/sso/bayernid |
+
+Die anderen Einstellungen bleiben beim Default.
+
+## User erstellen
+
+Unter "Users" im Tab "User list" auf den Button "Add user" drücken und den User erstellen.
+Beispiel Werte sind:
+
+| Feld                  | Wert   |
+|-----------------------|--------|
+| Required user actions | leer   |
+| Username              | test   |
+| First name            | Test   |
+| Last name             | Level1 |
+
+Nachdem der User erstellt wurde den User anklicken und die Attribute eintrage:
+
+| Feld           | Wert                                 |
+|----------------|--------------------------------------|
+| trustlevel     | STORK-QAA-Level-1                    |
+| postkorbHandle | 28721c6f-b78f-4d5c-a048-19fd2fc429d2 |
+| vorname        | Test                                 |
+| nachname       | Level1                               |
+
+## Attribute mapping konfigurieren
+Das Mapping muss nur einmal konfiguriert werden und wird dann für alle User angewendet.
+
+Unter "Client scopes" "role_list" auswählen dann den Tab "Mappers" auswählen.
+
+Dort die Mappings der User Attributes zu SAML Attributes konfigurieren.
+
+Dazu "Add Mappers" -> "By Configuration" auswählen
+
+Postkorbhandle Mapper:
+
+| Feld                | Wert             |
+|---------------------|------------------|
+| Mapper type         | User Attribute   |
+| Name                | PostkorbHandle   |
+| User Attribute      | postkorbHandle   |
+| Friendly Name       | PostkorbHandle   |
+| SAML Attribute Name | urn:oid:2.5.4.18 |
+
+Trustlevel Mapper:
+
+| Feld                | Wert                             |
+|---------------------|----------------------------------|
+| Mapper type         | User Attribute                   |
+| Name                | TrustLevel                       |
+| User Attribute      | trustlevel                       |
+| Friendly Name       | TrustLevel                       |
+| SAML Attribute Name | urn:oid:1.2.40.0.10.2.1.1.261.94 |
+
+! Wichtig die 'User Attribute' Werte müssen zu den Namen der User Attribute passen.
+
+## Erstelle Keys importieren
+
+Das weiter oben erstelle Zertifikat muss noch in den Client importiert werden.
+
+Dazu unter "Clients" den SAML Client anwählen und dann den Tab "Keys" öffen.
+Dort bei "Certificate" den Button "Import Key" drücken.
+Als "Archive Format" "Certificate PEM" auswählen und dann mit "Browse" die erstellte crt Datei auswählen.
+Anschließend den "Import" Button drücken.
+
+
+### Users
+
+| login      | Password | Trustlevel        | Postfachhandle                       |
+|------------|----------|-------------------|--------------------------------------|
+| test       | test     | STORK-QAA-Level-1 | 28721c6f-b78f-4d5c-a048-19fd2fc429d2 |
+| testLevel1 | Y9nk43yrQ_zzIPpfFU-I | STORK-QAA-Level-1 | 28721c6f-b78f-4d5c-a048-19fd2fc429d2 |
+| testLevel2 | Y9nk43yrQ_zzIPpfFU-I | STORK-QAA-Level-2 | 28721c6f-b78f-4d5c-a048-19fd2fc429d2 |
+| testLevel3 | Y9nk43yrQ_zzIPpfFU-I | STORK-QAA-Level-3 | 28721c6f-b78f-4d5c-a048-19fd2fc429d2 |
+| testLevel4 | Y9nk43yrQ_zzIPpfFU-I | STORK-QAA-Level-4 | 28721c6f-b78f-4d5c-a048-19fd2fc429d2 |
+
diff --git a/pom.xml b/pom.xml
index e5c4ee653a9ae8dd6834438a69dee1f94fcba281..834e11e93118294c111aad7c78c823a415459b08 100644
--- a/pom.xml
+++ b/pom.xml
@@ -18,13 +18,12 @@
   ~ Die sprachspezifischen Genehmigungen und Beschränkungen
   ~ unter der Lizenz sind dem Lizenztext zu entnehmen.
   -->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
 
     <modelVersion>4.0.0</modelVersion>
     <groupId>de.ozgcloud</groupId>
     <artifactId>antragsraum</artifactId>
-    <version>1.0.0</version>
+    <version>1.1.0</version>
 
     <name>OZG-Cloud Antragsraum</name>
     <packaging>pom</packaging>
diff --git a/release-startdev.sh b/release-startdev.sh
index 6b79073651802cb6b2f06355bdfca08f511e2130..669d2f176d91597c41200f09e9a5b5ab5045246b 100755
--- a/release-startdev.sh
+++ b/release-startdev.sh
@@ -16,14 +16,7 @@ echo
 # projectname/pom.xml:parent,main -> project.parent.version und project.version setzen
 #
 PROJECTS="pom.xml:main 
-          vorgang-manager-server/pom.xml:main
-          vorgang-manager-interface/pom.xml:main
-          vorgang-manager-utils/pom.xml:main
-          nachrichten-manager/pom.xml:main
-          notification-manager/pom.xml:main
-          vorgang-manager-command/pom.xml:main
-          vorgang-manager-base/pom.xml:main
-          bescheid-manger/pom.xml:main
+          server/pom.xml:main
         "
 
 for PROJECT in $PROJECTS;
diff --git a/server/pom.xml b/server/pom.xml
index 4e4b88a62e65c26dfe112e85ed27819c4853ea94..c8c36ff18fedb7fe2796a48663ccee1c8c4abd42 100644
--- a/server/pom.xml
+++ b/server/pom.xml
@@ -18,9 +18,7 @@
   ~ Die sprachspezifischen Genehmigungen und Beschränkungen
   ~ unter der Lizenz sind dem Lizenztext zu entnehmen.
   -->
-<project xmlns="http://maven.apache.org/POM/4.0.0"
-         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
 
     <parent>
@@ -32,7 +30,7 @@
 
     <groupId>de.ozgcloud.antragsraum</groupId>
     <artifactId>antragsraum-server</artifactId>
-    <version>1.0.0</version>
+    <version>1.1.0</version>
 
     <name>OZG-Cloud Antragsraum Server</name>
     <description>Server Implementierung des Antragsraums</description>
@@ -44,7 +42,7 @@
         <spring-boot.build-image.imageName>docker.ozg-sh.de/antragsraum-server:build-latest</spring-boot.build-image.imageName>
 
         <ozgcloud.license.version>1.6.0</ozgcloud.license.version>
-        <ozgcloud-starter.version>0.9.0</ozgcloud-starter.version>
+        <ozgcloud-starter.version>0.10.0</ozgcloud-starter.version>
 
         <maven-deploy-plugin.version>3.0.0</maven-deploy-plugin.version>
         <find-and-replace-maven-plugin.version>1.1.0</find-and-replace-maven-plugin.version>
@@ -54,10 +52,10 @@
         <net-devh-grpc.version>2.15.0.RELEASE</net-devh-grpc.version>
         <grpc.version>1.57.2</grpc.version>
         <modulith.version>1.1.3</modulith.version>
-        <info-manager-interface.version>1.0.0</info-manager-interface.version>
+        <info-manager-interface.version>1.1.0</info-manager-interface.version>
         <jjwt.version>0.12.5</jjwt.version>
         <openapi.version>2.3.0</openapi.version>
-        <nachrichten-manager-interface.version>2.7.0</nachrichten-manager-interface.version>
+        <nachrichten-manager-interface.version>2.10.0</nachrichten-manager-interface.version>
     </properties>
 
     <repositories>
diff --git a/server/src/main/docker/docker-compose-full.yml b/server/src/main/docker/docker-compose-full.yml
index f63f97f4046b1f2485d344493a635ec335d15afd..235bb21a34d4c25aa13b1ef78ed2b9cc7a4cf79a 100644
--- a/server/src/main/docker/docker-compose-full.yml
+++ b/server/src/main/docker/docker-compose-full.yml
@@ -28,15 +28,18 @@ services:
     ports:
       - "3000:3000"
   ozg-info-manager:
-    image: docker.ozg-sh.de/info-manager:OZG-4804-0.1.0-SNAPSHOT
-    platform: linux/amd64
+    image: docker.ozg-sh.de/info-manager:snapshot-latest
     ports:
-      - "9091:9090"
+      - "9091:9091"
       - "8084:8081"
     environment:
       - SPRING_DATA_MONGODB_HOST=ozg-mongodb
-      - SPRING_PROFILES_ACTIVE=dev
-  elastic:
+      - SPRING_PROFILES_ACTIVE=local
+  ozg-saml-idp:
+    image: docker.ozg-sh.de/mujina-idp:8.0.11
+    ports:
+      - "8088:8080"
+  ozg-elastic:
     image: docker.elastic.co/elasticsearch/elasticsearch:8.3.2
     ports:
       - "9200:9200"
diff --git a/server/src/main/docker/docker-compose.yml b/server/src/main/docker/docker-compose.yml
index af01dcf3a7fe3db05d28826380b2d0de2064ffc3..7e19a7576c01755fe647899786bf98b31cfb02f6 100644
--- a/server/src/main/docker/docker-compose.yml
+++ b/server/src/main/docker/docker-compose.yml
@@ -27,11 +27,17 @@ services:
     ports:
       - "3000:3000"
   ozg-info-manager:
-    image: docker.ozg-sh.de/info-manager:OZG-4804-0.1.0-SNAPSHOT
+    image: docker.ozg-sh.de/info-manager:snapshot-latest
     platform: linux/amd64
     ports:
-      - "9091:9090"
+      - "9091:9091"
       - "8084:8081"
     environment:
       - SPRING_DATA_MONGODB_HOST=ozg-mongodb
-      - SPRING_PROFILES_ACTIVE=dev
\ No newline at end of file
+      - SPRING_PROFILES_ACTIVE=local
+  ozg-saml-idp:
+    image: docker.ozg-sh.de/mujina-idp:8.0.11
+    ports:
+      - "8088:8080"
+    environment:
+      - IDP_BASE_URL=http://localhost:8088
\ No newline at end of file
diff --git a/server/src/main/helm/templates/deployment.yaml b/server/src/main/helm/templates/deployment.yaml
index 3b6292db32e239982a17f3d5839971ff0f824335..663a26a750a7be77178fce669e610b7cf44ce72c 100644
--- a/server/src/main/helm/templates/deployment.yaml
+++ b/server/src/main/helm/templates/deployment.yaml
@@ -114,6 +114,9 @@ spec:
         - name: SPRING_SECURITY_SAML2_RELYINGPARTY_REGISTRATION_BAYERNID_ASSERTINGPARTY_METADATA-URI
           value: file:///metadata/bayernid-idp-infra.xml
 
+        - name: SPRING_SECURITY_SAML2_RELYINGPARTY_REGISTRATION_BAYERNID_ENTITY-ID
+          value: {{ required ".Values.antragsraum.saml.entityID must be set" .Values.antragsraum.saml.entityID }}
+
         - name: OZGCLOUD_JWT_SECRET
           valueFrom:
             secretKeyRef:
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/RootController.java b/server/src/main/java/de/ozgcloud/antragsraum/RootController.java
index 2a9400ec0daf1ac10d78871a65a71afb0af62d02..f928980db83c863c9cd6b99ad80dd44e5cb9aaac 100644
--- a/server/src/main/java/de/ozgcloud/antragsraum/RootController.java
+++ b/server/src/main/java/de/ozgcloud/antragsraum/RootController.java
@@ -20,14 +20,15 @@
 
 package de.ozgcloud.antragsraum;
 
-import lombok.RequiredArgsConstructor;
+import static java.util.Objects.*;
+
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.boot.info.BuildProperties;
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RestController;
 
-import static java.util.Objects.*;
+import lombok.RequiredArgsConstructor;
 
 @RestController(RootController.PATH)
 @RequiredArgsConstructor
@@ -40,12 +41,12 @@ public class RootController {
 	@GetMapping
 	public ResponseEntity<Root> getRoot() {
 		var root = new Root.RootBuilder()
-				.version(isNull(buildProperties) ? null : buildProperties.getVersion())
-				.buildTime(isNull(buildProperties) ? null : buildProperties.getTime())
-				.name(isNull(buildProperties) ? null : buildProperties.getName())
-				.javaVersion(System.getProperty("java.version"))
-				.isProduction(production)
-				.build();
+		  .version(isNull(buildProperties) ? null : buildProperties.getVersion())
+		  .buildTime(isNull(buildProperties) ? null : buildProperties.getTime())
+		  .name(isNull(buildProperties) ? null : buildProperties.getName())
+		  .javaVersion(System.getProperty("java.version"))
+		  .isProduction(production)
+		  .build();
 
 		return ResponseEntity.ok(root);
 	}
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/SecurityConfiguration.java b/server/src/main/java/de/ozgcloud/antragsraum/SecurityConfiguration.java
index 0d54cf4ac3f13e44bd6cc872d2942d791d16b1e2..4ae44bcadbb6fb8d3251d133a49422490cb3cd9f 100644
--- a/server/src/main/java/de/ozgcloud/antragsraum/SecurityConfiguration.java
+++ b/server/src/main/java/de/ozgcloud/antragsraum/SecurityConfiguration.java
@@ -20,24 +20,15 @@
 
 package de.ozgcloud.antragsraum;
 
-import java.util.UUID;
-
-import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
-import org.springframework.security.authentication.AuthenticationManager;
-import org.springframework.security.authentication.ProviderManager;
-import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
 import org.springframework.security.config.Customizer;
-import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
 import org.springframework.security.config.annotation.web.builders.HttpSecurity;
 import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
 import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
 import org.springframework.security.core.userdetails.UserDetailsService;
-import org.springframework.security.crypto.factory.PasswordEncoderFactories;
 import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;
 import org.springframework.security.saml2.provider.service.web.DefaultRelyingPartyRegistrationResolver;
-import org.springframework.security.saml2.provider.service.web.RelyingPartyRegistrationResolver;
 import org.springframework.security.saml2.provider.service.web.authentication.OpenSaml4AuthenticationRequestResolver;
 import org.springframework.security.saml2.provider.service.web.authentication.Saml2AuthenticationRequestResolver;
 import org.springframework.security.web.SecurityFilterChain;
@@ -46,17 +37,13 @@ import org.springframework.security.web.authentication.UsernamePasswordAuthentic
 import org.springframework.web.servlet.config.annotation.CorsRegistry;
 import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 
-import de.ozgcloud.antragsraum.mocks.MockLogoutSuccessHandler;
-import de.ozgcloud.antragsraum.mocks.MockSuccessHandler;
 import de.ozgcloud.antragsraum.security.AntragsraumLogoutSuccessHandler;
 import de.ozgcloud.antragsraum.security.AntragsraumProperties;
 import de.ozgcloud.antragsraum.security.BayernIdProperties;
 import de.ozgcloud.antragsraum.security.BayernIdSaml2Extension;
-import de.ozgcloud.antragsraum.security.InMemoryUserDetailService;
 import de.ozgcloud.antragsraum.security.JwtTokenFilter;
 import de.ozgcloud.antragsraum.security.SamlUrlAuthenticationSuccessHandler;
 import de.ozgcloud.antragsraum.security.SecurityProvider;
-import de.ozgcloud.antragsraum.security.User;
 import lombok.NonNull;
 import lombok.RequiredArgsConstructor;
 import net.devh.boot.grpc.server.security.authentication.BasicGrpcAuthenticationReader;
@@ -66,8 +53,9 @@ import net.devh.boot.grpc.server.security.authentication.GrpcAuthenticationReade
 @EnableWebSecurity
 @RequiredArgsConstructor
 public class SecurityConfiguration {
-	public static final String OPTIONS = "OPTIONS";
-	public static final String GET = "GET";
+	private static final String OPTIONS = "OPTIONS";
+	private static final String GET = "GET";
+
 	@NonNull
 	private final BayernIdSaml2Extension bayernIdSaml2Extension;
 	@NonNull
@@ -78,10 +66,6 @@ public class SecurityConfiguration {
 	private final JwtTokenFilter tokenAuthenticationFilter;
 	@NonNull
 	private final AntragsraumProperties properties;
-	@Value("${ozgcloud.mock.auth:false}")
-	private boolean mockAuth;
-	@Value("${ozgcloud.mock.password:}")
-	private String password;
 
 	@Bean
 	public SecurityProvider securityProvider() {
@@ -90,59 +74,30 @@ public class SecurityConfiguration {
 
 	@Bean
 	Saml2AuthenticationRequestResolver authenticationRequestResolver(RelyingPartyRegistrationRepository registrations) {
-		RelyingPartyRegistrationResolver registrationResolver =
-		  new DefaultRelyingPartyRegistrationResolver(registrations);
-		OpenSaml4AuthenticationRequestResolver authenticationRequestResolver =
-		  new OpenSaml4AuthenticationRequestResolver(registrationResolver);
+		var registrationResolver = new DefaultRelyingPartyRegistrationResolver(registrations);
+		var authenticationRequestResolver = new OpenSaml4AuthenticationRequestResolver(registrationResolver);
 		authenticationRequestResolver.setAuthnRequestCustomizer(context -> {
 			context.getAuthnRequest().setForceAuthn(true);
 			context.getAuthnRequest().setExtensions(bayernIdSaml2Extension.createAkdbExtension());
 		});
-		return authenticationRequestResolver;
-	}
-
-	@Bean
-	public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration)
-	  throws Exception {
-		if (mockAuth) {
-			DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
-			authenticationProvider.setUserDetailsService(userDetailsService);
-			authenticationProvider.setPasswordEncoder(PasswordEncoderFactories.createDelegatingPasswordEncoder());
-
-			ProviderManager providerManager = new ProviderManager(authenticationProvider);
-			providerManager.setEraseCredentialsAfterAuthentication(false);
-
-			return providerManager;
-		}
 
-		return authenticationConfiguration.getAuthenticationManager();
+		return authenticationRequestResolver;
 	}
 
 	@Bean
 	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
 		http
 		  .authorizeHttpRequests(authorize -> authorize
-			.requestMatchers("/", "/actuator/**", "/swagger-ui/**", "/v3/api-docs/**", "/error", "/favicon.ico",
-			  "/auth/**", "/login", "/api/e2e/**").permitAll()
+			.requestMatchers("/", "/actuator/**", "/swagger-ui/**", "/v3/api-docs/**", "/error", "/favicon.ico", "/auth/**", "/login", "/api/e2e/**")
+			.permitAll()
 			.requestMatchers("/api/**").authenticated()
 			.anyRequest().denyAll())
 		  .addFilterBefore(tokenAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
 		  .csrf(AbstractHttpConfigurer::disable);
 
-		if (mockAuth) {
-			var pwEnc = PasswordEncoderFactories.createDelegatingPasswordEncoder();
-			var user = User.builder().id(UUID.randomUUID().toString()).username("test").password(pwEnc.encode(password)).build();
-			((InMemoryUserDetailService) userDetailsService).addUser(UUID.randomUUID().toString(), user);
-			http.httpBasic(Customizer.withDefaults())
-			  .formLogin(formLoginConfigurer -> formLoginConfigurer.successHandler(
-				new MockSuccessHandler(userDetailsService)))
-			  .logout(logoutConfigurer -> logoutConfigurer.logoutSuccessHandler(new MockLogoutSuccessHandler()));
-		} else {
-			http.saml2Login(
-				saml2LoginConfigurer -> saml2LoginConfigurer.successHandler(getSamlUrlAuthenticationSuccessHandler()))
-			  .saml2Logout(Customizer.withDefaults())
-			  .logout(logoutConfigurer -> logoutConfigurer.logoutSuccessHandler(logoutSuccessHandler()));
-		}
+		http.saml2Login(samlLogin -> samlLogin.successHandler(getSamlUrlAuthenticationSuccessHandler()))
+		  .saml2Logout(Customizer.withDefaults())
+		  .logout(logoutConfigurer -> logoutConfigurer.logoutSuccessHandler(getLogoutSuccessHandler()));
 
 		return http.build();
 	}
@@ -151,9 +106,10 @@ public class SecurityConfiguration {
 		return new SamlUrlAuthenticationSuccessHandler(bayernIdProperties.getRedirectUrl(), userDetailsService);
 	}
 
-	AntragsraumLogoutSuccessHandler logoutSuccessHandler() {
+	AntragsraumLogoutSuccessHandler getLogoutSuccessHandler() {
 		var handler = new AntragsraumLogoutSuccessHandler(userDetailsService);
 		handler.setDefaultTargetUrl(properties.getLogoutSuccessUrl());
+
 		return handler;
 	}
 
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/attachments/FileController.java b/server/src/main/java/de/ozgcloud/antragsraum/attachments/FileController.java
index 5b94af24d973d797bb2d817da24b4c1be4eaaa7b..c14ea8c5831388a6db1b39944e9cc124633f1929 100644
--- a/server/src/main/java/de/ozgcloud/antragsraum/attachments/FileController.java
+++ b/server/src/main/java/de/ozgcloud/antragsraum/attachments/FileController.java
@@ -21,8 +21,6 @@
 package de.ozgcloud.antragsraum.attachments;
 
 import java.net.URI;
-import java.nio.charset.StandardCharsets;
-import java.util.Base64;
 import java.util.concurrent.CompletableFuture;
 
 import org.springframework.http.HttpHeaders;
@@ -64,25 +62,21 @@ public class FileController {
 	private final @NonNull FileValidator fileValidator;
 
 	@Operation(summary = "Download file content")
-	@GetMapping(value = "{address}/{fileId}", produces = { MediaType.APPLICATION_OCTET_STREAM_VALUE,
-	  "images/*" })
+	@GetMapping(value = "{nachrichtEventId}/{fileId}", produces = { MediaType.APPLICATION_OCTET_STREAM_VALUE, "images/*" })
 	public ResponseEntity<StreamingResponseBody> getFileData(
-	  @Parameter(description = "The url encoded address of the OZG-Cloud instance", example = "6358fd4146811d04010f44d0")
-	  @PathVariable String address,
-	  @Parameter(description = "The id of the file", example = "6358fd0bee7a051389cdd788") @PathVariable
-	  String fileId) {
-		var decodedAddress = getDecodedAddress(address);
-		var ozgFile = getFile(fileId, decodedAddress);
+	  @Parameter(description = "The id of the NachrichtEvent in the InfoManager the file belongs to", example = "60af924b4f1a2560298b4567")
+	  @PathVariable String nachrichtEventId,
+	  @Parameter(description = "The id of the file", example = "6358fd0bee7a051389cdd788") @PathVariable String fileId) {
+		var ozgFile = getFile(fileId, nachrichtEventId);
 
-		return buildResponseEntity(ozgFile, createDownloadStreamingBody(fileId, decodedAddress));
+		return buildResponseEntity(ozgFile, createDownloadStreamingBody(fileId, nachrichtEventId));
 	}
 
-	OzgFile getFile(String fileId, String address) {
-		return fileService.getFile(fileId, address);
+	OzgFile getFile(String fileId, String nachrichtEventId) {
+		return fileService.getFile(fileId, nachrichtEventId);
 	}
 
-	private ResponseEntity<StreamingResponseBody> buildResponseEntity(OzgFile ozgFile,
-	  StreamingResponseBody responseBody) {
+	private ResponseEntity<StreamingResponseBody> buildResponseEntity(OzgFile ozgFile, StreamingResponseBody responseBody) {
 		if (ozgFile != null) {
 			return ResponseEntity.ok()
 			  .header(HttpHeaders.CONTENT_DISPOSITION, String.format("attachment; filename=%s", ozgFile.fileName()))
@@ -94,40 +88,34 @@ public class FileController {
 		}
 	}
 
-	private StreamingResponseBody createDownloadStreamingBody(String fileId, String address) {
-		return out -> fileService.downloadFileContent(fileId, out, address);
+	private StreamingResponseBody createDownloadStreamingBody(String fileId, String nachrichtEventId) {
+		return out -> fileService.downloadFileContent(fileId, out, nachrichtEventId);
 	}
 
 	@Operation(summary = "Upload file content",
-	  description = "You can use cURL to upload a file example: curl -F file=@TestDokument.pdf http://localhost:8080/api/file/[vorgangid]/[address] -v")
+	  description = "You can use cURL to upload a file example: curl -F file=@TestDokument.pdf http://localhost:8080/api/file/[vorgangid]/[nachrichtEventId] -v")
 	@ApiResponses(value = {
 	  @ApiResponse(responseCode = "201", description = "The file has been created",
 		content = @Content(examples = @ExampleObject(value = "6358fd0bee7a051389cdd788", description = "The id of the file created")),
 		headers = { @Header(name = "Location", description = "The path of of the uploaded file with its id") })
 	})
-	@PostMapping(value = "{vorgangId}/{address}", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
+	@PostMapping(value = "{vorgangId}/{nachrichtEventId}", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
 	@Async
 	public CompletableFuture<ResponseEntity<String>> uploadFile(
 	  @Parameter(description = "The id of the Vorgang the clerk message belongs to", example = "6358fd0bee7a051389cdd787")
 	  @PathVariable @NonNull String vorgangId,
-	  @Parameter(description = "The address og the ozg-cloud instance the message come from in urlencoded form", example = "static://localhost:9091")
-	  @PathVariable @NonNull String address,
+	  @Parameter(description = "The id of the NachrichtEvent in the InfoManager the file belongs to", example = "60af924b4f1a2560298b4567")
+	  @PathVariable @NonNull String nachrichtEventId,
 	  @RequestBody MultipartFile file) {
-		var decodedAddress = getDecodedAddress(address);
-		LOG.info("Uploading attachment for vorgang {} to address {}", vorgangId, decodedAddress);
+		LOG.info("Uploading attachment for vorgang {} for nachricht event id {}", vorgangId, nachrichtEventId);
+
 		if (fileValidator.isValid(file)) {
-			var fileIdFuture = fileService.upload(vorgangId, decodedAddress, file);
+			var fileIdFuture = fileService.upload(vorgangId, nachrichtEventId, file);
 
-			return fileIdFuture.thenApply(
-			  fileId -> ResponseEntity.created(URI.create(PATH_PATTERN.formatted(vorgangId, fileId))).body(fileId));
+			return fileIdFuture.thenApply(fileId -> ResponseEntity.created(URI.create(PATH_PATTERN.formatted(vorgangId, fileId))).body(fileId));
 		} else {
 			LOG.warn("Uploaded File {} is not valid.", file.getName());
 			throw new InvalidFileTypeException(file.getName());
 		}
 	}
-
-	@NonNull
-	private static String getDecodedAddress(String address) {
-		return new String(Base64.getDecoder().decode(address.getBytes(StandardCharsets.UTF_8)));
-	}
 }
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/attachments/FileRemoteService.java b/server/src/main/java/de/ozgcloud/antragsraum/attachments/FileRemoteService.java
index e391acd4e6b5669b1da6f6e4e56aa6613dea0857..cb2d5b0a17d2d366c29f466bec5777262b170e9e 100644
--- a/server/src/main/java/de/ozgcloud/antragsraum/attachments/FileRemoteService.java
+++ b/server/src/main/java/de/ozgcloud/antragsraum/attachments/FileRemoteService.java
@@ -33,10 +33,10 @@ import lombok.extern.log4j.Log4j2;
 @Log4j2
 @Service
 @RequiredArgsConstructor
-public class FileRemoteService {
+class FileRemoteService {
 	private final @NonNull FileGrpcClient grpcClient;
 
-	public OzgFile getFile(String fileId, String address) {
+	OzgFile getFile(String fileId, String address) {
 		var grpcFileMetadata = grpcClient.findBinaryFilesMetaData(buildGrpcBinaryFileRequest(fileId), address);
 
 		if (!grpcFileMetadata.getFileList().isEmpty()) {
@@ -62,7 +62,7 @@ public class FileRemoteService {
 		return fileIdFuture;
 	}
 
-	public void downloadFileContent(String fileId, OutputStream out, String address) {
+	void downloadFileContent(String fileId, OutputStream out, String address) {
 		grpcClient.downloadFileContent(fileId, out, address);
 	}
 }
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/attachments/FileService.java b/server/src/main/java/de/ozgcloud/antragsraum/attachments/FileService.java
index 1e4b8ec7db0b690602372f3bebf4a10a5824a1f9..56b6e2d270cee833ebee006176f11f9c09b3a456 100644
--- a/server/src/main/java/de/ozgcloud/antragsraum/attachments/FileService.java
+++ b/server/src/main/java/de/ozgcloud/antragsraum/attachments/FileService.java
@@ -30,6 +30,7 @@ import org.springframework.web.multipart.MultipartFile;
 
 import de.ozgcloud.antragsraum.common.TechnicalException;
 import de.ozgcloud.antragsraum.common.VirusFoundException;
+import de.ozgcloud.antragsraum.events.NachrichtEventService;
 import de.ozgcloud.apilib.file.OzgCloudUploadFile;
 import lombok.NonNull;
 import lombok.RequiredArgsConstructor;
@@ -38,25 +39,33 @@ import lombok.extern.log4j.Log4j2;
 @Log4j2
 @Service
 @RequiredArgsConstructor
-class FileService {
+public class FileService {
 	private final @NonNull FileRemoteService fileRemoteService;
 	private final @NonNull VirusScannerClient scanner;
+	private final @NonNull NachrichtEventService nachrichtEventService;
 
-	OzgFile getFile(String fileId, String address) {
-		return fileRemoteService.getFile(fileId, address);
+	public OzgFile getFile(String fileId, String nachrichtEventId) {
+		var nachrichtEvent = nachrichtEventService.getNachrichtEventById(nachrichtEventId);
+
+		return fileRemoteService.getFile(fileId, nachrichtEvent.address());
 	}
 
-	void downloadFileContent(String fileId, OutputStream out, String address) {
-		fileRemoteService.downloadFileContent(fileId, out, address);
+	void downloadFileContent(String fileId, OutputStream out, String nachrichtEventId) {
+		var nachrichtEvent = nachrichtEventService.getNachrichtEventById(nachrichtEventId);
+
+		fileRemoteService.downloadFileContent(fileId, out, nachrichtEvent.address());
 	}
 
-	CompletableFuture<String> upload(String vorgangId, String address, MultipartFile file) {
-		return fileRemoteService.uploadFile(createUploadFile(vorgangId, file), address);
+	CompletableFuture<String> upload(String vorgangId, String nachrichtEventId, MultipartFile file) {
+		var nachrichtEvent = nachrichtEventService.getNachrichtEventById(nachrichtEventId);
+
+		return fileRemoteService.uploadFile(createUploadFile(vorgangId, file), nachrichtEvent.address());
 	}
 
 	OzgUploadFile createUploadFile(String vorgangId, MultipartFile file) throws VirusFoundException {
 		if (isClean(file)) {
 			LOG.info("File {} is clean, preparing upload", file.getOriginalFilename());
+
 			return OzgUploadFile.builder()
 			  .fileData(OzgCloudUploadFile.builder()
 				.fileName(file.getOriginalFilename())
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/attachments/OzgFile.java b/server/src/main/java/de/ozgcloud/antragsraum/attachments/OzgFile.java
index 681a8fcb23cac54b33e88d55ad49c21aa3dffcf1..8d8a5c657aeb1174dbc5cf4073442b5277475312 100644
--- a/server/src/main/java/de/ozgcloud/antragsraum/attachments/OzgFile.java
+++ b/server/src/main/java/de/ozgcloud/antragsraum/attachments/OzgFile.java
@@ -27,28 +27,28 @@ import lombok.Builder;
 
 @Builder(toBuilder = true)
 public record OzgFile(
-        @Schema(description = "The id of the file, will be created by the OZG-Backend",
-                name = "id",
-                type = "string",
-                example = "65248ad3f46811d04010f44bb"
-        )
-        String id,
-        @Schema(description = "The name of the file. Optional when sending the reply",
-                name = "fileName",
-                type = "string",
-                example = "TestDok.txt"
-        )
-        String fileName,
-        @Schema(description = "The size if the file in bytes. Optional when sending the reply",
-                name = "fileSize",
-                type = "long",
-                example = "236478552"
-        )
-        long fileSize,
-        @Schema(description = "The content type of the file. Optional when sending the reply",
-                name = "contentType",
-                type = "string",
-                example = "text/plain"
-        )
-        String contentType) {
+  @Schema(description = "The id of the file, will be created by the OZG-Backend",
+	name = "id",
+	type = "string",
+	example = "65248ad3f46811d04010f44bb"
+  )
+  String id,
+  @Schema(description = "The name of the file. Optional when sending the reply",
+	name = "fileName",
+	type = "string",
+	example = "TestDok.txt"
+  )
+  String fileName,
+  @Schema(description = "The size if the file in bytes. Optional when sending the reply",
+	name = "fileSize",
+	type = "long",
+	example = "236478552"
+  )
+  long fileSize,
+  @Schema(description = "The content type of the file. Optional when sending the reply",
+	name = "contentType",
+	type = "string",
+	example = "text/plain"
+  )
+  String contentType) {
 }
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/attachments/OzgFileMapper.java b/server/src/main/java/de/ozgcloud/antragsraum/attachments/OzgFileMapper.java
index a0f3459a0f0c3121abad5270b3ddf5dbbb35b054..8ff6526dacc8a1f43b27d6fef0b240759766305c 100644
--- a/server/src/main/java/de/ozgcloud/antragsraum/attachments/OzgFileMapper.java
+++ b/server/src/main/java/de/ozgcloud/antragsraum/attachments/OzgFileMapper.java
@@ -27,12 +27,12 @@ import lombok.NoArgsConstructor;
 @NoArgsConstructor(access = AccessLevel.PRIVATE)
 class OzgFileMapper {
 
-    static OzgFile fromGrpcFile(GrpcOzgFile grpcFile) {
-        return OzgFile.builder()
-            .id(grpcFile.getId())
-            .fileName(grpcFile.getName())
-            .contentType(grpcFile.getContentType())
-            .fileSize(grpcFile.getSize())
-            .build();
-    }
+	static OzgFile fromGrpcFile(GrpcOzgFile grpcFile) {
+		return OzgFile.builder()
+		  .id(grpcFile.getId())
+		  .fileName(grpcFile.getName())
+		  .contentType(grpcFile.getContentType())
+		  .fileSize(grpcFile.getSize())
+		  .build();
+	}
 }
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/attachments/OzgUploadFile.java b/server/src/main/java/de/ozgcloud/antragsraum/attachments/OzgUploadFile.java
index 57378090932801029828b151f809419a00f06aaf..67060e8ca477c699f35f85f33f20039b8536e34b 100644
--- a/server/src/main/java/de/ozgcloud/antragsraum/attachments/OzgUploadFile.java
+++ b/server/src/main/java/de/ozgcloud/antragsraum/attachments/OzgUploadFile.java
@@ -20,11 +20,13 @@
 
 package de.ozgcloud.antragsraum.attachments;
 
-import de.ozgcloud.apilib.file.OzgCloudUploadFile;
 import java.io.InputStream;
-import lombok.Builder;
+
 import org.springframework.validation.annotation.Validated;
 
+import de.ozgcloud.apilib.file.OzgCloudUploadFile;
+import lombok.Builder;
+
 @Validated
 @Builder
 public record OzgUploadFile(OzgCloudUploadFile fileData, InputStream fileContent) {
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/attachments/VirusScannerClient.java b/server/src/main/java/de/ozgcloud/antragsraum/attachments/VirusScannerClient.java
index c4f75c63026ad22db2a42f80f3efbc1541834d8b..5f569fe6bd618a2a332f1c80b3e63a19621e6adc 100755
--- a/server/src/main/java/de/ozgcloud/antragsraum/attachments/VirusScannerClient.java
+++ b/server/src/main/java/de/ozgcloud/antragsraum/attachments/VirusScannerClient.java
@@ -54,7 +54,6 @@ public class VirusScannerClient {
 	private final RestTemplate restTemplate;
 
 	public Set<String> scan(MultipartFile file) {
-
 		Set<String> viruses = new HashSet<>();
 
 		if (Objects.nonNull(file)) {
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/callcontext/ContextService.java b/server/src/main/java/de/ozgcloud/antragsraum/callcontext/ContextService.java
index aee0430ec0d8f5d1bed7f86b77c1fcebf214a161..df691195d814be78ef96413912230866c914bc0f 100644
--- a/server/src/main/java/de/ozgcloud/antragsraum/callcontext/ContextService.java
+++ b/server/src/main/java/de/ozgcloud/antragsraum/callcontext/ContextService.java
@@ -20,6 +20,12 @@
 
 package de.ozgcloud.antragsraum.callcontext;
 
+import java.nio.charset.Charset;
+import java.util.Objects;
+
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.stereotype.Service;
+
 import de.ozgcloud.antragsraum.common.AuthenticationHelper;
 import de.ozgcloud.antragsraum.security.User;
 import de.ozgcloud.vorgang.grpc.command.GrpcCallContext;
@@ -27,71 +33,68 @@ import io.grpc.Metadata;
 import lombok.NonNull;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.log4j.Log4j2;
-import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
-import org.springframework.stereotype.Service;
-
-import java.nio.charset.Charset;
-import java.util.Objects;
 
 @Log4j2
 @Service
 @RequiredArgsConstructor
 public class ContextService {
-    public static final String CLIENT_NAME = "Antragsraum";
-    public static final String KEY_CLIENT_NAME = "CLIENT_NAME-bin";
-    public static final String KEY_REQUEST_ID = "REQUEST_ID-bin";
-    public static final String KEY_JWT_TOKEN = "JWT_TOKEN-bin";
-    public static final String NO_SAML_TOKEN = "--not set--";
-
-    private final @NonNull AuthenticationHelper authenticationHelper;
-    RequestAttributes requestAttributes;
-
-    public GrpcCallContext createCallContext() {
-        return GrpcCallContext.newBuilder()
-                .setClient(CLIENT_NAME)
-                .setRequestId(getRequestId())
-                .build();
-    }
-
-    public Metadata buildCallContextMetadata() {
-        var metadata = new Metadata();
-
-        metadata.put(createKeyOf(KEY_CLIENT_NAME), getClientName().getBytes(Charset.defaultCharset()));
-        metadata.put(createKeyOf(KEY_REQUEST_ID), getRequestId().getBytes(Charset.defaultCharset()));
-        metadata.put(createKeyOf(KEY_JWT_TOKEN), getJwtToken().getBytes(Charset.defaultCharset()));
-
-        return metadata;
-    }
-
-    public static Metadata.Key<byte[]> createKeyOf(String key) {
-        return Metadata.Key.of(key, Metadata.BINARY_BYTE_MARSHALLER);
-    }
-
-    String getClientName() {
-        return CLIENT_NAME;
-    }
-
-    public String getSamlResponse() {
-        String tokenValue = NO_SAML_TOKEN;
-        var auth = authenticationHelper.getAuthentication();
-
-        if (auth instanceof UsernamePasswordAuthenticationToken userToken && userToken.getPrincipal() instanceof User user) {
-            tokenValue = user.getSamlToken();
-        }
-
-        return tokenValue;
-    }
-
-    String getRequestId() {
-        return Objects.isNull(requestAttributes) ? "- no request scope -" : requestAttributes.getRequestId();
-    }
-
-    String getJwtToken() {
-        var auth = authenticationHelper.getAuthentication();
-        if (auth instanceof UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken) {
-            return (String) usernamePasswordAuthenticationToken.getCredentials();
-        }
-
-        return "";
-    }
+	public static final String CLIENT_NAME = "Antragsraum";
+	public static final String KEY_CLIENT_NAME = "CLIENT_NAME-bin";
+	public static final String KEY_REQUEST_ID = "REQUEST_ID-bin";
+	public static final String KEY_JWT_TOKEN = "JWT_TOKEN-bin";
+	public static final String NO_SAML_TOKEN = "--not set--";
+
+	private final @NonNull AuthenticationHelper authenticationHelper;
+	RequestAttributes requestAttributes;
+
+	public GrpcCallContext createCallContext() {
+		return GrpcCallContext.newBuilder()
+		  .setClient(CLIENT_NAME)
+		  .setRequestId(getRequestId())
+		  .build();
+	}
+
+	public Metadata buildCallContextMetadata() {
+		var metadata = new Metadata();
+
+		metadata.put(createKeyOf(KEY_CLIENT_NAME), getClientName().getBytes(Charset.defaultCharset()));
+		metadata.put(createKeyOf(KEY_REQUEST_ID), getRequestId().getBytes(Charset.defaultCharset()));
+		metadata.put(createKeyOf(KEY_JWT_TOKEN), getJwtToken().getBytes(Charset.defaultCharset()));
+
+		return metadata;
+	}
+
+	public static Metadata.Key<byte[]> createKeyOf(String key) {
+		return Metadata.Key.of(key, Metadata.BINARY_BYTE_MARSHALLER);
+	}
+
+	String getClientName() {
+		return CLIENT_NAME;
+	}
+
+	public String getSamlResponse() {
+		String tokenValue = NO_SAML_TOKEN;
+		var auth = authenticationHelper.getAuthentication();
+
+		if (auth instanceof UsernamePasswordAuthenticationToken userToken && userToken.getPrincipal() instanceof User user) {
+			tokenValue = user.getSamlToken();
+		}
+
+		LOG.debug("Returning SAML Token:[{}]", tokenValue);
+
+		return tokenValue;
+	}
+
+	String getRequestId() {
+		return Objects.isNull(requestAttributes) ? "- no request scope -" : requestAttributes.getRequestId();
+	}
+
+	String getJwtToken() {
+		var auth = authenticationHelper.getAuthentication();
+		if (auth instanceof UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken) {
+			return (String) usernamePasswordAuthenticationToken.getCredentials();
+		}
+
+		return "";
+	}
 }
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/command/Command.java b/server/src/main/java/de/ozgcloud/antragsraum/command/Command.java
new file mode 100644
index 0000000000000000000000000000000000000000..aa5345399859e458d9962ab7269292fcb46be814
--- /dev/null
+++ b/server/src/main/java/de/ozgcloud/antragsraum/command/Command.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2023-2024.
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+
+package de.ozgcloud.antragsraum.command;
+
+import jakarta.validation.constraints.Min;
+import jakarta.validation.constraints.NotBlank;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Builder;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@Builder()
+record Command(
+  @Schema(description = "The id of the command", name = "id", type = "string", example = "1258ad3f46811d04010f22ab")
+  @NotBlank
+  String id,
+  @Schema(description = "The id of the NachrichtEvent in the InfoManager the command belongs to",
+	name = "nachrichtEventId",
+	type = "string",
+	example = "60af924b4f1a2560298b4567"
+  )
+  String nachrichtEventId,
+  @Schema(description = "The status of the command", name = "status", type = "String", example = "PENDING")
+  String status,
+  @Schema(description = "The date on which the command was created.")
+  @Min(0)
+  long createdAt,
+  @Schema(description = "The date on which the command was completed.")
+  Long finishedAt) {
+}
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/command/CommandController.java b/server/src/main/java/de/ozgcloud/antragsraum/command/CommandController.java
new file mode 100644
index 0000000000000000000000000000000000000000..2adbd45a0cea1d1e38bc64e1af0733364cfdb054
--- /dev/null
+++ b/server/src/main/java/de/ozgcloud/antragsraum/command/CommandController.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2023-2024.
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+
+package de.ozgcloud.antragsraum.command;
+
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.security.SecurityRequirement;
+import lombok.NonNull;
+import lombok.RequiredArgsConstructor;
+
+@RestController
+@RequestMapping(CommandController.PATH)
+@RequiredArgsConstructor
+@SecurityRequirement(name = "security_auth")
+public class CommandController {
+	public static final String PATH = "/api";
+
+	private final @NonNull CommandService service;
+
+	@Operation(summary = "Get the matching command to a command reference")
+	@GetMapping(value = "/command/{commandId}/{nachrichtEventId}", produces = MediaType.APPLICATION_JSON_VALUE)
+	public Command getCommand(
+	  @Parameter(description = "The id of the command", example = "1258ad3f46811d04010f22ab") @PathVariable String commandId,
+	  @Parameter(description = "The id of the NachrichtEvent the command belongs to", example = "60af924b4f1a2560298b4567") @PathVariable String nachrichtEventId) {
+		return service.getCommand(commandId, nachrichtEventId);
+	}
+}
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/command/CommandGrpcClient.java b/server/src/main/java/de/ozgcloud/antragsraum/command/CommandGrpcClient.java
new file mode 100644
index 0000000000000000000000000000000000000000..49dfae9f2af870a265662ece3cb8ea9a8fb85f1b
--- /dev/null
+++ b/server/src/main/java/de/ozgcloud/antragsraum/command/CommandGrpcClient.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2023-2024.
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+
+package de.ozgcloud.antragsraum.command;
+
+import org.springframework.stereotype.Component;
+
+import de.ozgcloud.antragsraum.common.ChannelPropertiesFactory;
+import de.ozgcloud.vorgang.grpc.command.CommandServiceGrpc;
+import de.ozgcloud.vorgang.grpc.command.GrpcCommand;
+import de.ozgcloud.vorgang.grpc.command.GrpcGetCommandRequest;
+import lombok.NonNull;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.log4j.Log4j2;
+import net.devh.boot.grpc.client.channelfactory.GrpcChannelFactory;
+import net.devh.boot.grpc.client.interceptor.GlobalClientInterceptorRegistry;
+
+@Log4j2
+@Component
+@RequiredArgsConstructor
+public class CommandGrpcClient {
+	private final @NonNull GlobalClientInterceptorRegistry registry;
+	private final @NonNull ChannelPropertiesFactory channelPropertiesFactory;
+
+	public GrpcCommand getCommand(GrpcGetCommandRequest request, String address) {
+		try (GrpcChannelFactory channelFactory = getChannelFactory(address)) {
+			var channel = channelFactory.createChannel(address);
+			var commandServiceBlockingStub = CommandServiceGrpc.newBlockingStub(channel);
+
+			return getGrpcCommand(commandServiceBlockingStub, request);
+		}
+	}
+
+	GrpcCommand getGrpcCommand(CommandServiceGrpc.CommandServiceBlockingStub commandServiceBlockingStub, GrpcGetCommandRequest request) {
+		return commandServiceBlockingStub.getCommand(request);
+	}
+
+	GrpcChannelFactory getChannelFactory(String channelAddress) {
+		return de.ozgcloud.antragsraum.common.GrpcChannelFactory.getChannelFactory(channelPropertiesFactory.getGrpcChannelsProperties(channelAddress),
+		  registry);
+	}
+}
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/nachricht/GrpcCommandTestFactory.java b/server/src/main/java/de/ozgcloud/antragsraum/command/CommandMapper.java
old mode 100755
new mode 100644
similarity index 64%
rename from server/src/test/java/de/ozgcloud/antragsraum/nachricht/GrpcCommandTestFactory.java
rename to server/src/main/java/de/ozgcloud/antragsraum/command/CommandMapper.java
index 6dbef35d07242d2b47b88908cbfa04f4b8ce02ab..980c665922c687ba6712b508476872a7be4984f8
--- a/server/src/test/java/de/ozgcloud/antragsraum/nachricht/GrpcCommandTestFactory.java
+++ b/server/src/main/java/de/ozgcloud/antragsraum/command/CommandMapper.java
@@ -19,26 +19,27 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-package de.ozgcloud.antragsraum.nachricht;
 
-import java.util.UUID;
+package de.ozgcloud.antragsraum.command;
+
+import java.time.ZonedDateTime;
 
 import de.ozgcloud.vorgang.grpc.command.GrpcCommand;
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
 
 @NoArgsConstructor(access = AccessLevel.PRIVATE)
-class GrpcCommandTestFactory {
-	static final String ID = UUID.randomUUID().toString();
-	static final String STATUS_SEND = "SEND";
-	static final String STATUS_FINISHED = "FINISHED";
-	static final String STATUS_PENDING = "PENDING";
-
-	static GrpcCommand create() {
-		return createBuilder().build();
-	}
+public class CommandMapper {
+	static Command fromGrpcCommand(GrpcCommand grpcCommand, String nachrichtEventId) {
+		var createdAt = ZonedDateTime.parse(grpcCommand.getCreatedAt()).toEpochSecond() * 1000;
+		var finishedAt = grpcCommand.getFinishedAt().isEmpty() ? null : ZonedDateTime.parse(grpcCommand.getFinishedAt()).toEpochSecond() * 1000;
 
-	static GrpcCommand.Builder createBuilder() {
-		return GrpcCommand.newBuilder().setStatus(STATUS_SEND).setId(ID);
+		return Command.builder()
+		  .id(grpcCommand.getId())
+		  .nachrichtEventId(nachrichtEventId)
+		  .status(grpcCommand.getStatus())
+		  .createdAt(createdAt)
+		  .finishedAt(finishedAt)
+		  .build();
 	}
 }
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/command/CommandReference.java b/server/src/main/java/de/ozgcloud/antragsraum/command/CommandReference.java
new file mode 100644
index 0000000000000000000000000000000000000000..00e112bc6046822f5d898629f46651866c1a23ba
--- /dev/null
+++ b/server/src/main/java/de/ozgcloud/antragsraum/command/CommandReference.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2023-2024.
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+
+package de.ozgcloud.antragsraum.command;
+
+import jakarta.validation.constraints.NotBlank;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Builder;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@Builder(toBuilder = true)
+public record CommandReference(
+  @Schema(description = "The id of the command", name = "id", type = "string", example = "1258ad3f46811d04010f22ab")
+  @NotBlank
+  String id,
+  @Schema(description = "The id of the NachrichtEvent in the InfoManager the command belongs to",
+	name = "nachrichtEventId",
+	type = "string",
+	example = "60af924b4f1a2560298b4567"
+  )
+  String nachrichtEventId) {
+}
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/nachricht/NachrichtEventTestFactory.java b/server/src/main/java/de/ozgcloud/antragsraum/command/CommandRemoteService.java
similarity index 60%
rename from server/src/test/java/de/ozgcloud/antragsraum/nachricht/NachrichtEventTestFactory.java
rename to server/src/main/java/de/ozgcloud/antragsraum/command/CommandRemoteService.java
index dfb16e86a43cb138145d78f04fd0b016dfce33d8..e68ffccf78860697585054a38607f781b72b1639 100644
--- a/server/src/test/java/de/ozgcloud/antragsraum/nachricht/NachrichtEventTestFactory.java
+++ b/server/src/main/java/de/ozgcloud/antragsraum/command/CommandRemoteService.java
@@ -19,24 +19,27 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-package de.ozgcloud.antragsraum.nachricht;
 
-import java.util.UUID;
+package de.ozgcloud.antragsraum.command;
+
+import org.springframework.stereotype.Service;
 
 import de.ozgcloud.antragsraum.events.NachrichtEvent;
+import de.ozgcloud.vorgang.grpc.command.GrpcGetCommandRequest;
+import lombok.NonNull;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.log4j.Log4j2;
 
-public class NachrichtEventTestFactory {
-	public static final String POSTFACH_ID = UUID.randomUUID().toString();
-	public static final String VORGANG_ID = UUID.randomUUID().toString();
-	public static final String URL = "http://localhost";
+@Log4j2
+@Service
+@RequiredArgsConstructor
+class CommandRemoteService {
+	private final @NonNull CommandGrpcClient grpcClient;
 
-	public static NachrichtEvent create() {
-		return createBuilder().build();
-	}
+	Command getCommand(NachrichtEvent nachrichtEvent, String commandId) {
+		var request = GrpcGetCommandRequest.newBuilder().setId(commandId).build();
+		var response = grpcClient.getCommand(request, nachrichtEvent.address());
 
-	public static NachrichtEvent.NachrichtEventBuilder createBuilder() {
-		return NachrichtEvent.builder()
-		  .postfachId(POSTFACH_ID)
-		  .address(URL);
+		return CommandMapper.fromGrpcCommand(response, nachrichtEvent.id());
 	}
 }
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/command/CommandService.java b/server/src/main/java/de/ozgcloud/antragsraum/command/CommandService.java
new file mode 100644
index 0000000000000000000000000000000000000000..999f22bdc9fcebf6f0235bc643b60cebd4df035d
--- /dev/null
+++ b/server/src/main/java/de/ozgcloud/antragsraum/command/CommandService.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2023-2024.
+ * Das Land Schleswig-Holstein vertreten durch den Ministerpräsidenten des Landes Schleswig-Holstein Staatskanzlei Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+ *
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+
+package de.ozgcloud.antragsraum.command;
+
+import org.springframework.stereotype.Service;
+
+import de.ozgcloud.antragsraum.events.NachrichtEventService;
+import lombok.NonNull;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.log4j.Log4j2;
+
+@Log4j2
+@Service
+@RequiredArgsConstructor
+class CommandService {
+	private final @NonNull CommandRemoteService commandRemoteService;
+	private final @NonNull NachrichtEventService nachrichtEventService;
+
+	Command getCommand(String commandId, String nachrichtEventId) {
+		var nachrichtEvent = nachrichtEventService.getNachrichtEventById(nachrichtEventId);
+
+		return commandRemoteService.getCommand(nachrichtEvent, commandId);
+	}
+}
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/common/InsufficientTrustLevelException.java b/server/src/main/java/de/ozgcloud/antragsraum/common/NotAccessibleException.java
similarity index 73%
rename from server/src/main/java/de/ozgcloud/antragsraum/common/InsufficientTrustLevelException.java
rename to server/src/main/java/de/ozgcloud/antragsraum/common/NotAccessibleException.java
index fd27156afdcdc3bfc8eabfc5c52bb29f8da7f36a..88398b40b1b089bb25a30a9250b27c377311542c 100644
--- a/server/src/main/java/de/ozgcloud/antragsraum/common/InsufficientTrustLevelException.java
+++ b/server/src/main/java/de/ozgcloud/antragsraum/common/NotAccessibleException.java
@@ -1,6 +1,6 @@
 /*
- * Copyright (c) 2023-2024.
- * Das Land Schleswig-Holstein vertreten durch den Ministerpräsidenten des Landes Schleswig-Holstein Staatskanzlei Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+ * Copyright (c) 2023-2024.   Das Land Schleswig-Holstein vertreten durch den Ministerpräsidenten
+ * des Landes Schleswig-Holstein Staatskanzlei Abteilung Digitalisierung und zentrales IT-Management der Landesregierung.
  *
  * Lizenziert unter der EUPL, Version 1.2 oder - sobald
  * diese von der Europäischen Kommission genehmigt wurden -
@@ -22,10 +22,10 @@
 
 package de.ozgcloud.antragsraum.common;
 
-public class InsufficientTrustLevelException extends RuntimeException {
+public class NotAccessibleException extends RuntimeException {
 	private static final String MESSAGE_TEMPLATE = "Current user does not have the required trust level for the Rueckfrage with id '%s'.";
 
-	public InsufficientTrustLevelException(String rueckfrageId) {
+	public NotAccessibleException(String rueckfrageId) {
 		super(String.format(MESSAGE_TEMPLATE, rueckfrageId));
 	}
-}
+}
\ No newline at end of file
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/events/NachrichtEvent.java b/server/src/main/java/de/ozgcloud/antragsraum/events/NachrichtEvent.java
index 1d03a40f0a4520cc3ab4f90138780177e782f046..d325c2f78edc7c1b6787af994bd89f801cb89b56 100644
--- a/server/src/main/java/de/ozgcloud/antragsraum/events/NachrichtEvent.java
+++ b/server/src/main/java/de/ozgcloud/antragsraum/events/NachrichtEvent.java
@@ -25,5 +25,5 @@ package de.ozgcloud.antragsraum.events;
 import lombok.Builder;
 
 @Builder
-public record NachrichtEvent(String postfachId, String address) {
+public record NachrichtEvent(String id, String postfachId, String address) {
 }
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/events/NachrichtEventMapper.java b/server/src/main/java/de/ozgcloud/antragsraum/events/NachrichtEventMapper.java
index b70e068e5e086f62b8be75f701ee822c8a7daa09..0479993e4aea51f2a2e728a39358d3f475c63625 100644
--- a/server/src/main/java/de/ozgcloud/antragsraum/events/NachrichtEventMapper.java
+++ b/server/src/main/java/de/ozgcloud/antragsraum/events/NachrichtEventMapper.java
@@ -22,15 +22,16 @@
 
 package de.ozgcloud.antragsraum.events;
 
-import de.ozgcloud.info.nachricht.GrpcNachricht;
+import de.ozgcloud.info.GrpcInformationNachricht;
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
 
 @NoArgsConstructor(access = AccessLevel.PRIVATE)
 class NachrichtEventMapper {
-	static NachrichtEvent fromGrpc(GrpcNachricht nachricht) {
+	static NachrichtEvent fromGrpcInformationNachricht(GrpcInformationNachricht nachricht) {
 		return NachrichtEvent.builder()
+		  .id(nachricht.getId())
 		  .postfachId(nachricht.getPostfachId())
-		  .address(nachricht.getNachrichtenListUrl()).build();
+		  .address(nachricht.getOzgCloudAddress()).build();
 	}
 }
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/events/NachrichtEventRemoteService.java b/server/src/main/java/de/ozgcloud/antragsraum/events/NachrichtEventRemoteService.java
index 215b5880de1a60eba164f1ba3de8acb4fa0da243..341ccdb78cbd74814a0615c1187704cedd00b418 100644
--- a/server/src/main/java/de/ozgcloud/antragsraum/events/NachrichtEventRemoteService.java
+++ b/server/src/main/java/de/ozgcloud/antragsraum/events/NachrichtEventRemoteService.java
@@ -20,27 +20,38 @@
 
 package de.ozgcloud.antragsraum.events;
 
+import java.util.List;
+
+import org.springframework.stereotype.Service;
+
+import de.ozgcloud.info.GrpcInformationByIdRequest;
+import de.ozgcloud.info.GrpcInformationNachricht;
 import de.ozgcloud.info.GrpcInformationRequest;
 import de.ozgcloud.info.InformationServiceGrpc;
-import de.ozgcloud.info.nachricht.GrpcNachricht;
 import lombok.extern.log4j.Log4j2;
 import net.devh.boot.grpc.client.inject.GrpcClient;
-import org.springframework.stereotype.Service;
-
-import java.util.List;
 
 @Service
 @Log4j2
 class NachrichtEventRemoteService {
-
 	@GrpcClient("info-manager")
 	InformationServiceGrpc.InformationServiceBlockingStub informationServiceBlockingClient;
 
+	NachrichtEvent getNachrichtEventById(String id) {
+		return NachrichtEventMapper.fromGrpcInformationNachricht(loadEvent(id));
+	}
+
+	private GrpcInformationNachricht loadEvent(String id) {
+		var request = GrpcInformationByIdRequest.newBuilder().setId(id).build();
+
+		return informationServiceBlockingClient.getInformationById(request).getNachricht();
+	}
+
 	List<NachrichtEvent> getNachrichtEventsOfPostfach(String postfachId) {
-		return loadEvents(postfachId).stream().map(NachrichtEventMapper::fromGrpc).toList();
+		return loadEvents(postfachId).stream().map(NachrichtEventMapper::fromGrpcInformationNachricht).toList();
 	}
 
-	private List<GrpcNachricht> loadEvents(String postfachId) {
+	private List<GrpcInformationNachricht> loadEvents(String postfachId) {
 		var request = GrpcInformationRequest.newBuilder().setPostfachId(postfachId).build();
 
 		return informationServiceBlockingClient.getInformation(request).getNachrichtenList();
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/events/NachrichtEventService.java b/server/src/main/java/de/ozgcloud/antragsraum/events/NachrichtEventService.java
index f8143ba0c875ff9afd9492f985f000c3f310a10e..664e2a63a6756297849ead7279ca58158a4cb7e5 100644
--- a/server/src/main/java/de/ozgcloud/antragsraum/events/NachrichtEventService.java
+++ b/server/src/main/java/de/ozgcloud/antragsraum/events/NachrichtEventService.java
@@ -22,17 +22,22 @@
 
 package de.ozgcloud.antragsraum.events;
 
-import lombok.NonNull;
-import lombok.RequiredArgsConstructor;
+import java.util.List;
+
 import org.springframework.stereotype.Service;
 
-import java.util.List;
+import lombok.NonNull;
+import lombok.RequiredArgsConstructor;
 
 @Service
 @RequiredArgsConstructor
 public class NachrichtEventService {
 	private final @NonNull NachrichtEventRemoteService remoteService;
 
+	public NachrichtEvent getNachrichtEventById(String id) {
+		return remoteService.getNachrichtEventById(id);
+	}
+
 	public List<NachrichtEvent> getNachrichtEventsOfPostfachId(String postfachId) {
 		return remoteService.getNachrichtEventsOfPostfach(postfachId);
 	}
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/mocks/AntragsraumGrpcServiceStub.java b/server/src/main/java/de/ozgcloud/antragsraum/mocks/AntragsraumGrpcServiceStub.java
index bbf172496c49fc99371696e6c999f90b5e96d3a1..4b8e868908033e5f1b8493ace96d201900c1b8de 100644
--- a/server/src/main/java/de/ozgcloud/antragsraum/mocks/AntragsraumGrpcServiceStub.java
+++ b/server/src/main/java/de/ozgcloud/antragsraum/mocks/AntragsraumGrpcServiceStub.java
@@ -20,54 +20,68 @@
 
 package de.ozgcloud.antragsraum.mocks;
 
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+
 import de.ozgcloud.antragsraum.common.NotFoundException;
 import de.ozgcloud.nachrichten.antragraum.AntragraumServiceGrpc;
 import de.ozgcloud.nachrichten.antragraum.GrpcFindRueckfragenRequest;
 import de.ozgcloud.nachrichten.antragraum.GrpcFindRueckfragenResponse;
+import de.ozgcloud.nachrichten.antragraum.GrpcGetRueckfrageRequest;
+import de.ozgcloud.nachrichten.antragraum.GrpcGetRueckfrageResponse;
 import de.ozgcloud.nachrichten.antragraum.GrpcSendRueckfrageAnswerRequest;
 import de.ozgcloud.nachrichten.antragraum.GrpcSendRueckfrageAnswerResponse;
 import io.grpc.stub.StreamObserver;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.log4j.Log4j2;
 import net.devh.boot.grpc.server.service.GrpcService;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
 
 @Log4j2
 @GrpcService
 @ConditionalOnProperty(prefix = "grpc", name = "ozg_service.stubs.enabled")
 @RequiredArgsConstructor
 public class AntragsraumGrpcServiceStub extends AntragraumServiceGrpc.AntragraumServiceImplBase {
-    private final StubDataRepository dataRepository;
+	private final StubDataRepository dataRepository;
+
+	@Override
+	public void findRueckfragen(GrpcFindRueckfragenRequest request, StreamObserver<GrpcFindRueckfragenResponse> responseObserver) {
+		try {
+			var response = dataRepository.getRueckfragenResponse(request.getPostfachId());
+			LOG.info("Send response " + response);
 
-    @Override
-    public void findRueckfragen(GrpcFindRueckfragenRequest request,
-                                StreamObserver<GrpcFindRueckfragenResponse> responseObserver) {
-        try {
-            var response = dataRepository.getRueckfragenResponse(request.getPostfachId());
-            LOG.info("Send response " + response);
-            responseObserver.onNext(response);
+			responseObserver.onNext(response);
+			responseObserver.onCompleted();
+		} catch (NotFoundException e) {
+			LOG.error(e);
+			responseObserver.onError(e);
+		}
+	}
 
-            responseObserver.onCompleted();
-        } catch (NotFoundException e) {
-            LOG.error(e);
-            responseObserver.onError(e);
-        }
-    }
+	@Override
+	public void getRueckfrage(final GrpcGetRueckfrageRequest request, final StreamObserver<GrpcGetRueckfrageResponse> responseObserver) {
+		try {
+			var response = dataRepository.getRueckfrageResponse(request.getId());
+			LOG.info("Send response " + response);
 
-    @Override
-    public void sendRueckfrageAnswer(GrpcSendRueckfrageAnswerRequest request,
-                                     StreamObserver<GrpcSendRueckfrageAnswerResponse> responseObserver) {
-        LOG.info("Sending answer to OZG-CLOUD: " + request);
-        var response = GrpcSendRueckfrageAnswerResponse.newBuilder().setCommandId(CommandGrpcServiceStub.ID).build();
-        var res = dataRepository.addReply(request.getAnswer());
+			responseObserver.onNext(response);
+			responseObserver.onCompleted();
+		} catch (NotFoundException e) {
+			LOG.error(e);
+			responseObserver.onError(e);
+		}
+	}
 
-        if (res) {
-            responseObserver.onNext(response);
+	@Override
+	public void sendRueckfrageAnswer(GrpcSendRueckfrageAnswerRequest request, StreamObserver<GrpcSendRueckfrageAnswerResponse> responseObserver) {
+		LOG.info("Sending answer to OZG-CLOUD: " + request);
+		var response = GrpcSendRueckfrageAnswerResponse.newBuilder().setCommandId(CommandGrpcServiceStub.ID).build();
+		var res = dataRepository.addReply(request.getAnswer());
 
-            LOG.info("Send command response: " + response);
-            responseObserver.onCompleted();
-        } else {
-            responseObserver.onError(new RuntimeException("Error saving reply"));
-        }
-    }
+		if (res) {
+			responseObserver.onNext(response);
+			LOG.info("Send command response: " + response);
+			responseObserver.onCompleted();
+		} else {
+			responseObserver.onError(new RuntimeException("Error saving reply"));
+		}
+	}
 }
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/mocks/CommandGrpcServiceStub.java b/server/src/main/java/de/ozgcloud/antragsraum/mocks/CommandGrpcServiceStub.java
index fcc71f5aa280b0496fe9fc86d514636bd70319db..ef695d9bf7c44f615a4ead32a5a1d92a9ed8bb6a 100755
--- a/server/src/main/java/de/ozgcloud/antragsraum/mocks/CommandGrpcServiceStub.java
+++ b/server/src/main/java/de/ozgcloud/antragsraum/mocks/CommandGrpcServiceStub.java
@@ -20,35 +20,40 @@
 
 package de.ozgcloud.antragsraum.mocks;
 
+import java.util.UUID;
+
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+
 import de.ozgcloud.vorgang.grpc.command.CommandServiceGrpc;
 import de.ozgcloud.vorgang.grpc.command.GrpcCommand;
 import de.ozgcloud.vorgang.grpc.command.GrpcGetCommandRequest;
 import io.grpc.stub.StreamObserver;
 import lombok.extern.log4j.Log4j2;
 import net.devh.boot.grpc.server.service.GrpcService;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-
-import java.util.UUID;
 
 @GrpcService
 @Log4j2
 @ConditionalOnProperty(prefix = "grpc", name = "ozg_service.stubs.enabled")
 public class CommandGrpcServiceStub extends CommandServiceGrpc.CommandServiceImplBase {
-    static final String ID = UUID.randomUUID().toString();
-    static final String STATUS_SEND = "SEND";
-    static final String STATUS_FINISHED = "FINISHED";
-    static final String STATUS_PENDING = "PENDING";
+	static final String ID = UUID.randomUUID().toString();
+	private static final String STATUS_FINISHED = "FINISHED";
+	private static final String STATUS_PENDING = "PENDING";
+	private static final String CREATED_AT = "2024-06-24T08:09:57.076Z";
+	private static final String FINISHED_AT = "2024-06-24T08:10:13.076Z";
+
+	@Override
+	public void getCommand(GrpcGetCommandRequest request, StreamObserver<GrpcCommand> observer) {
+		var grpcCommandBuilder = GrpcCommand.newBuilder()
+		  .setId(ID)
+		  .setCreatedAt(CREATED_AT);
 
-    @Override
-    public void getCommand(GrpcGetCommandRequest request, StreamObserver<GrpcCommand> observer) {
-        if (ID.equals(request.getId())) {
-            LOG.info("Finishing command {}", request.getId());
-            observer.onNext(GrpcCommand.newBuilder().setStatus(STATUS_FINISHED).setId(ID).build());
-        } else {
-            LOG.info("Pending command {}", request.getId());
-            observer.onNext(GrpcCommand.newBuilder()
-                    .setStatus(STATUS_PENDING).setId(ID).build());
-        }
-        observer.onCompleted();
-    }
+		if (ID.equals(request.getId())) {
+			LOG.info("Finishing command {}", request.getId());
+			observer.onNext(grpcCommandBuilder.setStatus(STATUS_FINISHED).setFinishedAt(FINISHED_AT).build());
+		} else {
+			LOG.info("Pending command {}", request.getId());
+			observer.onNext(grpcCommandBuilder.setStatus(STATUS_PENDING).setFinishedAt("").build());
+		}
+		observer.onCompleted();
+	}
 }
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/mocks/E2eTestController.java b/server/src/main/java/de/ozgcloud/antragsraum/mocks/E2eTestController.java
index 273633df7f8f6d160d08766dfff23e8aee1b5852..e9cab13a4c7aca92ab4321700fb16bb4df5c4c53 100644
--- a/server/src/main/java/de/ozgcloud/antragsraum/mocks/E2eTestController.java
+++ b/server/src/main/java/de/ozgcloud/antragsraum/mocks/E2eTestController.java
@@ -20,14 +20,14 @@
 
 package de.ozgcloud.antragsraum.mocks;
 
-import de.ozgcloud.antragsraum.events.NachrichtEvent;
-import de.ozgcloud.vorgang.grpc.binaryFile.GrpcBinaryFile;
-import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.Parameter;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.log4j.Log4j2;
+import static de.ozgcloud.antragsraum.mocks.GrpcDataCreator.*;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.UUID;
+
 import org.apache.commons.lang3.StringUtils;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.annotation.Profile;
 import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.PostMapping;
@@ -35,17 +35,18 @@ import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
-import java.time.LocalDateTime;
-import java.time.format.DateTimeFormatter;
-import java.util.UUID;
-
-import static de.ozgcloud.antragsraum.mocks.GrpcDataCreator.*;
+import de.ozgcloud.antragsraum.events.NachrichtEvent;
+import de.ozgcloud.vorgang.grpc.binaryFile.GrpcBinaryFile;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.log4j.Log4j2;
 
 @RestController
 @Log4j2
 @RequestMapping(E2eTestController.PATH)
 @RequiredArgsConstructor
-@ConditionalOnProperty(name = "ozgcloud.mock.auth")
+@Profile("local")
 public class E2eTestController {
 	static final String CONTENT_TYPE = "text/plain";
 	private static final String DATA = "Inhalt der Testdatei ";
@@ -57,7 +58,6 @@ public class E2eTestController {
 	@Operation(summary = "Create a Nachricht and send it to the InfoManager")
 	@PostMapping(value = "event", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
 	public ResponseEntity<NachrichtEvent> sendNachricht(@RequestBody @Parameter(description = "The Testevent data as JSON") MockEvent mockEvent) {
-
 		var event = nachrichtEventService.addEvent(mockEvent);
 		var nachrichtId = createNachricht(event, mockEvent);
 
@@ -68,18 +68,22 @@ public class E2eTestController {
 
 	String createNachricht(NachrichtEvent nachrichtEvent, MockEvent mockEvent) {
 		var reply = GrpcDataCreator.getRueckfrageBuilder(mockEvent.vorgangId())
-				.setText(StringUtils.isNotEmpty(mockEvent.clerkMessageText()) ? mockEvent.clerkMessageText() : TEXT)
-				.setVorgangName(StringUtils.isNotEmpty(mockEvent.clerkMessageTitle()) ? mockEvent.clerkMessageTitle() : VORGANG_TITLE + mockEvent.vorgangId())
-				.setSentAt(StringUtils.isNotEmpty(mockEvent.sendDateTime()) ? mockEvent.sendDateTime() : LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
+		  .setText(StringUtils.isNotEmpty(mockEvent.clerkMessageText()) ? mockEvent.clerkMessageText() : TEXT)
+		  .setVorgangName(
+			StringUtils.isNotEmpty(mockEvent.clerkMessageTitle()) ? mockEvent.clerkMessageTitle() : VORGANG_TITLE + mockEvent.vorgangId())
+		  .setSentAt(StringUtils.isNotEmpty(mockEvent.sendDateTime())
+			? mockEvent.sendDateTime()
+			: LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
+
 		if (mockEvent.attachmentCount() > 0) {
 			for (int i = 0; i < mockEvent.attachmentCount(); i++) {
 				var fileId = UUID.randomUUID().toString();
 				var fileContent = (DATA + i).getBytes();
 				var file = GrpcBinaryFile.newBuilder()
-						.setId(fileId)
-						.setName("TestDoc" + i + ".txt")
-						.setContentType(CONTENT_TYPE)
-						.setSize(fileContent.length).build();
+				  .setId(fileId)
+				  .setName("TestDoc" + i + ".txt")
+				  .setContentType(CONTENT_TYPE)
+				  .setSize(fileContent.length).build();
 				reply.addAttachmentFileId(file.getId());
 
 				stubDataRepository.setFile(file, reply.getVorgangId());
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/mocks/GrpcDataCreator.java b/server/src/main/java/de/ozgcloud/antragsraum/mocks/GrpcDataCreator.java
index 38077504dce17523f3a607c7176f3985d011d940..28a9914268664bb0d5c0b3dcd69626e4941f081e 100644
--- a/server/src/main/java/de/ozgcloud/antragsraum/mocks/GrpcDataCreator.java
+++ b/server/src/main/java/de/ozgcloud/antragsraum/mocks/GrpcDataCreator.java
@@ -20,75 +20,103 @@
 
 package de.ozgcloud.antragsraum.mocks;
 
+import java.nio.charset.StandardCharsets;
+
+import org.apache.commons.lang3.RandomStringUtils;
+
 import de.ozgcloud.nachrichten.antragraum.GrpcRueckfrage;
-import de.ozgcloud.vorgang.grpc.binaryFile.GrpcBinaryFile;
-import de.ozgcloud.vorgang.grpc.file.GrpcOzgFile;
+import de.ozgcloud.nachrichten.antragraum.GrpcRueckfrageAnswer;
+import de.ozgcloud.nachrichten.antragraum.GrpcRueckfrageHead;
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
 import lombok.extern.log4j.Log4j2;
-import org.apache.commons.lang3.RandomStringUtils;
-import org.springframework.http.MediaType;
-
-import java.nio.charset.StandardCharsets;
 
 @NoArgsConstructor(access = AccessLevel.PRIVATE)
 @Log4j2
 class GrpcDataCreator {
 	static final String POSTFACH_ID_1 = "28721c6f-b78f-4d5c-a048-19fd2fc429d2";
-	static final String POSTFACH_ID_2 = "12345c6a-b78f-4d5c-a048-19fd2fc400a1";
-	static final String NACHRICHT_ID_1_0 = "6358fd4146811d04010f44d0";
-	static final String NACHRICHT_ID_2_0 = "6358fd4446811d04010f44da";
-	static final String NACHRICHT_ID_2_1 = "6358fd4446811d04010f44db";
+	static final String NACHRICHT_ID_1 = "6358fd4146811d04010f44d0";
+	static final String NACHRICHT_ID_2 = "6358fd4446811d04010f44da";
+	static final String NACHRICHT_ID_3 = "6358fd4446811d04010f44dh";
 	static final String VORGANG_ID_1 = "6358fd0bee7a051389cdd787";
 	static final String VORGANG_ID_2 = "6358fd3f46811d04010f44c7";
-	public static final String TEXT = """
-			Lorem ipsum dolor sit amet, consetetur sadipscing elitr,
-			 sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat,
-			 sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum.
-			 
-			 Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
-			 Lorem ipsum dolor sit amet, consetetur sadipscing elitr.
-			""";
+	static final String VORGANG_ID_3 = "6358fd3f46811d04010f44c2";
+	public static final String TEXT =
+	  "Lorem ipsum dolor sit amet, consetetur sadipscing elitr,\nsed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat,\nsed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum.\n\n"
+		+ "Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.Lorem ipsum dolor sit amet, consetetur sadipscing elitr.";
 	static final String FILE_ID_1 = "6358fd0bee7a051389cdd788";
-	static final String FILE_ID_2 = "6358fd0bee7a051389cdd799";
 	static final String FILE_NAME = "TestDokument.txt";
 	static final byte[] FILE_CONTENT = TEXT.getBytes(StandardCharsets.UTF_8);
 	static final String VORGANG_TITLE = "Vorgang title ";
+	static final String SENT_AT = "2022-10-26T09:26:25";
+	static final String ANSWERED_AT = "2022-11-26T09:26:25";
+	static final String TRUST_LEVEL = "LOW";
 
 	static GrpcRueckfrage.Builder getRueckfrageBuilder(String vorgangId) {
+		var id = RandomStringUtils.randomAlphanumeric(16);
 		var builder = GrpcRueckfrage.newBuilder()
-				.setId(RandomStringUtils.randomAlphanumeric(16))
-				.setVorgangId(vorgangId)
-				.setText(TEXT)
-				.setVorgangName(VORGANG_TITLE + vorgangId)
-				.setSentAt("2022-10-26T09:26:25")
-				.clearAnswers();
+		  .setId(id)
+		  .setVorgangId(vorgangId)
+		  .setText(TEXT)
+		  .setVorgangName(VORGANG_TITLE + vorgangId)
+		  .setSentAt(SENT_AT);
+
 		if (vorgangId.equals(VORGANG_ID_1)) {
-			builder.addAttachmentFileId(FILE_ID_1);
-			builder.setId(NACHRICHT_ID_1_0);
+			builder
+			  .setId(NACHRICHT_ID_1)
+			  .addAttachmentFileId(FILE_ID_1)
+			  .setAnsweredAt(ANSWERED_AT)
+			  .setAccessible(true)
+			  .setTrustLevel(TRUST_LEVEL)
+			  .setStatus("ANSWERED")
+			  .clearAnswers()
+			  .addAnswers(GrpcRueckfrageAnswer.newBuilder().setRueckfrageId(id).setAnswerText("The Reply").build());
 		} else if (vorgangId.equals(VORGANG_ID_2)) {
-			builder.setId(NACHRICHT_ID_2_0);
-			builder.addAttachmentFileId(FILE_ID_2);
+			builder
+			  .setId(NACHRICHT_ID_2)
+			  .setAccessible(true)
+			  .setTrustLevel(TRUST_LEVEL)
+			  .setStatus("NEW");
+		} else {
+			builder
+			  .setId(NACHRICHT_ID_3)
+			  .setAccessible(false)
+			  .setTrustLevel(TRUST_LEVEL)
+			  .setStatus("NEW");
 		}
 
 		return builder;
 	}
 
-	static GrpcBinaryFile createBinaryFile(String fileId) {
-		return GrpcBinaryFile.newBuilder()
-				.setContentType(MediaType.TEXT_PLAIN_VALUE)
-				.setSize(FILE_CONTENT.length)
-				.setId(fileId)
-				.setName(FILE_NAME)
-				.build();
-	}
+	static GrpcRueckfrageHead.Builder getRueckfrageHeadBuilder(String vorgangId) {
+		var id = RandomStringUtils.randomAlphanumeric(16);
+		var builder = GrpcRueckfrageHead.newBuilder()
+		  .setId(id)
+		  .setVorgangId(vorgangId)
+		  .setVorgangName(VORGANG_TITLE + vorgangId)
+		  .setSentAt(SENT_AT);
 
-	static GrpcOzgFile createFile(String fileId) {
-		return GrpcOzgFile.newBuilder()
-				.setContentType(MediaType.TEXT_PLAIN_VALUE)
-				.setSize(FILE_CONTENT.length)
-				.setId(fileId)
-				.setName(FILE_NAME)
-				.build();
+		if (vorgangId.equals(VORGANG_ID_1)) {
+			builder
+			  .setId(NACHRICHT_ID_1)
+			  .setAnsweredAt("2022-11-26T09:26:25")
+			  .setAccessible(true)
+			  .setTrustLevel(TRUST_LEVEL)
+			  .setStatus("ANSWERED");
+		} else if (vorgangId.equals(VORGANG_ID_2)) {
+			builder
+			  .setId(NACHRICHT_ID_2)
+			  .setAccessible(true)
+			  .setTrustLevel(TRUST_LEVEL)
+			  .setStatus("NEW");
+		} else {
+			builder
+			  .setId(NACHRICHT_ID_3)
+			  .setAccessible(false)
+			  .setTrustLevel(TRUST_LEVEL)
+			  .setStatus("NEW");
+		}
+
+		return builder;
 	}
 }
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/mocks/JwtTokenWrapper.java b/server/src/main/java/de/ozgcloud/antragsraum/mocks/JwtTokenWrapper.java
index 7dc50b6d57eccfee45554787ae6ecdb03f966c48..b8588771381943d16c280f6c53123e60fc9a58be 100644
--- a/server/src/main/java/de/ozgcloud/antragsraum/mocks/JwtTokenWrapper.java
+++ b/server/src/main/java/de/ozgcloud/antragsraum/mocks/JwtTokenWrapper.java
@@ -31,7 +31,6 @@ import org.springframework.stereotype.Component;
 import de.ozgcloud.antragsraum.security.DefaultRole;
 import de.ozgcloud.antragsraum.security.JwtTokenProvider;
 import de.ozgcloud.antragsraum.security.User;
-import de.ozgcloud.antragsraum.security.UserTrustLevel;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.log4j.Log4j2;
 
@@ -43,6 +42,7 @@ public class JwtTokenWrapper {
 	public static final String USER_ID = UUID.randomUUID().toString();
 	public static final String USER_NAME = "test";
 	public static final String SAML_TOKEN_DUMMY = "saml-token-dummy";
+	public static final String USER_TRUST_LEVEL = "STORK-QAA-Level-3";
 	private final JwtTokenProvider tokenProvider;
 
 	Authentication wrap(String accessToken) {
@@ -53,7 +53,7 @@ public class JwtTokenWrapper {
 		  .samlToken(SAML_TOKEN_DUMMY)
 		  .username(USER_NAME)
 		  .postkorbHandle(POSTKORB_HANDLE)
-		  .trustLevel(UserTrustLevel.STORK_QAA_LEVEL_3)
+		  .trustLevel(USER_TRUST_LEVEL)
 		  .tokenExpiresAt(new Date())
 		  .build();
 		return new UsernamePasswordAuthenticationToken(user.getId(), tokenProvider.generate(user), List.of(new DefaultRole()));
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/mocks/MockEvent.java b/server/src/main/java/de/ozgcloud/antragsraum/mocks/MockEvent.java
index 23c554cebfb6b69e6af421271efcabae4de57a9a..9150773c24c300e8418822997e7387f2557207a2 100644
--- a/server/src/main/java/de/ozgcloud/antragsraum/mocks/MockEvent.java
+++ b/server/src/main/java/de/ozgcloud/antragsraum/mocks/MockEvent.java
@@ -25,46 +25,46 @@ import lombok.Builder;
 
 @Builder(toBuilder = true)
 public record MockEvent(
-		@Schema(description = "The postkorbHandle",
-				name = "postkorbHandle",
-				type = "string",
-				example = "28721c6f-b78f-4d5c-a048-19fd2fc429d2"
-		)
-		String postkorbHandle,
-		@Schema(description = "The Vorgang Id",
-				name = "vorgangId",
-				type = "string",
-				example = "abcd1c6f-b78f-4d5c-a048-19fd2fc42xxx"
-		)
-		String vorgangId,
-		@Schema(description = "Address of the OZG-Cloud instance. Should be 'static://localhost:9090' other values will produce errors!",
-				name = "address",
-				type = "string",
-				example = "static://localhost:9090"
-		)
-		String address,
-		@Schema(description = "The Vorgang title of the message send by the clerk. Optional if empty the example title is used.",
-				name = "clerkMessageTitle",
-				type = "string",
-				example = "Vorgang title <id of the reply message>"
-		)
-		String clerkMessageTitle,
-		@Schema(description = "The text of the message send by the clerk. Optional, if empty an example text is used.",
-				name = "clerkMessageText",
-				type = "string",
-				example = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr,\n sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat,\\n sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum.\\n\\n Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.\\n Lorem ipsum dolor sit amet, consetetur sadipscing elitr."
-		)
-		String clerkMessageText,
+  @Schema(description = "The postkorbHandle",
+	name = "postkorbHandle",
+	type = "string",
+	example = "28721c6f-b78f-4d5c-a048-19fd2fc429d2"
+  )
+  String postkorbHandle,
+  @Schema(description = "The Vorgang Id",
+	name = "vorgangId",
+	type = "string",
+	example = "abcd1c6f-b78f-4d5c-a048-19fd2fc42xxx"
+  )
+  String vorgangId,
+  @Schema(description = "Address of the OZG-Cloud instance. Should be 'static://localhost:9090' other values will produce errors!",
+	name = "address",
+	type = "string",
+	example = "static://localhost:9090"
+  )
+  String address,
+  @Schema(description = "The Vorgang title of the message send by the clerk. Optional if empty the example title is used.",
+	name = "clerkMessageTitle",
+	type = "string",
+	example = "Vorgang title <id of the reply message>"
+  )
+  String clerkMessageTitle,
+  @Schema(description = "The text of the message send by the clerk. Optional, if empty an example text is used.",
+	name = "clerkMessageText",
+	type = "string",
+	example = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr,\n sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat,\\n sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum.\\n\\n Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.\\n Lorem ipsum dolor sit amet, consetetur sadipscing elitr."
+  )
+  String clerkMessageText,
 
-		@Schema(description = "The timestamp when the clerk message has been send. When not set the current time and date is used",
-				name = "sendDateTime",
-				type = "String",
-				example = "2023-12-01T12:23:25.000"
-		)
-		String sendDateTime,
-		@Schema(description = "Add the test attachments to the event. Defaults to 0, which means no attachments",
-				name = "attachmentCount",
-				type = "integer",
-				example = "0")
-		int attachmentCount) {
+  @Schema(description = "The timestamp when the clerk message has been send. When not set the current time and answeredAt is used",
+	name = "sendDateTime",
+	type = "String",
+	example = "2023-12-01T12:23:25.000"
+  )
+  String sendDateTime,
+  @Schema(description = "Add the test attachments to the event. Defaults to 0, which means no attachments",
+	name = "attachmentCount",
+	type = "integer",
+	example = "0")
+  int attachmentCount) {
 }
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/mocks/MockRedirectStrategy.java b/server/src/main/java/de/ozgcloud/antragsraum/mocks/MockRedirectStrategy.java
index ce19c26f12695358a5622d3557683208eca50667..195c9d11f9c47f31d68be8964ad465099c59c8e0 100644
--- a/server/src/main/java/de/ozgcloud/antragsraum/mocks/MockRedirectStrategy.java
+++ b/server/src/main/java/de/ozgcloud/antragsraum/mocks/MockRedirectStrategy.java
@@ -34,7 +34,6 @@ import org.springframework.security.web.DefaultRedirectStrategy;
 
 import de.ozgcloud.antragsraum.security.InMemoryUserDetailService;
 import de.ozgcloud.antragsraum.security.User;
-import de.ozgcloud.antragsraum.security.UserTrustLevel;
 import lombok.extern.log4j.Log4j2;
 
 @Log4j2
@@ -54,7 +53,7 @@ public class MockRedirectStrategy extends DefaultRedirectStrategy {
 			var authUser = (User) userToken.getPrincipal();
 			var user = authUser.toBuilder()
 			  .postkorbHandle(JwtTokenWrapper.POSTKORB_HANDLE)
-			  .trustLevel(UserTrustLevel.STORK_QAA_LEVEL_3)
+			  .trustLevel(JwtTokenWrapper.USER_TRUST_LEVEL)
 			  .refreshCode(RandomStringUtils.randomAlphanumeric(64))
 			  .samlToken(JwtTokenWrapper.SAML_TOKEN_DUMMY).build();
 			((InMemoryUserDetailService) userDetailsService).addUser(onetimeToken, user);
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/mocks/StubDataRepository.java b/server/src/main/java/de/ozgcloud/antragsraum/mocks/StubDataRepository.java
index 353b54709d58125a2e52d33726255fff8c87a3e2..1a212a40c9eeebda70d0a741cf4fc51507c7443d 100644
--- a/server/src/main/java/de/ozgcloud/antragsraum/mocks/StubDataRepository.java
+++ b/server/src/main/java/de/ozgcloud/antragsraum/mocks/StubDataRepository.java
@@ -20,18 +20,7 @@
 
 package de.ozgcloud.antragsraum.mocks;
 
-import de.ozgcloud.antragsraum.common.NotFoundException;
-import de.ozgcloud.antragsraum.events.NachrichtEvent;
-import de.ozgcloud.nachrichten.antragraum.GrpcFindRueckfragenResponse;
-import de.ozgcloud.nachrichten.antragraum.GrpcRueckfrage;
-import de.ozgcloud.nachrichten.antragraum.GrpcRueckfrageAnswer;
-import de.ozgcloud.vorgang.grpc.binaryFile.GrpcBinaryFile;
-import de.ozgcloud.vorgang.grpc.binaryFile.GrpcUploadBinaryFileMetaData;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.log4j.Log4j2;
-import org.apache.commons.lang3.RandomStringUtils;
-import org.springframework.http.MediaType;
-import org.springframework.stereotype.Component;
+import static de.ozgcloud.antragsraum.mocks.GrpcDataCreator.*;
 
 import java.time.LocalDateTime;
 import java.util.ArrayList;
@@ -41,27 +30,53 @@ import java.util.Optional;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicReference;
 
-import static de.ozgcloud.antragsraum.mocks.GrpcDataCreator.*;
+import org.apache.commons.lang3.RandomStringUtils;
+import org.springframework.http.MediaType;
+import org.springframework.stereotype.Component;
+
+import de.ozgcloud.antragsraum.common.NotFoundException;
+import de.ozgcloud.antragsraum.events.NachrichtEvent;
+import de.ozgcloud.nachrichten.antragraum.GrpcFindRueckfragenResponse;
+import de.ozgcloud.nachrichten.antragraum.GrpcGetRueckfrageResponse;
+import de.ozgcloud.nachrichten.antragraum.GrpcRueckfrage;
+import de.ozgcloud.nachrichten.antragraum.GrpcRueckfrageAnswer;
+import de.ozgcloud.nachrichten.antragraum.GrpcRueckfrageHead;
+import de.ozgcloud.vorgang.grpc.binaryFile.GrpcBinaryFile;
+import de.ozgcloud.vorgang.grpc.binaryFile.GrpcUploadBinaryFileMetaData;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.log4j.Log4j2;
 
 @Log4j2
 @Component
 @RequiredArgsConstructor
 class StubDataRepository {
 	private final Map<String, List<String>> messageStorage = new ConcurrentHashMap<>();
-	private final Map<String, GrpcRueckfrage> nachrichtStorage = new ConcurrentHashMap<>();
+	private final Map<String, GrpcRueckfrageHead> rueckfrageHeadStorage = new ConcurrentHashMap<>();
+	private final Map<String, GrpcRueckfrage> rueckfrageStorage = new ConcurrentHashMap<>();
 	private final Map<String, GrpcUploadBinaryFileMetaData> fileStorage = new ConcurrentHashMap<>();
 	private final Map<String, byte[]> fileContentStorage = new ConcurrentHashMap<>();
 
 	public GrpcFindRueckfragenResponse getRueckfragenResponse(String postfachId) {
 		reset();
 		if (messageStorage.get(postfachId) != null) {
-			var nachrichten = messageStorage.get(postfachId).stream().map(nachrichtStorage::get).toList();
-			return GrpcFindRueckfragenResponse.newBuilder().clearRueckfrage().addAllRueckfrage(nachrichten).build();
+			var rueckfrageHeads = messageStorage.get(postfachId).stream().map(rueckfrageHeadStorage::get).toList();
+
+			return GrpcFindRueckfragenResponse.newBuilder().clearRueckfrageHead().addAllRueckfrageHead(rueckfrageHeads).build();
 		} else {
 			throw new NotFoundException(GrpcFindRueckfragenResponse.class, postfachId);
 		}
 	}
 
+	public GrpcGetRueckfrageResponse getRueckfrageResponse(String rueckfrageId) {
+		reset();
+		var rueckfrage = rueckfrageStorage.get(rueckfrageId);
+		if (rueckfrage != null) {
+			return GrpcGetRueckfrageResponse.newBuilder().setRueckfrage(rueckfrage).build();
+		} else {
+			throw new NotFoundException(GrpcGetRueckfrageResponse.class, rueckfrageId);
+		}
+	}
+
 	void addFileContent(String fileId, byte[] content) {
 		fileContentStorage.put(fileId, content);
 	}
@@ -69,27 +84,28 @@ class StubDataRepository {
 	String addFile(GrpcUploadBinaryFileMetaData file) {
 		var fileId = RandomStringUtils.randomAlphanumeric(16);
 		fileStorage.put(fileId, file);
+
 		return fileId;
 	}
 
 	boolean addReply(GrpcRueckfrageAnswer answer) {
 		boolean success = true;
 
-		var reply = nachrichtStorage.get(answer.getRueckfrageId());
+		var reply = rueckfrageStorage.get(answer.getRueckfrageId());
 		if (reply != null) {
 			var attachmentsIds = answer.getAttachmentFileIdList().stream()
-					.map(this::getUploadedAnswerAttachment)
-					.filter(Optional::isPresent)
-					.map(Optional::get)
-					.map(GrpcBinaryFile::getId)
-					.toList();
+			  .map(this::getUploadedAnswerAttachment)
+			  .filter(Optional::isPresent)
+			  .map(Optional::get)
+			  .map(GrpcBinaryFile::getId)
+			  .toList();
 			var filledAnswer = answer.toBuilder().addAllAttachmentFileId(attachmentsIds).build();
 
 			var replyBuilder = reply.toBuilder()
-					.addAnswers(filledAnswer)
-					.setAnsweredAt(LocalDateTime.now().toString());
+			  .addAnswers(filledAnswer)
+			  .setAnsweredAt(LocalDateTime.now().toString());
 
-			nachrichtStorage.put(answer.getRueckfrageId(), replyBuilder.build());
+			rueckfrageStorage.put(answer.getRueckfrageId(), replyBuilder.build());
 		} else {
 			throw new NotFoundException(GrpcRueckfrageAnswer.class, answer.getRueckfrageId());
 		}
@@ -103,10 +119,10 @@ class StubDataRepository {
 		AtomicReference<Optional<GrpcBinaryFile>> res = new AtomicReference<>(Optional.empty());
 
 		fileDataOpt.ifPresent(fileMetaData -> res.set(Optional.of(GrpcBinaryFile.newBuilder()
-				.setContentType(fileMetaData.getContentType())
-				.setName(fileMetaData.getFileName())
-				.setSize(fileMetaData.getSize())
-				.setId(id).build()))
+		  .setContentType(fileMetaData.getContentType())
+		  .setName(fileMetaData.getFileName())
+		  .setSize(fileMetaData.getSize())
+		  .setId(id).build()))
 		);
 
 		return res.get();
@@ -115,12 +131,13 @@ class StubDataRepository {
 	Optional<GrpcUploadBinaryFileMetaData> getFileMetaData(String fileId) {
 		if (FILE_ID_1.equals(fileId)) {
 			return Optional.of(GrpcUploadBinaryFileMetaData.newBuilder()
-					.setFileName(FILE_NAME)
-					.setVorgangId(VORGANG_ID_1)
-					.setSize(FILE_CONTENT.length)
-					.setContentType(MediaType.TEXT_PLAIN_VALUE)
-					.build());
+			  .setFileName(FILE_NAME)
+			  .setVorgangId(VORGANG_ID_1)
+			  .setSize(FILE_CONTENT.length)
+			  .setContentType(MediaType.TEXT_PLAIN_VALUE)
+			  .build());
 		}
+
 		return Optional.ofNullable(fileStorage.get(fileId));
 	}
 
@@ -128,31 +145,34 @@ class StubDataRepository {
 		return Optional.ofNullable(fileContentStorage.get(fileId));
 	}
 
-
-	public void reset() {
+	private void reset() {
 		messageStorage.clear();
 		fileStorage.clear();
 
-		nachrichtStorage.put(NACHRICHT_ID_1_0, getRueckfrageBuilder(VORGANG_ID_1).build());
-		messageStorage.put(POSTFACH_ID_1, List.of(NACHRICHT_ID_1_0));
+		addRueckfrage(NACHRICHT_ID_1, VORGANG_ID_1);
+		addRueckfrage(NACHRICHT_ID_2, VORGANG_ID_2);
+		addRueckfrage(NACHRICHT_ID_3, VORGANG_ID_3);
+
+		messageStorage.put(POSTFACH_ID_1, List.of(NACHRICHT_ID_1, NACHRICHT_ID_2, NACHRICHT_ID_3));
+	}
 
-		nachrichtStorage.put(NACHRICHT_ID_2_0, getRueckfrageBuilder(VORGANG_ID_2).build());
-		nachrichtStorage.put(NACHRICHT_ID_2_1, getRueckfrageBuilder(VORGANG_ID_2).build());
-		messageStorage.put(POSTFACH_ID_2, List.of(NACHRICHT_ID_2_0, NACHRICHT_ID_2_1));
+	private void addRueckfrage(String nachrichtId, String vorgangId) {
+		rueckfrageHeadStorage.put(nachrichtId, getRueckfrageHeadBuilder(vorgangId).build());
+		rueckfrageStorage.put(nachrichtId, getRueckfrageBuilder(vorgangId).build());
 	}
 
 	public void setFile(GrpcBinaryFile file, String vorgangId) {
 		fileStorage.put(file.getId(), GrpcUploadBinaryFileMetaData.newBuilder()
-				.setFileName(file.getName())
-				.setVorgangId(vorgangId)
-				.setSize(file.getSize())
-				.setContentType(file.getContentType())
-				.build());
+		  .setFileName(file.getName())
+		  .setVorgangId(vorgangId)
+		  .setSize(file.getSize())
+		  .setContentType(file.getContentType())
+		  .build());
 	}
 
 	public String addReply(GrpcRueckfrage rueckfrage, NachrichtEvent event) {
 		String key = event.postfachId() + "-" + event.address();
-		nachrichtStorage.put(key, rueckfrage);
+		rueckfrageStorage.put(key, rueckfrage);
 
 		var nachrichtenListOpt = Optional.ofNullable(messageStorage.get(event.postfachId()));
 		nachrichtenListOpt.ifPresentOrElse(nachrichtenList -> {
@@ -162,7 +182,7 @@ class StubDataRepository {
 				messageStorage.put(event.postfachId(), nachrichtenIds);
 			}
 		}, () -> messageStorage.put(event.postfachId(), List.of(rueckfrage.getId())));
+
 		return rueckfrage.getId();
 	}
-
 }
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/mocks/WritingNachrichtenEventService.java b/server/src/main/java/de/ozgcloud/antragsraum/mocks/WritingNachrichtenEventService.java
index d8e47aa96f853e8cdfe4f2eaa8b45d57265b408c..047a69f3cc33041b9e3ebca1e856c7ef6cee4da3 100644
--- a/server/src/main/java/de/ozgcloud/antragsraum/mocks/WritingNachrichtenEventService.java
+++ b/server/src/main/java/de/ozgcloud/antragsraum/mocks/WritingNachrichtenEventService.java
@@ -47,13 +47,11 @@ public class WritingNachrichtenEventService {
 	private InformationServiceGrpc.InformationServiceBlockingStub informationServiceBlockingStub;
 
 	public NachrichtEvent addEvent(MockEvent event) {
-		var token =
-		  new UsernamePasswordAuthenticationToken(User.builder().samlToken("saml--token").build(), "dummy--token");
+		var token = new UsernamePasswordAuthenticationToken(User.builder().samlToken("saml--token").build(), "dummy--token");
 		SecurityContextHolder.getContext().setAuthentication(token);
 
 		String listUrl = event.address() != null ? event.address() : LOCALHOST_9090;
-		String postfachId =
-		  Objects.nonNull(event.postkorbHandle()) ? event.postkorbHandle() : UUID.randomUUID().toString();
+		String postfachId = Objects.nonNull(event.postkorbHandle()) ? event.postkorbHandle() : UUID.randomUUID().toString();
 
 		var nachricht = GrpcNachricht.newBuilder()
 		  .setNachrichtenListUrl(listUrl)
@@ -65,7 +63,7 @@ public class WritingNachrichtenEventService {
 		LOG.info("Saved NachrichtEvent: {}, Result: {}", nachricht, res);
 		return NachrichtEvent.builder()
 		  .postfachId(postfachId)
-		  .address("static://localhost;9091").build();
+		  .address("static://localhost:9091").build();
 	}
 }
 
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/nachricht/Nachricht.java b/server/src/main/java/de/ozgcloud/antragsraum/nachricht/Nachricht.java
index c5c79f95809882df632c83ca67e96f54240e9fc2..34109e347e168af70e62d5b7e51b31f3b3c57018 100644
--- a/server/src/main/java/de/ozgcloud/antragsraum/nachricht/Nachricht.java
+++ b/server/src/main/java/de/ozgcloud/antragsraum/nachricht/Nachricht.java
@@ -41,19 +41,24 @@ public record Nachricht(
   @Schema(description = "The address of the ozg-cloud instance base64 encoded", name = "id", type = "string", example = "1258ad3f46811d04010f22ab")
   @NotBlank
   String id,
-  @Schema(description = "The address of the ozg-cloud instance", name = "address", type = "string", example = "static://localhost:9090")
-  @NotBlank
-  String address,
-  @Schema(description = "The date the Rueckfrage has been send.")
+  @Schema(description = "The id of the NachrichtEvent in the InfoManager the nachricht belongs to",
+	name = "nachrichtEventId",
+	type = "string",
+	example = "60af924b4f1a2560298b4567"
+  )
+  String nachrichtEventId,
+  @Schema(description = "The answeredAt date time the Rueckfrage has been answered.")
+  Long answeredAt,
+  @Schema(description = "The sendAt date time the Rueckfrage has been send.")
   @Min(0)
-  long date,
-  @Schema(description = "The title of the topic. This is the title of the Vorgang",
-	name = "topicTitle",
+  long sendAt,
+  @Schema(description = "The title of the nachricht. This is the title of the Vorgang",
+	name = "title",
 	type = "string",
 	example = "Vorgang Hundesteuer Antrag"
   )
   @Size(max = 2048, message = "title too long")
-  String topicTitle,
+  String title,
   @Size(max = 500000, message = "message too long")
   String message,
   @Schema(description = "The id of the postfach. For BayernID this is the PostkorbHandle",
@@ -80,9 +85,19 @@ public record Nachricht(
   List<OzgFile> attachments,
   @Schema(hidden = true)
   List<ReplyNachricht> replyNachrichten,
+  @Schema(description = "Whether the Rueckfrage is accessible for current user or not",
+	name = "accessible",
+	type = "boolean"
+  )
+  boolean accessible,
   @Schema(description = "The trust level of the Rueckfrage",
 	name = "trustLevel",
-	type = "NachrichtTrustLevel"
+	type = "string"
+  )
+  String trustLevel,
+  @Schema(description = "The status of the Rueckfrage",
+	name = "status",
+	type = "String"
   )
-  NachrichtTrustLevel trustLevel) {
+  String status) {
 }
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/nachricht/NachrichtHeader.java b/server/src/main/java/de/ozgcloud/antragsraum/nachricht/NachrichtHeader.java
index 483e142833870bdc6f38a09e4c2ff6bb320f8785..ff39b0e4c681d94d14a5a20506fca0dd478294de 100644
--- a/server/src/main/java/de/ozgcloud/antragsraum/nachricht/NachrichtHeader.java
+++ b/server/src/main/java/de/ozgcloud/antragsraum/nachricht/NachrichtHeader.java
@@ -20,12 +20,6 @@
 
 package de.ozgcloud.antragsraum.nachricht;
 
-import jakarta.validation.constraints.Min;
-import jakarta.validation.constraints.NotBlank;
-import jakarta.validation.constraints.Size;
-
-import org.springframework.validation.annotation.Validated;
-
 import com.fasterxml.jackson.annotation.JsonInclude;
 
 import io.swagger.v3.oas.annotations.media.Schema;
@@ -33,37 +27,32 @@ import lombok.Builder;
 
 @JsonInclude(JsonInclude.Include.NON_NULL)
 @Builder(toBuilder = true)
-@Validated
 public record NachrichtHeader(
   @Schema(description = "The address of the ozg-cloud instance base64 encoded", name = "id", type = "string", example = "1258ad3f46811d04010f22ab")
-  @NotBlank
   String id,
-  @Schema(description = "The address of the ozg-cloud instance", name = "address", type = "string", example = "static://localhost:9090")
-  @NotBlank
-  String address,
-  @Schema(description = "The date the Rueckfrage has been send.")
-  @Min(0)
-  long date,
-  @Schema(description = "The title of the topic. This is the title of the Vorgang",
-	name = "topicTitle",
+  @Schema(description = "The id of the NachrichtEvent in the InfoManager the nachricht header belongs to",
+	name = "nachrichtEventId",
+	type = "string",
+	example = "60af924b4f1a2560298b4567"
+  )
+  String nachrichtEventId,
+  @Schema(description = "The title of the nachricht. This is the title of the Vorgang",
+	name = "title",
 	type = "string",
 	example = "Vorgang Hundesteuer Antrag"
   )
-  @Size(max = 2048, message = "title too long")
-  String topicTitle,
+  String title,
   @Schema(description = "The id of the postfach. For BayernID this is the PostkorbHandle",
 	name = "postfachId",
 	type = "string",
 	example = "28721c6f-b78f-4d5c-a048-19fd2fc429d2"
   )
-  @Size(max = 64, message = "postfach id to long")
   String postfachId,
   @Schema(description = "The id of the Vorgang the Rueckfrage belongs to",
 	name = "vorgangId",
 	type = "string",
 	example = "8523ad3f46811d04010f6654"
   )
-  @Size(max = 64, message = "vongang id id to long")
   String vorgangId,
   @Schema(description = "The reply option, not used right now always set 'ALLOWED'",
 	name = "vorgangId",
@@ -71,12 +60,23 @@ public record NachrichtHeader(
 	example = "ALLOWED"
   )
   ReplyOption replyOption,
-  @Schema(description = "The date on which the Rueckfrage was last answered")
-  @Min(0)
-  Long lastAnsweredDate,
+  @Schema(description = "The answeredAt Date on which the Rueckfrage was last answered")
+  Long answeredAt,
+  @Schema(description = "The sendAt Date on which the Rueckfrage send")
+  long sendAt,
+  @Schema(description = "Whether the Rueckfrage is accessible for current user or not",
+	name = "accessible",
+	type = "boolean"
+  )
+  boolean accessible,
   @Schema(description = "The trust level of the Rueckfrage",
 	name = "trustLevel",
-	type = "NachrichtTrustLevel"
+	type = "string"
+  )
+  String trustLevel,
+  @Schema(description = "The status of the Rueckfrage",
+	name = "status",
+	type = "String"
   )
-  NachrichtTrustLevel trustLevel) {
+  String status) {
 }
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/nachricht/NachrichtHeaderMapper.java b/server/src/main/java/de/ozgcloud/antragsraum/nachricht/NachrichtHeaderMapper.java
index 5e732e16896eda79c596aeb63faa712579ed7f57..a5765aea27d81d5d1a0965dfeb0a14afde6806f0 100644
--- a/server/src/main/java/de/ozgcloud/antragsraum/nachricht/NachrichtHeaderMapper.java
+++ b/server/src/main/java/de/ozgcloud/antragsraum/nachricht/NachrichtHeaderMapper.java
@@ -20,25 +20,42 @@
 
 package de.ozgcloud.antragsraum.nachricht;
 
+import java.time.DateTimeException;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+
+import de.ozgcloud.nachrichten.antragraum.GrpcRueckfrageHead;
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
+import lombok.extern.log4j.Log4j2;
 
+@Log4j2
 @NoArgsConstructor(access = AccessLevel.PRIVATE)
 class NachrichtHeaderMapper {
-	static NachrichtHeader fromNachricht(Nachricht nachricht) {
+	static NachrichtHeader fromGrpcRueckfrageHead(GrpcRueckfrageHead grpcRueckfrageHead, String nachrichtEventId) {
+		LOG.info("Mapping GrpcRueckfrageHead [{}] for NachrichtEvent [{}] to NachrichtHeader", grpcRueckfrageHead, nachrichtEventId);
 		var builder = NachrichtHeader.builder()
-		  .vorgangId(nachricht.vorgangId())
-		  .id(nachricht.id())
-		  .address(nachricht.address())
-		  .topicTitle(nachricht.topicTitle())
-		  .date(nachricht.date())
-		  .lastAnsweredDate(getLatestReplyDate(nachricht))
-		  .trustLevel(NachrichtTrustLevel.LOW);
+		  .vorgangId(grpcRueckfrageHead.getVorgangId())
+		  .id(grpcRueckfrageHead.getId())
+		  .nachrichtEventId(nachrichtEventId)
+		  .title(grpcRueckfrageHead.getVorgangName())
+		  .answeredAt(toMillisecondsTimestamp(grpcRueckfrageHead.getAnsweredAt()))
+		  .sendAt(toMillisecondsTimestamp(grpcRueckfrageHead.getSentAt()))
+		  .accessible(grpcRueckfrageHead.getAccessible())
+		  .trustLevel(TrustLevelMapper.map(grpcRueckfrageHead.getTrustLevel()))
+		  .status(grpcRueckfrageHead.getStatus());
 
 		return builder.build();
 	}
 
-	static Long getLatestReplyDate(Nachricht nachricht) {
-		return nachricht.replyNachrichten().stream().map(ReplyNachricht::date).max(Long::compare).orElse(null);
+	private static long toMillisecondsTimestamp(String dateString) {
+		long timestamp = 0;
+		try {
+			timestamp = LocalDateTime.parse(dateString).toEpochSecond(ZoneOffset.UTC) * 1000;
+		} catch (DateTimeException e) {
+			LOG.warn("Invalid date [{}] received for Nachricht. Setting it to 0 (=1970-01-01)", dateString);
+		}
+
+		return timestamp;
 	}
 }
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/nachricht/NachrichtMapper.java b/server/src/main/java/de/ozgcloud/antragsraum/nachricht/NachrichtMapper.java
index 4918c92b2eef43eedd29a1e2dd4a6fb1fb3ccdaa..12df5edb26af1aa81b4fac6dbe3f5c4441f80228 100644
--- a/server/src/main/java/de/ozgcloud/antragsraum/nachricht/NachrichtMapper.java
+++ b/server/src/main/java/de/ozgcloud/antragsraum/nachricht/NachrichtMapper.java
@@ -23,13 +23,15 @@ package de.ozgcloud.antragsraum.nachricht;
 import java.time.DateTimeException;
 import java.time.LocalDateTime;
 import java.time.ZoneOffset;
+import java.util.Comparator;
 import java.util.List;
 import java.util.Objects;
 
+import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.stereotype.Service;
 
-import de.ozgcloud.antragsraum.attachments.FileRemoteService;
+import de.ozgcloud.antragsraum.attachments.FileService;
 import de.ozgcloud.antragsraum.attachments.OzgFile;
 import de.ozgcloud.nachrichten.antragraum.GrpcRueckfrage;
 import de.ozgcloud.nachrichten.antragraum.GrpcRueckfrageAnswer;
@@ -41,48 +43,73 @@ import lombok.extern.log4j.Log4j2;
 @Service
 @RequiredArgsConstructor
 class NachrichtMapper {
-	private final @NonNull FileRemoteService fileRemoteService;
+	private final @NonNull FileService fileService;
+	private final String EXPECTED_DATE_FORMAT = "yyyy-MM-ddTHH:mm:ss";
 
-	Nachricht fromGrpcRueckfrage(GrpcRueckfrage grpcRueckfrage, String address) {
+	Nachricht fromGrpcRueckfrage(GrpcRueckfrage grpcRueckfrage, String nachrichtEventId) {
+		LOG.info("Mapping GrpcRueckfrage [{}] for NachrichtEvent [{}] to Nachricht", grpcRueckfrage, nachrichtEventId);
 		var builder = Nachricht.builder()
 		  .vorgangId(grpcRueckfrage.getVorgangId())
 		  .id(grpcRueckfrage.getId())
-		  .address(address)
-		  .topicTitle(grpcRueckfrage.getVorgangName())
+		  .nachrichtEventId(nachrichtEventId)
+		  .title(grpcRueckfrage.getVorgangName())
 		  .message(grpcRueckfrage.getText())
-		  .replyNachrichten(fromGrpcRueckfrageAnswer(grpcRueckfrage, address))
-		  .date(getUnixTimestamp(grpcRueckfrage.getSentAt()))
-		  .attachments(getAttachments(grpcRueckfrage.getAttachmentFileIdList(), address))
-		  .trustLevel(NachrichtTrustLevel.LOW);
+		  .replyNachrichten(fromGrpcRueckfrageAnswer(grpcRueckfrage, nachrichtEventId))
+		  .answeredAt(getAnsweredAt(grpcRueckfrage))
+		  .sendAt(toMillisecondsTimestamp(grpcRueckfrage.getSentAt()))
+		  .attachments(getAttachments(grpcRueckfrage.getAttachmentFileIdList(), nachrichtEventId))
+		  .accessible(grpcRueckfrage.getAccessible())
+		  .trustLevel(TrustLevelMapper.map(grpcRueckfrage.getTrustLevel()))
+		  .status(grpcRueckfrage.getStatus());
 
 		return builder.build();
 	}
 
-	private List<OzgFile> getAttachments(List<String> fileIds, String address) {
-		return fileIds.stream().filter(StringUtils::isNotEmpty).map(fileId -> fileRemoteService.getFile(fileId, address)).filter(Objects::nonNull)
-		  .toList();
+	// TODO: Entfernen, sobald valides answeredAt Datum gesendet wird
+	long getAnsweredAt(GrpcRueckfrage rueckfrage) {
+		var answeredAt = rueckfrage.getAnsweredAt();
+		if (StringUtils.isEmpty(answeredAt) && CollectionUtils.isNotEmpty(rueckfrage.getAnswersList())) {
+			LOG.info("Rückfrage answeredAt is not set, loading it from sendAt of the replies");
+			var sortedBySendBy = rueckfrage.getAnswersList().stream().filter(Objects::nonNull)
+			  .filter(answer -> StringUtils.isNotEmpty(answer.getSentAt()))
+			  .sorted(
+				Comparator.comparing(GrpcRueckfrageAnswer::getSentAt)).toList();
+
+			if (sortedBySendBy.isEmpty()) {
+				answeredAt = "";
+			} else {
+				answeredAt = sortedBySendBy.getLast().getSentAt().substring(0, EXPECTED_DATE_FORMAT.length());
+			}
+		}
+
+		return toMillisecondsTimestamp(answeredAt);
 	}
 
-	private List<ReplyNachricht> fromGrpcRueckfrageAnswer(GrpcRueckfrage rueckfrage, String address) {
+	private List<OzgFile> getAttachments(List<String> fileIds, String nachrichtEventId) {
+		return fileIds.stream().filter(StringUtils::isNotEmpty).map(fileId -> fileService.getFile(fileId, nachrichtEventId))
+		  .filter(Objects::nonNull).toList();
+	}
+
+	private List<ReplyNachricht> fromGrpcRueckfrageAnswer(GrpcRueckfrage rueckfrage, String nachrichtEventId) {
 		return rueckfrage.getAnswersList().stream()
 		  .map(answer -> {
 			  var builder = ReplyNachricht.builder()
 				.id(rueckfrage.getId())
-				.address(address)
+				.nachrichtEventId(nachrichtEventId)
 				.message(answer.getAnswerText())
-				.date(getUnixTimestamp(rueckfrage.getAnsweredAt()))
-				.attachments(getAttachments(answer.getAttachmentFileIdList(), address));
+				.attachments(getAttachments(answer.getAttachmentFileIdList(), nachrichtEventId));
 			  return builder.build();
 		  }).toList();
 	}
 
-	private long getUnixTimestamp(String dateString) {
+	long toMillisecondsTimestamp(String dateString) {
 		long timestamp = 0;
 		try {
-			timestamp = LocalDateTime.parse(dateString).toEpochSecond(ZoneOffset.UTC);
+			timestamp = LocalDateTime.parse(dateString).toEpochSecond(ZoneOffset.UTC) * 1000;
 		} catch (DateTimeException e) {
-			LOG.warn("Invalid send date [{}] received for Nachricht. Setting it to 0 (=1970-01-01)", dateString);
+			LOG.warn("Invalid date [{}] received for Nachricht. Setting it to 0 (=1970-01-01)", dateString);
 		}
+
 		return timestamp;
 	}
 
@@ -95,6 +122,7 @@ class NachrichtMapper {
 			builder.addAllAttachmentFileId(nachricht.attachments().stream()
 			  .map(OzgFile::id).toList());
 		}
+
 		return builder.build();
 	}
 }
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/nachricht/NachrichtProperties.java b/server/src/main/java/de/ozgcloud/antragsraum/nachricht/NachrichtProperties.java
deleted file mode 100755
index 30ce7e795bd9718a33123a13126b8a7e064190f2..0000000000000000000000000000000000000000
--- a/server/src/main/java/de/ozgcloud/antragsraum/nachricht/NachrichtProperties.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (c) 2023-2024.
- * Das Land Schleswig-Holstein vertreten durch den Ministerpräsidenten des Landes Schleswig-Holstein Staatskanzlei Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
- *
- * Lizenziert unter der EUPL, Version 1.2 oder - sobald
- * diese von der Europäischen Kommission genehmigt wurden -
- * Folgeversionen der EUPL ("Lizenz");
- * Sie dürfen dieses Werk ausschließlich gemäß
- * dieser Lizenz nutzen.
- * Eine Kopie der Lizenz finden Sie hier:
- *
- * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
- *
- * Sofern nicht durch anwendbare Rechtsvorschriften
- * gefordert oder in schriftlicher Form vereinbart, wird
- * die unter der Lizenz verbreitete Software "so wie sie
- * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
- * ausdrücklich oder stillschweigend - verbreitet.
- * Die sprachspezifischen Genehmigungen und Beschränkungen
- * unter der Lizenz sind dem Lizenztext zu entnehmen.
- */
-
-package de.ozgcloud.antragsraum.nachricht;
-
-import java.time.Duration;
-
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.context.annotation.Configuration;
-
-import lombok.Getter;
-import lombok.Setter;
-
-@Getter
-@Setter
-@Configuration
-@ConfigurationProperties(NachrichtProperties.PREFIX)
-class NachrichtProperties {
-	static final String PREFIX = "ozgcloud.nachricht";
-	// Send timeout as ISO-8601 duration format PnDTnHnMn.nS
-	private String sendTimeout = "PT60S";
-	// Send intervall as ISO-8601 duration format PnDTnHnMn.nS
-	private String sendPollInterval = "PT2S";
-
-	Duration getTimeoutDuration() {
-		return Duration.parse(sendTimeout);
-	}
-
-	Duration getSendPollIntervalDuration() {
-		return Duration.parse(sendPollInterval);
-	}
-}
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/nachricht/NachrichtenController.java b/server/src/main/java/de/ozgcloud/antragsraum/nachricht/NachrichtenController.java
index 76007db0d216682fdf65106a2a423535ef2be5e7..b2dcac82f3fc26efe74f6a7105f60a004383372f 100644
--- a/server/src/main/java/de/ozgcloud/antragsraum/nachricht/NachrichtenController.java
+++ b/server/src/main/java/de/ozgcloud/antragsraum/nachricht/NachrichtenController.java
@@ -32,6 +32,7 @@ import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+import de.ozgcloud.antragsraum.command.CommandReference;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.Parameter;
 import io.swagger.v3.oas.annotations.security.SecurityRequirement;
@@ -47,25 +48,25 @@ public class NachrichtenController {
 
 	private final @NonNull NachrichtenService service;
 
-	@Operation(summary = "Load all Nachrichten of a Postfach")
-	@GetMapping(value = "/nachrichten/{postfachId}", produces = MediaType.APPLICATION_JSON_VALUE)
-	public List<TopicHeader> getTopicHeadersOfPostfach(
+	@Operation(summary = "Load all Rueckfragen Headers of a Postfach")
+	@GetMapping(value = "/rueckfragen/{postfachId}", produces = MediaType.APPLICATION_JSON_VALUE)
+	public List<RueckfrageHeader> getRueckfrageHeadersOfPostfach(
 	  @Parameter(description = "The id of the postfach", example = "28721c6f-b78f-4d5c-a048-19fd2fc429d2") @PathVariable String postfachId) {
-		return service.getTopicHeadersOfPostfach(postfachId);
+		return service.getRueckfrageHeadersOfPostfach(postfachId);
 	}
 
-	@Operation(summary = "Load all Nachrichten of a specific topic of a Postfach")
-	@GetMapping(value = "/nachrichten/{postfachId}/{rueckfrageId}", produces = MediaType.APPLICATION_JSON_VALUE)
-	public Topic getTopicOfPostfach(
-	  @Parameter(description = "The id of the postfach", example = "28721c6f-b78f-4d5c-a048-19fd2fc429d2") @PathVariable String postfachId,
-	  @Parameter(description = "The id of the topic", example = "1258ad3f46811d04010f22ab") @PathVariable String rueckfrageId) {
-		return service.getTopicOfPostfach(postfachId, rueckfrageId);
+	@Operation(summary = "Load a Rueckfrage by id")
+	@GetMapping(value = "/rueckfrage/{rueckfrageId}/{nachrichtEventId}", produces = MediaType.APPLICATION_JSON_VALUE)
+	public Rueckfrage getRueckfrage(
+	  @Parameter(description = "The id of the Rueckfrage", example = "1258ad3f46811d04010f22ab") @PathVariable String rueckfrageId,
+	  @Parameter(description = "The id of the NachrichtEvent in the InfoManager the rueckfrage belongs to", example = "60af924b4f1a2560298b4567")
+	  @PathVariable String nachrichtEventId) {
+		return service.getRueckfrage(rueckfrageId, nachrichtEventId);
 	}
 
 	@Operation(summary = "Send the reply to the Rueckfrage into the ozg cloud")
-	@PutMapping(value = "/nachricht", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
-	public ReplyNachricht sendNachricht(
-	  @Parameter(description = "The Nachricht content as JSON") @RequestBody @Valid ReplyNachricht nachricht) {
+	@PutMapping(value = "/antwort", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
+	public CommandReference sendNachricht(@Parameter(description = "The Nachricht content as JSON") @RequestBody @Valid ReplyNachricht nachricht) {
 		return service.sendRueckfrageAnswer(nachricht);
 	}
 }
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/nachricht/NachrichtenGrpcClient.java b/server/src/main/java/de/ozgcloud/antragsraum/nachricht/NachrichtenGrpcClient.java
index a20fa73c627b1690ccddc508d2bb3c8e4eed3cf2..0ac8268cd92045015e4f6b0d0eb3ba9be65d46c9 100644
--- a/server/src/main/java/de/ozgcloud/antragsraum/nachricht/NachrichtenGrpcClient.java
+++ b/server/src/main/java/de/ozgcloud/antragsraum/nachricht/NachrichtenGrpcClient.java
@@ -26,11 +26,10 @@ import de.ozgcloud.antragsraum.common.ChannelPropertiesFactory;
 import de.ozgcloud.nachrichten.antragraum.AntragraumServiceGrpc;
 import de.ozgcloud.nachrichten.antragraum.GrpcFindRueckfragenRequest;
 import de.ozgcloud.nachrichten.antragraum.GrpcFindRueckfragenResponse;
+import de.ozgcloud.nachrichten.antragraum.GrpcGetRueckfrageRequest;
+import de.ozgcloud.nachrichten.antragraum.GrpcGetRueckfrageResponse;
 import de.ozgcloud.nachrichten.antragraum.GrpcSendRueckfrageAnswerRequest;
 import de.ozgcloud.nachrichten.antragraum.GrpcSendRueckfrageAnswerResponse;
-import de.ozgcloud.vorgang.grpc.command.CommandServiceGrpc;
-import de.ozgcloud.vorgang.grpc.command.GrpcCommand;
-import de.ozgcloud.vorgang.grpc.command.GrpcGetCommandRequest;
 import lombok.NonNull;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.log4j.Log4j2;
@@ -58,32 +57,32 @@ public class NachrichtenGrpcClient {
 		return antragraumServiceBlockingStub.findRueckfragen(request);
 	}
 
-	GrpcSendRueckfrageAnswerResponse answerRueckfrage(GrpcSendRueckfrageAnswerRequest request, String address) {
+	GrpcGetRueckfrageResponse getGetRueckfrage(GrpcGetRueckfrageRequest request, String address) {
 		try (GrpcChannelFactory channelFactory = getChannelFactory(address)) {
 			var channel = channelFactory.createChannel(address);
 			var antragsServiceBlockingStub = AntragraumServiceGrpc.newBlockingStub(channel);
 
-			return getAnswerResponse(request, antragsServiceBlockingStub);
+			return getGrpcGetRueckfrageResponse(request, antragsServiceBlockingStub);
 		}
 	}
 
-	GrpcSendRueckfrageAnswerResponse getAnswerResponse(GrpcSendRueckfrageAnswerRequest request,
+	GrpcGetRueckfrageResponse getGrpcGetRueckfrageResponse(GrpcGetRueckfrageRequest request,
 	  AntragraumServiceGrpc.AntragraumServiceBlockingStub antragraumServiceBlockingStub) {
-		return antragraumServiceBlockingStub.sendRueckfrageAnswer(request);
+		return antragraumServiceBlockingStub.getRueckfrage(request);
 	}
 
-	GrpcCommand getCommand(String address, String commandId) {
+	GrpcSendRueckfrageAnswerResponse answerRueckfrage(GrpcSendRueckfrageAnswerRequest request, String address) {
 		try (GrpcChannelFactory channelFactory = getChannelFactory(address)) {
 			var channel = channelFactory.createChannel(address);
-			var commandServiceBlockingStub = CommandServiceGrpc.newBlockingStub(channel);
+			var antragsServiceBlockingStub = AntragraumServiceGrpc.newBlockingStub(channel);
 
-			return getGrpcCommand(commandServiceBlockingStub, GrpcGetCommandRequest.newBuilder().setId(commandId).build());
+			return getAnswerResponse(request, antragsServiceBlockingStub);
 		}
 	}
 
-	GrpcCommand getGrpcCommand(CommandServiceGrpc.CommandServiceBlockingStub commandServiceBlockingStub,
-	  GrpcGetCommandRequest request) {
-		return commandServiceBlockingStub.getCommand(request);
+	GrpcSendRueckfrageAnswerResponse getAnswerResponse(GrpcSendRueckfrageAnswerRequest request,
+	  AntragraumServiceGrpc.AntragraumServiceBlockingStub antragraumServiceBlockingStub) {
+		return antragraumServiceBlockingStub.sendRueckfrageAnswer(request);
 	}
 
 	GrpcChannelFactory getChannelFactory(String channelAddress) {
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/nachricht/NachrichtenRemoteService.java b/server/src/main/java/de/ozgcloud/antragsraum/nachricht/NachrichtenRemoteService.java
index b4c443f65a5f9f51c7b8d86e84b3ce7947524bcc..3256fd9bfddbf7d1e13cf431810803489e65cb71 100644
--- a/server/src/main/java/de/ozgcloud/antragsraum/nachricht/NachrichtenRemoteService.java
+++ b/server/src/main/java/de/ozgcloud/antragsraum/nachricht/NachrichtenRemoteService.java
@@ -22,21 +22,15 @@ package de.ozgcloud.antragsraum.nachricht;
 
 import java.util.List;
 import java.util.Objects;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.context.SecurityContextHolder;
+import java.util.Optional;
+
 import org.springframework.stereotype.Service;
 
 import de.ozgcloud.antragsraum.callcontext.ContextService;
-import de.ozgcloud.antragsraum.common.SendTimeoutException;
-import de.ozgcloud.antragsraum.common.TechnicalException;
+import de.ozgcloud.antragsraum.command.CommandReference;
+import de.ozgcloud.antragsraum.events.NachrichtEvent;
 import de.ozgcloud.nachrichten.antragraum.GrpcFindRueckfragenRequest;
+import de.ozgcloud.nachrichten.antragraum.GrpcGetRueckfrageRequest;
 import de.ozgcloud.nachrichten.antragraum.GrpcSendRueckfrageAnswerRequest;
 import de.ozgcloud.nachrichten.antragraum.GrpcSendRueckfrageAnswerResponse;
 import io.grpc.StatusRuntimeException;
@@ -48,80 +42,59 @@ import lombok.extern.log4j.Log4j2;
 @Log4j2
 @RequiredArgsConstructor
 class NachrichtenRemoteService {
-	public static final String STATUS_FINISHED = "FINISHED";
-
-	private final @NonNull NachrichtenGrpcClient grpcClient;
-	private final @NonNull NachrichtProperties properties;
+	private final @NonNull NachrichtenGrpcClient nachrichtenGrpcClient;
 	private final @NonNull ContextService contextService;
 	private final @NonNull NachrichtMapper nachrichtMapper;
 
-	List<Nachricht> findRueckfragen(String postfachId, String address) {
+	List<NachrichtHeader> findRueckfrageHeads(NachrichtEvent event) {
 		try {
-			var rfBuilder = GrpcFindRueckfragenRequest.newBuilder()
-			  .setSamlToken(contextService.getSamlResponse())
-			  .setPostfachId(postfachId);
+			var rfBuilder = GrpcFindRueckfragenRequest.newBuilder().setPostfachId(event.postfachId());
 			if (Objects.nonNull(contextService.getSamlResponse())) {
 				rfBuilder.setSamlToken(contextService.getSamlResponse());
 			}
-			var reply = grpcClient.getFindRueckfragen(rfBuilder.build(), address);
 
-			return reply.getRueckfrageList().stream()
-			  .map(rueckfrage -> nachrichtMapper.fromGrpcRueckfrage(rueckfrage, address)).toList();
+			var reply = nachrichtenGrpcClient.getFindRueckfragen(rfBuilder.build(), event.address());
+			var rueckfrageHeads = reply.getRueckfrageHeadList();
+			LOG.info("{} RueckfrageHeads für Postfach ID {} erhalten", rueckfrageHeads.size(), event.postfachId());
+
+			return rueckfrageHeads.stream().map(rueckfrageHead -> NachrichtHeaderMapper.fromGrpcRueckfrageHead(rueckfrageHead, event.id())).toList();
 		} catch (StatusRuntimeException e) {
-			LOG.error("Error loading nachricht of postfach " + postfachId, e);
+			LOG.error("Error beim Laden der RueckfrageHeads für das Postfach {}", event.postfachId(), e);
 		}
 
 		return List.of();
 	}
 
-	boolean sendAnswer(ReplyNachricht nachricht, String address) {
-		GrpcSendRueckfrageAnswerResponse response = grpcClient.answerRueckfrage(
-		  GrpcSendRueckfrageAnswerRequest.newBuilder()
-			.setAnswer(nachrichtMapper.toGrpcRueckfrageAnswer(nachricht))
-			.setSamlToken(contextService.getSamlResponse())
-			.build(), address);
-
-		return waitUntilCommandIsFinished(address, response.getCommandId());
-	}
-
-	boolean waitUntilCommandIsFinished(String address, String commandId) {
-		var auth = SecurityContextHolder.getContext().getAuthentication();
-		ExecutorService executor = Executors.newSingleThreadScheduledExecutor();
-		Future<Boolean> future = executor.submit(() -> checkCommandIsFinished(address, commandId, auth));
+	Optional<Nachricht> getRueckfrage(String rueckfrageId, NachrichtEvent event) {
 		try {
-			return getSendResult(future);
-		} catch (InterruptedException e) {
-			Thread.currentThread().interrupt();
-			throw new TechnicalException(e);
-		} catch (ExecutionException e) {
-			throw new TechnicalException(e);
-		} catch (TimeoutException e) {
-			throw new SendTimeoutException(commandId, e);
-		} finally {
-			try {
-				executor.shutdown();
-			} catch (Exception e) {
-				LOG.error("Error shutting down executor. Closing it", e);
-				executor.close();
+			var rfBuilder = GrpcGetRueckfrageRequest.newBuilder().setId(rueckfrageId);
+			if (Objects.nonNull(contextService.getSamlResponse())) {
+				rfBuilder.setSamlToken(contextService.getSamlResponse());
 			}
-		}
-	}
-
-	Boolean checkCommandIsFinished(String address, String commandId, Authentication auth) throws InterruptedException {
-		SecurityContextHolder.getContext().setAuthentication(auth);
 
-		boolean notFinished = true;
-		while (notFinished) {
-			var resCommand = grpcClient.getCommand(address, commandId);
-			notFinished = !STATUS_FINISHED.equals(resCommand.getStatus());
+			var reply = nachrichtenGrpcClient.getGetRueckfrage(rfBuilder.build(), event.address());
+			var rueckfrage = reply.getRueckfrage();
+			LOG.info("Rueckfrage [{}] für ID {} erhalten", rueckfrage, rueckfrageId);
 
-			TimeUnit.MILLISECONDS.sleep(properties.getSendPollIntervalDuration().toMillis());
+			return Optional.of(nachrichtMapper.fromGrpcRueckfrage(reply.getRueckfrage(), event.id()));
+		} catch (StatusRuntimeException e) {
+			LOG.error("Error beim Laden der Rueckfrage mit ID {}", rueckfrageId, e);
 		}
 
-		return true;
+		return Optional.empty();
 	}
 
-	Boolean getSendResult(Future<Boolean> future) throws InterruptedException, ExecutionException, TimeoutException {
-		return future.get(properties.getTimeoutDuration().toMillis(), TimeUnit.MILLISECONDS);
+	CommandReference sendAnswer(ReplyNachricht nachricht, String address) {
+		var request = GrpcSendRueckfrageAnswerRequest.newBuilder()
+		  .setAnswer(nachrichtMapper.toGrpcRueckfrageAnswer(nachricht))
+		  .setSamlToken(contextService.getSamlResponse())
+		  .build();
+
+		GrpcSendRueckfrageAnswerResponse response = nachrichtenGrpcClient.answerRueckfrage(request, address);
+
+		return CommandReference.builder()
+		  .id(response.getCommandId())
+		  .nachrichtEventId(nachricht.nachrichtEventId())
+		  .build();
 	}
 }
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/nachricht/NachrichtenService.java b/server/src/main/java/de/ozgcloud/antragsraum/nachricht/NachrichtenService.java
index da45fe6538dbf0046628a02b8778c8fc8658471c..4957d99651f5c2944e7b85fb5abad73bff17cfe4 100644
--- a/server/src/main/java/de/ozgcloud/antragsraum/nachricht/NachrichtenService.java
+++ b/server/src/main/java/de/ozgcloud/antragsraum/nachricht/NachrichtenService.java
@@ -29,7 +29,8 @@ import java.util.List;
 
 import org.springframework.stereotype.Service;
 
-import de.ozgcloud.antragsraum.common.InsufficientTrustLevelException;
+import de.ozgcloud.antragsraum.command.CommandReference;
+import de.ozgcloud.antragsraum.common.NotAccessibleException;
 import de.ozgcloud.antragsraum.events.NachrichtEvent;
 import de.ozgcloud.antragsraum.events.NachrichtEventService;
 import lombok.NonNull;
@@ -40,57 +41,58 @@ import lombok.extern.log4j.Log4j2;
 @Service
 @RequiredArgsConstructor
 class NachrichtenService {
-	static final String TOPIC_LINK_RELATIONSHIP_NAME = "topic";
+	static final String RUECKFRAGE_LINK_RELATIONSHIP_NAME = "rueckfrage";
 
 	private final @NonNull NachrichtEventService nachrichtEventService;
 	private final @NonNull NachrichtenRemoteService nachrichtenRemoteService;
-	private final @NonNull NachrichtenTrustLevelService nachrichtenTrustLevelService;
 
-	List<TopicHeader> getTopicHeadersOfPostfach(String postfachId) {
-		var topicHeaders = TopicHeaderMapper.fromNachrichten(getRueckfragenOfPostfach(postfachId));
+	List<RueckfrageHeader> getRueckfrageHeadersOfPostfach(String postfachId) {
+		var headers = RueckfrageHeaderMapper.fromNachrichtHeaders(getNachrichtHeadersOfPostfach(postfachId));
+		linkRueckfrageHeaders(headers);
 
-		return linkTopicHeaders(topicHeaders, postfachId);
+		return headers;
 	}
 
-	private List<TopicHeader> linkTopicHeaders(List<TopicHeader> topicHeaders, String postfachId) {
-		return topicHeaders.stream().peek(topicHeader -> {
-			topicHeader.add(linkTo(NachrichtenController.class).withSelfRel());
+	Collection<NachrichtHeader> getNachrichtHeadersOfPostfach(String postfachId) {
+		var events = nachrichtEventService.getNachrichtEventsOfPostfachId(postfachId);
 
-			if (nachrichtenTrustLevelService.nachrichtMatchesUserTrustLevel(topicHeader.getTrustLevel())) {
-				topicHeader.add(
-				  linkTo(methodOn(NachrichtenController.class).getTopicOfPostfach(postfachId, topicHeader.getClerkMessage().id())).withRel(
-					TOPIC_LINK_RELATIONSHIP_NAME));
-			}
-		}).toList();
+		return events.stream().map(this::getNachrichtHeadersOfEvent).flatMap(List::stream).toList();
 	}
 
-	Topic getTopicOfPostfach(String postfachId, String rueckfrageId) {
-		var topic = TopicMapper.fromNachricht(getRueckfrageById(postfachId, rueckfrageId));
+	private List<NachrichtHeader> getNachrichtHeadersOfEvent(final NachrichtEvent event) {
+		var nachrichtHeaders = nachrichtenRemoteService.findRueckfrageHeads(event);
+		LOG.debug("{} NachrichtHeaders für Postfach ID {} erhalten", nachrichtHeaders.size(), event.postfachId());
 
-		if (!nachrichtenTrustLevelService.nachrichtMatchesUserTrustLevel(topic.getTrustLevel())) {
-			throw new InsufficientTrustLevelException(rueckfrageId);
-		}
-
-		return topic;
+		return nachrichtHeaders;
 	}
 
-	private Nachricht getRueckfrageById(String postfachId, String rueckfrageId) {
-		return getRueckfragenOfPostfach(postfachId).stream().filter(nachricht -> nachricht.id().equals(rueckfrageId)).findFirst().orElseThrow();
+	private void linkRueckfrageHeaders(List<RueckfrageHeader> headers) {
+		headers.forEach(header -> {
+			header.add(linkTo(NachrichtenController.class).withSelfRel());
+
+			var nachrichtHeader = header.getNachrichtHeader();
+			if (nachrichtHeader.accessible()) {
+				header.add(
+				  linkTo(methodOn(NachrichtenController.class).getRueckfrage(nachrichtHeader.id(), nachrichtHeader.nachrichtEventId())).withRel(
+					RUECKFRAGE_LINK_RELATIONSHIP_NAME));
+			}
+		});
 	}
 
-	Collection<Nachricht> getRueckfragenOfPostfach(String postfachId) {
-		var events = nachrichtEventService.getNachrichtEventsOfPostfachId(postfachId);
+	Rueckfrage getRueckfrage(String rueckfrageId, String nachrichtEventId) {
+		var nachrichtEvent = nachrichtEventService.getNachrichtEventById(nachrichtEventId);
+		var nachricht = nachrichtenRemoteService.getRueckfrage(rueckfrageId, nachrichtEvent).orElseThrow();
 
-		return events.stream().map(this::getNachrichtenOfEvent).flatMap(List::stream).toList();
-	}
+		if (!nachricht.accessible()) {
+			throw new NotAccessibleException(rueckfrageId);
+		}
 
-	private List<Nachricht> getNachrichtenOfEvent(final NachrichtEvent event) {
-		return nachrichtenRemoteService.findRueckfragen(event.postfachId(), event.address());
+		return RueckfrageMapper.fromNachricht(nachricht);
 	}
 
-	ReplyNachricht sendRueckfrageAnswer(final ReplyNachricht nachricht) {
-		nachrichtenRemoteService.sendAnswer(nachricht, nachricht.address());
+	CommandReference sendRueckfrageAnswer(final ReplyNachricht nachricht) {
+		var nachrichtEvent = nachrichtEventService.getNachrichtEventById(nachricht.nachrichtEventId());
 
-		return nachricht;
+		return nachrichtenRemoteService.sendAnswer(nachricht, nachrichtEvent.address());
 	}
 }
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/nachricht/NachrichtenTrustLevelService.java b/server/src/main/java/de/ozgcloud/antragsraum/nachricht/NachrichtenTrustLevelService.java
deleted file mode 100644
index 46da0380e57f3905fa7c814dfde813163afdd0b7..0000000000000000000000000000000000000000
--- a/server/src/main/java/de/ozgcloud/antragsraum/nachricht/NachrichtenTrustLevelService.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (c) 2024.   Das Land Schleswig-Holstein vertreten durch den Ministerpräsidenten
- * des Landes Schleswig-Holstein Staatskanzlei Abteilung Digitalisierung und zentrales IT-Management der Landesregierung.
- *
- * Lizenziert unter der EUPL, Version 1.2 oder - sobald
- * diese von der Europäischen Kommission genehmigt wurden -
- * Folgeversionen der EUPL ("Lizenz");
- * Sie dürfen dieses Werk ausschließlich gemäß
- * dieser Lizenz nutzen.
- * Eine Kopie der Lizenz finden Sie hier:
- *
- * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
- *
- * Sofern nicht durch anwendbare Rechtsvorschriften
- * gefordert oder in schriftlicher Form vereinbart, wird
- * die unter der Lizenz verbreitete Software "so wie sie
- * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
- * ausdrücklich oder stillschweigend - verbreitet.
- * Die sprachspezifischen Genehmigungen und Beschränkungen
- * unter der Lizenz sind dem Lizenztext zu entnehmen.
- */
-
-package de.ozgcloud.antragsraum.nachricht;
-
-import org.springframework.security.core.context.SecurityContextHolder;
-import org.springframework.security.core.userdetails.UserDetails;
-import org.springframework.security.web.authentication.session.SessionAuthenticationException;
-import org.springframework.stereotype.Service;
-
-import de.ozgcloud.antragsraum.security.User;
-import de.ozgcloud.antragsraum.security.UserTrustLevel;
-
-@Service
-public class NachrichtenTrustLevelService {
-	boolean nachrichtMatchesUserTrustLevel(NachrichtTrustLevel nachrichtTrustLevel) {
-		var userTrustLevel = getCurrentUser().getTrustLevel();
-		if (userTrustLevel == null) {
-			return false;
-		}
-
-		if (nachrichtTrustLevel == null || NachrichtTrustLevel.LOW.equals(nachrichtTrustLevel)) {
-			return true;
-		}
-
-		if (UserTrustLevel.STORK_QAA_LEVEL_4.equals(userTrustLevel)) {
-			return true;
-		}
-
-		if (UserTrustLevel.STORK_QAA_LEVEL_3.equals(userTrustLevel)) {
-			return NachrichtTrustLevel.SUBSTANTIAL.equals(nachrichtTrustLevel);
-		}
-
-		return false;
-	}
-
-	private User getCurrentUser() {
-		var authentication = SecurityContextHolder.getContext().getAuthentication();
-		if (authentication != null && authentication.getPrincipal() instanceof UserDetails) {
-			return (User) authentication.getPrincipal();
-		}
-
-		throw new SessionAuthenticationException("Current user is null");
-	}
-}
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/nachricht/ReplyNachricht.java b/server/src/main/java/de/ozgcloud/antragsraum/nachricht/ReplyNachricht.java
index ffa148c2522be71b283d71f888f59db9f9e7a049..76e071aecb2a1d11737c2c973e3c3747340ec545 100644
--- a/server/src/main/java/de/ozgcloud/antragsraum/nachricht/ReplyNachricht.java
+++ b/server/src/main/java/de/ozgcloud/antragsraum/nachricht/ReplyNachricht.java
@@ -22,7 +22,6 @@ package de.ozgcloud.antragsraum.nachricht;
 
 import java.util.List;
 
-import jakarta.validation.constraints.Min;
 import jakarta.validation.constraints.NotEmpty;
 import jakarta.validation.constraints.Size;
 
@@ -44,12 +43,12 @@ public record ReplyNachricht(
 	example = "28721c6f-b78f-4d5c-a048-19fd2fc429d2"
   )
   String postfachId,
-  @Schema(description = "The address of the OZG-Cloud instanz the reply belongs to",
-	name = "address",
+  @Schema(description = "The id of the NachrichtEvent in the InfoManager the reply belongs to",
+	name = "nachrichtEventId",
 	type = "string",
-	example = "static://utopia.sh.ozg-cloud.de:9090"
+	example = "60af924b4f1a2560298b4567"
   )
-  String address,
+  String nachrichtEventId,
   @Schema(description = "The encoded address of the OZG-Cloud instanz the reply belongs to",
 	name = "id",
 	type = "string",
@@ -64,9 +63,6 @@ public record ReplyNachricht(
   )
   @Size(max = 500000, message = "message too long")
   String message,
-  @Schema(description = "The answered date. Only set when displaying an already answered Rueckfrage. Will be set by the OZG-Cloud")
-  @Min(0)
-  long date,
   @Schema(description = "The list of the attached file ids. Only the file id is used when sending the reply, The other values are set by the backend")
   List<OzgFile> attachments) {
 }
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/nachricht/Topic.java b/server/src/main/java/de/ozgcloud/antragsraum/nachricht/Rueckfrage.java
similarity index 71%
rename from server/src/main/java/de/ozgcloud/antragsraum/nachricht/Topic.java
rename to server/src/main/java/de/ozgcloud/antragsraum/nachricht/Rueckfrage.java
index 4d685bede737e16af80aaf0716ee6192b77bcedc..c6654dabfc51e2dba0de629513fee4ea5cc9bbfc 100644
--- a/server/src/main/java/de/ozgcloud/antragsraum/nachricht/Topic.java
+++ b/server/src/main/java/de/ozgcloud/antragsraum/nachricht/Rueckfrage.java
@@ -30,26 +30,37 @@ import lombok.Getter;
 
 @Builder
 @Getter
-public class Topic {
-	@Schema(description = "The title of the topic. This is the title of the Vorgang",
-	  name = "topicTitle",
+public class Rueckfrage {
+	@Schema(description = "The title of the Rueckfrage. This is the title of the Vorgang",
+	  name = "title",
 	  type = "string",
 	  example = "Vorgang Hundesteuer Antrag"
 	)
-	String topicTitle;
+	String title;
+	@Schema(description = "The status of the Rueckfrage.",
+	  name = "status",
+	  type = "string",
+	  example = "ANSWERED"
+	)
+	String status;
 	@Schema(description = "The Rueckfrage sent by the clerk",
-	  name = "clerkMessage",
+	  name = "nachricht",
 	  type = "Nachricht"
 	)
-	Nachricht clerkMessage;
+	Nachricht nachricht;
+	@Schema(description = "Whether the Rueckfrage is accessible for current user or not",
+	  name = "accessible",
+	  type = "boolean"
+	)
+	boolean accessible;
 	@Schema(description = "The trust level of the Rueckfrage sent by the clerk",
 	  name = "trustLevel",
-	  type = "NachrichtTrustLevel"
+	  type = "string"
 	)
-	NachrichtTrustLevel trustLevel;
+	String trustLevel;
 	@Schema(description = "The reply to the Rueckfrage",
-	  name = "userMessage",
+	  name = "antworten",
 	  type = "ReplyNachricht"
 	)
-	List<ReplyNachricht> userMessages;
+	List<ReplyNachricht> antworten;
 }
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/nachricht/TopicHeader.java b/server/src/main/java/de/ozgcloud/antragsraum/nachricht/RueckfrageHeader.java
similarity index 69%
rename from server/src/main/java/de/ozgcloud/antragsraum/nachricht/TopicHeader.java
rename to server/src/main/java/de/ozgcloud/antragsraum/nachricht/RueckfrageHeader.java
index 0229a5d7beb47f399d19bd33254f62799e064cfa..b38d58e6fc85c6dc54c7cdf2e85d6bb3bea186ea 100644
--- a/server/src/main/java/de/ozgcloud/antragsraum/nachricht/TopicHeader.java
+++ b/server/src/main/java/de/ozgcloud/antragsraum/nachricht/RueckfrageHeader.java
@@ -26,25 +26,37 @@ import org.springframework.hateoas.RepresentationModel;
 
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Builder;
+import lombok.EqualsAndHashCode;
 import lombok.Getter;
 
 @Builder
 @Getter
-public class TopicHeader extends RepresentationModel<TopicHeader> {
-	@Schema(description = "The title of the topic. This is the title of the Vorgang",
-	  name = "topicTitle",
+@EqualsAndHashCode(callSuper = true)
+public class RueckfrageHeader extends RepresentationModel<RueckfrageHeader> {
+	@Schema(description = "The title of the rueckfrage. This is the title of the Vorgang",
+	  name = "title",
 	  type = "string",
 	  example = "Vorgang Hundesteuer Antrag"
 	)
-	String topicTitle;
+	String title;
 	@Schema(description = "The header of the Rueckfrage sent by the clerk",
-	  name = "clerkMessage",
+	  name = "nachrichtHeader",
 	  type = "NachrichtHeader"
 	)
-	NachrichtHeader clerkMessage;
+	NachrichtHeader nachrichtHeader;
+	@Schema(description = "Whether the Rueckfrage is accessible for current user or not",
+	  name = "accessible",
+	  type = "boolean"
+	)
+	boolean accessible;
 	@Schema(description = "The trust level of the Rueckfrage sent by the clerk",
 	  name = "trustLevel",
-	  type = "NachrichtTrustLevel"
+	  type = "string"
+	)
+	String trustLevel;
+	@Schema(description = "Status of the Rueckfrage",
+	  name = "status",
+	  type = "String"
 	)
-	NachrichtTrustLevel trustLevel;
+	String status;
 }
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/nachricht/TopicMapper.java b/server/src/main/java/de/ozgcloud/antragsraum/nachricht/RueckfrageHeaderMapper.java
similarity index 60%
rename from server/src/main/java/de/ozgcloud/antragsraum/nachricht/TopicMapper.java
rename to server/src/main/java/de/ozgcloud/antragsraum/nachricht/RueckfrageHeaderMapper.java
index da6ac2c5c5194d36c2eec5cac04b4851cc4b8fa2..a69bb75c3e63bb9efcedf89b1223a57af4248937 100644
--- a/server/src/main/java/de/ozgcloud/antragsraum/nachricht/TopicMapper.java
+++ b/server/src/main/java/de/ozgcloud/antragsraum/nachricht/RueckfrageHeaderMapper.java
@@ -22,31 +22,28 @@
 
 package de.ozgcloud.antragsraum.nachricht;
 
+import java.util.Collection;
 import java.util.List;
 
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
+import lombok.extern.log4j.Log4j2;
 
+@Log4j2
 @NoArgsConstructor(access = AccessLevel.PRIVATE)
-class TopicMapper {
-	static Topic fromNachricht(Nachricht nachricht) {
-		var clerkMessage = nachricht.toBuilder().replyNachrichten(null).build();
-
-		return Topic.builder()
-		  .topicTitle(nachricht.topicTitle())
-		  .clerkMessage(clerkMessage)
-		  .trustLevel(NachrichtTrustLevel.LOW)
-		  .userMessages(createUserNachricht(nachricht.replyNachrichten()))
-		  .build();
+class RueckfrageHeaderMapper {
+	static List<RueckfrageHeader> fromNachrichtHeaders(Collection<NachrichtHeader> nachrichtHeaders) {
+		return nachrichtHeaders.stream().map(RueckfrageHeaderMapper::fromNachrichtHeader).toList();
 	}
 
-	private static List<ReplyNachricht> createUserNachricht(List<ReplyNachricht> replyNachrichten) {
-		return replyNachrichten.stream().map(replyNachricht -> ReplyNachricht.builder()
-		  .id(replyNachricht.id())
-		  .address(replyNachricht.address())
-		  .message(replyNachricht.message())
-		  .date(replyNachricht.date())
-		  .attachments(replyNachricht.attachments())
-		  .build()).toList();
+	private static RueckfrageHeader fromNachrichtHeader(NachrichtHeader nachrichtHeader) {
+		LOG.info("Mapping NachrichtHeader [{}] to RueckfrageHeader", nachrichtHeader);
+		return RueckfrageHeader.builder()
+		  .title(nachrichtHeader.title())
+		  .nachrichtHeader(nachrichtHeader)
+		  .trustLevel(nachrichtHeader.trustLevel())
+		  .accessible(nachrichtHeader.accessible())
+		  .status(nachrichtHeader.status())
+		  .build();
 	}
 }
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/nachricht/TopicHeaderMapper.java b/server/src/main/java/de/ozgcloud/antragsraum/nachricht/RueckfrageMapper.java
similarity index 68%
rename from server/src/main/java/de/ozgcloud/antragsraum/nachricht/TopicHeaderMapper.java
rename to server/src/main/java/de/ozgcloud/antragsraum/nachricht/RueckfrageMapper.java
index f20f91e4dc4d1a73b2348aa0e6473cc83721bde5..6bc1c707b2a09166962422a0547c4473151eba2f 100644
--- a/server/src/main/java/de/ozgcloud/antragsraum/nachricht/TopicHeaderMapper.java
+++ b/server/src/main/java/de/ozgcloud/antragsraum/nachricht/RueckfrageMapper.java
@@ -22,23 +22,24 @@
 
 package de.ozgcloud.antragsraum.nachricht;
 
-import java.util.Collection;
-import java.util.List;
-
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
+import lombok.extern.log4j.Log4j2;
 
+@Log4j2
 @NoArgsConstructor(access = AccessLevel.PRIVATE)
-class TopicHeaderMapper {
-	static List<TopicHeader> fromNachrichten(Collection<Nachricht> nachrichten) {
-		return nachrichten.stream().map(TopicHeaderMapper::fromNachricht).toList();
-	}
+class RueckfrageMapper {
+	static Rueckfrage fromNachricht(Nachricht nachricht) {
+		var clerkNachricht = nachricht.toBuilder().replyNachrichten(null).build();
 
-	private static TopicHeader fromNachricht(Nachricht nachricht) {
-		return TopicHeader.builder()
-		  .topicTitle(nachricht.topicTitle())
-		  .clerkMessage(NachrichtHeaderMapper.fromNachricht(nachricht))
-		  .trustLevel(NachrichtTrustLevel.LOW)
+		LOG.info("Mapping Nachricht [{}] to Rueckfrage", nachricht);
+		return Rueckfrage.builder()
+		  .title(nachricht.title())
+		  .nachricht(clerkNachricht)
+		  .trustLevel(nachricht.trustLevel())
+		  .accessible(nachricht.accessible())
+		  .status(nachricht.status())
+		  .antworten(nachricht.replyNachrichten())
 		  .build();
 	}
 }
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/nachricht/TrustLevelMapper.java b/server/src/main/java/de/ozgcloud/antragsraum/nachricht/TrustLevelMapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..3c856c5f286d16eddaafd5ce82f495c51304c2ad
--- /dev/null
+++ b/server/src/main/java/de/ozgcloud/antragsraum/nachricht/TrustLevelMapper.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2023-2024.
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+
+package de.ozgcloud.antragsraum.nachricht;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import lombok.extern.log4j.Log4j2;
+
+@Log4j2
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+class TrustLevelMapper {
+	static final String TRUST_LEVEL_STORK_QAA_LEVEL_1 = "STORK-QAA-Level-1";
+	static final String TRUST_LEVEL_STORK_QAA_LEVEL_2 = "STORK-QAA-Level-2";
+	static final String TRUST_LEVEL_STORK_QAA_LEVEL_3 = "STORK-QAA-Level-3";
+	static final String TRUST_LEVEL_STORK_QAA_LEVEL_4 = "STORK-QAA-Level-4";
+	static final String TRUST_LEVEL_LOW = "LOW";
+	static final String TRUST_LEVEL_SUBSTANTIAL = "SUBSTANTIAL";
+	static final String TRUST_LEVEL_HIGH = "HIGH";
+
+	static String map(String trustLevel) {
+		var result = switch (trustLevel) {
+			case TRUST_LEVEL_LOW, TRUST_LEVEL_SUBSTANTIAL, TRUST_LEVEL_HIGH -> trustLevel;
+			case TRUST_LEVEL_STORK_QAA_LEVEL_3 -> TRUST_LEVEL_SUBSTANTIAL;
+			case TRUST_LEVEL_STORK_QAA_LEVEL_4 -> TRUST_LEVEL_HIGH;
+			default -> TRUST_LEVEL_LOW;
+		};
+
+		LOG.debug("Mapping trust level {} to {}", trustLevel, result);
+		return result;
+	}
+}
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/security/InMemoryUserDetailService.java b/server/src/main/java/de/ozgcloud/antragsraum/security/InMemoryUserDetailService.java
index b0fe8ede9d10719fc48842495a3043e7db414623..3cf3fb6d54c788490d00144859e396445259deb5 100644
--- a/server/src/main/java/de/ozgcloud/antragsraum/security/InMemoryUserDetailService.java
+++ b/server/src/main/java/de/ozgcloud/antragsraum/security/InMemoryUserDetailService.java
@@ -20,19 +20,7 @@
 
 package de.ozgcloud.antragsraum.security;
 
-import com.google.common.cache.Cache;
-import com.google.common.cache.CacheBuilder;
-import de.ozgcloud.antragsraum.common.NotFoundException;
-import lombok.NoArgsConstructor;
-import lombok.extern.log4j.Log4j2;
-import org.apache.commons.lang3.RandomStringUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.scheduling.annotation.Scheduled;
-import org.springframework.security.core.userdetails.UserDetails;
-import org.springframework.security.core.userdetails.UserDetailsService;
-import org.springframework.stereotype.Service;
-
+import java.security.SecureRandom;
 import java.time.ZoneId;
 import java.time.ZonedDateTime;
 import java.util.Date;
@@ -42,6 +30,21 @@ import java.util.Optional;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.TimeUnit;
 
+import org.apache.commons.lang3.RandomStringUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.stereotype.Service;
+
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+
+import de.ozgcloud.antragsraum.common.NotFoundException;
+import lombok.NoArgsConstructor;
+import lombok.extern.log4j.Log4j2;
+
 @Service
 @NoArgsConstructor
 @Log4j2
@@ -57,8 +60,8 @@ public class InMemoryUserDetailService implements UserDetailsService {
 	private Cache<String, String> getTempIdCache() {
 		if (Objects.isNull(tmpTokenUserIdCache)) {
 			tmpTokenUserIdCache = CacheBuilder.newBuilder()
-					.expireAfterAccess(codeExpireSeconds, TimeUnit.SECONDS)
-					.build();
+			  .expireAfterAccess(codeExpireSeconds, TimeUnit.SECONDS)
+			  .build();
 		}
 
 		return tmpTokenUserIdCache;
@@ -105,23 +108,24 @@ public class InMemoryUserDetailService implements UserDetailsService {
 
 	Optional<User> getUser(AuthCode refreshCode) {
 		return usersMap.entrySet().stream()
-				.filter(entry -> refreshCode.code().equals(entry.getValue().getRefreshCode()))
-				.findFirst()
-				.filter(entry -> entry.getValue().isCredentialsNonExpired())
-				.map(Map.Entry::getValue);
+		  .filter(entry -> refreshCode.code().equals(entry.getValue().getRefreshCode()))
+		  .findFirst()
+		  .filter(entry -> entry.getValue().isCredentialsNonExpired())
+		  .map(Map.Entry::getValue);
 	}
 
 	public User updateRefreshCodeOf(User user) {
+		var token = RandomStringUtils.random(128, 0, 0, true, true, null, new SecureRandom());
 		var updated = user.toBuilder()
-				.refreshCode(RandomStringUtils.randomAlphanumeric(64))
-				.tokenExpiresAt(createExpirationDateTime()).build();
+		  .refreshCode(token)
+		  .tokenExpiresAt(createExpirationDateTime()).build();
 		usersMap.put(updated.getId(), updated);
 		return updated;
 	}
 
 	Date createExpirationDateTime() {
-		var nowInstant =ZonedDateTime.now(ZoneId.of("UTC")).plusMinutes(jwtExpirationMinutes).toInstant();
-		LOG.debug("Setting expiry date time to {}", Date.from(nowInstant).toString());
+		var nowInstant = ZonedDateTime.now(ZoneId.of("UTC")).plusMinutes(jwtExpirationMinutes).toInstant();
+		LOG.debug("Setting expiry answeredAt time to {}", Date.from(nowInstant).toString());
 		return new Date(nowInstant.toEpochMilli());
 	}
 
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/security/JwtTokenProvider.java b/server/src/main/java/de/ozgcloud/antragsraum/security/JwtTokenProvider.java
index a6211c04397b9fa43d1f34d70f2044becb45967e..9cbb6452423f6fdc0edebdc75a16f692706aaa6a 100644
--- a/server/src/main/java/de/ozgcloud/antragsraum/security/JwtTokenProvider.java
+++ b/server/src/main/java/de/ozgcloud/antragsraum/security/JwtTokenProvider.java
@@ -77,7 +77,7 @@ public class JwtTokenProvider {
 		  .claim("firstname", user.getFirstName())
 		  .claim("lastname", user.getLastName())
 		  .claim("postkorbhandle", user.getPostkorbHandle())
-		  .claim("trustlevel", user.getTrustLevel().getValue())
+		  .claim("trustlevel", user.getTrustLevel())
 		  .compact();
 	}
 }
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/security/SamlRedirectStrategy.java b/server/src/main/java/de/ozgcloud/antragsraum/security/SamlRedirectStrategy.java
index 535f6a603825508a30b737e5e7e2a736b2c8bb8d..e41cbd4fa8f4b492a9eebcb6ee7288d6ed179218 100644
--- a/server/src/main/java/de/ozgcloud/antragsraum/security/SamlRedirectStrategy.java
+++ b/server/src/main/java/de/ozgcloud/antragsraum/security/SamlRedirectStrategy.java
@@ -26,6 +26,7 @@ import java.util.UUID;
 import jakarta.servlet.http.HttpServletRequest;
 import jakarta.servlet.http.HttpServletResponse;
 
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.userdetails.UserDetailsService;
 import org.springframework.security.saml2.provider.service.authentication.Saml2Authentication;
@@ -36,11 +37,13 @@ import lombok.extern.log4j.Log4j2;
 @Log4j2
 public class SamlRedirectStrategy extends DefaultRedirectStrategy {
 	private final UserDetailsService userDetailsService;
+	private final String redirectUrl;
 	private String onetimeToken;
 
-	public SamlRedirectStrategy(UserDetailsService userDetailsService) {
+	public SamlRedirectStrategy(UserDetailsService userDetailsService, String redirectUrl) {
 		super();
 		this.userDetailsService = userDetailsService;
+		this.redirectUrl = redirectUrl;
 	}
 
 	public void sendRedirect(HttpServletRequest request, HttpServletResponse response, String url, Authentication authentication) throws IOException {
@@ -56,12 +59,17 @@ public class SamlRedirectStrategy extends DefaultRedirectStrategy {
 
 	@Override
 	public void sendRedirect(HttpServletRequest request, HttpServletResponse response, String url) throws IOException {
-		String redirectUrl = this.calculateRedirectUrl(request.getContextPath(), url);
-		redirectUrl = redirectUrl + "?code=" + onetimeToken;
-		redirectUrl = response.encodeRedirectURL(redirectUrl);
+		String calculateRedirectUrl = null;
+		if (StringUtils.isEmpty(redirectUrl)) {
+			calculateRedirectUrl = this.calculateRedirectUrl(request.getContextPath(), url) + "?code=" + onetimeToken;
+		} else {
+			calculateRedirectUrl = redirectUrl + "?code=" + onetimeToken;
+		}
+
+		calculateRedirectUrl = response.encodeRedirectURL(calculateRedirectUrl);
 
-		LOG.debug("Redirecting to {}", redirectUrl);
+		LOG.debug("Redirecting to {}", calculateRedirectUrl);
 
-		response.sendRedirect(redirectUrl);
+		response.sendRedirect(calculateRedirectUrl);
 	}
 }
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/security/SamlUrlAuthenticationSuccessHandler.java b/server/src/main/java/de/ozgcloud/antragsraum/security/SamlUrlAuthenticationSuccessHandler.java
index eca45243927ad3000e7804e69d45bedc31ac4bf9..0f125093103b170604199e9b56868b47d99fe21f 100644
--- a/server/src/main/java/de/ozgcloud/antragsraum/security/SamlUrlAuthenticationSuccessHandler.java
+++ b/server/src/main/java/de/ozgcloud/antragsraum/security/SamlUrlAuthenticationSuccessHandler.java
@@ -46,7 +46,7 @@ public class SamlUrlAuthenticationSuccessHandler implements AuthenticationSucces
 
 	public SamlUrlAuthenticationSuccessHandler(final String redirectUrl, final UserDetailsService userService) {
 		super();
-		redirectStrategy = new SamlRedirectStrategy(userService);
+		redirectStrategy = new SamlRedirectStrategy(userService, redirectUrl);
 		roleTargetUrlMap.put(DefaultRole.ROLE, getRedirectUrl(redirectUrl));
 	}
 
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/security/SecurityProvider.java b/server/src/main/java/de/ozgcloud/antragsraum/security/SecurityProvider.java
index f48b1d4c11f8d9ba6d52884a08b710c7f0083018..98ef48877071818e013cc6b844805e30a3d60c3a 100644
--- a/server/src/main/java/de/ozgcloud/antragsraum/security/SecurityProvider.java
+++ b/server/src/main/java/de/ozgcloud/antragsraum/security/SecurityProvider.java
@@ -34,10 +34,10 @@ public class SecurityProvider implements InitializingBean {
 	public void afterPropertiesSet() {
 		Security.addProvider(new BouncyCastleProvider());
 
-		registerMukSignatureAlgorithm();
+		registerSignatureAlgorithms();
 	}
 
-	private void registerMukSignatureAlgorithm() {
+	private void registerSignatureAlgorithms() {
 		var algorithmRegistry = ConfigurationService.get(AlgorithmRegistry.class);
 		if (algorithmRegistry != null) {
 			algorithmRegistry.register(new SHA256withRSAAndMGF1SignatureAlgorithm());
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/security/User.java b/server/src/main/java/de/ozgcloud/antragsraum/security/User.java
index ac1604191a152acb90aa8437914508b95f1cecb8..b181c2fcaf5b72ce42c2546a7b754605c6fa0cbf 100644
--- a/server/src/main/java/de/ozgcloud/antragsraum/security/User.java
+++ b/server/src/main/java/de/ozgcloud/antragsraum/security/User.java
@@ -20,16 +20,21 @@
 
 package de.ozgcloud.antragsraum.security;
 
-import lombok.Builder;
-import lombok.Getter;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
 import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.core.userdetails.UserDetails;
 import org.springframework.security.crypto.factory.PasswordEncoderFactories;
 import org.springframework.security.crypto.password.PasswordEncoder;
 
-import java.time.ZoneId;
-import java.time.ZonedDateTime;
-import java.util.*;
+import lombok.Builder;
+import lombok.Getter;
 
 @Builder(toBuilder = true)
 @Getter
@@ -39,7 +44,7 @@ public class User implements UserDetails {
 	private String firstName;
 	private String lastName;
 	private String postkorbHandle;
-	private UserTrustLevel trustLevel;
+	private String trustLevel;
 	private String username;
 	private String refreshCode;
 	private Date tokenExpiresAt;
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/security/UserMapper.java b/server/src/main/java/de/ozgcloud/antragsraum/security/UserMapper.java
index 312dd2caccbbec390581e640cef865db3bed4797..a95d1fbf3e2b73819acb1eceefc458a0f8e048e9 100644
--- a/server/src/main/java/de/ozgcloud/antragsraum/security/UserMapper.java
+++ b/server/src/main/java/de/ozgcloud/antragsraum/security/UserMapper.java
@@ -20,6 +20,7 @@
 
 package de.ozgcloud.antragsraum.security;
 
+import java.security.SecureRandom;
 import java.util.List;
 import java.util.Map;
 
@@ -42,6 +43,7 @@ class UserMapper {
 
 	static User map(Saml2Authentication authentication) {
 		DefaultSaml2AuthenticatedPrincipal principal = (DefaultSaml2AuthenticatedPrincipal) authentication.getPrincipal();
+		var token = RandomStringUtils.random(128, 0, 0, true, true, null, new SecureRandom());
 		return new User.UserBuilder()
 		  .id(principal.getName())
 		  .username(principal.getName())
@@ -50,7 +52,7 @@ class UserMapper {
 		  .postkorbHandle(getPostkornHandle(principal))
 		  .trustLevel(getTrustLevel(principal))
 		  .samlToken(authentication.getSaml2Response())
-		  .refreshCode(RandomStringUtils.randomAlphanumeric(64))
+		  .refreshCode(token)
 		  .unknownAttributes(getUnknownAttributes(principal.getAttributes()))
 		  .build();
 	}
@@ -67,10 +69,8 @@ class UserMapper {
 		return principal.getFirstAttribute(POSTKORB_HANDLE_URN);
 	}
 
-	static UserTrustLevel getTrustLevel(DefaultSaml2AuthenticatedPrincipal principal) {
-		var trustLevel = (String) principal.getFirstAttribute(VERTRAUENSNIVEAU_URN);
-
-		return UserTrustLevel.fromString(trustLevel);
+	static String getTrustLevel(DefaultSaml2AuthenticatedPrincipal principal) {
+		return principal.getFirstAttribute(VERTRAUENSNIVEAU_URN);
 	}
 
 	static List<Map.Entry<String, List<Object>>> getUnknownAttributes(Map<String, List<Object>> attributes) {
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/security/UserTrustLevel.java b/server/src/main/java/de/ozgcloud/antragsraum/security/UserTrustLevel.java
deleted file mode 100644
index 369957bb7f759ce774c9fcd5714868abbedca3ad..0000000000000000000000000000000000000000
--- a/server/src/main/java/de/ozgcloud/antragsraum/security/UserTrustLevel.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2024.   Das Land Schleswig-Holstein vertreten durch den Ministerpräsidenten
- * des Landes Schleswig-Holstein Staatskanzlei Abteilung Digitalisierung und zentrales IT-Management der Landesregierung.
- *
- * Lizenziert unter der EUPL, Version 1.2 oder - sobald
- * diese von der Europäischen Kommission genehmigt wurden -
- * Folgeversionen der EUPL ("Lizenz");
- * Sie dürfen dieses Werk ausschließlich gemäß
- * dieser Lizenz nutzen.
- * Eine Kopie der Lizenz finden Sie hier:
- *
- * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
- *
- * Sofern nicht durch anwendbare Rechtsvorschriften
- * gefordert oder in schriftlicher Form vereinbart, wird
- * die unter der Lizenz verbreitete Software "so wie sie
- * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
- * ausdrücklich oder stillschweigend - verbreitet.
- * Die sprachspezifischen Genehmigungen und Beschränkungen
- * unter der Lizenz sind dem Lizenztext zu entnehmen.
- */
-
-package de.ozgcloud.antragsraum.security;
-
-import java.util.Arrays;
-
-import lombok.Getter;
-import lombok.RequiredArgsConstructor;
-
-@RequiredArgsConstructor
-@Getter
-public enum UserTrustLevel {
-	STORK_QAA_LEVEL_1("STORK-QAA-Level-1"),
-	STORK_QAA_LEVEL_3("STORK-QAA-Level-3"),
-	STORK_QAA_LEVEL_4("STORK-QAA-Level-4");
-
-	private final String value;
-
-	public static UserTrustLevel fromString(String value) {
-		return Arrays.stream(UserTrustLevel.values()).filter(trustLevel -> trustLevel.getValue().equals(value)).findFirst().orElse(null);
-	}
-}
diff --git a/server/src/main/resources/application-lasttest.yml b/server/src/main/resources/application-lasttest.yml
new file mode 100644
index 0000000000000000000000000000000000000000..0ce3014835f68c801b422885eb63f55e166c6913
--- /dev/null
+++ b/server/src/main/resources/application-lasttest.yml
@@ -0,0 +1,103 @@
+management:
+  server:
+    port: 8081
+  health:
+    livenessState:
+      enabled: true
+    readinessState:
+      enabled: true
+  endpoint:
+    health:
+      group:
+        exploratory:
+          include: livenessState,readinessState,ping
+          show-details: always
+      probes:
+        enabled: true
+    prometheus:
+      enabled: true
+  endpoints:
+    web:
+      exposure:
+        include: health, info, prometheus
+
+ozgcloud:
+  antragsraum:
+    authOrigins:
+        - "http://localhost:8082"
+        - "http://localhost:8080"
+    apiOrigins:
+        - "http://localhost:8082"
+    otherOrigins:
+        - "http://localhost:8082"
+  code:
+    expire:
+      seconds: 30
+  jwt:
+    expiration:
+      minutes: 30
+  upload.max-file-size: 100MB
+  nachricht:
+    send:
+      timeout: 60s
+    poll:
+      interval: 2s
+  bayernid:
+    organizationDisplayName: Antragsraum
+    redirectUrl: "http://localhost:8082"
+    authnMethods:
+      Authega: "false"
+      Benutzername: "true"
+      eID: "false"
+      eIDAS: "false"
+      Diia: "false"
+      Elster: "true"
+      FINK: "false"
+    requestedAttributeUrns:
+      - "urn:oid:2.5.4.18"
+      - "urn:oid:1.3.6.1.4.1.25484.494450.3"
+      - "urn:oid:1.2.40.0.10.2.1.1.261.94"
+      - "urn:oid:1.3.6.1.4.1.25484.494450.2"
+      - "urn:oid:2.5.4.42"
+      - "urn:oid:2.5.4.4"
+      - "urn:oid:0.9.2342.19200300.100.1.3"
+
+server:
+  forward-headers-strategy: framework
+
+spring:
+  application:
+    name: Antragsraum
+  jackson:
+    deserialization:
+      adjust-dates-to-context-time-zone: false
+  servlet:
+    multipart:
+      max-file-size: 150MB
+      max-request-size: 2GB
+  security:
+    saml2:
+      relyingparty:
+        registration:
+          bayernid:
+            entity-id: http://mock-idp
+            signing:
+              credentials:
+                - private-key-location: "file:///mujina.key"
+                  certificate-location: "file:///mujina.crt"
+            decryption:
+              credentials:
+                - private-key-location: "file:///mujina.key"
+                  certificate-location: "file:///mujina.crt"
+            assertingparty:
+              singlesignon:
+                sign-request: true
+              metadata-uri: "http://lt-saml-idp:8080/metadata"
+logging:
+  level:
+    "org.springframework.security": INFO
+    "org.springframework.http": INFO
+    "org.springframework.web": INFO
+    "de.ozgcloud": DEBUG
+    "net.devh.boot.grpc": INFO
+    "de.ozgcloud.common.binaryfile": DEBUG
\ No newline at end of file
diff --git a/server/src/main/resources/application-local.yml b/server/src/main/resources/application-local.yml
index 2797463ceca490923fa901face3ca4edd000e74a..7df6137609e5088dd090451d81ae9bfbc9f12de9 100644
--- a/server/src/main/resources/application-local.yml
+++ b/server/src/main/resources/application-local.yml
@@ -12,7 +12,7 @@ grpc:
       enabled: true
 
 clamav:
-  scanUrl: http://127.0.0.1:3010/api/v1/scan
+  scanUrl: http://127.0.0.1:3000/api/v1/scan
   connection:
     timeoutInS: 10
   read:
@@ -20,42 +20,39 @@ clamav:
 
 logging:
   level:
-    "org.springframework.security": WARN
+    "org.springframework.security": DEBUG
     "org.springframework.security.access": WARN
     "org.springframework.http": WARN
     "org.springframework.web": WARN
-    "de.ozgcloud.antragsraum": INFO
+    "de.ozgcloud.antragsraum": DEBUG
     "net.devh.boot.grpc": INFO
     "de.ozgcloud.common.binaryfile": DEBUG
+  config: "server/src/main/resources/log4j2-local.xml"
 
 ozgcloud:
-  mock:
-    auth: true
-    password: test
   grpc:
     client:
       negotiation-type: PLAINTEXT
   jwt:
     secret: "346593nbdgb8e74t6vw477q34bg83456§$%/&Hgvt78hlsjdgfw8äy.skeiw44tz asjkdefa wlfugwegw"
-  antragsraum:
-    bayernid:
-      redirect-url: "http://localhost:8082"
+  bayernid:
+    redirectUrl: "http://localhost:8082"
 spring:
   security:
     saml2:
       relyingparty:
         registration:
           bayernid:
-            entity-id: https://antragsraum.ozgcloud.de/
+            entity-id: http://mock-idp
             signing:
               credentials:
-                - private-key-location: "classpath:/bayernid-local-sign.key"
-                  certificate-location: "classpath:/bayernid-local-sign.crt"
+                - private-key-location: "classpath:/mujina-local.key"
+                  certificate-location: "classpath:/mujina-local.crt"
             decryption:
               credentials:
-                - private-key-location: "classpath:/bayernid-local-enc.key"
-                  certificate-location: "classpath:/bayernid-local-enc.crt"
+                - private-key-location: "classpath:/mujina-local.key"
+                  certificate-location: "classpath:/mujina-local.crt"
             assertingparty:
               singlesignon:
                 sign-request: true
-              metadata-uri: "classpath:/metadata/bayernid-idp-infra.xml"
\ No newline at end of file
+              metadata-uri: "http://localhost:8088/metadata"
\ No newline at end of file
diff --git a/server/src/main/resources/application.yml b/server/src/main/resources/application.yml
index 98a2fb2c6d747298d4b56dd89d1d69ef2a570c33..0fb62c021a15fd01c340a9540899698dce0cb059 100644
--- a/server/src/main/resources/application.yml
+++ b/server/src/main/resources/application.yml
@@ -37,11 +37,6 @@ ozgcloud:
     expiration:
       minutes: 30
   upload.max-file-size: 100MB
-  nachricht:
-    send:
-      timeout: 60s
-    poll:
-      interval: 2s
   bayernid:
     organizationDisplayName: Antragsraum
     authnMethods:
@@ -79,7 +74,6 @@ spring:
       relyingparty:
         registration:
           bayernid:
-            entity-id: https://antragsraum.ozgcloud.de/
             assertingparty:
               singlesignon:
                 sign-request: true
diff --git a/server/src/main/resources/metadata/keycloak-saml-metadata.xml b/server/src/main/resources/metadata/keycloak-saml-metadata.xml
new file mode 100644
index 0000000000000000000000000000000000000000..b5746cf909d209910496f9ffef142f748c9378e9
--- /dev/null
+++ b/server/src/main/resources/metadata/keycloak-saml-metadata.xml
@@ -0,0 +1,25 @@
+<md:EntityDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" entityID="https://sso.dev.by.ozg-cloud.de/realms/by-antragsraum-idp">
+<md:IDPSSODescriptor WantAuthnRequestsSigned="true" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
+<md:KeyDescriptor use="signing">
+<ds:KeyInfo>
+<ds:KeyName>qO7IAjV9WUVVahQd9b1LGC1jAn9zMWV8oiPeafCAfdM</ds:KeyName>
+<ds:X509Data>
+<ds:X509Certificate>MIICszCCAZsCBgGRLC9tAjANBgkqhkiG9w0BAQsFADAdMRswGQYDVQQDDBJieS1hbnRyYWdzcmF1bS1pZHAwHhcNMjQwODA3MDkzMTMxWhcNMzQwODA3MDkzMzExWjAdMRswGQYDVQQDDBJieS1hbnRyYWdzcmF1bS1pZHAwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCo2RVcJYiqv000dk20VBv6952+FXjEa1BzSzlX1vs4IrpWCVNQfsmZ4ZAg7TBlwJiBHtx0zMtM6DyHQthTVf/E/aaZvBtobUlLt/A/hy/Q31SkzScUgLZy4Nm+kIfmwHRj5/Mo9/53NCYfHcRV0nmRISPj9XsGIjjU6UWEb8sjhQC3OJJg4rWeXKzGNQfGIaMeYmSu0dPfDGo1g08jTMVhgMbF2vystHv4W6dC1q2r6Sp7SrdfXIkkaK2WZcHaqJ1uWWzw6rZMA5vjVdm/djdUN/RHeKpw2d8lD9B/a9+swJJ59cccuk7izqIgXMP2OPBG8qroqOydkyG9huma9C9JAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAAcQlpbNPvut1HjJ0Xlk8iyt6u43CvBhNpMPFdBcUPzdSlehiifmo214HOVIacBz7DAv+TzLXKDLsd+RNJkh3s+bEbA6C9lnYwOwi6jJy7Wp0Zsndks0Qf2b/jPYSBvUzFKx0v9w28kUS563ErQXF+TErqsin78kxQttMVRyfnjisC/3xSLcF7BngyVo20iggqMfcC4BDCGhEU2Th01I+Gk/Fs9UxL6laPfaf+CjJscCp9qJgA/TRMr+MRfPXb4QCLMTd+gMfv27fZN4YLvmhj0pWVIbqC76WJDlc0gzOdhxERWRwAtqei7WfqaEsRdcapm7t9clQQVyz2+WVlRSTxw=</ds:X509Certificate>
+</ds:X509Data>
+</ds:KeyInfo>
+</md:KeyDescriptor>
+<md:ArtifactResolutionService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="https://sso.dev.by.ozg-cloud.de/realms/by-antragsraum-idp/protocol/saml/resolve" index="0"/>
+<md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://sso.dev.by.ozg-cloud.de/realms/by-antragsraum-idp/protocol/saml"/>
+<md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://sso.dev.by.ozg-cloud.de/realms/by-antragsraum-idp/protocol/saml"/>
+<md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact" Location="https://sso.dev.by.ozg-cloud.de/realms/by-antragsraum-idp/protocol/saml"/>
+<md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="https://sso.dev.by.ozg-cloud.de/realms/by-antragsraum-idp/protocol/saml"/>
+<md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</md:NameIDFormat>
+<md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</md:NameIDFormat>
+<md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</md:NameIDFormat>
+<md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</md:NameIDFormat>
+<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://sso.dev.by.ozg-cloud.de/realms/by-antragsraum-idp/protocol/saml"/>
+<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://sso.dev.by.ozg-cloud.de/realms/by-antragsraum-idp/protocol/saml"/>
+<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="https://sso.dev.by.ozg-cloud.de/realms/by-antragsraum-idp/protocol/saml"/>
+<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact" Location="https://sso.dev.by.ozg-cloud.de/realms/by-antragsraum-idp/protocol/saml"/>
+</md:IDPSSODescriptor>
+</md:EntityDescriptor>
\ No newline at end of file
diff --git a/server/src/test/helm-linter-values.yaml b/server/src/test/helm-linter-values.yaml
index 271aedb1bb82e45d92e0bfe7b032181ab80e8582..ab0c865eed6dbf6e8b0777b084a00b41b0488364 100644
--- a/server/src/test/helm-linter-values.yaml
+++ b/server/src/test/helm-linter-values.yaml
@@ -38,20 +38,14 @@ grpcclient:
 clamav:
   scanUrl: https://cra-service.ozg-clamav.svc.cluster.local:3000/api/v1/scan
 
-samlRelyingpartyRegistrationBayernid:
-  entityid: "https://test.antragsraum.ozgcloud.de/"
-  signing:
-    privatekey: "classpath:bayernid-test-sign.key"
-    certificate: "classpath:bayernid-test-sign.crt"
-  decryption:
-    privatekey: "classpath:bayernid-test-enc.key"
-    certificate: "classpath:bayernid-test-enc.crt"
-  metadatauri: "classpath:/metadata/bayernid-idp-infra.xml"
+
 grpcclient:
   infomanager:
     address: "static://info-manager:9090"
     negotiationtype: PLAINTEXT
 antragsraum:
   logoutSuccessUrl: https://test.antragsraum.de/?logout
+  saml:
+    entityID: https://sso.dev.de/realms/by-antragsraum-idp
 
 samlRegistrationSecretName: bayernid-saml-registration-secret
\ No newline at end of file
diff --git a/server/src/test/helm/deployment_63_char_test.yaml b/server/src/test/helm/deployment_63_char_test.yaml
index 1ca8124ff7a14d674f34bda97e56c0541645502c..27cc33b8518c344c0e131bae999059e07676bac2 100644
--- a/server/src/test/helm/deployment_63_char_test.yaml
+++ b/server/src/test/helm/deployment_63_char_test.yaml
@@ -41,8 +41,11 @@ set:
     scanUrl: https://cra-service.ozg-clamav.svc.cluster.local:3000/api/v1/scan
   antragsraum:
     logoutSuccessUrl: https://test.antragsraum.de/?logout
+    saml:
+      entityID: https://sso.dev.de/realms/by-antragsraum-idp
   samlRegistrationSecretName: bayernid-saml-registration-secret
 
+
 tests:
   - it: should fail on .Release.Namespace length longer than 63 characters
     release:
diff --git a/server/src/test/helm/deployment_actuator_test.yaml b/server/src/test/helm/deployment_actuator_test.yaml
index d5ab71b1da8d359d680f3a081e7499c2798e3f47..9a48bee3c6e9b2bd8eab8261e8b479f59d9c96c6 100644
--- a/server/src/test/helm/deployment_actuator_test.yaml
+++ b/server/src/test/helm/deployment_actuator_test.yaml
@@ -40,7 +40,10 @@ set:
     scanUrl: https://cra-service.ozg-clamav.svc.cluster.local:3000/api/v1/scan
   antragsraum:
     logoutSuccessUrl: https://test.antragsraum.de/?logout
+    saml:
+      entityID: https://sso.dev.de/realms/by-antragsraum-idp
   samlRegistrationSecretName: bayernid-saml-registration-secret
+
 tests:
   - it: testIsDeployment
     template: deployment.yaml
diff --git a/server/src/test/helm/deployment_bindings_test.yaml b/server/src/test/helm/deployment_bindings_test.yaml
index bb290ce20f1a473a95d783b53fa0f6f1132dc924..d00462f84a4f4eb546a0a7535e8cecec501d0396 100644
--- a/server/src/test/helm/deployment_bindings_test.yaml
+++ b/server/src/test/helm/deployment_bindings_test.yaml
@@ -40,6 +40,8 @@ set:
     scanUrl: https://cra-service.ozg-clamav.svc.cluster.local:3000/api/v1/scan
   antragsraum:
     logoutSuccessUrl: https://test.antragsraum.de/?logout
+    saml:
+      entityID: https://sso.dev.de/realms/by-antragsraum-idp
   samlRegistrationSecretName: bayernid-saml-registration-secret
 
 tests:
diff --git a/server/src/test/helm/deployment_container_basic_test.yaml b/server/src/test/helm/deployment_container_basic_test.yaml
index 72ab81318b8a20d9500dc5b046a3ff8369f0f59a..5f8a398bc72f5b651e7f5b9a959f80bdefa4f720 100644
--- a/server/src/test/helm/deployment_container_basic_test.yaml
+++ b/server/src/test/helm/deployment_container_basic_test.yaml
@@ -40,6 +40,8 @@ set:
     scanUrl: https://cra-service.ozg-clamav.svc.cluster.local:3000/api/v1/scan
   antragsraum:
     logoutSuccessUrl: https://test.antragsraum.de/?logout
+    saml:
+      entityID: https://sso.dev.de/realms/by-antragsraum-idp
   samlRegistrationSecretName: bayernid-saml-registration-secret
 
 tests:
diff --git a/server/src/test/helm/deployment_container_other_values_test.yaml b/server/src/test/helm/deployment_container_other_values_test.yaml
index 0a0cfb395df8c409c35d79ee9bdb00abc5901fe5..d4029c77358f5932b4a90cb543bb489d470700f2 100644
--- a/server/src/test/helm/deployment_container_other_values_test.yaml
+++ b/server/src/test/helm/deployment_container_other_values_test.yaml
@@ -41,6 +41,8 @@ set:
     scanUrl: https://cra-service.ozg-clamav.svc.cluster.local:3000/api/v1/scan
   antragsraum:
     logoutSuccessUrl: https://test.antragsraum.de/?logout
+    saml:
+      entityID: https://sso.dev.de/realms/by-antragsraum-idp
   samlRegistrationSecretName: bayernid-saml-registration-secret
 tests:
   - it: should have correct values for container terminationMessagePolicy, terminationMessagePath, stdin, tty
diff --git a/server/src/test/helm/deployment_container_security_context_test.yaml b/server/src/test/helm/deployment_container_security_context_test.yaml
index 2d990e4ef5808801b3a3c672f0a0b3153f8b659b..8c4d2556686125925adb930d3e539a35632347b0 100644
--- a/server/src/test/helm/deployment_container_security_context_test.yaml
+++ b/server/src/test/helm/deployment_container_security_context_test.yaml
@@ -40,6 +40,8 @@ set:
     scanUrl: https://cra-service.ozg-clamav.svc.cluster.local:3000/api/v1/scan
   antragsraum:
     logoutSuccessUrl: https://test.antragsraum.de/?logout
+    saml:
+      entityID: https://sso.dev.de/realms/by-antragsraum-idp
   samlRegistrationSecretName: bayernid-saml-registration-secret
 
 tests:
diff --git a/server/src/test/helm/deployment_defaults_labels_test.yaml b/server/src/test/helm/deployment_defaults_labels_test.yaml
index 1399f4173a9582628d4043ccb275d566933ca5f0..fe68a2186ba7d0aab4be40b1dd4587f5b09a38bd 100644
--- a/server/src/test/helm/deployment_defaults_labels_test.yaml
+++ b/server/src/test/helm/deployment_defaults_labels_test.yaml
@@ -40,6 +40,8 @@ set:
     scanUrl: https://cra-service.ozg-clamav.svc.cluster.local:3000/api/v1/scan
   antragsraum:
     logoutSuccessUrl: https://test.antragsraum.de/?logout
+    saml:
+      entityID: https://sso.dev.de/realms/by-antragsraum-idp
   samlRegistrationSecretName: bayernid-saml-registration-secret
 tests:
   - it: check metadata.labels
diff --git a/server/src/test/helm/deployment_defaults_topologySpreadConstraints_test.yaml b/server/src/test/helm/deployment_defaults_topologySpreadConstraints_test.yaml
index 1e0c48ecd34d9ed8f987d2678ea1999b237679d3..0092f7bed627542af22fde772cdd7a73d5d13f09 100644
--- a/server/src/test/helm/deployment_defaults_topologySpreadConstraints_test.yaml
+++ b/server/src/test/helm/deployment_defaults_topologySpreadConstraints_test.yaml
@@ -40,6 +40,8 @@ set:
     scanUrl: https://cra-service.ozg-clamav.svc.cluster.local:3000/api/v1/scan
   antragsraum:
     logoutSuccessUrl: https://test.antragsraum.de/?logout
+    saml:
+      entityID: https://sso.dev.de/realms/by-antragsraum-idp
   samlRegistrationSecretName: bayernid-saml-registration-secret
 tests:
   - it: check default values of spec.template.spec.topologySpreadConstraints
diff --git a/server/src/test/helm/deployment_env_test.yaml b/server/src/test/helm/deployment_env_test.yaml
index 885a21a5d33e572fec89a628c9c5e1a9af19b1f9..1460d8de5fa0465ef08dd1ed8b19d253a9b425ba 100644
--- a/server/src/test/helm/deployment_env_test.yaml
+++ b/server/src/test/helm/deployment_env_test.yaml
@@ -37,6 +37,8 @@ set:
     scanUrl: https://cra-service.ozg-clamav.svc.cluster.local:3000/api/v1/scan
   antragsraum:
     logoutSuccessUrl: https://test.antragsraum.de/?logout
+    saml:
+      entityID: https://sso.dev.de/realms/by-antragsraum-idp
   samlRegistrationSecretName: bayernid-saml-registration-secret
 tests:
   - it: check customList as list
@@ -166,4 +168,13 @@ tests:
           path: spec.template.spec.containers[0].env
           content: 
              name: OZGCLOUD_ANTRAGSRAUM_LOGOUTSUCCESSURL
-             value: https://test.antragsraum.de/?logout
\ No newline at end of file
+             value: https://test.antragsraum.de/?logout
+
+
+  - it: should have correcct SPRING_SECURITY_SAML2_RELYINGPARTY_REGISTRATION_BAYERNID_ENTITY-ID
+    asserts:  
+      - contains:
+          path: spec.template.spec.containers[0].env
+          content: 
+             name: SPRING_SECURITY_SAML2_RELYINGPARTY_REGISTRATION_BAYERNID_ENTITY-ID
+             value: https://sso.dev.de/realms/by-antragsraum-idp
\ No newline at end of file
diff --git a/server/src/test/helm/deployment_host_aliases_test.yaml b/server/src/test/helm/deployment_host_aliases_test.yaml
index 63224918186471e099c518e6f08d7e796068c02b..61ad98b3d2af9f324d31557ca8f31b196ef00aac 100644
--- a/server/src/test/helm/deployment_host_aliases_test.yaml
+++ b/server/src/test/helm/deployment_host_aliases_test.yaml
@@ -40,6 +40,8 @@ set:
     scanUrl: https://cra-service.ozg-clamav.svc.cluster.local:3000/api/v1/scan
   antragsraum:
     logoutSuccessUrl: https://test.antragsraum.de/?logout
+    saml:
+      entityID: https://sso.dev.de/realms/by-antragsraum-idp
   samlRegistrationSecretName: bayernid-saml-registration-secret
 tests:
   - it: should not set spec.template.spec.hostAliases
diff --git a/server/src/test/helm/deployment_imagepull_secret_test.yaml b/server/src/test/helm/deployment_imagepull_secret_test.yaml
index 76156389aeebc334d4a94e5566785fd7650667c7..f85bf978e404f27c6bb0d04131a8f16c04a71e34 100644
--- a/server/src/test/helm/deployment_imagepull_secret_test.yaml
+++ b/server/src/test/helm/deployment_imagepull_secret_test.yaml
@@ -40,6 +40,8 @@ set:
     scanUrl: https://cra-service.ozg-clamav.svc.cluster.local:3000/api/v1/scan
   antragsraum:
     logoutSuccessUrl: https://test.antragsraum.de/?logout
+    saml:
+      entityID: https://sso.dev.de/realms/by-antragsraum-idp
   samlRegistrationSecretName: bayernid-saml-registration-secret
 tests:
   - it: should use correct imagePull secret
diff --git a/server/src/test/helm/deployment_pod_general_values_test.yaml b/server/src/test/helm/deployment_pod_general_values_test.yaml
index 66ad09c9fc3aba1e9e0b65f9d227624526a8d1e0..86722603f12fc007f3e2febd4a59ff79f239da92 100644
--- a/server/src/test/helm/deployment_pod_general_values_test.yaml
+++ b/server/src/test/helm/deployment_pod_general_values_test.yaml
@@ -40,6 +40,8 @@ set:
     scanUrl: https://cra-service.ozg-clamav.svc.cluster.local:3000/api/v1/scan
   antragsraum:
     logoutSuccessUrl: https://dev.antragsraum.de/?logout
+    saml:
+      entityID: https://sso.dev.de/realms/by-antragsraum-idp
   samlRegistrationSecretName: bayernid-saml-registration-secret
 
 tests:
diff --git a/server/src/test/helm/deployment_resources_test.yaml b/server/src/test/helm/deployment_resources_test.yaml
index 3ac201e84de69645902fe1c1b78fdf38ae9debcb..1ffafdf1755f7401c58ebae657dc44b094c6139d 100644
--- a/server/src/test/helm/deployment_resources_test.yaml
+++ b/server/src/test/helm/deployment_resources_test.yaml
@@ -39,6 +39,8 @@ set:
     scanUrl: https://cra-service.ozg-clamav.svc.cluster.local:3000/api/v1/scan
   antragsraum:
     logoutSuccessUrl: https://test.antragsraum.de/?logout
+    saml:
+      entityID: https://sso.dev.de/realms/by-antragsraum-idp
   samlRegistrationSecretName: bayernid-saml-registration-secret
 
 tests:
diff --git a/server/src/test/helm/deployment_service_account_test.yaml b/server/src/test/helm/deployment_service_account_test.yaml
index 55119cc010b3a9b10cfb37aa92417060fafd96fc..81bb11b0a3e3cc4e96fc98ed164062cfff7b7b2d 100644
--- a/server/src/test/helm/deployment_service_account_test.yaml
+++ b/server/src/test/helm/deployment_service_account_test.yaml
@@ -39,6 +39,8 @@ set:
     scanUrl: https://cra-service.ozg-clamav.svc.cluster.local:3000/api/v1/scan
   antragsraum:
     logoutSuccessUrl: https://test.antragsraum.de/?logout
+    saml:
+      entityID: https://sso.dev.de/realms/by-antragsraum-idp
   samlRegistrationSecretName: bayernid-saml-registration-secret
 
 tests:
diff --git a/server/src/test/helm/deployment_springProfile_test.yaml b/server/src/test/helm/deployment_springProfile_test.yaml
index 8097c1ce985542e89a98f19657b005c06264be4e..b28682317f140db1aa630b8da3d6e94f7bf905fa 100644
--- a/server/src/test/helm/deployment_springProfile_test.yaml
+++ b/server/src/test/helm/deployment_springProfile_test.yaml
@@ -40,6 +40,8 @@ set:
     scanUrl: https://cra-service.ozg-clamav.svc.cluster.local:3000/api/v1/scan
   antragsraum:
     logoutSuccessUrl: https://test.antragsraum.de/?logout
+    saml:
+      entityID: https://sso.dev.de/realms/by-antragsraum-idp
   samlRegistrationSecretName: bayernid-saml-registration-secret
 tests:
   - it: should override the spring profiles
diff --git a/server/src/test/helm/deyploment_general_value_test.yaml b/server/src/test/helm/deyploment_general_value_test.yaml
index 794e915fa4a611268ca4fe2def6e85138d1ccfa9..cdc44b8f56697fc92bb0ef9aeb98f3ebc7876f23 100644
--- a/server/src/test/helm/deyploment_general_value_test.yaml
+++ b/server/src/test/helm/deyploment_general_value_test.yaml
@@ -40,6 +40,8 @@ set:
     scanUrl: https://cra-service.ozg-clamav.svc.cluster.local:3000/api/v1/scan
   antragsraum:
     logoutSuccessUrl: https://test.antragsraum.de/?logout
+    saml:
+      entityID: https://sso.dev.de/realms/by-antragsraum-idp
   samlRegistrationSecretName: bayernid-saml-registration-secret
 
 tests:
diff --git a/server/src/test/helm/network_policy_test.yaml b/server/src/test/helm/network_policy_test.yaml
index 9c0fe44b06bcbd827089c07ee7cceef81e099545..38a140a841ca4e149c7ccac8358937218cd50504 100644
--- a/server/src/test/helm/network_policy_test.yaml
+++ b/server/src/test/helm/network_policy_test.yaml
@@ -28,19 +28,26 @@ release:
   namespace: by-helm-test
 templates:
   - templates/network_policy.yaml
-set:
-  networkPolicy:
-    dnsServerNamespace: kube-system
+
 tests:
   - it: should match apiVersion
+    set:
+      networkPolicy:
+        dnsServerNamespace: kube-system
     asserts:
       - isAPIVersion:
           of: networking.k8s.io/v1
   - it: should match kind
+    set:
+      networkPolicy:
+        dnsServerNamespace: kube-system
     asserts:
       - isKind:
           of: NetworkPolicy
   - it: validate metadata
+    set:
+      networkPolicy:
+        dnsServerNamespace: kube-system
     asserts:
       - equal:
           path: metadata
@@ -48,6 +55,9 @@ tests:
             name: network-policy-antragsraum-server
             namespace: by-helm-test
   - it: validate spec
+    set:
+      networkPolicy:
+        dnsServerNamespace: kube-system
     asserts:
       - equal:
           path: spec
@@ -170,6 +180,21 @@ tests:
       networkPolicy:
         disabled: false
         dnsServerNamespace: test-dns-server-namespace
+    asserts:
+      - hasDocuments:
+          count: 1
+  - it: test network policy dnsServerNamespace must be set message
+    set:
+      networkPolicy:
+        disabled: false
+    asserts:
+      - failedTemplate:
+          errorMessage: networkPolicy.dnsServerNamespace must be set
+
+  - it: test network policy should be enabled by default
+    set:
+      networkPolicy:
+        dnsServerNamespace: test-dns-server-namespace
     asserts:
       - hasDocuments:
           count: 1
\ No newline at end of file
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/ModularityTests.java b/server/src/test/java/de/ozgcloud/antragsraum/ModularityTests.java
index e87d78b8c44351f427135d976be076910329b914..a0e4353120770d293fac5f0d8824213419d132e2 100644
--- a/server/src/test/java/de/ozgcloud/antragsraum/ModularityTests.java
+++ b/server/src/test/java/de/ozgcloud/antragsraum/ModularityTests.java
@@ -26,18 +26,17 @@ import org.springframework.modulith.core.ApplicationModules;
 import org.springframework.modulith.docs.Documenter;
 
 class ModularityTests {
-    @Test
-    void verifyModularity() {
-        ApplicationModules.of(AntragsRaumApplication.class);
-    }
+	@Test
+	void verifyModularity() {
+		ApplicationModules.of(AntragsRaumApplication.class);
+	}
 
-    @Test
-    void writeDocumentationSnippets() {
+	@Test
+	void writeDocumentationSnippets() {
+		var modules = ApplicationModules.of(AntragsRaumApplication.class).verify();
 
-        var modules = ApplicationModules.of(AntragsRaumApplication.class).verify();
-
-        new Documenter(modules)
-                .writeModulesAsPlantUml()
-                .writeIndividualModulesAsPlantUml();
-    }
+		new Documenter(modules)
+		  .writeModulesAsPlantUml()
+		  .writeIndividualModulesAsPlantUml();
+	}
 }
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/SecurityConfigurationTest.java b/server/src/test/java/de/ozgcloud/antragsraum/SecurityConfigurationTest.java
index 5dd33d55261b79126222c1e512060b55b2677f36..8ba32440719497f65c3c470778c4bb8898fd553d 100644
--- a/server/src/test/java/de/ozgcloud/antragsraum/SecurityConfigurationTest.java
+++ b/server/src/test/java/de/ozgcloud/antragsraum/SecurityConfigurationTest.java
@@ -22,21 +22,15 @@ package de.ozgcloud.antragsraum;
 import static org.assertj.core.api.Assertions.*;
 import static org.mockito.Mockito.*;
 
-import java.util.UUID;
-
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.Mock;
 import org.mockito.junit.jupiter.MockitoExtension;
-import org.springframework.security.authentication.AuthenticationManager;
-import org.springframework.security.authentication.ProviderManager;
-import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
 import org.springframework.security.config.annotation.web.builders.HttpSecurity;
 import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;
 import org.springframework.security.saml2.provider.service.web.authentication.Saml2AuthenticationRequestResolver;
-import org.springframework.test.util.ReflectionTestUtils;
 import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 
 import de.ozgcloud.antragsraum.security.AntragsraumLogoutSuccessHandler;
@@ -56,13 +50,13 @@ class SecurityConfigurationTest {
 	private BayernIdProperties properties;
 
 	@Mock
-	JwtTokenFilter tokenFilter;
+	private InMemoryUserDetailService userDetailsService;
 
 	@Mock
-	InMemoryUserDetailService userDetailsService;
+	private JwtTokenFilter tokenFilter;
 
 	@Mock
-	AntragsraumProperties corsProperties;
+	private AntragsraumProperties corsProperties;
 
 	private SecurityConfiguration securityConfiguration;
 
@@ -120,30 +114,6 @@ class SecurityConfigurationTest {
 		}
 	}
 
-	@Nested
-	class TestAuthenticationConfiguration {
-		@Mock
-		private AuthenticationConfiguration authenticationConfiguration;
-
-		@Test
-		void shouldCreateAuthenticationManager() throws Exception {
-			when(authenticationConfiguration.getAuthenticationManager()).thenReturn(mock(AuthenticationManager.class));
-
-			var authenticationManager = securityConfiguration.authenticationManager(authenticationConfiguration);
-
-			assertThat(authenticationManager).isInstanceOf(AuthenticationManager.class);
-		}
-
-		@Test
-		void shouldCreateMockAuthenticationManager() throws Exception {
-			ReflectionTestUtils.setField(securityConfiguration, "mockAuth", true);
-
-			var authenticationManager = securityConfiguration.authenticationManager(authenticationConfiguration);
-
-			assertThat(authenticationManager).isInstanceOf(ProviderManager.class);
-		}
-	}
-
 	@Nested
 	class TestSamlFilterChain {
 		@Mock
@@ -151,7 +121,6 @@ class SecurityConfigurationTest {
 
 		@BeforeEach
 		void setUp() throws Exception {
-			ReflectionTestUtils.setField(securityConfiguration, "mockAuth", false);
 			when(security.authorizeHttpRequests(any())).thenReturn(security);
 			when(security.addFilterBefore(any(), any())).thenReturn(security);
 			when(security.saml2Login(any())).thenReturn(security);
@@ -173,37 +142,13 @@ class SecurityConfigurationTest {
 		}
 	}
 
-	@Nested
-	class TestMockFilterChain {
-		@Mock
-		HttpSecurity security;
-
-		@BeforeEach
-		void setUp() throws Exception {
-			ReflectionTestUtils.setField(securityConfiguration, "mockAuth", true);
-			ReflectionTestUtils.setField(securityConfiguration, "password", UUID.randomUUID().toString());
-
-			when(security.authorizeHttpRequests(any())).thenReturn(security);
-			when(security.addFilterBefore(any(), any())).thenReturn(security);
-			when(security.httpBasic(any())).thenReturn(security);
-			when(security.formLogin(any())).thenReturn(security);
-		}
-
-		@Test
-		void shouldSetHttpBasicIfMockAuth() throws Exception {
-			securityConfiguration.filterChain(security);
-
-			verify(security).httpBasic(any());
-		}
-	}
-
 	@Nested
 	class TestLogoutHandler {
 		@Test
 		void shouldCreateLogoutHandler() {
 			when(corsProperties.getLogoutSuccessUrl()).thenReturn("/");
 
-			var handler = securityConfiguration.logoutSuccessHandler();
+			var handler = securityConfiguration.getLogoutSuccessHandler();
 
 			assertThat(handler).isInstanceOf(AntragsraumLogoutSuccessHandler.class);
 		}
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/attachments/FileControllerITCase.java b/server/src/test/java/de/ozgcloud/antragsraum/attachments/FileControllerITCase.java
index 7908af6f64880c6e528111daec5fb401c466f4d1..3f0d52ee4e3357eb8d02d09cef3d5677f410a83f 100644
--- a/server/src/test/java/de/ozgcloud/antragsraum/attachments/FileControllerITCase.java
+++ b/server/src/test/java/de/ozgcloud/antragsraum/attachments/FileControllerITCase.java
@@ -20,34 +20,19 @@
 
 package de.ozgcloud.antragsraum.attachments;
 
-import static de.ozgcloud.antragsraum.attachments.FileController.PATH;
-import static de.ozgcloud.antragsraum.attachments.FileController.PATH_PATTERN;
-import static de.ozgcloud.antragsraum.attachments.FileTestProperties.ENCODED_CHANNEL_ADDRESS;
-import static de.ozgcloud.antragsraum.attachments.FileTestProperties.FILE_ID;
-import static de.ozgcloud.antragsraum.attachments.FileTestProperties.VORGANG_ID;
-import static de.ozgcloud.antragsraum.attachments.FileValidatorTest.TEST_FILE;
-import static de.ozgcloud.antragsraum.attachments.FileValidatorTest.TEST_INVALID_FILE;
-import static de.ozgcloud.antragsraum.attachments.FileValidatorTest.TEST_TOO_LARGE_FILE;
-import static org.hamcrest.Matchers.containsString;
+import static de.ozgcloud.antragsraum.attachments.FileController.*;
+import static de.ozgcloud.antragsraum.attachments.OzgFileTestFactory.*;
+import static de.ozgcloud.antragsraum.attachments.FileValidatorTest.*;
+import static org.hamcrest.Matchers.*;
 import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyString;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.when;
-import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.asyncDispatch;
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
+import static org.mockito.Mockito.*;
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.request;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
 
-import de.ozgcloud.antragsraum.common.NotFoundException;
-import de.ozgcloud.antragsraum.common.TechnicalException;
-import de.ozgcloud.antragsraum.common.VirusFoundException;
-import de.ozgcloud.antragsraum.nachricht.NachrichtTestFactory;
-import java.nio.charset.StandardCharsets;
-import java.util.Base64;
 import java.util.concurrent.CompletableFuture;
+
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
@@ -66,143 +51,147 @@ import org.springframework.test.web.servlet.MvcResult;
 import org.springframework.test.web.servlet.ResultActions;
 import org.springframework.web.client.RestTemplate;
 
+import de.ozgcloud.antragsraum.common.NotFoundException;
+import de.ozgcloud.antragsraum.common.TechnicalException;
+import de.ozgcloud.antragsraum.common.VirusFoundException;
+import de.ozgcloud.antragsraum.nachricht.NachrichtTestFactory;
+
 @AutoConfigureMockMvc
 @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
-@SpringJUnitConfig(classes = {FileControllerTestConfiguration.class})
+@SpringJUnitConfig(classes = { FileControllerTestConfiguration.class })
 public class FileControllerITCase {
-    @SpyBean
-    private FileController controller;
-
-    @MockBean
-    private FileService fileService;
-
-    @MockBean
-    private RestTemplate restTemplate;
-
-    @Autowired
-    private MockMvc mockMvc;
-
-    @Nested
-    class TestDownloadingFileContent {
-        @BeforeEach
-        void init() {
-            when(fileService.getFile(anyString(), anyString())).thenReturn(OzgFileTestFactory.createOzgFile());
-        }
-
-        @Test
-        @WithMockUser
-        void shouldGetFileContent() throws Exception {
-            performRequest().andExpect(status().isOk());
-        }
-    }
-
-    @Nested
-    class TestFileNotFoundError {
-        @BeforeEach
-        void init() {
-            doThrow(NotFoundException.class).when(fileService).getFile(anyString(), anyString());
-        }
-
-        @Test
-        @WithMockUser
-        void shouldReturn404() throws Exception {
-            performRequest().andExpect(status().isNotFound());
-        }
-    }
-
-    @Nested
-    class TestInternalError {
-        @Test
-        @WithMockUser
-        void shouldReturn500ByTechnicalException() throws Exception {
-            doThrow(TechnicalException.class).when(fileService).getFile(anyString(), anyString());
-
-            performRequest().andExpect(status().isInternalServerError());
-        }
-
-        @Test
-        @WithMockUser
-        void shouldReturn500ByRuntimeException() throws Exception {
-            doThrow(RuntimeException.class).when(fileService).getFile(anyString(), anyString());
-
-            performRequest().andExpect(status().isInternalServerError());
-        }
-    }
-
-    @Nested
-    class TestNotAcceptable {
-        @BeforeEach
-        void init() {
-            when(fileService.getFile(anyString(), any())).thenReturn(OzgFileTestFactory.createOzgFile());
-            doThrow(VirusFoundException.class).when(fileService).getFile(anyString(), any());
-        }
-
-        @Test
-        @WithMockUser
-        void shouldReturn406ByVirusFoundException() throws Exception {
-            performRequest().andExpect(status().isNotAcceptable());
-        }
-    }
-
-    ResultActions performRequest() throws Exception {
-        var id = Base64.getEncoder().encodeToString(NachrichtTestFactory.ADDRESS.getBytes(StandardCharsets.UTF_8));
-        return mockMvc.perform(
-            get(PATH + id + "/" + FILE_ID)
-                .with(csrf().asHeader())
-                .accept(MediaType.APPLICATION_OCTET_STREAM_VALUE));
-    }
-
-    @Nested
-    class TestFileUpload {
-        private final CompletableFuture<String> fileIdFuture = CompletableFuture.completedFuture(FILE_ID);
-
-        @BeforeEach
-        void init() {
-            when(fileService.upload(anyString(), anyString(), any())).thenReturn(fileIdFuture);
-        }
-
-        @Test
-        @WithMockUser
-        void shouldReturnCreatedStatus() throws Exception {
-            var result = callEndpoint(TEST_FILE);
-
-            mockMvc.perform(asyncDispatch(result)).andExpect(status().isCreated());
-        }
-
-        @Test
-        @WithMockUser
-        void shouldReturnLocation() throws Exception {
-            var result = callEndpoint(TEST_FILE);
-
-            mockMvc.perform(asyncDispatch(result))
-                .andExpect(header().string("Location", containsString(PATH_PATTERN.formatted(VORGANG_ID, FILE_ID))));
-        }
-
-        @Test
-        @WithMockUser
-        void shouldReturnNotAcceptableBecauseOfFileType() throws Exception {
-            var result = callEndpoint(TEST_INVALID_FILE);
-
-            mockMvc.perform(asyncDispatch(result))
-                .andExpect(status().is(HttpStatus.NOT_ACCEPTABLE.value()));
-        }
-
-        @Test
-        @WithMockUser
-        void shouldReturnNotAcceptableBecauseOfFileSize() throws Exception {
-            var result = callEndpoint(TEST_TOO_LARGE_FILE);
-
-            mockMvc.perform(asyncDispatch(result))
-                .andExpect(status().is(HttpStatus.NOT_ACCEPTABLE.value()));
-        }
-
-        private MvcResult callEndpoint(MockMultipartFile file) throws Exception {
-            return mockMvc.perform(multipart(PATH_PATTERN.formatted(VORGANG_ID, ENCODED_CHANNEL_ADDRESS))
-                    .file(file)
-                    .with(csrf())
-                    .contentType(MediaType.MULTIPART_FORM_DATA_VALUE))
-                .andExpect(request().asyncStarted())
-                .andReturn();
-        }
-    }
+	@SpyBean
+	private FileController controller;
+
+	@MockBean
+	private FileService fileService;
+
+	@MockBean
+	private RestTemplate restTemplate;
+
+	@Autowired
+	private MockMvc mockMvc;
+
+	@Nested
+	class TestDownloadingFileContent {
+		@BeforeEach
+		void init() {
+			when(fileService.getFile(anyString(), anyString())).thenReturn(OzgFileTestFactory.create());
+		}
+
+		@Test
+		@WithMockUser
+		void shouldGetFileContent() throws Exception {
+			performRequest().andExpect(status().isOk());
+		}
+	}
+
+	@Nested
+	class TestFileNotFoundError {
+		@BeforeEach
+		void init() {
+			doThrow(NotFoundException.class).when(fileService).getFile(anyString(), anyString());
+		}
+
+		@Test
+		@WithMockUser
+		void shouldReturn404() throws Exception {
+			performRequest().andExpect(status().isNotFound());
+		}
+	}
+
+	@Nested
+	class TestInternalError {
+		@Test
+		@WithMockUser
+		void shouldReturn500ByTechnicalException() throws Exception {
+			doThrow(TechnicalException.class).when(fileService).getFile(anyString(), anyString());
+
+			performRequest().andExpect(status().isInternalServerError());
+		}
+
+		@Test
+		@WithMockUser
+		void shouldReturn500ByRuntimeException() throws Exception {
+			doThrow(RuntimeException.class).when(fileService).getFile(anyString(), anyString());
+
+			performRequest().andExpect(status().isInternalServerError());
+		}
+	}
+
+	@Nested
+	class TestNotAcceptable {
+		@BeforeEach
+		void init() {
+			when(fileService.getFile(anyString(), any())).thenReturn(OzgFileTestFactory.create());
+			doThrow(VirusFoundException.class).when(fileService).getFile(anyString(), any());
+		}
+
+		@Test
+		@WithMockUser
+		void shouldReturn406ByVirusFoundException() throws Exception {
+			performRequest().andExpect(status().isNotAcceptable());
+		}
+	}
+
+	ResultActions performRequest() throws Exception {
+		return mockMvc.perform(
+		  get(PATH + NachrichtTestFactory.NACHRICHT_EVENT_ID + "/" + FILE_ID)
+			.with(csrf().asHeader())
+			.accept(MediaType.APPLICATION_OCTET_STREAM_VALUE));
+	}
+
+	@Nested
+	class TestFileUpload {
+		private final CompletableFuture<String> fileIdFuture = CompletableFuture.completedFuture(FILE_ID);
+
+		@BeforeEach
+		void init() {
+			when(fileService.upload(anyString(), anyString(), any())).thenReturn(fileIdFuture);
+		}
+
+		@Test
+		@WithMockUser
+		void shouldReturnCreatedStatus() throws Exception {
+			var result = callEndpoint(TEST_FILE);
+
+			mockMvc.perform(asyncDispatch(result)).andExpect(status().isCreated());
+		}
+
+		@Test
+		@WithMockUser
+		void shouldReturnLocation() throws Exception {
+			var result = callEndpoint(TEST_FILE);
+
+			mockMvc.perform(asyncDispatch(result))
+			  .andExpect(header().string("Location", containsString(PATH_PATTERN.formatted(VORGANG_ID, FILE_ID))));
+		}
+
+		@Test
+		@WithMockUser
+		void shouldReturnNotAcceptableBecauseOfFileType() throws Exception {
+			var result = callEndpoint(TEST_INVALID_FILE);
+
+			mockMvc.perform(asyncDispatch(result))
+			  .andExpect(status().is(HttpStatus.NOT_ACCEPTABLE.value()));
+		}
+
+		@Test
+		@WithMockUser
+		void shouldReturnNotAcceptableBecauseOfFileSize() throws Exception {
+			var result = callEndpoint(TEST_TOO_LARGE_FILE);
+
+			mockMvc.perform(asyncDispatch(result))
+			  .andExpect(status().is(HttpStatus.NOT_ACCEPTABLE.value()));
+		}
+
+		private MvcResult callEndpoint(MockMultipartFile file) throws Exception {
+			return mockMvc.perform(multipart(PATH_PATTERN.formatted(VORGANG_ID, NACHRICHT_EVENT_ID))
+				.file(file)
+				.with(csrf())
+				.contentType(MediaType.MULTIPART_FORM_DATA_VALUE))
+			  .andExpect(request().asyncStarted())
+			  .andReturn();
+		}
+	}
 }
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/attachments/FileControllerTest.java b/server/src/test/java/de/ozgcloud/antragsraum/attachments/FileControllerTest.java
index d9c4c9556eec332ff4cda6dfb6d6fa2f59ed8597..b47dd5674691754cc0899d90f3d93f229f90b3a7 100644
--- a/server/src/test/java/de/ozgcloud/antragsraum/attachments/FileControllerTest.java
+++ b/server/src/test/java/de/ozgcloud/antragsraum/attachments/FileControllerTest.java
@@ -20,8 +20,9 @@
 
 package de.ozgcloud.antragsraum.attachments;
 
-import static de.ozgcloud.antragsraum.attachments.FileTestProperties.VORGANG_ID;
-import static de.ozgcloud.antragsraum.attachments.FileTestProperties.*;
+import static de.ozgcloud.antragsraum.attachments.OzgFileTestFactory.NACHRICHT_EVENT_ID;
+import static de.ozgcloud.antragsraum.attachments.OzgFileTestFactory.VORGANG_ID;
+import static de.ozgcloud.antragsraum.attachments.OzgFileTestFactory.*;
 import static de.ozgcloud.antragsraum.nachricht.NachrichtTestFactory.*;
 import static org.assertj.core.api.Assertions.*;
 import static org.mockito.Mockito.*;
@@ -59,7 +60,7 @@ class FileControllerTest {
 	class TestGetFileContent {
 		@BeforeEach
 		void init() {
-			when(fileService.getFile(anyString(), anyString())).thenReturn(OzgFileTestFactory.createOzgFile());
+			when(fileService.getFile(anyString(), anyString())).thenReturn(OzgFileTestFactory.create());
 		}
 
 		@Test
@@ -139,7 +140,7 @@ class FileControllerTest {
 
 		@Test
 		void shouldCallService() {
-			fileController.uploadFile(VORGANG_ID, ENCODED_CHANNEL_ADDRESS, multipartFile);
+			fileController.uploadFile(VORGANG_ID, NACHRICHT_EVENT_ID, multipartFile);
 
 			verify(fileService).upload(anyString(), anyString(), any(MultipartFile.class));
 		}
@@ -147,14 +148,13 @@ class FileControllerTest {
 
 	@Nested
 	class TestFileUploadExceptions {
-
 		@Mock
 		private MultipartFile multipartFile;
 
 		@Test
 		void shouldThrowExceptionWhenVorgangIdIsNull() {
 			assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(
-			  () -> fileController.uploadFile(null, ENCODED_CHANNEL_ADDRESS, multipartFile));
+			  () -> fileController.uploadFile(null, NACHRICHT_EVENT_ID, multipartFile));
 		}
 
 		@Test
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/attachments/FileDownloadStreamObserverTest.java b/server/src/test/java/de/ozgcloud/antragsraum/attachments/FileDownloadStreamObserverTest.java
index 81bad95b90409e28a294f5d0ed634cc8242ed44f..e03c730c85c2bb5357f7c53611bfde03316fec8a 100644
--- a/server/src/test/java/de/ozgcloud/antragsraum/attachments/FileDownloadStreamObserverTest.java
+++ b/server/src/test/java/de/ozgcloud/antragsraum/attachments/FileDownloadStreamObserverTest.java
@@ -21,9 +21,14 @@
  */
 package de.ozgcloud.antragsraum.attachments;
 
-import com.google.protobuf.ByteString;
-import de.ozgcloud.antragsraum.common.TechnicalException;
-import de.ozgcloud.vorgang.grpc.binaryFile.GrpcGetBinaryFileDataResponse;
+import static de.ozgcloud.antragsraum.attachments.OzgFileTestFactory.*;
+import static org.assertj.core.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.concurrent.CompletableFuture;
+
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
@@ -31,13 +36,10 @@ import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.junit.jupiter.MockitoExtension;
 
-import java.io.IOException;
-import java.io.OutputStream;
-import java.util.concurrent.CompletableFuture;
+import com.google.protobuf.ByteString;
 
-import static de.ozgcloud.antragsraum.attachments.FileTestProperties.DATA;
-import static org.assertj.core.api.Assertions.*;
-import static org.mockito.Mockito.*;
+import de.ozgcloud.antragsraum.common.TechnicalException;
+import de.ozgcloud.vorgang.grpc.binaryFile.GrpcGetBinaryFileDataResponse;
 
 @ExtendWith(MockitoExtension.class)
 class FileDownloadStreamObserverTest {
@@ -50,7 +52,6 @@ class FileDownloadStreamObserverTest {
 
 	@Nested
 	class TestOnNext {
-
 		@Test
 		void shouldWriteToStreamOnReceivingContentPart() throws IOException {
 			downloadStreamObserver.onNext(createFileContentResponse());
@@ -67,13 +68,12 @@ class FileDownloadStreamObserverTest {
 			doThrow(IOException.class).when(out).write(any());
 
 			assertThatExceptionOfType(TechnicalException.class).isThrownBy(
-					() -> downloadStreamObserver.onNext(createFileContentResponse())).withMessage("TechnicalException happened! Message: null");
+			  () -> downloadStreamObserver.onNext(createFileContentResponse())).withMessage("TechnicalException happened! Message: null");
 		}
 	}
 
 	@Nested
 	class TestOnError {
-
 		@Mock
 		private Throwable throwable;
 
@@ -87,7 +87,6 @@ class FileDownloadStreamObserverTest {
 
 	@Nested
 	class TestOnCompleted {
-
 		@Test
 		void shouldCompleteFuture() {
 			downloadStreamObserver.onCompleted();
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/attachments/FileGrpcClientTest.java b/server/src/test/java/de/ozgcloud/antragsraum/attachments/FileGrpcClientTest.java
index b8533818a43ae77a1fe248ad1250c0a23627edc4..36e82251662c786fb9d19057eff850ae3749cee3 100644
--- a/server/src/test/java/de/ozgcloud/antragsraum/attachments/FileGrpcClientTest.java
+++ b/server/src/test/java/de/ozgcloud/antragsraum/attachments/FileGrpcClientTest.java
@@ -22,7 +22,7 @@
 
 package de.ozgcloud.antragsraum.attachments;
 
-import static de.ozgcloud.antragsraum.attachments.FileTestProperties.*;
+import static de.ozgcloud.antragsraum.attachments.OzgFileTestFactory.*;
 import static org.assertj.core.api.Assertions.*;
 import static org.junit.jupiter.api.Assertions.*;
 import static org.mockito.Mockito.*;
@@ -72,11 +72,9 @@ class FileGrpcClientTest {
 
 	@Nested
 	class TestCreatingChannel {
-
 		@BeforeEach
 		void init() {
-			when(channelPropertiesFactory.getGrpcChannelsProperties(anyString())).thenReturn(
-			  new GrpcChannelsProperties());
+			when(channelPropertiesFactory.getGrpcChannelsProperties(anyString())).thenReturn(new GrpcChannelsProperties());
 		}
 
 		@Test
@@ -107,7 +105,6 @@ class FileGrpcClientTest {
 
 	@Nested
 	class TestUploadingFile {
-
 		@Mock
 		private BinaryFileServiceGrpc.BinaryFileServiceStub asyncStub;
 
@@ -140,7 +137,6 @@ class FileGrpcClientTest {
 
 	@Nested
 	class TestBuildChunkRequest {
-
 		@Test
 		void shouldContainContent() {
 			var chunkRequest = fileGrpcClient.buildChunkRequest(DATA);
@@ -151,7 +147,6 @@ class FileGrpcClientTest {
 
 	@Nested
 	class TestDownloadingFiles {
-
 		@Mock
 		private FileDownloadStreamObserver responseObserver;
 
@@ -179,7 +174,6 @@ class FileGrpcClientTest {
 
 	@Nested
 	class TestWaitUntilFutureToComplete {
-
 		@Mock
 		private CompletableFuture<Boolean> streamFuture;
 
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/attachments/FileRemoteServiceITCase.java b/server/src/test/java/de/ozgcloud/antragsraum/attachments/FileRemoteServiceITCase.java
index b9529e2d0bd42c65cb8b1f082f363be5a268dc55..587b9d2afffbc44d9c5de683a390ae7ed155f3d1 100644
--- a/server/src/test/java/de/ozgcloud/antragsraum/attachments/FileRemoteServiceITCase.java
+++ b/server/src/test/java/de/ozgcloud/antragsraum/attachments/FileRemoteServiceITCase.java
@@ -21,6 +21,7 @@
  */
 package de.ozgcloud.antragsraum.attachments;
 
+import static de.ozgcloud.antragsraum.attachments.OzgFileTestFactory.*;
 import static org.assertj.core.api.Assertions.*;
 
 import java.io.ByteArrayOutputStream;
@@ -59,7 +60,7 @@ public class FileRemoteServiceITCase {
 			var idFuture = fileRemoteService.uploadFile(OzgUploadFileTestFactory.create(), CHANNEL_ADDRESS);
 
 			try {
-				assertThat(idFuture.get(1, TimeUnit.SECONDS)).isEqualTo(FileTestProperties.FILE_ID);
+				assertThat(idFuture.get(1, TimeUnit.SECONDS)).isEqualTo(FILE_ID);
 			} catch (InterruptedException | ExecutionException | TimeoutException e) {
 				fail(e.getMessage());
 			}
@@ -71,7 +72,7 @@ public class FileRemoteServiceITCase {
 		@Test
 		@DirtiesContext
 		void shouldGetFile() {
-			var file = fileRemoteService.getFile(FileTestProperties.FILE_ID, CHANNEL_ADDRESS);
+			var file = fileRemoteService.getFile(FILE_ID, CHANNEL_ADDRESS);
 
 			assertThat(file).isNotNull();
 		}
@@ -79,9 +80,9 @@ public class FileRemoteServiceITCase {
 		@Test
 		@DirtiesContext
 		void shouldHaveFileMetaData() {
-			var file = fileRemoteService.getFile(FileTestProperties.FILE_ID, CHANNEL_ADDRESS);
+			var file = fileRemoteService.getFile(FILE_ID, CHANNEL_ADDRESS);
 
-			assertThat(file).isEqualTo(OzgFileTestFactory.createOzgFile());
+			assertThat(file).isEqualTo(OzgFileTestFactory.create());
 		}
 	}
 
@@ -91,9 +92,9 @@ public class FileRemoteServiceITCase {
 		@DirtiesContext
 		void shouldGetFileContent() {
 			var out = new ByteArrayOutputStream();
-			fileRemoteService.downloadFileContent(FileTestProperties.FILE_ID, out, CHANNEL_ADDRESS);
+			fileRemoteService.downloadFileContent(FILE_ID, out, CHANNEL_ADDRESS);
 
-			assertThat(out.size()).isEqualTo(FileTestProperties.DATA.length);
+			assertThat(out.size()).isEqualTo(DATA.length);
 		}
 	}
 }
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/attachments/FileRemoteServiceTest.java b/server/src/test/java/de/ozgcloud/antragsraum/attachments/FileRemoteServiceTest.java
index 5152deaa01fa5157b0e6ea18443e866c11e4890a..b32d69abd87ad219e7bbdaf0ae8d98b437b98f98 100644
--- a/server/src/test/java/de/ozgcloud/antragsraum/attachments/FileRemoteServiceTest.java
+++ b/server/src/test/java/de/ozgcloud/antragsraum/attachments/FileRemoteServiceTest.java
@@ -22,7 +22,7 @@
 
 package de.ozgcloud.antragsraum.attachments;
 
-import static de.ozgcloud.antragsraum.attachments.FileTestProperties.*;
+import static de.ozgcloud.antragsraum.attachments.OzgFileTestFactory.*;
 import static org.assertj.core.api.Assertions.*;
 import static org.mockito.ArgumentMatchers.*;
 import static org.mockito.Mockito.any;
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/attachments/FileServiceTest.java b/server/src/test/java/de/ozgcloud/antragsraum/attachments/FileServiceTest.java
index 2165683c70abaf399beaf8c48b27c31701368bdb..51727bb2b3f4a8804ca47197c386e6b1081b6461 100644
--- a/server/src/test/java/de/ozgcloud/antragsraum/attachments/FileServiceTest.java
+++ b/server/src/test/java/de/ozgcloud/antragsraum/attachments/FileServiceTest.java
@@ -20,22 +20,10 @@
 
 package de.ozgcloud.antragsraum.attachments;
 
-import static de.ozgcloud.antragsraum.attachments.FileTestProperties.CHANNEL_ADDRESS;
-import static de.ozgcloud.antragsraum.attachments.FileTestProperties.DATA;
-import static de.ozgcloud.antragsraum.attachments.FileTestProperties.FILE_ID;
-import static de.ozgcloud.antragsraum.attachments.FileTestProperties.VORGANG_ID;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
-import static org.assertj.core.api.Assertions.fail;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyString;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
+import static de.ozgcloud.antragsraum.attachments.OzgFileTestFactory.*;
+import static org.assertj.core.api.Assertions.*;
+import static org.mockito.Mockito.*;
 
-import de.ozgcloud.antragsraum.common.TechnicalException;
-import de.ozgcloud.antragsraum.common.VirusFoundException;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
@@ -45,6 +33,7 @@ import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
+
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
@@ -55,103 +44,115 @@ import org.mockito.Spy;
 import org.mockito.junit.jupiter.MockitoExtension;
 import org.springframework.web.multipart.MultipartFile;
 
+import de.ozgcloud.antragsraum.common.TechnicalException;
+import de.ozgcloud.antragsraum.common.VirusFoundException;
+import de.ozgcloud.antragsraum.events.NachrichtEventService;
+import de.ozgcloud.antragsraum.events.NachrichtEventTestFactory;
+
 @ExtendWith(MockitoExtension.class)
 class FileServiceTest {
-    @Spy
-    @InjectMocks
-    private FileService fileService;
-
-    @Mock
-    private FileRemoteService remoteService;
-
-    @Mock
-    private VirusScannerClient virusScannerClient;
-
-    @Nested
-    class TestFileUpload {
-
-        @Mock
-        private MultipartFile multipartFile;
-
-        @BeforeEach
-        void init() throws IOException {
-            when(remoteService.uploadFile(any(OzgUploadFile.class), anyString())).thenReturn(
-                CompletableFuture.completedFuture(FILE_ID));
-            when(multipartFile.getInputStream()).thenReturn(new ByteArrayInputStream(DATA));
-        }
-
-        @Test
-        void shouldCallRemoteService() {
-            fileService.upload(VORGANG_ID, CHANNEL_ADDRESS, multipartFile);
-
-            verify(remoteService, times(1)).uploadFile(any(OzgUploadFile.class), anyString());
-        }
-
-        @Test
-        void shouldGetFileId() {
-            var res = fileService.upload(VORGANG_ID, CHANNEL_ADDRESS, multipartFile);
-
-            try {
-                assertThat(res.get(5, TimeUnit.SECONDS)).isEqualTo(FILE_ID);
-            } catch (InterruptedException | ExecutionException | TimeoutException e) {
-                fail("Exception happened! " + e.getMessage());
-            }
-        }
-    }
-
-    @Nested
-    class TestExceptionWhenSendingFile {
-        @Mock
-        private MultipartFile multipartFile;
-
-        @Test
-        void shouldThrowTechnicalExceptionOnUpload() throws IOException {
-            doThrow(IOException.class).when(multipartFile).getInputStream();
-
-            assertThatExceptionOfType(TechnicalException.class).isThrownBy(
-                    () -> fileService.upload(VORGANG_ID, CHANNEL_ADDRESS, multipartFile))
-                .withMessage("TechnicalException happened! Message: null");
-        }
-    }
-
-    @Nested
-    class TestLoadingFile {
-
-        @BeforeEach
-        void init() {
-            when(remoteService.getFile(anyString(), anyString())).thenReturn(OzgFileTestFactory.createOzgFile());
-        }
-
-        @Test
-        void shouldGetFile() {
-            var file = fileService.getFile(FILE_ID, CHANNEL_ADDRESS);
-
-            assertThat(file).isNotNull();
-        }
-    }
-
-    @Nested
-    class TestDownloadingFileContent {
-
-        @Test
-        void shouldCallRemoteService() {
-            fileService.downloadFileContent(FILE_ID, new ByteArrayOutputStream(), CHANNEL_ADDRESS);
-
-            verify(remoteService).downloadFileContent(anyString(), any(OutputStream.class), anyString());
-        }
-    }
-
-    @Nested
-    class TestVirusScanning {
-        @Mock
-        private MultipartFile multipartFile;
-
-        @Test
-        void shouldThrowVirusFoundExceptionWhenUploadingFile() {
-            when(virusScannerClient.scan(multipartFile)).thenReturn(Set.of("VirusA", "VirusB"));
-
-            assertThatExceptionOfType(VirusFoundException.class).isThrownBy(
-                () -> fileService.createUploadFile(VORGANG_ID, multipartFile));
-        }
-    }
+	@Spy
+	@InjectMocks
+	private FileService fileService;
+
+	@Mock
+	private FileRemoteService remoteService;
+
+	@Mock
+	private VirusScannerClient virusScannerClient;
+
+	@Mock
+	private NachrichtEventService nachrichtEventService;
+
+	@Nested
+	class TestFileUpload {
+		@Mock
+		private MultipartFile multipartFile;
+
+		@BeforeEach
+		void init() throws IOException {
+			when(remoteService.uploadFile(any(OzgUploadFile.class), anyString())).thenReturn(
+			  CompletableFuture.completedFuture(FILE_ID));
+			when(multipartFile.getInputStream()).thenReturn(new ByteArrayInputStream(DATA));
+			when(nachrichtEventService.getNachrichtEventById(NACHRICHT_EVENT_ID)).thenReturn(NachrichtEventTestFactory.createNachrichtEvent());
+		}
+
+		@Test
+		void shouldCallRemoteService() {
+			fileService.upload(VORGANG_ID, NACHRICHT_EVENT_ID, multipartFile);
+
+			verify(remoteService, times(1)).uploadFile(any(OzgUploadFile.class), anyString());
+		}
+
+		@Test
+		void shouldGetFileId() {
+			var res = fileService.upload(VORGANG_ID, NACHRICHT_EVENT_ID, multipartFile);
+
+			try {
+				assertThat(res.get(5, TimeUnit.SECONDS)).isEqualTo(FILE_ID);
+			} catch (InterruptedException | ExecutionException | TimeoutException e) {
+				fail("Exception happened! " + e.getMessage());
+			}
+		}
+	}
+
+	@Nested
+	class TestExceptionWhenSendingFile {
+		@Mock
+		private MultipartFile multipartFile;
+
+		@Test
+		void shouldThrowTechnicalExceptionOnUpload() throws IOException {
+			doThrow(IOException.class).when(multipartFile).getInputStream();
+
+			assertThatExceptionOfType(TechnicalException.class).isThrownBy(
+				() -> fileService.upload(VORGANG_ID, NACHRICHT_EVENT_ID, multipartFile))
+			  .withMessage("TechnicalException happened! Message: null");
+		}
+	}
+
+	@Nested
+	class TestLoadingFile {
+		@BeforeEach
+		void init() {
+			when(remoteService.getFile(anyString(), anyString())).thenReturn(OzgFileTestFactory.create());
+			when(nachrichtEventService.getNachrichtEventById(NACHRICHT_EVENT_ID)).thenReturn(NachrichtEventTestFactory.createNachrichtEvent());
+		}
+
+		@Test
+		void shouldGetFile() {
+			var file = fileService.getFile(FILE_ID, NACHRICHT_EVENT_ID);
+
+			assertThat(file).isNotNull();
+		}
+	}
+
+	@Nested
+	class TestDownloadingFileContent {
+		@BeforeEach
+		void init() {
+			when(nachrichtEventService.getNachrichtEventById(NACHRICHT_EVENT_ID)).thenReturn(NachrichtEventTestFactory.createNachrichtEvent());
+		}
+
+		@Test
+		void shouldCallRemoteService() {
+			fileService.downloadFileContent(FILE_ID, new ByteArrayOutputStream(), NACHRICHT_EVENT_ID);
+
+			verify(remoteService).downloadFileContent(anyString(), any(OutputStream.class), anyString());
+		}
+	}
+
+	@Nested
+	class TestVirusScanning {
+		@Mock
+		private MultipartFile multipartFile;
+
+		@Test
+		void shouldThrowVirusFoundExceptionWhenUploadingFile() {
+			when(virusScannerClient.scan(multipartFile)).thenReturn(Set.of("VirusA", "VirusB"));
+
+			assertThatExceptionOfType(VirusFoundException.class).isThrownBy(
+			  () -> fileService.createUploadFile(VORGANG_ID, multipartFile));
+		}
+	}
 }
\ No newline at end of file
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/attachments/FileTestProperties.java b/server/src/test/java/de/ozgcloud/antragsraum/attachments/FileTestProperties.java
deleted file mode 100644
index 6689f4110fa5bcc3fa057f62f5a74dad2abe2d8a..0000000000000000000000000000000000000000
--- a/server/src/test/java/de/ozgcloud/antragsraum/attachments/FileTestProperties.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (c) 2024.
- * Lizenziert unter der EUPL, Version 1.2 oder - sobald
- * diese von der Europäischen Kommission genehmigt wurden -
- * Folgeversionen der EUPL ("Lizenz");
- * Sie dürfen dieses Werk ausschließlich gemäß
- * dieser Lizenz nutzen.
- * Eine Kopie der Lizenz finden Sie hier:
- *
- * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
- *
- * Sofern nicht durch anwendbare Rechtsvorschriften
- * gefordert oder in schriftlicher Form vereinbart, wird
- * die unter der Lizenz verbreitete Software "so wie sie
- * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
- * ausdrücklich oder stillschweigend - verbreitet.
- * Die sprachspezifischen Genehmigungen und Beschränkungen
- * unter der Lizenz sind dem Lizenztext zu entnehmen.
- */
-
-package de.ozgcloud.antragsraum.attachments;
-
-import java.nio.charset.StandardCharsets;
-import java.util.Base64;
-import java.util.UUID;
-import org.apache.http.entity.ContentType;
-
-class FileTestProperties {
-    static final String FILE_ID = UUID.randomUUID().toString();
-    static final String VORGANG_ID = UUID.randomUUID().toString();
-    static final String CONTENT_TYPE = ContentType.APPLICATION_OCTET_STREAM.toString();
-    static final long FILE_SIZE = 10;
-    static final String FILE_NAME = "Testfile.pdf";
-    static final String CHANNEL_ADDRESS = "static://localhost:9090";
-    static final String ENCODED_CHANNEL_ADDRESS = Base64.getEncoder().encodeToString(CHANNEL_ADDRESS.getBytes(
-        StandardCharsets.UTF_8));
-    static final byte[] DATA = "juhu, ein bild".getBytes();
-}
\ No newline at end of file
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/attachments/FileValidatorTest.java b/server/src/test/java/de/ozgcloud/antragsraum/attachments/FileValidatorTest.java
index 5083e863ec5660dcbab54295ae26c4e1f113dc29..1b997385acf25ce1e5f0e866ac8521f403844a10 100644
--- a/server/src/test/java/de/ozgcloud/antragsraum/attachments/FileValidatorTest.java
+++ b/server/src/test/java/de/ozgcloud/antragsraum/attachments/FileValidatorTest.java
@@ -20,12 +20,9 @@
 
 package de.ozgcloud.antragsraum.attachments;
 
-import static de.ozgcloud.antragsraum.attachments.FileTestProperties.CONTENT_TYPE;
-import static de.ozgcloud.antragsraum.attachments.FileTestProperties.DATA;
-import static de.ozgcloud.antragsraum.attachments.FileTestProperties.FILE_NAME;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
-import static org.mockito.Mockito.when;
+import static de.ozgcloud.antragsraum.attachments.OzgFileTestFactory.*;
+import static org.assertj.core.api.Assertions.*;
+import static org.mockito.Mockito.*;
 
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Nested;
@@ -41,158 +38,158 @@ import org.springframework.util.unit.DataSize;
 
 @ExtendWith(MockitoExtension.class)
 class FileValidatorTest {
-    private static final String INVALID_FILE_NAME = "Testfile.exe";
-    public static final MockMultipartFile TEST_FILE = new MockMultipartFile("file", FILE_NAME, CONTENT_TYPE, DATA);
-    public static final MockMultipartFile TEST_INVALID_FILE =
-        new MockMultipartFile("file", INVALID_FILE_NAME, CONTENT_TYPE, DATA);
-    public static final MockMultipartFile TEST_TOO_LARGE_FILE =
-        new MockMultipartFile("file", FILE_NAME, CONTENT_TYPE, new byte[150_000_000]);
-    @InjectMocks
-    private FileValidator validator;
+	private static final String INVALID_FILE_NAME = "Testfile.exe";
+	public static final MockMultipartFile TEST_FILE = new MockMultipartFile("file", FILE_NAME, CONTENT_TYPE, DATA);
+	public static final MockMultipartFile TEST_INVALID_FILE =
+	  new MockMultipartFile("file", INVALID_FILE_NAME, CONTENT_TYPE, DATA);
+	public static final MockMultipartFile TEST_TOO_LARGE_FILE =
+	  new MockMultipartFile("file", FILE_NAME, CONTENT_TYPE, new byte[150_000_000]);
+	@InjectMocks
+	private FileValidator validator;
 
-    @Mock
-    private FileProperties fileProperties;
+	@Mock
+	private FileProperties fileProperties;
 
-    @Nested
-    class TestDefaultValues {
+	@Nested
+	class TestDefaultValues {
 
-        @Nested
-        class TestAllowedFileTypes {
+		@Nested
+		class TestAllowedFileTypes {
 
-            @ParameterizedTest
-            @ValueSource(strings = {"pdf", "doc", "docx", "xls", "xlsx", "txt", "png", "jpg", "jpeg", "tif", "tiff"})
-            void shouldBeValidLowerCase(String suffix) {
-                var file = createFile(suffix);
+			@ParameterizedTest
+			@ValueSource(strings = { "pdf", "doc", "docx", "xls", "xlsx", "txt", "png", "jpg", "jpeg", "tif", "tiff" })
+			void shouldBeValidLowerCase(String suffix) {
+				var file = createFile(suffix);
 
-                var result = validator.isValid(file);
+				var result = validator.isValid(file);
 
-                assertThat(result).isTrue();
-            }
+				assertThat(result).isTrue();
+			}
 
-            @ParameterizedTest
-            @ValueSource(strings = {"PDF"})
-            void shouldBeValidUppercase(String suffix) {
-                var file = createFile(suffix);
+			@ParameterizedTest
+			@ValueSource(strings = { "PDF" })
+			void shouldBeValidUppercase(String suffix) {
+				var file = createFile(suffix);
 
-                var result = validator.isValid(file);
+				var result = validator.isValid(file);
 
-                assertThat(result).isTrue();
+				assertThat(result).isTrue();
 
-            }
-        }
+			}
+		}
 
-        @Nested
-        class TestFileSize {
+		@Nested
+		class TestFileSize {
 
-            @Test
-            void shouldBeValidDefault() {
-                var res = validator.isValid(TEST_FILE);
+			@Test
+			void shouldBeValidDefault() {
+				var res = validator.isValid(TEST_FILE);
 
-                assertThat(res).isTrue();
-            }
+				assertThat(res).isTrue();
+			}
 
-            @Test
-            void shouldNotBeValid() {
-                var res = validator.isValid(TEST_INVALID_FILE);
+			@Test
+			void shouldNotBeValid() {
+				var res = validator.isValid(TEST_INVALID_FILE);
 
-                assertThat(res).isFalse();
-            }
-        }
+				assertThat(res).isFalse();
+			}
+		}
 
-        @Nested
-        class TestForbiddenFileTypes {
-            @ParameterizedTest
-            @ValueSource(strings = {"zip", "exe"})
-            void shouldNotBeValidLowercase(String suffix) {
-                var file = createFile(suffix);
+		@Nested
+		class TestForbiddenFileTypes {
+			@ParameterizedTest
+			@ValueSource(strings = { "zip", "exe" })
+			void shouldNotBeValidLowercase(String suffix) {
+				var file = createFile(suffix);
 
-                var result = validator.isValid(file);
+				var result = validator.isValid(file);
 
-                assertThat(result).isFalse();
-            }
+				assertThat(result).isFalse();
+			}
 
-            @ParameterizedTest
-            @ValueSource(strings = {"EXE"})
-            void shouldNotBeValidUpperCase(String suffix) {
-                var file = createFile(suffix);
+			@ParameterizedTest
+			@ValueSource(strings = { "EXE" })
+			void shouldNotBeValidUpperCase(String suffix) {
+				var file = createFile(suffix);
 
-                var result = validator.isValid(file);
+				var result = validator.isValid(file);
 
-                assertThat(result).isFalse();
-            }
-        }
-    }
+				assertThat(result).isFalse();
+			}
+		}
+	}
 
-    @Nested
-    class TestTypeWithFileProperties {
-        @InjectMocks
-        private FileValidator validator;
+	@Nested
+	class TestTypeWithFileProperties {
+		@InjectMocks
+		private FileValidator validator;
 
-        @Mock
-        private FileProperties fileProperties;
+		@Mock
+		private FileProperties fileProperties;
 
-        @BeforeEach
-        void init() {
-            when(fileProperties.getAllowedSuffixes()).thenReturn("pdf,doc");
-            //when(fileProperties.getMaxFileSize()).thenReturn(DataSize.ofMegabytes(50));
-        }
+		@BeforeEach
+		void init() {
+			when(fileProperties.getAllowedSuffixes()).thenReturn("pdf,doc");
+			//when(fileProperties.getMaxFileSize()).thenReturn(DataSize.ofMegabytes(50));
+		}
 
-        @ParameterizedTest
-        @ValueSource(strings = {"pdf", "doc"})
-        void shouldBeValid(String suffix) {
-            var file = createFile(suffix);
+		@ParameterizedTest
+		@ValueSource(strings = { "pdf", "doc" })
+		void shouldBeValid(String suffix) {
+			var file = createFile(suffix);
 
-            var result = validator.isValid(file);
+			var result = validator.isValid(file);
 
-            assertThat(result).isTrue();
-        }
+			assertThat(result).isTrue();
+		}
 
-        @ParameterizedTest
-        @ValueSource(strings = {"txt", "png"})
-        void shouldNotBeValid(String suffix) {
-            var file = createFile(suffix);
+		@ParameterizedTest
+		@ValueSource(strings = { "txt", "png" })
+		void shouldNotBeValid(String suffix) {
+			var file = createFile(suffix);
 
-            var result = validator.isValid(file);
+			var result = validator.isValid(file);
 
-            assertThat(result).isFalse();
-        }
-    }
+			assertThat(result).isFalse();
+		}
+	}
 
-    @Nested
-    class TestSizeWithFileProperties {
-        @BeforeEach
-        void init() {
-            when(fileProperties.getMaxFileSize()).thenReturn(DataSize.ofMegabytes(50));
-        }
+	@Nested
+	class TestSizeWithFileProperties {
+		@BeforeEach
+		void init() {
+			when(fileProperties.getMaxFileSize()).thenReturn(DataSize.ofMegabytes(50));
+		}
 
-        @Test
-        void shouldBeValidProperties() {
-            var res = validator.isValid(TEST_FILE);
+		@Test
+		void shouldBeValidProperties() {
+			var res = validator.isValid(TEST_FILE);
 
-            assertThat(res).isTrue();
-        }
+			assertThat(res).isTrue();
+		}
 
-        @Test
-        void shouldNotBeValidProperties() {
-            var res = validator.isValid(TEST_TOO_LARGE_FILE);
+		@Test
+		void shouldNotBeValidProperties() {
+			var res = validator.isValid(TEST_TOO_LARGE_FILE);
 
-            assertThat(res).isFalse();
-        }
-    }
+			assertThat(res).isFalse();
+		}
+	}
 
-    private MockMultipartFile createFile(String suffix) {
-        return new MockMultipartFile("file", "test." + suffix, CONTENT_TYPE, DATA);
-    }
+	private MockMultipartFile createFile(String suffix) {
+		return new MockMultipartFile("file", "test." + suffix, CONTENT_TYPE, DATA);
+	}
 
-    @Test
-    void shouldGetFileSuffix() {
-        var suffix = validator.getFileNameSuffix("test.txt");
+	@Test
+	void shouldGetFileSuffix() {
+		var suffix = validator.getFileNameSuffix("test.txt");
 
-        assertThat(suffix).isEqualTo("txt");
-    }
+		assertThat(suffix).isEqualTo("txt");
+	}
 
-    @Test
-    void shouldThrowException() {
-        assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> validator.getFileNameSuffix(null));
-    }
+	@Test
+	void shouldThrowException() {
+		assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> validator.getFileNameSuffix(null));
+	}
 }
\ No newline at end of file
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/attachments/GrpcBinaryFileServiceStub.java b/server/src/test/java/de/ozgcloud/antragsraum/attachments/GrpcBinaryFileServiceStub.java
index 51f85c311a80980f794b55cc0552bc0c7908a864..7fd7dce06a238c172079cc695a2a32b62c8fc6c9 100644
--- a/server/src/test/java/de/ozgcloud/antragsraum/attachments/GrpcBinaryFileServiceStub.java
+++ b/server/src/test/java/de/ozgcloud/antragsraum/attachments/GrpcBinaryFileServiceStub.java
@@ -22,7 +22,7 @@
 
 package de.ozgcloud.antragsraum.attachments;
 
-import static de.ozgcloud.antragsraum.attachments.FileTestProperties.*;
+import static de.ozgcloud.antragsraum.attachments.OzgFileTestFactory.*;
 
 import com.google.protobuf.ByteString;
 
diff --git a/server/src/main/java/de/ozgcloud/antragsraum/nachricht/NachrichtTrustLevel.java b/server/src/test/java/de/ozgcloud/antragsraum/attachments/GrpcOzgFileTestFactory.java
similarity index 60%
rename from server/src/main/java/de/ozgcloud/antragsraum/nachricht/NachrichtTrustLevel.java
rename to server/src/test/java/de/ozgcloud/antragsraum/attachments/GrpcOzgFileTestFactory.java
index 3d9f18ffcbf151007a88ac3dc91a9232c53c01dd..62f361aa5b175e2a0016503e62d869a3497b2682 100644
--- a/server/src/main/java/de/ozgcloud/antragsraum/nachricht/NachrichtTrustLevel.java
+++ b/server/src/test/java/de/ozgcloud/antragsraum/attachments/GrpcOzgFileTestFactory.java
@@ -1,7 +1,5 @@
 /*
- * Copyright (c) 2024.   Das Land Schleswig-Holstein vertreten durch den Ministerpräsidenten
- * des Landes Schleswig-Holstein Staatskanzlei Abteilung Digitalisierung und zentrales IT-Management der Landesregierung.
- *
+ * Copyright (c) 2023-2024.
  * Lizenziert unter der EUPL, Version 1.2 oder - sobald
  * diese von der Europäischen Kommission genehmigt wurden -
  * Folgeversionen der EUPL ("Lizenz");
@@ -20,17 +18,22 @@
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
 
-package de.ozgcloud.antragsraum.nachricht;
+package de.ozgcloud.antragsraum.attachments;
+
+import static de.ozgcloud.antragsraum.attachments.OzgFileTestFactory.*;
 
-import lombok.Getter;
-import lombok.RequiredArgsConstructor;
+import de.ozgcloud.vorgang.grpc.file.GrpcOzgFile;
 
-@RequiredArgsConstructor
-@Getter
-public enum NachrichtTrustLevel {
-	LOW("Niedrig"),
-	SUBSTANTIAL("Substantiell"),
-	HIGH("Hoch");
+public class GrpcOzgFileTestFactory {
+	static GrpcOzgFile create() {
+		return createBuilder().build();
+	}
 
-	private final String value;
+	static GrpcOzgFile.Builder createBuilder() {
+		return GrpcOzgFile.newBuilder()
+		  .setId(FILE_ID)
+		  .setContentType(CONTENT_TYPE)
+		  .setSize(FILE_SIZE)
+		  .setName(FILE_NAME);
+	}
 }
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/attachments/OzgFileMapperTest.java b/server/src/test/java/de/ozgcloud/antragsraum/attachments/OzgFileMapperTest.java
index 397c760d170e6ef8fba0243ba952a43a99fda254..144e9223095bbdf1b102ec096fdbcd831724c034 100644
--- a/server/src/test/java/de/ozgcloud/antragsraum/attachments/OzgFileMapperTest.java
+++ b/server/src/test/java/de/ozgcloud/antragsraum/attachments/OzgFileMapperTest.java
@@ -22,45 +22,45 @@
 
 package de.ozgcloud.antragsraum.attachments;
 
-import static de.ozgcloud.antragsraum.attachments.FileTestProperties.CONTENT_TYPE;
-import static de.ozgcloud.antragsraum.attachments.FileTestProperties.FILE_ID;
-import static de.ozgcloud.antragsraum.attachments.FileTestProperties.FILE_NAME;
-import static de.ozgcloud.antragsraum.attachments.FileTestProperties.FILE_SIZE;
-import static org.assertj.core.api.Assertions.assertThat;
+import static de.ozgcloud.antragsraum.attachments.OzgFileTestFactory.*;
+import static org.assertj.core.api.Assertions.*;
 
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
 
+import de.ozgcloud.vorgang.grpc.file.GrpcOzgFile;
+
 class OzgFileMapperTest {
+	@Nested
+	class TestMappingGrpcOzgFile {
+		private final GrpcOzgFile grpcOzgFile = GrpcOzgFileTestFactory.create();
 
-    @Nested
-    class TestMappingGrpcOzgFile {
-        @Test
-        void shouldHaveFileName() {
-            var file = OzgFileMapper.fromGrpcFile(OzgFileTestFactory.createGrpcFile());
+		@Test
+		void shouldHaveFileName() {
+			var file = OzgFileMapper.fromGrpcFile(grpcOzgFile);
 
-            assertThat(file.fileName()).isEqualTo(FILE_NAME);
-        }
+			assertThat(file.fileName()).isEqualTo(FILE_NAME);
+		}
 
-        @Test
-        void shouldHaveFileSize() {
-            var file = OzgFileMapper.fromGrpcFile(OzgFileTestFactory.createGrpcFile());
+		@Test
+		void shouldHaveFileSize() {
+			var file = OzgFileMapper.fromGrpcFile(grpcOzgFile);
 
-            assertThat(file.fileSize()).isEqualTo(FILE_SIZE);
-        }
+			assertThat(file.fileSize()).isEqualTo(FILE_SIZE);
+		}
 
-        @Test
-        void shouldHaveContentType() {
-            var file = OzgFileMapper.fromGrpcFile(OzgFileTestFactory.createGrpcFile());
+		@Test
+		void shouldHaveContentType() {
+			var file = OzgFileMapper.fromGrpcFile(grpcOzgFile);
 
-            assertThat(file.contentType()).isEqualTo(CONTENT_TYPE);
-        }
+			assertThat(file.contentType()).isEqualTo(CONTENT_TYPE);
+		}
 
-        @Test
-        void shouldHaveFileId() {
-            var file = OzgFileMapper.fromGrpcFile(OzgFileTestFactory.createGrpcFile());
+		@Test
+		void shouldHaveFileId() {
+			var file = OzgFileMapper.fromGrpcFile(grpcOzgFile);
 
-            assertThat(file.id()).isEqualTo(FILE_ID);
-        }
-    }
+			assertThat(file.id()).isEqualTo(FILE_ID);
+		}
+	}
 }
\ No newline at end of file
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/attachments/OzgFileTestFactory.java b/server/src/test/java/de/ozgcloud/antragsraum/attachments/OzgFileTestFactory.java
index 45aa7438ffba7982a3ed2e2acf3b2fb5d2b4e3f3..7ffd19c0f4eb69de55d103523e5e6b7253c7bc70 100644
--- a/server/src/test/java/de/ozgcloud/antragsraum/attachments/OzgFileTestFactory.java
+++ b/server/src/test/java/de/ozgcloud/antragsraum/attachments/OzgFileTestFactory.java
@@ -20,35 +20,29 @@
 
 package de.ozgcloud.antragsraum.attachments;
 
-import static de.ozgcloud.antragsraum.attachments.FileTestProperties.CONTENT_TYPE;
-import static de.ozgcloud.antragsraum.attachments.FileTestProperties.FILE_ID;
-import static de.ozgcloud.antragsraum.attachments.FileTestProperties.FILE_NAME;
-import static de.ozgcloud.antragsraum.attachments.FileTestProperties.FILE_SIZE;
+import java.util.UUID;
 
-import de.ozgcloud.vorgang.grpc.file.GrpcOzgFile;
+import org.apache.http.entity.ContentType;
 
 public class OzgFileTestFactory {
-    public static OzgFile createOzgFile() {
-        return createOzgFileBuilder().build();
-    }
+	static final String FILE_ID = UUID.randomUUID().toString();
+	static final String VORGANG_ID = UUID.randomUUID().toString();
+	static final String CONTENT_TYPE = ContentType.APPLICATION_OCTET_STREAM.toString();
+	static final long FILE_SIZE = 10;
+	static final String FILE_NAME = "Testfile.pdf";
+	static final String NACHRICHT_EVENT_ID = UUID.randomUUID().toString();
+	static final String CHANNEL_ADDRESS = "static://localhost:9090";
+	static final byte[] DATA = "juhu, ein bild".getBytes();
 
-    private static OzgFile.OzgFileBuilder createOzgFileBuilder() {
-        return OzgFile.builder()
-            .id(FILE_ID)
-            .contentType(CONTENT_TYPE)
-            .fileSize(FILE_SIZE)
-            .fileName(FILE_NAME);
-    }
+	public static OzgFile create() {
+		return createBuilder().build();
+	}
 
-    static GrpcOzgFile createGrpcFile() {
-        return createGrpcFileBuilder().build();
-    }
-
-    private static GrpcOzgFile.Builder createGrpcFileBuilder() {
-        return GrpcOzgFile.newBuilder()
-            .setId(FILE_ID)
-            .setContentType(CONTENT_TYPE)
-            .setSize(FILE_SIZE)
-            .setName(FILE_NAME);
-    }
+	public static OzgFile.OzgFileBuilder createBuilder() {
+		return OzgFile.builder()
+		  .id(FILE_ID)
+		  .contentType(CONTENT_TYPE)
+		  .fileSize(FILE_SIZE)
+		  .fileName(FILE_NAME);
+	}
 }
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/attachments/OzgUploadFileTestFactory.java b/server/src/test/java/de/ozgcloud/antragsraum/attachments/OzgUploadFileTestFactory.java
index b8af49c925af63c5f883ed048934492abba915f8..4fdcb9d201a0f6e9241a1ac2014de43bbefc001c 100644
--- a/server/src/test/java/de/ozgcloud/antragsraum/attachments/OzgUploadFileTestFactory.java
+++ b/server/src/test/java/de/ozgcloud/antragsraum/attachments/OzgUploadFileTestFactory.java
@@ -1,7 +1,5 @@
 /*
  * Copyright (c) 2023-2024.
- * Das Land Schleswig-Holstein vertreten durch den Ministerpräsidenten des Landes Schleswig-Holstein Staatskanzlei Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
- *
  * Lizenziert unter der EUPL, Version 1.2 oder - sobald
  * diese von der Europäischen Kommission genehmigt wurden -
  * Folgeversionen der EUPL ("Lizenz");
@@ -22,26 +20,24 @@
 
 package de.ozgcloud.antragsraum.attachments;
 
-import static de.ozgcloud.antragsraum.attachments.FileTestProperties.CONTENT_TYPE;
-import static de.ozgcloud.antragsraum.attachments.FileTestProperties.DATA;
-import static de.ozgcloud.antragsraum.attachments.FileTestProperties.FILE_NAME;
-import static de.ozgcloud.antragsraum.attachments.FileTestProperties.VORGANG_ID;
+import static de.ozgcloud.antragsraum.attachments.OzgFileTestFactory.*;
 
-import de.ozgcloud.apilib.file.OzgCloudUploadFile;
 import java.io.ByteArrayInputStream;
 
-class OzgUploadFileTestFactory {
-    static OzgUploadFile create() {
-        return createBuilder().build();
-    }
+import de.ozgcloud.apilib.file.OzgCloudUploadFile;
+
+public class OzgUploadFileTestFactory {
+	static OzgUploadFile create() {
+		return createBuilder().build();
+	}
 
-    private static OzgUploadFile.OzgUploadFileBuilder createBuilder() {
-        return new OzgUploadFile.OzgUploadFileBuilder()
-            .fileData(OzgCloudUploadFile.builder()
-                .fileName(FILE_NAME)
-                .contentType(CONTENT_TYPE)
-                .vorgangId(VORGANG_ID)
-                .build())
-            .fileContent(new ByteArrayInputStream(DATA));
-    }
+	static OzgUploadFile.OzgUploadFileBuilder createBuilder() {
+		return new OzgUploadFile.OzgUploadFileBuilder()
+		  .fileData(OzgCloudUploadFile.builder()
+			.fileName(FILE_NAME)
+			.contentType(CONTENT_TYPE)
+			.vorgangId(VORGANG_ID)
+			.build())
+		  .fileContent(new ByteArrayInputStream(DATA));
+	}
 }
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/attachments/VirusScannerClientTest.java b/server/src/test/java/de/ozgcloud/antragsraum/attachments/VirusScannerClientTest.java
old mode 100755
new mode 100644
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/command/CommandControllerITCase.java b/server/src/test/java/de/ozgcloud/antragsraum/command/CommandControllerITCase.java
new file mode 100644
index 0000000000000000000000000000000000000000..c098e33402df2c5f57766133ea662e033f2c11b0
--- /dev/null
+++ b/server/src/test/java/de/ozgcloud/antragsraum/command/CommandControllerITCase.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2023-2024.
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+package de.ozgcloud.antragsraum.command;
+
+import static org.mockito.Mockito.*;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
+
+import java.nio.charset.Charset;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.boot.test.mock.mockito.SpyBean;
+import org.springframework.http.MediaType;
+import org.springframework.security.test.context.support.WithMockUser;
+import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.ResultActions;
+
+import de.ozgcloud.antragsraum.common.TechnicalException;
+import de.ozgcloud.antragsraum.events.NachrichtEventTestFactory;
+
+@AutoConfigureMockMvc
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
+@SpringJUnitConfig(classes = { CommandControllerTestConfiguration.class })
+public class CommandControllerITCase {
+	@SpyBean
+	private CommandController commandController;
+
+	@Autowired
+	private MockMvc mockMvc;
+
+	@MockBean
+	private CommandService commandService;
+
+	@Nested
+	class TestGetCommand {
+		@BeforeEach
+		void init() {
+			when(commandService.getCommand(CommandTestFactory.ID, NachrichtEventTestFactory.ID)).thenReturn(CommandTestFactory.createCommand());
+		}
+
+		@Test
+		@WithMockUser
+		void shouldLoadCommand() throws Exception {
+			performRequest()
+			  .andExpect(status().isOk())
+			  .andExpect(jsonPath("$['id']").value(CommandTestFactory.ID));
+		}
+
+		@Test
+		void shouldNotLoadCommandUnauthorized() throws Exception {
+			performRequest().andExpect(status().isUnauthorized());
+		}
+
+		@Test
+		@WithMockUser
+		void shouldHandleRuntimeExceptions() throws Exception {
+			doThrow(RuntimeException.class).when(commandService).getCommand(CommandTestFactory.ID, NachrichtEventTestFactory.ID);
+
+			performRequest().andExpect(status().isInternalServerError());
+		}
+
+		@Test
+		@WithMockUser
+		void shouldHandleTechnicalExceptions() throws Exception {
+			doThrow(TechnicalException.class).when(commandService).getCommand(CommandTestFactory.ID, NachrichtEventTestFactory.ID);
+
+			performRequest().andExpect(status().isInternalServerError());
+		}
+
+		ResultActions performRequest() throws Exception {
+			return mockMvc.perform(
+			  get(CommandController.PATH + "/command/" + CommandTestFactory.ID + "/" + NachrichtEventTestFactory.ID)
+				.contentType(MediaType.APPLICATION_JSON).characterEncoding(Charset.defaultCharset()));
+		}
+	}
+}
\ No newline at end of file
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/command/CommandControllerTest.java b/server/src/test/java/de/ozgcloud/antragsraum/command/CommandControllerTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..4506a65dbd117175714cbb81faa648938dddff2f
--- /dev/null
+++ b/server/src/test/java/de/ozgcloud/antragsraum/command/CommandControllerTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2023-2024.
+ * Das Land Schleswig-Holstein vertreten durch den Ministerpräsidenten des Landes Schleswig-Holstein Staatskanzlei Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+ *
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+package de.ozgcloud.antragsraum.command;
+
+import static org.assertj.core.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Spy;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import de.ozgcloud.antragsraum.events.NachrichtEventTestFactory;
+
+@ExtendWith(MockitoExtension.class)
+class CommandControllerTest {
+	@Spy
+	@InjectMocks
+	private CommandController commandController;
+
+	@Mock
+	private CommandService commandService;
+
+	@Nested
+	class TestGetCommand {
+		@BeforeEach
+		void init() {
+			when(commandService.getCommand(CommandTestFactory.ID, NachrichtEventTestFactory.ID)).thenReturn(CommandTestFactory.createCommand());
+		}
+
+		@Test
+		void shouldCallGetCommand() {
+			commandController.getCommand(CommandTestFactory.ID, NachrichtEventTestFactory.ID);
+
+			verify(commandService).getCommand(CommandTestFactory.ID, NachrichtEventTestFactory.ID);
+		}
+
+		@Test
+		void shouldLoadRueckfrageHeaders() {
+			var result = commandController.getCommand(CommandTestFactory.ID, NachrichtEventTestFactory.ID);
+
+			assertThat(result).isInstanceOf(Command.class);
+		}
+	}
+}
\ No newline at end of file
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/command/CommandControllerTestConfiguration.java b/server/src/test/java/de/ozgcloud/antragsraum/command/CommandControllerTestConfiguration.java
new file mode 100644
index 0000000000000000000000000000000000000000..b3fd6d9b4861715dd560f69eb1a94d804b0db727
--- /dev/null
+++ b/server/src/test/java/de/ozgcloud/antragsraum/command/CommandControllerTestConfiguration.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2023-2024.
+ * Das Land Schleswig-Holstein vertreten durch den Ministerpräsidenten des Landes Schleswig-Holstein Staatskanzlei Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+ *
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+package de.ozgcloud.antragsraum.command;
+
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.FilterType;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+
+import net.devh.boot.grpc.client.config.GrpcChannelsProperties;
+import net.devh.boot.grpc.client.interceptor.GlobalClientInterceptorRegistry;
+
+@EnableWebMvc
+@EnableAsync
+@ComponentScan(value = { "de.ozgcloud.antragsraum.command", "de.ozgcloud.antragsraum.common" },
+  excludeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,
+	classes = CommandRemoteServiceTestConfiguration.class))
+@Configuration
+public class CommandControllerTestConfiguration {
+	@Bean
+	GrpcChannelsProperties grpcChannelsProperties() {
+		return new GrpcChannelsProperties();
+	}
+
+	@Bean
+	GlobalClientInterceptorRegistry globalClientInterceptorRegistry(final ApplicationContext applicationContext) {
+		return new GlobalClientInterceptorRegistry(applicationContext);
+	}
+}
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/command/CommandGrpcClientTest.java b/server/src/test/java/de/ozgcloud/antragsraum/command/CommandGrpcClientTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..fef5c0dd77c675b9c92bf76cd922d1e3b27074c3
--- /dev/null
+++ b/server/src/test/java/de/ozgcloud/antragsraum/command/CommandGrpcClientTest.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2023-2024.
+ * Das Land Schleswig-Holstein vertreten durch den Ministerpräsidenten des Landes Schleswig-Holstein Staatskanzlei Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+ *
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+package de.ozgcloud.antragsraum.command;
+
+import static org.assertj.core.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+import java.util.UUID;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Spy;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import com.google.common.collect.ImmutableList;
+
+import de.ozgcloud.antragsraum.common.ChannelPropertiesFactory;
+import de.ozgcloud.vorgang.grpc.command.CommandServiceGrpc;
+import de.ozgcloud.vorgang.grpc.command.GrpcCommand;
+import de.ozgcloud.vorgang.grpc.command.GrpcGetCommandRequest;
+import io.grpc.Channel;
+import net.devh.boot.grpc.client.channelfactory.GrpcChannelFactory;
+import net.devh.boot.grpc.client.config.GrpcChannelsProperties;
+import net.devh.boot.grpc.client.interceptor.GlobalClientInterceptorRegistry;
+
+@ExtendWith(MockitoExtension.class)
+class CommandGrpcClientTest {
+	private final static String CHANNEL_ADDRESS = "static://localhost:9090";
+
+	@Spy
+	@InjectMocks
+	private CommandGrpcClient grpcClient;
+
+	@Mock
+	private GlobalClientInterceptorRegistry registry;
+
+	@Mock
+	private ChannelPropertiesFactory channelPropertiesFactory;
+
+	@Nested
+	class TestCreatingChannel {
+		@BeforeEach
+		void init() {
+			when(channelPropertiesFactory.getGrpcChannelsProperties(anyString())).thenReturn(new GrpcChannelsProperties());
+		}
+
+		@Test
+		void shouldGetChannelFactory() {
+			var channelFactory = grpcClient.getChannelFactory(CHANNEL_ADDRESS);
+
+			assertThat(channelFactory).isNotNull();
+		}
+
+		@Test
+		void shouldGetChannel() {
+			when(registry.getClientInterceptors()).thenReturn(ImmutableList.of());
+
+			var channel = grpcClient.getChannelFactory(CHANNEL_ADDRESS).createChannel(CHANNEL_ADDRESS);
+
+			assertThat(channel).isNotNull();
+		}
+	}
+
+	@Nested
+	class TestGetCommand {
+		@Mock
+		private CommandServiceGrpc.CommandServiceBlockingStub commandServiceBlockingStub;
+		@Mock
+		private GrpcGetCommandRequest request;
+
+		@Test
+		void shouldCallGetGrpcCommand() {
+			var channelFactory = mock(GrpcChannelFactory.class);
+			var channel = mock(Channel.class);
+			when(channelFactory.createChannel(anyString())).thenReturn(channel);
+			doReturn(channelFactory).when(grpcClient).getChannelFactory(anyString());
+			doReturn(mock(GrpcCommand.class)).when(grpcClient).getGrpcCommand(any(), any(GrpcGetCommandRequest.class));
+
+			var request = GrpcGetCommandRequest.newBuilder().setId(UUID.randomUUID().toString()).build();
+			grpcClient.getCommand(request, CHANNEL_ADDRESS);
+
+			verify(grpcClient).getGrpcCommand(any(), any(GrpcGetCommandRequest.class));
+		}
+
+		@Test
+		void shouldGetCommand() {
+			grpcClient.getGrpcCommand(commandServiceBlockingStub, request);
+
+			verify(commandServiceBlockingStub).getCommand(any(GrpcGetCommandRequest.class));
+		}
+	}
+}
\ No newline at end of file
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/nachricht/CommandGrpcService.java b/server/src/test/java/de/ozgcloud/antragsraum/command/CommandGrpcService.java
old mode 100755
new mode 100644
similarity index 77%
rename from server/src/test/java/de/ozgcloud/antragsraum/nachricht/CommandGrpcService.java
rename to server/src/test/java/de/ozgcloud/antragsraum/command/CommandGrpcService.java
index 9cd3871cf1cce286ce3af714bdb8134f673161d2..b5266b1043bc83f62d0d3ddac38c6b21f3f7e080
--- a/server/src/test/java/de/ozgcloud/antragsraum/nachricht/CommandGrpcService.java
+++ b/server/src/test/java/de/ozgcloud/antragsraum/command/CommandGrpcService.java
@@ -19,9 +19,7 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-package de.ozgcloud.antragsraum.nachricht;
-
-import java.util.UUID;
+package de.ozgcloud.antragsraum.command;
 
 import de.ozgcloud.vorgang.grpc.command.CommandServiceGrpc;
 import de.ozgcloud.vorgang.grpc.command.GrpcCommand;
@@ -31,15 +29,9 @@ import net.devh.boot.grpc.server.service.GrpcService;
 
 @GrpcService
 public class CommandGrpcService extends CommandServiceGrpc.CommandServiceImplBase {
-
 	@Override
 	public void getCommand(GrpcGetCommandRequest request, StreamObserver<GrpcCommand> observer) {
-		if (GrpcCommandTestFactory.ID.equals(request.getId())) {
-			observer.onNext(GrpcCommandTestFactory.createBuilder().setStatus(GrpcCommandTestFactory.STATUS_FINISHED).build());
-		} else {
-			observer.onNext(GrpcCommandTestFactory.createBuilder()
-			  .setStatus(GrpcCommandTestFactory.STATUS_PENDING).setId(UUID.randomUUID().toString()).build());
-		}
+		observer.onNext(CommandTestFactory.createGrpcCommand());
 		observer.onCompleted();
 	}
 }
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/command/CommandMapperTest.java b/server/src/test/java/de/ozgcloud/antragsraum/command/CommandMapperTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..68ef942ae23ca3945a0b9684c29bde2a27686586
--- /dev/null
+++ b/server/src/test/java/de/ozgcloud/antragsraum/command/CommandMapperTest.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2023-2024.
+ * Das Land Schleswig-Holstein vertreten durch den Ministerpräsidenten des Landes Schleswig-Holstein Staatskanzlei Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+ *
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+package de.ozgcloud.antragsraum.command;
+
+import static org.assertj.core.api.Assertions.*;
+
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+
+import de.ozgcloud.vorgang.grpc.command.GrpcCommand;
+
+class CommandMapperTest {
+	@Nested
+	class TestFromGrpcCommand {
+		private final GrpcCommand grpcCommand = CommandTestFactory.createGrpcCommand();
+
+		@Test
+		void shouldMapCommandId() {
+			var command = CommandMapper.fromGrpcCommand(grpcCommand, CommandTestFactory.NACHRICHT_EVENT_ID);
+
+			assertThat(command.id()).isEqualTo(CommandTestFactory.ID);
+		}
+
+		@Test
+		void shouldMapNachrichtEventId() {
+			var command = CommandMapper.fromGrpcCommand(grpcCommand, CommandTestFactory.NACHRICHT_EVENT_ID);
+
+			assertThat(command.nachrichtEventId()).isEqualTo(CommandTestFactory.NACHRICHT_EVENT_ID);
+		}
+
+		@Test
+		void shouldMapStatus() {
+			var command = CommandMapper.fromGrpcCommand(grpcCommand, CommandTestFactory.NACHRICHT_EVENT_ID);
+
+			assertThat(command.status()).isEqualTo(CommandTestFactory.STATUS);
+		}
+
+		@Test
+		void shouldMapCreatedAt() {
+			var command = CommandMapper.fromGrpcCommand(grpcCommand, CommandTestFactory.NACHRICHT_EVENT_ID);
+
+			assertThat(command.createdAt()).isEqualTo(CommandTestFactory.CREATED_AT_DATE);
+		}
+
+		@Test
+		void shouldMapFinishedAt() {
+			var command = CommandMapper.fromGrpcCommand(grpcCommand, CommandTestFactory.NACHRICHT_EVENT_ID);
+
+			assertThat(command.finishedAt()).isEqualTo(CommandTestFactory.FINISHED_AT_DATE);
+		}
+	}
+}
\ No newline at end of file
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/events/GrpcNachrichtTestFactory.java b/server/src/test/java/de/ozgcloud/antragsraum/command/CommandReferenceTestFactory.java
similarity index 67%
rename from server/src/test/java/de/ozgcloud/antragsraum/events/GrpcNachrichtTestFactory.java
rename to server/src/test/java/de/ozgcloud/antragsraum/command/CommandReferenceTestFactory.java
index 4565b306d4e90144ec9ce5c4678f66641a4c8c4c..1dfbd06d5d538f4e3bbc9c2037ab6f2e715d0257 100644
--- a/server/src/test/java/de/ozgcloud/antragsraum/events/GrpcNachrichtTestFactory.java
+++ b/server/src/test/java/de/ozgcloud/antragsraum/command/CommandReferenceTestFactory.java
@@ -19,16 +19,21 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
+package de.ozgcloud.antragsraum.command;
 
-package de.ozgcloud.antragsraum.events;
-
-import de.ozgcloud.info.nachricht.GrpcNachricht;
 import java.util.UUID;
 
-class GrpcNachrichtTestFactory {
-    static final String POSTFACH_ID = UUID.randomUUID().toString();
+public class CommandReferenceTestFactory {
+	public static final String ID = UUID.randomUUID().toString();
+	public static final String NACHRICHT_EVENT_ID = UUID.randomUUID().toString();
+
+	public static CommandReference create() {
+		return createBuilder().build();
+	}
 
-    static GrpcNachricht.Builder createBuilder() {
-        return GrpcNachricht.newBuilder().setPostfachId(POSTFACH_ID);
-    }
+	public static CommandReference.CommandReferenceBuilder createBuilder() {
+		return CommandReference.builder()
+		  .id(ID)
+		  .nachrichtEventId(NACHRICHT_EVENT_ID);
+	}
 }
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/command/CommandRemoteServiceITCase.java b/server/src/test/java/de/ozgcloud/antragsraum/command/CommandRemoteServiceITCase.java
new file mode 100644
index 0000000000000000000000000000000000000000..3e0bfa3bdaa228c178cc76f11f304986bc2a1387
--- /dev/null
+++ b/server/src/test/java/de/ozgcloud/antragsraum/command/CommandRemoteServiceITCase.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2023-2024.
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+package de.ozgcloud.antragsraum.command;
+
+import static org.assertj.core.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.SpyBean;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
+
+import de.ozgcloud.antragsraum.events.NachrichtEvent;
+import de.ozgcloud.antragsraum.events.NachrichtEventTestFactory;
+import lombok.extern.log4j.Log4j2;
+
+@SpringBootTest(properties = {
+  "grpc.server.inProcessName=test2",
+  "grpc.server.port=-1"
+})
+@SpringJUnitConfig(classes = { CommandRemoteServiceTestConfiguration.class })
+@DirtiesContext
+@ExtendWith(MockitoExtension.class)
+@Log4j2
+class CommandRemoteServiceITCase {
+	private static final String ADDRESS = "in-process:test2";
+
+	@SpyBean
+	CommandRemoteService commandRemoteService;
+
+	@Nested
+	class TestGetCommand {
+		private final NachrichtEvent nachrichtEvent = NachrichtEventTestFactory.createNachrichtEventBuilder().address(ADDRESS).build();
+
+		@BeforeEach
+		void setup() {
+			UsernamePasswordAuthenticationToken authentication = mock(UsernamePasswordAuthenticationToken.class);
+			lenient().when(authentication.getCredentials()).thenReturn("jwt-token");
+			SecurityContextHolder.getContext().setAuthentication(authentication);
+		}
+
+		@Test
+		void shouldLoadCommand() {
+			var command = commandRemoteService.getCommand(nachrichtEvent, CommandTestFactory.ID);
+
+			assertThat(command).isInstanceOf(Command.class);
+		}
+
+		@Test
+		void shouldHaveCommandId() {
+			var command = commandRemoteService.getCommand(nachrichtEvent, CommandTestFactory.ID);
+
+			assertThat(command.id()).isEqualTo(CommandTestFactory.ID);
+		}
+
+		@Test
+		void shouldHaveNachrichtEventId() {
+			var command = commandRemoteService.getCommand(nachrichtEvent, CommandTestFactory.ID);
+
+			assertThat(command.nachrichtEventId()).isEqualTo(NachrichtEventTestFactory.ID);
+		}
+
+		@Test
+		void shouldHaveStatus() {
+			var command = commandRemoteService.getCommand(nachrichtEvent, CommandTestFactory.ID);
+
+			assertThat(command.status()).isEqualTo(CommandTestFactory.STATUS);
+		}
+
+		@Test
+		void shouldHaveCreatedAt() {
+			var command = commandRemoteService.getCommand(nachrichtEvent, CommandTestFactory.ID);
+
+			assertThat(command.createdAt()).isEqualTo(CommandTestFactory.CREATED_AT_DATE);
+		}
+
+		@Test
+		void shouldHaveFinishedAt() {
+			var command = commandRemoteService.getCommand(nachrichtEvent, CommandTestFactory.ID);
+
+			assertThat(command.finishedAt()).isEqualTo(CommandTestFactory.FINISHED_AT_DATE);
+		}
+	}
+}
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/command/CommandRemoteServiceTest.java b/server/src/test/java/de/ozgcloud/antragsraum/command/CommandRemoteServiceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..11a5f48f403ddb5436c50f65a0e2c8647a0cefd5
--- /dev/null
+++ b/server/src/test/java/de/ozgcloud/antragsraum/command/CommandRemoteServiceTest.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2023-2024.
+ * Das Land Schleswig-Holstein vertreten durch den Ministerpräsidenten des Landes Schleswig-Holstein Staatskanzlei Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+ *
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+
+package de.ozgcloud.antragsraum.command;
+
+import static org.assertj.core.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Spy;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import de.ozgcloud.antragsraum.common.AddressNotFoundException;
+import de.ozgcloud.antragsraum.events.NachrichtEventTestFactory;
+import de.ozgcloud.vorgang.grpc.command.GrpcGetCommandRequest;
+
+@ExtendWith(MockitoExtension.class)
+public class CommandRemoteServiceTest {
+	@Spy
+	@InjectMocks
+	private CommandRemoteService commandRemoteService;
+
+	@Mock
+	private CommandGrpcClient commandGrpcClient;
+
+	@Nested
+	class TestGetCommand {
+		@BeforeEach
+		void init() {
+			when(commandGrpcClient.getCommand(any(GrpcGetCommandRequest.class), anyString())).thenReturn(CommandTestFactory.createGrpcCommand());
+		}
+
+		@Test
+		void shouldLoadCommand() {
+			var command = commandRemoteService.getCommand(NachrichtEventTestFactory.createNachrichtEvent(), CommandTestFactory.ID);
+
+			assertThat(command).isInstanceOf(Command.class);
+		}
+	}
+
+	@Nested
+	class TestNoTargetAddressAvailable {
+		@BeforeEach
+		void init() {
+			doThrow(AddressNotFoundException.class).when(commandGrpcClient).getCommand(any(GrpcGetCommandRequest.class), anyString());
+		}
+
+		@Test
+		void shouldThrowAddressNotFoundException() {
+			var nachrichtEvent = NachrichtEventTestFactory.createNachrichtEvent();
+
+			assertThatExceptionOfType(AddressNotFoundException.class).isThrownBy(
+			  () -> commandRemoteService.getCommand(nachrichtEvent, CommandTestFactory.ID));
+		}
+	}
+}
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/command/CommandRemoteServiceTestConfiguration.java b/server/src/test/java/de/ozgcloud/antragsraum/command/CommandRemoteServiceTestConfiguration.java
new file mode 100644
index 0000000000000000000000000000000000000000..166c3a25c2e5057c188da10f9fdd423bf616a87c
--- /dev/null
+++ b/server/src/test/java/de/ozgcloud/antragsraum/command/CommandRemoteServiceTestConfiguration.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2023-2024.
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+package de.ozgcloud.antragsraum.command;
+
+import static org.mockito.Mockito.*;
+
+import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import com.google.common.collect.ImmutableList;
+
+import de.ozgcloud.antragsraum.callcontext.CallContextAttachingInterceptor;
+import de.ozgcloud.antragsraum.callcontext.ContextService;
+import de.ozgcloud.antragsraum.common.AuthenticationHelper;
+import de.ozgcloud.antragsraum.common.ChannelPropertiesFactory;
+import lombok.NonNull;
+import net.devh.boot.grpc.client.autoconfigure.GrpcClientAutoConfiguration;
+import net.devh.boot.grpc.client.autoconfigure.GrpcClientHealthAutoConfiguration;
+import net.devh.boot.grpc.client.autoconfigure.GrpcClientMetricAutoConfiguration;
+import net.devh.boot.grpc.client.autoconfigure.GrpcClientSecurityAutoConfiguration;
+import net.devh.boot.grpc.client.autoconfigure.GrpcClientTraceAutoConfiguration;
+import net.devh.boot.grpc.client.config.GrpcChannelsProperties;
+import net.devh.boot.grpc.client.interceptor.GlobalClientInterceptorRegistry;
+import net.devh.boot.grpc.common.autoconfigure.GrpcCommonCodecAutoConfiguration;
+import net.devh.boot.grpc.common.autoconfigure.GrpcCommonTraceAutoConfiguration;
+import net.devh.boot.grpc.server.autoconfigure.GrpcServerAutoConfiguration;
+import net.devh.boot.grpc.server.autoconfigure.GrpcServerFactoryAutoConfiguration;
+
+@Configuration
+@ImportAutoConfiguration({
+  GrpcCommonCodecAutoConfiguration.class,
+  GrpcCommonTraceAutoConfiguration.class,
+
+  GrpcServerAutoConfiguration.class,
+  GrpcServerFactoryAutoConfiguration.class,
+
+  GrpcClientAutoConfiguration.class,
+  GrpcClientHealthAutoConfiguration.class,
+  GrpcClientMetricAutoConfiguration.class,
+  GrpcClientSecurityAutoConfiguration.class,
+  GrpcClientTraceAutoConfiguration.class
+})
+public class CommandRemoteServiceTestConfiguration {
+	@Bean
+	CommandGrpcService commandGrpcService() {
+		return new CommandGrpcService();
+	}
+
+	@Bean
+	CommandRemoteService commandRemoteService() {
+		return new CommandRemoteService(commandGrpcClient());
+	}
+
+	CommandGrpcClient commandGrpcClient() {
+		return new CommandGrpcClient(initGlobalClientInterceptorRegistry(), initChannelsPropertiesFactory());
+	}
+
+	@Bean
+	public ContextService contextService() {
+		return new ContextService(authenticationHelper());
+	}
+
+	@Bean
+	public AuthenticationHelper authenticationHelper() {
+		return new AuthenticationHelper();
+	}
+
+	private GlobalClientInterceptorRegistry initGlobalClientInterceptorRegistry() {
+		GlobalClientInterceptorRegistry globalClientInterceptorRegistry = mock(GlobalClientInterceptorRegistry.class);
+		when(globalClientInterceptorRegistry.getClientInterceptors()).thenReturn(
+		  ImmutableList.of(new CallContextAttachingInterceptor(contextService())));
+
+		return globalClientInterceptorRegistry;
+	}
+
+	@NonNull
+	private static ChannelPropertiesFactory initChannelsPropertiesFactory() {
+		return new ChannelPropertiesFactory(new GrpcChannelsProperties());
+	}
+}
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/command/CommandServiceTest.java b/server/src/test/java/de/ozgcloud/antragsraum/command/CommandServiceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..9b92ed59efcc385dc9ce8058e79af86d101e962e
--- /dev/null
+++ b/server/src/test/java/de/ozgcloud/antragsraum/command/CommandServiceTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2023-2024.
+ * Das Land Schleswig-Holstein vertreten durch den Ministerpräsidenten des Landes Schleswig-Holstein Staatskanzlei Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+ *
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+package de.ozgcloud.antragsraum.command;
+
+import static org.assertj.core.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Spy;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import de.ozgcloud.antragsraum.events.NachrichtEvent;
+import de.ozgcloud.antragsraum.events.NachrichtEventService;
+import de.ozgcloud.antragsraum.events.NachrichtEventTestFactory;
+
+@ExtendWith(MockitoExtension.class)
+class CommandServiceTest {
+	@Spy
+	@InjectMocks
+	private CommandService commandService;
+	@Mock
+	private CommandRemoteService commandRemoteService;
+	@Mock
+	private NachrichtEventService nachrichtEventService;
+
+	@Nested
+	class TestGetCommand {
+		@BeforeEach
+		void init() {
+			final NachrichtEvent nachrichtEvent = NachrichtEventTestFactory.createNachrichtEvent();
+			when(nachrichtEventService.getNachrichtEventById(NachrichtEventTestFactory.ID)).thenReturn(nachrichtEvent);
+			when(commandRemoteService.getCommand(nachrichtEvent, CommandTestFactory.ID)).thenReturn(CommandTestFactory.createCommand());
+		}
+
+		@Test
+		void shouldReturnCommand() {
+			var result = commandService.getCommand(CommandTestFactory.ID, NachrichtEventTestFactory.ID);
+
+			assertThat(result).isInstanceOf(Command.class);
+		}
+	}
+}
\ No newline at end of file
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/command/CommandTestFactory.java b/server/src/test/java/de/ozgcloud/antragsraum/command/CommandTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..86936a7aa43ddad63e8bb3ed85f8822dd12d692b
--- /dev/null
+++ b/server/src/test/java/de/ozgcloud/antragsraum/command/CommandTestFactory.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2023-2024.
+ * Das Land Schleswig-Holstein vertreten durch den Ministerpräsidenten des Landes Schleswig-Holstein Staatskanzlei Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+ *
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+package de.ozgcloud.antragsraum.command;
+
+import java.time.ZonedDateTime;
+import java.util.UUID;
+
+import de.ozgcloud.vorgang.grpc.command.GrpcCommand;
+
+public class CommandTestFactory {
+	public static final String ID = UUID.randomUUID().toString();
+	static final String NACHRICHT_EVENT_ID = UUID.randomUUID().toString();
+	static final String STATUS = "FINISHED";
+	static final String CREATED_AT = "2024-06-24T08:09:57.076Z";
+	static final long CREATED_AT_DATE = ZonedDateTime.parse(CREATED_AT).toEpochSecond() * 1000;
+	static final String FINISHED_AT = "2024-06-24T08:10:13.076Z";
+	static final long FINISHED_AT_DATE = ZonedDateTime.parse(FINISHED_AT).toEpochSecond() * 1000;
+
+	static Command createCommand() {
+		return createCommandBuilder().build();
+	}
+
+	static Command.CommandBuilder createCommandBuilder() {
+		return Command.builder()
+		  .id(ID)
+		  .nachrichtEventId(NACHRICHT_EVENT_ID)
+		  .status(STATUS)
+		  .createdAt(CREATED_AT_DATE)
+		  .finishedAt(FINISHED_AT_DATE);
+	}
+
+	static GrpcCommand createGrpcCommand() {
+		return createGrpcCommandBuilder().build();
+	}
+
+	static GrpcCommand.Builder createGrpcCommandBuilder() {
+		return GrpcCommand.newBuilder()
+		  .setId(ID)
+		  .setStatus(STATUS)
+		  .setCreatedAt(CREATED_AT)
+		  .setFinishedAt(FINISHED_AT);
+	}
+}
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/common/InsufficientTrustLevelExceptionTest.java b/server/src/test/java/de/ozgcloud/antragsraum/common/NotAccessibleExceptionTest.java
similarity index 77%
rename from server/src/test/java/de/ozgcloud/antragsraum/common/InsufficientTrustLevelExceptionTest.java
rename to server/src/test/java/de/ozgcloud/antragsraum/common/NotAccessibleExceptionTest.java
index b7d3edc4e2a6def49a8a60a77816d390fe067ff3..1c92b68d628b88f86c5b02d2c430d7b2e76298ec 100644
--- a/server/src/test/java/de/ozgcloud/antragsraum/common/InsufficientTrustLevelExceptionTest.java
+++ b/server/src/test/java/de/ozgcloud/antragsraum/common/NotAccessibleExceptionTest.java
@@ -1,6 +1,6 @@
 /*
- * Copyright (c) 2023-2024.
- * Das Land Schleswig-Holstein vertreten durch den Ministerpräsidenten des Landes Schleswig-Holstein Staatskanzlei Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+ * Copyright (c) 2023-2024.   Das Land Schleswig-Holstein vertreten durch den Ministerpräsidenten
+ * des Landes Schleswig-Holstein Staatskanzlei Abteilung Digitalisierung und zentrales IT-Management der Landesregierung.
  *
  * Lizenziert unter der EUPL, Version 1.2 oder - sobald
  * diese von der Europäischen Kommission genehmigt wurden -
@@ -27,11 +27,11 @@ import java.util.UUID;
 
 import org.junit.jupiter.api.Test;
 
-class InsufficientTrustLevelExceptionTest {
+class NotAccessibleExceptionTest {
 	@Test
 	void shouldCreateException() {
 		var rueckfrageId = UUID.randomUUID().toString();
-		var exception = new InsufficientTrustLevelException(rueckfrageId);
+		var exception = new NotAccessibleException(rueckfrageId);
 
 		assertThat(exception.getMessage()).isEqualTo(
 		  "Current user does not have the required trust level for the Rueckfrage with id '" + rueckfrageId + "'.");
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/events/InformationGrpcServiceStub.java b/server/src/test/java/de/ozgcloud/antragsraum/events/InformationGrpcServiceStub.java
index 1da4b261c993fd5d81b0d1ee443f6e3d494ef1aa..a9b7ed61941174ada6b4b09204529688b599c6ce 100644
--- a/server/src/test/java/de/ozgcloud/antragsraum/events/InformationGrpcServiceStub.java
+++ b/server/src/test/java/de/ozgcloud/antragsraum/events/InformationGrpcServiceStub.java
@@ -20,32 +20,51 @@
 
 package de.ozgcloud.antragsraum.events;
 
-import de.ozgcloud.antragsraum.nachricht.NachrichtEventTestFactory;
+import java.util.UUID;
+
+import de.ozgcloud.info.GrpcInformationByIdRequest;
+import de.ozgcloud.info.GrpcInformationByIdResponse;
+import de.ozgcloud.info.GrpcInformationNachricht;
 import de.ozgcloud.info.GrpcInformationRequest;
 import de.ozgcloud.info.GrpcInformationResponse;
 import de.ozgcloud.info.InformationServiceGrpc;
-import de.ozgcloud.info.nachricht.GrpcNachricht;
+import io.grpc.Status;
 import io.grpc.stub.StreamObserver;
 import net.devh.boot.grpc.server.service.GrpcService;
 
 @GrpcService
 public class InformationGrpcServiceStub extends InformationServiceGrpc.InformationServiceImplBase {
-    public static final NachrichtEvent NACHRICHT_EVENT = NachrichtEventTestFactory.create();
-    public static final String EMPTY_POSTFACH_ID = "550e8400-e29b-41d4-a716-446655440000";
+	public static final String ID = UUID.randomUUID().toString();
+	public static final String EMPTY_ID = UUID.randomUUID().toString();
+	public static final String POSTFACH_ID = UUID.randomUUID().toString();
+	public static final String EMPTY_POSTFACH_ID = "550e8400-e29b-41d4-a716-446655440000";
+
+	@Override
+	public void getInformationById(final GrpcInformationByIdRequest request, final StreamObserver<GrpcInformationByIdResponse> responseObserver) {
+		if (request.getId().equals(EMPTY_ID)) {
+			responseObserver.onError(Status.INVALID_ARGUMENT.asRuntimeException());
+		} else {
+			responseObserver.onNext(GrpcInformationByIdResponse.newBuilder()
+			  .setNachricht(GrpcInformationNachricht.newBuilder()
+				.setPostfachId(POSTFACH_ID)
+				.build())
+			  .build());
+			responseObserver.onCompleted();
+		}
+	}
 
-    @Override
-    public void getInformation(GrpcInformationRequest request,
-                               StreamObserver<GrpcInformationResponse> responseObserver) {
-        if (request.getPostfachId().equals(EMPTY_POSTFACH_ID)) {
-            responseObserver.onNext(GrpcInformationResponse.getDefaultInstance());
-        } else {
-            responseObserver.onNext(GrpcInformationResponse.newBuilder()
-                .addNachrichten(GrpcNachricht.newBuilder()
-                    .setPostfachId(NACHRICHT_EVENT.postfachId())
-                    .build()).build()
-            );
-        }
+	@Override
+	public void getInformation(GrpcInformationRequest request, StreamObserver<GrpcInformationResponse> responseObserver) {
+		if (request.getPostfachId().equals(EMPTY_POSTFACH_ID)) {
+			responseObserver.onNext(GrpcInformationResponse.getDefaultInstance());
+		} else {
+			responseObserver.onNext(GrpcInformationResponse.newBuilder()
+			  .addNachrichten(GrpcInformationNachricht.newBuilder()
+				.setPostfachId(POSTFACH_ID)
+				.build()).build()
+			);
+		}
 
-        responseObserver.onCompleted();
-    }
+		responseObserver.onCompleted();
+	}
 }
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/events/NachrichtEventGrpcTestConfiguration.java b/server/src/test/java/de/ozgcloud/antragsraum/events/NachrichtEventGrpcTestConfiguration.java
index ec340df8191c4c5380e315eb30f97303b0c65e44..32c4eeafb7fdc4f33ffeefac69e7e68c136d1e4b 100644
--- a/server/src/test/java/de/ozgcloud/antragsraum/events/NachrichtEventGrpcTestConfiguration.java
+++ b/server/src/test/java/de/ozgcloud/antragsraum/events/NachrichtEventGrpcTestConfiguration.java
@@ -19,45 +19,52 @@
  */
 package de.ozgcloud.antragsraum.events;
 
+import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
 import de.ozgcloud.info.InformationServiceGrpc;
-import net.devh.boot.grpc.client.autoconfigure.*;
+import net.devh.boot.grpc.client.autoconfigure.GrpcClientAutoConfiguration;
+import net.devh.boot.grpc.client.autoconfigure.GrpcClientHealthAutoConfiguration;
+import net.devh.boot.grpc.client.autoconfigure.GrpcClientMetricAutoConfiguration;
+import net.devh.boot.grpc.client.autoconfigure.GrpcClientSecurityAutoConfiguration;
+import net.devh.boot.grpc.client.autoconfigure.GrpcClientTraceAutoConfiguration;
+import net.devh.boot.grpc.client.autoconfigure.GrpcDiscoveryClientAutoConfiguration;
 import net.devh.boot.grpc.client.inject.GrpcClient;
 import net.devh.boot.grpc.common.autoconfigure.GrpcCommonCodecAutoConfiguration;
 import net.devh.boot.grpc.common.autoconfigure.GrpcCommonTraceAutoConfiguration;
 import net.devh.boot.grpc.server.autoconfigure.GrpcServerAutoConfiguration;
 import net.devh.boot.grpc.server.autoconfigure.GrpcServerFactoryAutoConfiguration;
-import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
 
 @Configuration
 @ImportAutoConfiguration({
-        GrpcCommonCodecAutoConfiguration.class,
-        GrpcCommonTraceAutoConfiguration.class,
-
-        GrpcServerAutoConfiguration.class,
-        GrpcServerFactoryAutoConfiguration.class,
-
-        GrpcClientAutoConfiguration.class,
-        GrpcClientHealthAutoConfiguration.class,
-        GrpcClientMetricAutoConfiguration.class,
-        GrpcClientSecurityAutoConfiguration.class,
-        GrpcClientTraceAutoConfiguration.class,
-        GrpcDiscoveryClientAutoConfiguration.class
+  GrpcCommonCodecAutoConfiguration.class,
+  GrpcCommonTraceAutoConfiguration.class,
+
+  GrpcServerAutoConfiguration.class,
+  GrpcServerFactoryAutoConfiguration.class,
+
+  GrpcClientAutoConfiguration.class,
+  GrpcClientHealthAutoConfiguration.class,
+  GrpcClientMetricAutoConfiguration.class,
+  GrpcClientSecurityAutoConfiguration.class,
+  GrpcClientTraceAutoConfiguration.class,
+  GrpcDiscoveryClientAutoConfiguration.class
 })
 public class NachrichtEventGrpcTestConfiguration {
-    @Bean
-    InformationGrpcServiceStub informationServiceGrpcStub() {
-        return new InformationGrpcServiceStub();
-    }
-
-    @GrpcClient("info-manager")
-    InformationServiceGrpc.InformationServiceBlockingStub informationServiceBlockingClient;
-
-    @Bean
-    NachrichtEventRemoteService nachrichtEventRemoteService() {
-        var nachrichtEventRemoteService = new NachrichtEventRemoteService();
-        nachrichtEventRemoteService.informationServiceBlockingClient = informationServiceBlockingClient;
-        return nachrichtEventRemoteService;
-    }
+	@Bean
+	InformationGrpcServiceStub informationServiceGrpcStub() {
+		return new InformationGrpcServiceStub();
+	}
+
+	@GrpcClient("info-manager")
+	InformationServiceGrpc.InformationServiceBlockingStub informationServiceBlockingClient;
+
+	@Bean
+	NachrichtEventRemoteService nachrichtEventRemoteService() {
+		var nachrichtEventRemoteService = new NachrichtEventRemoteService();
+		nachrichtEventRemoteService.informationServiceBlockingClient = informationServiceBlockingClient;
+
+		return nachrichtEventRemoteService;
+	}
 }
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/events/NachrichtEventMapperTest.java b/server/src/test/java/de/ozgcloud/antragsraum/events/NachrichtEventMapperTest.java
index da1b4d0fd70f6a773370b04e3b03f23d520dc23e..42c38f2489af5af819d001c8ab2255efe453ad17 100644
--- a/server/src/test/java/de/ozgcloud/antragsraum/events/NachrichtEventMapperTest.java
+++ b/server/src/test/java/de/ozgcloud/antragsraum/events/NachrichtEventMapperTest.java
@@ -21,26 +21,44 @@
  */
 package de.ozgcloud.antragsraum.events;
 
+import static org.assertj.core.api.Assertions.*;
+
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
 
-import static org.assertj.core.api.Assertions.*;
+import de.ozgcloud.info.GrpcInformationNachricht;
 
 class NachrichtEventMapperTest {
 	@Nested
-	class TestMapFromGrpc {
+	class TestFromGrpcInformationNachricht {
+		private final GrpcInformationNachricht grpcInformationNachricht = NachrichtEventTestFactory.createGrpcInformationNachricht();
+
 		@Test
 		void shouldMap() {
-			var nachrichtEvent = NachrichtEventMapper.fromGrpc(GrpcNachrichtTestFactory.createBuilder().build());
+			var nachrichtEvent = NachrichtEventMapper.fromGrpcInformationNachricht(grpcInformationNachricht);
 
 			assertThat(nachrichtEvent).isNotNull();
 		}
 
+		@Test
+		void shouldHaveId() {
+			var nachrichtEvent = NachrichtEventMapper.fromGrpcInformationNachricht(grpcInformationNachricht);
+
+			assertThat(nachrichtEvent.id()).isEqualTo(NachrichtEventTestFactory.ID);
+		}
+
 		@Test
 		void shouldHavePostfachId() {
-			var nachrichtEvent = NachrichtEventMapper.fromGrpc(GrpcNachrichtTestFactory.createBuilder().build());
+			var nachrichtEvent = NachrichtEventMapper.fromGrpcInformationNachricht(grpcInformationNachricht);
+
+			assertThat(nachrichtEvent.postfachId()).isEqualTo(NachrichtEventTestFactory.POSTFACH_ID);
+		}
+
+		@Test
+		void shouldHaveOzgCloudAddress() {
+			var nachrichtEvent = NachrichtEventMapper.fromGrpcInformationNachricht(grpcInformationNachricht);
 
-			assertThat(nachrichtEvent.postfachId()).isEqualTo(GrpcNachrichtTestFactory.POSTFACH_ID);
+			assertThat(nachrichtEvent.address()).isEqualTo(NachrichtEventTestFactory.URL);
 		}
 	}
 }
\ No newline at end of file
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/events/NachrichtEventRemoteServiceITCase.java b/server/src/test/java/de/ozgcloud/antragsraum/events/NachrichtEventRemoteServiceITCase.java
index 0b9018036108e73a81000477a7c1813498a53370..b5adab4110bd8ccf9422cdca32fa4b6f0b7bc16f 100644
--- a/server/src/test/java/de/ozgcloud/antragsraum/events/NachrichtEventRemoteServiceITCase.java
+++ b/server/src/test/java/de/ozgcloud/antragsraum/events/NachrichtEventRemoteServiceITCase.java
@@ -21,6 +21,9 @@
  */
 package de.ozgcloud.antragsraum.events;
 
+import static org.assertj.core.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.*;
+
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
@@ -30,28 +33,26 @@ import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.test.annotation.DirtiesContext;
 import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
 
-import static org.assertj.core.api.Assertions.*;
+import io.grpc.StatusRuntimeException;
 
 @SpringBootTest(properties = {
-		"grpc.server.inProcessName=test",
-		"grpc.server.port=-1",
-		"grpc.client.inProcess.address=in-process:test"
+  "grpc.server.inProcessName=test",
+  "grpc.server.port=-1",
+  "grpc.client.inProcess.address=in-process:test"
 })
-@SpringJUnitConfig(classes = {NachrichtEventGrpcTestConfiguration.class})
+@SpringJUnitConfig(classes = { NachrichtEventGrpcTestConfiguration.class })
 @DirtiesContext
 @ExtendWith(MockitoExtension.class)
 class NachrichtEventRemoteServiceITCase {
-
 	@Autowired
 	NachrichtEventRemoteService nachrichtEventRemoteService;
 
 	@Nested
 	class TestInformationAvailable {
-
 		@Test
 		@DirtiesContext
 		void shouldLoadNachrichtEvents() {
-			var result = nachrichtEventRemoteService.getNachrichtEventsOfPostfach(InformationGrpcServiceStub.NACHRICHT_EVENT.postfachId());
+			var result = nachrichtEventRemoteService.getNachrichtEventsOfPostfach(InformationGrpcServiceStub.POSTFACH_ID);
 
 			assertThat(result).hasSize(1);
 		}
@@ -66,4 +67,24 @@ class NachrichtEventRemoteServiceITCase {
 			assertThat(result).isEmpty();
 		}
 	}
+
+	@Nested
+	class TestInformationByIdAvailable {
+		@Test
+		@DirtiesContext
+		void shouldLoadNachrichtEventById() {
+			var result = nachrichtEventRemoteService.getNachrichtEventById(InformationGrpcServiceStub.ID);
+
+			assertThat(result).isInstanceOf(NachrichtEvent.class);
+		}
+	}
+
+	@Nested
+	class TestNoInformationByIdAvailable {
+		@Test
+		@DirtiesContext
+		void shouldThrowStatusRuntimeException() {
+			assertThrows(StatusRuntimeException.class, () -> nachrichtEventRemoteService.getNachrichtEventById(InformationGrpcServiceStub.EMPTY_ID));
+		}
+	}
 }
\ No newline at end of file
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/events/NachrichtEventRemoteServiceTest.java b/server/src/test/java/de/ozgcloud/antragsraum/events/NachrichtEventRemoteServiceTest.java
index 3a6780619cde046d123c5ea5ee26756e5284a62f..33482575e9791983f11ee46e94c2081a3bdd2af7 100644
--- a/server/src/test/java/de/ozgcloud/antragsraum/events/NachrichtEventRemoteServiceTest.java
+++ b/server/src/test/java/de/ozgcloud/antragsraum/events/NachrichtEventRemoteServiceTest.java
@@ -20,16 +20,12 @@
 
 package de.ozgcloud.antragsraum.events;
 
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.when;
+import static org.assertj.core.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.*;
 
-import de.ozgcloud.info.GrpcInformationRequest;
-import de.ozgcloud.info.GrpcInformationResponse;
-import de.ozgcloud.info.InformationServiceGrpc;
-import de.ozgcloud.info.nachricht.GrpcNachricht;
 import java.util.List;
-import java.util.UUID;
+
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
@@ -39,59 +35,102 @@ import org.mockito.Mock;
 import org.mockito.Spy;
 import org.mockito.junit.jupiter.MockitoExtension;
 
+import de.ozgcloud.info.GrpcInformationByIdRequest;
+import de.ozgcloud.info.GrpcInformationByIdResponse;
+import de.ozgcloud.info.GrpcInformationNachricht;
+import de.ozgcloud.info.GrpcInformationRequest;
+import de.ozgcloud.info.GrpcInformationResponse;
+import de.ozgcloud.info.InformationServiceGrpc;
+import io.grpc.Status;
+import io.grpc.StatusRuntimeException;
+
 @ExtendWith(MockitoExtension.class)
 class NachrichtEventRemoteServiceTest {
-
-    @Spy
-    @InjectMocks
-    private NachrichtEventRemoteService remoteService;
-    @Mock
-    private InformationServiceGrpc.InformationServiceBlockingStub informationServiceBlockingClient;
-
-    @Nested
-    class TestInformationAvailable {
-
-        private final String postfachId = UUID.randomUUID().toString();
-        private final List<GrpcNachricht> nachrichten =
-            List.of(GrpcNachrichtTestFactory.createBuilder().setPostfachId(postfachId).build());
-
-        @BeforeEach
-        void init() {
-            when(informationServiceBlockingClient.getInformation(any(GrpcInformationRequest.class)))
-                .thenReturn(GrpcInformationResponse.newBuilder().addAllNachrichten(nachrichten).build());
-        }
-
-        @Test
-        void shouldLoadNachrichtEvents() {
-            var events = remoteService.getNachrichtEventsOfPostfach(postfachId);
-
-            assertThat(events).hasSize(1);
-        }
-
-        @Test
-        void shouldHavePostfachId() {
-            var events = remoteService.getNachrichtEventsOfPostfach(postfachId);
-
-            assertThat(events.get(0).postfachId()).isEqualTo(postfachId);
-        }
-    }
-
-    @Nested
-    class TestNoInformationAvailable {
-        private final String postfachId = UUID.randomUUID().toString();
-        private final List<GrpcNachricht> nachrichten = List.of();
-
-        @BeforeEach
-        void init() {
-            when(informationServiceBlockingClient.getInformation(any(GrpcInformationRequest.class)))
-                .thenReturn(GrpcInformationResponse.newBuilder().addAllNachrichten(nachrichten).build());
-        }
-
-        @Test
-        void shouldLoadEmptyNachrichtEvents() {
-            var events = remoteService.getNachrichtEventsOfPostfach(postfachId);
-
-            assertThat(events).hasSize(0);
-        }
-    }
+	@Spy
+	@InjectMocks
+	private NachrichtEventRemoteService remoteService;
+	@Mock
+	private InformationServiceGrpc.InformationServiceBlockingStub informationServiceBlockingClient;
+
+	@Nested
+	class TestInformationAvailable {
+		private final List<GrpcInformationNachricht> nachrichten = List.of(NachrichtEventTestFactory.createGrpcInformationNachricht());
+
+		@BeforeEach
+		void init() {
+			when(informationServiceBlockingClient.getInformation(any(GrpcInformationRequest.class)))
+			  .thenReturn(GrpcInformationResponse.newBuilder().addAllNachrichten(nachrichten).build());
+		}
+
+		@Test
+		void shouldLoadNachrichtEvents() {
+			var events = remoteService.getNachrichtEventsOfPostfach(NachrichtEventTestFactory.POSTFACH_ID);
+
+			assertThat(events).hasSize(1);
+		}
+
+		@Test
+		void shouldHavePostfachId() {
+			var events = remoteService.getNachrichtEventsOfPostfach(NachrichtEventTestFactory.POSTFACH_ID);
+
+			assertThat(events.getFirst().postfachId()).isEqualTo(NachrichtEventTestFactory.POSTFACH_ID);
+		}
+	}
+
+	@Nested
+	class TestNoInformationAvailable {
+		private final List<GrpcInformationNachricht> nachrichten = List.of();
+
+		@BeforeEach
+		void init() {
+			when(informationServiceBlockingClient.getInformation(any(GrpcInformationRequest.class)))
+			  .thenReturn(GrpcInformationResponse.newBuilder().addAllNachrichten(nachrichten).build());
+		}
+
+		@Test
+		void shouldLoadEmptyNachrichtEvents() {
+			var events = remoteService.getNachrichtEventsOfPostfach(NachrichtEventTestFactory.POSTFACH_ID);
+
+			assertThat(events).hasSize(0);
+		}
+	}
+
+	@Nested
+	class TestInformationByIdAvailable {
+		private final GrpcInformationNachricht nachricht = NachrichtEventTestFactory.createGrpcInformationNachricht();
+
+		@BeforeEach
+		void init() {
+			when(informationServiceBlockingClient.getInformationById(any(GrpcInformationByIdRequest.class)))
+			  .thenReturn(GrpcInformationByIdResponse.newBuilder().setNachricht(nachricht).build());
+		}
+
+		@Test
+		void shouldLoadNachrichtEventById() {
+			var event = remoteService.getNachrichtEventById(NachrichtEventTestFactory.ID);
+
+			assertThat(event).isInstanceOf(NachrichtEvent.class);
+		}
+
+		@Test
+		void shouldHavePostfachId() {
+			var event = remoteService.getNachrichtEventById(NachrichtEventTestFactory.ID);
+
+			assertThat(event.postfachId()).isEqualTo(NachrichtEventTestFactory.POSTFACH_ID);
+		}
+	}
+
+	@Nested
+	class TestNoInformationByIdAvailable {
+		@BeforeEach
+		void init() {
+			when(informationServiceBlockingClient.getInformationById(any(GrpcInformationByIdRequest.class)))
+			  .thenThrow(new StatusRuntimeException(Status.INVALID_ARGUMENT));
+		}
+
+		@Test
+		void shouldLoadEmptyNachrichtEvents() {
+			assertThrows(StatusRuntimeException.class, () -> remoteService.getNachrichtEventById(InformationGrpcServiceStub.ID));
+		}
+	}
 }
\ No newline at end of file
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/events/NachrichtEventServiceTest.java b/server/src/test/java/de/ozgcloud/antragsraum/events/NachrichtEventServiceTest.java
index c0359770835455fd29f7ec55470df0836bba0fe6..adfef179f5b1ddc046ed08f9efc8b4bc50653c12 100644
--- a/server/src/test/java/de/ozgcloud/antragsraum/events/NachrichtEventServiceTest.java
+++ b/server/src/test/java/de/ozgcloud/antragsraum/events/NachrichtEventServiceTest.java
@@ -21,7 +21,8 @@
  */
 package de.ozgcloud.antragsraum.events;
 
-import de.ozgcloud.antragsraum.nachricht.NachrichtTestFactory;
+import static org.mockito.Mockito.*;
+
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.InjectMocks;
@@ -29,7 +30,7 @@ import org.mockito.Mock;
 import org.mockito.Spy;
 import org.mockito.junit.jupiter.MockitoExtension;
 
-import static org.mockito.Mockito.*;
+import de.ozgcloud.antragsraum.nachricht.NachrichtTestFactory;
 
 @ExtendWith(MockitoExtension.class)
 class NachrichtEventServiceTest {
@@ -45,4 +46,11 @@ class NachrichtEventServiceTest {
 
 		verify(remoteService).getNachrichtEventsOfPostfach(anyString());
 	}
+
+	@Test
+	void shouldCallRemoteServiceForEventById() {
+		service.getNachrichtEventById(NachrichtTestFactory.ID);
+
+		verify(remoteService).getNachrichtEventById(anyString());
+	}
 }
\ No newline at end of file
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/events/NachrichtEventTestFactory.java b/server/src/test/java/de/ozgcloud/antragsraum/events/NachrichtEventTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..c8278825d9768cd1ed373a9d5123a4405ea55da5
--- /dev/null
+++ b/server/src/test/java/de/ozgcloud/antragsraum/events/NachrichtEventTestFactory.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2023-2024.   Das Land Schleswig-Holstein vertreten durch den Ministerpräsidenten
+ * des Landes Schleswig-Holstein Staatskanzlei Abteilung Digitalisierung und zentrales IT-Management der Landesregierung.
+ *
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+package de.ozgcloud.antragsraum.events;
+
+import java.util.UUID;
+
+import de.ozgcloud.info.GrpcInformationNachricht;
+
+public class NachrichtEventTestFactory {
+	public static final String ID = UUID.randomUUID().toString();
+	public static final String POSTFACH_ID = UUID.randomUUID().toString();
+	public static final String URL = "http://localhost";
+
+	public static NachrichtEvent createNachrichtEvent() {
+		return createNachrichtEventBuilder().build();
+	}
+
+	public static NachrichtEvent.NachrichtEventBuilder createNachrichtEventBuilder() {
+		return NachrichtEvent.builder()
+		  .id(ID)
+		  .postfachId(POSTFACH_ID)
+		  .address(URL);
+	}
+
+	static GrpcInformationNachricht createGrpcInformationNachricht() {
+		return createGrpcInformationNachrichtBuilder().build();
+	}
+
+	static GrpcInformationNachricht.Builder createGrpcInformationNachrichtBuilder() {
+		return GrpcInformationNachricht.newBuilder()
+		  .setId(ID)
+		  .setPostfachId(POSTFACH_ID)
+		  .setOzgCloudAddress(URL);
+	}
+}
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/nachricht/AntragsraumServiceGrpc.java b/server/src/test/java/de/ozgcloud/antragsraum/nachricht/AntragsraumServiceGrpc.java
index 1116d7f96fefe0a327674b227a690b308667e224..cb04aef1018aae6850de93dbd1f9c81c74a9c1e0 100644
--- a/server/src/test/java/de/ozgcloud/antragsraum/nachricht/AntragsraumServiceGrpc.java
+++ b/server/src/test/java/de/ozgcloud/antragsraum/nachricht/AntragsraumServiceGrpc.java
@@ -23,6 +23,8 @@ package de.ozgcloud.antragsraum.nachricht;
 import de.ozgcloud.nachrichten.antragraum.AntragraumServiceGrpc;
 import de.ozgcloud.nachrichten.antragraum.GrpcFindRueckfragenRequest;
 import de.ozgcloud.nachrichten.antragraum.GrpcFindRueckfragenResponse;
+import de.ozgcloud.nachrichten.antragraum.GrpcGetRueckfrageRequest;
+import de.ozgcloud.nachrichten.antragraum.GrpcGetRueckfrageResponse;
 import de.ozgcloud.nachrichten.antragraum.GrpcSendRueckfrageAnswerRequest;
 import de.ozgcloud.nachrichten.antragraum.GrpcSendRueckfrageAnswerResponse;
 import io.grpc.stub.StreamObserver;
@@ -31,16 +33,21 @@ import net.devh.boot.grpc.server.service.GrpcService;
 @GrpcService
 public class AntragsraumServiceGrpc extends AntragraumServiceGrpc.AntragraumServiceImplBase {
 	@Override
-	public void findRueckfragen(GrpcFindRueckfragenRequest request,
-	  StreamObserver<GrpcFindRueckfragenResponse> responseObserver) {
-		responseObserver.onNext(GrpcRueckfragenTestFactory.createFindRueckfragenResponse());
+	public void findRueckfragen(GrpcFindRueckfragenRequest request, StreamObserver<GrpcFindRueckfragenResponse> responseObserver) {
+		responseObserver.onNext(GrpcRueckfrageTestFactory.createFindRueckfragenResponse());
+		responseObserver.onCompleted();
+	}
+
+	@Override
+	public void getRueckfrage(final GrpcGetRueckfrageRequest request, final StreamObserver<GrpcGetRueckfrageResponse> responseObserver) {
+		responseObserver.onNext(GrpcRueckfrageTestFactory.createGetRueckfrageResponse());
 		responseObserver.onCompleted();
 	}
 
 	@Override
 	public void sendRueckfrageAnswer(GrpcSendRueckfrageAnswerRequest request,
 	  StreamObserver<GrpcSendRueckfrageAnswerResponse> responseObserver) {
-		responseObserver.onNext(GrpcRueckfragenTestFactory.createSendRueckfrageAnswerResponse());
+		responseObserver.onNext(GrpcRueckfrageTestFactory.createSendRueckfrageAnswerResponse());
 		responseObserver.onCompleted();
 	}
 }
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/nachricht/GrpcPostfachMailTestFactory.java b/server/src/test/java/de/ozgcloud/antragsraum/nachricht/GrpcPostfachMailTestFactory.java
deleted file mode 100644
index e5aafce38bcee6f1564127a280b9ef916637f25b..0000000000000000000000000000000000000000
--- a/server/src/test/java/de/ozgcloud/antragsraum/nachricht/GrpcPostfachMailTestFactory.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (c) 2023-2024.
- * Das Land Schleswig-Holstein vertreten durch den Ministerpräsidenten des Landes Schleswig-Holstein Staatskanzlei Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
- *
- * Lizenziert unter der EUPL, Version 1.2 oder - sobald
- * diese von der Europäischen Kommission genehmigt wurden -
- * Folgeversionen der EUPL ("Lizenz");
- * Sie dürfen dieses Werk ausschließlich gemäß
- * dieser Lizenz nutzen.
- * Eine Kopie der Lizenz finden Sie hier:
- *
- * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
- *
- * Sofern nicht durch anwendbare Rechtsvorschriften
- * gefordert oder in schriftlicher Form vereinbart, wird
- * die unter der Lizenz verbreitete Software "so wie sie
- * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
- * ausdrücklich oder stillschweigend - verbreitet.
- * Die sprachspezifischen Genehmigungen und Beschränkungen
- * unter der Lizenz sind dem Lizenztext zu entnehmen.
- */
-package de.ozgcloud.antragsraum.nachricht;
-
-import java.util.UUID;
-
-import de.ozgcloud.nachrichten.postfach.GrpcDirection;
-import de.ozgcloud.nachrichten.postfach.GrpcPostfachAddress;
-import de.ozgcloud.nachrichten.postfach.GrpcPostfachMail;
-import de.ozgcloud.vorgang.common.GrpcObject;
-import de.ozgcloud.vorgang.common.GrpcProperty;
-
-public class GrpcPostfachMailTestFactory {
-	static final String NACHRICHT_ID = UUID.randomUUID().toString();
-	static final String VORGANG_ID = NachrichtTestFactory.VORGANG_ID;
-
-	static final String POSTFACH_ID_FIELD = "postfachId";
-
-	static GrpcPostfachMail create() {
-		return createBuilder().build();
-	}
-
-	static GrpcPostfachMail.Builder createBuilder() {
-		return GrpcPostfachMail.newBuilder()
-		  .setId(NACHRICHT_ID)
-		  .setVorgangId(VORGANG_ID)
-		  .setPostfachAddress(createPostfachAddress())
-		  .setMailBody(NachrichtTestFactory.TEXT)
-		  .setSubject(NachrichtTestFactory.VORGANG_TITLE)
-		  .setDirection(GrpcDirection.OUT)
-		  .setSentAt(NachrichtTestFactory.DATE_STRING)
-		  .setCreatedAt(NachrichtTestFactory.DATE_STRING)
-		  .setReplyOption(NachrichtTestFactory.REPLY_FORBIDDEN.name())
-		  .addAttachment(NachrichtTestFactory.ATTACHMENT_ID_1)
-		  .addAttachment(NachrichtTestFactory.ATTACHMENT_ID_2);
-	}
-
-	private static GrpcPostfachAddress createPostfachAddress() {
-		return GrpcPostfachAddress.newBuilder()
-		  .setIdentifier(GrpcObject.newBuilder()
-			.addProperty(
-			  GrpcProperty.newBuilder()
-				.setName(POSTFACH_ID_FIELD)
-				.addValue(NachrichtTestFactory.POSTFACH_ID).build()
-			).build()
-		  ).build();
-	}
-}
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/nachricht/GrpcRueckfragenTestFactory.java b/server/src/test/java/de/ozgcloud/antragsraum/nachricht/GrpcRueckfrageTestFactory.java
similarity index 63%
rename from server/src/test/java/de/ozgcloud/antragsraum/nachricht/GrpcRueckfragenTestFactory.java
rename to server/src/test/java/de/ozgcloud/antragsraum/nachricht/GrpcRueckfrageTestFactory.java
index 6307efa21587ae39fb6bbf4389988d70138ef9df..f0aeebdb9db52a67c682cbbd289c876e8ae4d0e2 100644
--- a/server/src/test/java/de/ozgcloud/antragsraum/nachricht/GrpcRueckfragenTestFactory.java
+++ b/server/src/test/java/de/ozgcloud/antragsraum/nachricht/GrpcRueckfrageTestFactory.java
@@ -27,17 +27,19 @@ import java.time.ZoneOffset;
 import java.util.List;
 import java.util.UUID;
 
+import de.ozgcloud.antragsraum.command.CommandTestFactory;
 import de.ozgcloud.nachrichten.antragraum.GrpcFindRueckfragenResponse;
+import de.ozgcloud.nachrichten.antragraum.GrpcGetRueckfrageResponse;
 import de.ozgcloud.nachrichten.antragraum.GrpcRueckfrage;
 import de.ozgcloud.nachrichten.antragraum.GrpcRueckfrageAnswer;
+import de.ozgcloud.nachrichten.antragraum.GrpcRueckfrageHead;
 import de.ozgcloud.nachrichten.antragraum.GrpcSendRueckfrageAnswerResponse;
 
-public class GrpcRueckfragenTestFactory {
-	static final String RUECKFRAGE_ID = UUID.randomUUID().toString();
-	static final String VORGANG_ID = UUID.randomUUID().toString();
-	static final String VORGANG_NAME = NachrichtTestFactory.VORGANG_TITLE;
-	static final String ANSWER_FILE_ID = UUID.randomUUID().toString();
-
+public class GrpcRueckfrageTestFactory {
+	public static final String RUECKFRAGE_ID = UUID.randomUUID().toString();
+	public static final String VORGANG_ID = UUID.randomUUID().toString();
+	public static final String VORGANG_NAME = NachrichtTestFactory.VORGANG_TITLE;
+	public static final String ANSWER_FILE_ID = UUID.randomUUID().toString();
 	public static final String TEXT = """
 	  Lorem ipsum dolor sit amet, consetetur sadipscing elitr,
 	   sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat,
@@ -46,40 +48,34 @@ public class GrpcRueckfragenTestFactory {
 	   Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
 	   Lorem ipsum dolor sit amet, consetetur sadipscing elitr.
 	  """;
-
 	public static final String ANSWER_TEXT = """
 	  ANTWORT Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
 	   Lorem ipsum dolor sit amet, consetetur sadipscing elitr.
 	  """;
-
 	public static final String SEND_AT = "2022-10-26T09:26:25";
-
-	public static final long SEND_AT_DATE = LocalDateTime.parse(SEND_AT).toEpochSecond(ZoneOffset.UTC);
-
+	public static final String SEND_AT_LONG = "2022-10-26T09:26:25.242804292Z[UTC]";
+	public static final long SEND_AT_DATE = LocalDateTime.parse(SEND_AT).toEpochSecond(ZoneOffset.UTC) * 1000;
 	public static final String ANSWERED_AT = "2022-10-27T12:00:00";
+	public static final long ANSWERED_AT_DATE = LocalDateTime.parse(ANSWERED_AT).toEpochSecond(ZoneOffset.UTC) * 1000;
+	public static final boolean ACCESSIBLE = true;
+	public static final String TRUST_LEVEL = "LOW";
+	public static final String STATUS = "ANSWERED";
 
-	public static final long ANSWERED_AT_DATE = LocalDateTime.parse(ANSWERED_AT).toEpochSecond(ZoneOffset.UTC);
-
-	static GrpcFindRueckfragenResponse createFindRueckfragenResponse() {
-		return GrpcFindRueckfragenResponse.newBuilder().addRueckfrage(
-			createRueckfrageBuilder()
-			  .build())
-		  .build();
-	}
-
-	static GrpcSendRueckfrageAnswerResponse createSendRueckfrageAnswerResponse() {
-		return GrpcSendRueckfrageAnswerResponse.newBuilder().setCommandId(GrpcCommandTestFactory.ID).build();
+	static GrpcGetRueckfrageResponse createGetRueckfrageResponse() {
+		return GrpcGetRueckfrageResponse.newBuilder().setRueckfrage(createRueckfrage()).build();
 	}
 
-	static GrpcRueckfrage create() {
+	static GrpcRueckfrage createRueckfrage() {
 		return createRueckfrageBuilder().build();
 	}
 
-	static GrpcRueckfrage createWithReply() {
+	static GrpcRueckfrage createRueckfrageWithReply() {
 		return createRueckfrageBuilder()
 		  .setAnsweredAt(ANSWERED_AT)
+		  .setSentAt(SEND_AT)
 		  .addAnswers(GrpcRueckfrageAnswer.newBuilder()
 			.setAnswerText(ANSWER_TEXT)
+			.setSentAt(SEND_AT)
 			.addAttachmentFileId(ANSWER_FILE_ID)
 			.build())
 		  .build();
@@ -92,7 +88,34 @@ public class GrpcRueckfragenTestFactory {
 		  .setVorgangName(VORGANG_NAME)
 		  .setText(TEXT)
 		  .setSentAt(SEND_AT)
+		  .setAccessible(ACCESSIBLE)
+		  .setTrustLevel(TRUST_LEVEL)
+		  .setStatus(STATUS)
 		  .addAllAttachmentFileId(
 			List.of(NachrichtTestFactory.ATTACHMENT_ID_1, NachrichtTestFactory.ATTACHMENT_ID_2));
 	}
+
+	static GrpcFindRueckfragenResponse createFindRueckfragenResponse() {
+		return GrpcFindRueckfragenResponse.newBuilder().addRueckfrageHead(createRueckfrageHead()).build();
+	}
+
+	static GrpcRueckfrageHead createRueckfrageHead() {
+		return createRueckfrageHeadBuilder().build();
+	}
+
+	static GrpcRueckfrageHead.Builder createRueckfrageHeadBuilder() {
+		return GrpcRueckfrageHead.newBuilder()
+		  .setId(RUECKFRAGE_ID)
+		  .setVorgangId(VORGANG_ID)
+		  .setVorgangName(VORGANG_NAME)
+		  .setSentAt(SEND_AT)
+		  .setAnsweredAt(ANSWERED_AT)
+		  .setAccessible(ACCESSIBLE)
+		  .setTrustLevel(TRUST_LEVEL)
+		  .setStatus(STATUS);
+	}
+
+	static GrpcSendRueckfrageAnswerResponse createSendRueckfrageAnswerResponse() {
+		return GrpcSendRueckfrageAnswerResponse.newBuilder().setCommandId(CommandTestFactory.ID).build();
+	}
 }
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/nachricht/NachrichtHeaderMapperTest.java b/server/src/test/java/de/ozgcloud/antragsraum/nachricht/NachrichtHeaderMapperTest.java
index 0d4aa86fb84f58183080bdb51c72f9182d97d1b6..e555cbecdff08325ee95610e69d4137ba3deda46 100644
--- a/server/src/test/java/de/ozgcloud/antragsraum/nachricht/NachrichtHeaderMapperTest.java
+++ b/server/src/test/java/de/ozgcloud/antragsraum/nachricht/NachrichtHeaderMapperTest.java
@@ -23,87 +23,81 @@ package de.ozgcloud.antragsraum.nachricht;
 
 import static org.assertj.core.api.Assertions.*;
 
-import java.util.Collections;
-import java.util.List;
-
-import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
 
+import de.ozgcloud.nachrichten.antragraum.GrpcRueckfrageHead;
+
 class NachrichtHeaderMapperTest {
-	@Nested
-	class TestFromNachricht {
-		private final Nachricht nachricht = NachrichtTestFactory.createNachricht();
+	private final GrpcRueckfrageHead rueckfrageHead = GrpcRueckfrageTestFactory.createRueckfrageHead();
 
-		@Test
-		void shouldMapNachrichtId() {
-			var nachrichtHeader = NachrichtHeaderMapper.fromNachricht(nachricht);
+	@Test
+	void shouldMapId() {
+		var nachrichtHeader = NachrichtHeaderMapper.fromGrpcRueckfrageHead(rueckfrageHead, NachrichtTestFactory.NACHRICHT_EVENT_ID);
 
-			assertThat(nachrichtHeader.id()).isEqualTo(NachrichtTestFactory.ID);
-		}
+		assertThat(nachrichtHeader.id()).isEqualTo(GrpcRueckfrageTestFactory.RUECKFRAGE_ID);
+	}
 
-		@Test
-		void shouldMapAddress() {
-			var nachrichtHeader = NachrichtHeaderMapper.fromNachricht(nachricht);
+	@Test
+	void shouldMapNachrichtEventId() {
+		var nachrichtHeader = NachrichtHeaderMapper.fromGrpcRueckfrageHead(rueckfrageHead, NachrichtTestFactory.NACHRICHT_EVENT_ID);
 
-			assertThat(nachrichtHeader.address()).isEqualTo(NachrichtTestFactory.ADDRESS);
-		}
+		assertThat(nachrichtHeader.nachrichtEventId()).isEqualTo(NachrichtTestFactory.NACHRICHT_EVENT_ID);
+	}
 
-		@Test
-		void shouldMapVorgangId() {
-			var nachrichtHeader = NachrichtHeaderMapper.fromNachricht(nachricht);
+	@Test
+	void shouldMapVorgangId() {
+		var nachrichtHeader = NachrichtHeaderMapper.fromGrpcRueckfrageHead(rueckfrageHead, NachrichtTestFactory.NACHRICHT_EVENT_ID);
 
-			assertThat(nachrichtHeader.vorgangId()).isEqualTo(NachrichtTestFactory.VORGANG_ID);
-		}
+		assertThat(nachrichtHeader.vorgangId()).isEqualTo(GrpcRueckfrageTestFactory.VORGANG_ID);
+	}
 
-		@Test
-		void shouldMapVorgangName() {
-			var nachrichtHeader = NachrichtHeaderMapper.fromNachricht(nachricht);
+	@Test
+	void shouldMapVorgangName() {
+		var nachrichtHeader = NachrichtHeaderMapper.fromGrpcRueckfrageHead(rueckfrageHead, NachrichtTestFactory.NACHRICHT_EVENT_ID);
 
-			assertThat(nachrichtHeader.topicTitle()).isEqualTo(NachrichtTestFactory.VORGANG_TITLE);
-		}
+		assertThat(nachrichtHeader.title()).isEqualTo(GrpcRueckfrageTestFactory.VORGANG_NAME);
+	}
 
-		@Test
-		void shouldMapCreationDate() {
-			var nachrichtHeader = NachrichtHeaderMapper.fromNachricht(nachricht);
+	@Test
+	void shouldMapAnsweredAtDate() {
+		var nachrichtHeader = NachrichtHeaderMapper.fromGrpcRueckfrageHead(rueckfrageHead, NachrichtTestFactory.NACHRICHT_EVENT_ID);
 
-			assertThat(nachrichtHeader.date()).isEqualTo(NachrichtTestFactory.DATE);
-		}
+		assertThat(nachrichtHeader.answeredAt()).isEqualTo(GrpcRueckfrageTestFactory.ANSWERED_AT_DATE);
+	}
 
-		@Test
-		void shouldMapLastAnsweredDate() {
-			var nachrichtHeader = NachrichtHeaderMapper.fromNachricht(nachricht);
+	@Test
+	void shouldMapEmptyAnsweredAtDate() {
+		var nachrichtHeader = NachrichtHeaderMapper.fromGrpcRueckfrageHead(
+		  GrpcRueckfrageTestFactory.createRueckfrageHeadBuilder().setAnsweredAt("").build(), NachrichtTestFactory.NACHRICHT_EVENT_ID);
 
-			assertThat(nachrichtHeader.lastAnsweredDate()).isEqualTo(NachrichtTestFactory.DATE);
-		}
+		assertThat(nachrichtHeader.answeredAt()).isEqualTo(0);
+	}
 
-		@Test
-		void shouldMapTrustLevel() {
-			var nachrichtHeader = NachrichtHeaderMapper.fromNachricht(nachricht);
+	@Test
+	void shouldMapSendAtDate() {
+		var nachrichtHeader = NachrichtHeaderMapper.fromGrpcRueckfrageHead(rueckfrageHead, NachrichtTestFactory.NACHRICHT_EVENT_ID);
 
-			assertThat(nachrichtHeader.trustLevel()).isEqualTo(NachrichtTrustLevel.LOW);
-		}
+		assertThat(nachrichtHeader.sendAt()).isEqualTo(GrpcRueckfrageTestFactory.SEND_AT_DATE);
 	}
 
-	@Nested
-	class TestGetLatestReplyDate {
-		@Test
-		void shouldHaveNoDate() {
-			var nachricht = Nachricht.builder().replyNachrichten(Collections.emptyList()).build();
-			var result = NachrichtHeaderMapper.getLatestReplyDate(nachricht);
-
-			assertThat(result).isNull();
-		}
-
-		@Test
-		void shouldReturnLatestDate() {
-			var replyNachrichten = List.of(
-			  ReplyNachricht.builder().date(NachrichtTestFactory.DATE).build(),
-			  ReplyNachricht.builder().date(NachrichtTestFactory.DATE - 1000).build()
-			);
-			var nachricht = Nachricht.builder().replyNachrichten(replyNachrichten).build();
-			var result = NachrichtHeaderMapper.getLatestReplyDate(nachricht);
-
-			assertThat(result).isEqualTo(NachrichtTestFactory.DATE);
-		}
+	@Test
+	void shouldMapAccessible() {
+		var nachrichtHeader = NachrichtHeaderMapper.fromGrpcRueckfrageHead(rueckfrageHead, NachrichtTestFactory.NACHRICHT_EVENT_ID);
+
+		assertThat(nachrichtHeader.accessible()).isEqualTo(GrpcRueckfrageTestFactory.ACCESSIBLE);
+	}
+
+	@Test
+	void shouldMapTrustLevel() {
+		var nachrichtHeader = NachrichtHeaderMapper.fromGrpcRueckfrageHead(rueckfrageHead, NachrichtTestFactory.NACHRICHT_EVENT_ID);
+
+		assertThat(nachrichtHeader.trustLevel()).isEqualTo(GrpcRueckfrageTestFactory.TRUST_LEVEL);
+	}
+
+	@Test
+	void shouldMapStatus() {
+		var nachrichtHeader = NachrichtHeaderMapper.fromGrpcRueckfrageHead(rueckfrageHead, NachrichtTestFactory.NACHRICHT_EVENT_ID);
+
+		assertThat(nachrichtHeader.status()).isEqualTo(GrpcRueckfrageTestFactory.STATUS);
 	}
 }
\ No newline at end of file
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/nachricht/NachrichtMapperTest.java b/server/src/test/java/de/ozgcloud/antragsraum/nachricht/NachrichtMapperTest.java
index 6dd00b933dec2c1890134eadf2537b45ad351d27..e11a3ec265dc2fcfb3a8d01e7d95552ac624f654 100644
--- a/server/src/test/java/de/ozgcloud/antragsraum/nachricht/NachrichtMapperTest.java
+++ b/server/src/test/java/de/ozgcloud/antragsraum/nachricht/NachrichtMapperTest.java
@@ -21,6 +21,7 @@
  */
 package de.ozgcloud.antragsraum.nachricht;
 
+import static de.ozgcloud.antragsraum.nachricht.GrpcRueckfrageTestFactory.*;
 import static org.assertj.core.api.Assertions.*;
 import static org.mockito.Mockito.*;
 
@@ -35,130 +36,213 @@ import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.junit.jupiter.MockitoExtension;
 
-import de.ozgcloud.antragsraum.attachments.FileRemoteService;
+import de.ozgcloud.antragsraum.attachments.FileService;
 import de.ozgcloud.antragsraum.attachments.OzgFile;
 import de.ozgcloud.antragsraum.attachments.OzgFileTestFactory;
 import de.ozgcloud.nachrichten.antragraum.GrpcRueckfrage;
+import de.ozgcloud.nachrichten.antragraum.GrpcRueckfrageAnswer;
 
 @ExtendWith(MockitoExtension.class)
 class NachrichtMapperTest {
 	@Mock
-	private FileRemoteService fileRemoteService;
+	private FileService fileService;
 
 	@InjectMocks
 	private NachrichtMapper mapper;
 
 	@Nested
 	class TestFromGrpcRueckfrage {
-		private final GrpcRueckfrage rueckfrage = GrpcRueckfragenTestFactory.create();
-		private final GrpcRueckfrage answeredRueckfrage = GrpcRueckfragenTestFactory.createWithReply();
+		private final GrpcRueckfrage rueckfrage = GrpcRueckfrageTestFactory.createRueckfrage();
+		private final GrpcRueckfrage answeredRueckfrage = GrpcRueckfrageTestFactory.createRueckfrageWithReply();
 
 		@BeforeEach
 		void setup() {
-			when(fileRemoteService.getFile(anyString(), anyString())).thenReturn(OzgFileTestFactory.createOzgFile());
+			when(fileService.getFile(anyString(), anyString())).thenReturn(OzgFileTestFactory.create());
 		}
 
 		@Test
 		void shouldMapNachrichtId() {
-			var nachricht = mapper.fromGrpcRueckfrage(GrpcRueckfragenTestFactory.createRueckfrageBuilder().setId(NachrichtTestFactory.ID).build(),
-			  NachrichtTestFactory.ADDRESS);
+			var nachricht = mapper.fromGrpcRueckfrage(GrpcRueckfrageTestFactory.createRueckfrageBuilder().setId(NachrichtTestFactory.ID).build(),
+			  NachrichtTestFactory.NACHRICHT_EVENT_ID);
 
 			assertThat(nachricht.id()).isEqualTo(NachrichtTestFactory.ID);
 		}
 
 		@Test
-		void shouldMapAddress() {
-			var nachricht = mapper.fromGrpcRueckfrage(GrpcRueckfragenTestFactory.createRueckfrageBuilder().setId(NachrichtTestFactory.ID).build(),
-			  NachrichtTestFactory.ADDRESS);
+		void shouldMapNachrichtEventId() {
+			var nachricht = mapper.fromGrpcRueckfrage(GrpcRueckfrageTestFactory.createRueckfrageBuilder().setId(NachrichtTestFactory.ID).build(),
+			  NachrichtTestFactory.NACHRICHT_EVENT_ID);
 
-			assertThat(nachricht.address()).isEqualTo(NachrichtTestFactory.ADDRESS);
+			assertThat(nachricht.nachrichtEventId()).isEqualTo(NachrichtTestFactory.NACHRICHT_EVENT_ID);
 		}
 
 		@Test
 		void shouldMapVorgangId() {
-			var nachricht = mapper.fromGrpcRueckfrage(rueckfrage, NachrichtTestFactory.ADDRESS);
+			var nachricht = mapper.fromGrpcRueckfrage(rueckfrage, NachrichtTestFactory.NACHRICHT_EVENT_ID);
 
-			assertThat(nachricht.vorgangId()).isEqualTo(GrpcRueckfragenTestFactory.VORGANG_ID);
+			assertThat(nachricht.vorgangId()).isEqualTo(GrpcRueckfrageTestFactory.VORGANG_ID);
 		}
 
 		@Test
 		void shouldMapVorgangName() {
-			var nachricht = mapper.fromGrpcRueckfrage(rueckfrage, NachrichtTestFactory.ADDRESS);
+			var nachricht = mapper.fromGrpcRueckfrage(rueckfrage, NachrichtTestFactory.NACHRICHT_EVENT_ID);
 
-			assertThat(nachricht.topicTitle()).isEqualTo(NachrichtTestFactory.VORGANG_TITLE);
+			assertThat(nachricht.title()).isEqualTo(NachrichtTestFactory.VORGANG_TITLE);
 		}
 
 		@Test
 		void shouldMapNachrichtText() {
-			var nachricht = mapper.fromGrpcRueckfrage(rueckfrage, NachrichtTestFactory.ADDRESS);
+			var nachricht = mapper.fromGrpcRueckfrage(rueckfrage, NachrichtTestFactory.NACHRICHT_EVENT_ID);
 
-			assertThat(nachricht.message()).isEqualTo(GrpcRueckfragenTestFactory.TEXT);
+			assertThat(nachricht.message()).isEqualTo(GrpcRueckfrageTestFactory.TEXT);
 		}
 
 		@Test
-		void shouldMapCreationDate() {
-			var nachricht = mapper.fromGrpcRueckfrage(rueckfrage, NachrichtTestFactory.ADDRESS);
+		void shouldMapAnsweredAt() {
+			var nachricht = mapper.fromGrpcRueckfrage(answeredRueckfrage, NachrichtTestFactory.NACHRICHT_EVENT_ID);
 
-			assertThat(nachricht.date()).isEqualTo(GrpcRueckfragenTestFactory.SEND_AT_DATE);
+			assertThat(nachricht.answeredAt()).isEqualTo(GrpcRueckfrageTestFactory.ANSWERED_AT_DATE);
 		}
 
 		@Test
-		void shouldMapInvalidCreationDate() {
-			var nachricht = mapper.fromGrpcRueckfrage(GrpcRueckfragenTestFactory.createRueckfrageBuilder().setSentAt("huu").build(),
-			  NachrichtTestFactory.ADDRESS);
+		void shouldMapSendAt() {
+			var nachricht = mapper.fromGrpcRueckfrage(rueckfrage, NachrichtTestFactory.NACHRICHT_EVENT_ID);
 
-			assertThat(nachricht.date()).isZero();
+			assertThat(nachricht.sendAt()).isEqualTo(GrpcRueckfrageTestFactory.SEND_AT_DATE);
+		}
+
+		@Test
+		void shouldMapInvalidAnsweredAt() {
+			var nachricht = mapper.fromGrpcRueckfrage(GrpcRueckfrageTestFactory.createRueckfrageBuilder().setAnsweredAt("huu").build(),
+			  NachrichtTestFactory.NACHRICHT_EVENT_ID);
+
+			assertThat(nachricht.answeredAt()).isZero();
 		}
 
 		@Test
 		void shouldMapAttachments() {
-			var nachricht = mapper.fromGrpcRueckfrage(GrpcRueckfragenTestFactory.create(), NachrichtTestFactory.ADDRESS);
+			var nachricht = mapper.fromGrpcRueckfrage(GrpcRueckfrageTestFactory.createRueckfrage(), NachrichtTestFactory.NACHRICHT_EVENT_ID);
 
 			assertThat(nachricht.attachments()).hasSize(2);
 		}
 
 		@Test
 		void shouldMapEmptyAttachments() {
-			when(fileRemoteService.getFile(anyString(), anyString())).thenReturn(null);
+			when(fileService.getFile(anyString(), anyString())).thenReturn(null);
 
-			var nachricht = mapper.fromGrpcRueckfrage(GrpcRueckfragenTestFactory.create(), NachrichtTestFactory.ADDRESS);
+			var nachricht = mapper.fromGrpcRueckfrage(GrpcRueckfrageTestFactory.createRueckfrage(), NachrichtTestFactory.NACHRICHT_EVENT_ID);
 
 			assertThat(nachricht.attachments()).isEmpty();
 		}
 
+		@Test
+		void shouldMapAccessible() {
+			var nachricht = mapper.fromGrpcRueckfrage(answeredRueckfrage, NachrichtTestFactory.NACHRICHT_EVENT_ID);
+
+			assertThat(nachricht.accessible()).isEqualTo(NachrichtTestFactory.ACCESSIBLE);
+		}
+
 		@Test
 		void shouldMapTrustLevel() {
-			var nachricht = mapper.fromGrpcRueckfrage(answeredRueckfrage, NachrichtTestFactory.ADDRESS);
+			var nachricht = mapper.fromGrpcRueckfrage(answeredRueckfrage, NachrichtTestFactory.NACHRICHT_EVENT_ID);
 
-			assertThat(nachricht.trustLevel()).isEqualTo(NachrichtTrustLevel.LOW);
+			assertThat(nachricht.trustLevel()).isEqualTo(NachrichtTestFactory.TRUST_LEVEL);
 		}
 
 		@Test
 		void shouldNotHaveAnswersWhenUnanswered() {
-			var nachricht = mapper.fromGrpcRueckfrage(GrpcRueckfragenTestFactory.create(), NachrichtTestFactory.ADDRESS);
+			var nachricht = mapper.fromGrpcRueckfrage(GrpcRueckfrageTestFactory.createRueckfrage(), NachrichtTestFactory.NACHRICHT_EVENT_ID);
 
 			assertThat(nachricht.replyNachrichten()).isEmpty();
 		}
 
 		@Test
 		void shouldMapAnswerNachrichtText() {
-			var nachricht = mapper.fromGrpcRueckfrage(answeredRueckfrage, NachrichtTestFactory.ADDRESS);
+			var nachricht = mapper.fromGrpcRueckfrage(answeredRueckfrage, NachrichtTestFactory.NACHRICHT_EVENT_ID);
+
+			assertThat(nachricht.replyNachrichten().getFirst().message()).isEqualTo(GrpcRueckfrageTestFactory.ANSWER_TEXT);
+		}
 
-			assertThat(nachricht.replyNachrichten().getFirst().message()).isEqualTo(GrpcRueckfragenTestFactory.ANSWER_TEXT);
+		@Test
+		void shouldMapAnswerAttachments() {
+			var nachricht = mapper.fromGrpcRueckfrage(answeredRueckfrage, NachrichtTestFactory.NACHRICHT_EVENT_ID);
+
+			assertThat(nachricht.replyNachrichten().getFirst().attachments()).hasSize(1);
 		}
 
 		@Test
-		void shouldMapAnsweredDate() {
-			var nachricht = mapper.fromGrpcRueckfrage(answeredRueckfrage, NachrichtTestFactory.ADDRESS);
+		void shouldMapStatus() {
+			var nachricht = mapper.fromGrpcRueckfrage(rueckfrage, NachrichtTestFactory.NACHRICHT_EVENT_ID);
 
-			assertThat(nachricht.replyNachrichten().getFirst().date()).isEqualTo(GrpcRueckfragenTestFactory.ANSWERED_AT_DATE);
+			assertThat(nachricht.status()).isEqualTo(NachrichtTestFactory.STATUS);
 		}
+	}
 
+	@Nested
+	class TestGetAnsweredAt {
 		@Test
-		void shouldMapAnswerAttachments() {
-			var nachricht = mapper.fromGrpcRueckfrage(answeredRueckfrage, NachrichtTestFactory.ADDRESS);
+		void shouldGetAnsweredAtWhenAnsweredAtIsSet() {
+			GrpcRueckfrage answeredRueckfrage = GrpcRueckfrageTestFactory.createRueckfrageWithReply();
 
-			assertThat(nachricht.replyNachrichten().getFirst().attachments()).hasSize(1);
+			var date = mapper.getAnsweredAt(answeredRueckfrage);
+
+			assertThat(date).isEqualTo(mapper.toMillisecondsTimestamp(answeredRueckfrage.getAnsweredAt()));
+		}
+
+		@Test
+		void shouldGetAnsweredAtWhenAnsweredAtIsNotSetButAnswersHaveSendDat() {
+			GrpcRueckfrage answeredRueckfrage = GrpcRueckfrageTestFactory.createRueckfrageBuilder()
+			  .setAnsweredAt("")
+			  .clearAnswers()
+			  .addAnswers(GrpcRueckfrageAnswer.newBuilder().setSentAt(SEND_AT).build())
+			  .addAnswers(GrpcRueckfrageAnswer.newBuilder().setSentAt(ANSWERED_AT).build())
+			  .build();
+
+			var date = mapper.getAnsweredAt(answeredRueckfrage);
+
+			assertThat(date).isEqualTo(mapper.toMillisecondsTimestamp(ANSWERED_AT));
+		}
+
+		@Test
+		void shouldGetAnsweredAtWhenAnsweredAtIsNotSetAtAll() {
+			GrpcRueckfrage answeredRueckfrage = GrpcRueckfrageTestFactory.createRueckfrageBuilder()
+			  .setAnsweredAt("")
+			  .clearAnswers()
+			  .addAnswers(GrpcRueckfrageAnswer.newBuilder().build())
+			  .addAnswers(GrpcRueckfrageAnswer.newBuilder().build())
+			  .build();
+
+			var date = mapper.getAnsweredAt(answeredRueckfrage);
+
+			assertThat(date).isEqualTo(0);
+		}
+
+		@Test
+		void shouldGetAnsweredWhenSecondSendAtIsNull() {
+			GrpcRueckfrage answeredRueckfrage = GrpcRueckfrageTestFactory.createRueckfrageBuilder()
+			  .setAnsweredAt("")
+			  .clearAnswers()
+			  .addAnswers(GrpcRueckfrageAnswer.newBuilder().setSentAt(SEND_AT_LONG).build())
+			  .addAnswers(GrpcRueckfrageAnswer.newBuilder().build())
+			  .build();
+
+			var date = mapper.getAnsweredAt(answeredRueckfrage);
+
+			assertThat(date).isEqualTo(mapper.toMillisecondsTimestamp(SEND_AT));
+		}
+
+		@Test
+		void shouldGetAnsweredWhenFirstSendAtIsNull() {
+			GrpcRueckfrage answeredRueckfrage = GrpcRueckfrageTestFactory.createRueckfrageBuilder()
+			  .setAnsweredAt("")
+			  .clearAnswers()
+			  .addAnswers(GrpcRueckfrageAnswer.newBuilder().build())
+			  .addAnswers(GrpcRueckfrageAnswer.newBuilder().setSentAt(SEND_AT).build())
+			  .build();
+
+			var date = mapper.getAnsweredAt(answeredRueckfrage);
+
+			assertThat(date).isEqualTo(mapper.toMillisecondsTimestamp(SEND_AT));
 		}
 	}
 
@@ -190,8 +274,8 @@ class NachrichtMapperTest {
 		@Test
 		void shouldNotMapEmptyAttachments() {
 			var nachricht = mapper.fromGrpcRueckfrage(
-			  GrpcRueckfragenTestFactory.createRueckfrageBuilder().clearAttachmentFileId().addAttachmentFileId("").build(),
-			  NachrichtTestFactory.ADDRESS);
+			  GrpcRueckfrageTestFactory.createRueckfrageBuilder().clearAttachmentFileId().addAttachmentFileId("").build(),
+			  NachrichtTestFactory.NACHRICHT_EVENT_ID);
 
 			assertThat(nachricht.attachments()).isEmpty();
 		}
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/nachricht/NachrichtTestFactory.java b/server/src/test/java/de/ozgcloud/antragsraum/nachricht/NachrichtTestFactory.java
index eeae99b8f93b5cbb51eb9223e0d7d11591d3f96a..a90b4c4b403ca74a37ef03cff5f5f75b7305fef4 100644
--- a/server/src/test/java/de/ozgcloud/antragsraum/nachricht/NachrichtTestFactory.java
+++ b/server/src/test/java/de/ozgcloud/antragsraum/nachricht/NachrichtTestFactory.java
@@ -23,12 +23,12 @@ package de.ozgcloud.antragsraum.nachricht;
 
 import java.time.LocalDateTime;
 import java.time.ZoneOffset;
-import java.util.Collections;
 import java.util.List;
 import java.util.UUID;
 
 public class NachrichtTestFactory {
 	public static final String ID = UUID.randomUUID().toString();
+	public static final String NACHRICHT_EVENT_ID = UUID.randomUUID().toString();
 	public static final String POSTFACH_ID = UUID.randomUUID().toString();
 	public static final String VORGANG_ID = UUID.randomUUID().toString();
 	public static final String TEXT = """
@@ -44,10 +44,11 @@ public class NachrichtTestFactory {
 	public static final String ATTACHMENT_ID_2 = "6358fd4146811d04010f44d0";
 	public static final String DATE_STRING = "2022-10-26T09:26:25";
 	public static final long DATE = LocalDateTime.parse(DATE_STRING).toEpochSecond(ZoneOffset.UTC);
-	public static final ReplyOption REPLY_FORBIDDEN = ReplyOption.FORBIDDEN;
 	public static final ReplyOption REPLY_ALLOWED = ReplyOption.ALLOWED;
 	public static final String REPLY_TO_NACHRICHT_ID = UUID.randomUUID().toString();
-	public static final String ADDRESS = "static://localhost:9090";
+	public static final boolean ACCESSIBLE = true;
+	public static final String TRUST_LEVEL = "LOW";
+	public static final String STATUS = "ANSWERED";
 
 	static Nachricht createNachricht() {
 		return createNachrichtBuilder().build();
@@ -56,15 +57,18 @@ public class NachrichtTestFactory {
 	static Nachricht.NachrichtBuilder createNachrichtBuilder() {
 		return Nachricht.builder()
 		  .id(ID)
-		  .address(ADDRESS)
+		  .nachrichtEventId(NACHRICHT_EVENT_ID)
 		  .message(TEXT)
-		  .topicTitle(VORGANG_TITLE)
+		  .title(VORGANG_TITLE)
 		  .vorgangId(VORGANG_ID)
 		  .postfachId(POSTFACH_ID)
 		  .replyOption(REPLY_ALLOWED)
-		  .replyNachrichten(List.of(ReplyNachricht.builder().address(ADDRESS).date(DATE).build()))
-		  .date(DATE)
-		  .trustLevel(NachrichtTrustLevel.LOW);
+		  .replyNachrichten(List.of(ReplyNachricht.builder().nachrichtEventId(NACHRICHT_EVENT_ID).build()))
+		  .status(STATUS)
+		  .answeredAt(DATE)
+		  .sendAt(DATE)
+		  .trustLevel(TRUST_LEVEL)
+		  .accessible(ACCESSIBLE);
 	}
 
 	static NachrichtHeader createNachrichtHeader() {
@@ -74,34 +78,15 @@ public class NachrichtTestFactory {
 	static NachrichtHeader.NachrichtHeaderBuilder createNachrichtHeaderBuilder() {
 		return NachrichtHeader.builder()
 		  .id(ID)
-		  .topicTitle(VORGANG_TITLE)
+		  .nachrichtEventId(NACHRICHT_EVENT_ID)
 		  .vorgangId(VORGANG_ID)
 		  .postfachId(POSTFACH_ID)
+		  .title(VORGANG_TITLE)
 		  .replyOption(REPLY_ALLOWED)
-		  .date(DATE)
-		  .trustLevel(NachrichtTrustLevel.LOW);
-	}
-
-	static Topic createTopic() {
-		return createTopicBuilder().build();
-	}
-
-	static Topic.TopicBuilder createTopicBuilder() {
-		return Topic.builder()
-		  .topicTitle(VORGANG_TITLE)
-		  .clerkMessage(createNachricht())
-		  .trustLevel(NachrichtTrustLevel.LOW)
-		  .userMessages(Collections.emptyList());
-	}
-
-	static TopicHeader createTopicHeader() {
-		return createTopicHeaderBuilder().build();
-	}
-
-	static TopicHeader.TopicHeaderBuilder createTopicHeaderBuilder() {
-		return TopicHeader.builder()
-		  .topicTitle(VORGANG_TITLE)
-		  .clerkMessage(createNachrichtHeader())
-		  .trustLevel(NachrichtTrustLevel.LOW);
+		  .answeredAt(DATE)
+		  .sendAt(DATE)
+		  .trustLevel(TRUST_LEVEL)
+		  .accessible(ACCESSIBLE)
+		  .status(STATUS);
 	}
 }
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/nachricht/NachrichtenControllerITCase.java b/server/src/test/java/de/ozgcloud/antragsraum/nachricht/NachrichtenControllerITCase.java
index 56f33e94243866e42fd88abfda1cf9884b8dec51..372dd4def2c81ec0d448211894fea4cdce485ba2 100644
--- a/server/src/test/java/de/ozgcloud/antragsraum/nachricht/NachrichtenControllerITCase.java
+++ b/server/src/test/java/de/ozgcloud/antragsraum/nachricht/NachrichtenControllerITCase.java
@@ -28,7 +28,6 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
 
 import java.nio.charset.Charset;
 import java.util.List;
-import java.util.concurrent.TimeoutException;
 
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Nested;
@@ -46,10 +45,11 @@ import org.springframework.test.web.servlet.ResultActions;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
 
-import de.ozgcloud.antragsraum.attachments.FileRemoteService;
+import de.ozgcloud.antragsraum.attachments.FileService;
 import de.ozgcloud.antragsraum.callcontext.ContextService;
+import de.ozgcloud.antragsraum.command.CommandReference;
+import de.ozgcloud.antragsraum.command.CommandReferenceTestFactory;
 import de.ozgcloud.antragsraum.common.AddressNotFoundException;
-import de.ozgcloud.antragsraum.common.SendTimeoutException;
 import de.ozgcloud.antragsraum.common.TechnicalException;
 
 @AutoConfigureMockMvc
@@ -69,19 +69,19 @@ public class NachrichtenControllerITCase {
 	private ContextService contextService;
 
 	@MockBean
-	private FileRemoteService fileRemoteService;
+	private FileService fileService;
 
 	@Nested
-	class TestLoadingTopicHeaders {
+	class TestLoadingRueckfrageHeaders {
 		@Test
 		@WithMockUser
 		void shouldLoadRueckfragenHeader() throws Exception {
-			when(nachrichtenService.getTopicHeadersOfPostfach(NachrichtTestFactory.POSTFACH_ID)).thenReturn(
-			  List.of(NachrichtTestFactory.createTopicHeader()));
+			when(nachrichtenService.getRueckfrageHeadersOfPostfach(NachrichtTestFactory.POSTFACH_ID)).thenReturn(
+			  List.of(RueckfrageTestFactory.createRueckfrageHeader()));
 
 			performRequest()
 			  .andExpect(status().isOk())
-			  .andExpect(jsonPath("$[0]['clerkMessage']['id']").value(NachrichtTestFactory.ID));
+			  .andExpect(jsonPath("$[0]['nachrichtHeader']['id']").value(NachrichtTestFactory.ID));
 		}
 
 		@Test
@@ -92,10 +92,10 @@ public class NachrichtenControllerITCase {
 		@Test
 		@WithMockUser
 		void shouldOnlyIncludeSelfLink() throws Exception {
-			var topicHeaderWithSelfLink = NachrichtTestFactory.createTopicHeader();
-			topicHeaderWithSelfLink.add(linkTo(NachrichtenController.class).withSelfRel());
+			var headerWithSelfLink = RueckfrageTestFactory.createRueckfrageHeader();
+			headerWithSelfLink.add(linkTo(NachrichtenController.class).withSelfRel());
 
-			when(nachrichtenService.getTopicHeadersOfPostfach(NachrichtTestFactory.POSTFACH_ID)).thenReturn(List.of(topicHeaderWithSelfLink));
+			when(nachrichtenService.getRueckfrageHeadersOfPostfach(NachrichtTestFactory.POSTFACH_ID)).thenReturn(List.of(headerWithSelfLink));
 
 			performRequest()
 			  .andExpect(status().isOk())
@@ -106,27 +106,29 @@ public class NachrichtenControllerITCase {
 
 		@Test
 		@WithMockUser
-		void shouldIncludeSelfAndTopicLink() throws Exception {
-			var fullyLinkedTopicHeader = NachrichtTestFactory.createTopicHeader();
-			fullyLinkedTopicHeader.add(linkTo(NachrichtenController.class).withSelfRel());
-			fullyLinkedTopicHeader.add(linkTo(methodOn(NachrichtenController.class).getTopicOfPostfach(NachrichtTestFactory.POSTFACH_ID,
-			  fullyLinkedTopicHeader.getClerkMessage().id())).withRel(TOPIC_LINK_RELATIONSHIP_NAME));
+		void shouldIncludeSelfAndRueckfrageLink() throws Exception {
+			var fullyLinkedRueckfrageHeader = RueckfrageTestFactory.createRueckfrageHeader();
+			fullyLinkedRueckfrageHeader.add(linkTo(NachrichtenController.class).withSelfRel());
+			fullyLinkedRueckfrageHeader.add(linkTo(
+			  methodOn(NachrichtenController.class).getRueckfrage(fullyLinkedRueckfrageHeader.getNachrichtHeader().id(),
+				fullyLinkedRueckfrageHeader.getNachrichtHeader().nachrichtEventId())).withRel(RUECKFRAGE_LINK_RELATIONSHIP_NAME));
 
-			when(nachrichtenService.getTopicHeadersOfPostfach(NachrichtTestFactory.POSTFACH_ID)).thenReturn(List.of(fullyLinkedTopicHeader));
+			when(nachrichtenService.getRueckfrageHeadersOfPostfach(NachrichtTestFactory.POSTFACH_ID)).thenReturn(
+			  List.of(fullyLinkedRueckfrageHeader));
 
 			performRequest()
 			  .andExpect(status().isOk())
 			  .andExpect(jsonPath("$[0]['links'].length()").value(2))
 			  .andExpect(jsonPath("$[0]['links'][0]['rel']").value("self"))
 			  .andExpect(jsonPath("$[0]['links'][0]['href']").isString())
-			  .andExpect(jsonPath("$[0]['links'][1]['rel']").value(TOPIC_LINK_RELATIONSHIP_NAME))
+			  .andExpect(jsonPath("$[0]['links'][1]['rel']").value(RUECKFRAGE_LINK_RELATIONSHIP_NAME))
 			  .andExpect(jsonPath("$[0]['links'][1]['href']").isString());
 		}
 
 		@Test
 		@WithMockUser
 		void shouldHandleRuntimeExceptions() throws Exception {
-			doThrow(RuntimeException.class).when(nachrichtenService).getTopicHeadersOfPostfach(NachrichtTestFactory.POSTFACH_ID);
+			doThrow(RuntimeException.class).when(nachrichtenService).getRueckfrageHeadersOfPostfach(NachrichtTestFactory.POSTFACH_ID);
 
 			performRequest().andExpect(status().isInternalServerError());
 		}
@@ -134,24 +136,24 @@ public class NachrichtenControllerITCase {
 		@Test
 		@WithMockUser
 		void shouldHandleTechnicalException() throws Exception {
-			doThrow(TechnicalException.class).when(nachrichtenService).getTopicHeadersOfPostfach(NachrichtTestFactory.POSTFACH_ID);
+			doThrow(TechnicalException.class).when(nachrichtenService).getRueckfrageHeadersOfPostfach(NachrichtTestFactory.POSTFACH_ID);
 
 			performRequest().andExpect(status().isInternalServerError());
 		}
 
 		ResultActions performRequest() throws Exception {
 			return mockMvc.perform(
-			  get(NachrichtenController.PATH + "/nachrichten/" + NachrichtTestFactory.POSTFACH_ID)
+			  get(NachrichtenController.PATH + "/rueckfragen/" + NachrichtTestFactory.POSTFACH_ID)
 				.contentType(MediaType.APPLICATION_JSON).characterEncoding(Charset.defaultCharset()));
 		}
 	}
 
 	@Nested
-	class TestLoadingTopic {
+	class TestLoadingRueckfrage {
 		@BeforeEach
 		void init() {
-			when(nachrichtenService.getTopicOfPostfach(NachrichtTestFactory.POSTFACH_ID, NachrichtTestFactory.ID)).thenReturn(
-			  NachrichtTestFactory.createTopic());
+			when(nachrichtenService.getRueckfrage(NachrichtTestFactory.ID, NachrichtTestFactory.NACHRICHT_EVENT_ID)).thenReturn(
+			  RueckfrageTestFactory.createRueckfrage());
 		}
 
 		@Test
@@ -159,7 +161,7 @@ public class NachrichtenControllerITCase {
 		void shouldLoadRueckfrage() throws Exception {
 			performRequest()
 			  .andExpect(status().isOk())
-			  .andExpect(jsonPath("$['clerkMessage']['id']").value(NachrichtTestFactory.ID));
+			  .andExpect(jsonPath("$['nachricht']['id']").value(NachrichtTestFactory.ID));
 		}
 
 		@Test
@@ -170,7 +172,7 @@ public class NachrichtenControllerITCase {
 		@Test
 		@WithMockUser
 		void shouldHandleRuntimeExceptions() throws Exception {
-			doThrow(RuntimeException.class).when(nachrichtenService).getTopicOfPostfach(NachrichtTestFactory.POSTFACH_ID, NachrichtTestFactory.ID);
+			doThrow(RuntimeException.class).when(nachrichtenService).getRueckfrage(NachrichtTestFactory.ID, NachrichtTestFactory.NACHRICHT_EVENT_ID);
 
 			performRequest().andExpect(status().isInternalServerError());
 		}
@@ -178,14 +180,15 @@ public class NachrichtenControllerITCase {
 		@Test
 		@WithMockUser
 		void shouldHandleTechnicalException() throws Exception {
-			doThrow(TechnicalException.class).when(nachrichtenService).getTopicOfPostfach(NachrichtTestFactory.POSTFACH_ID, NachrichtTestFactory.ID);
+			doThrow(TechnicalException.class).when(nachrichtenService)
+			  .getRueckfrage(NachrichtTestFactory.ID, NachrichtTestFactory.NACHRICHT_EVENT_ID);
 
 			performRequest().andExpect(status().isInternalServerError());
 		}
 
 		ResultActions performRequest() throws Exception {
 			return mockMvc.perform(
-			  get(NachrichtenController.PATH + "/nachrichten/" + NachrichtTestFactory.POSTFACH_ID + "/" + NachrichtTestFactory.ID)
+			  get(NachrichtenController.PATH + "/rueckfrage/" + NachrichtTestFactory.ID + "/" + NachrichtTestFactory.NACHRICHT_EVENT_ID)
 				.contentType(MediaType.APPLICATION_JSON).characterEncoding(Charset.defaultCharset()));
 		}
 	}
@@ -194,10 +197,11 @@ public class NachrichtenControllerITCase {
 	class TestSendingNachricht {
 		private final ObjectMapper mapper = new ObjectMapper();
 		private final ReplyNachricht msg = ReplyNachrichtTestFactory.create();
+		private final CommandReference commandReference = CommandReferenceTestFactory.create();
 
 		@BeforeEach
 		void init() {
-			doReturn(msg).when(nachrichtenService).sendRueckfrageAnswer(any(ReplyNachricht.class));
+			doReturn(commandReference).when(nachrichtenService).sendRueckfrageAnswer(any(ReplyNachricht.class));
 		}
 
 		@Test
@@ -205,7 +209,8 @@ public class NachrichtenControllerITCase {
 		void shouldSendNachricht() throws Exception {
 			performPutRequest(mapper.writeValueAsString(msg))
 			  .andExpect(status().isOk())
-			  .andExpect(jsonPath("$.id").value(ReplyNachrichtTestFactory.ID));
+			  .andExpect(jsonPath("$.id").value(CommandReferenceTestFactory.ID))
+			  .andExpect(jsonPath("$.nachrichtEventId").value(CommandReferenceTestFactory.NACHRICHT_EVENT_ID));
 		}
 
 		@Test
@@ -213,31 +218,28 @@ public class NachrichtenControllerITCase {
 		void shouldNotSendNachrichtBlankId() throws Exception {
 			var invalidMsg = ReplyNachrichtTestFactory.createBuilder().id("").build();
 
-			performPutRequest(mapper.writeValueAsString(invalidMsg))
-			  .andExpect(status().isBadRequest());
+			performPutRequest(mapper.writeValueAsString(invalidMsg)).andExpect(status().isBadRequest());
 		}
 
 		@Test
 		@WithMockUser
-		void shouldNotSendNachrichtNoAddress() throws Exception {
+		void shouldNotSendNachrichtWithoutAddress() throws Exception {
 			doThrow(AddressNotFoundException.class).when(nachrichtenService).sendRueckfrageAnswer(any());
 
-			performPutRequest(mapper.writeValueAsString(msg))
-			  .andExpect(status().isNotFound());
+			performPutRequest(mapper.writeValueAsString(msg)).andExpect(status().isNotFound());
 		}
 
 		@Test
 		@WithMockUser
-		void shouldNotSendNachrichtTimeout() throws Exception {
-			doThrow(new SendTimeoutException("test", new TimeoutException())).when(nachrichtenService).sendRueckfrageAnswer(any());
+		void shouldHandleRuntimeExceptions() throws Exception {
+			doThrow(RuntimeException.class).when(nachrichtenService).sendRueckfrageAnswer(any());
 
-			performPutRequest(mapper.writeValueAsString(msg))
-			  .andExpect(status().isGatewayTimeout());
+			performPutRequest(mapper.writeValueAsString(msg)).andExpect(status().isInternalServerError());
 		}
 
 		ResultActions performPutRequest(String body) throws Exception {
 			return mockMvc.perform(
-			  put(NachrichtenController.PATH + "/nachricht")
+			  put(NachrichtenController.PATH + "/antwort")
 				.with(csrf().asHeader())
 				.contentType(MediaType.APPLICATION_JSON)
 				.characterEncoding(Charset.defaultCharset())
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/nachricht/NachrichtenControllerTest.java b/server/src/test/java/de/ozgcloud/antragsraum/nachricht/NachrichtenControllerTest.java
index 51a64509712e8c43d8cdbd537741de4792b37641..4cbade4e3e0ad583f973d91afc5a2bff75d02f92 100644
--- a/server/src/test/java/de/ozgcloud/antragsraum/nachricht/NachrichtenControllerTest.java
+++ b/server/src/test/java/de/ozgcloud/antragsraum/nachricht/NachrichtenControllerTest.java
@@ -45,48 +45,48 @@ class NachrichtenControllerTest {
 	private NachrichtenService nachrichtenService;
 
 	@Nested
-	class TestLoadingTopicHeaders {
+	class TestLoadingRueckfrageHeaders {
 		@BeforeEach
 		void init() {
-			when(nachrichtenService.getTopicHeadersOfPostfach(NachrichtTestFactory.POSTFACH_ID)).thenReturn(
-			  List.of(NachrichtTestFactory.createTopicHeader()));
+			when(nachrichtenService.getRueckfrageHeadersOfPostfach(NachrichtTestFactory.POSTFACH_ID)).thenReturn(
+			  List.of(RueckfrageTestFactory.createRueckfrageHeader()));
 		}
 
 		@Test
-		void shouldLoadTopicHeaders() {
-			var result = nachrichtenController.getTopicHeadersOfPostfach(NachrichtTestFactory.POSTFACH_ID);
+		void shouldLoadRueckfrageHeaders() {
+			var result = nachrichtenController.getRueckfrageHeadersOfPostfach(NachrichtTestFactory.POSTFACH_ID);
 
 			assertThat(result).hasSize(1);
 		}
 
 		@Test
-		void shouldCallGetTopicHeadersOfPostfach() {
-			nachrichtenController.getTopicHeadersOfPostfach(NachrichtTestFactory.POSTFACH_ID);
+		void shouldCallGetRueckfrageHeadersOfPostfach() {
+			nachrichtenController.getRueckfrageHeadersOfPostfach(NachrichtTestFactory.POSTFACH_ID);
 
-			verify(nachrichtenService).getTopicHeadersOfPostfach(anyString());
+			verify(nachrichtenService).getRueckfrageHeadersOfPostfach(anyString());
 		}
 	}
 
 	@Nested
-	class TestLoadingTopic {
+	class TestLoadingRueckfrage {
 		@BeforeEach
 		void init() {
-			when(nachrichtenService.getTopicOfPostfach(NachrichtTestFactory.POSTFACH_ID, NachrichtTestFactory.ID)).thenReturn(
-			  NachrichtTestFactory.createTopic());
+			when(nachrichtenService.getRueckfrage(NachrichtTestFactory.ID, NachrichtTestFactory.NACHRICHT_EVENT_ID)).thenReturn(
+			  RueckfrageTestFactory.createRueckfrage());
 		}
 
 		@Test
-		void shouldLoadTopic() {
-			var result = nachrichtenController.getTopicOfPostfach(NachrichtTestFactory.POSTFACH_ID, NachrichtTestFactory.ID);
+		void shouldLoadRueckfrage() {
+			var result = nachrichtenController.getRueckfrage(NachrichtTestFactory.ID, NachrichtTestFactory.NACHRICHT_EVENT_ID);
 
 			assertThat(result).isNotNull();
 		}
 
 		@Test
-		void shouldCallGetTopicOfPostfach() {
-			nachrichtenController.getTopicOfPostfach(NachrichtTestFactory.POSTFACH_ID, NachrichtTestFactory.ID);
+		void shouldCallGetRueckfrageOfPostfach() {
+			nachrichtenController.getRueckfrage(NachrichtTestFactory.ID, NachrichtTestFactory.NACHRICHT_EVENT_ID);
 
-			verify(nachrichtenService).getTopicOfPostfach(anyString(), anyString());
+			verify(nachrichtenService).getRueckfrage(anyString(), anyString());
 		}
 	}
 
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/nachricht/NachrichtenGrpcClientTest.java b/server/src/test/java/de/ozgcloud/antragsraum/nachricht/NachrichtenGrpcClientTest.java
index eb93d827b561d34739b17c801b838aacd9292132..8f007fc38ca286d29f9784db6eda416d4edaa863 100644
--- a/server/src/test/java/de/ozgcloud/antragsraum/nachricht/NachrichtenGrpcClientTest.java
+++ b/server/src/test/java/de/ozgcloud/antragsraum/nachricht/NachrichtenGrpcClientTest.java
@@ -24,8 +24,6 @@ package de.ozgcloud.antragsraum.nachricht;
 import static org.assertj.core.api.Assertions.*;
 import static org.mockito.Mockito.*;
 
-import java.util.UUID;
-
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
@@ -41,11 +39,10 @@ import de.ozgcloud.antragsraum.common.ChannelPropertiesFactory;
 import de.ozgcloud.nachrichten.antragraum.AntragraumServiceGrpc;
 import de.ozgcloud.nachrichten.antragraum.GrpcFindRueckfragenRequest;
 import de.ozgcloud.nachrichten.antragraum.GrpcFindRueckfragenResponse;
+import de.ozgcloud.nachrichten.antragraum.GrpcGetRueckfrageRequest;
+import de.ozgcloud.nachrichten.antragraum.GrpcGetRueckfrageResponse;
 import de.ozgcloud.nachrichten.antragraum.GrpcSendRueckfrageAnswerRequest;
 import de.ozgcloud.nachrichten.antragraum.GrpcSendRueckfrageAnswerResponse;
-import de.ozgcloud.vorgang.grpc.command.CommandServiceGrpc;
-import de.ozgcloud.vorgang.grpc.command.GrpcCommand;
-import de.ozgcloud.vorgang.grpc.command.GrpcGetCommandRequest;
 import io.grpc.Channel;
 import net.devh.boot.grpc.client.channelfactory.GrpcChannelFactory;
 import net.devh.boot.grpc.client.config.GrpcChannelsProperties;
@@ -54,6 +51,7 @@ import net.devh.boot.grpc.client.interceptor.GlobalClientInterceptorRegistry;
 @ExtendWith(MockitoExtension.class)
 class NachrichtenGrpcClientTest {
 	private final static String CHANNEL_ADDRESS = "static://localhost:9090";
+
 	@Spy
 	@InjectMocks
 	private NachrichtenGrpcClient grpcClient;
@@ -146,32 +144,32 @@ class NachrichtenGrpcClientTest {
 				verify(antragraumServiceBlockingStub).findRueckfragen(any(GrpcFindRueckfragenRequest.class));
 			}
 		}
-	}
 
-	@Nested
-	class TestCheckingCommandStatus {
-		@Mock
-		private CommandServiceGrpc.CommandServiceBlockingStub commandServiceBlockingStub;
-		@Mock
-		private GrpcGetCommandRequest request;
+		@Nested
+		class TestGetRueckfrage {
+			@Mock
+			private GrpcGetRueckfrageRequest request;
 
-		@Test
-		void shouldCallGetGrpcCommand() {
-			var channelFactory = mock(GrpcChannelFactory.class);
-			var channel = mock(Channel.class);
-			when(channelFactory.createChannel(anyString())).thenReturn(channel);
-			doReturn(channelFactory).when(grpcClient).getChannelFactory(anyString());
-			doReturn(mock(GrpcCommand.class)).when(grpcClient).getGrpcCommand(any(), any(GrpcGetCommandRequest.class));
+			@Test
+			void shouldCallClientGetRueckfrage() {
+				var channelFactory = mock(GrpcChannelFactory.class);
+				var channel = mock(Channel.class);
+				when(channelFactory.createChannel(anyString())).thenReturn(channel);
+				doReturn(channelFactory).when(grpcClient).getChannelFactory(anyString());
+				doReturn(GrpcGetRueckfrageResponse.getDefaultInstance()).when(grpcClient)
+				  .getGrpcGetRueckfrageResponse(any(GrpcGetRueckfrageRequest.class), any());
 
-			grpcClient.getCommand(UUID.randomUUID().toString(), CHANNEL_ADDRESS);
+				grpcClient.getGetRueckfrage(request, CHANNEL_ADDRESS);
 
-			verify(grpcClient).getGrpcCommand(any(), any(GrpcGetCommandRequest.class));
-		}
+				verify(grpcClient).getGrpcGetRueckfrageResponse(any(GrpcGetRueckfrageRequest.class), any());
+			}
 
-		@Test
-		void shouldGetCommand() {
-			grpcClient.getGrpcCommand(commandServiceBlockingStub, request);
-			verify(commandServiceBlockingStub).getCommand(any(GrpcGetCommandRequest.class));
+			@Test
+			void shouldCallRemoteServiceFindRueckfragen() {
+				grpcClient.getGrpcGetRueckfrageResponse(request, antragraumServiceBlockingStub);
+
+				verify(antragraumServiceBlockingStub).getRueckfrage(any(GrpcGetRueckfrageRequest.class));
+			}
 		}
 	}
 }
\ No newline at end of file
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/nachricht/NachrichtenRemoteServiceITCase.java b/server/src/test/java/de/ozgcloud/antragsraum/nachricht/NachrichtenRemoteServiceITCase.java
index 390994d87a525a8bfed8c2deec4f9ec186c46f72..ddfe83bd7bff720c865e7e8516b9eae3e1c418d6 100644
--- a/server/src/test/java/de/ozgcloud/antragsraum/nachricht/NachrichtenRemoteServiceITCase.java
+++ b/server/src/test/java/de/ozgcloud/antragsraum/nachricht/NachrichtenRemoteServiceITCase.java
@@ -19,7 +19,7 @@
  */
 package de.ozgcloud.antragsraum.nachricht;
 
-import static de.ozgcloud.antragsraum.nachricht.GrpcRueckfragenTestFactory.*;
+import static de.ozgcloud.antragsraum.nachricht.GrpcRueckfrageTestFactory.*;
 import static org.assertj.core.api.Assertions.*;
 import static org.mockito.Mockito.*;
 
@@ -37,12 +37,12 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.boot.test.mock.mockito.SpyBean;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
-import org.springframework.security.core.Authentication;
 import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.test.annotation.DirtiesContext;
 import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
 
-import de.ozgcloud.antragsraum.common.SendTimeoutException;
+import de.ozgcloud.antragsraum.events.NachrichtEvent;
+import de.ozgcloud.antragsraum.events.NachrichtEventTestFactory;
 import lombok.extern.log4j.Log4j2;
 
 @SpringBootTest(properties = {
@@ -55,7 +55,6 @@ import lombok.extern.log4j.Log4j2;
 @Log4j2
 class NachrichtenRemoteServiceITCase {
 	public static final String ADDRESS = "in-process:test2";
-	public static final String COMMAND_ID = "id";
 	String samlResponse;
 
 	@SpyBean
@@ -73,55 +72,62 @@ class NachrichtenRemoteServiceITCase {
 	}
 
 	@Nested
-	class TestGetNachrichten {
+	class TestGetNachrichtHeaders {
+		private final NachrichtEvent nachrichtEvent = NachrichtEventTestFactory.createNachrichtEventBuilder().address(ADDRESS).build();
+
 		@BeforeEach
 		void setup() {
 			initUserPasswordToken();
 		}
 
 		@Test
-		void shouldLoadNachrichten() {
-			var nachricht = nachrichtenRemoteService.findRueckfragen(NachrichtEventTestFactory.POSTFACH_ID, ADDRESS);
+		void shouldLoadNachrichtHeaders() {
+			var nachrichtHeaders = nachrichtenRemoteService.findRueckfrageHeads(nachrichtEvent);
 
-			assertThat(nachricht).isNotNull();
+			assertThat(nachrichtHeaders).isNotNull();
 		}
 
 		@Test
 		void shouldHaveRueckfrageId() {
-			var nachrichten = nachrichtenRemoteService.findRueckfragen(NachrichtEventTestFactory.POSTFACH_ID, ADDRESS);
+			var nachrichtHeaders = nachrichtenRemoteService.findRueckfrageHeads(nachrichtEvent);
 
-			assertThat(nachrichten.get(0).id()).isEqualTo(RUECKFRAGE_ID);
+			assertThat(nachrichtHeaders.getFirst().id()).isEqualTo(RUECKFRAGE_ID);
 		}
 	}
 
 	@Nested
-	class TestSendNachricht {
-		@Test
-		void shouldSendNachricht() {
+	class TestGetNachricht {
+		private final NachrichtEvent nachrichtEvent = NachrichtEventTestFactory.createNachrichtEventBuilder().address(ADDRESS).build();
+
+		@BeforeEach
+		void setup() {
 			initUserPasswordToken();
+		}
 
-			var res = nachrichtenRemoteService.sendAnswer(ReplyNachrichtTestFactory.create(), ADDRESS);
+		@Test
+		void shouldLoadNachricht() {
+			var nachricht = nachrichtenRemoteService.getRueckfrage(RUECKFRAGE_ID, nachrichtEvent);
 
-			assertThat(res).isTrue();
+			assertThat(nachricht).isNotNull();
 		}
 
 		@Test
-		void shouldCheckCommand() throws Exception {
-			SecurityContextHolder.getContext().setAuthentication(mock(Authentication.class));
-
-			nachrichtenRemoteService.sendAnswer(ReplyNachrichtTestFactory.create(), ADDRESS);
+		void shouldHaveRueckfrageId() {
+			var nachricht = nachrichtenRemoteService.getRueckfrage(RUECKFRAGE_ID, nachrichtEvent).orElseThrow();
 
-			verify(nachrichtenRemoteService).waitUntilCommandIsFinished(anyString(), anyString());
-			verify(nachrichtenRemoteService).checkCommandIsFinished(anyString(), anyString(), any(Authentication.class));
+			assertThat(nachricht.id()).isEqualTo(RUECKFRAGE_ID);
 		}
+	}
 
+	@Nested
+	class TestSendNachricht {
 		@Test
-		void shouldThrowSendTimeoutException() {
+		void shouldSendNachricht() {
 			initUserPasswordToken();
 
-			assertThatExceptionOfType(SendTimeoutException.class).isThrownBy(() ->
-			  nachrichtenRemoteService.waitUntilCommandIsFinished(ADDRESS, COMMAND_ID)
-			);
+			var res = nachrichtenRemoteService.sendAnswer(ReplyNachrichtTestFactory.create(), ADDRESS);
+
+			assertThat(res).isNotNull();
 		}
 	}
 
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/nachricht/NachrichtenRemoteServiceTest.java b/server/src/test/java/de/ozgcloud/antragsraum/nachricht/NachrichtenRemoteServiceTest.java
index 05a5e22c4c2a39b2db56d1fdfe6806cdb4e99b8a..24b464387010d5cf472cc9a0eb504473139a8ce8 100644
--- a/server/src/test/java/de/ozgcloud/antragsraum/nachricht/NachrichtenRemoteServiceTest.java
+++ b/server/src/test/java/de/ozgcloud/antragsraum/nachricht/NachrichtenRemoteServiceTest.java
@@ -25,10 +25,7 @@ package de.ozgcloud.antragsraum.nachricht;
 import static org.assertj.core.api.Assertions.*;
 import static org.mockito.Mockito.*;
 
-import java.time.Duration;
-import java.time.temporal.ChronoUnit;
 import java.util.UUID;
-import java.util.concurrent.ExecutionException;
 
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Nested;
@@ -41,11 +38,13 @@ import org.mockito.Spy;
 import org.mockito.junit.jupiter.MockitoExtension;
 
 import de.ozgcloud.antragsraum.callcontext.ContextService;
+import de.ozgcloud.antragsraum.command.CommandReference;
+import de.ozgcloud.antragsraum.command.CommandTestFactory;
 import de.ozgcloud.antragsraum.common.AddressNotFoundException;
-import de.ozgcloud.antragsraum.common.SendTimeoutException;
-import de.ozgcloud.antragsraum.common.TechnicalException;
+import de.ozgcloud.antragsraum.events.NachrichtEvent;
+import de.ozgcloud.antragsraum.events.NachrichtEventTestFactory;
 import de.ozgcloud.nachrichten.antragraum.GrpcFindRueckfragenRequest;
-import de.ozgcloud.nachrichten.antragraum.GrpcFindRueckfragenResponse;
+import de.ozgcloud.nachrichten.antragraum.GrpcGetRueckfrageRequest;
 import de.ozgcloud.nachrichten.antragraum.GrpcRueckfrageAnswer;
 import de.ozgcloud.nachrichten.antragraum.GrpcSendRueckfrageAnswerRequest;
 import io.grpc.StatusRuntimeException;
@@ -66,37 +65,32 @@ public class NachrichtenRemoteServiceTest {
 	@Mock
 	private NachrichtMapper nachrichtMapper;
 
-	@Mock
-	private NachrichtProperties nachrichtProperties;
-
 	@Mock
 	private ContextService contextService;
 
 	@Nested
 	class TestNachrichtenAvailable {
+		private final NachrichtEvent nachrichtEvent = NachrichtEventTestFactory.createNachrichtEvent();
 
 		@BeforeEach
 		void init() {
 			when(contextService.getSamlResponse()).thenReturn(SAML_TOKEN);
-			when(nachrichtMapper.fromGrpcRueckfrage(any(), anyString())).thenReturn(NachrichtTestFactory.createNachricht());
-			when(nachrichtenGrpcClient.getFindRueckfragen(any(GrpcFindRueckfragenRequest.class),
-			  anyString())).thenReturn(
-			  GrpcFindRueckfragenResponse.newBuilder().addRueckfrage(GrpcRueckfragenTestFactory.create()).build());
+			when(nachrichtenGrpcClient.getFindRueckfragen(any(GrpcFindRueckfragenRequest.class), anyString())).thenReturn(
+			  GrpcRueckfrageTestFactory.createFindRueckfragenResponse());
 		}
 
 		@Test
-		void shouldLoadNachrichtById() {
-			var nachricht = nachrichtenRemoteService.findRueckfragen(POSTFACH_ID, ADDRESS);
+		void shouldLoadNachrichtHeaders() {
+			var nachrichtHeaders = nachrichtenRemoteService.findRueckfrageHeads(nachrichtEvent);
 
-			assertThat(nachricht).isNotEmpty();
+			assertThat(nachrichtHeaders).isNotEmpty();
 		}
 
 		@Test
 		void shouldSetSamlToken() {
-			ArgumentCaptor<GrpcFindRueckfragenRequest> requestArgumentCaptor =
-			  ArgumentCaptor.forClass(GrpcFindRueckfragenRequest.class);
+			ArgumentCaptor<GrpcFindRueckfragenRequest> requestArgumentCaptor = ArgumentCaptor.forClass(GrpcFindRueckfragenRequest.class);
 
-			nachrichtenRemoteService.findRueckfragen(POSTFACH_ID, ADDRESS);
+			nachrichtenRemoteService.findRueckfrageHeads(nachrichtEvent);
 
 			verify(nachrichtenGrpcClient).getFindRueckfragen(requestArgumentCaptor.capture(), anyString());
 			assertThat(requestArgumentCaptor.getValue().getSamlToken()).isNotEmpty();
@@ -105,103 +99,102 @@ public class NachrichtenRemoteServiceTest {
 
 	@Nested
 	class TestNoNachrichtenAvailable {
-
 		@BeforeEach
 		void init() {
 			when(contextService.getSamlResponse()).thenReturn(SAML_TOKEN);
-
-			doThrow(StatusRuntimeException.class).when(nachrichtenGrpcClient)
-			  .getFindRueckfragen(any(GrpcFindRueckfragenRequest.class), anyString());
+			doThrow(StatusRuntimeException.class).when(nachrichtenGrpcClient).getFindRueckfragen(any(GrpcFindRueckfragenRequest.class), anyString());
 		}
 
 		@Test
 		void shouldHandleStatusRuntimeException() {
-			var nachricht = nachrichtenRemoteService.findRueckfragen(POSTFACH_ID, ADDRESS);
+			var nachrichtHeaders = nachrichtenRemoteService.findRueckfrageHeads(NachrichtEventTestFactory.createNachrichtEvent());
 
-			assertThat(nachricht).isEmpty();
+			assertThat(nachrichtHeaders).isEmpty();
 		}
 	}
 
 	@Nested
-	class TestSendAnswer {
-
-		private final ReplyNachricht reply = ReplyNachrichtTestFactory.create();
-
+	class TestNoTargetAddressAvailable {
 		@BeforeEach
 		void init() {
 			when(contextService.getSamlResponse()).thenReturn(SAML_TOKEN);
-			when(nachrichtMapper.toGrpcRueckfrageAnswer(any())).thenReturn(GrpcRueckfrageAnswer.newBuilder().build());
-			when(nachrichtenGrpcClient.answerRueckfrage(any(GrpcSendRueckfrageAnswerRequest.class),
-			  anyString())).thenReturn(GrpcRueckfragenTestFactory.createSendRueckfrageAnswerResponse());
+			doThrow(AddressNotFoundException.class).when(nachrichtenGrpcClient)
+			  .getFindRueckfragen(any(GrpcFindRueckfragenRequest.class), anyString());
 		}
 
 		@Test
-		void shouldSendAnswer() {
-			when(nachrichtenGrpcClient.getCommand(anyString(), anyString())).thenReturn(
-			  GrpcCommandTestFactory.createBuilder().setStatus(GrpcCommandTestFactory.STATUS_FINISHED).build());
-			when(nachrichtProperties.getSendPollIntervalDuration()).thenReturn(Duration.of(1L, ChronoUnit.SECONDS));
-			when(nachrichtProperties.getTimeoutDuration()).thenReturn(Duration.of(2L, ChronoUnit.SECONDS));
+		void shouldThrowAddressNotFoundException() {
+			var nachrichtEvent = NachrichtEventTestFactory.createNachrichtEvent();
 
-			assertThat(nachrichtenRemoteService.sendAnswer(reply, ADDRESS)).isTrue();
+			assertThatExceptionOfType(AddressNotFoundException.class).isThrownBy(() -> nachrichtenRemoteService.findRueckfrageHeads(nachrichtEvent));
 		}
+	}
 
-		@Test
-		void shouldSetSamlResponse() {
-			when(nachrichtenGrpcClient.getCommand(anyString(), anyString())).thenReturn(
-			  GrpcCommandTestFactory.createBuilder().setStatus(GrpcCommandTestFactory.STATUS_FINISHED).build());
-			when(nachrichtProperties.getSendPollIntervalDuration()).thenReturn(Duration.of(1L, ChronoUnit.SECONDS));
-			when(nachrichtProperties.getTimeoutDuration()).thenReturn(Duration.of(2L, ChronoUnit.SECONDS));
-
-			ArgumentCaptor<GrpcSendRueckfrageAnswerRequest> requestArgumentCaptor =
-			  ArgumentCaptor.forClass(GrpcSendRueckfrageAnswerRequest.class);
-
-			nachrichtenRemoteService.sendAnswer(reply, ADDRESS);
-
-			verify(nachrichtenGrpcClient).answerRueckfrage(requestArgumentCaptor.capture(), anyString());
-			assertThat(requestArgumentCaptor.getValue().getSamlToken()).isNotEmpty();
-		}
+	@Nested
+	class TestGetNachricht {
+		private final NachrichtEvent nachrichtEvent = NachrichtEventTestFactory.createNachrichtEvent();
 
-		@Test
-		void shouldThrowTimeoutException() {
-			assertThatExceptionOfType(SendTimeoutException.class).isThrownBy(
-			  () -> nachrichtenRemoteService.sendAnswer(reply, ADDRESS));
+		@BeforeEach
+		void init() {
+			when(contextService.getSamlResponse()).thenReturn(SAML_TOKEN);
+			when(nachrichtMapper.fromGrpcRueckfrage(any(), anyString())).thenReturn(NachrichtTestFactory.createNachricht());
+			when(nachrichtenGrpcClient.getGetRueckfrage(any(GrpcGetRueckfrageRequest.class), anyString())).thenReturn(
+			  GrpcRueckfrageTestFactory.createGetRueckfrageResponse());
 		}
 
 		@Test
-		void shouldThrowTechnicalExceptionBecauseOfInterruptedException() throws Exception {
-			doThrow(InterruptedException.class).when(nachrichtenRemoteService).getSendResult(any());
+		void shouldLoadNachricht() {
+			var nachricht = nachrichtenRemoteService.getRueckfrage(GrpcRueckfrageTestFactory.RUECKFRAGE_ID, nachrichtEvent);
 
-			assertThatExceptionOfType(TechnicalException.class).isThrownBy(
-			  () -> nachrichtenRemoteService.sendAnswer(reply, ADDRESS));
+			assertThat(nachricht).isNotEmpty();
 		}
 
 		@Test
-		void shouldThrowTechnicalExceptionBecauseOfExecutionException() throws Exception {
-			doThrow(ExecutionException.class).when(nachrichtenRemoteService).getSendResult(any());
+		void shouldSetSamlToken() {
+			ArgumentCaptor<GrpcGetRueckfrageRequest> requestArgumentCaptor = ArgumentCaptor.forClass(GrpcGetRueckfrageRequest.class);
+
+			var nachricht = nachrichtenRemoteService.getRueckfrage(GrpcRueckfrageTestFactory.RUECKFRAGE_ID, nachrichtEvent);
 
-			assertThatExceptionOfType(TechnicalException.class).isThrownBy(
-			  () -> nachrichtenRemoteService.sendAnswer(reply, ADDRESS));
+			verify(nachrichtenGrpcClient).getGetRueckfrage(requestArgumentCaptor.capture(), anyString());
+			assertThat(requestArgumentCaptor.getValue().getSamlToken()).isNotEmpty();
 		}
 	}
 
 	@Nested
-	class TestNoTargetAddressAvailable {
-
-		private String address;
+	class TestSendAnswer {
+		private final ReplyNachricht reply = ReplyNachrichtTestFactory.create();
 
 		@BeforeEach
 		void init() {
 			when(contextService.getSamlResponse()).thenReturn(SAML_TOKEN);
-			doThrow(AddressNotFoundException.class).when(nachrichtenGrpcClient)
-			  .getFindRueckfragen(any(GrpcFindRueckfragenRequest.class), anyString());
-			address = "static://localhost:9090";
+			when(nachrichtMapper.toGrpcRueckfrageAnswer(any())).thenReturn(GrpcRueckfrageAnswer.newBuilder().build());
+			when(nachrichtenGrpcClient.answerRueckfrage(any(GrpcSendRueckfrageAnswerRequest.class),
+			  anyString())).thenReturn(GrpcRueckfrageTestFactory.createSendRueckfrageAnswerResponse());
 		}
 
 		@Test
-		void shouldThrowAddressNotFoundException() {
-			assertThatExceptionOfType(AddressNotFoundException.class).isThrownBy(
-			  () -> nachrichtenRemoteService.findRueckfragen(POSTFACH_ID, address)
-			);
+		void shouldSendAnswer() {
+			var result = nachrichtenRemoteService.sendAnswer(reply, ADDRESS);
+
+			assertThat(result).isInstanceOf(CommandReference.class);
+		}
+
+		@Test
+		void shouldReturnCommandReference() {
+			var result = nachrichtenRemoteService.sendAnswer(reply, ADDRESS);
+
+			assertThat(result.id()).isEqualTo(CommandTestFactory.ID);
+			assertThat(result.nachrichtEventId()).isEqualTo(ReplyNachrichtTestFactory.NACHRICHT_EVENT_ID);
+		}
+
+		@Test
+		void shouldSetSamlResponse() {
+			ArgumentCaptor<GrpcSendRueckfrageAnswerRequest> requestArgumentCaptor = ArgumentCaptor.forClass(GrpcSendRueckfrageAnswerRequest.class);
+
+			nachrichtenRemoteService.sendAnswer(reply, ADDRESS);
+
+			verify(nachrichtenGrpcClient).answerRueckfrage(requestArgumentCaptor.capture(), anyString());
+			assertThat(requestArgumentCaptor.getValue().getSamlToken()).isNotEmpty();
 		}
 	}
 }
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/nachricht/NachrichtenServiceGrpcTestConfiguration.java b/server/src/test/java/de/ozgcloud/antragsraum/nachricht/NachrichtenServiceGrpcTestConfiguration.java
index 3ed65ff486a97335ecc477790ac821b94a6d3963..7e0ceba791ba1e7b313b9d90abebf18487f63053 100644
--- a/server/src/test/java/de/ozgcloud/antragsraum/nachricht/NachrichtenServiceGrpcTestConfiguration.java
+++ b/server/src/test/java/de/ozgcloud/antragsraum/nachricht/NachrichtenServiceGrpcTestConfiguration.java
@@ -27,7 +27,7 @@ import org.springframework.context.annotation.Configuration;
 
 import com.google.common.collect.ImmutableList;
 
-import de.ozgcloud.antragsraum.attachments.FileRemoteService;
+import de.ozgcloud.antragsraum.attachments.FileService;
 import de.ozgcloud.antragsraum.callcontext.CallContextAttachingInterceptor;
 import de.ozgcloud.antragsraum.callcontext.ContextService;
 import de.ozgcloud.antragsraum.common.AuthenticationHelper;
@@ -66,21 +66,9 @@ public class NachrichtenServiceGrpcTestConfiguration {
 		return new AntragsraumServiceGrpc();
 	}
 
-	@Bean
-	CommandGrpcService commandGrpcServiceStub() {
-		return new CommandGrpcService();
-	}
-
-	NachrichtProperties nachrichtProperties() {
-		NachrichtProperties nachrichtProperties = new NachrichtProperties();
-		nachrichtProperties.setSendPollInterval("PT-0.5S");
-		nachrichtProperties.setSendTimeout("PT2S");
-		return nachrichtProperties;
-	}
-
 	@Bean
 	NachrichtenRemoteService nachrichtRemoteService() {
-		return new NachrichtenRemoteService(nachrichtenGrpcClient(), nachrichtProperties(), contextService(), nachrichtMapper());
+		return new NachrichtenRemoteService(nachrichtenGrpcClient(), contextService(), nachrichtMapper());
 	}
 
 	NachrichtenGrpcClient nachrichtenGrpcClient() {
@@ -88,7 +76,7 @@ public class NachrichtenServiceGrpcTestConfiguration {
 	}
 
 	NachrichtMapper nachrichtMapper() {
-		return new NachrichtMapper(mock(FileRemoteService.class));
+		return new NachrichtMapper(mock(FileService.class));
 	}
 
 	@Bean
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/nachricht/NachrichtenServiceTest.java b/server/src/test/java/de/ozgcloud/antragsraum/nachricht/NachrichtenServiceTest.java
index 3e910b0330f75ab6172edd61cae196b75abd40a3..e459afbdec26b3dad332bd966fb8d5813d0e1ebf 100644
--- a/server/src/test/java/de/ozgcloud/antragsraum/nachricht/NachrichtenServiceTest.java
+++ b/server/src/test/java/de/ozgcloud/antragsraum/nachricht/NachrichtenServiceTest.java
@@ -27,7 +27,7 @@ import static org.mockito.Mockito.*;
 import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*;
 
 import java.util.List;
-import java.util.UUID;
+import java.util.Optional;
 
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Nested;
@@ -38,10 +38,12 @@ import org.mockito.Mock;
 import org.mockito.Spy;
 import org.mockito.junit.jupiter.MockitoExtension;
 
-import de.ozgcloud.antragsraum.attachments.OzgFile;
-import de.ozgcloud.antragsraum.common.InsufficientTrustLevelException;
+import de.ozgcloud.antragsraum.command.CommandReference;
+import de.ozgcloud.antragsraum.command.CommandReferenceTestFactory;
+import de.ozgcloud.antragsraum.common.NotAccessibleException;
 import de.ozgcloud.antragsraum.events.NachrichtEvent;
 import de.ozgcloud.antragsraum.events.NachrichtEventService;
+import de.ozgcloud.antragsraum.events.NachrichtEventTestFactory;
 
 @ExtendWith(MockitoExtension.class)
 class NachrichtenServiceTest {
@@ -52,175 +54,114 @@ class NachrichtenServiceTest {
 	private NachrichtEventService nachrichtEventService;
 	@Mock
 	private NachrichtenRemoteService nachrichtenRemoteService;
-	@Mock
-	private NachrichtenTrustLevelService nachrichtenTrustLevelService;
 
 	@Nested
-	class TestGetTopicHeadersOfPostfach {
+	class TestGetRueckfrageHeadersOfPostfach {
 		@BeforeEach
 		void init() {
-			when(nachrichtEventService.getNachrichtEventsOfPostfachId(anyString())).thenReturn(List.of(NachrichtEventTestFactory.create()));
-			when(nachrichtenRemoteService.findRueckfragen(any(), anyString())).thenReturn(List.of(NachrichtTestFactory.createNachricht()));
+			when(nachrichtEventService.getNachrichtEventsOfPostfachId(anyString())).thenReturn(
+			  List.of(NachrichtEventTestFactory.createNachrichtEvent()));
+			when(nachrichtenRemoteService.findRueckfrageHeads(any())).thenReturn(List.of(NachrichtTestFactory.createNachrichtHeader()));
 		}
 
 		@Test
-		void shouldReturnTopicHeader() {
-			when(nachrichtenTrustLevelService.nachrichtMatchesUserTrustLevel(any(NachrichtTrustLevel.class))).thenReturn(false);
-
-			var result = nachrichtenService.getTopicHeadersOfPostfach(NachrichtTestFactory.POSTFACH_ID);
+		void shouldReturnRueckfrageHeader() {
+			var result = nachrichtenService.getRueckfrageHeadersOfPostfach(NachrichtTestFactory.POSTFACH_ID);
 
 			assertThat(result).hasSize(1);
 		}
 
 		@Test
 		void shouldOnlyAddSelfLink() {
-			var topicHeaderWithSelfLink = NachrichtTestFactory.createTopicHeader();
-			topicHeaderWithSelfLink.add(linkTo(NachrichtenController.class).withSelfRel());
+			when(nachrichtenRemoteService.findRueckfrageHeads(any())).thenReturn(
+			  List.of(NachrichtTestFactory.createNachrichtHeaderBuilder().accessible(false).build()));
 
-			when(nachrichtenTrustLevelService.nachrichtMatchesUserTrustLevel(any(NachrichtTrustLevel.class))).thenReturn(false);
+			var headerWithSelfLink = RueckfrageTestFactory.createRueckfrageHeader();
+			headerWithSelfLink.add(linkTo(NachrichtenController.class).withSelfRel());
 
-			var result = nachrichtenService.getTopicHeadersOfPostfach(NachrichtTestFactory.POSTFACH_ID);
+			var result = nachrichtenService.getRueckfrageHeadersOfPostfach(NachrichtTestFactory.POSTFACH_ID);
 
-			assertThat(result.get(0)).isEqualTo(topicHeaderWithSelfLink);
+			assertThat(result.getFirst().getLinks()).isEqualTo(headerWithSelfLink.getLinks());
 		}
 
 		@Test
-		void shouldAddSelfAndTopicLink() {
-			var fullyLinkedTopicHeader = NachrichtTestFactory.createTopicHeader();
-			fullyLinkedTopicHeader.add(linkTo(NachrichtenController.class).withSelfRel());
-			fullyLinkedTopicHeader.add(linkTo(methodOn(NachrichtenController.class).getTopicOfPostfach(NachrichtTestFactory.POSTFACH_ID,
-			  fullyLinkedTopicHeader.getClerkMessage().id())).withRel(TOPIC_LINK_RELATIONSHIP_NAME));
+		void shouldAddSelfAndRueckfrageLink() {
+			var fullyLinkedHeader = RueckfrageTestFactory.createRueckfrageHeader();
+			fullyLinkedHeader.add(linkTo(NachrichtenController.class).withSelfRel());
+			fullyLinkedHeader.add(linkTo(methodOn(NachrichtenController.class).getRueckfrage(fullyLinkedHeader.getNachrichtHeader().id(),
+			  fullyLinkedHeader.getNachrichtHeader().nachrichtEventId())).withRel(RUECKFRAGE_LINK_RELATIONSHIP_NAME));
 
-			when(nachrichtenTrustLevelService.nachrichtMatchesUserTrustLevel(any(NachrichtTrustLevel.class))).thenReturn(true);
+			var result = nachrichtenService.getRueckfrageHeadersOfPostfach(NachrichtTestFactory.POSTFACH_ID);
 
-			var result = nachrichtenService.getTopicHeadersOfPostfach(NachrichtTestFactory.POSTFACH_ID);
-
-			assertThat(result.get(0)).isEqualTo(fullyLinkedTopicHeader);
+			assertThat(result.getFirst().getLinks()).isEqualTo(fullyLinkedHeader.getLinks());
 		}
 	}
 
 	@Nested
-	class TestGetTopicOfPostfach {
+	class TestGetRueckfrage {
+		private final NachrichtEvent nachrichtEvent = NachrichtEventTestFactory.createNachrichtEvent();
+
 		@BeforeEach
 		void init() {
-			final NachrichtEvent event = NachrichtEventTestFactory.create();
-
-			when(nachrichtEventService.getNachrichtEventsOfPostfachId(anyString())).thenReturn(List.of(event));
-
-			when(nachrichtenRemoteService.findRueckfragen(any(), anyString())).thenReturn(List.of(NachrichtTestFactory.createNachrichtBuilder()
-			  .postfachId(event.postfachId())
-			  .vorgangId(NachrichtTestFactory.VORGANG_ID)
-			  .id(NachrichtTestFactory.ID)
-			  .attachments(List.of(OzgFile.builder().id(NachrichtTestFactory.ATTACHMENT_ID_1).build()))
-			  .replyNachrichten(List.of(ReplyNachrichtTestFactory.createBuilder().id(UUID.randomUUID().toString()).build()))
-			  .build())
-			);
+			when(nachrichtEventService.getNachrichtEventById(anyString())).thenReturn(nachrichtEvent);
 		}
 
 		@Test
-		void shouldThrowInsufficientTrustLevelException() {
-			when(nachrichtenTrustLevelService.nachrichtMatchesUserTrustLevel(any(NachrichtTrustLevel.class))).thenReturn(false);
+		void shouldMapRueckfrage() {
+			when(nachrichtenRemoteService.getRueckfrage(NachrichtTestFactory.ID, nachrichtEvent)).thenReturn(
+			  Optional.of(NachrichtTestFactory.createNachricht()));
 
-			assertThatExceptionOfType(InsufficientTrustLevelException.class).isThrownBy(
-				() -> nachrichtenService.getTopicOfPostfach(NachrichtTestFactory.POSTFACH_ID, NachrichtTestFactory.ID))
-			  .withMessage("Current user does not have the required trust level for the Rueckfrage with id '" + NachrichtTestFactory.ID + "'.");
+			var result = nachrichtenService.getRueckfrage(NachrichtTestFactory.ID, NachrichtTestFactory.NACHRICHT_EVENT_ID);
+
+			assertThat(result).isNotNull();
 		}
 
 		@Test
-		void shouldMapTopic() {
-			when(nachrichtenTrustLevelService.nachrichtMatchesUserTrustLevel(any(NachrichtTrustLevel.class))).thenReturn(true);
+		void shouldThrowNotAccessibleException() {
+			when(nachrichtenRemoteService.getRueckfrage(NachrichtTestFactory.ID, nachrichtEvent)).thenReturn(
+			  Optional.of(NachrichtTestFactory.createNachrichtBuilder().accessible(false).build()));
 
-			var result = nachrichtenService.getTopicOfPostfach(NachrichtTestFactory.POSTFACH_ID, NachrichtTestFactory.ID);
-
-			assertThat(result).isNotNull();
+			assertThatExceptionOfType(NotAccessibleException.class).isThrownBy(
+				() -> nachrichtenService.getRueckfrage(NachrichtTestFactory.ID, NachrichtTestFactory.NACHRICHT_EVENT_ID))
+			  .withMessage("Current user does not have the required trust level for the Rueckfrage with id '" + NachrichtTestFactory.ID + "'.");
 		}
 	}
 
 	@Nested
-	class TestGetRueckfragenOfPostfachWithNachrichtenEventAvailable {
-		final NachrichtEvent event = NachrichtEventTestFactory.create();
+	class TestGetNachrichtHeadersOfPostfachWithNachrichtenEventAvailable {
+		final NachrichtEvent event = NachrichtEventTestFactory.createNachrichtEvent();
 
 		@BeforeEach
 		void init() {
 			when(nachrichtEventService.getNachrichtEventsOfPostfachId(anyString())).thenReturn(List.of(event));
-
-			when(nachrichtenRemoteService.findRueckfragen(any(), anyString())).thenReturn(
-			  List.of(NachrichtTestFactory.createNachrichtBuilder()
-				.postfachId(event.postfachId())
-				.vorgangId(NachrichtTestFactory.VORGANG_ID)
-				.id(NachrichtTestFactory.ID)
-				.attachments(List.of(OzgFile.builder().id(NachrichtTestFactory.ATTACHMENT_ID_1).build()))
-				.replyNachrichten(List.of(ReplyNachrichtTestFactory.createBuilder().id(UUID.randomUUID().toString()).build()))
-				.build())
-			);
+			when(nachrichtenRemoteService.findRueckfrageHeads(any())).thenReturn(
+			  List.of(NachrichtTestFactory.createNachrichtHeaderBuilder().postfachId(event.postfachId()).build()));
 		}
 
 		@Test
 		void shouldCallNachrichtRemoteService() {
-			nachrichtenService.getRueckfragenOfPostfach(event.postfachId());
+			nachrichtenService.getNachrichtHeadersOfPostfach(event.postfachId());
 
-			verify(nachrichtenRemoteService, atMostOnce()).findRueckfragen(anyString(), anyString());
+			verify(nachrichtenRemoteService, atMostOnce()).findRueckfrageHeads(any(NachrichtEvent.class));
 		}
 
 		@Test
-		void shouldHaveNachrichten() {
-			var nachrichten = nachrichtenService.getRueckfragenOfPostfach(event.postfachId());
+		void shouldHaveNachrichtHeaders() {
+			var nachrichtHeaders = nachrichtenService.getNachrichtHeadersOfPostfach(event.postfachId());
 
-			assertThat(nachrichten).hasSize(1);
-		}
-
-		@Test
-		void shouldHaveNachrichtenText() {
-			var nachrichten = nachrichtenService.getRueckfragenOfPostfach(event.postfachId());
-
-			assertThat(nachrichten.stream().findFirst()).isPresent().map(Nachricht::message).isNotNull();
+			assertThat(nachrichtHeaders).hasSize(1);
 		}
 
 		@Test
 		void shouldHavePostfachId() {
-			var nachrichten = nachrichtenService.getRueckfragenOfPostfach(event.postfachId());
-
-			assertThat(nachrichten.stream().findFirst()).isPresent().map(Nachricht::postfachId).hasValue(event.postfachId());
-		}
-
-		@Test
-		void shouldHaveAttachment() {
-			var nachrichten = nachrichtenService.getRueckfragenOfPostfach(event.postfachId());
-
-			assertThat(nachrichten.stream().findFirst()).isPresent().map(Nachricht::attachments)
-			  .hasValue(List.of(OzgFile.builder().id(NachrichtTestFactory.ATTACHMENT_ID_1).build()));
-		}
-	}
-
-	@Nested
-	class TestNachrichtWithNullAttachment {
-		final NachrichtEvent event = NachrichtEventTestFactory.create();
-
-		@BeforeEach
-		void init() {
-			when(nachrichtEventService.getNachrichtEventsOfPostfachId(anyString())).thenReturn(
-			  List.of(event)
-			);
-
-			when(nachrichtenRemoteService.findRueckfragen(anyString(), anyString())).thenReturn(
-			  List.of(NachrichtTestFactory.createNachrichtBuilder()
-				.vorgangId(NachrichtTestFactory.VORGANG_ID)
-				.postfachId(event.postfachId())
-				.id(NachrichtTestFactory.ID)
-				.build())
-			);
-		}
-
-		@Test
-		void shouldNotHaveAttachment() {
-			var nachrichten = nachrichtenService.getRueckfragenOfPostfach(event.postfachId());
+			var nachrichtHeaders = nachrichtenService.getNachrichtHeadersOfPostfach(event.postfachId());
 
-			assertThat(nachrichten.stream().findFirst()).isPresent().map(Nachricht::attachments).isEmpty();
+			assertThat(nachrichtHeaders.stream().findFirst()).isPresent().map(NachrichtHeader::postfachId).hasValue(event.postfachId());
 		}
 	}
 
 	@Nested
-	class TestGetRueckfragenOfPostfachWithNoNachrichtenEventAvailable {
+	class TestGetNachrichtHeadersOfPostfachWithNoNachrichtenEventAvailable {
 		@BeforeEach
 		void init() {
 			when(nachrichtEventService.getNachrichtEventsOfPostfachId(anyString())).thenReturn(List.of());
@@ -228,16 +169,16 @@ class NachrichtenServiceTest {
 
 		@Test
 		void shouldCallNachrichtEventService() {
-			var nachrichten = nachrichtenService.getRueckfragenOfPostfach(NachrichtTestFactory.POSTFACH_ID);
+			var nachrichten = nachrichtenService.getNachrichtHeadersOfPostfach(NachrichtTestFactory.POSTFACH_ID);
 
 			assertThat(nachrichten).isEmpty();
 		}
 
 		@Test
 		void shouldNotCallNachrichtRemoteService() {
-			nachrichtenService.getRueckfragenOfPostfach(NachrichtTestFactory.POSTFACH_ID);
+			nachrichtenService.getNachrichtHeadersOfPostfach(NachrichtTestFactory.POSTFACH_ID);
 
-			verify(nachrichtenRemoteService, never()).findRueckfragen(anyString(), anyString());
+			verify(nachrichtenRemoteService, never()).findRueckfrageHeads(any(NachrichtEvent.class));
 		}
 	}
 
@@ -245,11 +186,24 @@ class NachrichtenServiceTest {
 	class TestSendNachricht {
 		ReplyNachricht msg = ReplyNachrichtTestFactory.create();
 
+		@BeforeEach
+		void init() {
+			when(nachrichtEventService.getNachrichtEventById(anyString())).thenReturn(NachrichtEventTestFactory.createNachrichtEvent());
+			when(nachrichtenRemoteService.sendAnswer(any(ReplyNachricht.class), anyString())).thenReturn(CommandReferenceTestFactory.create());
+		}
+
 		@Test
 		void shouldCallRemoteService() {
 			nachrichtenService.sendRueckfrageAnswer(msg);
 
 			verify(nachrichtenRemoteService).sendAnswer(any(ReplyNachricht.class), anyString());
 		}
+
+		@Test
+		void shouldReturnCommandReference() {
+			var result = nachrichtenService.sendRueckfrageAnswer(msg);
+
+			assertThat(result).isInstanceOf(CommandReference.class);
+		}
 	}
 }
\ No newline at end of file
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/nachricht/NachrichtenTrustLevelServiceTest.java b/server/src/test/java/de/ozgcloud/antragsraum/nachricht/NachrichtenTrustLevelServiceTest.java
deleted file mode 100644
index cd35b8ee1278d634700304525c8e719565222ea2..0000000000000000000000000000000000000000
--- a/server/src/test/java/de/ozgcloud/antragsraum/nachricht/NachrichtenTrustLevelServiceTest.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright (c) 2023-2024.
- * Das Land Schleswig-Holstein vertreten durch den Ministerpräsidenten des Landes Schleswig-Holstein Staatskanzlei Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
- *
- * Lizenziert unter der EUPL, Version 1.2 oder - sobald
- * diese von der Europäischen Kommission genehmigt wurden -
- * Folgeversionen der EUPL ("Lizenz");
- * Sie dürfen dieses Werk ausschließlich gemäß
- * dieser Lizenz nutzen.
- * Eine Kopie der Lizenz finden Sie hier:
- *
- * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
- *
- * Sofern nicht durch anwendbare Rechtsvorschriften
- * gefordert oder in schriftlicher Form vereinbart, wird
- * die unter der Lizenz verbreitete Software "so wie sie
- * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
- * ausdrücklich oder stillschweigend - verbreitet.
- * Die sprachspezifischen Genehmigungen und Beschränkungen
- * unter der Lizenz sind dem Lizenztext zu entnehmen.
- */
-package de.ozgcloud.antragsraum.nachricht;
-
-import static org.assertj.core.api.Assertions.*;
-import static org.mockito.Mockito.*;
-
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Nested;
-import org.junit.jupiter.api.Test;
-import org.mockito.MockedStatic;
-import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
-import org.springframework.security.core.context.SecurityContext;
-import org.springframework.security.core.context.SecurityContextHolder;
-
-import de.ozgcloud.antragsraum.security.User;
-import de.ozgcloud.antragsraum.security.UserTrustLevel;
-
-class NachrichtenTrustLevelServiceTest {
-	private NachrichtenTrustLevelService nachrichtenTrustLevelService;
-
-	@Nested
-	class TestNachrichtMatchesUserTrustLevel {
-		@BeforeEach
-		void init() {
-			nachrichtenTrustLevelService = new NachrichtenTrustLevelService();
-		}
-
-		@Test
-		void shouldDenyUsersWithoutTrustLevel() {
-			try (MockedStatic<SecurityContextHolder> securityContextHolder = mockStatic(SecurityContextHolder.class)) {
-				var mockedSecurityContext = getMockedSecurityContext(null);
-				securityContextHolder.when(SecurityContextHolder::getContext).thenReturn(mockedSecurityContext);
-
-				var resultLow = nachrichtenTrustLevelService.nachrichtMatchesUserTrustLevel(NachrichtTrustLevel.LOW);
-				var resultSubstantial = nachrichtenTrustLevelService.nachrichtMatchesUserTrustLevel(NachrichtTrustLevel.SUBSTANTIAL);
-				var resultHigh = nachrichtenTrustLevelService.nachrichtMatchesUserTrustLevel(NachrichtTrustLevel.HIGH);
-
-				assertThat(resultLow).isFalse();
-				assertThat(resultSubstantial).isFalse();
-				assertThat(resultHigh).isFalse();
-			}
-		}
-
-		@Test
-		void shouldAllowNachrichtenWithoutTrustLevel() {
-			try (MockedStatic<SecurityContextHolder> securityContextHolder = mockStatic(SecurityContextHolder.class)) {
-				var mockedSecurityContext = getMockedSecurityContext(UserTrustLevel.STORK_QAA_LEVEL_1);
-				securityContextHolder.when(SecurityContextHolder::getContext).thenReturn(mockedSecurityContext);
-
-				var result = nachrichtenTrustLevelService.nachrichtMatchesUserTrustLevel(null);
-
-				assertThat(result).isTrue();
-			}
-		}
-
-		@Test
-		void shouldAllowLowLevelNachrichten() {
-			try (MockedStatic<SecurityContextHolder> securityContextHolder = mockStatic(SecurityContextHolder.class)) {
-				var mockedSecurityContext = getMockedSecurityContext(UserTrustLevel.STORK_QAA_LEVEL_1);
-				securityContextHolder.when(SecurityContextHolder::getContext).thenReturn(mockedSecurityContext);
-
-				var result = nachrichtenTrustLevelService.nachrichtMatchesUserTrustLevel(NachrichtTrustLevel.LOW);
-
-				assertThat(result).isTrue();
-			}
-		}
-
-		@Test
-		void shouldAllowLevel4Users() {
-			try (MockedStatic<SecurityContextHolder> securityContextHolder = mockStatic(SecurityContextHolder.class)) {
-				var mockedSecurityContext = getMockedSecurityContext(UserTrustLevel.STORK_QAA_LEVEL_4);
-				securityContextHolder.when(SecurityContextHolder::getContext).thenReturn(mockedSecurityContext);
-
-				var resultLow = nachrichtenTrustLevelService.nachrichtMatchesUserTrustLevel(NachrichtTrustLevel.LOW);
-				var resultSubstantial = nachrichtenTrustLevelService.nachrichtMatchesUserTrustLevel(NachrichtTrustLevel.SUBSTANTIAL);
-				var resultHigh = nachrichtenTrustLevelService.nachrichtMatchesUserTrustLevel(NachrichtTrustLevel.HIGH);
-
-				assertThat(resultLow).isTrue();
-				assertThat(resultSubstantial).isTrue();
-				assertThat(resultHigh).isTrue();
-			}
-		}
-
-		@Test
-		void shouldOnlyDenyHighLevelNachrichtenForLevel3Users() {
-			try (MockedStatic<SecurityContextHolder> securityContextHolder = mockStatic(SecurityContextHolder.class)) {
-				var mockedSecurityContext = getMockedSecurityContext(UserTrustLevel.STORK_QAA_LEVEL_3);
-				securityContextHolder.when(SecurityContextHolder::getContext).thenReturn(mockedSecurityContext);
-
-				var resultLow = nachrichtenTrustLevelService.nachrichtMatchesUserTrustLevel(NachrichtTrustLevel.LOW);
-				var resultSubstantial = nachrichtenTrustLevelService.nachrichtMatchesUserTrustLevel(NachrichtTrustLevel.SUBSTANTIAL);
-				var resultHigh = nachrichtenTrustLevelService.nachrichtMatchesUserTrustLevel(NachrichtTrustLevel.HIGH);
-
-				assertThat(resultLow).isTrue();
-				assertThat(resultSubstantial).isTrue();
-				assertThat(resultHigh).isFalse();
-			}
-		}
-
-		@Test
-		void shouldOnlyAllowLowLevelNachrichtenForLevel1Users() {
-			try (MockedStatic<SecurityContextHolder> securityContextHolder = mockStatic(SecurityContextHolder.class)) {
-				var mockedSecurityContext = getMockedSecurityContext(UserTrustLevel.STORK_QAA_LEVEL_1);
-				securityContextHolder.when(SecurityContextHolder::getContext).thenReturn(mockedSecurityContext);
-
-				var resultLow = nachrichtenTrustLevelService.nachrichtMatchesUserTrustLevel(NachrichtTrustLevel.LOW);
-				var resultSubstantial = nachrichtenTrustLevelService.nachrichtMatchesUserTrustLevel(NachrichtTrustLevel.SUBSTANTIAL);
-				var resultHigh = nachrichtenTrustLevelService.nachrichtMatchesUserTrustLevel(NachrichtTrustLevel.HIGH);
-
-				assertThat(resultLow).isTrue();
-				assertThat(resultSubstantial).isFalse();
-				assertThat(resultHigh).isFalse();
-			}
-		}
-
-		private SecurityContext getMockedSecurityContext(UserTrustLevel userTrustLevel) {
-			var authentication = mock(UsernamePasswordAuthenticationToken.class);
-			when(authentication.getPrincipal()).thenReturn(User.builder().trustLevel(userTrustLevel).build());
-			var context = mock(SecurityContext.class);
-			when(context.getAuthentication()).thenReturn(authentication);
-
-			return context;
-		}
-	}
-}
\ No newline at end of file
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/nachricht/ReplyNachrichtTestFactory.java b/server/src/test/java/de/ozgcloud/antragsraum/nachricht/ReplyNachrichtTestFactory.java
index 1f09e65f6a569516cf3ed13673c2a144aadbafa9..72225ad0b3f086a94a840ec2fd6ad93d7be30a10 100644
--- a/server/src/test/java/de/ozgcloud/antragsraum/nachricht/ReplyNachrichtTestFactory.java
+++ b/server/src/test/java/de/ozgcloud/antragsraum/nachricht/ReplyNachrichtTestFactory.java
@@ -21,26 +21,22 @@
  */
 package de.ozgcloud.antragsraum.nachricht;
 
-import java.util.Date;
 import java.util.UUID;
 
 public class ReplyNachrichtTestFactory {
 	public static final String ID = UUID.randomUUID().toString();
-	public static final String ADDRESS = "static://localhost:9091";
-	public static final long DATE = new Date().getTime();
+	public static final String NACHRICHT_EVENT_ID = UUID.randomUUID().toString();
 	public static final String TEXT = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam";
 
-	public static ReplyNachricht create() {
+	static ReplyNachricht create() {
 		return createBuilder().build();
 	}
 
-	public static ReplyNachricht.ReplyNachrichtBuilder createBuilder() {
+	static ReplyNachricht.ReplyNachrichtBuilder createBuilder() {
 		return ReplyNachricht.builder()
 		  .id(ID)
-		  .address(ADDRESS)
+		  .nachrichtEventId(NACHRICHT_EVENT_ID)
 		  .postfachId(NachrichtTestFactory.POSTFACH_ID)
-		  .address(ADDRESS)
-		  .date(DATE)
 		  .message(TEXT);
 	}
 }
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/nachricht/RueckfrageHeaderMapperTest.java b/server/src/test/java/de/ozgcloud/antragsraum/nachricht/RueckfrageHeaderMapperTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..c8fa4a617e0f8c8c0201683b179e445e0e5f8f21
--- /dev/null
+++ b/server/src/test/java/de/ozgcloud/antragsraum/nachricht/RueckfrageHeaderMapperTest.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2023-2024.
+ * Das Land Schleswig-Holstein vertreten durch den Ministerpräsidenten des Landes Schleswig-Holstein Staatskanzlei Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+ *
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+package de.ozgcloud.antragsraum.nachricht;
+
+import static org.assertj.core.api.Assertions.*;
+
+import java.util.List;
+
+import org.junit.jupiter.api.Test;
+
+class RueckfrageHeaderMapperTest {
+	private final List<NachrichtHeader> nachrichtHeaders = List.of(NachrichtTestFactory.createNachrichtHeader(),
+	  NachrichtTestFactory.createNachrichtHeader());
+
+	@Test
+	void shouldHaveHeaders() {
+		var headers = RueckfrageHeaderMapper.fromNachrichtHeaders(nachrichtHeaders);
+
+		assertThat(headers).hasSize(2);
+	}
+
+	@Test
+	void shouldMapClerkNachrichtHeader() {
+		var headers = RueckfrageHeaderMapper.fromNachrichtHeaders(nachrichtHeaders);
+
+		assertThat(headers.getFirst().getNachrichtHeader()).isNotNull();
+		assertThat(headers.get(1).getNachrichtHeader()).isNotNull();
+	}
+
+	@Test
+	void shouldMapVorgangId() {
+		var headers = RueckfrageHeaderMapper.fromNachrichtHeaders(nachrichtHeaders);
+
+		assertThat(headers.getFirst().getNachrichtHeader().id()).isEqualTo(NachrichtTestFactory.ID);
+		assertThat(headers.get(1).getNachrichtHeader().id()).isEqualTo(NachrichtTestFactory.ID);
+	}
+
+	@Test
+	void shouldMapVorgangName() {
+		var headers = RueckfrageHeaderMapper.fromNachrichtHeaders(nachrichtHeaders);
+
+		assertThat(headers.getFirst().getTitle()).isEqualTo(NachrichtTestFactory.VORGANG_TITLE);
+		assertThat(headers.get(1).getTitle()).isEqualTo(NachrichtTestFactory.VORGANG_TITLE);
+	}
+
+	@Test
+	void shouldMapAccessible() {
+		var headers = RueckfrageHeaderMapper.fromNachrichtHeaders(nachrichtHeaders);
+
+		assertThat(headers.getFirst().isAccessible()).isEqualTo(NachrichtTestFactory.ACCESSIBLE);
+		assertThat(headers.get(1).isAccessible()).isEqualTo(NachrichtTestFactory.ACCESSIBLE);
+	}
+
+	@Test
+	void shouldMapTrustLevel() {
+		var headers = RueckfrageHeaderMapper.fromNachrichtHeaders(nachrichtHeaders);
+
+		assertThat(headers.getFirst().getTrustLevel()).isEqualTo(NachrichtTestFactory.TRUST_LEVEL);
+		assertThat(headers.get(1).getTrustLevel()).isEqualTo(NachrichtTestFactory.TRUST_LEVEL);
+	}
+
+	@Test
+	void shouldMapStatus() {
+		var headers = RueckfrageHeaderMapper.fromNachrichtHeaders(nachrichtHeaders);
+
+		assertThat(headers.getFirst().getStatus()).isEqualTo(NachrichtTestFactory.STATUS);
+		assertThat(headers.get(1).getStatus()).isEqualTo(NachrichtTestFactory.STATUS);
+	}
+}
\ No newline at end of file
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/nachricht/RueckfrageMapperTest.java b/server/src/test/java/de/ozgcloud/antragsraum/nachricht/RueckfrageMapperTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..52b78297f13704bc48a891ec386e47c49a8a3ea0
--- /dev/null
+++ b/server/src/test/java/de/ozgcloud/antragsraum/nachricht/RueckfrageMapperTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2023-2024.
+ * Das Land Schleswig-Holstein vertreten durch den Ministerpräsidenten des Landes Schleswig-Holstein Staatskanzlei Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+ *
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+package de.ozgcloud.antragsraum.nachricht;
+
+import static org.assertj.core.api.Assertions.*;
+
+import org.junit.jupiter.api.Test;
+
+class RueckfrageMapperTest {
+	private final Nachricht nachricht = NachrichtTestFactory.createNachricht();
+
+	@Test
+	void shouldHaveRueckfrage() {
+		var rueckfrage = RueckfrageMapper.fromNachricht(nachricht);
+
+		assertThat(rueckfrage).isNotNull();
+	}
+
+	@Test
+	void shouldMapClerkNachricht() {
+		var rueckfrage = RueckfrageMapper.fromNachricht(nachricht);
+
+		assertThat(rueckfrage.getNachricht()).isNotNull();
+	}
+
+	@Test
+	void shouldMapVorgangId() {
+		var rueckfrage = RueckfrageMapper.fromNachricht(nachricht);
+
+		assertThat(rueckfrage.getNachricht().id()).isEqualTo(NachrichtTestFactory.ID);
+	}
+
+	@Test
+	void shouldNotHaveReplyInNachricht() {
+		var rueckfrage = RueckfrageMapper.fromNachricht(nachricht);
+
+		assertThat(rueckfrage.getNachricht().replyNachrichten()).isNull();
+	}
+
+	@Test
+	void shouldMapUserNachrichten() {
+		var rueckfrage = RueckfrageMapper.fromNachricht(nachricht);
+
+		assertThat(rueckfrage.getAntworten()).hasSize(1);
+	}
+
+	@Test
+	void shouldMapVorgangName() {
+		var rueckfrage = RueckfrageMapper.fromNachricht(nachricht);
+
+		assertThat(rueckfrage.getTitle()).isEqualTo(NachrichtTestFactory.VORGANG_TITLE);
+	}
+
+	@Test
+	void shouldMapAccessible() {
+		var rueckfrage = RueckfrageMapper.fromNachricht(nachricht);
+
+		assertThat(rueckfrage.isAccessible()).isEqualTo(NachrichtTestFactory.ACCESSIBLE);
+	}
+
+	@Test
+	void shouldMapTrustLevel() {
+		var rueckfrage = RueckfrageMapper.fromNachricht(nachricht);
+
+		assertThat(rueckfrage.getTrustLevel()).isEqualTo(NachrichtTestFactory.TRUST_LEVEL);
+	}
+}
\ No newline at end of file
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/nachricht/NachrichtPropertiesTest.java b/server/src/test/java/de/ozgcloud/antragsraum/nachricht/RueckfrageTestFactory.java
old mode 100755
new mode 100644
similarity index 52%
rename from server/src/test/java/de/ozgcloud/antragsraum/nachricht/NachrichtPropertiesTest.java
rename to server/src/test/java/de/ozgcloud/antragsraum/nachricht/RueckfrageTestFactory.java
index 626f42274e2ed86e9b93e721d7b027447a39d7b6..497c391de992ada4a9b524437ad1bc5a1b7b25de
--- a/server/src/test/java/de/ozgcloud/antragsraum/nachricht/NachrichtPropertiesTest.java
+++ b/server/src/test/java/de/ozgcloud/antragsraum/nachricht/RueckfrageTestFactory.java
@@ -21,30 +21,36 @@
  */
 package de.ozgcloud.antragsraum.nachricht;
 
-import static org.assertj.core.api.Assertions.*;
+import static de.ozgcloud.antragsraum.nachricht.NachrichtTestFactory.*;
 
-import java.time.Duration;
-import java.time.temporal.ChronoUnit;
+import java.util.Collections;
 
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
+public class RueckfrageTestFactory {
+	public static final String VORGANG_TITLE = "Vorgang Test ";
+	public static final String TRUST_LEVEL = "LOW";
 
-class NachrichtPropertiesTest {
-	private final NachrichtProperties properties = new NachrichtProperties();
+	static Rueckfrage createRueckfrage() {
+		return createRueckfrageBuilder().build();
+	}
 
-	@BeforeEach
-	void setup() {
-		properties.setSendTimeout("PT120S");
-		properties.setSendPollInterval("PT300S");
+	static Rueckfrage.RueckfrageBuilder createRueckfrageBuilder() {
+		return Rueckfrage.builder()
+		  .title(VORGANG_TITLE)
+		  .nachricht(createNachricht())
+		  .accessible(true)
+		  .trustLevel(TRUST_LEVEL)
+		  .antworten(Collections.emptyList());
 	}
 
-	@Test
-	void shouldGetSendTimeoutDuration() {
-		assertThat(properties.getTimeoutDuration()).isEqualTo(Duration.of(120, ChronoUnit.SECONDS));
+	static RueckfrageHeader createRueckfrageHeader() {
+		return createRueckfrageHeaderBuilder().build();
 	}
 
-	@Test
-	void shouldGetSendPollIntervallDuration() {
-		assertThat(properties.getSendPollIntervalDuration()).isEqualTo(Duration.of(300, ChronoUnit.SECONDS));
+	static RueckfrageHeader.RueckfrageHeaderBuilder createRueckfrageHeaderBuilder() {
+		return RueckfrageHeader.builder()
+		  .title(VORGANG_TITLE)
+		  .nachrichtHeader(createNachrichtHeader())
+		  .accessible(true)
+		  .trustLevel(TRUST_LEVEL);
 	}
-}
\ No newline at end of file
+}
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/nachricht/TopicHeaderMapperTest.java b/server/src/test/java/de/ozgcloud/antragsraum/nachricht/TopicHeaderMapperTest.java
deleted file mode 100644
index bf55068eaeada9dd1a53bd23dd76dccc0aff08f4..0000000000000000000000000000000000000000
--- a/server/src/test/java/de/ozgcloud/antragsraum/nachricht/TopicHeaderMapperTest.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (c) 2023-2024.
- * Das Land Schleswig-Holstein vertreten durch den Ministerpräsidenten des Landes Schleswig-Holstein Staatskanzlei Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
- *
- * Lizenziert unter der EUPL, Version 1.2 oder - sobald
- * diese von der Europäischen Kommission genehmigt wurden -
- * Folgeversionen der EUPL ("Lizenz");
- * Sie dürfen dieses Werk ausschließlich gemäß
- * dieser Lizenz nutzen.
- * Eine Kopie der Lizenz finden Sie hier:
- *
- * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
- *
- * Sofern nicht durch anwendbare Rechtsvorschriften
- * gefordert oder in schriftlicher Form vereinbart, wird
- * die unter der Lizenz verbreitete Software "so wie sie
- * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
- * ausdrücklich oder stillschweigend - verbreitet.
- * Die sprachspezifischen Genehmigungen und Beschränkungen
- * unter der Lizenz sind dem Lizenztext zu entnehmen.
- */
-package de.ozgcloud.antragsraum.nachricht;
-
-import static org.assertj.core.api.Assertions.*;
-
-import java.util.List;
-
-import org.junit.jupiter.api.Nested;
-import org.junit.jupiter.api.Test;
-
-class TopicHeaderMapperTest {
-	@Nested
-	class TestFromNachrichten {
-		private final List<Nachricht> nachrichten = List.of(NachrichtTestFactory.createNachricht(), NachrichtTestFactory.createNachricht());
-
-		@Test
-		void shouldHaveTopicHeaders() {
-			var topicHeaders = TopicHeaderMapper.fromNachrichten(nachrichten);
-
-			assertThat(topicHeaders).hasSize(2);
-		}
-
-		@Test
-		void shouldMapClerkNachrichtHeader() {
-			var topicHeaders = TopicHeaderMapper.fromNachrichten(nachrichten);
-
-			assertThat(topicHeaders.get(0).getClerkMessage()).isNotNull();
-			assertThat(topicHeaders.get(1).getClerkMessage()).isNotNull();
-		}
-
-		@Test
-		void shouldMapVorgangId() {
-			var topicHeaders = TopicHeaderMapper.fromNachrichten(nachrichten);
-
-			assertThat(topicHeaders.get(0).getClerkMessage().id()).isEqualTo(NachrichtTestFactory.ID);
-			assertThat(topicHeaders.get(1).getClerkMessage().id()).isEqualTo(NachrichtTestFactory.ID);
-		}
-
-		@Test
-		void shouldMapVorgangName() {
-			var topicHeaders = TopicHeaderMapper.fromNachrichten(nachrichten);
-
-			assertThat(topicHeaders.get(0).getTopicTitle()).isEqualTo(NachrichtTestFactory.VORGANG_TITLE);
-			assertThat(topicHeaders.get(1).getTopicTitle()).isEqualTo(NachrichtTestFactory.VORGANG_TITLE);
-		}
-
-		@Test
-		void shouldMapTrustLevel() {
-			var topicHeaders = TopicHeaderMapper.fromNachrichten(nachrichten);
-
-			assertThat(topicHeaders.get(0).getTrustLevel()).isEqualTo(NachrichtTrustLevel.LOW);
-			assertThat(topicHeaders.get(1).getTrustLevel()).isEqualTo(NachrichtTrustLevel.LOW);
-		}
-	}
-}
\ No newline at end of file
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/nachricht/TopicMapperTest.java b/server/src/test/java/de/ozgcloud/antragsraum/nachricht/TopicMapperTest.java
deleted file mode 100644
index 0fb0d24e4e0ffd7865fec6cabdef78f0deeda265..0000000000000000000000000000000000000000
--- a/server/src/test/java/de/ozgcloud/antragsraum/nachricht/TopicMapperTest.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (c) 2023-2024.
- * Das Land Schleswig-Holstein vertreten durch den Ministerpräsidenten des Landes Schleswig-Holstein Staatskanzlei Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
- *
- * Lizenziert unter der EUPL, Version 1.2 oder - sobald
- * diese von der Europäischen Kommission genehmigt wurden -
- * Folgeversionen der EUPL ("Lizenz");
- * Sie dürfen dieses Werk ausschließlich gemäß
- * dieser Lizenz nutzen.
- * Eine Kopie der Lizenz finden Sie hier:
- *
- * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
- *
- * Sofern nicht durch anwendbare Rechtsvorschriften
- * gefordert oder in schriftlicher Form vereinbart, wird
- * die unter der Lizenz verbreitete Software "so wie sie
- * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
- * ausdrücklich oder stillschweigend - verbreitet.
- * Die sprachspezifischen Genehmigungen und Beschränkungen
- * unter der Lizenz sind dem Lizenztext zu entnehmen.
- */
-package de.ozgcloud.antragsraum.nachricht;
-
-import static org.assertj.core.api.Assertions.*;
-
-import org.junit.jupiter.api.Nested;
-import org.junit.jupiter.api.Test;
-
-class TopicMapperTest {
-	@Nested
-	class TestFromNachricht {
-		private final Nachricht nachricht = NachrichtTestFactory.createNachricht();
-
-		@Test
-		void shouldHaveTopic() {
-			var topic = TopicMapper.fromNachricht(nachricht);
-
-			assertThat(topic).isNotNull();
-		}
-
-		@Test
-		void shouldMapClerkNachricht() {
-			var topic = TopicMapper.fromNachricht(nachricht);
-
-			assertThat(topic.getClerkMessage()).isNotNull();
-		}
-
-		@Test
-		void shouldMapVorgangId() {
-			var topic = TopicMapper.fromNachricht(nachricht);
-
-			assertThat(topic.getClerkMessage().id()).isEqualTo(NachrichtTestFactory.ID);
-		}
-
-		@Test
-		void shouldNotHaveReplyInClerkNachricht() {
-			var topic = TopicMapper.fromNachricht(nachricht);
-
-			assertThat(topic.getClerkMessage().replyNachrichten()).isNull();
-		}
-
-		@Test
-		void shouldMapUserNachrichten() {
-			var topic = TopicMapper.fromNachricht(nachricht);
-
-			assertThat(topic.getUserMessages()).hasSize(1);
-		}
-
-		@Test
-		void shouldMapVorgangName() {
-			var topic = TopicMapper.fromNachricht(nachricht);
-
-			assertThat(topic.getTopicTitle()).isEqualTo(NachrichtTestFactory.VORGANG_TITLE);
-		}
-
-		@Test
-		void shouldMapTrustLevel() {
-			var topic = TopicMapper.fromNachricht(nachricht);
-
-			assertThat(topic.getTrustLevel()).isEqualTo(NachrichtTrustLevel.LOW);
-		}
-	}
-}
\ No newline at end of file
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/nachricht/TrustLevelMapperTest.java b/server/src/test/java/de/ozgcloud/antragsraum/nachricht/TrustLevelMapperTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..f147beb31e0736e63f6e78ae8725504b2cd6aa06
--- /dev/null
+++ b/server/src/test/java/de/ozgcloud/antragsraum/nachricht/TrustLevelMapperTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2023-2024.
+ * Das Land Schleswig-Holstein vertreten durch den Ministerpräsidenten des Landes Schleswig-Holstein Staatskanzlei Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+ *
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+package de.ozgcloud.antragsraum.nachricht;
+
+import static org.assertj.core.api.Assertions.*;
+
+import org.junit.jupiter.api.Test;
+
+class TrustLevelMapperTest {
+	@Test
+	void shouldMapLowTrustLevel() {
+		assertThat(TrustLevelMapper.map(TrustLevelMapper.TRUST_LEVEL_LOW)).isEqualTo(TrustLevelMapper.TRUST_LEVEL_LOW);
+	}
+
+	@Test
+	void shouldMapSubstantialTrustLevel() {
+		assertThat(TrustLevelMapper.map(TrustLevelMapper.TRUST_LEVEL_SUBSTANTIAL)).isEqualTo(TrustLevelMapper.TRUST_LEVEL_SUBSTANTIAL);
+	}
+
+	@Test
+	void shouldMapHighTrustLevel() {
+		assertThat(TrustLevelMapper.map(TrustLevelMapper.TRUST_LEVEL_HIGH)).isEqualTo(TrustLevelMapper.TRUST_LEVEL_HIGH);
+	}
+
+	@Test
+	void shouldMapLevel1TrustLevel() {
+		assertThat(TrustLevelMapper.map(TrustLevelMapper.TRUST_LEVEL_STORK_QAA_LEVEL_1)).isEqualTo(TrustLevelMapper.TRUST_LEVEL_LOW);
+	}
+
+	@Test
+	void shouldMapLevel2TrustLevel() {
+		assertThat(TrustLevelMapper.map(TrustLevelMapper.TRUST_LEVEL_STORK_QAA_LEVEL_2)).isEqualTo(TrustLevelMapper.TRUST_LEVEL_LOW);
+	}
+
+	@Test
+	void shouldMapLevel3TrustLevel() {
+		assertThat(TrustLevelMapper.map(TrustLevelMapper.TRUST_LEVEL_STORK_QAA_LEVEL_3)).isEqualTo(TrustLevelMapper.TRUST_LEVEL_SUBSTANTIAL);
+	}
+
+	@Test
+	void shouldMapLevel4TrustLevel() {
+		assertThat(TrustLevelMapper.map(TrustLevelMapper.TRUST_LEVEL_STORK_QAA_LEVEL_4)).isEqualTo(TrustLevelMapper.TRUST_LEVEL_HIGH);
+	}
+}
\ No newline at end of file
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/security/BayernIdSaml2ExtensionTest.java b/server/src/test/java/de/ozgcloud/antragsraum/security/BayernIdSaml2ExtensionTest.java
index 256306bdc586d9d70aa36549ecf1c76e97f18859..c0a5af1dbde1e7e2f71350f1add19cee851f2e80 100644
--- a/server/src/test/java/de/ozgcloud/antragsraum/security/BayernIdSaml2ExtensionTest.java
+++ b/server/src/test/java/de/ozgcloud/antragsraum/security/BayernIdSaml2ExtensionTest.java
@@ -107,7 +107,7 @@ class BayernIdSaml2ExtensionTest {
 		}
 
 		private XSAny getChild(XMLObject authMethodElement) {
-			return (XSAny) authMethodElement.getOrderedChildren().get(0);
+			return (XSAny) authMethodElement.getOrderedChildren().getFirst();
 		}
 	}
 
@@ -195,7 +195,7 @@ class BayernIdSaml2ExtensionTest {
 
 		@Test
 		void shouldHaveOneGrandChild() {
-			assertThat(displayInformation.getOrderedChildren().get(0).getOrderedChildren()).hasSize(1);
+			assertThat(displayInformation.getOrderedChildren().getFirst().getOrderedChildren()).hasSize(1);
 		}
 
 		@Test
@@ -223,7 +223,7 @@ class BayernIdSaml2ExtensionTest {
 		}
 
 		private XSAny getGrandChild(XMLObject authMethodElement) {
-			return (XSAny) authMethodElement.getOrderedChildren().get(0).getOrderedChildren().get(0);
+			return (XSAny) authMethodElement.getOrderedChildren().getFirst().getOrderedChildren().getFirst();
 		}
 	}
 
@@ -243,7 +243,7 @@ class BayernIdSaml2ExtensionTest {
 
 		@Test
 		void shouldHaveAkdbElement() {
-			var akdbExtension = extensions.getOrderedChildren().get(0);
+			var akdbExtension = extensions.getOrderedChildren().getFirst();
 
 			assertThat(akdbExtension.getElementQName().getPrefix()).isEqualTo(NAMESPACE_PREFIX);
 			assertThat(akdbExtension.getElementQName().getLocalPart()).isEqualTo(AUTHENTICATION_REQUEST_LOCAL_NAME);
@@ -253,28 +253,28 @@ class BayernIdSaml2ExtensionTest {
 
 		@Test
 		void shouldHaveAttributeVersion() {
-			XSAny akdbExtension = (XSAny) extensions.getOrderedChildren().get(0);
+			XSAny akdbExtension = (XSAny) extensions.getOrderedChildren().getFirst();
 
 			assertThat(akdbExtension.getUnknownAttributes()).containsEntry(new QName(VERSION_LOCAL_PART), "2");
 		}
 
 		@Test
 		void shouldHaveAuthMethods() {
-			var authMethods = getChildElement(AUTHN_METHODS_LOCAL_NAME, extensions.getOrderedChildren().get(0));
+			var authMethods = getChildElement(AUTHN_METHODS_LOCAL_NAME, extensions.getOrderedChildren().getFirst());
 
 			assertThat(authMethods).isPresent();
 		}
 
 		@Test
 		void shouldHaveRequestAttributes() {
-			var requestAttributes = getChildElement(REQUESTED_ATTRIBUTES_LOCAL_NAME, extensions.getOrderedChildren().get(0));
+			var requestAttributes = getChildElement(REQUESTED_ATTRIBUTES_LOCAL_NAME, extensions.getOrderedChildren().getFirst());
 
 			assertThat(requestAttributes).isPresent();
 		}
 
 		@Test
 		void shouldHaveDisplayInformation() {
-			var displayInformation = getChildElement(DISPLAY_INFORMATION_LOCAL_NAME, extensions.getOrderedChildren().get(0));
+			var displayInformation = getChildElement(DISPLAY_INFORMATION_LOCAL_NAME, extensions.getOrderedChildren().getFirst());
 
 			assertThat(displayInformation).isPresent();
 		}
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/security/JwtTokenVerifierTest.java b/server/src/test/java/de/ozgcloud/antragsraum/security/JwtTokenVerifierTest.java
index 4f8b9e3bff654f9726f4504e3f0e23a3e54a27b1..d03f3a4473bface487b6ec5ce37d5d8aa5423a3e 100644
--- a/server/src/test/java/de/ozgcloud/antragsraum/security/JwtTokenVerifierTest.java
+++ b/server/src/test/java/de/ozgcloud/antragsraum/security/JwtTokenVerifierTest.java
@@ -110,7 +110,7 @@ class JwtTokenVerifierTest {
 			  .claim("firstname", UserTestFactory.FIRST_NAME)
 			  .claim("lastname", UserTestFactory.LAST_NAME)
 			  .claim("postkorbhandle", UserTestFactory.POSTKORB_HANDLE)
-			  .claim("trustlevel", UserTestFactory.TRUST_LEVEL.getValue())
+			  .claim("trustlevel", UserTestFactory.TRUST_LEVEL)
 			  .compact();
 		}
 	}
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/security/SamlRedirectStrategyTest.java b/server/src/test/java/de/ozgcloud/antragsraum/security/SamlRedirectStrategyTest.java
index 92f1ed4b66f028243221630c326449d6c2c70c2c..416364c5b9cd6ab01edbd50678d8837b412aa93c 100644
--- a/server/src/test/java/de/ozgcloud/antragsraum/security/SamlRedirectStrategyTest.java
+++ b/server/src/test/java/de/ozgcloud/antragsraum/security/SamlRedirectStrategyTest.java
@@ -60,15 +60,15 @@ class SamlRedirectStrategyTest {
 
 	SamlRedirectStrategy samlRedirectStrategy;
 
-	@BeforeEach
-	void setup() {
-		when(request.getContextPath()).thenReturn(URL);
-		when(response.encodeRedirectURL(matches(URL + "\\?code=*"))).thenReturn(URL + "?code=abc");
-		samlRedirectStrategy = new SamlRedirectStrategy(userDetailsService);
-	}
-
 	@Nested
 	class TestRedirect {
+		@BeforeEach
+		void setup() {
+			when(request.getContextPath()).thenReturn(URL);
+			when(response.encodeRedirectURL(matches(URL + "\\?code=*"))).thenReturn(URL + "?code=abc");
+			samlRedirectStrategy = new SamlRedirectStrategy(userDetailsService, null);
+		}
+
 		@Test
 		void shouldAddUserToUserDetailservice() throws IOException {
 			initAuthentication();
@@ -83,7 +83,7 @@ class SamlRedirectStrategyTest {
 			attributes.put(UserMapper.NACHNAME_URN, List.of(UserTestFactory.LAST_NAME));
 			attributes.put(UserMapper.VORNAME_URN, List.of(UserTestFactory.FIRST_NAME));
 			attributes.put(UserMapper.POSTKORB_HANDLE_URN, List.of(UserTestFactory.POSTKORB_HANDLE));
-			attributes.put(UserMapper.VERTRAUENSNIVEAU_URN, List.of(UserTestFactory.TRUST_LEVEL.getValue()));
+			attributes.put(UserMapper.VERTRAUENSNIVEAU_URN, List.of(UserTestFactory.TRUST_LEVEL));
 			attributes.put(UserMapper.BK2_URN, List.of(UserTestFactory.USER_NAME));
 
 			var principal = new DefaultSaml2AuthenticatedPrincipal(UserTestFactory.USER_ID, attributes);
@@ -97,4 +97,22 @@ class SamlRedirectStrategyTest {
 			verify(response).sendRedirect(matches(URL + "\\?code=*"));
 		}
 	}
+
+	@Nested
+	class TestRedirectWithConfiguredUrl {
+		private final String CONFIGURED_REDIRECT_URL = "https://redirect.me";
+
+		@BeforeEach
+		void setup() {
+			when(response.encodeRedirectURL(matches(CONFIGURED_REDIRECT_URL + "\\?code=*"))).thenReturn(CONFIGURED_REDIRECT_URL + "?code=abc");
+			samlRedirectStrategy = new SamlRedirectStrategy(userDetailsService, CONFIGURED_REDIRECT_URL);
+		}
+
+		@Test
+		void shouldCreateRedirectUrl() throws IOException {
+			samlRedirectStrategy.sendRedirect(request, response, URL);
+
+			verify(response).sendRedirect(eq(CONFIGURED_REDIRECT_URL + "?code=abc"));
+		}
+	}
 }
\ No newline at end of file
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/security/SecurityProviderTest.java b/server/src/test/java/de/ozgcloud/antragsraum/security/SecurityProviderTest.java
index cb53cdcea859cb548193f8e954eb05fc67d77108..395077c2c3afec293d50030690e71833bf1e79f6 100644
--- a/server/src/test/java/de/ozgcloud/antragsraum/security/SecurityProviderTest.java
+++ b/server/src/test/java/de/ozgcloud/antragsraum/security/SecurityProviderTest.java
@@ -67,7 +67,7 @@ public class SecurityProviderTest {
 		}
 
 		@Test
-		void shouldNotRegisterMukSignatureAlgorithm() {
+		void shouldNotRegisterSignatureAlgorithms() {
 			try (var configService = mockStatic(ConfigurationService.class)) {
 				configService.when(() -> ConfigurationService.get(AlgorithmRegistry.class)).thenReturn(new AlgorithmRegistry());
 
@@ -76,7 +76,7 @@ public class SecurityProviderTest {
 		}
 
 		@Test
-		void shouldRegisterMukSignatureAlgorithm() {
+		void shouldRegisterSignatureAlgorithms() {
 			try (var configService = mockStatic(ConfigurationService.class)) {
 				configService.when(() -> ConfigurationService.get(AlgorithmRegistry.class)).thenReturn(new AlgorithmRegistry());
 
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/security/UserMapperTest.java b/server/src/test/java/de/ozgcloud/antragsraum/security/UserMapperTest.java
index 1678e1c25f64b78a91e80b05a7aff3f3dc509a7f..219af424a39ab69a503186c94ddff007ab35be0e 100644
--- a/server/src/test/java/de/ozgcloud/antragsraum/security/UserMapperTest.java
+++ b/server/src/test/java/de/ozgcloud/antragsraum/security/UserMapperTest.java
@@ -51,7 +51,7 @@ class UserMapperTest {
         attributes.put(UserMapper.NACHNAME_URN, List.of(UserTestFactory.LAST_NAME));
         attributes.put(UserMapper.VORNAME_URN, List.of(UserTestFactory.FIRST_NAME));
         attributes.put(UserMapper.POSTKORB_HANDLE_URN, List.of(UserTestFactory.POSTKORB_HANDLE));
-        attributes.put(UserMapper.VERTRAUENSNIVEAU_URN, List.of(UserTestFactory.TRUST_LEVEL.getValue()));
+        attributes.put(UserMapper.VERTRAUENSNIVEAU_URN, List.of(UserTestFactory.TRUST_LEVEL));
         attributes.put(UserMapper.BK2_URN, List.of(UserTestFactory.USER_NAME));
 
         var principal = new DefaultSaml2AuthenticatedPrincipal(UserTestFactory.USER_ID, attributes);
diff --git a/server/src/test/java/de/ozgcloud/antragsraum/security/UserTestFactory.java b/server/src/test/java/de/ozgcloud/antragsraum/security/UserTestFactory.java
index 2507fae953178f44bfee548e701080ba0c0723ac..4916708bf49d622424a33bd0ecd474f0c3292938 100644
--- a/server/src/test/java/de/ozgcloud/antragsraum/security/UserTestFactory.java
+++ b/server/src/test/java/de/ozgcloud/antragsraum/security/UserTestFactory.java
@@ -32,7 +32,7 @@ public class UserTestFactory {
 	static final String LAST_NAME = "Panter";
 	static final String USER_NAME = FIRST_NAME + "_" + LAST_NAME;
 	static final String POSTKORB_HANDLE = UUID.randomUUID().toString();
-	static final UserTrustLevel TRUST_LEVEL = UserTrustLevel.STORK_QAA_LEVEL_3;
+	static final String TRUST_LEVEL = "STORK-QAA-Level-3";
 	static final String SAML_TOKEN = "saml";
 	static final Date TOKEN_EXPIRATION = Date.from(ZonedDateTime.now(ZoneId.of("UTC")).plusMinutes(30L).toInstant());