diff --git a/.gitignore b/.gitignore
index 671fb0fee4dba749bd6cb2b15d03422c8ea29976..b97206eaa9037206fb36f521f938d8c355afb4da 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,6 +16,8 @@ target/
 # Client
 goofy-client/.vscode/
 goofy-client/apps/coverage/
+goofy-client/node/*
+goofy-client/temp/*
 
 .attach**
-.factorypath
\ No newline at end of file
+.factorypath
diff --git a/alfa-service/pom.xml b/alfa-service/pom.xml
index b28e9df32cc6244f0c27bfadcef451c7f3e50a72..7e4f81cd52eb0791b9f9cea0e8b1f2c4aa6a7483 100644
--- a/alfa-service/pom.xml
+++ b/alfa-service/pom.xml
@@ -32,7 +32,7 @@
 	<parent>
 		<groupId>de.itvsh.ozg</groupId>
 		<artifactId>goofy</artifactId>
-		<version>1.15.0-SNAPSHOT</version>
+		<version>1.16.0-SNAPSHOT</version>
 	</parent>
 
 	<artifactId>alfa-service</artifactId>
@@ -43,6 +43,9 @@
 	<properties>
 		<maven.compiler.source>${java.version}</maven.compiler.source>
 		<maven.compiler.target>${java.version}</maven.compiler.target>
+
+		<!-- TODO: die Version über kop-common ziehen -->
+		<jjwt.version>0.11.5</jjwt.version>
 	</properties>
 
 	<dependencies>
@@ -51,7 +54,6 @@
 			<groupId>org.springframework.boot</groupId>
 			<artifactId>spring-boot-starter-log4j2</artifactId>
 		</dependency>
-
 		<dependency>
 			<groupId>org.springframework.boot</groupId>
 			<artifactId>spring-boot-starter-web</artifactId>
@@ -64,29 +66,25 @@
 			<groupId>org.springframework.boot</groupId>
 			<artifactId>spring-boot-starter-validation</artifactId>
 		</dependency>
-
 		<dependency>
 			<groupId>net.devh</groupId>
 			<artifactId>grpc-client-spring-boot-starter</artifactId>
 		</dependency>
-
 		<dependency>
 			<groupId>org.springframework.boot</groupId>
 			<artifactId>spring-boot-starter-actuator</artifactId>
 		</dependency>
-
 		<dependency>
 			<groupId>org.springframework.boot</groupId>
 			<artifactId>spring-boot-starter-security</artifactId>
 		</dependency>
-
 		<dependency>
-			<groupId>org.keycloak</groupId>
-			<artifactId>keycloak-spring-boot-starter</artifactId>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
 		</dependency>
 		<dependency>
-			<groupId>org.keycloak</groupId>
-			<artifactId>keycloak-admin-client</artifactId>
+			<groupId>com.jayway.jsonpath</groupId>
+			<artifactId>json-path</artifactId>
 		</dependency>
 
 		<!-- jwt -->
@@ -96,7 +94,18 @@
 		</dependency>
 		<dependency>
 			<groupId>io.jsonwebtoken</groupId>
-			<artifactId>jjwt</artifactId>
+			<artifactId>jjwt-api</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>io.jsonwebtoken</groupId>
+			<artifactId>jjwt-impl</artifactId>
+			<version>${jjwt.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>io.jsonwebtoken</groupId>
+			<artifactId>jjwt-jackson</artifactId>
+			<version>${jjwt.version}</version>
+			<scope>runtime</scope>
 		</dependency>
 
 		<!-- own projects -->
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/EnvironmentController.java b/alfa-service/src/main/java/de/ozgcloud/alfa/EnvironmentController.java
index 0103a54760c7db79f34c0ab0980a0b569383108b..9dda134b2ea6580936e80d068055309175b645ce 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/EnvironmentController.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/EnvironmentController.java
@@ -25,7 +25,6 @@ package de.ozgcloud.alfa;
 
 import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*;
 
-import org.keycloak.adapters.springboot.KeycloakSpringBootProperties;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -37,23 +36,19 @@ import org.springframework.web.bind.annotation.RestController;
 public class EnvironmentController {
 
 	@Autowired
-	private KeycloakSpringBootProperties kcProperties;
+	private OAuth2Properties oAuth2Properties;
 
 	@Value("${goofy.production}")
 	private boolean production = true;
 
 	@GetMapping
 	public FrontendEnvironment getFrontendEnvironment() {
-		return FrontendEnvironment.builder()//
-				.production(production)//
-				.remoteHost(apiRoot())//
-				.authServer(kcProperties.getAuthServerUrl())//
-				.clientId(kcProperties.getResource())//
-				.realm(kcProperties.getRealm())
+		return FrontendEnvironment.builder()
+				.production(production)
+				.remoteHost(linkTo(RootController.class).toUri().toString())
+				.authServer(oAuth2Properties.getAuthServerUrl())
+				.clientId(oAuth2Properties.getResource())
+				.realm(oAuth2Properties.getRealm())
 				.build();
 	}
-
-	private String apiRoot() {
-		return linkTo(RootController.class).toUri().toString();
-	}
 }
\ No newline at end of file
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/GrpcConfiguration.java b/alfa-service/src/main/java/de/ozgcloud/alfa/GrpcConfiguration.java
new file mode 100644
index 0000000000000000000000000000000000000000..97cac2f8ea30484287afa30ab96bf522d1034bd9
--- /dev/null
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/GrpcConfiguration.java
@@ -0,0 +1,23 @@
+package de.ozgcloud.alfa;
+
+import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * A workaround for @GrpcClient to work i.e. inject dependency until full Spring 3 support is available.
+ * https://github.com/yidongnan/grpc-spring-boot-starter/pull/775
+ */
+@Configuration
+@ImportAutoConfiguration({
+		net.devh.boot.grpc.client.autoconfigure.GrpcClientAutoConfiguration.class,
+		net.devh.boot.grpc.client.autoconfigure.GrpcClientMetricAutoConfiguration.class,
+		net.devh.boot.grpc.client.autoconfigure.GrpcClientHealthAutoConfiguration.class,
+		net.devh.boot.grpc.client.autoconfigure.GrpcClientSecurityAutoConfiguration.class,
+		net.devh.boot.grpc.client.autoconfigure.GrpcClientTraceAutoConfiguration.class,
+		net.devh.boot.grpc.client.autoconfigure.GrpcDiscoveryClientAutoConfiguration.class,
+
+		net.devh.boot.grpc.common.autoconfigure.GrpcCommonCodecAutoConfiguration.class,
+		net.devh.boot.grpc.common.autoconfigure.GrpcCommonTraceAutoConfiguration.class
+})
+public class GrpcConfiguration {
+}
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/JwtAuthConverter.java b/alfa-service/src/main/java/de/ozgcloud/alfa/JwtAuthConverter.java
new file mode 100644
index 0000000000000000000000000000000000000000..70397ac1de728d4d94369b5b227b0228750c3897
--- /dev/null
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/JwtAuthConverter.java
@@ -0,0 +1,85 @@
+package de.ozgcloud.alfa;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.apache.commons.collections.MapUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.convert.converter.Converter;
+import org.springframework.lang.NonNull;
+import org.springframework.security.authentication.AbstractAuthenticationToken;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.oauth2.jwt.Jwt;
+import org.springframework.security.oauth2.jwt.JwtClaimNames;
+import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
+import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
+import org.springframework.stereotype.Component;
+
+@Component
+public class JwtAuthConverter implements Converter<Jwt, AbstractAuthenticationToken> {
+
+	private final JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
+
+	private static final String SIMPLE_GRANT_AUTHORITY_PREFIX = "ROLE_";
+	static final String RESOURCE_ACCESS_KEY = "resource_access";
+	static final String ROLES_KEY = "roles";
+
+	@Autowired
+	private OAuth2Properties oAuth2Properties;
+
+	@Override
+	public AbstractAuthenticationToken convert(@NonNull Jwt jwt) {
+		return new JwtAuthenticationToken(jwt, getAuthorities(jwt), getPrincipleClaimName(jwt));
+	}
+
+	String getPrincipleClaimName(Jwt jwt) {
+		return MapUtils.getString(jwt.getClaims(), getClaimName());
+	}
+
+	private String getClaimName() {
+		return Optional.ofNullable(oAuth2Properties.getPrincipleAttribute()).orElse(JwtClaimNames.SUB);
+	}
+
+	Set<GrantedAuthority> getAuthorities(Jwt jwt) {
+		return Stream.concat(jwtGrantedAuthoritiesConverter.convert(jwt).stream(), extractResourceRoles(jwt).stream()).collect(Collectors.toSet());
+	}
+
+	Collection<SimpleGrantedAuthority> extractResourceRoles(Jwt jwt) {
+		var resourceAccess = getResourceAccess(jwt);
+		if (resourceAccess.isEmpty()) {
+			return Collections.emptySet();
+		}
+		if (Objects.isNull(resourceAccess.get(oAuth2Properties.getResource()))) {
+			return Collections.emptySet();
+		}
+		return extractRoles(getClaimMapFromMap(resourceAccess, oAuth2Properties.getResource()));
+	}
+
+	private Map<String, Object> getResourceAccess(Jwt jwt) {
+		return jwt.getClaimAsMap(RESOURCE_ACCESS_KEY);
+	}
+
+	@SuppressWarnings("unchecked")
+	private Map<String, Object> getClaimMapFromMap(Map<String, Object> claimMap, String claimName) {
+		return MapUtils.getMap(claimMap, claimName);
+	}
+
+	Set<SimpleGrantedAuthority> extractRoles(Map<String, Object> resource) {
+		if (!resource.containsKey(ROLES_KEY)) {
+			return Collections.emptySet();
+		}
+		return getRoles(resource).stream().map(role -> new SimpleGrantedAuthority(SIMPLE_GRANT_AUTHORITY_PREFIX + role)).collect(Collectors.toSet());
+	}
+
+	@SuppressWarnings("unchecked")
+	private Collection<String> getRoles(Map<String, Object> resource) {
+		return (Collection<String>) resource.get(ROLES_KEY);
+	}
+}
\ No newline at end of file
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/OAuth2Properties.java b/alfa-service/src/main/java/de/ozgcloud/alfa/OAuth2Properties.java
new file mode 100644
index 0000000000000000000000000000000000000000..6a8d79d91213599bfcc0e9ff7213ff83a9ff53c2
--- /dev/null
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/OAuth2Properties.java
@@ -0,0 +1,36 @@
+package de.ozgcloud.alfa;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Setter
+@Getter
+@Configuration
+@ConfigurationProperties(prefix = OAuth2Properties.PREFIX)
+public class OAuth2Properties {
+
+	static final String PREFIX = "ozgcloud.oauth2";
+
+	/**
+	 * OAuth2 auth server url
+	 */
+	private String authServerUrl;
+
+	/**
+	 * OAuth2 realm
+	 */
+	private String realm;
+
+	/**
+	 * OAuth2 resource
+	 */
+	private String resource;
+
+	/**
+	 * OAuth2 principle attribute
+	 */
+	private String principleAttribute;
+}
\ No newline at end of file
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/RequestIdFilter.java b/alfa-service/src/main/java/de/ozgcloud/alfa/RequestIdFilter.java
index c99af4d374c060118ff2930849ef4eccf40d99dc..83b33e364ebd220e94962637bc6fedc545ad2efb 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/RequestIdFilter.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/RequestIdFilter.java
@@ -25,10 +25,10 @@ package de.ozgcloud.alfa;
 
 import java.io.IOException;
 
-import javax.servlet.FilterChain;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 
 import org.apache.logging.log4j.CloseableThreadContext;
 import org.springframework.beans.factory.annotation.Autowired;
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/SecurityConfiguration.java b/alfa-service/src/main/java/de/ozgcloud/alfa/SecurityConfiguration.java
index ca8c0c09f524b0ad77df52c18d25d0451c331b69..42f7e4158e24894ebc33b10354c346c5efb3c8eb 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/SecurityConfiguration.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/SecurityConfiguration.java
@@ -23,16 +23,20 @@
  */
 package de.ozgcloud.alfa;
 
-import org.keycloak.adapters.springsecurity.KeycloakConfiguration;
-import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider;
-import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter;
+import java.util.Optional;
+
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
 import org.springframework.http.HttpMethod;
+import org.springframework.security.authentication.AuthenticationManager;
 import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
-import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
+import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
 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.oauth2.server.resource.OAuth2ResourceServerConfigurer;
 import org.springframework.security.config.http.SessionCreationPolicy;
-import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper;
+import org.springframework.security.web.SecurityFilterChain;
 import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
 import org.springframework.security.web.authentication.session.NullAuthenticatedSessionStrategy;
 import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
@@ -42,48 +46,57 @@ import org.springframework.security.web.header.writers.frameoptions.XFrameOption
 
 import de.ozgcloud.alfa.common.downloadtoken.DownloadTokenAuthenticationFilter;
 
-@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
-@KeycloakConfiguration
-public class SecurityConfiguration extends KeycloakWebSecurityConfigurerAdapter {
+@Configuration
+@EnableWebSecurity
+@EnableMethodSecurity(securedEnabled = true)
+public class SecurityConfiguration {
+
+	@Autowired
+	private JwtAuthConverter jwtAuthConverter;
 
 	@Autowired
-	private DownloadTokenAuthenticationFilter downloadTokenFilter;
+	private SpringJwtProperties springJwtProperties;
+
+	@Bean
+	SecurityFilterChain securityFilterChain(HttpSecurity http, DownloadTokenAuthenticationFilter downloadTokenFilter) throws Exception {
+		http.csrf(csrf -> csrf.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()));
 
-	@Override
-	protected void configure(HttpSecurity http) throws Exception {
-		super.configure(http);
-		http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
+		http.sessionManagement(management -> management.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
 
-		http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
-				.and().authorizeRequests()//
-				.antMatchers(HttpMethod.GET, "/api/environment").permitAll()//
-				.antMatchers(HttpMethod.GET, "/assets/**").permitAll()//
-				.antMatchers(HttpMethod.GET, "/vorgang/**").permitAll()//
-				.antMatchers(HttpMethod.GET, "/meine/**").permitAll()//
-				.antMatchers(HttpMethod.GET, "/alle/**").permitAll()//
-				.antMatchers(HttpMethod.GET, "/unassigned/**").permitAll()//
-				.antMatchers("/api").authenticated()//
-				.antMatchers("/api/**").authenticated()//
-				.antMatchers("/actuator").permitAll()//
-				.antMatchers("/actuator/**").permitAll()//
-				.antMatchers("/").permitAll()//
-				.antMatchers("/*").permitAll()//
-				.anyRequest().denyAll();
+		http.authorizeHttpRequests(authorize -> authorize
+				.requestMatchers(HttpMethod.GET, "/api/environment").permitAll()
+				.requestMatchers(HttpMethod.GET, "/assets/**").permitAll()
+				.requestMatchers(HttpMethod.GET, "/vorgang/**").permitAll()
+				.requestMatchers(HttpMethod.GET, "/meine/**").permitAll()
+				.requestMatchers(HttpMethod.GET, "/alle/**").permitAll()
+				.requestMatchers(HttpMethod.GET, "/unassigned/**").permitAll()
+				.requestMatchers("/api").authenticated()
+				.requestMatchers("/api/**").authenticated()
+				.requestMatchers("/actuator").permitAll()
+				.requestMatchers("/actuator/**").permitAll()
+				.requestMatchers("/").permitAll()
+				.requestMatchers("/*").permitAll()
+				.anyRequest().denyAll());
 
-		http.headers().addHeaderWriter(new XFrameOptionsHeaderWriter(XFrameOptionsMode.SAMEORIGIN));
+		http.oauth2ResourceServer(this::setOAuth2ResourceServer);
+		http.headers(headers -> headers.addHeaderWriter(new XFrameOptionsHeaderWriter(XFrameOptionsMode.SAMEORIGIN)));
 		http.addFilterBefore(downloadTokenFilter, UsernamePasswordAuthenticationFilter.class);
+
+		return http.build();
 	}
 
-	@Autowired
-	public void configureGlobal(AuthenticationManagerBuilder auth) {
-		KeycloakAuthenticationProvider keyCloakAuthProvider = keycloakAuthenticationProvider();
-		keyCloakAuthProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
-		auth.authenticationProvider(keyCloakAuthProvider);
+	private void setOAuth2ResourceServer(OAuth2ResourceServerConfigurer<HttpSecurity> configurer) {
+		configurer.jwt().jwtAuthenticationConverter(jwtAuthConverter);
+		Optional.ofNullable(springJwtProperties.getJwkSetUri()).ifPresent(jwkSetUri -> configurer.jwt().jwkSetUri(jwkSetUri));
 	}
 
-	@Override
+	@Bean
 	protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
 		return new NullAuthenticatedSessionStrategy();
 	}
 
+	@Bean
+	AuthenticationManager authenticationManager(HttpSecurity http) throws Exception {
+		return http.getSharedObject(AuthenticationManagerBuilder.class).build();
+	}
 }
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/SpringJwtProperties.java b/alfa-service/src/main/java/de/ozgcloud/alfa/SpringJwtProperties.java
new file mode 100644
index 0000000000000000000000000000000000000000..9b81c0654242a2132f92ce8a1c2e509981951c00
--- /dev/null
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/SpringJwtProperties.java
@@ -0,0 +1,21 @@
+package de.ozgcloud.alfa;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Setter
+@Getter
+@Configuration
+@ConfigurationProperties(prefix = SpringJwtProperties.PREFIX)
+public class SpringJwtProperties {
+
+	static final String PREFIX = "spring.security.oauth2.resourceserver.jwt";
+
+	/**
+	 * Jwt jwk set uri
+	 */
+	private String jwkSetUri = null;
+}
\ No newline at end of file
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/WebConfig.java b/alfa-service/src/main/java/de/ozgcloud/alfa/WebConfig.java
index 2074b2e67f74c77f5b00ff6c9a8f6b6f8e0bd7ed..a0669a9539fecfa3fb4bb46020f5c85f9f133dde 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/WebConfig.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/WebConfig.java
@@ -26,9 +26,6 @@ package de.ozgcloud.alfa;
 import java.io.IOException;
 import java.util.concurrent.TimeUnit;
 
-import org.keycloak.adapters.KeycloakConfigResolver;
-import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver;
-import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.core.io.Resource;
 import org.springframework.http.CacheControl;
@@ -36,6 +33,8 @@ import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry
 import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 import org.springframework.web.servlet.resource.PathResourceResolver;
 
+import lombok.NoArgsConstructor;
+
 @Configuration
 public class WebConfig implements WebMvcConfigurer {
 
@@ -43,7 +42,6 @@ public class WebConfig implements WebMvcConfigurer {
 
 	@Override
 	public void addResourceHandlers(ResourceHandlerRegistry registry) {
-
 		registry.addResourceHandler("/*.js", "/*.css", "/*.ttf", "/*.woff", "/*.woff2", "/*.eot",
 				"/**/*.svg", "/*.svf", "/*.otf", "/*.ico", "/**/*.png")
 				.addResourceLocations(RESOURCE_LOCATION)
@@ -56,18 +54,20 @@ public class WebConfig implements WebMvcConfigurer {
 				.setCacheControl(CacheControl.noStore())
 				.setUseLastModified(false)
 				.resourceChain(true)
-				.addResolver(new PathResourceResolver() {
-					@Override
-					protected Resource getResource(String resourcePath, Resource location) throws IOException {
-						Resource requestedResource = location.createRelative(resourcePath);
-						return requestedResource.exists() && requestedResource.isReadable() ? requestedResource
-								: super.getResource("index.html", location);
-					}
-				});
+				.addResolver(new OzgCloudPathResourceResolver());
 	}
 
-	@Bean
-	public KeycloakConfigResolver keyCloakConfigResolver() {
-		return new KeycloakSpringBootConfigResolver();
+	@NoArgsConstructor
+	static class OzgCloudPathResourceResolver extends PathResourceResolver {
+
+		@Override
+		protected Resource getResource(String resourcePath, Resource location) throws IOException {
+			var requestedResource = location.createRelative(resourcePath);
+
+			if (requestedResource.exists() && requestedResource.isReadable()) {
+				return requestedResource;
+			}
+			return super.getResource("index.html", location);
+		}
 	}
-}
+}
\ No newline at end of file
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/common/GermanDateTimeFormatter.java b/alfa-service/src/main/java/de/ozgcloud/alfa/common/GermanDateTimeFormatter.java
new file mode 100644
index 0000000000000000000000000000000000000000..97dc0511e8c1d58ffd0de06b34820df0dfe23f03
--- /dev/null
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/common/GermanDateTimeFormatter.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2022 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.alfa.common;
+
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Locale;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import lombok.NonNull;
+
+@Component
+public class GermanDateTimeFormatter {
+
+	private static final DateTimeFormatter DATE_TIME_ZONE = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss z").withLocale(Locale.GERMANY);
+
+	@Autowired
+	private SystemProperties systemProperties;
+
+	public String formatZonedDateTime(@NonNull ZonedDateTime zonedDateTime) {
+		return DATE_TIME_ZONE.format(zonedDateTime.withZoneSameInstant(systemProperties.getTimeZone()));
+	}
+}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/TestSecurityConfiguration.java b/alfa-service/src/main/java/de/ozgcloud/alfa/common/SystemProperties.java
similarity index 60%
rename from alfa-service/src/test/java/de/ozgcloud/alfa/TestSecurityConfiguration.java
rename to alfa-service/src/main/java/de/ozgcloud/alfa/common/SystemProperties.java
index 9ea7dbf43b0ffb08b194e501e39bdd26da99d539..d58bada4d2c41ca587bf689f646d4524134c8a86 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/TestSecurityConfiguration.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/common/SystemProperties.java
@@ -21,23 +21,26 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-package de.ozgcloud.alfa;
+package de.ozgcloud.alfa.common;
 
+import java.time.ZoneId;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
 import org.springframework.context.annotation.Configuration;
-import org.springframework.core.annotation.Order;
-import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
-import org.springframework.security.config.annotation.web.builders.HttpSecurity;
-import org.springframework.security.config.annotation.web.builders.WebSecurity;
-import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
 
+import lombok.Getter;
+import lombok.Setter;
+
+@Setter
+@Getter
 @Configuration
-@Order(50)
-public class TestSecurityConfiguration extends WebSecurityConfigurerAdapter implements WebSecurityConfigurer<WebSecurity> {
+@ConfigurationProperties(prefix = SystemProperties.PREFIX)
+public class SystemProperties {
 
-	@Override
-	protected void configure(HttpSecurity http) throws Exception {
-		super.configure(http);
+	static final String PREFIX = "ozgcloud.system";
 
-		http.csrf().disable();
-	}
+	/**
+	 * Timezone to be used in application.
+	 */
+	private ZoneId timeZone = ZoneId.of("Europe/Berlin");
 }
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/common/binaryfile/BinaryFileMaxSizeConstraint.java b/alfa-service/src/main/java/de/ozgcloud/alfa/common/binaryfile/BinaryFileMaxSizeConstraint.java
index 0f252193a005ef714be422942761728f397165c5..4e2e344b837e957f0804d7cd7a48c2bdd607817e 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/common/binaryfile/BinaryFileMaxSizeConstraint.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/common/binaryfile/BinaryFileMaxSizeConstraint.java
@@ -30,8 +30,8 @@ import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-import javax.validation.Constraint;
-import javax.validation.Payload;
+import jakarta.validation.Constraint;
+import jakarta.validation.Payload;
 
 import de.ozgcloud.alfa.common.ValidationMessageCodes;
 
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/common/binaryfile/BinaryFileService.java b/alfa-service/src/main/java/de/ozgcloud/alfa/common/binaryfile/BinaryFileService.java
index 74bfd67e7f22ec26d200d2c43e729a9c151cd54c..eebbd2caea67e481ca652f08743a50d023d09752 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/common/binaryfile/BinaryFileService.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/common/binaryfile/BinaryFileService.java
@@ -28,7 +28,7 @@ import java.util.List;
 import java.util.concurrent.CompletableFuture;
 import java.util.stream.Stream;
 
-import javax.validation.Valid;
+import jakarta.validation.Valid;
 
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/common/binaryfile/DownloadAuthenticationHandler.java b/alfa-service/src/main/java/de/ozgcloud/alfa/common/binaryfile/DownloadAuthenticationHandler.java
index ad7639749de0b76fa04e88485ae985ba110f6718..ee46850a3953a45a759529e3ba3513766bfc62a8 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/common/binaryfile/DownloadAuthenticationHandler.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/common/binaryfile/DownloadAuthenticationHandler.java
@@ -39,7 +39,7 @@ public class DownloadAuthenticationHandler {
 
 	boolean check(FileId fileId, Authentication auth) {
 		if (auth instanceof UsernamePasswordAuthenticationToken userPasswordToken) {
-			GoofyUserWithFileId user = (GoofyUserWithFileId) userPasswordToken.getPrincipal();
+			var user = (GoofyUserWithFileId) userPasswordToken.getPrincipal();
 			return Objects.nonNull(fileId) && fileId.equals(user.getFileId()) && auth.isAuthenticated();
 		}
 
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/common/binaryfile/UploadBinaryFileSizeValidator.java b/alfa-service/src/main/java/de/ozgcloud/alfa/common/binaryfile/UploadBinaryFileSizeValidator.java
index 6aa3dbce4860ce92368a052da6ecc0374b5ec821..1bef03838dd01d3f8da8b215395e119ea6d546a3 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/common/binaryfile/UploadBinaryFileSizeValidator.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/common/binaryfile/UploadBinaryFileSizeValidator.java
@@ -26,8 +26,8 @@ package de.ozgcloud.alfa.common.binaryfile;
 import java.util.Map;
 import java.util.Optional;
 
-import javax.validation.ConstraintValidator;
-import javax.validation.ConstraintValidatorContext;
+import jakarta.validation.ConstraintValidator;
+import jakarta.validation.ConstraintValidatorContext;
 
 import org.hibernate.validator.constraintvalidation.HibernateConstraintValidatorContext;
 import org.springframework.beans.factory.annotation.Autowired;
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/CommandService.java b/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/CommandService.java
index ea7534a4f95a24c47197ac3662ab60bd87362bb5..638a672caa20cd5268b4218db07f69e0e810182c 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/CommandService.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/CommandService.java
@@ -26,7 +26,7 @@ package de.ozgcloud.alfa.common.command;
 import java.util.Optional;
 import java.util.stream.Stream;
 
-import javax.validation.Valid;
+import jakarta.validation.Valid;
 
 import org.apache.commons.collections.MapUtils;
 import org.springframework.beans.factory.annotation.Autowired;
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/CreateCommand.java b/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/CreateCommand.java
index 3cb5adcf3fcfa15f82dbd6228eeb607714691a85..0f8887ca869483fc91e817df3e986669cf29c940 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/CreateCommand.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/CreateCommand.java
@@ -23,7 +23,7 @@
  */
 package de.ozgcloud.alfa.common.command;
 
-import javax.validation.Valid;
+import jakarta.validation.Valid;
 
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonTypeInfo;
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/RequiredOrder.java b/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/RequiredOrder.java
index da13800709784f1a2c7906d3bfba20def3cd4a62..f998dfe648a4457c8247c56631934ea36eeed1ec 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/RequiredOrder.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/RequiredOrder.java
@@ -7,8 +7,8 @@ import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-import javax.validation.Constraint;
-import javax.validation.Payload;
+import jakarta.validation.Constraint;
+import jakarta.validation.Payload;
 
 @Constraint(validatedBy = { RequiredOrderValidator.class })
 @Target({ FIELD, METHOD, PARAMETER, ANNOTATION_TYPE, TYPE_USE })
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/RequiredOrderValidator.java b/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/RequiredOrderValidator.java
index 79c52429309481d71020d72bb26c3949e8bb0cc7..ef8a8897172582847e3cdc9377a5f5b4122a8342 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/RequiredOrderValidator.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/RequiredOrderValidator.java
@@ -1,7 +1,7 @@
 package de.ozgcloud.alfa.common.command;
 
-import javax.validation.ConstraintValidator;
-import javax.validation.ConstraintValidatorContext;
+import jakarta.validation.ConstraintValidator;
+import jakarta.validation.ConstraintValidatorContext;
 
 public class RequiredOrderValidator implements ConstraintValidator<RequiredOrder, CreateCommand> {
 
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/common/downloadtoken/DownloadTokenAuthenticationFilter.java b/alfa-service/src/main/java/de/ozgcloud/alfa/common/downloadtoken/DownloadTokenAuthenticationFilter.java
index 297aa8e7a22308f54ca8a3781c92e3742eeb6adf..e2824c6edfb29aababf2e32ef78a04364acdb468 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/common/downloadtoken/DownloadTokenAuthenticationFilter.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/common/downloadtoken/DownloadTokenAuthenticationFilter.java
@@ -25,13 +25,12 @@ package de.ozgcloud.alfa.common.downloadtoken;
 
 import java.io.IOException;
 
-import javax.servlet.FilterChain;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 
 import org.apache.commons.lang3.StringUtils;
-import org.apache.http.HttpStatus;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.core.annotation.Order;
 import org.springframework.stereotype.Component;
@@ -52,7 +51,7 @@ public class DownloadTokenAuthenticationFilter extends OncePerRequestFilter {
 		try {
 			downloadTokenService.handleToken(request, getDownloadToken(request));
 		} catch (TechnicalException e) {
-			response.setStatus(HttpStatus.SC_UNAUTHORIZED);
+			response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
 			return;
 		}
 
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/common/downloadtoken/DownloadTokenProperties.java b/alfa-service/src/main/java/de/ozgcloud/alfa/common/downloadtoken/DownloadTokenProperties.java
index 8e63cd4b96fe65a1ef4b937c301c0f6b1ffd782a..d07c0a7956c415e8c80adeadd5205aa634e32ec3 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/common/downloadtoken/DownloadTokenProperties.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/common/downloadtoken/DownloadTokenProperties.java
@@ -23,7 +23,7 @@
  */
 package de.ozgcloud.alfa.common.downloadtoken;
 
-import javax.validation.constraints.NotNull;
+import jakarta.validation.constraints.NotNull;
 
 import org.springframework.boot.context.properties.ConfigurationProperties;
 import org.springframework.context.annotation.Configuration;
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/common/downloadtoken/DownloadTokenService.java b/alfa-service/src/main/java/de/ozgcloud/alfa/common/downloadtoken/DownloadTokenService.java
index fa4276a91aebf8d0fae0b1ea4ae5c7aa14a08442..466881c91649dc8b37de5ec46057b33d5e717c89 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/common/downloadtoken/DownloadTokenService.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/common/downloadtoken/DownloadTokenService.java
@@ -27,7 +27,7 @@ import static de.ozgcloud.alfa.JwtTokenUtil.*;
 
 import java.util.Optional;
 
-import javax.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletRequest;
 
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -90,12 +90,12 @@ class DownloadTokenService {
 		Optional<Claims> claimsOptional = jwtTokenUtil.getAllClaimsFromToken(token);
 		var downloadUserBuilder = GoofyUserWithFileId.builder();
 		claimsOptional.ifPresent(claims -> downloadUserBuilder.user(
-				UserProfile.builder()
-						.id(UserId.from(claims.get(USERID_CLAIM, String.class)))
-						.firstName(claims.get(FIRSTNAME_CLAIM, String.class))
-						.lastName(claims.get(LASTNAME_CLAIM, String.class))
-						.authorities(jwtTokenUtil.getRolesFromToken(token))
-						.organisationseinheitIds(jwtTokenUtil.getOrganisationseinheitIdsFromToken(token)).build())
+						UserProfile.builder()
+								.id(UserId.from(claims.get(USERID_CLAIM, String.class)))
+								.firstName(claims.get(FIRSTNAME_CLAIM, String.class))
+								.lastName(claims.get(LASTNAME_CLAIM, String.class))
+								.authorities(jwtTokenUtil.getRolesFromToken(token))
+								.organisationseinheitIds(jwtTokenUtil.getOrganisationseinheitIdsFromToken(token)).build())
 				.fileId(FileId.from(claims.get(FILEID_CLAIM, String.class))));
 
 		return downloadUserBuilder.build();
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/common/errorhandling/ExceptionController.java b/alfa-service/src/main/java/de/ozgcloud/alfa/common/errorhandling/ExceptionController.java
index 0772ce937792cb74d362034fea4ea1e4d58792c0..018624fea26e30f86f059b898038ce02efdf0059 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/common/errorhandling/ExceptionController.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/common/errorhandling/ExceptionController.java
@@ -33,10 +33,10 @@ import java.util.Set;
 import java.util.UUID;
 import java.util.stream.Stream;
 
-import javax.validation.ConstraintViolation;
-import javax.validation.ConstraintViolationException;
-import javax.validation.Path;
-import javax.validation.metadata.ConstraintDescriptor;
+import jakarta.validation.ConstraintViolation;
+import jakarta.validation.ConstraintViolationException;
+import jakarta.validation.Path;
+import jakarta.validation.metadata.ConstraintDescriptor;
 
 import org.hibernate.validator.engine.HibernateConstraintViolation;
 import org.springframework.core.annotation.Order;
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/common/user/CurrentUserHelper.java b/alfa-service/src/main/java/de/ozgcloud/alfa/common/user/CurrentUserHelper.java
index c3752745433b597fec75c1eea29995c7efda3075..b0414c8fc1f7a12e718c0a8aeec96ebeedd8468b 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/common/user/CurrentUserHelper.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/common/user/CurrentUserHelper.java
@@ -34,26 +34,20 @@ import org.springframework.security.authentication.AuthenticationTrustResolverIm
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.oauth2.jwt.Jwt;
 
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
 
 @NoArgsConstructor(access = AccessLevel.PRIVATE)
 public class CurrentUserHelper {
-	static final String ROLE_PREFIX = "ROLE_";
 
-	public static final Predicate<String> HAS_ROLE = CurrentUserHelper::hasRole;
+	static final String ROLE_PREFIX = "ROLE_";
+	private static final String SUB_CLAIM_KEY = "sub";
 
 	private static final AuthenticationTrustResolver TRUST_RESOLVER = new AuthenticationTrustResolverImpl();
-	private static final Predicate<Authentication> TRUSTED = auth -> !TRUST_RESOLVER.isAnonymous(auth);
-
-	public static Authentication getAuthentication() {
-		return findAuthentication().orElseThrow(() -> new IllegalStateException("No authenticated User found"));
-	}
-
-	public static Optional<Authentication> findAuthentication() {
-		return Optional.ofNullable(SecurityContextHolder.getContext().getAuthentication()).filter(TRUSTED);
-	}
+	private static final Predicate<Authentication> IS_TRUSTED = auth -> !TRUST_RESOLVER.isAnonymous(auth);
+	private static final Predicate<String> IS_ROLE_PREFIX_MISSING = role -> !role.startsWith(ROLE_PREFIX);
 
 	public static boolean hasRole(String role) {
 		var auth = getAuthentication();
@@ -61,46 +55,44 @@ public class CurrentUserHelper {
 		if ((Objects.isNull(auth)) || (Objects.isNull(auth.getPrincipal()))) {
 			return false;
 		}
-		Collection<? extends GrantedAuthority> authorities = auth.getAuthorities();
-		return containsRole(authorities, role);
-
+		return containsRole(auth.getAuthorities(), role);
 	}
 
 	public static boolean containsRole(Collection<? extends GrantedAuthority> authorities, String role) {
-		String roleToCheck;
-
-		if (Objects.nonNull(role) && !role.startsWith(ROLE_PREFIX)) {
-			roleToCheck = ROLE_PREFIX + role;
-		} else {
-			roleToCheck = role;
-		}
-
 		if (Objects.isNull(authorities)) {
 			return false;
 		}
+		return containsRole(prepareRoleForCheck(role), authorities);
+	}
 
-		return containsRole(roleToCheck, authorities);
+	static boolean containsRole(String role, Collection<? extends GrantedAuthority> authorities) {
+		return authorities.stream().anyMatch(a -> isAuthorityEquals(role, a.getAuthority()));
 	}
 
-	public static String prepareRoleForCheck(String role) {
-		if ((Objects.nonNull(role)) && (!role.startsWith(ROLE_PREFIX))) {
-			return ROLE_PREFIX + role;
-		} else {
-			return role;
-		}
+	private static boolean isAuthorityEquals(String role, String authority) {
+		return StringUtils.equalsIgnoreCase(role, authority) || StringUtils.equalsIgnoreCase(prepareRoleForCheck(role), authority);
 	}
 
-	public static boolean containsRole(String role, Collection<? extends GrantedAuthority> authorities) {
-		return authorities.stream().anyMatch(a -> isAuthorityEquals(role, a.getAuthority()));
+	static String prepareRoleForCheck(String roleToCheck) {
+		return Optional.ofNullable(roleToCheck)
+				.filter(IS_ROLE_PREFIX_MISSING)
+				.map(role -> String.format("%s%s", ROLE_PREFIX, role))
+				.orElse(roleToCheck);
 	}
 
-	private static boolean isAuthorityEquals(String role, String authority) {
-		String roleToCheck = prepareRoleForCheck(role);
-		return StringUtils.equalsIgnoreCase(role, authority) || StringUtils.equalsIgnoreCase(roleToCheck, authority);
+	public static UserId getCurrentUserId() {
+		return UserId.from(getSubClaim());
 	}
 
-	static UserId getCurrentUserId() {
-		return UserId.from(getAuthentication().getName());
+	private static String getSubClaim() {
+		return ((Jwt) getAuthentication().getPrincipal()).getClaim(SUB_CLAIM_KEY);
 	}
 
+	public static Authentication getAuthentication() {
+		return findAuthentication().orElseThrow(() -> new IllegalStateException("No authenticated User found"));
+	}
+
+	private static Optional<Authentication> findAuthentication() {
+		return Optional.ofNullable(SecurityContextHolder.getContext().getAuthentication()).filter(IS_TRUSTED);
+	}
 }
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/common/user/CurrentUserService.java b/alfa-service/src/main/java/de/ozgcloud/alfa/common/user/CurrentUserService.java
index 94b9c3900b2f7decee285d35e220fd28463a5fe5..6ba0fc106713431e94c8974c21f50b93b6ca03a6 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/common/user/CurrentUserService.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/common/user/CurrentUserService.java
@@ -25,17 +25,14 @@ package de.ozgcloud.alfa.common.user;
 
 import java.util.Collection;
 import java.util.Collections;
-import java.util.HashSet;
 import java.util.List;
-import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
 
-import org.keycloak.KeycloakPrincipal;
-import org.keycloak.representations.AccessToken;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
 import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.oauth2.jwt.Jwt;
 import org.springframework.stereotype.Service;
 
 import de.itvsh.kop.common.errorhandling.TechnicalException;
@@ -50,6 +47,10 @@ public class CurrentUserService {
 
 	static final String USER_ATTRIBUTE_ORGANISATIONSEINHEIT_ID = "organisationseinheitId";
 
+	static final String KEYCLOAK_USER_PREFERRED_USERNAME = "preferred_username";
+	static final String KEYCLOAK_USER_GIVEN_NAME = "given_name";
+	static final String KEYCLOAK_USER_FAMILY_NAME = "family_name";
+
 	@Autowired
 	private UserService userService;
 	@Autowired
@@ -65,44 +66,47 @@ public class CurrentUserService {
 		return CurrentUserHelper.containsRole(reachableRoles, role);
 	}
 
-	public Collection<GrantedAuthority> getAuthorities() {
-		return Collections.unmodifiableCollection(new HashSet<GrantedAuthority>(CurrentUserHelper.getAuthentication().getAuthorities()));
-	}
-
 	public UserProfile getUser() {
-		var dlUser = getDownloadUser();
-		if (dlUser.isPresent()) {
-			return dlUser.get();
-		}
-
-		Optional<AccessToken> token = getCurrentSecurityToken();
+		return getDownloadUser().orElseGet(this::buildUserProfile);
+	}
 
+	private UserProfile buildUserProfile() {
 		var userBuilder = UserProfile.builder()
 				.id(getUserId())
 				.authorities(getAuthorities());
 
-		token.ifPresent(t -> userBuilder.userName(t.getPreferredUsername())
-				.firstName(t.getGivenName())
-				.lastName(t.getFamilyName())
-				.organisationseinheitIds(getOrganisationseinheitId(t.getOtherClaims())));
+		getCurrentSecurityToken().ifPresent(token -> userBuilder
+				.userName(token.getClaimAsString(KEYCLOAK_USER_PREFERRED_USERNAME))
+				.firstName(token.getClaimAsString(KEYCLOAK_USER_GIVEN_NAME))
+				.lastName(token.getClaimAsString(KEYCLOAK_USER_FAMILY_NAME))
+				.organisationseinheitIds(getOrganisationsEinheitIds(token)));
 
 		return userBuilder.build();
 	}
 
+	public Collection<GrantedAuthority> getAuthorities() {
+		return Collections.unmodifiableCollection(CurrentUserHelper.getAuthentication().getAuthorities());
+	}
+
 	public UserId getUserId() {
 		return findUserId()
 				.orElseThrow(() -> new TechnicalException("Cannot find internal UserId. Check sync with UserManager or Token Mapper in keycloak."));
 	}
 
 	public Optional<UserId> findUserId() {
-		return Optional.ofNullable(
-						getSingleClaimValue(ATTRIBUTE_NAME_USER_ID).map(UserId::from)
-								.orElseGet(() -> userService.getInternalId(CurrentUserHelper.getCurrentUserId()).orElse(null)))
+		return Optional.ofNullable(getSingleClaimValue(ATTRIBUTE_NAME_USER_ID)
+				.map(UserId::from)
+				.orElseGet(this::getInternalId))
 				.filter(Objects::nonNull);
 	}
 
-	List<String> getOrganisationseinheitId(Map<String, Object> claims) {
-		return Optional.ofNullable(claims.get(USER_ATTRIBUTE_ORGANISATIONSEINHEIT_ID))
+	private UserId getInternalId() {
+		return userService.getInternalId(CurrentUserHelper.getCurrentUserId()).orElse(null);
+	}
+
+	List<String> getOrganisationsEinheitIds(Jwt jwt) {
+		return Optional.ofNullable(jwt)
+				.map(token -> token.getClaim(USER_ATTRIBUTE_ORGANISATIONSEINHEIT_ID))
 				.map(col -> (Collection<?>) col).orElse(Collections.emptyList()) // NOSONAR - Collection.class::cast has type-safty issue
 				.stream().map(Object::toString).toList();
 	}
@@ -114,19 +118,19 @@ public class CurrentUserService {
 				.map(GoofyUserWithFileId::getUser);
 	}
 
-	Optional<AccessToken> getCurrentSecurityToken() {
-		Object principal = CurrentUserHelper.getAuthentication().getPrincipal();
+	Optional<String> getSingleClaimValue(String attributeName) {
+		return getCurrentSecurityToken()
+				.map(token -> token.getClaim(attributeName))
+				.map(String.class::cast);
+	}
+
+	Optional<Jwt> getCurrentSecurityToken() {
+		var principal = CurrentUserHelper.getAuthentication().getPrincipal();
 
-		if (principal instanceof KeycloakPrincipal<?> kcPrincipal) {
-			return Optional.of(kcPrincipal.getKeycloakSecurityContext().getToken());
+		if (principal instanceof Jwt kcPrincipal) {
+			return Optional.of(kcPrincipal);
 		}
 
 		return Optional.empty();
 	}
-
-	Optional<String> getSingleClaimValue(String attributeName) {
-		return getCurrentSecurityToken()
-				.map(token -> token.getOtherClaims().get(attributeName))
-				.map(String.class::cast);
-	}
 }
\ No newline at end of file
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/historie/HistorieCommandHandler.java b/alfa-service/src/main/java/de/ozgcloud/alfa/historie/HistorieCommandHandler.java
index dc735be8bf8f3da848fd631fa28612ff23a444fb..fe54b77f7a60a44ac005f05864c7819587701b36 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/historie/HistorieCommandHandler.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/historie/HistorieCommandHandler.java
@@ -27,8 +27,8 @@ import java.util.Map;
 import java.util.Optional;
 import java.util.function.Predicate;
 
-import org.apache.commons.codec.binary.StringUtils;
 import org.apache.commons.collections.MapUtils;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/kommentar/Kommentar.java b/alfa-service/src/main/java/de/ozgcloud/alfa/kommentar/Kommentar.java
index a522e29cf9e9fd05ca47cc1b663b835235d2a5b0..1dde8e3c04207e104bddf8f3a5986879e6dbc666 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/kommentar/Kommentar.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/kommentar/Kommentar.java
@@ -28,8 +28,8 @@ import static de.ozgcloud.alfa.common.ValidationMessageCodes.*;
 import java.time.ZonedDateTime;
 import java.util.List;
 
-import javax.validation.constraints.NotNull;
-import javax.validation.constraints.Size;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
 
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonProperty;
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/kommentar/KommentarCommand.java b/alfa-service/src/main/java/de/ozgcloud/alfa/kommentar/KommentarCommand.java
index a6945fac38dcd6aec6466cb2649f248a8e38801b..7f6e99db26f4255bc06827e0f0ccfd64545b77f4 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/kommentar/KommentarCommand.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/kommentar/KommentarCommand.java
@@ -23,7 +23,7 @@
  */
 package de.ozgcloud.alfa.kommentar;
 
-import javax.validation.Valid;
+import jakarta.validation.Valid;
 
 import com.fasterxml.jackson.annotation.JsonIgnore;
 
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/kommentar/KommentarService.java b/alfa-service/src/main/java/de/ozgcloud/alfa/kommentar/KommentarService.java
index 8edacd2a909f462b4bd23b20707318bb44acb1f0..4bd41879a07fffedf0e715c4d3adb65ca36575db 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/kommentar/KommentarService.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/kommentar/KommentarService.java
@@ -26,7 +26,7 @@ package de.ozgcloud.alfa.kommentar;
 import java.time.ZonedDateTime;
 import java.util.stream.Stream;
 
-import javax.validation.Valid;
+import jakarta.validation.Valid;
 
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungService.java b/alfa-service/src/main/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungService.java
index d215118ece078659764cff242d4a87101a9bf4a1..d478b7f56b218436f5c30404ad132c4261b331ae 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungService.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungService.java
@@ -3,7 +3,7 @@ package de.ozgcloud.alfa.loeschanforderung;
 import java.util.List;
 import java.util.Optional;
 
-import javax.validation.Valid;
+import jakarta.validation.Valid;
 
 import org.apache.commons.collections.MapUtils;
 import org.springframework.beans.factory.annotation.Autowired;
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/PostfachMail.java b/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/PostfachMail.java
index 722d7f5b9f2b4e96daa4f228ab42101371d04bb9..0b5a606b86e6ab51a6cd027b4e8caecf8f4320e0 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/PostfachMail.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/PostfachMail.java
@@ -29,8 +29,8 @@ import java.time.ZonedDateTime;
 import java.util.List;
 import java.util.Map;
 
-import javax.validation.constraints.NotEmpty;
-import javax.validation.constraints.Size;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.Size;
 
 import com.fasterxml.jackson.annotation.JsonIgnore;
 
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/PostfachNachrichtPdfModel.java b/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/PostfachNachrichtPdfModel.java
index 011cfc7be512df6257e987a66cc80c8a0926e952..47457f9b4040d2c3a47f01843b797a1131e227d2 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/PostfachNachrichtPdfModel.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/PostfachNachrichtPdfModel.java
@@ -25,9 +25,9 @@ package de.ozgcloud.alfa.postfach;
 
 import java.util.List;
 
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlElementWrapper;
-import javax.xml.bind.annotation.XmlRootElement;
+import jakarta.xml.bind.annotation.XmlElement;
+import jakarta.xml.bind.annotation.XmlElementWrapper;
+import jakarta.xml.bind.annotation.XmlRootElement;
 
 import lombok.AccessLevel;
 import lombok.AllArgsConstructor;
@@ -76,7 +76,7 @@ class PostfachNachrichtPdfModel {
 	@Getter
 	@Builder
 	static class Nachricht {
-		
+
 		@XmlElement
 		private boolean isFirst;
 
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/PostfachNachrichtPdfService.java b/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/PostfachNachrichtPdfService.java
index 6a71d24ad93dd318d8064f7692b2e81f70a339f3..1ab1d3efdd79fd8b6e2790f6329efcda55278dff 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/PostfachNachrichtPdfService.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/PostfachNachrichtPdfService.java
@@ -26,8 +26,6 @@ package de.ozgcloud.alfa.postfach;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.time.format.DateTimeFormatter;
-import java.util.Locale;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.stream.Stream;
@@ -40,6 +38,7 @@ import org.springframework.stereotype.Service;
 
 import de.itvsh.kop.common.errorhandling.TechnicalException;
 import de.itvsh.kop.common.pdf.PdfService;
+import de.ozgcloud.alfa.common.GermanDateTimeFormatter;
 import de.ozgcloud.alfa.common.user.UserManagerUrlProvider;
 import de.ozgcloud.alfa.common.user.UserProfile;
 import de.ozgcloud.alfa.postfach.PostfachMail.Direction;
@@ -56,11 +55,12 @@ class PostfachNachrichtPdfService {
 
 	static final String FALLBACK_ANTRAGSTELLER_NAME = "Antragsteller";
 
-	private static final DateTimeFormatter CREATED_AT_FORMATTER = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss O").withLocale(Locale.GERMANY);
-
 	@Autowired
 	private PdfService pdfService;
 
+	@Autowired
+	private GermanDateTimeFormatter germanDateTimeFormatter;
+
 	private boolean isFirstNachricht;
 
 	@Value(PostfachNachrichtPdfService.PDF_TEMPLATE_PATH)
@@ -111,7 +111,7 @@ class PostfachNachrichtPdfService {
 				.isFirst(isFirstNachricht())
 				.subject(postfachMail.getSubject())
 				.mailBody(postfachMail.getMailBody())
-				.createdAt(CREATED_AT_FORMATTER.format(postfachMail.getCreatedAt()))
+				.createdAt(germanDateTimeFormatter.formatZonedDateTime(postfachMail.getCreatedAt()))
 				.createdBy(buildAbsenderName(postfachMail, antragsteller))
 				.attachments(postfachMail.getAttachmentNames())
 				.build();
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/system/SystemStatusService.java b/alfa-service/src/main/java/de/ozgcloud/alfa/system/SystemStatusService.java
index 2659fe7ee8dfa9ae928f6d8b4ef645454b827c38..b188e77aade4147f71521677815a9c569c6bc5d1 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/system/SystemStatusService.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/system/SystemStatusService.java
@@ -43,4 +43,5 @@ public class SystemStatusService {
 			return false;
 		}
 	}
-}
+
+}
\ No newline at end of file
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/vorgang/VorgangController.java b/alfa-service/src/main/java/de/ozgcloud/alfa/vorgang/VorgangController.java
index 71072fbadc071f5fad12a96dd85bf56556e14fa0..35062413fb4a816eaf0263aa284d2bc5b32b4e6a 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/vorgang/VorgangController.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/vorgang/VorgangController.java
@@ -25,7 +25,7 @@ package de.ozgcloud.alfa.vorgang;
 
 import java.util.Optional;
 
-import javax.servlet.http.HttpServletResponse;
+import jakarta.servlet.http.HttpServletResponse;
 
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/vorgang/forwarding/ForwardingLandesnetzInfoService.java b/alfa-service/src/main/java/de/ozgcloud/alfa/vorgang/forwarding/ForwardingLandesnetzInfoService.java
index 2221f8b9ccb32f3a468b398151be6722d152a568..0f011886bd0a3faf917b2119476b283b8949e5e2 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/vorgang/forwarding/ForwardingLandesnetzInfoService.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/vorgang/forwarding/ForwardingLandesnetzInfoService.java
@@ -27,7 +27,7 @@ import java.util.Collections;
 import java.util.Objects;
 import java.util.Set;
 
-import javax.annotation.PostConstruct;
+import jakarta.annotation.PostConstruct;
 
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/vorgang/forwarding/ForwardingPasswordSizeConstraint.java b/alfa-service/src/main/java/de/ozgcloud/alfa/vorgang/forwarding/ForwardingPasswordSizeConstraint.java
index 7a09abea36f1a4233b26f4487885a884b56dbc26..5910b2d2754dead2289ec19ea5869df79d28ea31 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/vorgang/forwarding/ForwardingPasswordSizeConstraint.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/vorgang/forwarding/ForwardingPasswordSizeConstraint.java
@@ -30,8 +30,8 @@ import java.lang.annotation.Documented;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-import javax.validation.Constraint;
-import javax.validation.Payload;
+import jakarta.validation.Constraint;
+import jakarta.validation.Payload;
 
 import de.ozgcloud.alfa.common.ValidationMessageCodes;
 
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/vorgang/forwarding/ForwardingPasswordValidator.java b/alfa-service/src/main/java/de/ozgcloud/alfa/vorgang/forwarding/ForwardingPasswordValidator.java
index 30ee0e6cb971cd815b9ab4aeba9a626cfe2572c9..38ffb406bb2bd60125442acfb55734510a99fd2e 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/vorgang/forwarding/ForwardingPasswordValidator.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/vorgang/forwarding/ForwardingPasswordValidator.java
@@ -23,8 +23,8 @@
  */
 package de.ozgcloud.alfa.vorgang.forwarding;
 
-import javax.validation.ConstraintValidator;
-import javax.validation.ConstraintValidatorContext;
+import jakarta.validation.ConstraintValidator;
+import jakarta.validation.ConstraintValidatorContext;
 
 import org.apache.commons.lang3.ArrayUtils;
 import org.apache.commons.lang3.StringUtils;
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/vorgang/forwarding/RedirectRequest.java b/alfa-service/src/main/java/de/ozgcloud/alfa/vorgang/forwarding/RedirectRequest.java
index 832f4b088c63a02a1f7d8a3eb5a10ad1a0489d1a..8ffde941d1a0a2f2747f5eace6246448131c43b0 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/vorgang/forwarding/RedirectRequest.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/vorgang/forwarding/RedirectRequest.java
@@ -25,8 +25,8 @@ package de.ozgcloud.alfa.vorgang.forwarding;
 
 import static de.ozgcloud.alfa.common.ValidationMessageCodes.*;
 
-import javax.validation.constraints.Email;
-import javax.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.Email;
+import jakarta.validation.constraints.NotEmpty;
 
 import org.springframework.validation.annotation.Validated;
 
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/wiedervorlage/Wiedervorlage.java b/alfa-service/src/main/java/de/ozgcloud/alfa/wiedervorlage/Wiedervorlage.java
index bcb6b368af74344e0d18efe48f7bdb20a12cb6e3..08871f86e4d81489b0589e0caba54435c6a6f263 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/wiedervorlage/Wiedervorlage.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/wiedervorlage/Wiedervorlage.java
@@ -29,9 +29,9 @@ import java.time.LocalDate;
 import java.time.ZonedDateTime;
 import java.util.List;
 
-import javax.validation.constraints.FutureOrPresent;
-import javax.validation.constraints.NotNull;
-import javax.validation.constraints.Size;
+import jakarta.validation.constraints.FutureOrPresent;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
 
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonProperty;
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageCommand.java b/alfa-service/src/main/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageCommand.java
index f44964506366e8a82b60939dd1493db4393b0d79..398f2b6e0905fa5bcae4d27cc9a0703ab569a0dc 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageCommand.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageCommand.java
@@ -23,7 +23,7 @@
  */
 package de.ozgcloud.alfa.wiedervorlage;
 
-import javax.validation.Valid;
+import jakarta.validation.Valid;
 
 import com.fasterxml.jackson.annotation.JsonIgnore;
 
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageService.java b/alfa-service/src/main/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageService.java
index 9c496fa1f0b95ab94b73be62dec0d9a05a5f3fe2..660aeefbe8e6a5d1425fd04d4d3b9cedee1a6e8a 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageService.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageService.java
@@ -31,7 +31,7 @@ import java.util.Optional;
 import java.util.function.Predicate;
 import java.util.stream.Stream;
 
-import javax.validation.Valid;
+import jakarta.validation.Valid;
 
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.scheduling.annotation.Async;
diff --git a/alfa-service/src/main/resources/fop/postfach-nachrichten.xsl b/alfa-service/src/main/resources/fop/postfach-nachrichten.xsl
index b030aacd5e9d4f8127ce23fe7a65b7cf5402da04..7442f94c340789ee9a8929ce29d935df370fcac8 100644
--- a/alfa-service/src/main/resources/fop/postfach-nachrichten.xsl
+++ b/alfa-service/src/main/resources/fop/postfach-nachrichten.xsl
@@ -75,7 +75,7 @@
 	
 	<xsl:template name="nachricht">
 		
-			<fo:block font-size="11pt"  margin-bottom="2mm">
+			<fo:block font-size="11pt"  margin-bottom="2mm" linefeed-treatment="preserve">
 				<xsl:if test="isFirst='false'">
 					<fo:leader leader-pattern="rule" leader-length="175mm" rule-style="solid" rule-thickness="1pt"/>
 				</xsl:if>
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/EnvironmentControllerTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/EnvironmentControllerTest.java
index 145d1e512f80ce0538074b74fde6272c7269e12a..7ef79567ddc28f389673dc545eab8832d6f26916 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/EnvironmentControllerTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/EnvironmentControllerTest.java
@@ -29,12 +29,14 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
 
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
-import org.keycloak.adapters.springboot.KeycloakSpringBootProperties;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.ResultActions;
 import org.springframework.test.web.servlet.setup.MockMvcBuilders;
 
+import lombok.SneakyThrows;
+
 class EnvironmentControllerTest {
 
 	private final String PATH = "/api/environment";
@@ -42,7 +44,7 @@ class EnvironmentControllerTest {
 	@InjectMocks
 	private EnvironmentController controller;
 	@Mock
-	private KeycloakSpringBootProperties kcProperties;
+	private OAuth2Properties oAuth2Properties;
 
 	private MockMvc mockMvc;
 
@@ -52,22 +54,30 @@ class EnvironmentControllerTest {
 	}
 
 	@Test
-	void loadEnvironment() throws Exception {
-		mockMvc.perform(get(PATH)).andExpect(status().isOk());
+	void shouldReturnOk() throws Exception {
+		var response = doRequest();
+
+		response.andExpect(status().isOk());
 	}
 
 	@Test
 	void shouldHaveProductionTrueAsDefault() throws Exception {
-		mockMvc.perform(get(PATH)).andExpect(status().is2xxSuccessful())//
-				.andExpect(jsonPath("$.production").value(true));
+		var response = doRequest();
+
+		response.andExpect(jsonPath("$.production").value(true));
 	}
 
 	@Test
 	void shouldHaveClientId() throws Exception {
 		var client = "goofy";
+		when(oAuth2Properties.getResource()).thenReturn(client);
+		var response = doRequest();
 
-		when(kcProperties.getResource()).thenReturn(client);
+		response.andExpect(jsonPath("$.clientId").value(client));
+	}
 
-		mockMvc.perform(get(PATH)).andExpect(jsonPath("$.clientId").value(client));
+	@SneakyThrows
+	private ResultActions doRequest() {
+		return mockMvc.perform(get(PATH));
 	}
 }
\ No newline at end of file
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/JwtAuthConverterTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/JwtAuthConverterTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..273deca7fae29bbefd8ffaa6f9f1aec98e7a56af
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/JwtAuthConverterTest.java
@@ -0,0 +1,232 @@
+package de.ozgcloud.alfa;
+
+import static org.assertj.core.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.*;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.lang3.StringUtils;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Spy;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.oauth2.jwt.Jwt;
+import org.springframework.security.oauth2.jwt.JwtClaimNames;
+import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
+
+import com.thedeanda.lorem.LoremIpsum;
+
+class JwtAuthConverterTest {
+
+	@Spy
+	@InjectMocks
+	private final JwtAuthConverter converter = new JwtAuthConverter();
+	@Mock
+	private OAuth2Properties oAuth2Properties;
+
+	@DisplayName("Convert")
+	@Nested
+	class TestConvert {
+
+		@Mock
+		private Jwt jwt;
+
+		@BeforeEach
+		void mock() {
+			doReturn(StringUtils.EMPTY).when(converter).getPrincipleClaimName(any());
+			doReturn(Collections.emptySet()).when(converter).getAuthorities(any());
+		}
+
+		@Test
+		void shouldGetAuthrorities() {
+			converter.convert(jwt);
+
+			verify(converter).getAuthorities(jwt);
+		}
+
+		@Test
+		void shouldGetPrincipleClaimName() {
+			converter.convert(jwt);
+
+			verify(converter).getPrincipleClaimName(jwt);
+		}
+
+		@Test
+		void shouldReturnJwtAuthenticationToken() {
+			var token = converter.convert(jwt);
+
+			assertThat(token).isInstanceOf(JwtAuthenticationToken.class);
+		}
+	}
+
+	@DisplayName("Get principle claim name")
+	@Nested
+	class TestGetPrincipleClaimName {
+
+		private final String subClaimValue = LoremIpsum.getInstance().getWords(1);
+		private final String principleClaimKey = LoremIpsum.getInstance().getWords(1);
+		private final String principleClaimValue = LoremIpsum.getInstance().getWords(1);
+		private final Map<String, Object> claimMap = Map.of(JwtClaimNames.SUB, subClaimValue, principleClaimKey, principleClaimValue);
+		private final Jwt jwt = JwtTestFactory.create(claimMap);
+
+		@DisplayName("if principle attribute is set")
+		@Nested
+		class TestIfPrincipleAttributeIsSet {
+
+			@BeforeEach
+			void mock() {
+				when(oAuth2Properties.getPrincipleAttribute()).thenReturn(null);
+			}
+
+			@Test
+			void shouleReturnPrincipleAttributeClaimValue() {
+				var principleClaimName = converter.getPrincipleClaimName(jwt);
+
+				assertThat(principleClaimName).isEqualTo(subClaimValue);
+			}
+		}
+
+		@DisplayName("if principle attribute is not set")
+		@Nested
+		class TestIfPrincipleAttributeNotSet {
+
+			@BeforeEach
+			void mock() {
+				when(oAuth2Properties.getPrincipleAttribute()).thenReturn(principleClaimKey);
+			}
+
+			@Test
+			void shouldReturnSubClaimValue() {
+				var principleClaimName = converter.getPrincipleClaimName(jwt);
+
+				assertThat(principleClaimName).isEqualTo(principleClaimValue);
+			}
+		}
+	}
+
+	@DisplayName("Get authorities")
+	@Nested
+	class TestGetAuthorities {
+
+		private final static String SCOPE_CLAIM_KEY = "scope";
+		private final static String SCOPE_CLAIM_VALUE = "dummyClaimValue";
+		private final Jwt jwt = JwtTestFactory.create(Map.of(SCOPE_CLAIM_KEY, SCOPE_CLAIM_VALUE));
+
+		@BeforeEach
+		void mock() {
+			doReturn(Collections.emptyList()).when(converter).extractResourceRoles(any());
+		}
+
+		@Test
+		void shouldConvertJwt() {
+			var authorities = converter.getAuthorities(jwt);
+
+			assertThat(authorities).extracting(GrantedAuthority::toString)
+					.contains(String.format("%s_%s", SCOPE_CLAIM_KEY.toUpperCase(), SCOPE_CLAIM_VALUE));
+		}
+
+		@Test
+		void shouldExtractRoles() {
+			converter.getAuthorities(jwt);
+
+			verify(converter).extractResourceRoles(jwt);
+		}
+	}
+
+	@DisplayName("Extract resource roles")
+	@Nested
+	class TestExtractResourceRoles {
+
+		private final Map<String, Object> claimsMap = Map.of(JwtAuthConverter.RESOURCE_ACCESS_KEY, Map.of("dummyKey", "dummyValue"));
+		private final Jwt jwt = JwtTestFactory.create(claimsMap);
+
+		@Test
+		void shouldReturnEmptySetOnMissingResourceAccess() {
+			var claimsMap = Map.<String, Object>of(JwtAuthConverter.RESOURCE_ACCESS_KEY, Collections.emptyMap());
+			var jwt = JwtTestFactory.create(claimsMap);
+
+			var resourceRoles = converter.extractResourceRoles(jwt);
+
+			assertThat(resourceRoles).isEmpty();
+		}
+
+		@DisplayName("on existing resource access")
+		@Nested
+		class TestOnExistingResourceAccess {
+
+			@Test
+			void shouldCallProperties() {
+				converter.extractResourceRoles(jwt);
+
+				verify(oAuth2Properties).getResource();
+			}
+
+			@Test
+			void shouldReturnEmptySetOnMissingResourceId() {
+				when(oAuth2Properties.getResource()).thenReturn(null);
+
+				var resourceRoles = converter.extractResourceRoles(jwt);
+
+				assertThat(resourceRoles).isEmpty();
+			}
+
+			@DisplayName("and existing resourceId")
+			@Nested
+			class TestAndExistingResourceId {
+
+				private final static String RESOURCE_ID = "dummyResourceId";
+				private final Map<String, Object> authoritiesMap = Map.of(JwtAuthConverter.RESOURCE_ACCESS_KEY,
+						Map.of(RESOURCE_ID, Collections.emptyMap()));
+				private final Jwt jwt = JwtTestFactory.create(authoritiesMap);
+
+				@BeforeEach
+				void mock() {
+					doReturn(Collections.emptySet()).when(converter).extractRoles(any());
+					when(oAuth2Properties.getResource()).thenReturn(RESOURCE_ID);
+				}
+
+				@Test
+				void shouldExtractRoles() {
+					converter.extractResourceRoles(jwt);
+
+					verify(converter).extractRoles(any());
+				}
+			}
+
+		}
+	}
+
+	@DisplayName("Extract roles")
+	@Nested
+	class TestExtractRoles {
+
+		@Test
+		void shouldReturnMappedRoleIfRolesExist() {
+			var authorities = converter.extractRoles(Map.of(JwtAuthConverter.ROLES_KEY, List.of("dummy")));
+
+			assertThat(authorities).extracting(SimpleGrantedAuthority::toString).containsExactly("ROLE_dummy");
+		}
+
+		@Test
+		void shouldReturnEmptySetIfNoRoleExists() {
+			var authorities = converter.extractRoles(Map.of(JwtAuthConverter.ROLES_KEY, Collections.emptyList()));
+
+			assertThat(authorities).isEmpty();
+		}
+
+		@Test
+		void shouldReturnEmptySetIfRolesEntryNotExists() {
+			var authorities = converter.extractRoles(Collections.emptyMap());
+
+			assertThat(authorities).isEmpty();
+		}
+	}
+}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/JwtTestFactory.java b/alfa-service/src/test/java/de/ozgcloud/alfa/JwtTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..b3f4ea31829b65c243d3349c2837fe29a3b18aa0
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/JwtTestFactory.java
@@ -0,0 +1,23 @@
+package de.ozgcloud.alfa;
+
+import java.time.Instant;
+import java.util.Map;
+
+import org.springframework.security.oauth2.jwt.Jwt;
+
+import com.thedeanda.lorem.LoremIpsum;
+
+public class JwtTestFactory {
+
+	public static final String TOKEN_VALUE = LoremIpsum.getInstance().getWords(1);
+	private static final Instant ISSUE_AT = Instant.now();
+	private static final Instant EXPIRES_AT = Instant.now();
+
+	public static final String DUMMY_HEADER_KEY = "dummyHeaderKey";
+	private static final String DUMMY_HEADER_VALUE = "dummyHeaderValue";
+	private static final Map<String, Object> HEADERS = Map.of(DUMMY_HEADER_KEY, DUMMY_HEADER_VALUE);
+
+	public static Jwt create(Map<String, Object> claims) {
+		return new Jwt(TOKEN_VALUE, ISSUE_AT, EXPIRES_AT, HEADERS, claims);
+	}
+}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/JwtTokenUtilTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/JwtTokenUtilTest.java
index b9105b305f4a32c1ff3820116743cd3a478903ce..3f1cec61922fc4b62939c88a165ad734fe72a023 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/JwtTokenUtilTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/JwtTokenUtilTest.java
@@ -59,7 +59,7 @@ class JwtTokenUtilTest {
 	@Mock
 	private DownloadTokenProperties downloadTokenProperties;
 
-	private static final String TOKEN_SECRET = "t0pS3cr3t";
+	private static final String TOKEN_SECRET = "t0pS3cr3t".repeat(8);
 	private static final int TOKEN_VALIDITY = 60000;
 
 	@BeforeEach
@@ -121,7 +121,7 @@ class JwtTokenUtilTest {
 
 		@Test
 		void shouldThrowExceptionOnInvalidToken() {
-			var token = buildToken(UUID.randomUUID().toString(), "invalid_token", TOKEN_VALIDITY);
+			var token = buildToken(UUID.randomUUID().toString(), "invalid_token".repeat(5), TOKEN_VALIDITY);
 
 			assertThrows(JWTVerificationException.class, () -> jwtTokenUtil.verifyToken(token));
 		}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/RequestIdFilterTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/RequestIdFilterTest.java
index bfaf794ff0962158e404c7af8d1f89720bc384a4..fbcb5735ea29412d836659128ecbcb8505f35fa5 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/RequestIdFilterTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/RequestIdFilterTest.java
@@ -29,10 +29,10 @@ import static org.mockito.Mockito.*;
 
 import java.io.IOException;
 
-import javax.servlet.FilterChain;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 
 import org.junit.jupiter.api.Test;
 import org.mockito.InjectMocks;
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/common/GermanDateTimeFormatterTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/common/GermanDateTimeFormatterTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..0c4b738d8cefe6f0d736c870827df8c44d7d6ded
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/common/GermanDateTimeFormatterTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2022 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.alfa.common;
+
+import static org.assertj.core.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.util.stream.Stream;
+
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+
+class GermanDateTimeFormatterTest {
+
+	@Mock
+	private SystemProperties properties;
+
+	@InjectMocks
+	private GermanDateTimeFormatter germanDateTimeFormatter;
+
+	@ParameterizedTest
+	@MethodSource("provideDataForFormatZonedDateTime")
+	void shouldFormatZonedDateTime(ZonedDateTime date, String zoneId, String expected) {
+		when(properties.getTimeZone()).thenReturn(ZoneId.of(zoneId));
+
+		assertThat(germanDateTimeFormatter.formatZonedDateTime(date)).isEqualTo(expected);
+	}
+
+	private static Stream<Arguments> provideDataForFormatZonedDateTime() {
+		return Stream.of(
+				Arguments.of(zonedDateTime(2023, 9, 25, 10, "UTC"), "Europe/Berlin", "25.09.2023 12:00:00 MESZ"),
+				Arguments.of(zonedDateTime(2023, 9, 25, 23, "UTC"), "Europe/Berlin", "26.09.2023 01:00:00 MESZ"),
+				Arguments.of(zonedDateTime(2023, 12, 1, 10, "UTC"), "Europe/Berlin", "01.12.2023 11:00:00 MEZ"),
+				Arguments.of(zonedDateTime(2023, 9, 25, 10, "UTC"), "America/Los_Angeles", "25.09.2023 03:00:00 PDT"),
+				Arguments.of(zonedDateTime(2023, 9, 25, 4, "UTC"), "America/Los_Angeles", "24.09.2023 21:00:00 PDT"),
+				Arguments.of(zonedDateTime(2023, 12, 1, 10, "UTC"), "America/Los_Angeles", "01.12.2023 02:00:00 PST"),
+				Arguments.of(zonedDateTime(2023, 12, 1, 10, "America/Los_Angeles"), "Europe/Berlin", "01.12.2023 19:00:00 MEZ")
+		);
+	}
+
+	private static ZonedDateTime zonedDateTime(int year, int month, int dayOfMonth, int hour, String zoneID) {
+		return ZonedDateTime.of(year, month, dayOfMonth, hour, 0, 0, 0, ZoneId.of(zoneID));
+	}
+}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/common/binaryfile/BinaryFileControllerITCase.java b/alfa-service/src/test/java/de/ozgcloud/alfa/common/binaryfile/BinaryFileControllerITCase.java
index e3a8457b6e01b8680b547ed55596152657b3afa6..b83901c79d420a68c3ebd4741782e0f22b0c7a36 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/common/binaryfile/BinaryFileControllerITCase.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/common/binaryfile/BinaryFileControllerITCase.java
@@ -26,6 +26,7 @@ package de.ozgcloud.alfa.common.binaryfile;
 import static de.ozgcloud.alfa.JwtTokenUtil.*;
 import static org.mockito.ArgumentMatchers.*;
 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.*;
 
@@ -112,7 +113,8 @@ class BinaryFileControllerITCase {
 		}
 
 		void setTokenToSecuriyContext(String token) throws Exception {
-			mockMvc.perform(get(DownloadTokenController.DOWNLOAD_TOKEN_PATH + "?" + DownloadTokenController.PARAM_TOKEN + "=" + token))
+			mockMvc.perform(get(DownloadTokenController.DOWNLOAD_TOKEN_PATH + "?" + DownloadTokenController.PARAM_TOKEN + "=" + token)
+					.with(csrf()))
 					.andExpect(status().isOk());
 		}
 	}
@@ -130,10 +132,10 @@ class BinaryFileControllerITCase {
 		}
 
 		@Test
-		void shouldGet401WhenUnautorised() throws Exception {
+		void shouldGet403WhenUnautorised() throws Exception {
 			when(authentication.isAuthenticated()).thenReturn(Boolean.FALSE);
 
-			performRequest().andExpect(status().isUnauthorized());
+			performRequest().andExpect(status().isForbidden());
 		}
 
 		@Test
@@ -145,7 +147,7 @@ class BinaryFileControllerITCase {
 	}
 
 	ResultActions performRequest() throws Exception {
-		return mockMvc.perform(get(BinaryFileController.PATH + "/" + fileId.toString()));
+		return mockMvc.perform(get(BinaryFileController.PATH + "/" + fileId.toString()).with(csrf()));
 	}
 
 }
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/common/binaryfile/BinaryFileITCase.java b/alfa-service/src/test/java/de/ozgcloud/alfa/common/binaryfile/BinaryFileITCase.java
index 5d090e6c206eb25921d3bec103a9da73aa23eb3c..6a10133bb7a092eeae2289d4fe9002a4f608820c 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/common/binaryfile/BinaryFileITCase.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/common/binaryfile/BinaryFileITCase.java
@@ -25,6 +25,7 @@ package de.ozgcloud.alfa.common.binaryfile;
 
 import static org.mockito.ArgumentMatchers.*;
 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.*;
 
@@ -116,7 +117,7 @@ class BinaryFileITCase {
 		}
 
 		private ResultActions callEndpoint(MockMultipartFile file, String field) throws Exception {
-			return mockMvc.perform(multipart(SINGLE_PATH, VorgangHeaderTestFactory.ID, field).file(file));
+			return mockMvc.perform(multipart(SINGLE_PATH, VorgangHeaderTestFactory.ID, field).file(file).with(csrf()));
 		}
 	}
 }
\ No newline at end of file
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/common/binaryfile/DownloadAuthenticationHandlerTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/common/binaryfile/DownloadAuthenticationHandlerTest.java
index 155ac009c8fc0b9604f993dd188a71fde2ed1355..d9cc748ca8211b95706ca0ad8af73fea013a1693 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/common/binaryfile/DownloadAuthenticationHandlerTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/common/binaryfile/DownloadAuthenticationHandlerTest.java
@@ -29,9 +29,10 @@ 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.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
+import org.mockito.Mock;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 import org.springframework.security.core.Authentication;
+import org.springframework.security.oauth2.jwt.Jwt;
 
 class DownloadAuthenticationHandlerTest {
 
@@ -40,18 +41,22 @@ class DownloadAuthenticationHandlerTest {
 	@Nested
 	class TestAuthorizationKeycloak {
 
+		@Mock
+		private Jwt jwt;
+
 		private Authentication authentication = mock(Authentication.class);
 
 		@BeforeEach
 		void init() {
 			when(authentication.isAuthenticated()).thenReturn(Boolean.TRUE);
-			KeycloakAuthenticationToken keycloakToken = mock(KeycloakAuthenticationToken.class);
-			when(authentication.getPrincipal()).thenReturn(keycloakToken);
+			when(authentication.getPrincipal()).thenReturn(jwt);
 		}
 
 		@Test
 		void shouldAuthenticate() {
-			assertThat(downloadAuthorizationHandler.check(FileId.createNew(), authentication)).isTrue();
+			var check = downloadAuthorizationHandler.check(FileId.createNew(), authentication);
+
+			assertThat(check).isTrue();
 		}
 	}
 
@@ -69,23 +74,32 @@ class DownloadAuthenticationHandlerTest {
 
 		@Test
 		void shouldAuthenticate() {
-			assertThat(downloadAuthorizationHandler.check(fileId, authentication)).isTrue();
+			var check = downloadAuthorizationHandler.check(fileId, authentication);
+
+			assertThat(check).isTrue();
 		}
 
 		@Test
 		void shouldNotAuthenticateWrongFileId() {
-			assertThat(downloadAuthorizationHandler.check(FileId.createNew(), authentication)).isFalse();
+			var check = downloadAuthorizationHandler.check(FileId.createNew(), authentication);
+
+			assertThat(check).isFalse();
 		}
 
 		@Test
 		void shouldNotAuthenticateNoFileId() {
-			assertThat(downloadAuthorizationHandler.check(null, authentication)).isFalse();
+			var check = downloadAuthorizationHandler.check(null, authentication);
+
+			assertThat(check).isFalse();
 		}
 
 		@Test
 		void shouldNotAuthenticate() {
 			when(authentication.isAuthenticated()).thenReturn(Boolean.FALSE);
-			assertThat(downloadAuthorizationHandler.check(fileId, authentication)).isFalse();
+
+			var check = downloadAuthorizationHandler.check(fileId, authentication);
+
+			assertThat(check).isFalse();
 		}
 	}
 }
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/common/binaryfile/UploadBinaryFileSizeValidatorTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/common/binaryfile/UploadBinaryFileSizeValidatorTest.java
index 4ffb8a1e0758d81027e2160f48c8617b3d187a75..ad74b10d3b54551e3cf1171d5e1093f1148957e1 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/common/binaryfile/UploadBinaryFileSizeValidatorTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/common/binaryfile/UploadBinaryFileSizeValidatorTest.java
@@ -30,7 +30,7 @@ import static org.mockito.Mockito.*;
 import java.util.Collections;
 import java.util.Map;
 
-import javax.validation.ConstraintValidatorContext;
+import jakarta.validation.ConstraintValidatorContext;
 
 import org.hibernate.validator.constraintvalidation.HibernateConstraintValidatorContext;
 import org.junit.jupiter.api.BeforeEach;
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/common/command/CommandITCase.java b/alfa-service/src/test/java/de/ozgcloud/alfa/common/command/CommandITCase.java
index 6720703ad4c10512df430355ae65a52841d97e7e..301aa043ce57a76ace03a859b7e79b7c3be90f8a 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/common/command/CommandITCase.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/common/command/CommandITCase.java
@@ -26,6 +26,7 @@ package de.ozgcloud.alfa.common.command;
 import static org.assertj.core.api.Assertions.*;
 import static org.mockito.ArgumentMatchers.*;
 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.*;
 
@@ -88,7 +89,7 @@ public class CommandITCase {
 		}
 
 		private void createCommand() throws Exception {
-			mockMvc.perform(post(buildUrl()).content(createContent()).contentType(MediaType.APPLICATION_JSON))
+			mockMvc.perform(post(buildUrl()).with(csrf()).content(createContent()).contentType(MediaType.APPLICATION_JSON))
 					.andExpect(status().isCreated());
 		}
 
@@ -298,6 +299,7 @@ public class CommandITCase {
 		ResultActions doRequest(String content) throws Exception {
 			return mockMvc.perform(post("/api/vorgangs/" + CommandTestFactory.VORGANG_ID + "/relations/" + CommandTestFactory.RELATION_ID + "/"
 					+ CommandTestFactory.RELATION_VERSION + "/commands")
+							.with(csrf())
 							.contentType(MediaType.APPLICATION_JSON)
 							.content(content));
 		}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/common/command/RequiredOrderValidatorTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/common/command/RequiredOrderValidatorTest.java
index 58c1d44963fd8fa89d42943b42b601ae900550b5..6319e02a44ff12556ba1c5be98143fb13476d430 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/common/command/RequiredOrderValidatorTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/common/command/RequiredOrderValidatorTest.java
@@ -3,7 +3,7 @@ package de.ozgcloud.alfa.common.command;
 import static org.assertj.core.api.Assertions.*;
 import static org.mockito.Mockito.*;
 
-import javax.validation.ConstraintValidatorContext;
+import jakarta.validation.ConstraintValidatorContext;
 
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Nested;
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/common/downloadtoken/DownloadTokenAuthenticationFilterITCase.java b/alfa-service/src/test/java/de/ozgcloud/alfa/common/downloadtoken/DownloadTokenAuthenticationFilterITCase.java
index d4754cd7b9f14b02c81f64b645509b9404e9f8d2..d2647b285fc74570cee9c0448eae40b7c37f13ab 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/common/downloadtoken/DownloadTokenAuthenticationFilterITCase.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/common/downloadtoken/DownloadTokenAuthenticationFilterITCase.java
@@ -81,7 +81,7 @@ class DownloadTokenAuthenticationFilterITCase {
 
 	@Test
 	void shouldReturnUnauthorised() throws Exception {
-		String token = DownloadTokenTestFactory.createToken("badSecret", downloadTokenProperties.getValidity());
+		String token = DownloadTokenTestFactory.createToken("badSecret".repeat(8), downloadTokenProperties.getValidity());
 
 		performRequest(DownloadTokenController.DOWNLOAD_TOKEN_PATH + "?" + DownloadTokenController.PARAM_TOKEN + "=" + token)
 				.andExpect(status().isUnauthorized());
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/common/downloadtoken/DownloadTokenAuthenticationFilterTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/common/downloadtoken/DownloadTokenAuthenticationFilterTest.java
index 4a8a712a21b6fad31ecd2a78ca3b68042946ed02..1d3e7c76ea1c13c1364338baf4d0839c39b7c223 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/common/downloadtoken/DownloadTokenAuthenticationFilterTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/common/downloadtoken/DownloadTokenAuthenticationFilterTest.java
@@ -29,10 +29,10 @@ import static org.mockito.Mockito.*;
 import java.io.IOException;
 import java.util.UUID;
 
-import javax.servlet.FilterChain;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Nested;
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/common/downloadtoken/DownloadTokenServiceTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/common/downloadtoken/DownloadTokenServiceTest.java
index b8fa3484dac7c506414fc628c6682dffdddef280..24bf8ab7f626e0e52f8d6a89b164e3dccb2e7934 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/common/downloadtoken/DownloadTokenServiceTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/common/downloadtoken/DownloadTokenServiceTest.java
@@ -33,8 +33,8 @@ import java.util.Collection;
 import java.util.List;
 import java.util.Optional;
 
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Nested;
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/common/errorhandling/ExceptionControllerTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/common/errorhandling/ExceptionControllerTest.java
index 376bfbc299b60769cfe5231ce72b01ef67133d79..53fcd7d7e86047df2a8a4450c903de8c652bcb19 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/common/errorhandling/ExceptionControllerTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/common/errorhandling/ExceptionControllerTest.java
@@ -29,7 +29,7 @@ import static org.mockito.Mockito.*;
 import java.util.Collections;
 import java.util.Map;
 
-import javax.validation.ConstraintViolationException;
+import jakarta.validation.ConstraintViolationException;
 
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.DisplayName;
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/common/errorhandling/ExceptionTestFactory.java b/alfa-service/src/test/java/de/ozgcloud/alfa/common/errorhandling/ExceptionTestFactory.java
index 3f3af3bc7782ad9930753a12d7ab7c3a6d6c52e1..d96c42787390b1b99df6bd412efce278c3dd7335 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/common/errorhandling/ExceptionTestFactory.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/common/errorhandling/ExceptionTestFactory.java
@@ -29,9 +29,9 @@ import static org.mockito.Mockito.*;
 import java.util.Map;
 import java.util.UUID;
 
-import javax.validation.ConstraintViolation;
-import javax.validation.Path;
-import javax.validation.metadata.ConstraintDescriptor;
+import jakarta.validation.ConstraintViolation;
+import jakarta.validation.Path;
+import jakarta.validation.metadata.ConstraintDescriptor;
 
 import org.hibernate.validator.engine.HibernateConstraintViolation;
 
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/common/user/CurrentUserHelperTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/common/user/CurrentUserHelperTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..c3ceac882e23c0f86a8dfb20d11131808060ab4a
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/common/user/CurrentUserHelperTest.java
@@ -0,0 +1,40 @@
+package de.ozgcloud.alfa.common.user;
+
+import static org.assertj.core.api.Assertions.*;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+
+class CurrentUserHelperTest {
+
+	@DisplayName("Prepare role for check")
+	@Nested
+	class TestPrepareRoleForCheck {
+
+		@Test
+		void shouldAddPrefixIfMissing() {
+			var roleWithoutPrefix = UserRole.VERWALTUNG_USER;
+
+			var role = CurrentUserHelper.prepareRoleForCheck(roleWithoutPrefix);
+
+			assertThat(role).isEqualTo(String.format("%s%s", CurrentUserHelper.ROLE_PREFIX, UserRole.VERWALTUNG_USER));
+		}
+
+		@Test
+		void shouldReturnRoleIfPrefixAlreadyExists() {
+			var roleWithPrefix = String.format("ROLE_%s", UserRole.VERWALTUNG_USER);
+
+			var role = CurrentUserHelper.prepareRoleForCheck(roleWithPrefix);
+
+			assertThat(role).isEqualTo(roleWithPrefix);
+		}
+
+		@Test
+		void shouldReturnPassingRoleIfNonNull() {
+			var role = CurrentUserHelper.prepareRoleForCheck(null);
+
+			assertThat(role).isNull();
+		}
+	}
+}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/common/user/CurrentUserServiceTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/common/user/CurrentUserServiceTest.java
index f22c42b6cb253d3b2a1956e9f741d1aaa7c6a076..e363dc185c06592f6e7e11e35f25c131bd6a83d6 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/common/user/CurrentUserServiceTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/common/user/CurrentUserServiceTest.java
@@ -32,10 +32,14 @@ import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 
+import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
-import org.keycloak.representations.AccessToken;
+import org.mockito.Mock;
 import org.mockito.Spy;
+import org.springframework.security.oauth2.jwt.Jwt;
+
+import de.ozgcloud.alfa.JwtTestFactory;
 
 class CurrentUserServiceTest {
 
@@ -45,34 +49,39 @@ class CurrentUserServiceTest {
 	@Nested
 	class TestGetOrganisationseinheit {
 
+		@Mock
+		private Jwt jwt;
+
 		@Test
 		void shouldReturnOrganisationseinheitIdsFromMap() {
-			Map<String, Object> claims = Map.of(CurrentUserService.USER_ATTRIBUTE_ORGANISATIONSEINHEIT_ID, List.of("1", "2"));
+			when(jwt.getClaim(CurrentUserService.USER_ATTRIBUTE_ORGANISATIONSEINHEIT_ID)).thenReturn(List.of("1", "2"));
 
-			var result = service.getOrganisationseinheitId(claims);
+			var result = service.getOrganisationsEinheitIds(jwt);
 
-			assertThat(result).contains("1").contains("2");
+			assertThat(result).containsExactly("1", "2");
 		}
 
 		@Test
 		void shouldReturnOrgaIdAsString() {
-			var result = service.getOrganisationseinheitId(Map.of(CurrentUserService.USER_ATTRIBUTE_ORGANISATIONSEINHEIT_ID, List.of("1", 2)));
+			when(jwt.getClaim(CurrentUserService.USER_ATTRIBUTE_ORGANISATIONSEINHEIT_ID)).thenReturn(List.of("1", 2));
+
+			var result = service.getOrganisationsEinheitIds(jwt);
 
-			assertThat(result).contains("1").contains("2");
+			assertThat(result).containsExactly("1", "2");
 		}
 
 		@Test
 		void shouldReturnEmptyList() {
-			Map<String, Object> claims = Map.of(CurrentUserService.USER_ATTRIBUTE_ORGANISATIONSEINHEIT_ID, Collections.emptyList());
+			when(jwt.getClaim(CurrentUserService.USER_ATTRIBUTE_ORGANISATIONSEINHEIT_ID)).thenReturn(Collections.emptyList());
 
-			var result = service.getOrganisationseinheitId(claims);
+			var result = service.getOrganisationsEinheitIds(jwt);
 
 			assertThat(result).isEmpty();
 		}
 
 		@Test
 		void shouldReturnEmptyListIfNotExists() {
-			var result = service.getOrganisationseinheitId(Collections.emptyMap());
+			var result = service.getOrganisationsEinheitIds(null);
 
 			assertThat(result).isEmpty();
 		}
@@ -80,6 +89,7 @@ class CurrentUserServiceTest {
 
 	@Nested
 	class TestGetUserId {
+
 		@Test
 		void shouldReturnValueFromClaim() {
 			doReturn(Optional.of(UserProfileTestFactory.ID.toString())).when(service).getSingleClaimValue(any());
@@ -90,31 +100,43 @@ class CurrentUserServiceTest {
 		}
 	}
 
+	@DisplayName("Get single claim value")
 	@Nested
 	class TestGetSingleClaimValue {
 
-		private static final String ATTRIBUTE_NAME = "userId";
-		private static final String ATTRIBUTE_VALUE = "deadbeef";
+		@DisplayName("on existing claim")
+		@Nested
+		class TestOnExistingClaim {
 
-		@Test
-		void shouldReturnUserAttribute() {
-			var token = new AccessToken();
-			token.setOtherClaims(ATTRIBUTE_NAME, ATTRIBUTE_VALUE);
-			doReturn(Optional.of(token)).when(service).getCurrentSecurityToken();
+			private static final String ATTRIBUTE_NAME = "userId";
+			private static final String ATTRIBUTE_VALUE = "deadbeef";
+			private static final Map<String, Object> CLAIMS = Map.of(ATTRIBUTE_NAME, ATTRIBUTE_VALUE);
 
-			var attribute = service.getSingleClaimValue(ATTRIBUTE_NAME);
+			@Test
+			void shouldReturnUserAttribute() {
+				doReturn(Optional.of(JwtTestFactory.create(CLAIMS))).when(service).getCurrentSecurityToken();
 
-			assertThat(attribute).isPresent().hasValue(ATTRIBUTE_VALUE);
+				var attribute = service.getSingleClaimValue(ATTRIBUTE_NAME);
+
+				assertThat(attribute).isPresent().hasValue(ATTRIBUTE_VALUE);
+			}
 		}
 
-		@Test
-		void shouldReturnEmpty() {
-			var token = new AccessToken();
-			doReturn(Optional.of(token)).when(service).getCurrentSecurityToken();
+		@DisplayName("on missing claim")
+		@Nested
+		class TestOnMissingClaim {
+
+			private static final String ATTRIBUTE_NAME = "non_existing_claim";
+			private static final Map<String, Object> CLAIMS = Collections.<String, Object>singletonMap("dummyClaim", "DummyClaimValue");
+
+			@Test
+			void shouldReturnEmpty() {
+				doReturn(Optional.of(JwtTestFactory.create(CLAIMS))).when(service).getCurrentSecurityToken();
 
-			var attribute = service.getSingleClaimValue(ATTRIBUTE_NAME);
+				var attribute = service.getSingleClaimValue(ATTRIBUTE_NAME);
 
-			assertThat(attribute).isEmpty();
+				assertThat(attribute).isEmpty();
+			}
 		}
 	}
 }
\ No newline at end of file
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/kommentar/KommentarCommandITCase.java b/alfa-service/src/test/java/de/ozgcloud/alfa/kommentar/KommentarCommandITCase.java
index deff95fefd19822253e20a1cd819b4bb594af93d..426a7478778d7515642180f96a63bfcbd775db45 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/kommentar/KommentarCommandITCase.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/kommentar/KommentarCommandITCase.java
@@ -26,6 +26,7 @@ package de.ozgcloud.alfa.kommentar;
 import static de.ozgcloud.alfa.kommentar.KommentarCommandTestFactory.*;
 import static org.mockito.ArgumentMatchers.*;
 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.*;
 
@@ -129,9 +130,10 @@ class KommentarCommandITCase {
 		}
 
 		private ResultActions doRequestByKommentarId(String content) throws Exception {
-			return mockMvc.perform(post(KommentarCommandController.KOMMENTAR_COMMANDS, KommentarTestFactory.ID, KommentarTestFactory.VERSION)
-					.contentType(MediaType.APPLICATION_JSON)
-					.content(content));
+			return mockMvc
+					.perform(post(KommentarCommandController.KOMMENTAR_COMMANDS, KommentarTestFactory.ID, KommentarTestFactory.VERSION).with(csrf())
+							.contentType(MediaType.APPLICATION_JSON)
+							.content(content));
 		}
 	}
 
@@ -145,7 +147,7 @@ class KommentarCommandITCase {
 		void initTest() {
 			when(remoteService.getById(any())).thenReturn(KommentarTestFactory.create());
 			when(commandRemoteService.createCommand(any())).thenReturn(CommandTestFactory.create());
-			
+
 			doReturn(UserProfileTestFactory.ID).when(userService).getUserId();
 		}
 
@@ -201,7 +203,7 @@ class KommentarCommandITCase {
 
 		private ResultActions doRequestByVorgangId(String content) throws Exception {
 			return mockMvc.perform(post(KommentarCommandByVorgangController.KOMMENTAR_COMMANDS_BY_VORGANG, VorgangHeaderTestFactory.ID,
-					RELATION_ID_ON_CREATE)
+					RELATION_ID_ON_CREATE).with(csrf())
 							.contentType(MediaType.APPLICATION_JSON)
 							.content(content));
 		}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungCommandControllerITCase.java b/alfa-service/src/test/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungCommandControllerITCase.java
index 4ab04b7ef7a132ff4be843f5a8dacf7291e3ebbf..ad33e02b65e595b745d94a65b9f1ede29f7449fe 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungCommandControllerITCase.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungCommandControllerITCase.java
@@ -2,6 +2,7 @@ package de.ozgcloud.alfa.loeschanforderung;
 
 import static org.mockito.ArgumentMatchers.*;
 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.*;
 
@@ -124,6 +125,7 @@ class LoeschAnforderungCommandControllerITCase {
 				commandOrder.name());
 
 		return mockMvc.perform(post(LoeschAnforderungCommandController.BASE_PATH, LoeschAnforderungTestFactory.ID)
+				.with(csrf())
 				.content(requestBody).contentType(MediaType.APPLICATION_JSON).characterEncoding(StandardCharsets.UTF_8.name()));
 	}
 }
\ No newline at end of file
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/postfach/PostfachNachrichtPdfServiceITCase.java b/alfa-service/src/test/java/de/ozgcloud/alfa/postfach/PostfachNachrichtPdfServiceITCase.java
index 6788d51ca049d5cbf99a15cfcc6c3670f0857ce1..74d9ef6eda8bc319a8fd7dabdfad2065bbb0d109 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/postfach/PostfachNachrichtPdfServiceITCase.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/postfach/PostfachNachrichtPdfServiceITCase.java
@@ -30,6 +30,8 @@ import static org.mockito.Mockito.*;
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.OutputStream;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
 import java.util.Collections;
 import java.util.List;
 import java.util.stream.Stream;
@@ -45,6 +47,7 @@ import org.springframework.boot.test.mock.mockito.MockBean;
 import de.ozgcloud.alfa.common.user.UserId;
 import de.ozgcloud.alfa.common.user.UserProfileTestFactory;
 import de.ozgcloud.alfa.common.user.UserService;
+import de.ozgcloud.alfa.vorgang.AntragstellerTestFactory;
 import de.ozgcloud.alfa.vorgang.EingangTestFactory;
 import de.ozgcloud.alfa.vorgang.VorgangWithEingang;
 import de.ozgcloud.alfa.vorgang.VorgangWithEingangTestFactory;
@@ -118,6 +121,21 @@ class PostfachNachrichtPdfServiceITCase {
 		}
 	}
 
+	@DisplayName("Map Postfach-Nachricht")
+	@Nested
+	class TestMapPostfachNachricht {
+
+		private final ZonedDateTime createdAt = ZonedDateTime.of(2023, 9, 25, 10, 0, 0, 0, ZoneId.of("UTC"));
+		private final PostfachNachrichtPdfData pdfData = PostfachNachrichtPdfDataTestFactory.createBuilder().createdAt(createdAt).build();
+
+		@Test
+		void shouldMapCreatedAtWithCorrectTimezoneAndFormatting() {
+			var nachricht = service.mapPostfachNachricht(pdfData, AntragstellerTestFactory.create());
+
+			assertThat(nachricht.getCreatedAt()).isEqualTo("25.09.2023 12:00:00 MESZ");
+		}
+	}
+
 	private VorgangWithEingang buildVorgangAntragstellerNotSet() {
 		return VorgangWithEingangTestFactory.createBuilder().eingang(EingangTestFactory.createBuilder().antragsteller(null).build()).build();
 	}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/postfach/PostfachNachrichtPdfServiceTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/postfach/PostfachNachrichtPdfServiceTest.java
index 454c45619a589c2481f4ea86688ef005cbd3d83a..e470d8adc1fdde352d4baaf6e11e2a7bec5ed3b5 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/postfach/PostfachNachrichtPdfServiceTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/postfach/PostfachNachrichtPdfServiceTest.java
@@ -30,7 +30,6 @@ import static org.mockito.Mockito.*;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.time.ZonedDateTime;
 import java.util.stream.Stream;
 
 import org.apache.commons.lang3.StringUtils;
@@ -46,6 +45,7 @@ import org.springframework.test.util.ReflectionTestUtils;
 
 import de.itvsh.kop.common.errorhandling.TechnicalException;
 import de.itvsh.kop.common.pdf.PdfService;
+import de.ozgcloud.alfa.common.GermanDateTimeFormatter;
 import de.ozgcloud.alfa.common.binaryfile.BinaryFileTestFactory;
 import de.ozgcloud.alfa.common.user.UserProfileTestFactory;
 import de.ozgcloud.alfa.postfach.PostfachMail.Direction;
@@ -62,6 +62,8 @@ class PostfachNachrichtPdfServiceTest {
 	private PostfachNachrichtPdfService service;
 	@Mock
 	private PdfService pdfService;
+	@Mock
+	private GermanDateTimeFormatter germanDateTimeFormatter;
 
 	@DisplayName("Get all as pdf")
 	@Nested
@@ -239,17 +241,19 @@ class PostfachNachrichtPdfServiceTest {
 
 				@Test
 				void shouldMapNachrichtCreatedAt() {
+					var expected = "formatted date";
+					when(germanDateTimeFormatter.formatZonedDateTime(PostfachMailTestFactory.CREATED_AT)).thenReturn(expected);
+
 					var nachricht = mapNachricht();
 
-					assertThat(nachricht.getCreatedAt()).isEqualTo("01.01.2000 01:00:00 GMT");
+					assertThat(nachricht.getCreatedAt()).isEqualTo(expected);
 				}
 
 				@Test
-				void shouldFormatTimeIn24hFormat() {
-					var pdfNachricht = mapNachricht(
-							PostfachNachrichtPdfDataTestFactory.createBuilder().createdAt(ZonedDateTime.parse("2019-12-31T13:00:00Z")).build());
+				void shouldCallDateFormatter() {
+					mapNachricht();
 
-					assertThat(pdfNachricht.getCreatedAt()).isEqualTo("31.12.2019 13:00:00 GMT");
+					verify(germanDateTimeFormatter).formatZonedDateTime(PostfachMailTestFactory.CREATED_AT);
 				}
 
 				@Test
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/GrpcAntragstellerTestFactory.java b/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/GrpcAntragstellerTestFactory.java
index cf104ab5b8253e561da74e000b3f60f2131240a9..019daf75b2e632d7755af94667a76015a9bd2f0b 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/GrpcAntragstellerTestFactory.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/GrpcAntragstellerTestFactory.java
@@ -36,7 +36,7 @@ public class GrpcAntragstellerTestFactory {
 	public final static String ANREDE = "HERR/FRAU";
 	public final static String NACHNAME = LoremIpsum.getInstance().getLastName();
 	public final static String VORNAME = LoremIpsum.getInstance().getFirstName();
-	public final static String GEBURTSDATUM_STR = "1995-03-21";
+	public final static String GEBURTSDATUM_STR = "21.03.1995";
 	public final static String GEBURTSORT = LoremIpsum.getInstance().getCountry();
 	public final static String GEBURTSNAME = LoremIpsum.getInstance().getFirstName();
 	public final static String EMAIL = LoremIpsum.getInstance().getEmail();
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/VorgangControllerITCase.java b/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/VorgangControllerITCase.java
index d914ccfe173f8a2ee6c0da25e8006821482154e5..8eea6215c5ed51e9cd4d184c627a70ba5ee5a55a 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/VorgangControllerITCase.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/VorgangControllerITCase.java
@@ -25,6 +25,7 @@ package de.ozgcloud.alfa.vorgang;
 
 import static org.mockito.ArgumentMatchers.*;
 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.*;
 
@@ -52,6 +53,7 @@ import de.ozgcloud.alfa.common.attacheditem.VorgangAttachedItemTestFactory;
 import de.ozgcloud.alfa.common.clientattribute.ClientAttributeService;
 import de.ozgcloud.alfa.common.command.CommandController;
 import de.ozgcloud.alfa.common.errorhandling.ResourceNotFoundException;
+import de.ozgcloud.alfa.common.user.CurrentUserService;
 import de.ozgcloud.alfa.common.user.UserProfileTestFactory;
 import de.ozgcloud.alfa.common.user.UserService;
 import de.ozgcloud.alfa.postfach.PostfachMailController;
@@ -81,29 +83,23 @@ class VorgangControllerITCase {
 	@MockBean
 	private VorgangAttachedItemService vorgangAttachedItemService;
 
-	@Autowired
-	private MockMvc mockMvc;
-
+	@MockBean
+	private CurrentUserService currentUserService;
 	@MockBean
 	private UserService userService;
 
-	@BeforeEach
-	void prepareUserService() {
-		when(userService.getInternalId(any())).thenReturn(Optional.of(UserProfileTestFactory.INTERNAL_ID));
-	}
+	@Autowired
+	private MockMvc mockMvc;
 
 	@BeforeEach
-	void prepareStatisticController() {
+	void mock() {
+		when(currentUserService.getUser()).thenReturn(UserProfileTestFactory.create());
+		when(userService.getInternalId(any())).thenReturn(Optional.of(UserProfileTestFactory.INTERNAL_ID));
 		when(statisticController.getVorgaengeStatistic()).thenReturn(StatisticTestFactory.create());
-	}
-
-	@BeforeEach
-	void prepareVorgangAttachedItemService() {
 		when(vorgangAttachedItemService.findLoeschAnforderung(anyString())).thenReturn(Stream.of(VorgangAttachedItemTestFactory.create()));
 	}
 
 	@DisplayName("Vorganglist by page and limit")
-	@WithMockUser
 	@Nested
 	class TestVorgangListByPage {
 
@@ -119,12 +115,16 @@ class VorgangControllerITCase {
 
 		@Test
 		void shouldReturnResult() throws Exception {
-			doRequest().andExpect(jsonPath("$._embedded.vorgangHeaderList[0].nextFrist").value(WiedervorlageTestFactory.FRIST_STR));
+			var response = doRequest();
+
+			response.andExpect(jsonPath("$._embedded.vorgangHeaderList[0].nextFrist").value(WiedervorlageTestFactory.FRIST_STR));
 		}
 
 		@Test
 		void shouldReturnStatusOk() throws Exception {
-			doRequest().andExpect(status().isOk());
+			var response = doRequest();
+
+			response.andExpect(status().isOk());
 		}
 
 		private ResultActions doRequest() throws Exception {
@@ -143,43 +143,56 @@ class VorgangControllerITCase {
 
 				@Test
 				void shouldContainsNeu() throws Exception {
-					doRequest().andExpect(jsonPath(BY_STATUS_PATH + "neu").value(ByStatusTestFactory.NEU_COUNT));
+					var response = doRequest();
+
+					response.andExpect(jsonPath(BY_STATUS_PATH + "neu").value(ByStatusTestFactory.NEU_COUNT));
 				}
 
 				@Test
 				void shouldContainsAngenommen() throws Exception {
-					doRequest().andExpect(jsonPath(BY_STATUS_PATH + "angenommen").value(ByStatusTestFactory.ANGENOMMEN_COUNT));
+					var response = doRequest();
+
+					response.andExpect(jsonPath(BY_STATUS_PATH + "angenommen").value(ByStatusTestFactory.ANGENOMMEN_COUNT));
 				}
 
 				@Test
 				void shouldContainsInBearbeitung() throws Exception {
-					doRequest().andExpect(jsonPath(BY_STATUS_PATH + "inBearbeitung").value(ByStatusTestFactory.IN_BEARBEITUNG_COUNT));
+					var response = doRequest();
+
+					response.andExpect(jsonPath(BY_STATUS_PATH + "inBearbeitung").value(ByStatusTestFactory.IN_BEARBEITUNG_COUNT));
 				}
 
 				@Test
 				void shouldContainsBeschieden() throws Exception {
-					doRequest().andExpect(jsonPath(BY_STATUS_PATH + "beschieden").value(ByStatusTestFactory.BESCHIEDEN_COUNT));
+					var response = doRequest();
+
+					response.andExpect(jsonPath(BY_STATUS_PATH + "beschieden").value(ByStatusTestFactory.BESCHIEDEN_COUNT));
 				}
 
 				@Test
 				void shouldContainsAbgeschlossen() throws Exception {
-					doRequest().andExpect(jsonPath(BY_STATUS_PATH + "abgeschlossen").value(ByStatusTestFactory.ABGESCHLOSSEN_COUNT));
+					var response = doRequest();
+
+					response.andExpect(jsonPath(BY_STATUS_PATH + "abgeschlossen").value(ByStatusTestFactory.ABGESCHLOSSEN_COUNT));
 				}
 
 				@Test
 				void shouldContainsVerworfen() throws Exception {
-					doRequest().andExpect(jsonPath(BY_STATUS_PATH + "verworfen").value(ByStatusTestFactory.VERWORFEN_COUNT));
+					var response = doRequest();
+
+					response.andExpect(jsonPath(BY_STATUS_PATH + "verworfen").value(ByStatusTestFactory.VERWORFEN_COUNT));
 				}
 			}
 
 			@Test
 			void shouldContainsWiedervorlagen() throws Exception {
-				doRequest().andExpect(jsonPath("$.statistic.wiedervorlagen").value(StatisticTestFactory.COUNT_WIEDERVORLAGEN));
+				var response = doRequest();
+
+				response.andExpect(jsonPath("$.statistic.wiedervorlagen").value(StatisticTestFactory.COUNT_WIEDERVORLAGEN));
 			}
 		}
 	}
 
-	@WithMockUser
 	@Nested
 	class TestGetSingleVorgang {
 
@@ -189,26 +202,31 @@ class VorgangControllerITCase {
 		void shouldReturnNotFound() throws Exception {
 			when(remoteService.findVorgangWithEingang(anyString(), any())).thenThrow(new ResourceNotFoundException(Vorgang.class, StringUtils.EMPTY));
 
-			doRequest().andExpect(status().isNotFound());
+			var response = doRequest();
+
+			response.andExpect(status().isNotFound());
 		}
 
 		@Test
 		void shouldFormatDateTime() throws Exception {
 			when(remoteService.findVorgangWithEingang(anyString(), any())).thenReturn(VorgangWithEingangTestFactory.create());
 
-			doRequest().andExpect(status().isOk()).andExpect(jsonPath("$.createdAt").value(VorgangHeaderTestFactory.CREATED_AT_STR));
+			var response = doRequest();
+
+			response.andExpect(status().isOk()).andExpect(jsonPath("$.createdAt").value(VorgangHeaderTestFactory.CREATED_AT_STR));
 		}
 
 		@Test
 		void shouldHaveAnnehmenLink() throws Exception {
 			when(remoteService.findVorgangWithEingang(anyString(), any())).thenReturn(VorgangWithEingangTestFactory.create());
 
-			doRequest().andExpect(jsonPath("$._links.annehmen.href")
+			var response = doRequest();
+
+			response.andExpect(jsonPath("$._links.annehmen.href")
 					.value("http://localhost/api/vorgangs/" + VorgangHeaderTestFactory.ID + "/relations/" + VorgangHeaderTestFactory.ID + "/"
 							+ VorgangHeaderTestFactory.VERSION + "/commands"));
 		}
 
-		@WithMockUser
 		@Nested
 		class TestLinkToAssignedUser {
 
@@ -216,16 +234,19 @@ class VorgangControllerITCase {
 			void shouldReturnStatusOk() throws Exception {
 				when(remoteService.findVorgangWithEingang(anyString(), any())).thenReturn(VorgangWithEingangTestFactory.create());
 
-				doRequest().andExpect(status().is2xxSuccessful());
+				var response = doRequest();
+
+				response.andExpect(status().is2xxSuccessful());
 			}
 
 			@Test
 			void shouldBePresentIfAssigned() throws Exception {
 				when(remoteService.findVorgangWithEingang(anyString(), any())).thenReturn(VorgangWithEingangTestFactory.create());
 
-				doRequest()
-						.andExpect(jsonPath("$._links.assignedTo.href")
-								.value(StringEndsWith.endsWith("/api/userProfiles/" + UserProfileTestFactory.ID)));
+				var response = doRequest();
+
+				response.andExpect(jsonPath("$._links.assignedTo.href")
+						.value(StringEndsWith.endsWith("/api/userProfiles/" + UserProfileTestFactory.ID)));
 			}
 
 			@Test
@@ -233,33 +254,42 @@ class VorgangControllerITCase {
 				when(remoteService.findVorgangWithEingang(anyString(), any()))
 						.thenReturn(VorgangWithEingangTestFactory.createBuilder().assignedTo(null).build());
 
-				doRequest().andExpect(jsonPath("$._links.assignedTo.href").doesNotExist());
+				var response = doRequest();
+
+				response.andExpect(jsonPath("$._links.assignedTo.href").doesNotExist());
 			}
 		}
 
 		private ResultActions doRequest() throws Exception {
-			return mockMvc.perform(get(PATH, VorgangHeaderTestFactory.ID));
+			return mockMvc.perform(get(PATH, VorgangHeaderTestFactory.ID).with(csrf()));
 		}
 	}
 
 	@Nested
 	class TestClientAttribute {
+
 		@Test
 		void shouldReturnNoContent() throws Exception {
-			mockMvc
-					.perform(put("http://localhost/api/vorgangs/{0}/hasNewPostfachNachricht", VorgangHeaderTestFactory.ID)
-							.contentType(MediaType.APPLICATION_JSON)
-							.content("{\"hasNewPostfachNachricht\":false}"))
-					.andExpect(status().isNoContent());
+			var content = VorgangHeaderTestFactory.createHasNewPostfachNachrichtContent(false);
+
+			var response = doRequest(content);
+
+			response.andExpect(status().isNoContent());
 		}
 
 		@Test
 		void shouldReturnUnprocessableEntity() throws Exception {
-			mockMvc
-					.perform(put("http://localhost/api/vorgangs/{0}/hasNewPostfachNachricht", VorgangHeaderTestFactory.ID)
-							.contentType(MediaType.APPLICATION_JSON)
-							.content("{\"hasNewPostfachNachricht\":true}"))
-					.andExpect(status().isUnprocessableEntity());
+			var content = VorgangHeaderTestFactory.createHasNewPostfachNachrichtContent(true);
+
+			var response = doRequest(content);
+
+			response.andExpect(status().isUnprocessableEntity());
+		}
+
+		private ResultActions doRequest(String content) throws Exception {
+			return mockMvc.perform(put("/api/vorgangs/{0}/hasNewPostfachNachricht", VorgangHeaderTestFactory.ID).with(csrf())
+					.contentType(MediaType.APPLICATION_JSON)
+					.content(content));
 		}
 	}
 }
\ No newline at end of file
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/VorgangHeaderTestFactory.java b/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/VorgangHeaderTestFactory.java
index e60afed35c82377a91797c6bad99867691bff275..2eb1d65bc814907ccc77bbf9e645c64e69f9b005 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/VorgangHeaderTestFactory.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/VorgangHeaderTestFactory.java
@@ -28,6 +28,7 @@ import java.util.UUID;
 
 import com.thedeanda.lorem.LoremIpsum;
 
+import de.itvsh.kop.common.test.TestUtils;
 import de.ozgcloud.alfa.common.user.UserProfileTestFactory;
 import de.ozgcloud.alfa.vorgang.Vorgang.VorgangStatus;
 
@@ -57,4 +58,8 @@ public class VorgangHeaderTestFactory {
 				.createdAt(CREATED_AT)
 				.assignedTo(UserProfileTestFactory.ID);
 	}
+
+	public static String createHasNewPostfachNachrichtContent(boolean hasNewPostfachNachricht) {
+		return TestUtils.loadTextFile("jsonTemplates/command/hasNewPostfachNachricht.json.tmpl", String.valueOf(hasNewPostfachNachricht));
+	}
 }
\ No newline at end of file
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/forwarding/ForwardingPasswordValidatorTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/forwarding/ForwardingPasswordValidatorTest.java
index 1899552eb91bc8feb8b42996b09aacec84dbfa0b..1a5a0a2227b498f3c2360fcacaae5af12f7ac7f3 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/forwarding/ForwardingPasswordValidatorTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/forwarding/ForwardingPasswordValidatorTest.java
@@ -27,8 +27,8 @@ import static org.assertj.core.api.Assertions.*;
 import static org.mockito.ArgumentMatchers.*;
 import static org.mockito.Mockito.*;
 
-import javax.validation.ConstraintValidatorContext;
-import javax.validation.ConstraintValidatorContext.ConstraintViolationBuilder;
+import jakarta.validation.ConstraintValidatorContext;
+import jakarta.validation.ConstraintValidatorContext.ConstraintViolationBuilder;
 
 import org.apache.commons.lang3.RandomStringUtils;
 import org.apache.commons.lang3.StringUtils;
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageCommandITCase.java b/alfa-service/src/test/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageCommandITCase.java
index b2948594597319e749674a7af63ece47d55d6ffc..c47e51a4d16204d0e660a16d8f93df57b612655c 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageCommandITCase.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageCommandITCase.java
@@ -26,12 +26,13 @@ package de.ozgcloud.alfa.wiedervorlage;
 import static de.ozgcloud.alfa.wiedervorlage.WiedervorlageCommandTestFactory.*;
 import static org.mockito.ArgumentMatchers.*;
 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.*;
 
 import java.time.LocalDate;
 
-import org.assertj.core.internal.bytebuddy.utility.RandomString;
+import org.apache.commons.lang3.RandomStringUtils;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Nested;
@@ -125,7 +126,7 @@ class WiedervorlageCommandITCase {
 			@DisplayName("for 41 character in Betreff")
 			@Test
 			void createCommandWithLongBetreff() throws Exception {
-				var content = buildContentWithBetreff(RandomString.make(41));
+				var content = buildContentWithBetreff(RandomStringUtils.random(41));
 
 				doRequest(content).andExpect(status().isUnprocessableEntity());
 			}
@@ -165,6 +166,7 @@ class WiedervorlageCommandITCase {
 		private ResultActions doRequest(String content) throws Exception {
 			return mockMvc.perform(
 					post(WiedervorlageCommandController.WIEDERVORLAGE_COMMANDS, WiedervorlageTestFactory.ID, WiedervorlageTestFactory.VERSION)
+							.with(csrf())
 							.contentType(MediaType.APPLICATION_JSON)
 							.content(content));
 		}
@@ -181,7 +183,7 @@ class WiedervorlageCommandITCase {
 		void initTest() {
 			when(commandRemoteService.createCommand(any())).thenReturn(CommandTestFactory.create());
 			when(wiedervorlageRemoteService.getById(anyString())).thenReturn(WiedervorlageTestFactory.create());
-			
+
 			doReturn(UserProfileTestFactory.ID).when(userService).getUserId();
 		}
 
@@ -229,7 +231,7 @@ class WiedervorlageCommandITCase {
 			@DisplayName("for 41 character in Betreff")
 			@Test
 			void createCommandWithLongBetreff() throws Exception {
-				var content = buildContentWithBetreff(RandomString.make(41));
+				var content = buildContentWithBetreff(RandomStringUtils.random(41));
 
 				doRequest(content).andExpect(status().isUnprocessableEntity());
 			}
@@ -267,8 +269,9 @@ class WiedervorlageCommandITCase {
 		private ResultActions doRequest(String content) throws Exception {
 			return mockMvc.perform(post(WiedervorlageCommandByVorgangController.WIEDERVORLAGE_COMMANDS_BY_VORGANG, VorgangHeaderTestFactory.ID,
 					RELATION_ID_ON_CREATE)
-							.contentType(MediaType.APPLICATION_JSON)
-							.content(content));
+					.with(csrf())
+					.contentType(MediaType.APPLICATION_JSON)
+					.content(content));
 		}
 	}
 }
\ No newline at end of file
diff --git a/alfa-service/src/test/resources/application.yml b/alfa-service/src/test/resources/application.yml
index a46d7989678c79a6f2338deb269565b88e026824..90b792d47554dae05fae77dd26ed00e58bf90ed2 100644
--- a/alfa-service/src/test/resources/application.yml
+++ b/alfa-service/src/test/resources/application.yml
@@ -4,7 +4,19 @@ logging:
     '[de.itvsh]': INFO
     '[de.ozgcloud]': INFO,
     '[org.springframework.security]': WARN
-    '[org.keycloak.adapters]': WARN
+
+
+ozgcloud:
+   keycloak:
+      auth-server-url: https://sso.dev.by.ozg-cloud.de
+      realm: by-kiel-dev
+      resource: ${jwt.auth.converter.resource-id}
+      
+jwt:
+  auth:
+    converter:
+      resource-id: alfa
+      principle-attribute: preferred_username  
 
 spring:
   mvc:
@@ -19,7 +31,13 @@ spring:
     multipart:
       max-file-size: 2GB
       max-request-size: 2GB
-
+  security:
+    oauth2:
+      resourceserver:
+        jwt:
+          issuer-uri: ${ozgcloud.keycloak.auth-server-url}/realms/${ozgcloud.keycloak.realm}
+          jwk-set-uri: ${spring.security.oauth2.resourceserver.jwt.issuer-uri}/protocol/openid-connect/certs
+            
 server:
   http2:
     enabled: true
@@ -51,14 +69,7 @@ management:
 
 goofy:
   production: true
-
-keycloak:
-  auth-server-url: http://localhost:8088
-  realm: sh-kiel-dev
-  resource: sh-kiel-dev-goofy
-  public-client: true
-  use-resource-role-mappings: true
-
+    
 grpc:
   client:
     pluto:
@@ -71,7 +82,7 @@ grpc:
 kop:
   auth:
     token:
-      secret: XPPWagXn3rDwKG6Ywoir
+      secret: XPPWagXn3rDwKG6YwoirXPPWagXn3rDwKG6YwoirXPPWagXn3rDwKG6YwoirXPPWagXn3rDwKG6Ywoir
       validity: 60000
   upload:
     maxFileSize:
diff --git a/alfa-service/src/test/resources/jsonTemplates/command/hasNewPostfachNachricht.json.tmpl b/alfa-service/src/test/resources/jsonTemplates/command/hasNewPostfachNachricht.json.tmpl
new file mode 100644
index 0000000000000000000000000000000000000000..419bb5bcbb5a8951482425d305d39aa40a9dd9e0
--- /dev/null
+++ b/alfa-service/src/test/resources/jsonTemplates/command/hasNewPostfachNachricht.json.tmpl
@@ -0,0 +1,3 @@
+{
+	"hasNewPostfachNachricht": %s
+}
\ No newline at end of file
diff --git a/alfa-xdomea/pom.xml b/alfa-xdomea/pom.xml
index 63bfe4d5a9f21ab7f5d788d9dd52c41b7d5fb68b..61f04572ae58e69f87f3cb228c4682338f5942a0 100644
--- a/alfa-xdomea/pom.xml
+++ b/alfa-xdomea/pom.xml
@@ -32,7 +32,7 @@
 	<parent>
 		<groupId>de.itvsh.ozg</groupId>
 		<artifactId>goofy</artifactId>
-		<version>1.15.0-SNAPSHOT</version>
+		<version>1.16.0-SNAPSHOT</version>
 	</parent>
 
 	<artifactId>alfa-xdomea</artifactId>
@@ -43,8 +43,7 @@
 	<properties>
 		<maven.compiler.source>${java.version}</maven.compiler.source>
 		<maven.compiler.target>${java.version}</maven.compiler.target>
-		<jaxb2-maven-plugin.version>2.5.0</jaxb2-maven-plugin.version>
-		
+		<jaxb2-maven-plugin.version>3.1.0</jaxb2-maven-plugin.version>
 	</properties>
 
 	<dependencies>
diff --git a/alfa-xdomea/src/main/java/de/ozgcloud/alfa/export/DateConverter.java b/alfa-xdomea/src/main/java/de/ozgcloud/alfa/export/DateConverter.java
new file mode 100644
index 0000000000000000000000000000000000000000..b41173ea1bcc9246309dce3ca752d24dc4dbb715
--- /dev/null
+++ b/alfa-xdomea/src/main/java/de/ozgcloud/alfa/export/DateConverter.java
@@ -0,0 +1,30 @@
+package de.ozgcloud.alfa.export;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.Locale;
+import java.util.Optional;
+
+import javax.xml.datatype.DatatypeConfigurationException;
+import javax.xml.datatype.DatatypeFactory;
+import javax.xml.datatype.XMLGregorianCalendar;
+
+import org.springframework.stereotype.Component;
+
+import de.itvsh.kop.common.errorhandling.TechnicalException;
+
+@Component
+class DateConverter {
+
+	private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("dd.MM.yyyy", Locale.GERMAN);
+
+	public Optional<XMLGregorianCalendar> convertGermanFormatToISO(String dateStr) {
+		try {
+			return Optional.of(DatatypeFactory.newInstance().newXMLGregorianCalendar(LocalDate.parse(dateStr, DATE_TIME_FORMATTER).toString()));
+		} catch (DatatypeConfigurationException e) {
+			throw new TechnicalException(String.format("Error converting date %s to ISO.", dateStr), e);
+		} catch (Exception e) {
+			return Optional.empty();
+		}
+	}
+}
diff --git a/alfa-xdomea/src/main/java/de/ozgcloud/alfa/export/ExportData.java b/alfa-xdomea/src/main/java/de/ozgcloud/alfa/export/ExportData.java
new file mode 100644
index 0000000000000000000000000000000000000000..c6e4888c0865072a025a6cf2ecf2729c408dd078
--- /dev/null
+++ b/alfa-xdomea/src/main/java/de/ozgcloud/alfa/export/ExportData.java
@@ -0,0 +1,22 @@
+package de.ozgcloud.alfa.export;
+
+import java.util.stream.Stream;
+
+import de.ozgcloud.alfa.common.file.OzgFile;
+import de.ozgcloud.alfa.vorgang.VorgangWithEingang;
+import lombok.AccessLevel;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+
+@Builder
+@AllArgsConstructor(access = AccessLevel.PRIVATE)
+@Getter
+class ExportData {
+
+	private VorgangWithEingang vorgang;
+	private String exportFilename;
+	private String xmlFileContent;
+	private Stream<OzgFile> exportFiles;
+
+}
diff --git a/alfa-xdomea/src/main/java/de/ozgcloud/alfa/export/ExportFilenameGenerator.java b/alfa-xdomea/src/main/java/de/ozgcloud/alfa/export/ExportFilenameGenerator.java
new file mode 100644
index 0000000000000000000000000000000000000000..13471e6d59b8ffd385aad5532c1c9bd982172c04
--- /dev/null
+++ b/alfa-xdomea/src/main/java/de/ozgcloud/alfa/export/ExportFilenameGenerator.java
@@ -0,0 +1,17 @@
+package de.ozgcloud.alfa.export;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import de.ozgcloud.alfa.common.file.OzgFile;
+
+@Component
+class ExportFilenameGenerator {
+
+	@Autowired
+	private UUIDConverter uuidConverter;
+
+	public String generateExportFilename(OzgFile ozgFile) {
+		return String.format("%s_%s", uuidConverter.fromObjectId(ozgFile.getId().toString()), ozgFile.getName());
+	}
+}
diff --git a/alfa-xdomea/src/main/java/de/ozgcloud/alfa/export/KontaktTypeCreator.java b/alfa-xdomea/src/main/java/de/ozgcloud/alfa/export/KontaktTypeCreator.java
new file mode 100644
index 0000000000000000000000000000000000000000..0f13079a7a8acba8763844ca936ee785c27ba62e
--- /dev/null
+++ b/alfa-xdomea/src/main/java/de/ozgcloud/alfa/export/KontaktTypeCreator.java
@@ -0,0 +1,62 @@
+package de.ozgcloud.alfa.export;
+
+import java.util.Optional;
+import java.util.function.Predicate;
+
+import javax.xml.datatype.XMLGregorianCalendar;
+
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import de.ozgcloud.alfa.vorgang.Antragsteller;
+import de.ozgcloud.alfa.vorgang.VorgangWithEingang;
+import de.xoev.xdomea.GeburtType;
+import de.xoev.xdomea.KontaktType;
+
+@Component
+class KontaktTypeCreator {
+
+	private final Predicate<Antragsteller> HAS_VORNAME = antragsteller -> StringUtils.isNotBlank(antragsteller.getVorname());
+	private final Predicate<Antragsteller> HAS_NACHNAME = antragsteller -> StringUtils.isNotBlank(antragsteller.getNachname());
+	private final Predicate<Antragsteller> HAS_ANREDE = antragsteller -> StringUtils.isNotBlank(antragsteller.getAnrede());
+	private final Predicate<Antragsteller> HAS_VALID_GEBURTSDATUM = this::hasValidGeburtsdatum;
+
+	@Autowired
+	private NameNatuerlichePersonTypeCreator nameNatuerlichePersonTypeCreator;
+
+	@Autowired
+	private DateConverter dateConverter;
+
+	public Optional<KontaktType> create(VorgangWithEingang vorgang) {
+		return getAntragstellerIfHasRequiredData(vorgang).map(this::toKontaktType);
+	}
+
+	Optional<Antragsteller> getAntragstellerIfHasRequiredData(VorgangWithEingang vorgang) {
+		return Optional.ofNullable(vorgang.getEingang().getAntragsteller())
+				.filter(HAS_VORNAME.or(HAS_NACHNAME).or(HAS_ANREDE).or(HAS_VALID_GEBURTSDATUM));
+	}
+
+	KontaktType toKontaktType(Antragsteller antragsteller) {
+		var kontakt = new KontaktType();
+		kontakt.setName(nameNatuerlichePersonTypeCreator.create(antragsteller));
+		var geburtsdatumIso = dateConverter.convertGermanFormatToISO(antragsteller.getGeburtsdatum());
+		kontakt.setGeburt(createGeburtType(geburtsdatumIso));
+		return kontakt;
+	}
+
+	GeburtType createGeburtType(Optional<XMLGregorianCalendar> geburtsdatum) {
+		return geburtsdatum.map(this::createGeburtType).orElseGet(GeburtType::new);
+	}
+
+	private GeburtType createGeburtType(XMLGregorianCalendar datum) {
+		var geburtType = new GeburtType();
+		geburtType.setDatum(datum);
+		return geburtType;
+	}
+
+	private boolean hasValidGeburtsdatum(Antragsteller antragsteller) {
+		return dateConverter.convertGermanFormatToISO(antragsteller.getGeburtsdatum()).isPresent();
+	}
+
+}
diff --git a/alfa-xdomea/src/main/java/de/ozgcloud/alfa/export/NameNatuerlichePersonTypeCreator.java b/alfa-xdomea/src/main/java/de/ozgcloud/alfa/export/NameNatuerlichePersonTypeCreator.java
new file mode 100644
index 0000000000000000000000000000000000000000..285854614408573b9f9238c000e7943ed94800e9
--- /dev/null
+++ b/alfa-xdomea/src/main/java/de/ozgcloud/alfa/export/NameNatuerlichePersonTypeCreator.java
@@ -0,0 +1,30 @@
+package de.ozgcloud.alfa.export;
+
+import static java.util.Optional.*;
+
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Component;
+
+import de.ozgcloud.alfa.vorgang.Antragsteller;
+import de.xoev.xdomea.AllgemeinerNameType;
+import de.xoev.xdomea.NameNatuerlichePersonType;
+
+@Component
+class NameNatuerlichePersonTypeCreator {
+
+	public NameNatuerlichePersonType create(Antragsteller antragsteller) {
+		var nameNatuerlichPerson = new NameNatuerlichePersonType();
+		nameNatuerlichPerson.setAnrede(ofNullable(antragsteller).map(Antragsteller::getAnrede).orElse(StringUtils.EMPTY));
+		nameNatuerlichPerson.setVorname(
+				createAllgemeinerNameType(ofNullable(antragsteller).map(Antragsteller::getVorname).orElse(StringUtils.EMPTY)));
+		nameNatuerlichPerson.setFamilienname(
+				createAllgemeinerNameType(ofNullable(antragsteller).map(Antragsteller::getNachname).orElse(StringUtils.EMPTY)));
+		return nameNatuerlichPerson;
+	}
+
+	private AllgemeinerNameType createAllgemeinerNameType(String name) {
+		var allgemeinerName = new AllgemeinerNameType();
+		allgemeinerName.setName(name);
+		return allgemeinerName;
+	}
+}
diff --git a/alfa-xdomea/src/main/java/de/ozgcloud/alfa/export/PrimaerdokumentTypeCreator.java b/alfa-xdomea/src/main/java/de/ozgcloud/alfa/export/PrimaerdokumentTypeCreator.java
index d1fb7a35542796cc1cfe465edb13f9852d50fd1d..593e0ef8195aed2d85c3d8290317e80f5efadf5c 100644
--- a/alfa-xdomea/src/main/java/de/ozgcloud/alfa/export/PrimaerdokumentTypeCreator.java
+++ b/alfa-xdomea/src/main/java/de/ozgcloud/alfa/export/PrimaerdokumentTypeCreator.java
@@ -11,17 +11,13 @@ import de.xoev.xdomea.PrimaerdokumentType;
 class PrimaerdokumentTypeCreator {
 
 	@Autowired
-	private UUIDConverter uuidConverter;
+	private ExportFilenameGenerator exportFilenameGenerator;
 
 	public PrimaerdokumentType create(VorgangWithEingang vorgang, OzgFile ozgFile) {
 		var primaerdokument = new PrimaerdokumentType();
-		primaerdokument.setDateiname(createDateiname(ozgFile));
+		primaerdokument.setDateiname(exportFilenameGenerator.generateExportFilename(ozgFile));
 		primaerdokument.setDateinameOriginal(ozgFile.getName());
 		primaerdokument.setErsteller(vorgang.getEingang().getHeader().getFormEngineName());
 		return primaerdokument;
 	}
-
-	String createDateiname(OzgFile ozgFile) {
-		return String.format("%s_%s", uuidConverter.fromObjectId(ozgFile.getId().toString()), ozgFile.getName());
-	}
 }
diff --git a/alfa-xdomea/src/main/java/de/ozgcloud/alfa/export/VorgangTypeCreator.java b/alfa-xdomea/src/main/java/de/ozgcloud/alfa/export/VorgangTypeCreator.java
index 6fd299fbea09cdd2bfcbe25324412bc7cf14f930..792143b96e0074e5ffdbcd1c48a204759d8d710e 100644
--- a/alfa-xdomea/src/main/java/de/ozgcloud/alfa/export/VorgangTypeCreator.java
+++ b/alfa-xdomea/src/main/java/de/ozgcloud/alfa/export/VorgangTypeCreator.java
@@ -22,12 +22,16 @@ class VorgangTypeCreator {
 	@Autowired
 	private DokumentTypeCreator dokumentTypeCreator;
 
+	@Autowired
+	private KontaktTypeCreator kontaktTypeCreator;
+
 	public VorgangType create(VorgangWithEingang vorgangWithEingang, AnwendungsspezifischeErweiterungType erweiterung) {
 		var vorgang = new VorgangType();
 		vorgang.setAnwendungsspezifischeErweiterung(erweiterung);
 		vorgang.setIdentifikation(createIdentifikation());
 		vorgang.setAllgemeineMetadaten(createAllgemeineMetadaten(vorgangWithEingang));
 		vorgang.getDokument().addAll(dokumentTypeCreator.create(vorgangWithEingang).toList());
+		kontaktTypeCreator.create(vorgangWithEingang).ifPresent(vorgang.getKontakt()::add);
 		return vorgang;
 	}
 
diff --git a/alfa-xdomea/src/main/java/de/ozgcloud/alfa/export/XDomeaNamespacePrefixMapper.java b/alfa-xdomea/src/main/java/de/ozgcloud/alfa/export/XDomeaNamespacePrefixMapper.java
index 4730cee16db3ad6c5819946deb8e87ebc5389672..81bb3fd6a3188265b05f3d731bd096a6a78ae8b8 100644
--- a/alfa-xdomea/src/main/java/de/ozgcloud/alfa/export/XDomeaNamespacePrefixMapper.java
+++ b/alfa-xdomea/src/main/java/de/ozgcloud/alfa/export/XDomeaNamespacePrefixMapper.java
@@ -2,10 +2,9 @@ package de.ozgcloud.alfa.export;
 
 import java.util.Map;
 
+import org.glassfish.jaxb.runtime.marshaller.NamespacePrefixMapper;
 import org.springframework.stereotype.Component;
 
-import com.sun.xml.bind.marshaller.NamespacePrefixMapper;
-
 @Component
 class XDomeaNamespacePrefixMapper extends NamespacePrefixMapper {
 
diff --git a/alfa-xdomea/src/main/java/de/ozgcloud/alfa/export/XDomeaService.java b/alfa-xdomea/src/main/java/de/ozgcloud/alfa/export/XDomeaService.java
index c7012b1dd4b9d9d65186a25aaf3ceedf217864a1..ae924df290489e4851084caec61c45654da41d89 100644
--- a/alfa-xdomea/src/main/java/de/ozgcloud/alfa/export/XDomeaService.java
+++ b/alfa-xdomea/src/main/java/de/ozgcloud/alfa/export/XDomeaService.java
@@ -1,5 +1,8 @@
 package de.ozgcloud.alfa.export;
 
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.nio.charset.StandardCharsets;
@@ -10,6 +13,7 @@ import java.util.zip.ZipOutputStream;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import de.itvsh.kop.common.binaryfile.TempFileUtils;
 import de.itvsh.kop.common.errorhandling.TechnicalException;
 import de.ozgcloud.alfa.common.file.OzgFile;
 import de.ozgcloud.alfa.vorgang.VorgangController;
@@ -34,18 +38,21 @@ class XDomeaService {
 	@Autowired
 	private ExportFileService exportFileService;
 
+	@Autowired
+	private ExportFilenameGenerator exportFilenameGenerator;
+
 	public void writeExport(String vorgangId, String filenameId, OutputStream out) {
+		var exportData = collectExportData(vorgangId, filenameId);
+		var zipFile = createZipFile(exportData);
+		writeZipFileContent(zipFile, out);
+	}
+
+	ExportData collectExportData(String vorgangId, String filenameId) {
 		var vorgang = vorgangController.getVorgang(vorgangId);
-		var fileName = buildXmlFilename(filenameId);
 		var xmlContent = createXmlContent(vorgang);
+		var filename = buildXmlFilename(filenameId);
 		var ozgFiles = exportFileService.getAllPdfs(vorgang.getEingang().getId());
-
-		try (var zipOutputStream = new ZipOutputStream(out)) {
-			putZipEntry(fileName, xmlContent, zipOutputStream);
-			putFilesIntoZip(ozgFiles, zipOutputStream);
-		} catch (Exception e) {
-			throw new TechnicalException("Error creating XDomea zip file", e);
-		}
+		return ExportData.builder().vorgang(vorgang).xmlFileContent(xmlContent).exportFilename(filename).exportFiles(ozgFiles).build();
 	}
 
 	String buildXmlFilename(String filenameId) {
@@ -56,6 +63,17 @@ class XDomeaService {
 		return xDomeaXmlMarshaller.marshal(abgabeCreator.create(vorgang));
 	}
 
+	File createZipFile(ExportData exportData) {
+		var file = TempFileUtils.createTmpFile().toFile();
+		try (var zipOutputStream = new ZipOutputStream(new FileOutputStream(file))) {
+			putZipEntry(exportData.getExportFilename(), exportData.getXmlFileContent(), zipOutputStream);
+			putFilesIntoZip(exportData.getExportFiles(), zipOutputStream);
+			return file;
+		} catch (Exception e) {
+			throw new TechnicalException("Error creating XDomea zip file", e);
+		}
+	}
+
 	void putZipEntry(String fileName, String fileData, ZipOutputStream zipOutputStream) throws IOException {
 		var entry = new ZipEntry(fileName);
 		zipOutputStream.putNextEntry(entry);
@@ -70,9 +88,17 @@ class XDomeaService {
 	}
 
 	void putOzgFileIntoZip(OzgFile ozgFile, ZipOutputStream zipOutputStream) throws IOException {
-		var entry = new ZipEntry(ozgFile.getName());
+		var entry = new ZipEntry(exportFilenameGenerator.generateExportFilename(ozgFile));
 		zipOutputStream.putNextEntry(entry);
 		exportFileService.writeOzgFile(ozgFile.getId(), zipOutputStream);
 		zipOutputStream.closeEntry();
 	}
+
+	void writeZipFileContent(File file, OutputStream outputStream) {
+		try (var fileInputStream = new FileInputStream(file)) {
+			fileInputStream.transferTo(outputStream);
+		} catch (Exception e) {
+			throw new TechnicalException("Error writting XDomea zip file to output stream", e);
+		}
+	}
 }
diff --git a/alfa-xdomea/src/main/java/de/ozgcloud/alfa/export/XDomeaXmlMarshallerConfiguration.java b/alfa-xdomea/src/main/java/de/ozgcloud/alfa/export/XDomeaXmlMarshallerConfiguration.java
index 964d431c324c4e4af2a063a8dce2d2b473cab7ad..b6b8bd1a0dd4ae9d91e6a8442cb1dc9828da3e4f 100644
--- a/alfa-xdomea/src/main/java/de/ozgcloud/alfa/export/XDomeaXmlMarshallerConfiguration.java
+++ b/alfa-xdomea/src/main/java/de/ozgcloud/alfa/export/XDomeaXmlMarshallerConfiguration.java
@@ -3,7 +3,7 @@ package de.ozgcloud.alfa.export;
 import java.util.HashMap;
 import java.util.Map;
 
-import javax.xml.bind.Marshaller;
+import jakarta.xml.bind.Marshaller;
 
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Bean;
@@ -14,7 +14,7 @@ import org.springframework.oxm.jaxb.Jaxb2Marshaller;
 class XDomeaXmlMarshallerConfiguration {
 
 	static final boolean JAXB_FORMATTED_OUTPUT = true;
-	static final String PROPERTY_NAMESPACE_PREFIX_MAPPER = "com.sun.xml.bind.namespacePrefixMapper";
+	static final String PROPERTY_NAMESPACE_PREFIX_MAPPER = "org.glassfish.jaxb.namespacePrefixMapper";
 	static final String CONTEXT_PATH = "de.xoev.xdomea";
 
 	@Autowired
diff --git a/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/DateConverterTest.java b/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/DateConverterTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..c296eff263a96f41fe254f6fdfe07e8520766a16
--- /dev/null
+++ b/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/DateConverterTest.java
@@ -0,0 +1,72 @@
+package de.ozgcloud.alfa.export;
+
+import static org.assertj.core.api.Assertions.*;
+
+import java.util.Optional;
+
+import javax.xml.datatype.DatatypeConfigurationException;
+import javax.xml.datatype.DatatypeFactory;
+import javax.xml.datatype.XMLGregorianCalendar;
+
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+import org.mockito.InjectMocks;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+
+import de.itvsh.kop.common.errorhandling.TechnicalException;
+
+class DateConverterTest {
+
+	@InjectMocks
+	private DateConverter converter;
+
+	@Nested
+	class TestConvertGermanFormatToISO {
+
+		private static final int YEAR = 2023;
+		private static final int MONTH = 2;
+		private static final int DAY = 14;
+
+		private static final String DATE = String.format("%s.%s%s.%s", DAY, 0, MONTH, YEAR);
+
+		@Test
+		void shouldConvert() {
+			var converted = callConverter(DATE);
+
+			assertThat(converted).get().extracting(XMLGregorianCalendar::getYear, XMLGregorianCalendar::getMonth, XMLGregorianCalendar::getDay)
+					.containsExactly(YEAR, MONTH, DAY);
+		}
+
+		@ParameterizedTest
+		@ValueSource(strings = { "2005-10-10", "abc", "19. February 1970", " ", "" })
+		void shouldReturnEmpty(String dateStr) {
+			var converted = callConverter(dateStr);
+
+			assertThat(converted).isEmpty();
+		}
+
+		@Test
+		void shouldReturnEmptyIfDateIsNull() {
+			var converted = callConverter(null);
+
+			assertThat(converted).isEmpty();
+		}
+
+		@Test
+		void shouldThrowTechnicalException() {
+			try (MockedStatic<DatatypeFactory> datatypeFactory = Mockito.mockStatic(DatatypeFactory.class)) {
+				datatypeFactory.when(DatatypeFactory::newInstance).thenThrow(DatatypeConfigurationException.class);
+
+				assertThatThrownBy(() -> callConverter(DATE)).isInstanceOf(TechnicalException.class);
+			}
+		}
+
+		private Optional<XMLGregorianCalendar> callConverter(String dateStr) {
+			return converter.convertGermanFormatToISO(dateStr);
+		}
+	}
+
+}
\ No newline at end of file
diff --git a/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/DokumentTypeCreatorTest.java b/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/DokumentTypeCreatorTest.java
index 0bf790c21d424b1c64d84ffe28a6e076287872a6..45015d4e9a5f95dd66bf6bc57c7e4f3970067425 100644
--- a/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/DokumentTypeCreatorTest.java
+++ b/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/DokumentTypeCreatorTest.java
@@ -206,14 +206,14 @@ class DokumentTypeCreatorTest {
 		void shouldHaveKennzeichen() {
 			var allgemeineMetadaten = creator.createAllgemeineMetadaten(ozgFile);
 
-			assertThat(allgemeineMetadaten.getKennzeichen()).isEqualTo(StringUtils.EMPTY);
+			assertThat(allgemeineMetadaten.getKennzeichen()).isEmpty();
 		}
 
 		@Test
 		void shouldHaveBemerkung() {
 			var allgemeineMetadaten = creator.createAllgemeineMetadaten(ozgFile);
 
-			assertThat(allgemeineMetadaten.getBemerkung()).isEqualTo(StringUtils.EMPTY);
+			assertThat(allgemeineMetadaten.getBemerkung()).isEmpty();
 		}
 
 		@Test
diff --git a/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/ExportDataTestFactory.java b/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/ExportDataTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..2be3ee462e90de9997dff74f5b9d145cbb873256
--- /dev/null
+++ b/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/ExportDataTestFactory.java
@@ -0,0 +1,25 @@
+package de.ozgcloud.alfa.export;
+
+import java.util.stream.Stream;
+
+import de.ozgcloud.alfa.common.file.OzgFile;
+import de.ozgcloud.alfa.common.file.OzgFileTestFactory;
+import de.ozgcloud.alfa.vorgang.VorgangWithEingang;
+import de.ozgcloud.alfa.vorgang.VorgangWithEingangTestFactory;
+
+class ExportDataTestFactory {
+
+	public static final String EXPORT_FILENAME = "file.zip";
+	public static final String XML_FILE_CONTENT = "<xml></xml>";
+	public static final OzgFile OZG_FILE = OzgFileTestFactory.create();
+	public static final VorgangWithEingang VORGANG = VorgangWithEingangTestFactory.create();
+
+	public static ExportData create() {
+		return createBuilder().build();
+	}
+
+	public static ExportData.ExportDataBuilder createBuilder() {
+		return ExportData.builder().exportFilename(EXPORT_FILENAME).xmlFileContent(XML_FILE_CONTENT).vorgang(VORGANG)
+				.exportFiles(Stream.of(OZG_FILE));
+	}
+}
diff --git a/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/ExportFilenameGeneratorTest.java b/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/ExportFilenameGeneratorTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..66d6480e708665d465935f20010c1bdc5cba38f6
--- /dev/null
+++ b/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/ExportFilenameGeneratorTest.java
@@ -0,0 +1,55 @@
+package de.ozgcloud.alfa.export;
+
+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.InjectMocks;
+import org.mockito.Mock;
+
+import de.ozgcloud.alfa.common.TestUtils;
+import de.ozgcloud.alfa.common.file.OzgFile;
+import de.ozgcloud.alfa.common.file.OzgFileTestFactory;
+
+class ExportFilenameGeneratorTest {
+
+	@InjectMocks
+	private ExportFilenameGenerator generator;
+
+	@Mock
+	private UUIDConverter uuidConverter;
+
+	@Nested
+	class TestGenerateExportFilename {
+
+		private static final String UUID = "64a820d3-6285-172a-c028-0000000026d0";
+
+		private final OzgFile ozgFile = OzgFileTestFactory.create();
+
+		@BeforeEach
+		void init() {
+			when(uuidConverter.fromObjectId(ozgFile.getId().toString())).thenReturn(UUID);
+		}
+
+		@Test
+		void shouldConvertObjectId() {
+			callGenerator();
+
+			verify(uuidConverter).fromObjectId(ozgFile.getId().toString());
+		}
+
+		@Test
+		void shouldGenerate() {
+			var filename = callGenerator();
+
+			assertThat(filename).matches(String.format("^%s_%s$", TestUtils.UUID_REGEX, ozgFile.getName()));
+		}
+
+		private String callGenerator() {
+			return generator.generateExportFilename(ozgFile);
+		}
+	}
+
+}
\ No newline at end of file
diff --git a/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/FeldGruppeTypeCreatorTest.java b/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/FeldGruppeTypeCreatorTest.java
index 95027d111a4d367dcdfa559b31a28c4ceea41491..2ca1494a2bd482efb4d3fd9a3deb931ad8ec1b8b 100644
--- a/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/FeldGruppeTypeCreatorTest.java
+++ b/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/FeldGruppeTypeCreatorTest.java
@@ -205,7 +205,7 @@ class FeldGruppeTypeCreatorTest {
 			void shouldBeEmptyStringForNullEingang() {
 				var created = create(VorgangWithEingangTestFactory.createBuilder().eingang(null).build());
 
-				assertThat(created).extracting(FeldType::getWert).isEqualTo(StringUtils.EMPTY);
+				assertThat(created.getWert()).isEmpty();
 			}
 
 			@Test
@@ -214,7 +214,7 @@ class FeldGruppeTypeCreatorTest {
 						VorgangWithEingangTestFactory.createBuilder().eingang(EingangTestFactory.createBuilder().antragsteller(null).build())
 								.build());
 
-				assertThat(created).extracting(FeldType::getWert).isEqualTo(StringUtils.EMPTY);
+				assertThat(created.getWert()).isEmpty();
 			}
 
 			@Test
@@ -225,7 +225,7 @@ class FeldGruppeTypeCreatorTest {
 												.build())
 								.build());
 
-				assertThat(created).extracting(FeldType::getWert).isEqualTo(StringUtils.EMPTY);
+				assertThat(created.getWert()).isEmpty();
 			}
 
 			@DisplayName("DatentypCode")
@@ -293,7 +293,7 @@ class FeldGruppeTypeCreatorTest {
 			void shouldBeEmptyStringForNullEingang() {
 				var created = create(VorgangWithEingangTestFactory.createBuilder().eingang(null).build());
 
-				assertThat(created).extracting(FeldType::getWert).isEqualTo(StringUtils.EMPTY);
+				assertThat(created.getWert()).isEmpty();
 			}
 
 			@Test
@@ -302,7 +302,7 @@ class FeldGruppeTypeCreatorTest {
 						VorgangWithEingangTestFactory.createBuilder().eingang(EingangTestFactory.createBuilder().antragsteller(null).build())
 								.build());
 
-				assertThat(created).extracting(FeldType::getWert).isEqualTo(StringUtils.EMPTY);
+				assertThat(created.getWert()).isEmpty();
 			}
 
 			@Test
@@ -313,7 +313,7 @@ class FeldGruppeTypeCreatorTest {
 												.build())
 								.build());
 
-				assertThat(created).extracting(FeldType::getWert).isEqualTo(StringUtils.EMPTY);
+				assertThat(created.getWert()).isEmpty();
 			}
 
 			@DisplayName("DatentypCode")
@@ -381,7 +381,7 @@ class FeldGruppeTypeCreatorTest {
 			void shouldBeEmptyStringForNullEingang() {
 				var created = create(VorgangWithEingangTestFactory.createBuilder().eingang(null).build());
 
-				assertThat(created).extracting(FeldType::getWert).isEqualTo(StringUtils.EMPTY);
+				assertThat(created.getWert()).isEmpty();
 			}
 
 			@Test
@@ -390,7 +390,7 @@ class FeldGruppeTypeCreatorTest {
 						VorgangWithEingangTestFactory.createBuilder().eingang(EingangTestFactory.createBuilder().antragsteller(null).build())
 								.build());
 
-				assertThat(created).extracting(FeldType::getWert).isEqualTo(StringUtils.EMPTY);
+				assertThat(created.getWert()).isEmpty();
 			}
 
 			@Test
@@ -401,7 +401,7 @@ class FeldGruppeTypeCreatorTest {
 												.build())
 								.build());
 
-				assertThat(created).extracting(FeldType::getWert).isEqualTo(StringUtils.EMPTY);
+				assertThat(created.getWert()).isEmpty();
 			}
 
 			@DisplayName("DatentypCode")
@@ -469,7 +469,7 @@ class FeldGruppeTypeCreatorTest {
 			void shouldBeEmptyStringForNullEingang() {
 				var created = create(VorgangWithEingangTestFactory.createBuilder().eingang(null).build());
 
-				assertThat(created).extracting(FeldType::getWert).isEqualTo(StringUtils.EMPTY);
+				assertThat(created.getWert()).isEmpty();
 			}
 
 			@Test
@@ -478,7 +478,7 @@ class FeldGruppeTypeCreatorTest {
 						VorgangWithEingangTestFactory.createBuilder().eingang(EingangTestFactory.createBuilder().antragsteller(null).build())
 								.build());
 
-				assertThat(created).extracting(FeldType::getWert).isEqualTo(StringUtils.EMPTY);
+				assertThat(created.getWert()).isEmpty();
 			}
 
 			@Test
@@ -489,7 +489,7 @@ class FeldGruppeTypeCreatorTest {
 												.build())
 								.build());
 
-				assertThat(created).extracting(FeldType::getWert).isEqualTo(StringUtils.EMPTY);
+				assertThat(created.getWert()).isEmpty();
 			}
 
 			@DisplayName("DatentypCode")
diff --git a/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/FormatTypeCreatorTest.java b/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/FormatTypeCreatorTest.java
index be881eb41bb7ea565008bf5c9d0bcb2f94ba114b..a15c43215ff5d4ebfd44461fc74a75d44fb70010 100644
--- a/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/FormatTypeCreatorTest.java
+++ b/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/FormatTypeCreatorTest.java
@@ -64,14 +64,14 @@ class FormatTypeCreatorTest {
 		void shouldHaveSonstigerName() {
 			var format = creator.create(vorgang, ozgFile);
 
-			assertThat(format.getSonstigerName()).isEqualTo(StringUtils.EMPTY);
+			assertThat(format.getSonstigerName()).isEmpty();
 		}
 
 		@Test
 		void shouldHaveVersion() {
 			var format = creator.create(vorgang, ozgFile);
 
-			assertThat(format.getVersion()).isEqualTo(StringUtils.EMPTY);
+			assertThat(format.getVersion()).isEmpty();
 		}
 	}
 
diff --git a/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/GeburtTypeTestFactory.java b/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/GeburtTypeTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..34c8fef41b03a4f5c1c31c51a0c23735f1d61522
--- /dev/null
+++ b/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/GeburtTypeTestFactory.java
@@ -0,0 +1,10 @@
+package de.ozgcloud.alfa.export;
+
+import de.xoev.xdomea.GeburtType;
+
+public class GeburtTypeTestFactory {
+
+	public static GeburtType create() {
+		return new GeburtType();
+	}
+}
diff --git a/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/KontaktTypeCreatorTest.java b/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/KontaktTypeCreatorTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..e9a7d11824af1db52a8e6c21031f132194149b68
--- /dev/null
+++ b/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/KontaktTypeCreatorTest.java
@@ -0,0 +1,244 @@
+package de.ozgcloud.alfa.export;
+
+import static org.assertj.core.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+import java.util.Optional;
+
+import javax.xml.datatype.XMLGregorianCalendar;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Spy;
+
+import de.ozgcloud.alfa.vorgang.Antragsteller;
+import de.ozgcloud.alfa.vorgang.AntragstellerTestFactory;
+import de.ozgcloud.alfa.vorgang.EingangTestFactory;
+import de.ozgcloud.alfa.vorgang.VorgangWithEingang;
+import de.ozgcloud.alfa.vorgang.VorgangWithEingangTestFactory;
+import de.xoev.xdomea.GeburtType;
+import de.xoev.xdomea.KontaktType;
+import de.xoev.xdomea.NameNatuerlichePersonType;
+
+class KontaktTypeCreatorTest {
+
+	@Spy
+	@InjectMocks
+	private KontaktTypeCreator creator;
+
+	@Mock
+	private NameNatuerlichePersonTypeCreator nameNatuerlichePersonTypeCreator;
+
+	@Mock
+	private DateConverter dateConverter;
+
+	@Nested
+	class TestCreate {
+
+		@Nested
+		class TestWithAntragsteller {
+
+			private final VorgangWithEingang vorgang = VorgangWithEingangTestFactory.create();
+			private final KontaktType kontaktType = KontaktTypeTestFactory.create();
+
+			@BeforeEach
+			void setUp() {
+				doReturn(Optional.of(vorgang.getEingang().getAntragsteller())).when(creator).getAntragstellerIfHasRequiredData(vorgang);
+				doReturn(kontaktType).when(creator).toKontaktType(vorgang.getEingang().getAntragsteller());
+			}
+
+			@Test
+			void shouldGetAntragsteller() {
+				callCreator(vorgang);
+
+				verify(creator).getAntragstellerIfHasRequiredData(vorgang);
+			}
+
+			@Test
+			void shouldMapToKontaktType() {
+				callCreator(vorgang);
+
+				verify(creator).toKontaktType(vorgang.getEingang().getAntragsteller());
+			}
+
+			@Test
+			void shouldReturnKontakt() {
+				var kontakt = callCreator(vorgang);
+
+				assertThat(kontakt).get().isEqualTo(kontaktType);
+			}
+		}
+
+		@Nested
+		class TestWithoutAntragsteller {
+
+			private final VorgangWithEingang vorgang = VorgangWithEingangTestFactory.createBuilder()
+					.eingang(EingangTestFactory.createBuilder().antragsteller(null).build())
+					.build();
+
+			@BeforeEach
+			void setUp() {
+				doReturn(Optional.empty()).when(creator).getAntragstellerIfHasRequiredData(vorgang);
+			}
+
+			@Test
+			void shouldBeEmpty() {
+				var kontakt = callCreator(vorgang);
+
+				assertThat(kontakt).isEmpty();
+			}
+		}
+
+		private Optional<KontaktType> callCreator(VorgangWithEingang vorgang) {
+			return creator.create(vorgang);
+		}
+	}
+
+	@Nested
+	class TestToKontaktType {
+
+		@Mock
+		private XMLGregorianCalendar geburtsdatum;
+
+		private final VorgangWithEingang vorgang = VorgangWithEingangTestFactory.create();
+		private final NameNatuerlichePersonType nameNatuerlichePerson = NameNatuerlichePersonTypeTestFactory.create();
+		private final GeburtType geburtType = GeburtTypeTestFactory.create();
+
+		@BeforeEach
+		void setUp() {
+			when(nameNatuerlichePersonTypeCreator.create(vorgang.getEingang().getAntragsteller())).thenReturn(nameNatuerlichePerson);
+			when(dateConverter.convertGermanFormatToISO(AntragstellerTestFactory.GEBURTSDATUM_STR)).thenReturn(Optional.of(geburtsdatum));
+			doReturn(geburtType).when(creator).createGeburtType(Optional.of(geburtsdatum));
+		}
+
+		@Test
+		void shouldCreateNameNatuerlichePerson() {
+			callCreator(vorgang);
+
+			verify(nameNatuerlichePersonTypeCreator).create(vorgang.getEingang().getAntragsteller());
+		}
+
+		@Test
+		void shouldHaveNameNatuerlichePerson() {
+			var kontakt = callCreator(vorgang);
+
+			assertThat(kontakt.getName()).isEqualTo(nameNatuerlichePerson);
+		}
+
+		@Test
+		void shouldCallDateConverter() {
+			callCreator(vorgang);
+
+			verify(dateConverter).convertGermanFormatToISO(AntragstellerTestFactory.GEBURTSDATUM_STR);
+		}
+
+		@Test
+		void shouldCreateGeburtType() {
+			callCreator(vorgang);
+
+			verify(creator).createGeburtType(Optional.of(geburtsdatum));
+		}
+
+		@Test
+		void shouldHaveGeburtType() {
+			var kontakt = callCreator(vorgang);
+
+			assertThat(kontakt.getGeburt()).isEqualTo(geburtType);
+		}
+
+		private KontaktType callCreator(VorgangWithEingang vorgang) {
+			return creator.toKontaktType(vorgang.getEingang().getAntragsteller());
+		}
+	}
+
+	@Nested
+	class TestCreateGeburtType {
+
+		@Mock
+		private XMLGregorianCalendar geburtsdatum;
+
+		@Test
+		void shouldCreate() {
+			var geburtType = callCreator(Optional.of(geburtsdatum));
+
+			assertThat(geburtType.getDatum()).isEqualTo(geburtsdatum);
+		}
+
+		@Test
+		void shouldCreateEmptyGeburt() {
+			var geburtType = callCreator(Optional.empty());
+
+			assertThat(geburtType.getDatum()).isNull();
+		}
+
+		private GeburtType callCreator(Optional<XMLGregorianCalendar> geburtsdatum) {
+			return creator.createGeburtType(geburtsdatum);
+		}
+	}
+
+	@Nested
+	class TestGetAntragstellerIfHasRequiredData {
+
+		@Mock
+		private XMLGregorianCalendar geburtsdatum;
+
+		@Test
+		void shouldBeEmptyIfAntragstellerNull() {
+			var antragsteller = callCreator(buildVorgang(null));
+
+			assertThat(antragsteller).isEmpty();
+		}
+
+		@Test
+		void shouldBeEmptyIfNoneOfRequiredDataExists() {
+			when(dateConverter.convertGermanFormatToISO(null)).thenReturn(Optional.empty());
+
+			var antragsteller = callCreator(buildVorgang(Antragsteller.builder().build()));
+
+			assertThat(antragsteller).isEmpty();
+		}
+
+		@Test
+		void shouldNotBeEmptyIfHasVorname() {
+			var antragsteller = callCreator(buildVorgang(Antragsteller.builder().vorname(AntragstellerTestFactory.VORNAME).build()));
+
+			assertThat(antragsteller).isNotEmpty();
+		}
+
+		@Test
+		void shouldNotBeEmptyIfHasNachname() {
+			var antragsteller = callCreator(buildVorgang(Antragsteller.builder().nachname(AntragstellerTestFactory.NACHNAME).build()));
+
+			assertThat(antragsteller).isNotEmpty();
+		}
+
+		@Test
+		void shouldNotBeEmptyIfHasAnrede() {
+			var antragsteller = callCreator(buildVorgang(Antragsteller.builder().anrede(AntragstellerTestFactory.ANREDE).build()));
+
+			assertThat(antragsteller).isNotEmpty();
+		}
+
+		@Test
+		void shouldNotBeEmptyIfHasGeburtsdatum() {
+			when(dateConverter.convertGermanFormatToISO(AntragstellerTestFactory.GEBURTSDATUM_STR)).thenReturn(Optional.of(geburtsdatum));
+
+			var antragsteller = callCreator(buildVorgang(Antragsteller.builder().geburtsdatum(AntragstellerTestFactory.GEBURTSDATUM_STR).build()));
+
+			assertThat(antragsteller).isNotEmpty();
+		}
+
+		private Optional<Antragsteller> callCreator(VorgangWithEingang vorgang) {
+			return creator.getAntragstellerIfHasRequiredData(vorgang);
+		}
+
+		private VorgangWithEingang buildVorgang(Antragsteller antragsteller) {
+			return VorgangWithEingangTestFactory.createBuilder().eingang(EingangTestFactory.createBuilder().antragsteller(antragsteller).build())
+					.build();
+		}
+	}
+
+}
\ No newline at end of file
diff --git a/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/KontaktTypeTestFactory.java b/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/KontaktTypeTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..3daad690a0d408df23c9e0b75dbee73720a128cd
--- /dev/null
+++ b/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/KontaktTypeTestFactory.java
@@ -0,0 +1,10 @@
+package de.ozgcloud.alfa.export;
+
+import de.xoev.xdomea.KontaktType;
+
+public class KontaktTypeTestFactory {
+
+	public static KontaktType create() {
+		return new KontaktType();
+	}
+}
diff --git a/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/NameNatuerlichePersonTypeCreatorTest.java b/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/NameNatuerlichePersonTypeCreatorTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..7124b6f846a1cd545df3a71c4567f2f42c166f70
--- /dev/null
+++ b/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/NameNatuerlichePersonTypeCreatorTest.java
@@ -0,0 +1,93 @@
+package de.ozgcloud.alfa.export;
+
+import static org.assertj.core.api.Assertions.*;
+
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.mockito.InjectMocks;
+
+import de.ozgcloud.alfa.vorgang.Antragsteller;
+import de.ozgcloud.alfa.vorgang.AntragstellerTestFactory;
+import de.xoev.xdomea.NameNatuerlichePersonType;
+
+class NameNatuerlichePersonTypeCreatorTest {
+
+	@InjectMocks
+	private NameNatuerlichePersonTypeCreator creator;
+
+	@Nested
+	class TestCreate {
+
+		@Test
+		void shouldHaveAnrede() {
+			var nameNatuerlichePerson = callCreator(AntragstellerTestFactory.create());
+
+			assertThat(nameNatuerlichePerson.getAnrede()).isEqualTo(AntragstellerTestFactory.ANREDE);
+		}
+
+		@Test
+		void shouldHaveEmptyAnrede() {
+			var nameNatuerlichePerson = callCreator(AntragstellerTestFactory.createBuilder().anrede(null).build());
+
+			assertThat(nameNatuerlichePerson.getAnrede()).isEmpty();
+		}
+
+		@Test
+		void shouldHaveVorname() {
+			var nameNatuerlichePerson = callCreator(AntragstellerTestFactory.create());
+
+			assertThat(nameNatuerlichePerson.getVorname().getName()).isEqualTo(AntragstellerTestFactory.VORNAME);
+		}
+
+		@Test
+		void shouldHaveEmptyVorname() {
+			var nameNatuerlichePerson = callCreator(AntragstellerTestFactory.createBuilder().vorname(null).build());
+
+			assertThat(nameNatuerlichePerson.getVorname().getName()).isEmpty();
+		}
+
+		@Test
+		void shouldHaveFamilienname() {
+			var nameNatuerlichePerson = callCreator(AntragstellerTestFactory.create());
+
+			assertThat(nameNatuerlichePerson.getFamilienname().getName()).isEqualTo(AntragstellerTestFactory.NACHNAME);
+		}
+
+		@Test
+		void shouldHaveEmptyFamilienname() {
+			var nameNatuerlichePerson = callCreator(AntragstellerTestFactory.createBuilder().nachname(null).build());
+
+			assertThat(nameNatuerlichePerson.getFamilienname().getName()).isEmpty();
+		}
+
+		@Nested
+		class TestWhenNullAntragsteller {
+
+			@Test
+			void shouldHaveEmptyAnrede() {
+				var nameNatuerlichePerson = callCreator(null);
+
+				assertThat(nameNatuerlichePerson.getAnrede()).isEmpty();
+			}
+
+			@Test
+			void shouldHaveEmptyVorname() {
+				var nameNatuerlichePerson = callCreator(null);
+
+				assertThat(nameNatuerlichePerson.getVorname().getName()).isEmpty();
+			}
+
+			@Test
+			void shouldHaveEmptyFamilienname() {
+				var nameNatuerlichePerson = callCreator(null);
+
+				assertThat(nameNatuerlichePerson.getFamilienname().getName()).isEmpty();
+			}
+		}
+
+		private NameNatuerlichePersonType callCreator(Antragsteller antragsteller) {
+			return creator.create(antragsteller);
+		}
+	}
+
+}
\ No newline at end of file
diff --git a/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/NameNatuerlichePersonTypeTestFactory.java b/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/NameNatuerlichePersonTypeTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..79abd234311aa7c864b7b146f932aa9197c5d980
--- /dev/null
+++ b/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/NameNatuerlichePersonTypeTestFactory.java
@@ -0,0 +1,10 @@
+package de.ozgcloud.alfa.export;
+
+import de.xoev.xdomea.NameNatuerlichePersonType;
+
+public class NameNatuerlichePersonTypeTestFactory {
+
+	public static NameNatuerlichePersonType create() {
+		return new NameNatuerlichePersonType();
+	}
+}
diff --git a/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/PrimaerdokumentTypeCreatorTest.java b/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/PrimaerdokumentTypeCreatorTest.java
index 4446ecacf545501b69dc7b0a45da999411ef8ce2..db307b1e5da896283a48d60c7e31da70ecba26d9 100644
--- a/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/PrimaerdokumentTypeCreatorTest.java
+++ b/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/PrimaerdokumentTypeCreatorTest.java
@@ -10,7 +10,6 @@ import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.Spy;
 
-import de.ozgcloud.alfa.common.TestUtils;
 import de.ozgcloud.alfa.common.file.OzgFile;
 import de.ozgcloud.alfa.common.file.OzgFileTestFactory;
 import de.ozgcloud.alfa.vorgang.EingangHeaderTestFactory;
@@ -24,7 +23,7 @@ class PrimaerdokumentTypeCreatorTest {
 	private PrimaerdokumentTypeCreator creator;
 
 	@Mock
-	private UUIDConverter uuidConverter;
+	private ExportFilenameGenerator exportFilenameGenerator;
 
 	@Nested
 	class TestCreate {
@@ -34,14 +33,14 @@ class PrimaerdokumentTypeCreatorTest {
 
 		@BeforeEach
 		void init() {
-			doReturn(ozgFile.getName()).when(creator).createDateiname(ozgFile);
+			when(exportFilenameGenerator.generateExportFilename(ozgFile)).thenReturn(ozgFile.getName());
 		}
 
 		@Test
-		void shouldCreateDateiname() {
+		void shouldGenerateExportFilename() {
 			creator.create(vorgang, ozgFile);
 
-			verify(creator).createDateiname(ozgFile);
+			verify(exportFilenameGenerator).generateExportFilename(ozgFile);
 		}
 
 		@Test
@@ -65,29 +64,4 @@ class PrimaerdokumentTypeCreatorTest {
 			assertThat(primaerdokument.getErsteller()).isEqualTo(EingangHeaderTestFactory.FORM_ENGINE_NAME);
 		}
 	}
-
-	@Nested
-	class TestCreateDateiname {
-
-		private final OzgFile ozgFile = OzgFileTestFactory.create();
-
-		@BeforeEach
-		void init() {
-			when(uuidConverter.fromObjectId(ozgFile.getId().toString())).thenReturn("64a820d3-6285-172a-c028-0000000026d0");
-		}
-
-		@Test
-		void shouldConvertObjectId() {
-			creator.createDateiname(ozgFile);
-
-			verify(uuidConverter).fromObjectId(ozgFile.getId().toString());
-		}
-
-		@Test
-		void shouldCreate() {
-			var dateiname = creator.createDateiname(ozgFile);
-
-			assertThat(dateiname).matches(String.format("^%s_%s$", TestUtils.UUID_REGEX, ozgFile.getName()));
-		}
-	}
 }
\ No newline at end of file
diff --git a/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/VorgangTypeCreatorTest.java b/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/VorgangTypeCreatorTest.java
index 62cd4dd2e55337719205f5586d24aa3a9234b180..f97c9906d1eaa1c8cfe8414b2b574c95983e8c5b 100644
--- a/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/VorgangTypeCreatorTest.java
+++ b/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/VorgangTypeCreatorTest.java
@@ -3,9 +3,9 @@ package de.ozgcloud.alfa.export;
 import static org.assertj.core.api.Assertions.*;
 import static org.mockito.Mockito.*;
 
+import java.util.Optional;
 import java.util.stream.Stream;
 
-import org.apache.commons.lang3.StringUtils;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
@@ -21,6 +21,8 @@ import de.xoev.xdomea.AllgemeineMetadatenType;
 import de.xoev.xdomea.AnwendungsspezifischeErweiterungType;
 import de.xoev.xdomea.DokumentType;
 import de.xoev.xdomea.IdentifikationObjektType;
+import de.xoev.xdomea.KontaktType;
+import de.xoev.xdomea.VorgangType;
 
 class VorgangTypeCreatorTest {
 
@@ -31,6 +33,9 @@ class VorgangTypeCreatorTest {
 	@Mock
 	private DokumentTypeCreator dokumentTypeCreator;
 
+	@Mock
+	private KontaktTypeCreator kontaktTypeCreator;
+
 	@Nested
 	class TestCreate {
 
@@ -40,6 +45,7 @@ class VorgangTypeCreatorTest {
 		private final AllgemeineMetadatenType allgemeineMetadaten = AllgemeineMetadatenTypeTestFactory.create();
 		private final AnwendungsspezifischeErweiterungType anwendungsspezifischeErweiterung = AnwendungsspezifischeErweiterungTypeTestFactory.create();
 		private final DokumentType dokument = DokumentTypeTestFactory.create();
+		private final KontaktType kontakt = KontaktTypeTestFactory.create();
 
 		@BeforeEach
 		void init() {
@@ -47,50 +53,77 @@ class VorgangTypeCreatorTest {
 			doReturn(allgemeineMetadaten).when(creator).createAllgemeineMetadaten(vorgang);
 
 			when(dokumentTypeCreator.create(vorgang)).thenReturn(Stream.of(dokument));
+			when(kontaktTypeCreator.create(vorgang)).thenReturn(Optional.of(kontakt));
 		}
 
 		@Test
 		void shouldHaveAnwendungsspezifischeErweiterungType() {
-			var vorgangType = creator.create(vorgang, anwendungsspezifischeErweiterung);
+			var vorgangType = callCreator();
 
 			assertThat(vorgangType.getAnwendungsspezifischeErweiterung()).isEqualTo(anwendungsspezifischeErweiterung);
 		}
 
 		@Test
 		void shouldCallCreateIdentifikation() {
-			creator.create(vorgang, anwendungsspezifischeErweiterung);
+			callCreator();
 
 			verify(creator).createIdentifikation();
 		}
 
 		@Test
 		void shouldHaveIdentifikation() {
-			var vorgangType = creator.create(vorgang, anwendungsspezifischeErweiterung);
+			var vorgangType = callCreator();
 
 			assertThat(vorgangType.getIdentifikation()).isEqualTo(identifikationObjekt);
 		}
 
 		@Test
 		void shouldCallCreateAllgemeineMetadaten() {
-			creator.create(vorgang, anwendungsspezifischeErweiterung);
+			callCreator();
 
 			verify(creator).createAllgemeineMetadaten(vorgang);
 		}
 
 		@Test
 		void shouldHaveAllgemeineMetadaten() {
-			var vorgangType = creator.create(vorgang, anwendungsspezifischeErweiterung);
+			var vorgangType = callCreator();
 
 			assertThat(vorgangType.getAllgemeineMetadaten()).isEqualTo(allgemeineMetadaten);
 		}
 
 		@Test
 		void shouldCreateDokumenType() {
-			var vorgangType = creator.create(vorgang, anwendungsspezifischeErweiterung);
+			var vorgangType = callCreator();
 
 			verify(dokumentTypeCreator).create(vorgang);
 			assertThat(vorgangType.getDokument()).hasSize(1).containsExactly(dokument);
 		}
+
+		@Test
+		void shouldCallKontaktTypeCreator() {
+			callCreator();
+
+			verify(kontaktTypeCreator).create(vorgang);
+		}
+
+		@Test
+		void shouldHaveKontakt() {
+			var vorgangType = callCreator();
+
+			assertThat(vorgangType.getKontakt()).containsExactly(kontakt);
+		}
+
+		@Test
+		void shouldNotHaveKontakt() {
+			when(kontaktTypeCreator.create(vorgang)).thenReturn(Optional.empty());
+			var vorgangType = callCreator();
+
+			assertThat(vorgangType.getKontakt()).isEmpty();
+		}
+
+		private VorgangType callCreator() {
+			return creator.create(vorgang, anwendungsspezifischeErweiterung);
+		}
 	}
 
 	@Nested
@@ -116,7 +149,7 @@ class VorgangTypeCreatorTest {
 		void shouldHaveBemerkung() {
 			var allgemeineMetadaten = creator.createAllgemeineMetadaten(vorgang);
 
-			assertThat(allgemeineMetadaten.getBemerkung()).isEqualTo(StringUtils.EMPTY);
+			assertThat(allgemeineMetadaten.getBemerkung()).isEmpty();
 		}
 
 		@Test
diff --git a/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/XDomeaServiceTest.java b/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/XDomeaServiceTest.java
index 1f204306638b352ecae3d1ec6f32ac1e70893a93..f2471d907ae8b11e38264726ff7fb1245c72435d 100644
--- a/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/XDomeaServiceTest.java
+++ b/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/XDomeaServiceTest.java
@@ -6,6 +6,7 @@ import static org.mockito.ArgumentMatchers.*;
 import static org.mockito.Mockito.*;
 
 import java.io.ByteArrayOutputStream;
+import java.io.File;
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
 import java.util.UUID;
@@ -53,22 +54,68 @@ class XDomeaServiceTest {
 	@Mock
 	private ExportFileService exportFileService;
 
+	@Mock
+	private ExportFilenameGenerator exportFilenameGenerator;
+
 	@DisplayName("Write exportToXdomea")
 	@Nested
 	class TestWriteExport {
 
-		private static final String XML_STRING = "<xml>";
 		private static final String FILENAME_ID = UUID.randomUUID().toString();
+		private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+		private final ExportData exportData = ExportDataTestFactory.create();
+
+		@Mock
+		private File zipFile;
+
+		@BeforeEach
+		void setUp() {
+			doReturn(exportData).when(service).collectExportData(VorgangHeaderTestFactory.ID, FILENAME_ID);
+			doReturn(zipFile).when(service).createZipFile(exportData);
+			doNothing().when(service).writeZipFileContent(zipFile, outputStream);
+		}
+
+		@Test
+		void shouldCollectExportData() {
+			callService();
+
+			verify(service).collectExportData(VorgangHeaderTestFactory.ID, FILENAME_ID);
+		}
+
+		@Test
+		void shouldCreateZipFile() {
+			callService();
+
+			verify(service).createZipFile(exportData);
+		}
+
+		@Test
+		void shouldWriteZipFileContentToOutputStream() {
+			callService();
+
+			verify(service).writeZipFileContent(zipFile, outputStream);
+		}
+
+		private void callService() {
+			service.writeExport(VorgangHeaderTestFactory.ID, FILENAME_ID, outputStream);
+		}
+	}
+
+	@Nested
+	class TestCollectExportData {
 
+		private static final String FILENAME_ID = UUID.randomUUID().toString();
+		private static final String FILE_NAME = "file.zip";
+		private static final String XML_STRING = "<xml>";
 		private final VorgangWithEingang vorgang = VorgangWithEingangTestFactory.create();
-		private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
-		private final OzgFile ozgFile = OzgFileTestFactory.create();
+		private final Stream<OzgFile> ozgFiles = Stream.of(OzgFileTestFactory.create());
 
 		@BeforeEach
-		void init() {
+		void setUp() {
+			when(exportFileService.getAllPdfs(EingangTestFactory.ID)).thenReturn(ozgFiles);
 			when(vorgangController.getVorgang(VorgangHeaderTestFactory.ID)).thenReturn(vorgang);
 			doReturn(XML_STRING).when(service).createXmlContent(vorgang);
-			when(exportFileService.getAllPdfs(EingangTestFactory.ID)).thenReturn(Stream.of(ozgFile));
+			doReturn(FILE_NAME).when(service).buildXmlFilename(FILENAME_ID);
 		}
 
 		@Test
@@ -86,51 +133,49 @@ class XDomeaServiceTest {
 		}
 
 		@Test
-		void shouldCreateZipEntry() throws IOException {
+		void shouldGenerateXmlFilename() {
 			callService();
 
-			verify(service).putZipEntry(anyString(), eq(XML_STRING), any(ZipOutputStream.class));
+			verify(service).buildXmlFilename(FILENAME_ID);
 		}
 
 		@Test
-		void shouldGenerateXmlFilename() {
+		void shouldGetPdfFiles() {
 			callService();
 
-			verify(service).buildXmlFilename(FILENAME_ID);
+			verify(exportFileService).getAllPdfs(EingangTestFactory.ID);
 		}
 
 		@Test
-		void shouldWriteBytes() {
-			callService();
+		void shouldContainsVorgang() {
+			var exportData = callService();
 
-			assertThat(outputStream).isNotNull();
-			assertThat(outputStream.toByteArray()).hasSizeGreaterThan(100);
+			assertThat(exportData.getVorgang()).isEqualTo(vorgang);
 		}
 
 		@Test
-		void shouldThrowTechnicalException() throws IOException {
-			doThrow(IOException.class).when(service).putZipEntry(anyString(), eq(XML_STRING), any(ZipOutputStream.class));
+		void shouldContainsXmlContent() {
+			var exportData = callService();
 
-			assertThatThrownBy(this::callService).isInstanceOf(TechnicalException.class);
+			assertThat(exportData.getXmlFileContent()).isEqualTo(XML_STRING);
 		}
 
 		@Test
-		void shouldGetPdfFiles() {
-			callService();
+		void shouldContainsExportFilename() {
+			var exportData = callService();
 
-			verify(exportFileService).getAllPdfs(EingangTestFactory.ID);
+			assertThat(exportData.getExportFilename()).isEqualTo(FILE_NAME);
 		}
 
-		@SneakyThrows
 		@Test
-		void shouldWritePdfFiles() {
-			callService();
+		void shouldContainsExportExportFiles() {
+			var exportData = callService();
 
-			verify(service).putOzgFileIntoZip(eq(ozgFile), any(ZipOutputStream.class));
+			assertThat(exportData.getExportFiles()).isEqualTo(ozgFiles);
 		}
 
-		private void callService() {
-			service.writeExport(VorgangHeaderTestFactory.ID, FILENAME_ID, outputStream);
+		private ExportData callService() {
+			return service.collectExportData(VorgangHeaderTestFactory.ID, FILENAME_ID);
 		}
 
 	}
@@ -188,6 +233,66 @@ class XDomeaServiceTest {
 		}
 	}
 
+	@Nested
+	class TestCreateZipFile {
+
+		private static final String XML_STRING = "<xml>";
+		private final ExportData exportData = ExportDataTestFactory.create();
+
+		@Captor
+		private ArgumentCaptor<ZipOutputStream> zipOutputStreamArgumentCaptor;
+
+		@SneakyThrows
+		@BeforeEach
+		void setUp() {
+			doNothing().when(service).putOzgFileIntoZip(any(OzgFile.class), any(ZipOutputStream.class));
+		}
+
+		@Test
+		void shouldCreateZipEntry() throws IOException {
+			callService();
+
+			verify(service).putZipEntry(eq(ExportDataTestFactory.EXPORT_FILENAME), eq(ExportDataTestFactory.XML_FILE_CONTENT),
+					any(ZipOutputStream.class));
+		}
+
+		@Test
+		void shouldCreateZipOutputStream() throws IOException {
+			callService();
+
+			verify(service).putZipEntry(eq(ExportDataTestFactory.EXPORT_FILENAME), eq(ExportDataTestFactory.XML_FILE_CONTENT),
+					zipOutputStreamArgumentCaptor.capture());
+			assertThat(zipOutputStreamArgumentCaptor.getValue()).isInstanceOf(ZipOutputStream.class);
+		}
+
+		@Test
+		void shouldWriteBytes() {
+			var file = callService();
+
+			assertThat(file).isNotEmpty().content().hasSizeGreaterThan(100);
+		}
+
+		@SneakyThrows
+		@Test
+		void shouldWritePdfFiles() {
+			callService();
+
+			verify(service).putOzgFileIntoZip(eq(ExportDataTestFactory.OZG_FILE), any(ZipOutputStream.class));
+		}
+
+		@Test
+		void shouldThrowTechnicalException() throws IOException {
+			doThrow(IOException.class).when(service).putZipEntry(anyString(), eq(XML_STRING), any(ZipOutputStream.class));
+
+			assertThatThrownBy(this::callService).isInstanceOf(TechnicalException.class);
+		}
+
+		private File callService() {
+			return service.createZipFile(exportData);
+		}
+
+	}
+
 	@Nested
 	class TestPutZipEntry {
 
@@ -246,6 +351,18 @@ class XDomeaServiceTest {
 
 		private final OzgFile ozgFile = OzgFileTestFactory.create();
 
+		@BeforeEach
+		void setUp() {
+			when(exportFilenameGenerator.generateExportFilename(ozgFile)).thenReturn(OzgFileTestFactory.NAME);
+		}
+
+		@Test
+		void shouldGenerateExportFilename() {
+			callService();
+
+			verify(exportFilenameGenerator).generateExportFilename(ozgFile);
+		}
+
 		@SneakyThrows
 		@Test
 		void shouldPutNextEntry() {
diff --git a/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/XmlMarshallerConfigurationTest.java b/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/XmlMarshallerConfigurationTest.java
index 91d53e4afc8c6f934d904c1bef9df3ea87adfb8c..46ddabac96c193f78b8ec3e8a448cbb68897c90f 100644
--- a/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/XmlMarshallerConfigurationTest.java
+++ b/alfa-xdomea/src/test/java/de/ozgcloud/alfa/export/XmlMarshallerConfigurationTest.java
@@ -5,7 +5,7 @@ import static org.mockito.Mockito.*;
 
 import java.util.Map;
 
-import javax.xml.bind.Marshaller;
+import jakarta.xml.bind.Marshaller;
 
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Nested;
diff --git a/goofy-client/apps/goofy-e2e/Jenkinsfile b/goofy-client/apps/goofy-e2e/Jenkinsfile
index 50fd697a3fa21b9a62ef0f9198fefe61ebb08277..c25dede479bf24c9037d9c13d44f45abb864d9c3 100644
--- a/goofy-client/apps/goofy-e2e/Jenkinsfile
+++ b/goofy-client/apps/goofy-e2e/Jenkinsfile
@@ -190,15 +190,6 @@ pipeline {
             }
         }
 
-//        stage('Pausing to wait for ozg-operator') {
-//			when {
-//                expression { !SKIP_RUN }
-//            }
-//            steps {
-//                sleep(time: 3, unit: 'MINUTES')
-//            }
-//        }
-
         stage('Run E2E-Tests') {
             when {
                 expression { !SKIP_RUN }
@@ -615,11 +606,12 @@ Void publishE2ETestResult(String reportFolder, String reportName) {
 
 String runTests(String bezeichner, String reportFolder, Integer dbPort, String stageName) {
     def config = generateCypressConfig(bezeichner, reportFolder, dbPort)
+	def spec = "apps/goofy-e2e/src/e2e/${reportFolder}"
 
     try {
-        dir("goofy-client") {
-      	    sh "npm run cypress:version"
-            sh "npm run cypress:ci-run --CONFIG='${config}' --REPORT_FOLDER=${reportFolder}"
+        dir('goofy-client'){
+			sh "npm run cypress:version"
+			sh "npm run cypress:ci-run --CONFIG=./${config} --REPORT_FOLDER=${reportFolder}"
         }
     } catch (Exception e) {
         printNpmDebugLog()
@@ -658,26 +650,35 @@ String cutBranchNameForKeycloakRealm(String branchName, String stageName) {
 
 String generateCypressConfig(String bezeichner, String testFolder, Integer dbPort) {
     def namespace = generateNamespace(bezeichner)
+	def configName = "cypress-ci-"+testFolder+".json"
 
-	def plutoDatabaseSecret = getPlutoDatabaseSecret(namespace);
-	def decodedPassword = decodeString(plutoDatabaseSecret.password);
-	def parsablePassword = makePasswordUrlConform(decodedPassword);
+	dir('goofy-client/apps/goofy-e2e/'){
+		def config = readJSON file: 'cypress-ci.json'
+
+		def plutoDatabaseSecret = getPlutoDatabaseSecret(namespace);
+		def decodedPassword = decodeString(plutoDatabaseSecret.password);
+		def parsablePassword = makePasswordUrlConform(decodedPassword);
+
+		config.baseUrl = "https://${bezeichner}.${env.CLUSTER_BASE_URL}" as String
+		config.env.dbUrl = "mongodb://${decodeString(plutoDatabaseSecret.username)}:${parsablePassword}@localhost:${dbPort}/admin?ssl=false&directConnection=true" as String
+		config.env.keycloakUrl = "https://${env.SSO_URL}/" as String
+		config.env.keycloakRealm = namespace as String
+		config.env.sabineUuid = getKeycloakUuid(namespace, "sabine") as String
+		config.videosFolder = "./reports/${testFolder}/videos" as String
+		config.screenshotsFolder = "./reports/${testFolder}/screenshots" as String
+		config.reporterOptions.reportDir = "./reports/${testFolder}/mochawesome-report" as String
+
+        config.specPattern = "src/e2e/${testFolder}/**/*.cy.{js,jsx,ts,tsx}" as String
+
+		config.env.put("search", getElasticsearchEnv(namespace))
+		config.env.put("userManager", getUserManagerEnv(namespace, dbPort))
+
+		writeJSON file: configName, json: config
+
+		sh "cat ${configName}"
+	}
 
-	config.baseUrl = "https://${bezeichner}.${env.CLUSTER_BASE_URL}" as String
-	config.env.dbUrl = "mongodb://${decodeString(plutoDatabaseSecret.username)}:${parsablePassword}@localhost:${dbPort}/admin?ssl=false&directConnection=true" as String
-	config.env.keycloakUrl = "https://${env.SSO_URL}/" as String
-	config.env.keycloakRealm = namespace as String
-	config.env.keycloakClient = "alfa" as String
-	config.env.sabineUuid = getKeycloakUuid(namespace, "sabine") as String
-	config.integrationFolder = "./src/integration/${testFolder}" as String
-	config.videosFolder = "./reports/${testFolder}/videos" as String
-	config.screenshotsFolder = "./reports/${testFolder}/screenshots" as String
-	config.reporterOptions.reportDir = "./reports/${testFolder}/mochawesome-report" as String
-
-	config.env.put("search", getElasticsearchEnv(namespace))
-	config.env.put("userManager", getUserManagerEnv(namespace, dbPort))
-
-    return JSONObject.fromObject(config)
+	return "cypress-ci-"+testFolder+".config.ts"
 }
 
 String makePasswordUrlConform(String password) {
diff --git a/goofy-client/apps/goofy-e2e/cypress-ci-einheitlicher-ansprechpartner.config.ts b/goofy-client/apps/goofy-e2e/cypress-ci-einheitlicher-ansprechpartner.config.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5ef91724365a1ed66f94db34d0c762d8b1b3b2b7
--- /dev/null
+++ b/goofy-client/apps/goofy-e2e/cypress-ci-einheitlicher-ansprechpartner.config.ts
@@ -0,0 +1,16 @@
+import { nxE2EPreset } from '@nrwl/cypress/plugins/cypress-preset';
+import { defineConfig } from 'cypress';
+
+//Cypress config is generated by JenkinsFile
+const cypressConfig = require('./cypress-ci-einheitlicher-ansprechpartner.json');
+const cypressEvents = require('./src/support/cypress-tasks.ts');
+
+export default defineConfig({
+	e2e: {
+		...nxE2EPreset(__dirname),
+		...cypressConfig,
+		setupNodeEvents(on, config) {
+			return cypressEvents(on, config);
+		}
+	},
+});
\ No newline at end of file
diff --git a/goofy-client/apps/goofy-e2e/cypress-ci-main-tests.config.ts b/goofy-client/apps/goofy-e2e/cypress-ci-main-tests.config.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c3b17666b23e7ef150bfc88da510380739f7f49a
--- /dev/null
+++ b/goofy-client/apps/goofy-e2e/cypress-ci-main-tests.config.ts
@@ -0,0 +1,16 @@
+import { nxE2EPreset } from '@nrwl/cypress/plugins/cypress-preset';
+import { defineConfig } from 'cypress';
+
+//Cypress config is generated by JenkinsFile
+const cypressConfig = require('./cypress-ci-main-tests.json');
+const cypressEvents = require('./src/support/cypress-tasks.ts');
+
+export default defineConfig({
+	e2e: {
+		...nxE2EPreset(__dirname),
+		...cypressConfig,
+		setupNodeEvents(on, config) {
+			return cypressEvents(on, config);
+		}
+	},
+});
\ No newline at end of file
diff --git a/goofy-client/apps/goofy-e2e/cypress-ci.json b/goofy-client/apps/goofy-e2e/cypress-ci.json
index cbcd4bfb981c2d6443c05fe4925c05646c1c9325..084a420ec79ba1ddf02340bfe17f62db94a8b985 100644
--- a/goofy-client/apps/goofy-e2e/cypress-ci.json
+++ b/goofy-client/apps/goofy-e2e/cypress-ci.json
@@ -1,30 +1,22 @@
 {
-	"baseUrl": "https://e2e.dev.by.ozg-cloud.de",
 	"env": {
-		"dbUrl": "mongodb+srv://pluto-database-user:XnHhfznNWg65NNd@pluto-database-svc.sh-e2e-dev.svc.cluster.local/admin?ssl=false",
 		"database": "pluto-database",
-		"keycloakRealm": "by-e2e-local-dev",
-		"keycloakUrl": "https://sso.dev.by.ozg-cloud.de/",
 		"keycloakClient": "alfa"
 	},
 	"fileServerFolder": ".",
 	"fixturesFolder": "./src/fixtures",
-	"integrationFolder": "./src/integration",
 	"modifyObstructiveCode": false,
-	"pluginsFile": "./src/plugins/index",
-	"supportFile": "./src/support/index.ts",
 	"video": true,
-	"videosFolder": "./reports/videos",
-	"screenshotsFolder": "./reports/screenshots",
 	"chromeWebSecurity": false,
 	"reporter": "../../node_modules/cypress-mochawesome-reporter",
 	"defaultCommandTimeout": 10000,
+	"supportFile": "./src/support/e2e.ts",
+	"testIsolation": false,
 	"reporterOptions": {
 		"html": false,
 		"json": true,
 		"quite": true,
-		"reportDir": "./reports/mochawesome-report",
 		"reportFilename": "report",
 		"overwrite": false
 	}
-}
\ No newline at end of file
+}
diff --git a/goofy-client/apps/goofy-e2e/cypress.config.json b/goofy-client/apps/goofy-e2e/cypress.config.json
new file mode 100644
index 0000000000000000000000000000000000000000..2eaa211f04655dea29923a5a9228dc5a98dcc19b
--- /dev/null
+++ b/goofy-client/apps/goofy-e2e/cypress.config.json
@@ -0,0 +1,39 @@
+{
+	"baseUrl": "http://localhost:4300",
+	"env": {
+		"dbUrl": "mongodb://localhost:27018",
+		"database": "test",
+		"keycloakRealm": "by-e2e-local-dev",
+		"keycloakUrl": "https://sso.dev.by.ozg-cloud.de/",
+		"keycloakClient": "alfa",
+		"sabineUuid": "2ccf0c13-da74-4516-ae3d-f46d30e8ec0c",
+		"search": {
+			"url": "http://localhost:9200",
+			"index": "e2e-test-index",
+			"user": "elastic",
+			"password": "password"
+		},
+		"userManager": {
+			"dbUrl": "mongodb://localhost:27018",
+			"database": "usermanager"
+		}
+	},
+	"fileServerFolder": ".",
+	"fixturesFolder": "./src/fixtures",
+	"video": false,
+	"videosFolder": "./reports/videos",
+	"screenshotsFolder": "./reports/screenshots",
+	"chromeWebSecurity": false,
+	"reporter": "../../node_modules/cypress-mochawesome-reporter",
+	"defaultCommandTimeout": 10000,
+	"specPattern": "src/e2e/**/*.cy.{js,jsx,ts,tsx}",
+	"supportFile": "src/support/e2e.ts",
+	"testIsolation": false,
+	"reporterOptions": {
+		"html": false,
+		"json": true,
+		"reportDir": "./reports/mochawesome-report",
+		"reportFilename": "report",
+		"overwrite": true
+	}
+}
diff --git a/goofy-client/apps/goofy-e2e/cypress.config.ts b/goofy-client/apps/goofy-e2e/cypress.config.ts
index f202506b3f402b3aa90fd1959a868b249fda09a8..21b3aad9fb32db1ae98081e63a3facb256b3593a 100644
--- a/goofy-client/apps/goofy-e2e/cypress.config.ts
+++ b/goofy-client/apps/goofy-e2e/cypress.config.ts
@@ -1,383 +1,15 @@
 import { nxE2EPreset } from '@nrwl/cypress/plugins/cypress-preset';
 import { defineConfig } from 'cypress';
 
-const MongoClient = require('mongodb').MongoClient;
-const Binary = require('mongodb').Binary;
-const ObjectId = require('mongodb').ObjectId;
-const Long = require('mongodb').Long;
-const fs = require('fs');
-const {rmdir} = require('fs');
-
-const cypressJsonConfig = {
-	baseUrl: 'http://localhost:4300',
-	env: {
-		dbUrl: 'mongodb://localhost:27018',
-		database: 'test',
-		keycloakRealm: 'by-e2e-local-dev',
-		keycloakUrl: 'https://sso.dev.by.ozg-cloud.de/',
-		keycloakClient: 'alfa',
-		sabineUuid: '2ccf0c13-da74-4516-ae3d-f46d30e8ec0c',
-		search: {
-			url: 'http://localhost:9200',
-			index: 'e2e-test-index',
-			user: 'elastic',
-			password: 'password',
-		},
-		userManager: {
-			dbUrl: 'mongodb://localhost:27018',
-			database: 'usermanager',
-		},
-	},
-	fileServerFolder: '.',
-	fixturesFolder: './src/fixtures',
-	video: false,
-	videosFolder: './reports/videos',
-	screenshotsFolder: './reports/screenshots',
-	chromeWebSecurity: false,
-	reporter: '../../node_modules/cypress-mochawesome-reporter',
-	defaultCommandTimeout: 10000,
-	reporterOptions: {
-		html: false,
-		json: true,
-		reportDir: './reports/mochawesome-report',
-		reportFilename: 'report',
-		overwrite: true,
-	},
-	specPattern: 'src/e2e/**/*.cy.{js,jsx,ts,tsx}',
-	supportFile: 'src/support/e2e.ts',
-	testIsolation: false
-};
+const cypressConfig = require('./cypress.config.json');
+const cypressEvents = require('./src/support/cypress-tasks.ts');
 
 export default defineConfig({
 	e2e: {
 		...nxE2EPreset(__dirname),
-		...cypressJsonConfig,
+		...cypressConfig,
 		setupNodeEvents(on, config) {
-			on('task', {
-				initCommandData({collection, data}) {
-					console.log('initCommandData');
-					insertIntoDatabase(config, collection, parseCommandData(data));
-					return 0;
-				},
-				initGridFsFileData({collection, data}) {
-					console.log('initGridFsFileData');
-					insertIntoDatabase(config, collection, parseGridFsFileData(data));
-					return 0;
-				},
-				initGridFsChunkData({collection, data}) {
-					console.log('initGridFsChunkData');
-					insertIntoDatabase(config, collection, parseGridFsChunkData(data));
-					return 0;
-				},
-				initVorgangData({collection, data}) {
-					console.log('initVorgangData');
-					insertIntoDatabase(config, collection, parseVorgangData(data));
-					return 0;
-				},
-				initVorgangAttachedItemData({collection, data}) {
-					console.log('initVorgangAttachedItemData');
-					insertIntoDatabase(config, collection, parseVorgangAttachedItemData(data));
-					return 0;
-				},
-				initUsermanagerData({collection, data}) {
-					console.log('initUsermanagerData');
-					insertIntoUserManagerDatabase(config, collection, parseUserData(data));
-					return 0;
-				},
-				dropCollections(collections) {
-					console.log('dropCollections: ', collections);
-					dropCollectionsFromDatabase(config, collections);
-					return 0;
-				},
-				dropUserManagerCollections(collections) {
-					console.log('dropUserManagerCollections: ', collections);
-					dropUserManagerCollectionsFromDatabase(config, collections);
-					return 0;
-				},
-				countFiles(folderName) {
-					console.log('counting files in folder %s', folderName);
-					return countFiles(folderName);					
-				},
-				deleteFolder(folderName) {
-					console.log('deleting folder %s', folderName);
-					deleteFolder(folderName);
-					return 0;
-				  },
-			});
-
-			// Workaround für Angular 13 und Cypress mit Webpack 4,
-			// Siehe https://github.com/cypress-io/cypress/issues/19066#issuecomment-1012055705
-			// Entfernen, sobald Cypress Webpack 5 nutzt - https://github.com/cypress-io/cypress/issues/19555
-			// Ursache: Angular linker needed to link partial-ivy code,
-			//   see https://angular.io/guide/creating-libraries#consuming-partial-ivy-code-outside-the-angular-cli
-			// Fehlerbild:
-			//   - Anwendung läuft im Browser, aber nicht in Cypress.
-			//   - Fehlermeldung in Cypress: The injectable 'SystemDateTimeProvider' needs to be compiled using the JIT compiler, but '@angular/compiler' is not available.
-			// Lösung:
-			//   - NPM-Paket identifizieren, dass "SystemDateTimeProvider" enthält.
-			//   - NPM-Paket im "test" Attribut unten hinzufügen.
-			const webpackPreprocessor = require('@cypress/webpack-batteries-included-preprocessor');
-			const webpackOptions = webpackPreprocessor.defaultOptions.webpackOptions;
-
-			webpackOptions.module.rules.unshift({
-				test: /[/\\](@angular|@ngxp|angular-oauth2-oidc)[/\\].+\.m?js$/,
-				resolve: {
-					fullySpecified: false,
-				},
-				use: {
-					loader: 'babel-loader',
-					options: {
-						plugins: ['@angular/compiler-cli/linker/babel'],
-						compact: false,
-						cacheDirectory: true
-					}
-				}
-			});
-
-			on('file:preprocessor', webpackPreprocessor({
-				webpackOptions: webpackOptions,
-				typescript: require.resolve('typescript')
-			}));
-
-			return config;
-			// Ende - Workaround für Angular 13 und Cypress mit Webpack 4
+			return cypressEvents(on, config);
 		}
 	},
 });
-
-function parseCommandData(commands) {
-	commands.forEach(command => parseCommand(command))
-	return commands;
-}
-
-function parseCommand(command) {
-	command.createdAt = createDate(command.createdAt);
-	if(command.finishedAt){
-		command.finishedAt = createDate(command.finishedAt);
-	}
-	command.relationVersion = createNumberLong(command.relationVersion);
-}
-
-function parseGridFsFileData(gridFsFiles) {
-	gridFsFiles.forEach(gridFsFile => parseGridFsFile(gridFsFile))
-	return gridFsFiles;
-}
-
-function parseGridFsFile(gridFsFile) {
-	gridFsFile._id = createObjectId(gridFsFile);
-	gridFsFile.length = createNumberLong(gridFsFile.length);
-	gridFsFile.uploadDate = createDate(gridFsFile.uploadDate);
-}
-
-function parseGridFsChunkData(gridFsChunks) {
-	gridFsChunks.forEach(gridFsChunk => parseGridFsChunk(gridFsChunk));
-	return gridFsChunks;
-}
-
-function parseGridFsChunk(gridFsChunk) {
-	gridFsChunk._id = createObjectId(gridFsChunk);
-	//TODO createObjectId nutzen, sobald diese umgestellt ist
-	gridFsChunk.files_id = new ObjectId(gridFsChunk.files_id.$oid);
-	gridFsChunk.data = createBinData(gridFsChunk.data);
-}
-
-function parseVorgangData(data) {
-	data.forEach(vorgang => parseVorgang(vorgang));
-	return data;
-}
-
-function parseVorgang(vorgang) {
-	vorgang._id = createObjectId(vorgang);
-	vorgang.createdAt = createDate(vorgang.createdAt);
-
-	vorgang.eingangs.forEach(eingang => parseEingang(eingang));
-
-	if (vorgang.wiedervorlages) {
-		vorgang.wiedervorlages.forEach(wiedervorlage => parseWiedervorlage(wiedervorlage));
-	}
-	if(vorgang.kommentars){
-		vorgang.kommentars.forEach(kommentar => parseKommentar(kommentar));
-	}
-}
-
-function parseEingang(eingang) {
-	eingang.header.createdAt = createDate(eingang.header.createdAt);
-
-	if (eingang.attachments) {
-		eingang.attachments.forEach(attachment => parseAttachment(attachment));
-	}
-	if (eingang.representations) {
-		eingang.representations.forEach(representation => parseRepresentations(representation));
-	}
-}
-
-function parseAttachment(attachment) {
-	attachment.files[ 0 ].content = createBinData('');
-}
-
-function createBinData(encoded64Value){
-	return Binary(Buffer.from(encoded64Value, 'base64'), 0);
-}
-
-function parseRepresentations(representation) {
-	representation.content = createBinary(representation);
-}
-
-//TODO Code entfernen und stattdessen createBinData(value) nutzen
-function createBinary(field) {
-	return Binary(field.content.$binary.base64, 'base64');
-}
-
-function parseWiedervorlage(wiedervorlage) {
-	wiedervorlage.frist = createDate(wiedervorlage.frist);
-	wiedervorlage.createdAt = createDate(wiedervorlage.createdAt);
-}
-
-function parseKommentar(kommentar) {
-	kommentar.createdAt = createDate(kommentar.createdAt);
-}
-
-function createDate(field) {
-	return new Date(field.$date);
-}
-
-function parseVorgangAttachedItemData(vorgangAttachedItems){
-	vorgangAttachedItems.forEach(vorgangAttachedItem => parseVorgangAttachedItem(vorgangAttachedItem));
-	return vorgangAttachedItems;
-}
-
-function parseVorgangAttachedItem(parseVorgangAttachedItem) {
-	parseVorgangAttachedItem._id = createObjectId(parseVorgangAttachedItem);
-	parseVorgangAttachedItem.version = createNumberLong(parseVorgangAttachedItem.version);
-}
-
-function parseUserData(data) {
-	data.forEach(user => parseUser(user));
-	return data;
-}
-
-function parseUser(user) {
-	user._id = createObjectId(user);
-	user.createdAt = createDate(user.createdAt);
-}
-
-//TOOD Beschraenkung auf _id aufheben
-function createObjectId(field) {
-	return new ObjectId(field._id.$oid);
-}
-
-function createNumberLong(numberValue){
-	return Long.fromNumber(numberValue);
-}
-
-function insertIntoDatabase(config, collection, data) {
-	insert(getDatabaseUrl(config), getDatabase(config), collection, data);
-}
-
-function insertIntoUserManagerDatabase(config, collection, data){
-	insert(getUserManagerDatabaseUrl(config), getUserManagerDatabase(config), collection, data);
-}
-
-function insert(databaseUrl, databaseName, collection, data){
-	MongoClient.connect(databaseUrl, (error, connection) => {
-		console.log(`connect to ${databaseName} database with ${databaseUrl}`);
-		if (!error) {
-			console.log('success');
-			var db = connection.db(databaseName);
-
-			db.collection(collection).drop(() => {
-				db.createCollection(collection, (error) => handleCreateCollection(db, connection, collection, data, error));
-			});
-		} else {
-			console.log('fail', error);
-		}
-	});
-}
-
-function handleCreateCollection(db, connection, collection, data, error) {
-	if (error) {
-		console.log(`Fehler beim Erstellen der Collection "${collection}": `, error);
-	} else {
-		console.log(`Collection ${collection} erfolgreich erstellt`);
-		insertManyToDatabase(db, connection, collection, data);
-	}
-}
-
-function insertManyToDatabase(db, connection, collection, data) {
-	db.collection(collection).insertMany(data, (error) => handleInsertMany(connection, error));
-}
-
-function handleInsertMany(connection, error) {
-	if (error) {
-		console.log('Fehler beim Einlesen der Daten: ', error);
-	} else {
-		console.log('Die Daten wurden erfolgreich eingelesen.');
-	}
-	connection.close();
-}
-
-function dropCollectionsFromDatabase(config, collections) {
-	dropCollections(getDatabaseUrl(config), getDatabase(config), collections);
-}
-
-function getDatabaseUrl(config){
-	return config.env.dbUrl;
-}
-
-function getDatabase(config){
-	return config.env.database
-}
-
-function dropUserManagerCollectionsFromDatabase(config, collections){
-	dropCollections(getUserManagerDatabaseUrl(config), getUserManagerDatabase(config), collections);
-}
-
-function getUserManagerDatabaseUrl(config){
-	return config.env.userManager.dbUrl;
-}
-
-function getUserManagerDatabase(config){
-	return config.env.userManager.database;
-}
-
-function dropCollections(databaseUrl, databaseName, collections){
-	MongoClient.connect(databaseUrl, (error, connection) => {
-		if (!error) {
-			const db = connection.db(databaseName);
-			collections.forEach((oneCollection, index) => {
-				console.log('drop collection', oneCollection);
-				db.collection(oneCollection).drop(() => {
-					//CHECKME Ist die Abfrage notwendig?
-					if(index == collections.length){
-						console.log('close connection');
-						connection.close();
-					}
-				});
-			});
-		}
-	});
-}
-
-function countFiles(folderName): Promise<number> {
-	return new Promise((resolve, reject) => {
-		fs.readdir(folderName, (err, files) => {
-			if (err) {
-				return reject(err)
-			}
-
-			resolve(files.length)
-		})
-	})
-}
-
-function deleteFolder(folderName): void {
-	new Promise((resolve, reject) => {
-		rmdir(folderName, { maxRetries: 10, recursive: true }, (err) => {
-		  if (err) {
-			console.error(err)
-			return reject(err)
-		  }
-		  resolve(null)
-		})
-	  })
-}
\ No newline at end of file
diff --git a/goofy-client/apps/goofy-e2e/docker-compose.yml b/goofy-client/apps/goofy-e2e/docker-compose.yml
index 31c7707a16771124d617049f524badcd5f0914f4..3b0a0ea591d1afed116ba0810a7b3cd6e49ecdc6 100644
--- a/goofy-client/apps/goofy-e2e/docker-compose.yml
+++ b/goofy-client/apps/goofy-e2e/docker-compose.yml
@@ -39,10 +39,11 @@ services:
       - SPRING_DATA_MONGODB_HOST=ozg-mongodb
       - SPRING_PROFILES_ACTIVE=${SPRING_PROFILE:-dev,e2e}
       - logging_level_org_springframework_security=${LOGGING_LEVEL:-WARN}
-      - SPRING_ELASTICSEARCH_URIS=http://ozg-elastic:9200
-      - SPRING_ELASTICSEARCH_USERNAME=elastic
-      - SPRING_ELASTICSEARCH_PASSWORD=password
-      - KOP_ELASTICSEARCH_INDEX=e2e-test-index
+      - OZGCLOUD_ELASTICSEARCH_ADDRESS=ozg-elastic:9200
+      - OZGCLOUD_ELASTICSEARCH_USERNAME=elastic
+      - OZGCLOUD_ELASTICSEARCH_PASSWORD=password
+      - OZGCLOUD_ELASTICSEARCH_INDEX=e2e-test-index
+      - OZGCLOUD_ELASTICSEARCH_USESSL=false
       - GRPC_CLIENT_USER_MANAGER_ADDRESS=static://ozg-usermanager:9000
       - GRPC_CLIENT_USER_MANAGER_NEGOTIATION_TYPE=PLAINTEXT
       - KOP_USERMANAGER_URL=http://localhost:9092/migration/user
@@ -98,12 +99,14 @@ services:
       interval: 10s
       timeout: 10s
       retries: 5
+
   ozg-usermanager:
     image: docker.ozg-sh.de/user-manager:${USERMANAGER_DOCKER_IMAGE:-snapshot-latest}
     platform: linux/amd64
     environment:
       - QUARKUS_HTTP_CORS_ORIGINS=http://localhost:4300,http://127.0.0.1:4300,https://e2e.dev.by.ozg-cloud.de
       - QUARKUS_OIDC_AUTH_SERVER_URL=https://sso.dev.by.ozg-cloud.de/realms/by-e2e-local-dev
+      - QUARKUS_LOG_CONSOLE_JSON=false
       - QUARKUS_OIDC_CLIENT_ID=alfa
       - KOP_KEYCLOAK_API_USER=usermanagerapiuser
       - KOP_KEYCLOAK_API_PASSWORD= 
diff --git a/goofy-client/apps/goofy-e2e/src/e2e/main-tests/accessibility/vorgang-list.cy.ts b/goofy-client/apps/goofy-e2e/src/e2e/main-tests/accessibility/vorgang-list.cy.ts
index 3d241ea57ab838b9e1bd955a9130238c568a932f..8ada47b1edcf7e7d636abc0cd8361557663d35ad 100644
--- a/goofy-client/apps/goofy-e2e/src/e2e/main-tests/accessibility/vorgang-list.cy.ts
+++ b/goofy-client/apps/goofy-e2e/src/e2e/main-tests/accessibility/vorgang-list.cy.ts
@@ -4,9 +4,9 @@ import { VorgangSearchE2EComponent } from 'apps/goofy-e2e/src/components/vorgang
 import { VorgangViewsE2EComponent } from 'apps/goofy-e2e/src/components/vorgang/vorgang-views.e2e.component';
 import { HeaderE2EComponent } from 'apps/goofy-e2e/src/page-objects/header.po';
 import { MainPage, waitForSpinnerToDisappear } from 'apps/goofy-e2e/src/page-objects/main.po';
-import { getFormField, isKeyboardFocused, isMatFocused } from 'apps/goofy-e2e/src/support/angular.util';
+import { isKeyboardFocused } from 'apps/goofy-e2e/src/support/angular.util';
 import { dropCollections, pressTab } from 'apps/goofy-e2e/src/support/cypress-helper';
-import { exist } from 'apps/goofy-e2e/src/support/cypress.util';
+import { exist, haveFocus } from 'apps/goofy-e2e/src/support/cypress.util';
 import { getUserManagerUserSabine, initUsermanagerUsers, loginAsSabine } from 'apps/goofy-e2e/src/support/user-util';
 
 describe('VorgangList Page', () => {
@@ -54,7 +54,7 @@ describe('VorgangList Page', () => {
 			it('should focus search field', () => {
 				pressTab();
 
-				isMatFocused(getFormField(vorgangSearch.getForm()));
+				haveFocus(vorgangSearch.getInput());
 			})
 
 			it('should focus help menu icon', () => {
diff --git a/goofy-client/apps/goofy-e2e/src/e2e/main-tests/interceptor/interceptor-server-error.cy.ts b/goofy-client/apps/goofy-e2e/src/e2e/main-tests/interceptor/interceptor-server-error.cy.ts
index bbac0d37ed2ce91377bcd6da2b872ca4e0de9f6a..e57681f1ff5a596a9f12b28123f2e9ffe69f8531 100644
--- a/goofy-client/apps/goofy-e2e/src/e2e/main-tests/interceptor/interceptor-server-error.cy.ts
+++ b/goofy-client/apps/goofy-e2e/src/e2e/main-tests/interceptor/interceptor-server-error.cy.ts
@@ -65,7 +65,6 @@ describe('Interceptor Server Error', () => {
 
 		it('should show page', () => {
 			vorgangList.getListItem(vorgang.name).getRoot().click();
-			waitForSpinnerToDisappear();
 
 			waitOfInterceptor(interceptor).then(interception => {
 				assert(interception.response.statusCode, statusCode.toString());
diff --git a/goofy-client/apps/goofy-e2e/src/e2e/main-tests/loesch-anforderung/endgueltig-loeschen.cy.ts b/goofy-client/apps/goofy-e2e/src/e2e/main-tests/loesch-anforderung/endgueltig-loeschen.cy.ts
index f3588c671c47d3c7029f50e2f54434dce166ae86..18eba64a91139e1f089a1ce399f8729e5f95ba9b 100644
--- a/goofy-client/apps/goofy-e2e/src/e2e/main-tests/loesch-anforderung/endgueltig-loeschen.cy.ts
+++ b/goofy-client/apps/goofy-e2e/src/e2e/main-tests/loesch-anforderung/endgueltig-loeschen.cy.ts
@@ -105,7 +105,8 @@ describe('Vorgang endgültig löschen', () => {
 		})
 	})
 
-	describe('Endgültig Löschen (ludwig löscht den Vorgang für den die sabine die Löschanforderung gestellt hat)', () => {
+	// TODO Warum exakt derselbe Test nochmal, nur mit objectIds[2] anstelle objectIds[1]?
+	describe.skip('Endgültig Löschen (ludwig löscht den Vorgang für den die sabine die Löschanforderung gestellt hat)', () => {
 
 		before(() => {
 			initVorgang(vorgangZuLoeschen);
diff --git a/goofy-client/apps/goofy-e2e/src/e2e/main-tests/vorgang-list/vorgang-list.search.cy.ts b/goofy-client/apps/goofy-e2e/src/e2e/main-tests/vorgang-list/vorgang-list.search.cy.ts
index 1e7f6eb1e7c108eeb80bba03550c68078ed89a36..977ce30f2e623f7661b02f9ea3ad8ed672bfbfaf 100644
--- a/goofy-client/apps/goofy-e2e/src/e2e/main-tests/vorgang-list/vorgang-list.search.cy.ts
+++ b/goofy-client/apps/goofy-e2e/src/e2e/main-tests/vorgang-list/vorgang-list.search.cy.ts
@@ -54,15 +54,19 @@ describe('VorgangList Suche', () => {
 		const vorgangToStay: VorgangE2E = { ...createVorgang(), name: 'VorgangToStay', eingangs: [eingang], assignedTo: getUserSabineInternalId() };
 
 		const vorgangToDisappear: VorgangE2E = { ...buildVorgang(objectIds[0], 'VorgangToDisappear'), status: VorgangStatusE2E.NEU };
+		const vorgangHyphen: VorgangE2E = { ...buildVorgang(objectIds[1], 'Vorgang-mit-Bindestrich'), status: VorgangStatusE2E.NEU };
+		const vorgangWOHyphen: VorgangE2E = { ...buildVorgang(objectIds[2], 'Vorgang mit Leerzeichen'), status: VorgangStatusE2E.NEU };
 
 		const vorgangStayInList: VorgangListItemE2EComponent = vorgangList.getListItem(vorgangToStay.name);
 		const vorgangDisappearInList: VorgangListItemE2EComponent = vorgangList.getListItem(vorgangToDisappear.name);
+		const vorgangHyphenInList: VorgangListItemE2EComponent = vorgangList.getListItem(vorgangHyphen.name);
+		const vorgangWOHyphenInList: VorgangListItemE2EComponent = vorgangList.getListItem(vorgangWOHyphen.name);
 
 		const userSabine: UserE2E = getUserSabine();
 
 		before(() => {
-			initVorgaenge([vorgangToStay, vorgangToDisappear]);
-			initSearchIndex([vorgangToStay, vorgangToDisappear]);
+			initVorgaenge([vorgangToStay, vorgangToDisappear, vorgangHyphen, vorgangWOHyphen]);
+			initSearchIndex([vorgangToStay, vorgangToDisappear, vorgangHyphen, vorgangWOHyphen]);
 			initUsermanagerUsers([getUserManagerUserSabine()]);
 
 			loginAsSabine();
@@ -84,6 +88,64 @@ describe('VorgangList Suche', () => {
 			notExist(vorgangDisappearInList.getRoot());
 		})
 
+		describe('Search for partial strings...', () => {
+			it ('should find partial string at the beginning', () => {
+				doSearchWith('VorgangToS');
+				waitForSpinnerToDisappear();
+
+				exist(vorgangStayInList.getRoot());
+			})
+
+			it ('should find partial string in the middle', () => {
+				doSearchWith('gangToSt');
+				waitForSpinnerToDisappear();
+
+				exist(vorgangStayInList.getRoot());
+			})
+
+			it ('should find partial string at the end, case insensitive', () => {
+				doSearchWith('toStay');
+				waitForSpinnerToDisappear();
+
+				exist(vorgangStayInList.getRoot());
+			})
+
+		})
+
+		describe ('Search with hyphen', () => {
+			it ('should find entry with hyphen', () => {
+				doSearchWith('Vorgang-mit');
+				waitForSpinnerToDisappear();
+
+				exist(vorgangHyphenInList.getRoot());
+				notExist(vorgangWOHyphenInList.getRoot());
+			})
+
+			it ('should find entry without hyphen', () => {
+				doSearchWith('Vorgang mit');
+				waitForSpinnerToDisappear();
+
+				notExist(vorgangHyphenInList.getRoot());
+				exist(vorgangWOHyphenInList.getRoot());
+			})
+		})
+
+		describe ('Search using AND operator', () => {
+			it ('should find entry with all matches', () => {
+				doSearchWith('Vorgang mit Leerzeichen');
+				waitForSpinnerToDisappear();
+
+				exist(vorgangWOHyphenInList.getRoot());
+			})
+
+			it ('should not find entry when using additional words', () => {
+				doSearchWith('Vorgang mit als Leerzeichen');
+				waitForSpinnerToDisappear();
+
+				notExist(vorgangWOHyphenInList.getRoot());
+			})
+		})
+
 		describe('navigate with filtered list to vorgang detail', () => {
 
 			beforeEach(() => {
@@ -442,6 +504,7 @@ describe('VorgangList Suche', () => {
 	})
 
 
+
 	function doSearchWith(searchBy: string): void {
 		enterWith(vorgangSearch.getInput(), searchBy);
 	}
diff --git a/goofy-client/apps/goofy-e2e/src/e2e/main-tests/wiedervorlage-attachment/wiedervorlage-attachment.cy.ts b/goofy-client/apps/goofy-e2e/src/e2e/main-tests/wiedervorlage-attachment/wiedervorlage-attachment.cy.ts
index f3f81417223f0b351ef9711bd9644e8a644960e1..8d25b11950bd3be02aa1dd0048245a2a7b732985 100644
--- a/goofy-client/apps/goofy-e2e/src/e2e/main-tests/wiedervorlage-attachment/wiedervorlage-attachment.cy.ts
+++ b/goofy-client/apps/goofy-e2e/src/e2e/main-tests/wiedervorlage-attachment/wiedervorlage-attachment.cy.ts
@@ -25,14 +25,14 @@ import { AttachmentContainerE2EComponent, AttachmentListE2EComponent } from 'app
 import { WiedervorlageSubnavigationE2EComponent } from 'apps/goofy-e2e/src/components/wiedervorlage/wiedervorlage-subnavigation';
 import { BinaryFileSnackbarMessageE2E } from 'apps/goofy-e2e/src/model/binary-file';
 import { WiedervorlageE2E } from 'apps/goofy-e2e/src/model/wiedervorlage';
-import { dropCollections, readFileFromDownloads } from 'apps/goofy-e2e/src/support/cypress-helper';
+import { dropCollections, readFileFromDownloads, wait } from 'apps/goofy-e2e/src/support/cypress-helper';
 import { initVorgangAttachedItem } from 'apps/goofy-e2e/src/support/vorgang-attached-item-util';
 import { SnackBarE2EComponent } from '../../../components/ui/snackbar.e2e.component';
 import { VorgangListE2EComponent } from '../../../components/vorgang/vorgang-list.e2e.component';
 import { WiedervorlageInVorgangE2EComponent } from '../../../components/wiedervorlage/wiedervorlage-in-vorgang.e2e.component';
 import { WiedervorlageE2EComponent } from '../../../components/wiedervorlage/wiedervorlage-page.e2e.component';
 import { VorgangE2E } from '../../../model/vorgang';
-import { MainPage, waitForSpinnerToDisappear, waitforSpinnerToAppear } from '../../../page-objects/main.po';
+import { MainPage, waitForSpinnerToDisappear } from '../../../page-objects/main.po';
 import { VorgangPage } from '../../../page-objects/vorgang.po';
 import { WiedervorlagePage } from '../../../page-objects/wiedervorlage.po';
 import { containClass, contains, exist, haveLength, notContainClass, notExist } from '../../../support/cypress.util';
@@ -233,9 +233,9 @@ describe('Wiedervorlage attachments', () => {
 		const wiedervorlageComp: WiedervorlageInVorgangE2EComponent = wiedervorlageContainerInVorgang.getWiedervorlage(WIEDERVORLAGE_WITH_ATTACHMENTS_BETREFF);
 
 		it('should open wiedervorlage page', () => {
+			wait(500);
 			wiedervorlageComp.getLink().click();
 
-			waitforSpinnerToAppear();
 			waitForSpinnerToDisappear();
 
 			exist(attachmentList.getItem(TEST_FILE_WITH_CONTENT).getRoot());
@@ -244,7 +244,6 @@ describe('Wiedervorlage attachments', () => {
 		it('should mark as erledigt', () => {
 			subnavigation.erledigen();
 
-			waitforSpinnerToAppear();
 			waitForSpinnerToDisappear();
 
 			containClass(wiedervorlageContainer.getStatusDot(), 'erledigt');
@@ -260,7 +259,6 @@ describe('Wiedervorlage attachments', () => {
 		it('should mark as open', () => {
 			subnavigation.wiedereroeffnen();
 
-			waitforSpinnerToAppear();
 			waitForSpinnerToDisappear();
 
 			notContainClass(wiedervorlageContainer.getStatusDot(), 'erledigt');
diff --git a/goofy-client/apps/goofy-e2e/src/e2e/main-tests/wiedervorlage/wiedervorlage.cy.ts b/goofy-client/apps/goofy-e2e/src/e2e/main-tests/wiedervorlage/wiedervorlage.cy.ts
index bf77d79dacff2e909c12074011363e1d445e68b4..45c8b354131803e75927e39787f1909a53eb8eb0 100644
--- a/goofy-client/apps/goofy-e2e/src/e2e/main-tests/wiedervorlage/wiedervorlage.cy.ts
+++ b/goofy-client/apps/goofy-e2e/src/e2e/main-tests/wiedervorlage/wiedervorlage.cy.ts
@@ -33,7 +33,7 @@ import { VorgangE2E } from '../../../model/vorgang';
 import { MainPage, waitForSpinnerToDisappear } from '../../../page-objects/main.po';
 import { VorgangPage } from '../../../page-objects/vorgang.po';
 import { WiedervorlagePage } from '../../../page-objects/wiedervorlage.po';
-import { dropCollections } from '../../../support/cypress-helper';
+import { dropCollections, wait } from '../../../support/cypress-helper';
 import { exist, haveText, haveValue, notExist } from '../../../support/cypress.util';
 import { MessagesE2E } from '../../../support/messages';
 import { formatDateLocal } from '../../../support/tech.util';
@@ -165,6 +165,7 @@ describe('Wiedervorlage', () => {
 		it('should open Wiedervorlage-Page by click on wiedervorlage ', () => {
 			const wiedervorlageInVorgang: WiedervorlageInVorgangE2EComponent = vorgangPage.getWiedervorlagenContainer().getWiedervorlage(wiedervorlageBetreff);
 
+			wait(500);
 			wiedervorlageInVorgang.getLink().click();
 			waitForSpinnerToDisappear();
 
diff --git a/goofy-client/apps/goofy-e2e/src/e2e/main-tests/wiedervorlage/wiedervorlage.erledigen.cy.ts b/goofy-client/apps/goofy-e2e/src/e2e/main-tests/wiedervorlage/wiedervorlage.erledigen.cy.ts
index 000e8fb12d3357f5360bc3cc3f00678a289a0c65..f9a7d8593f4e6a546c4c9e12a312b9290be4df5b 100644
--- a/goofy-client/apps/goofy-e2e/src/e2e/main-tests/wiedervorlage/wiedervorlage.erledigen.cy.ts
+++ b/goofy-client/apps/goofy-e2e/src/e2e/main-tests/wiedervorlage/wiedervorlage.erledigen.cy.ts
@@ -98,6 +98,7 @@ describe('Wiedervorlage erledigen/wiedereroeffnen', () => {
 		it('should open wiedervorlage on click', () => {
 			exist(wiedervorlage.getRoot());
 
+			wait(500);
 			wiedervorlage.getLink().click();
 			waitForSpinnerToDisappear();
 
@@ -135,7 +136,7 @@ describe('Wiedervorlage erledigen/wiedereroeffnen', () => {
 		const wiedervorlage: WiedervorlageInVorgangE2EComponent = wiedervorlageContainerInVorgang.getWiedervorlage(wiedervorlageZumWiedereroeffnen.betreff);
 
 		it('should open wiedervorlage on click', () => {
-			wait(1000);
+			wait(500);
 			wiedervorlage.getLink().click();
 			waitForSpinnerToDisappear();
 
@@ -173,6 +174,7 @@ describe('Wiedervorlage erledigen/wiedereroeffnen', () => {
 		const wiedervorlage: WiedervorlageInVorgangE2EComponent = wiedervorlageContainerInVorgang.getWiedervorlage(wiedervorlageZumWiedereroeffnen.betreff);
 
 		it('should open wiedervorlage on click', () => {
+			wait(500);
 			wiedervorlage.getLink().click();
 
 			waitForSpinnerToDisappear();
@@ -277,6 +279,7 @@ describe('Wiedervorlage erledigen/wiedereroeffnen', () => {
 		})
 
 		it('should mark as erledigt', () => {
+			wait(500);
 			wiedervorlage.getLink().click();
 			waitForSpinnerToDisappear();
 			subnavigation.erledigen();
diff --git a/goofy-client/apps/goofy-e2e/src/support/commands.ts b/goofy-client/apps/goofy-e2e/src/support/commands.ts
index 69700be30367bfac9a89f1c673ea2283f4318c62..7ee49c952b9212d5f85a12852ec954b71951e011 100644
--- a/goofy-client/apps/goofy-e2e/src/support/commands.ts
+++ b/goofy-client/apps/goofy-e2e/src/support/commands.ts
@@ -1,3 +1,4 @@
+
 /*
  * Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den
  * Ministerpräsidenten des Landes Schleswig-Holstein
@@ -21,6 +22,53 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
+enum HttpMethod {
+	POST = 'POST',
+	GET = 'GET'
+}
+
+interface HttpHeader {
+	[headerKey: string]: string
+}
+
+const DATA_TEST_ID: string = 'data-test-id';
+const DATA_TEST_CLASS: string = 'data-test-class';
+
+const ACCES_TOKEN: string = 'access_token';
+const ID_TOKEN: string = 'id_token';
+
+enum Header {
+	CONTENT_TYPE = 'Content-Type',
+	AUTHORIZATION = 'Authorization'
+}
+
+const CYPRESS_CONFIG_BASE_URL: unknown = 'baseUrl';
+
+enum CypressEnv {
+	KEYCLOAK_CLIENT = 'keycloakClient',
+	KEYCLOAK_REALM = 'keycloakRealm',
+	KEYCLOAK_URL = 'keycloakUrl',
+	SEARCH = 'search'
+}
+
+const CONTENT_TYPE_HEADER_VALUE: string = 'application/x-www-form-urlencoded';
+
+interface SearchIndex {
+	vorgangId: string,
+	vorgangName: string,
+	vorgangNummer: string,
+	createdAt: string,
+	antragstellerName: string,
+	antragstellerVorname: string,
+	status: string,
+	organisationseinheitenId: string,
+	aktenzeichen: string,
+	assignedTo: string,
+	_class: string
+}
+
+const SEARCH_INDEX_CLASS: string = 'de.itvsh.ozg.pluto.common.search.IndexedVorgang';
+
 declare namespace Cypress {
 	interface Chainable<Subject> {
 		getTestElementWithOid(oid: string, ...args);
@@ -36,12 +84,13 @@ declare namespace Cypress {
 	}
 }
 
+
 Cypress.Commands.add('getTestElement', (selector, ...args) => {
-	return cy.get(`[data-test-id~="${selector}"]`, ...args)
+	return cy.get(`[${DATA_TEST_ID}~="${selector}"]`, ...args)
 })
 
 Cypress.Commands.add('getTestElementWithClass', (selector, ...args) => {
-	return cy.get(`[data-test-class="${selector}"]`, ...args)
+	return cy.get(`[${DATA_TEST_CLASS}="${selector}"]`, ...args)
 })
 
 Cypress.Commands.add('getTestElementWithOid', (oid, ...args) => {
@@ -49,63 +98,73 @@ Cypress.Commands.add('getTestElementWithOid', (oid, ...args) => {
 })
 
 Cypress.Commands.add('findTestElementWithClass', { prevSubject: true }, (subject: any, selector) => {
-	return subject.find(`[data-test-class="${selector}"]`)
+	return subject.find(`[${DATA_TEST_CLASS}="${selector}"]`)
 })
 
 Cypress.Commands.add('findElement', { prevSubject: true }, (subject: any, selector) => {
 	return subject.find(selector);
 })
 
-Cypress.Commands.add('login', (user, password) => {
+Cypress.Commands.add('login', (user: string, password: string) => {
 	cy.session(user, () => {
-		cy.request({
-			method: 'POST',
-			followRedirect: false,
-			url: `${getKeycloakBaseRealmUrl()}/token`,
-			headers: {
-				'Content-Type': 'application/x-www-form-urlencoded'
-			},
-			body: {
-				client_id: Cypress.env('keycloakClient'),
-				username: user,
-				password: password,
-				grant_type: 'password',
-				redirect_uri: Cypress.config('baseUrl'),
-				response_mode: 'fragment',
-				response_type: 'code',
-				scope: 'openid'
-			}
-		}).then(response => {
-			const authorization: any = `bearer ${response.body.access_token}`;
-			cy.visit('', authorization);
-
-			window.sessionStorage.setItem('access_token', response.body.access_token);
-			window.sessionStorage.setItem('id_token', response.body.id_token);
-
-			cy.setCookie('XSRF-TOKEN', response.body.session_state);
-		});
+		cy.request(buildLoginRequest(user, password)).then(response => handleLoginResponse(response));
 	});
 })
 
+function buildLoginRequest(user: string, password: string): any {
+	return {
+		method: HttpMethod.POST,
+		followRedirect: false,
+		url: `${getKeycloakBaseRealmUrl()}/token`,
+		headers: {
+			[Header.CONTENT_TYPE]: CONTENT_TYPE_HEADER_VALUE
+		},
+		body: buildLoginRequestBody(user, password)
+	}
+}
+
+function buildLoginRequestBody(user: string, password: string): any {
+	return {
+		client_id: Cypress.env(CypressEnv.KEYCLOAK_CLIENT),
+		username: user,
+		password: password,
+		grant_type: 'password',
+		redirect_uri: Cypress.config(CYPRESS_CONFIG_BASE_URL),
+		response_mode: 'fragment',
+		response_type: 'code',
+		scope: 'openid'
+	}
+}
+
+function handleLoginResponse(response): void {
+	const authorization: any = `bearer ${response.body.access_token}`;
+	cy.visit('', authorization);
+
+	window.sessionStorage.setItem(ACCES_TOKEN, response.body.access_token);
+	window.sessionStorage.setItem(ID_TOKEN, response.body.id_token);
+
+	cy.setCookie('XSRF-TOKEN', response.body.session_state);
+}
+
 Cypress.Commands.add('getUserInfo', () => {
 	return cy.request({
-		method: 'GET',
+		method: HttpMethod.GET,
 		url: `${getKeycloakBaseRealmUrl()}/userinfo`,
 		headers: {
-			Authorization: `bearer ${window.sessionStorage.getItem('access_token')}`
+			[Header.AUTHORIZATION]: `bearer ${window.sessionStorage.getItem(ACCES_TOKEN)}`
 		}
 	});
 })
 
 Cypress.Commands.add('logout', () => {
 	cy.request({
-		method: 'GET',
+		method: HttpMethod.GET,
 		url: `${getKeycloakBaseRealmUrl()}/logout`,
 		headers: {
-			'Content-Type': 'application/x-www-form-urlencoded'
+			[Header.CONTENT_TYPE]: CONTENT_TYPE_HEADER_VALUE
 		},
 		body: {
-			refresh_token: window.sessionStorage.getItem('id_token')
+			refresh_token: window.sessionStorage.getItem(ID_TOKEN)
 		},
 		failOnStatusCode: false
 	}).then(() => {
@@ -116,62 +175,62 @@ Cypress.Commands.add('logout', () => {
 })
 
 function getKeycloakBaseRealmUrl(): string {
-	return `${Cypress.env('keycloakUrl')}realms/${Cypress.env('keycloakRealm')}/protocol/openid-connect`;
+	return `${Cypress.env(CypressEnv.KEYCLOAK_URL)}realms/${Cypress.env(CypressEnv.KEYCLOAK_REALM)}/protocol/openid-connect`;
 }
 
 Cypress.Commands.add('addVorgangToSearchIndex', (vorgang) => {
 	cy.request({
-		method: 'POST',
+		method: HttpMethod.POST,
 		url: `${buildSearchIndexPostUrl()}/_doc/${vorgang._id.$oid}`,
 		headers: buildAuthorizationHeader(),
 		body: buildSearchIndexBody(vorgang)
 	});
 })
 
-function buildSearchIndexBody(vorgang) {
+function buildSearchIndexBody(vorgang: any): SearchIndex {
 	return {
-		'_class': 'de.itvsh.ozg.pluto.common.search.IndexedVorgang',
-		'vorgangId': vorgang._id.$oid,
-		'vorgangName': vorgang.name,
-		'vorgangNummer': vorgang.nummer,
-		'createdAt': vorgang.createdAt.$date,
-		'antragstellerName': vorgang.eingangs[0].antragsteller.nachname,
-		'antragstellerVorname': vorgang.eingangs[0].antragsteller.vorname,
-		'status': vorgang.status,
-		'organisationseinheitenId': vorgang.eingangs[0].zustaendigeStelle.organisationseinheitenId,
-		'aktenzeichen': vorgang.aktenzeichen,
-		'assignedTo': vorgang.assignedTo
+		vorgangId: vorgang._id.$oid,
+		vorgangName: vorgang.name,
+		vorgangNummer: vorgang.nummer,
+		createdAt: vorgang.createdAt.$date,
+		antragstellerName: vorgang.eingangs[0].antragsteller.nachname,
+		antragstellerVorname: vorgang.eingangs[0].antragsteller.vorname,
+		status: vorgang.status,
+		organisationseinheitenId: vorgang.eingangs[0].zustaendigeStelle.organisationseinheitenId,
+		aktenzeichen: vorgang.aktenzeichen,
+		assignedTo: vorgang.assignedTo,
+		_class: SEARCH_INDEX_CLASS,
 	};
 }
 
 Cypress.Commands.add('removeAllDocumentsFromSearchIndex', () => {
 	cy.request({
-		method: 'POST',
+		method: HttpMethod.POST,
 		url: `${buildSearchIndexPostUrl()}/_delete_by_query`,
 		headers: buildAuthorizationHeader(),
 		body: buildSearchIndexRemoveAllBody()
 	});
 })
 
-function buildSearchIndexPostUrl() {
-	const searchEnv = getSearchEnv();
+function buildSearchIndexPostUrl(): string {
+	const searchEnv: string = getSearchEnv();
 	return `${searchEnv['url']}/${searchEnv['index']}`;
 }
 
-function buildAuthorizationHeader() {
-	return { 'Authorization': `Basic ${buildToken()}` };
+function buildAuthorizationHeader(): HttpHeader {
+	return { [Header.AUTHORIZATION]: `Basic ${buildToken()}` };
 }
 
-function buildToken() {
-	const searchEnv = getSearchEnv();
+function buildToken(): string {
+	const searchEnv: string = getSearchEnv();
 	return btoa(`${searchEnv['user']}:${searchEnv['password']}`);
 }
 
-function getSearchEnv() {
-	return Cypress.env('search');
+function getSearchEnv(): string {
+	return Cypress.env(CypressEnv.SEARCH);
 }
 
-function buildSearchIndexRemoveAllBody() {
+function buildSearchIndexRemoveAllBody(): any {
 	return {
 		'query': {
 			'match_all': {}
diff --git a/goofy-client/apps/goofy-e2e/src/support/cypress-tasks.ts b/goofy-client/apps/goofy-e2e/src/support/cypress-tasks.ts
new file mode 100644
index 0000000000000000000000000000000000000000..6c6806b83b7e4cd4e2d8dbfcd48976a506dc6774
--- /dev/null
+++ b/goofy-client/apps/goofy-e2e/src/support/cypress-tasks.ts
@@ -0,0 +1,298 @@
+import { Long, MongoClient, ObjectId } from 'mongodb';
+
+const Binary = require('mongodb').Binary;
+
+module.exports = (on: any, config: any) => {
+	on('task', {
+		initCommandData({collection, data}) {
+			console.log('initCommandData');
+			insertIntoDatabase(config, collection, parseCommandData(data));
+			return 0;
+		},
+		initGridFsFileData({collection, data}) {
+			console.log('initGridFsFileData');
+			insertIntoDatabase(config, collection, parseGridFsFileData(data));
+			return 0;
+		},
+		initGridFsChunkData({collection, data}) {
+			console.log('initGridFsChunkData');
+			insertIntoDatabase(config, collection, parseGridFsChunkData(data));
+			return 0;
+		},
+		initVorgangData({collection, data}) {
+			console.log('initVorgangData');
+			insertIntoDatabase(config, collection, parseVorgangData(data));
+			return 0;
+		},
+		initVorgangAttachedItemData({collection, data}) {
+			console.log('initVorgangAttachedItemData');
+			insertIntoDatabase(config, collection, parseVorgangAttachedItemData(data));
+			return 0;
+		},
+		initUsermanagerData({collection, data}) {
+			console.log('initUsermanagerData');
+			insertIntoUserManagerDatabase(config, collection, parseUserData(data));
+			return 0;
+		},
+		dropCollections(collections) {
+			console.log('dropCollections: ', collections);
+			dropCollectionsFromDatabase(config, collections);
+			return 0;
+		},
+		dropUserManagerCollections(collections) {
+			console.log('dropUserManagerCollections: ', collections);
+			dropUserManagerCollectionsFromDatabase(config, collections);
+			return 0;
+		}
+	});
+
+	// Workaround für Angular 13 und Cypress mit Webpack 4,
+	// Siehe https://github.com/cypress-io/cypress/issues/19066#issuecomment-1012055705
+	// Entfernen, sobald Cypress Webpack 5 nutzt - https://github.com/cypress-io/cypress/issues/19555
+	// Ursache: Angular linker needed to link partial-ivy code,
+	//   see https://angular.io/guide/creating-libraries#consuming-partial-ivy-code-outside-the-angular-cli
+	// Fehlerbild:
+	//   - Anwendung läuft im Browser, aber nicht in Cypress.
+	//   - Fehlermeldung in Cypress: The injectable 'SystemDateTimeProvider' needs to be compiled using the JIT compiler, but '@angular/compiler' is not available.
+	// Lösung:
+	//   - NPM-Paket identifizieren, dass "SystemDateTimeProvider" enthält.
+	//   - NPM-Paket im "test" Attribut unten hinzufügen.
+	const webpackPreprocessor = require('@cypress/webpack-batteries-included-preprocessor');
+	const webpackOptions = webpackPreprocessor.defaultOptions.webpackOptions;
+
+	webpackOptions.module.rules.unshift({
+		test: /[/\\](@angular|@ngxp|angular-oauth2-oidc)[/\\].+\.m?js$/,
+		resolve: {
+			fullySpecified: false,
+		},
+		use: {
+			loader: 'babel-loader',
+			options: {
+				plugins: ['@angular/compiler-cli/linker/babel'],
+				compact: false,
+				cacheDirectory: true
+			}
+		}
+	});
+
+	on('file:preprocessor', webpackPreprocessor({
+		webpackOptions: webpackOptions,
+		typescript: require.resolve('typescript')
+	}));
+
+	return config;
+	// Ende - Workaround für Angular 13 und Cypress mit Webpack 4
+}
+
+function parseCommandData(commands) {
+	commands.forEach(command => parseCommand(command))
+	return commands;
+}
+
+function parseCommand(command) {
+	command.createdAt = createDate(command.createdAt);
+	if(command.finishedAt){
+		command.finishedAt = createDate(command.finishedAt);
+	}
+	command.relationVersion = createNumberLong(command.relationVersion);
+}
+
+function parseGridFsFileData(gridFsFiles) {
+	gridFsFiles.forEach(gridFsFile => parseGridFsFile(gridFsFile))
+	return gridFsFiles;
+}
+
+function parseGridFsFile(gridFsFile) {
+	gridFsFile._id = createObjectId(gridFsFile);
+	gridFsFile.length = createNumberLong(gridFsFile.length);
+	gridFsFile.uploadDate = createDate(gridFsFile.uploadDate);
+}
+
+function parseGridFsChunkData(gridFsChunks) {
+	gridFsChunks.forEach(gridFsChunk => parseGridFsChunk(gridFsChunk));
+	return gridFsChunks;
+}
+
+function parseGridFsChunk(gridFsChunk) {
+	gridFsChunk._id = createObjectId(gridFsChunk);
+	//TODO createObjectId nutzen, sobald diese umgestellt ist
+	gridFsChunk.files_id = new ObjectId(gridFsChunk.files_id.$oid);
+	gridFsChunk.data = createBinData(gridFsChunk.data);
+}
+
+function parseVorgangData(data) {
+	data.forEach(vorgang => parseVorgang(vorgang));
+	return data;
+}
+
+function parseVorgang(vorgang) {
+	vorgang._id = createObjectId(vorgang);
+	vorgang.createdAt = createDate(vorgang.createdAt);
+
+	vorgang.eingangs.forEach(eingang => parseEingang(eingang));
+
+	if (vorgang.wiedervorlages) {
+		vorgang.wiedervorlages.forEach(wiedervorlage => parseWiedervorlage(wiedervorlage));
+	}
+	if(vorgang.kommentars){
+		vorgang.kommentars.forEach(kommentar => parseKommentar(kommentar));
+	}
+}
+
+function parseEingang(eingang) {
+	eingang.header.createdAt = createDate(eingang.header.createdAt);
+
+	if (eingang.attachments) {
+		eingang.attachments.forEach(attachment => parseAttachment(attachment));
+	}
+	if (eingang.representations) {
+		eingang.representations.forEach(representation => parseRepresentations(representation));
+	}
+}
+
+function parseAttachment(attachment) {
+	attachment.files[ 0 ].content = createBinData('');
+}
+
+function createBinData(encoded64Value){
+	return Binary(Buffer.from(encoded64Value, 'base64'), 0);
+}
+
+function parseRepresentations(representation) {
+	representation.content = createBinary(representation);
+}
+
+//TODO Code entfernen und stattdessen createBinData(value) nutzen
+function createBinary(field) {
+	return Binary(field.content.$binary.base64, 'base64');
+}
+
+function parseWiedervorlage(wiedervorlage) {
+	wiedervorlage.frist = createDate(wiedervorlage.frist);
+	wiedervorlage.createdAt = createDate(wiedervorlage.createdAt);
+}
+
+function parseKommentar(kommentar) {
+	kommentar.createdAt = createDate(kommentar.createdAt);
+}
+
+function createDate(field) {
+	return new Date(field.$date);
+}
+
+function parseVorgangAttachedItemData(vorgangAttachedItems){
+	vorgangAttachedItems.forEach(vorgangAttachedItem => parseVorgangAttachedItem(vorgangAttachedItem));
+	return vorgangAttachedItems;
+}
+
+function parseVorgangAttachedItem(parseVorgangAttachedItem) {
+	parseVorgangAttachedItem._id = createObjectId(parseVorgangAttachedItem);
+	parseVorgangAttachedItem.version = createNumberLong(parseVorgangAttachedItem.version);
+}
+
+function parseUserData(data) {
+	data.forEach(user => parseUser(user));
+	return data;
+}
+
+function parseUser(user) {
+	user._id = createObjectId(user);
+	user.createdAt = createDate(user.createdAt);
+}
+
+//TOOD Beschraenkung auf _id aufheben
+function createObjectId(field) {
+	return new ObjectId(field._id.$oid);
+}
+
+function createNumberLong(numberValue){
+	return Long.fromNumber(numberValue);
+}
+
+function insertIntoDatabase(config, collection, data) {
+	insert(getDatabaseUrl(config), getDatabase(config), collection, data);
+}
+
+function insertIntoUserManagerDatabase(config, collection, data){
+	insert(getUserManagerDatabaseUrl(config), getUserManagerDatabase(config), collection, data);
+}
+
+function insert(databaseUrl, databaseName, collection, data){
+	MongoClient.connect(databaseUrl, (error, connection) => {
+		console.log(`connect to ${databaseName} database with ${databaseUrl}`);
+		if (!error) {
+			console.log('success');
+			var db = connection.db(databaseName);
+
+			db.collection(collection).drop(() => {
+				db.createCollection(collection, (error) => handleCreateCollection(db, connection, collection, data, error));
+			});
+		} else {
+			console.log('fail', error);
+		}
+	});
+}
+
+function handleCreateCollection(db, connection, collection, data, error) {
+	if (error) {
+		console.log(`Fehler beim Erstellen der Collection "${collection}": `, error);
+	} else {
+		console.log(`Collection ${collection} erfolgreich erstellt`);
+		insertManyToDatabase(db, connection, collection, data);
+	}
+}
+
+function insertManyToDatabase(db, connection, collection, data) {
+	db.collection(collection).insertMany(data, (error) => handleInsertMany(connection, error));
+}
+
+function handleInsertMany(connection, error) {
+	if (error) {
+		console.log('Fehler beim Einlesen der Daten: ', error);
+	} else {
+		console.log('Die Daten wurden erfolgreich eingelesen.');
+	}
+	connection.close();
+}
+
+function dropCollectionsFromDatabase(config, collections) {
+	dropCollections(getDatabaseUrl(config), getDatabase(config), collections);
+}
+
+function getDatabaseUrl(config){
+	return config.env.dbUrl;
+}
+
+function getDatabase(config){
+	return config.env.database
+}
+
+function dropUserManagerCollectionsFromDatabase(config, collections){
+	dropCollections(getUserManagerDatabaseUrl(config), getUserManagerDatabase(config), collections);
+}
+
+function getUserManagerDatabaseUrl(config){
+	return config.env.userManager.dbUrl;
+}
+
+function getUserManagerDatabase(config){
+	return config.env.userManager.database;
+}
+
+function dropCollections(databaseUrl, databaseName, collections){
+	MongoClient.connect(databaseUrl, (error, connection) => {
+		if (!error) {
+			const db = connection.db(databaseName);
+			collections.forEach((oneCollection, index) => {
+				console.log('drop collection', oneCollection);
+				db.collection(oneCollection).drop(() => {
+					//CHECKME Ist die Abfrage notwendig?
+					if(index == collections.length){
+						console.log('close connection');
+						connection.close();
+					}
+				});
+			});
+		}
+	});
+}
\ No newline at end of file
diff --git a/goofy-client/apps/goofy-e2e/src/support/cypress.util.ts b/goofy-client/apps/goofy-e2e/src/support/cypress.util.ts
index c37486aab81955a516338c2fd08ce5f240decb09..ee3a1ea7f04adbec0e2fbc08c692e6b6c7fa5130 100644
--- a/goofy-client/apps/goofy-e2e/src/support/cypress.util.ts
+++ b/goofy-client/apps/goofy-e2e/src/support/cypress.util.ts
@@ -48,6 +48,10 @@ export function haveValue(element: any, value: string): void {
 	element.should('have.value', value);
 }
 
+export function haveFocus(element: any): void {
+	element.should('have.focus');
+}
+
 export function mouseEnter(element: any): void {
 	element.trigger('mouseenter');
 }
diff --git a/goofy-client/apps/goofy-e2e/src/support/delete-old-reports.ts b/goofy-client/apps/goofy-e2e/src/support/delete-old-reports.ts
index 3a7e7d5170a0d442ac2272f1082c2f440ada2ca4..7e1fe4e63291541aca5faff95ceafd503f76d672 100644
--- a/goofy-client/apps/goofy-e2e/src/support/delete-old-reports.ts
+++ b/goofy-client/apps/goofy-e2e/src/support/delete-old-reports.ts
@@ -21,6 +21,6 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-const fs = require('fs')
+const fs = require('fs');
 
 fs.rmdirSync(`apps/goofy-e2e/reports/${process.env.REPORT_FOLDER}`, { recursive: true });
\ No newline at end of file
diff --git a/goofy-client/apps/goofy-e2e/src/support/pre-ea-report-merge.ts b/goofy-client/apps/goofy-e2e/src/support/pre-ea-report-merge.ts
index 656abb5c66310317a87aa181d77a0c6ed3838a8a..08d5f533e0192fe38759f724e2eb41984fea6fed 100644
--- a/goofy-client/apps/goofy-e2e/src/support/pre-ea-report-merge.ts
+++ b/goofy-client/apps/goofy-e2e/src/support/pre-ea-report-merge.ts
@@ -21,8 +21,8 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-const fs = require('fs')
+const fs = require('fs');
 
-if (fs.existsSync('apps/goofy-e2e/reports_einheitlicher-ansprechpartner/mochawesome-report/.jsons')) {
-	fs.rename('apps/goofy-e2e/reports_einheitlicher-ansprechpartner/mochawesome-report/.jsons', 'apps/goofy-e2e/reports_einheitlicher-ansprechpartner/mochawesome-report/jsons', () => { })
+if (fs.existsSync(`apps/goofy-e2e/reports_einheitlicher-ansprechpartner/mochawesome-report/.jsons`)) {
+	fs.rename(`apps/goofy-e2e/reports_einheitlicher-ansprechpartner/mochawesome-report/.jsons`, `apps/goofy-e2e/reports_einheitlicher-ansprechpartner/mochawesome-report/jsons`, () => { })
 }
\ No newline at end of file
diff --git a/goofy-client/apps/goofy-e2e/src/support/pre-merge.ts b/goofy-client/apps/goofy-e2e/src/support/pre-merge.ts
index 710c4513d9884794cf3050d31326c01490336a34..6ea856303c5a3675377b4df88b5e7fbdf19f9c38 100644
--- a/goofy-client/apps/goofy-e2e/src/support/pre-merge.ts
+++ b/goofy-client/apps/goofy-e2e/src/support/pre-merge.ts
@@ -21,7 +21,7 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-const fs = require('fs')
+const fs = require('fs');
 
 if (fs.existsSync(`apps/goofy-e2e/reports/${process.env.REPORT_FOLDER}/mochawesome-report/.jsons`)) {
 	fs.rename(`apps/goofy-e2e/reports/${process.env.REPORT_FOLDER}/mochawesome-report/.jsons`, `apps/goofy-e2e/reports/${process.env.REPORT_FOLDER}/mochawesome-report/jsons`, () => { })
diff --git a/goofy-client/apps/goofy-e2e/src/support/tech.util.ts b/goofy-client/apps/goofy-e2e/src/support/tech.util.ts
index fb41b54279a6218940dd985f5600cce9566dd0bb..f8fcc0bfe39b31c84546cc045d4ccde00e60de3c 100644
--- a/goofy-client/apps/goofy-e2e/src/support/tech.util.ts
+++ b/goofy-client/apps/goofy-e2e/src/support/tech.util.ts
@@ -77,7 +77,7 @@ export function replaceAllWhitespaces(value: string, replaceWith: string): strin
 }
 
 export function simpleTransliteration(value: string) {
-	return value.normalize('NFKD').replace(/[^-_\w]/g, '');
+	return value.normalize('NFKD').replace(/[^-A-Za-z0-9_]/g, '');
 }
 
 export function createDateToday(): string {
diff --git a/goofy-client/apps/goofy-e2e/tsconfig.json b/goofy-client/apps/goofy-e2e/tsconfig.json
index 4c5841de058b41112f526f8e9e7fbac5250450bd..2cdee4db8b30c135503582f5274a1387ec8cd70c 100644
--- a/goofy-client/apps/goofy-e2e/tsconfig.json
+++ b/goofy-client/apps/goofy-e2e/tsconfig.json
@@ -1,22 +1,28 @@
 {
 	"extends": "../../tsconfig.base.json",
 	"compilerOptions": {
-	  "sourceMap": false,
-	  "outDir": "../dist/out-tsc",
-	  "allowJs": true,
-	  "types": ["cypress", "node"],
-	  "forceConsistentCasingInFileNames": true,
-	  "strict": false,
-	  "noImplicitOverride": true,
-	  "noPropertyAccessFromIndexSignature": true,
-	  "noImplicitReturns": true,
-	  "noFallthroughCasesInSwitch": true
+		"sourceMap": false,
+		"outDir": "../dist/out-tsc",
+		"allowJs": true,
+		"types": ["cypress", "node"],
+		"forceConsistentCasingInFileNames": true,
+		"strict": false,
+		"noImplicitOverride": true,
+		"noPropertyAccessFromIndexSignature": true,
+		"noImplicitReturns": true,
+		"noFallthroughCasesInSwitch": true
 	},
-	"include": ["src/**/*.ts", "src/**/*.js", "cypress.config.ts"],
+	"include": [
+		"src/**/*.ts",
+		"src/**/*.js",
+		"cypress.config.ts",
+		"cypress-ci-main-tests.config.ts",
+		"cypress-ci-einheitlicher-ansprechpartner.config.ts"
+	],
 	"angularCompilerOptions": {
-	  "enableI18nLegacyMessageIdFormat": false,
-	  "strictInjectionParameters": true,
-	  "strictInputAccessModifiers": true,
-	  "strictTemplates": true
+		"enableI18nLegacyMessageIdFormat": false,
+		"strictInjectionParameters": true,
+		"strictInputAccessModifiers": true,
+		"strictTemplates": true
 	}
-  }
+}
diff --git a/goofy-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang/kommentar-list-item-in-vorgang/kommentar-list-item-in-vorgang.component.ts b/goofy-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang/kommentar-list-item-in-vorgang/kommentar-list-item-in-vorgang.component.ts
index a89cd0122c03a80556be442cc4f09dbac26161e6..df3208154642a8ac4f8c351dc665a92e5015cc78 100644
--- a/goofy-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang/kommentar-list-item-in-vorgang/kommentar-list-item-in-vorgang.component.ts
+++ b/goofy-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang/kommentar-list-item-in-vorgang/kommentar-list-item-in-vorgang.component.ts
@@ -23,10 +23,10 @@
  */
 import { Component, Input, OnInit } from '@angular/core';
 import { BinaryFileListResource } from '@goofy-client/binary-file-shared';
-import { KommentarLinkRel, KommentarListLinkRel, KommentarListResource, KommentarResource, KommentarService } from '@goofy-client/kommentar-shared';
-import { createEmptyStateResource, StateResource } from "@goofy-client/tech-shared";
-import { Observable, of } from 'rxjs';
+import { KommentarLinkRel, KommentarListResource, KommentarResource, KommentarService } from '@goofy-client/kommentar-shared';
+import { StateResource, createEmptyStateResource } from "@goofy-client/tech-shared";
 import { hasLink } from '@ngxp/rest';
+import { Observable, of } from 'rxjs';
 
 @Component({
 	selector: 'goofy-client-kommentar-list-item-in-vorgang',
diff --git a/goofy-client/libs/loesch-anforderung-shared/src/lib/+state/loesch-anforderung.actions.ts b/goofy-client/libs/loesch-anforderung-shared/src/lib/+state/loesch-anforderung.actions.ts
index c3a62b795e46767355136240ed7621ae7a31cda3..3cc1ebc16bab01635a685cc7199b60473a3765d9 100644
--- a/goofy-client/libs/loesch-anforderung-shared/src/lib/+state/loesch-anforderung.actions.ts
+++ b/goofy-client/libs/loesch-anforderung-shared/src/lib/+state/loesch-anforderung.actions.ts
@@ -12,10 +12,10 @@ export const loadLoeschAnforderung: TypedActionCreatorWithProps<VorgangWithEinga
 export const loadLoeschAnforderungSuccess: TypedActionCreatorWithProps<LoeschAnforderungProps> = createAction('[LoeschAnforderung] Load LoeschAnforderung Success', props<LoeschAnforderungProps>());
 export const loadLoeschAnforderungFailure: TypedActionCreatorWithProps<ApiErrorAction> = createAction('[LoeschAnforderung] Load LoeschAnforderung Failure', props<ApiErrorAction>());
 
-export interface loeschAnforderungZuruecknehmenFailedAndReloadVorgangFailureProps {
+export interface LoeschAnforderungZuruecknehmenFailedAndReloadVorgangFailureProps {
 	error: HttpErrorResponse,
 	overviewUrl: string
 }
 
 export const loeschAnforderungZuruecknehmenFailedAndReloadVorgangSuccess: TypedActionCreator = createAction('[LoeschAnforderung] LoeschAnforderung zurücknehmen reload vorgang success');
-export const loeschAnforderungZuruecknehmenFailedAndReloadVorgangFailure: TypedActionCreatorWithProps<loeschAnforderungZuruecknehmenFailedAndReloadVorgangFailureProps> = createAction('[LoeschAnforderung] LoeschAnforderung zurücknehmen reload vorgang failure', props<loeschAnforderungZuruecknehmenFailedAndReloadVorgangFailureProps>());
\ No newline at end of file
+export const loeschAnforderungZuruecknehmenFailedAndReloadVorgangFailure: TypedActionCreatorWithProps<LoeschAnforderungZuruecknehmenFailedAndReloadVorgangFailureProps> = createAction('[LoeschAnforderung] LoeschAnforderung zurücknehmen reload vorgang failure', props<LoeschAnforderungZuruecknehmenFailedAndReloadVorgangFailureProps>());
\ No newline at end of file
diff --git a/goofy-client/libs/loesch-anforderung-shared/src/lib/+state/loesch-anforderung.effects.ts b/goofy-client/libs/loesch-anforderung-shared/src/lib/+state/loesch-anforderung.effects.ts
index de14570bb3c540ae8ae4ba9da583725d405a2bba..8aeedfcb045ce309dad0d847d8d6dc92f1bda51f 100644
--- a/goofy-client/libs/loesch-anforderung-shared/src/lib/+state/loesch-anforderung.effects.ts
+++ b/goofy-client/libs/loesch-anforderung-shared/src/lib/+state/loesch-anforderung.effects.ts
@@ -9,7 +9,7 @@ import { hasLink } from '@ngxp/rest';
 import { of } from 'rxjs';
 import { catchError, filter, map, switchMap, tap } from 'rxjs/operators';
 import { isVorgangLoeschenCommand } from '../loesch-anforderung.util';
-import { loeschAnforderungZuruecknehmenFailedAndReloadVorgangFailureProps } from './loesch-anforderung.actions';
+import { LoeschAnforderungZuruecknehmenFailedAndReloadVorgangFailureProps } from './loesch-anforderung.actions';
 import { LoeschAnforderungRepository } from './loesch-anforderung.repository';
 
 import * as CommandActions from '../../../../command-shared/src/lib/+state/command.actions';
@@ -40,8 +40,8 @@ export class LoeschAnforderungEffects {
 	), { dispatch: false });
 
 	loeschAnforderungZuruecknehmenFailedAndReloadVorgangFailure$ = createEffect(() => this.actions$.pipe(ofType(LoeschAnforderungActions.loeschAnforderungZuruecknehmenFailedAndReloadVorgangFailure),
-		filter((props: loeschAnforderungZuruecknehmenFailedAndReloadVorgangFailureProps) => isNotFound(props.error.error.status)),
-		tap((props: loeschAnforderungZuruecknehmenFailedAndReloadVorgangFailureProps) => {
+		filter((props: LoeschAnforderungZuruecknehmenFailedAndReloadVorgangFailureProps) => isNotFound(props.error.error.status)),
+		tap((props: LoeschAnforderungZuruecknehmenFailedAndReloadVorgangFailureProps) => {
 			this.snackBarService.showInfo(LOESCH_ANFORDERUNG_ZURUECKNEHMEN_CONCURRENT_TO_DELETE_VORGANG_MESSAGE);
 			this.navigationService.navigate(props.overviewUrl);
 		})
diff --git a/goofy-client/libs/navigation/src/lib/build-info/build-info.component.scss b/goofy-client/libs/navigation/src/lib/build-info/build-info.component.scss
index 317e2628d4eec056d13bb3ba295c674fc2be3a9f..687bf9dc28611fe0de820edacad151dcd45114db 100644
--- a/goofy-client/libs/navigation/src/lib/build-info/build-info.component.scss
+++ b/goofy-client/libs/navigation/src/lib/build-info/build-info.component.scss
@@ -44,7 +44,6 @@ p {
 	margin: 0;
 	line-height: 1;
 	white-space: nowrap;
-	font-family: 'Roboto';
 	font-style: normal;
 	font-weight: 400;
 	font-size: 11px;
diff --git a/goofy-client/libs/tech-shared/src/lib/tech.util.ts b/goofy-client/libs/tech-shared/src/lib/tech.util.ts
index 49578dea0312b3342430c049d875ce6f772a0a70..1e77223d9318e59bb225991cf7a5d0bcdcfb969f 100644
--- a/goofy-client/libs/tech-shared/src/lib/tech.util.ts
+++ b/goofy-client/libs/tech-shared/src/lib/tech.util.ts
@@ -39,14 +39,6 @@ export function isEmptyObject(obj: any): boolean {
 	return Object.keys(obj).length === 0;
 }
 
-export function replaceAllWhitespaces(value: string, replaceWith: string) {
-	return value.replace(/ /g, replaceWith);
-}
-
-export function simpleTransliteration(value: string) {
-	return value.normalize('NFKD').replace(/[^-_\w]/g, '');
-}
-
 export function replacePlaceholders(text: string, placeholders: { [key: string]: string }): string {
 	let replaced = text;
 	Object.keys(placeholders).forEach(key => replaced = replacePlaceholder(replaced, key, placeholders[key]));
@@ -96,6 +88,14 @@ export function convertForDataTest(value: string): string {
 	return simpleTransliteration(value);
 }
 
+export function replaceAllWhitespaces(value: string, replaceWith: string) {
+	return value.replace(/ /g, replaceWith);
+}
+
+export function simpleTransliteration(value: string) {
+	return value.normalize('NFKD').replace(/[^-A-Za-z0-9_]/g, '');
+}
+
 export function getStringValue(value: null | undefined | string): string {
 	if (isNil(value)) {
 		return EMPTY_STRING;
diff --git a/goofy-client/libs/test-utils/src/lib/mocking.ts b/goofy-client/libs/test-utils/src/lib/mocking.ts
index e0f99e200bc81fb4bc7c73dc7c7d7e7ad33765f8..141db74e40b6275c057e8889b718015448889e6c 100644
--- a/goofy-client/libs/test-utils/src/lib/mocking.ts
+++ b/goofy-client/libs/test-utils/src/lib/mocking.ts
@@ -56,5 +56,5 @@ export function mockComponent(options: Component): Component {
 }
 
 export function mockClass(clazz: any): Mock<any> {
-	return clazz as jest.Mocked<typeof clazz>;
+	return clazz as jest.Mocked<typeof clazz>; //NOSONAR
 }
\ No newline at end of file
diff --git a/goofy-client/libs/ui/src/lib/ui/fixed-dialog/_fixed-dialog.theme.scss b/goofy-client/libs/ui/src/lib/ui/fixed-dialog/_fixed-dialog.theme.scss
index 677a82fcb5b52c9f5a4e0f62ada552b952b702bd..0b4c18dfae3bbfe602477119799a5a2b7bee7b18 100644
--- a/goofy-client/libs/ui/src/lib/ui/fixed-dialog/_fixed-dialog.theme.scss
+++ b/goofy-client/libs/ui/src/lib/ui/fixed-dialog/_fixed-dialog.theme.scss
@@ -73,7 +73,7 @@
 				min-height: initial;
 				overflow: hidden;
 				margin: 0;
-				padding: 0;
+				padding: 0 !important;
 
 				.button-bar-bottom {
 					height: 0;
diff --git a/goofy-client/libs/user-assistance/src/lib/help-menu/documentation/dowload-documentation-button/download-documentation-button.component.ts b/goofy-client/libs/user-assistance/src/lib/help-menu/documentation/dowload-documentation-button/download-documentation-button.component.ts
index cc44375e2821e8a51fff5d37f8a3e58b4b236e61..4e26419b8f4543755cb6bb677f0ca920d2291427 100644
--- a/goofy-client/libs/user-assistance/src/lib/help-menu/documentation/dowload-documentation-button/download-documentation-button.component.ts
+++ b/goofy-client/libs/user-assistance/src/lib/help-menu/documentation/dowload-documentation-button/download-documentation-button.component.ts
@@ -1,6 +1,6 @@
 import { Component, Input } from '@angular/core';
 
-const FILE_NAME_REGEX: string = '^.*\\/(.*.pdf)$';
+const FILE_NAME_REGEX: RegExp = /^.*\/(.*.pdf)$/;
 
 @Component({
 	selector: 'goofy-client-download-documentation-button',
diff --git a/goofy-client/package.json b/goofy-client/package.json
index f3cc6f84ca9355a8f5492610677586f2f2412ea0..2845ef85f7653a7c6373040601dba9ed5646e45a 100644
--- a/goofy-client/package.json
+++ b/goofy-client/package.json
@@ -34,12 +34,12 @@
 		"help": "nx help",
 		"favicon": "real-favicon generate favicon/faviconDescription.json favicon/faviconData.json src/favicon",
 		"cypress:run": "npx cypress run --project apps/goofy-e2e",
-		"cypress:run-main": "npx cypress run --project apps/goofy-e2e --config video=false,integrationFolder=./src/integration/main-tests",
-		"cypress:run-ea": "npx cypress run --project apps/goofy-e2e --config video=false,integrationFolder=./src/integration/einheitlicher-ansprechpartner",
+		"cypress:run-main": "npx cypress run --project apps/goofy-e2e --spec apps/goofy-e2e/src/e2e/main-tests",
+		"cypress:run-ea": "npx cypress run --project apps/goofy-e2e --spec apps/goofy-e2e/src/e2e/einheitlicher-ansprechpartner",
 		"cypress:version": "npx cypress version",
 		"cypress:install": "npx cypress install",
 		"cypress:open": "npx cypress open --project apps/goofy-e2e",
-		"cypress:ci-run": "npm run cypress:delete-old-reports --REPORT_FOLDER=${npm_config_report_folder} ; NO_COLOR=1 npm run cypress:run -- --config=${npm_config_config} ; test=$(echo \"$?\") ; npm run cypress:pre-merge --REPORT_FOLDER=${npm_config_report_folder} ; npm run cypress:generate-report --REPORT_FOLDER=${npm_config_report_folder} ; exit $test",
+		"cypress:ci-run": "npm run cypress:delete-old-reports --REPORT_FOLDER=${npm_config_report_folder} ; NO_COLOR=1 npm run cypress:run -- --config-file=${npm_config_config} ; test=$(echo \"$?\") ; npm run cypress:pre-merge --REPORT_FOLDER=${npm_config_report_folder} ; npm run cypress:generate-report --REPORT_FOLDER=${npm_config_report_folder} ; exit $test",
 		"cypress:delete-old-reports": "REPORT_FOLDER=${npm_config_report_folder} node apps/goofy-e2e/src/support/delete-old-reports.ts",
 		"cypress:pre-merge": "REPORT_FOLDER=${npm_config_report_folder} node apps/goofy-e2e/src/support/pre-merge.ts",
 		"cypress:generate-report": "npm run cypress:merge-report --REPORT_FOLDER=${npm_config_report_folder} ; npm run cypress:generate-html --REPORT_FOLDER=${npm_config_report_folder}",
diff --git a/goofy-client/pom.xml b/goofy-client/pom.xml
index d63ae820e5a084c655eede5de0f913b90d464bbc..0cda8691e2dce048d1d62f5c774a959e535f3019 100644
--- a/goofy-client/pom.xml
+++ b/goofy-client/pom.xml
@@ -30,7 +30,7 @@
 	<parent>
 		<groupId>de.itvsh.ozg</groupId>
 		<artifactId>goofy</artifactId>
-		<version>1.15.0-SNAPSHOT</version>
+		<version>1.16.0-SNAPSHOT</version>
 	</parent>
 
     <modelVersion>4.0.0</modelVersion>
@@ -54,83 +54,81 @@
                 </configuration>
             </plugin>
 
-            <plugin>
-                <groupId>org.codehaus.mojo</groupId>
-                <artifactId>exec-maven-plugin</artifactId>
-                <version>3.0.0</version>
-                <executions>
-
-                     <execution>
-                        <id>test-application</id>
-                        <phase>test</phase>
-                        <configuration>
-                            <workingDirectory>./</workingDirectory>
-                            <executable>npm</executable>
-                            <arguments>
-                                <argument>run</argument>
-                                <argument>test</argument>
-                            </arguments>
-                        </configuration>
-                        <goals>
-                            <goal>exec</goal>
-                        </goals>
-                    </execution>
-
-                    <execution>
-                        <id>build-application</id>
-                        <phase>compile</phase>
-                        <configuration>
-                            <workingDirectory>./</workingDirectory>
-                            <executable>npm</executable>
-                            <arguments>
-                                <argument>run</argument>
-                                <argument>ci-build</argument>
-                            </arguments>
-                        </configuration>
-                        <goals>
-                            <goal>exec</goal>
-                        </goals>
-                    </execution>
-                </executions>
-            </plugin>
-        </plugins>
-    </build>
+			<plugin>
+				<groupId>org.codehaus.mojo</groupId>
+				<artifactId>exec-maven-plugin</artifactId>
+				<version>3.0.0</version>
+				<executions>
+					<execution>
+						<id>test-application</id>
+						<phase>test</phase>
+						<configuration>
+							<workingDirectory>./</workingDirectory>
+							<executable>npm</executable>
+							<arguments>
+								<argument>run</argument>
+								<argument>test</argument>
+							</arguments>
+                            <skip>${skipTests}</skip>
+						</configuration>
+						<goals>
+							<goal>exec</goal>
+						</goals>
+					</execution>
+					<execution>
+						<id>build-application</id>
+						<phase>compile</phase>
+						<configuration>
+							<workingDirectory>./</workingDirectory>
+							<executable>npm</executable>
+							<arguments>
+								<argument>run</argument>
+								<argument>ci-build</argument>
+							</arguments>
+						</configuration>
+						<goals>
+							<goal>exec</goal>
+						</goals>
+					</execution>
+				</executions>
+			</plugin>
+		</plugins>
+	</build>
 
-    <profiles>
-        <profile>
-            <activation>
-                <property>
-                    <name>!skipNpmInstall</name>
-                </property>
-            </activation>
-            <id>npmInstall</id>
-            <build>
-                <plugins>
-                    <plugin>
-                        <groupId>org.codehaus.mojo</groupId>
-                        <artifactId>exec-maven-plugin</artifactId>
-                        <version>3.0.0</version>
-                        <executions>
-                            <execution>
-                                <id>install-dependencies</id>
-                                <phase>generate-sources</phase>
-                                <configuration>
-                                    <workingDirectory>./</workingDirectory>
-                                    <executable>npm</executable>
-                                    <arguments>
-                                        <argument>install</argument>
-                                        <argument>--legacy-peer-deps</argument>
-                                    </arguments>
-                                </configuration>
-                                <goals>
-                                    <goal>exec</goal>
-                                </goals>
-                            </execution>
-                        </executions>
-                    </plugin>
-                </plugins>
-            </build>
-        </profile>
-    </profiles>
+	<profiles>
+		<profile>
+			<activation>
+				<property>
+					<name>!skipNpmInstall</name>
+				</property>
+			</activation>
+			<id>npmInstall</id>
+			<build>
+				<plugins>
+					<plugin>
+						<groupId>org.codehaus.mojo</groupId>
+						<artifactId>exec-maven-plugin</artifactId>
+						<version>3.0.0</version>
+						<executions>
+							<execution>
+								<id>install-dependencies</id>
+								<phase>generate-sources</phase>
+								<configuration>
+									<workingDirectory>./</workingDirectory>
+									<executable>npm</executable>
+									<arguments>
+										<argument>install</argument>
+									</arguments>
+								</configuration>
+								<goals>
+									<goal>exec</goal>
+								</goals>
+							</execution>
+						</executions>
+					</plugin>
+				</plugins>
+			</build>
+		</profile>
+	</profiles>
 
 </project>
diff --git a/goofy-server/pom.xml b/goofy-server/pom.xml
index 3d10300f55b3f09e2044091cc76ea69c00caf813..28fe2d2e897585e351e34b1582aa06d4ded23936 100644
--- a/goofy-server/pom.xml
+++ b/goofy-server/pom.xml
@@ -4,7 +4,7 @@
   <parent>
     <groupId>de.itvsh.ozg</groupId>
     <artifactId>goofy</artifactId>
-    <version>1.15.0-SNAPSHOT</version>
+    <version>1.16.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>goofy-server</artifactId>
@@ -15,32 +15,27 @@
     <maven.compiler.source>${java.version}</maven.compiler.source>
     <maven.compiler.target>${java.version}</maven.compiler.target>
 
-    <spring-boot.build-image.imageName>docker.ozg-sh.de/goofy:build-latest</spring-boot.build-image.imageName>
-  </properties>
+		<spring-boot.build-image.imageName>docker.ozg-sh.de/goofy:build-latest</spring-boot.build-image.imageName>
+	</properties>
 
-  <dependencies>
+	<dependencies>
+		<dependency>
+			<groupId>de.itvsh.ozg</groupId>
+			<artifactId>alfa-service</artifactId>
+			<version>${project.version}</version>
+		</dependency>
 
-    <dependency>
-      <groupId>de.itvsh.ozg</groupId>
-      <artifactId>alfa-service</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>de.itvsh.ozg</groupId>
-      <artifactId>alfa-xdomea</artifactId>
-      <version>${project.version}</version>
-    </dependency>
+		<dependency>
+			<groupId>de.itvsh.ozg</groupId>
+			<artifactId>alfa-xdomea</artifactId>
+			<version>${project.version}</version>
+		</dependency>
 
-    <dependency>
-      <groupId>org.springframework.boot</groupId>
-      <artifactId>spring-boot-starter</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.springframework.boot</groupId>
-      <artifactId>spring-boot-starter-security</artifactId>
-    </dependency>
-
-  </dependencies>
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter</artifactId>
+		</dependency>
+	</dependencies>
 
   <build>
     <finalName>${project.artifactId}</finalName>
diff --git a/goofy-server/src/main/java/de/ozgcloud/alfa/AlfaServerApplication.java b/goofy-server/src/main/java/de/ozgcloud/alfa/AlfaServerApplication.java
index 38814989905b94b6a5996c4d32a92290e55d0fe6..54525b45e9a5b1363132efdcbad4ae8269df23f7 100644
--- a/goofy-server/src/main/java/de/ozgcloud/alfa/AlfaServerApplication.java
+++ b/goofy-server/src/main/java/de/ozgcloud/alfa/AlfaServerApplication.java
@@ -49,14 +49,14 @@ public class AlfaServerApplication {
 	}
 
 	@Bean
-	public FilterRegistrationBean<ForwardedHeaderFilter> forwardedHeaderFilter() {
+	FilterRegistrationBean<ForwardedHeaderFilter> forwardedHeaderFilter() {
 		FilterRegistrationBean<ForwardedHeaderFilter> bean = new FilterRegistrationBean<>();
 		bean.setFilter(new ForwardedHeaderFilter());
 		return bean;
 	}
 
 	@Bean
-	public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
+	ThreadPoolTaskExecutor threadPoolTaskExecutor() {
 		ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
 
 		executor.setThreadNamePrefix("async-");
@@ -65,12 +65,12 @@ public class AlfaServerApplication {
 	}
 
 	@Bean
-	public CallScope callScope() {
+	CallScope callScope() {
 		return new CallScope();
 	}
 
 	@Bean
-	public BeanFactoryPostProcessor beanFactoryPostProcessor(CallScope callScope) {
+	BeanFactoryPostProcessor beanFactoryPostProcessor(CallScope callScope) {
 		return new CallBeanFactoryPostProcessor(callScope);
 	}
 }
\ No newline at end of file
diff --git a/goofy-server/src/main/resources/application-dev.yml b/goofy-server/src/main/resources/application-dev.yml
index be7dc4d1adb0c218ef1d2c908b35b8fbd2142632..66b1bb57668a073ceaeab1e2d50c1f47ed7632fa 100644
--- a/goofy-server/src/main/resources/application-dev.yml
+++ b/goofy-server/src/main/resources/application-dev.yml
@@ -2,14 +2,14 @@ goofy:
   production: false
 
 keycloak:
-  auth-server-url: https://sso.dev.by.ozg-cloud.de
-  realm: by-kiel-dev
-  resource: alfa
+   auth-server-url: https://sso.dev.by.ozg-cloud.de		
+   realm: by-kiel-dev		
+   resource: alfa
 
 server:
   error:
     include-stacktrace: always
-    
+
 ozgcloud:
   feature:
      vorgang-export: true
diff --git a/goofy-server/src/main/resources/application-e2e.yml b/goofy-server/src/main/resources/application-e2e.yml
index 6b4c84428d26ff921ab8c233062ebd1b8837dce4..50cac7fbb8d11fe5c5ad23487bcdaed4b72a05d0 100644
--- a/goofy-server/src/main/resources/application-e2e.yml
+++ b/goofy-server/src/main/resources/application-e2e.yml
@@ -1,13 +1,11 @@
 keycloak:
   realm: by-e2e-local-dev
-  resource: alfa
-  
 kop:
   forwarding:
     lninfo:
       url: classpath:files/LandesnetzInfo.html
   user-manager:
-    url: http://localhost:9091
+    url: http://localhost:9092
     
 ozgcloud:
   feature:
@@ -15,4 +13,4 @@ ozgcloud:
      createBescheid: true
   user-assistance:
      documentation:
-        url: /assets/benutzerleitfaden/Benutzerleitfaden_2.5.pdf
\ No newline at end of file
+        url: /assets/benutzerleitfaden/benutzerleitfaden.pdf
\ No newline at end of file
diff --git a/goofy-server/src/main/resources/application-local.yml b/goofy-server/src/main/resources/application-local.yml
index 4f0e0f12aab2ad4c7fd4c89d4263a8a03ccaa8e2..48b03024d8f9f74e8c4aa72a27dadeb853eb6739 100644
--- a/goofy-server/src/main/resources/application-local.yml
+++ b/goofy-server/src/main/resources/application-local.yml
@@ -7,11 +7,6 @@ logging:
 goofy:
   production: false
 
-keycloak:
-  auth-server-url: http://localhost:8088
-  realm: sh-kiel-dev #TODO adjust
-  resource: sh-kiel-dev-goofy #TODO adjust
-
 server:
   error:
     include-stacktrace: always
@@ -30,4 +25,12 @@ grpc:
       
 ozgcloud:
   feature:
-    vorgang-export: true
\ No newline at end of file
+    vorgang-export: true
+  user-assistance:
+     documentation:
+        url: /assets/benutzerleitfaden/benutzerleitfaden.pdf
+    
+keycloak:
+  auth-server-url: http://localhost:8088
+  realm: sh-kiel-dev #TODO adjust
+  resource: sh-kiel-dev-goofy #TODO adjust
\ No newline at end of file
diff --git a/goofy-server/src/main/resources/application-remotekc.yml b/goofy-server/src/main/resources/application-remotekc.yml
index f27d8bf81a26dd58d2b10d44b8b01eb89add3c8f..60e21682a25f6e8445fcc8d21dea502e5de6f890 100644
--- a/goofy-server/src/main/resources/application-remotekc.yml
+++ b/goofy-server/src/main/resources/application-remotekc.yml
@@ -1,6 +1,4 @@
-keycloak: 
-  realm: by-kiel-dev
-  resource: alfa
-  public-client: true
-  use-resource-role-mappings: true
+keycloak:
   auth-server-url: https://sso.dev.by.ozg-cloud.de
+  realm: by-kiel-dev
+  resource: alfa
\ No newline at end of file
diff --git a/goofy-server/src/main/resources/application.yml b/goofy-server/src/main/resources/application.yml
index a84e4da06ffa475b8240b43d5301fe68a85cbbda..711b24897872a68bff0743da9e7f7092de0aaa5d 100644
--- a/goofy-server/src/main/resources/application.yml
+++ b/goofy-server/src/main/resources/application.yml
@@ -4,12 +4,11 @@ logging:
     '[de.itvsh]': INFO
     '[de.ozgcloud]': INFO,
     '[org.springframework.security]': WARN
-    '[org.keycloak.adapters]': WARN
 
 spring:
   mvc:
     pathmatch:
-      matching-strategy: ant-path-matcher
+      matching-strategy: ant_path_matcher
   application:
     name: Goofy
   jackson:
@@ -19,6 +18,12 @@ spring:
     multipart:
       max-file-size: 2GB
       max-request-size: 2GB
+  security:
+    oauth2:
+      resourceserver:
+        jwt:
+          issuer-uri: ${ozgcloud.oauth2.issuer-uri}
+          jwk-set-uri: ${spring.security.oauth2.resourceserver.jwt.issuer-uri}/protocol/openid-connect/certs
 
 server:
   http2:
@@ -51,13 +56,6 @@ management:
 
 goofy:
   production: true
-    
-keycloak:
-  auth-server-url: http://localhost:8088
-  realm: sh-kiel-dev
-  resource: sh-kiel-dev-goofy
-  public-client: true
-  use-resource-role-mappings: true
 
 grpc:
   client:
@@ -71,7 +69,7 @@ grpc:
 kop:
   auth:
     token:
-      secret: XPPWagXn3rDwKG6Ywoir
+      secret: XPPWagXn3rDwKG6YwoirXPPWagXn3rDwKG6YwoirXPPWagXn3rDwKG6YwoirXPPWagXn3rDwKG6Ywoir
       validity: 60000
   upload:
     maxFileSize:
@@ -79,4 +77,12 @@ kop:
       wiedervorlageAttachment: 40MB
   user-manager:
     profile-template: /api/userProfiles/%s
-    search-template: /api/userProfiles/?searchBy={searchBy}
\ No newline at end of file
+    search-template: /api/userProfiles/?searchBy={searchBy}
+
+ozgcloud:
+  oauth2:
+    auth-server-url: ${keycloak.auth-server-url}
+    realm: ${keycloak.realm}
+    resource: ${keycloak.resource}
+    principle-attribute: preferred_username
+    issuer-uri: ${ozgcloud.oauth2.auth-server-url}/realms/${ozgcloud.oauth2.realm}
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 46ae5cc7d1bce45bc36dd5ec8bf33208aa7dedea..f638626967522113a0fffbb5740fd92d5264d580 100644
--- a/pom.xml
+++ b/pom.xml
@@ -30,14 +30,14 @@
 
 	<groupId>de.itvsh.ozg</groupId>
 	<artifactId>goofy</artifactId>
-	<version>1.15.0-SNAPSHOT</version>
+	<version>1.16.0-SNAPSHOT</version>
 	<name>Goofy Parent</name>
 	<packaging>pom</packaging>
 
 	<parent>
 		<groupId>de.itvsh.kop.common</groupId>
 		<artifactId>kop-common-parent</artifactId>
-		<version>1.7.0</version>
+		<version>2.3.1</version>
 	</parent>
 
 	<modules>
@@ -45,20 +45,20 @@
 		<module>goofy-server</module>
 		<module>alfa-xdomea</module>
 		<module>alfa-service</module>
-  </modules>
+	</modules>
 
 	<properties>
 		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
-		
+
 		<pluto.version>1.13.0</pluto.version>
-		<kop-common-pdf.version>1.6.4</kop-common-pdf.version>
+		<kop-common-pdf.version>2.3.1</kop-common-pdf.version>
 		<user-manager.version>1.6.0</user-manager.version>
 	</properties>
-	
+
 	<build>
 		<pluginManagement>
-		    <plugins>
+			<plugins>
 				<plugin>
 					<groupId>com.mycila</groupId>
 					<artifactId>license-maven-plugin</artifactId>
diff --git a/src/main/helm/templates/deployment.yaml b/src/main/helm/templates/deployment.yaml
index aff0dfc2523947fd1f62d054291478403089a1c2..696cc298187a3424fbfceed525c6f778c5af26c4 100644
--- a/src/main/helm/templates/deployment.yaml
+++ b/src/main/helm/templates/deployment.yaml
@@ -139,6 +139,8 @@ spec:
            mountPath: "/bindings/ca-certificates/user-manager-tls-ca.pem"
            subPath: ca.crt
            readOnly: true
+         - name: temp-dir
+           mountPath: "/tmp"
       volumes:
          - name: bindings
            configMap:
@@ -146,6 +148,8 @@ spec:
          - name: user-manager-tls-certificate
            secret:
               secretName: user-manager-tls-cert
+         - name: temp-dir
+           emptyDir: {}
       dnsConfig: {}
       dnsPolicy: ClusterFirst
       imagePullSecrets:
diff --git a/src/test/helm/deployment_bindings_test.yaml b/src/test/helm/deployment_bindings_test.yaml
index a835a85e2d1a52bbe280128990f521bd1506af65..b10cfb4fffe37fe5749a6cb2e38a6f946d6f304a 100644
--- a/src/test/helm/deployment_bindings_test.yaml
+++ b/src/test/helm/deployment_bindings_test.yaml
@@ -47,6 +47,11 @@ tests:
             mountPath: "/bindings/ca-certificates/user-manager-tls-ca.pem"
             subPath: ca.crt
             readOnly: true
+      - contains:
+          path: spec.template.spec.containers[0].volumeMounts
+          content:
+            name: temp-dir
+            mountPath: "/tmp"
   - it: should have volume mounts
     set: 
        usermanagerName: user-manager
@@ -62,4 +67,9 @@ tests:
            content:
               name: user-manager-tls-certificate
               secret:
-                 secretName: user-manager-tls-cert
\ No newline at end of file
+                 secretName: user-manager-tls-cert
+      - contains:
+          path: spec.template.spec.volumes
+          content:
+            name: temp-dir
+            emptyDir: {}
\ No newline at end of file
diff --git a/src/test/helm/deployment_defaults_env_test.yaml b/src/test/helm/deployment_defaults_env_test.yaml
index f131dc469ec94a9c1d305de7d4e073e1a2fa7c60..6c64212eb3409ab825aac12fc8841dd68645ca74 100644
--- a/src/test/helm/deployment_defaults_env_test.yaml
+++ b/src/test/helm/deployment_defaults_env_test.yaml
@@ -50,21 +50,6 @@ tests:
           content:
             name: spring_profiles_active
             value: oc, test
-      - contains:
-          path: spec.template.spec.containers[0].env
-          content:
-            name: keycloak_realm
-            value: sh-helm-test
-      - contains:
-          path: spec.template.spec.containers[0].env
-          content:
-            name: keycloak_resource
-            value: alfa
-      - contains:
-          path: spec.template.spec.containers[0].env
-          content:
-            name: keycloak_auth-server-url
-            value: https://sso.sh.ozg-cloud.de
   - it: should have service binding root
     set: 
        usermanagerName: user-manager