diff --git a/Jenkinsfile b/Jenkinsfile
index 29d72c6ab83a5b3d97f1bd01d6ada52ad2dc0f2a..8028deca350abe05a476de6816dc32272fc6419a 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -48,7 +48,7 @@ pipeline {
                 }
 
                 configFileProvider([configFile(fileId: 'maven-settings', variable: 'MAVEN_SETTINGS')]) {
-                    sh "mvn -s $MAVEN_SETTINGS clean install -Dmaven.wagon.http.retryHandler.count=3 -DelasticTests.disabled=true -Dbuild.number=$BUILD_NUMBER"
+                    sh 'mvn -s $MAVEN_SETTINGS clean install -Dmaven.wagon.http.retryHandler.count=3 -DelasticTests.disabled=true -Dbuild.number=$BUILD_NUMBER'
                 }
             }
         }
@@ -116,7 +116,7 @@ pipeline {
                 
                 configFileProvider([configFile(fileId: 'maven-settings', variable: 'MAVEN_SETTINGS')]) {
                     withCredentials([usernamePassword(credentialsId: 'jenkins-nexus-login', usernameVariable: 'USER', passwordVariable: 'PASSWORD')]) {
-                        sh 'mvn -s $MAVEN_SETTINGS spring-boot:build-image -DskipTests -Dmaven.wagon.http.retryHandler.count=3 $BUILD_PROFILE -Ddocker.publishRegistry.username=${USER} -Ddocker.publishRegistry.password=${PASSWORD}'
+                        sh 'mvn -s $MAVEN_SETTINGS spring-boot:build-image -DskipTests -Dmaven.wagon.http.retryHandler.count=3 $BUILD_PROFILE -Ddocker.publishRegistry.username=${USER} -Ddocker.publishRegistry.password=${PASSWORD} -Dbuild.number=$BUILD_NUMBER -DimageTag=$IMAGE_TAG -DpublishImage=true'
                     }
                 }
             }
diff --git a/pom.xml b/pom.xml
index e8dbfcfe93f84bc818e739441f93e92cc5ee60d8..60a6b290c85d56bb4ee6e133e9e59d788b3eb9df 100644
--- a/pom.xml
+++ b/pom.xml
@@ -17,10 +17,13 @@
 
 	<properties>
 		<imageName>docker.ozg-sh.de/administration</imageName>
+		<imageTag>build-latest</imageTag>
+		<publishImage>false</publishImage>
 		<build.number>SET_BY_JENKINS</build.number>	
 		<spring-cloud-config-server.version>4.1.0</spring-cloud-config-server.version>
 		<testcontainers-keycloak.version>3.2.0</testcontainers-keycloak.version>
 		<keycloak-admin-client.version>23.0.6</keycloak-admin-client.version>
+		<mongock.version>5.4.0</mongock.version>
 	</properties>
 
 	<dependencies>
@@ -67,6 +70,17 @@
 		    <artifactId>spring-boot-configuration-processor</artifactId>
 		    <optional>true</optional>
 		</dependency>
+		<!-- mongock -->
+		<dependency>
+			<groupId>io.mongock</groupId>
+			<artifactId>mongock-springboot-v3</artifactId>
+			<version>${mongock.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>io.mongock</groupId>
+			<artifactId>mongodb-springdata-v4-driver</artifactId>
+			<version>${mongock.version}</version>
+		</dependency>
 
 		<!-- Dev -->
 		<dependency>
@@ -178,8 +192,8 @@
 				<artifactId>spring-boot-maven-plugin</artifactId>
 				<configuration>
 				<image>
-					<name>${imageName}:${env.BRANCH_NAME}-${project.version}</name>
-					<publish>true</publish>
+					<name>${imageName}:${imageTag}</name>
+					<publish>${publishImage}</publish>
 				</image>
 				<docker>
 					<publishRegistry>
diff --git a/src/main/java/de/ozgcloud/admin/AdministrationApplication.java b/src/main/java/de/ozgcloud/admin/AdministrationApplication.java
index c9535837fdbb37dcb5a4344bff54816679d33223..563eea5b36d486c99187d35a08c61e6fb2e34bf1 100644
--- a/src/main/java/de/ozgcloud/admin/AdministrationApplication.java
+++ b/src/main/java/de/ozgcloud/admin/AdministrationApplication.java
@@ -21,6 +21,7 @@
  */
 package de.ozgcloud.admin;
 
+import io.mongock.runner.springboot.EnableMongock;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.cloud.config.server.EnableConfigServer;
@@ -28,6 +29,7 @@ import org.springframework.data.mongodb.repository.config.EnableMongoRepositorie
 
 @SpringBootApplication
 @EnableConfigServer
+@EnableMongock
 @EnableMongoRepositories
 public class AdministrationApplication {
 
diff --git a/src/main/java/de/ozgcloud/admin/RootModelAssembler.java b/src/main/java/de/ozgcloud/admin/RootModelAssembler.java
index cd66647d10b09a38b229b1931cf2e65bbef5733a..2cf01448f6fa1ab4f52d3a72fc06b15d57c5cda7 100644
--- a/src/main/java/de/ozgcloud/admin/RootModelAssembler.java
+++ b/src/main/java/de/ozgcloud/admin/RootModelAssembler.java
@@ -28,13 +28,11 @@ import org.springframework.hateoas.server.RepresentationModelAssembler;
 import org.springframework.hateoas.server.mvc.WebMvcLinkBuilder;
 import org.springframework.stereotype.Component;
 
-import io.micrometer.common.lang.NonNullApi;
 import lombok.RequiredArgsConstructor;
 
 @Component
 @RequiredArgsConstructor
-@NonNullApi
-class RootModelAssembler implements RepresentationModelAssembler<Root, EntityModel<Root>> {
+public class RootModelAssembler implements RepresentationModelAssembler<Root, EntityModel<Root>> {
 	static final String REL_CONFIGURATION = "configuration";
 
 	private final RepositoryRestProperties restProperties;
@@ -46,7 +44,6 @@ class RootModelAssembler implements RepresentationModelAssembler<Root, EntityMod
 		return EntityModel.of(
 				root,
 				Link.of(configLink.toUriString(), REL_CONFIGURATION),
-				rootLink.withSelfRel()
-		);
+				rootLink.withSelfRel());
 	}
 }
diff --git a/src/main/java/de/ozgcloud/admin/errorhandling/AdminExceptionHandler.java b/src/main/java/de/ozgcloud/admin/common/errorhandling/ExceptionController.java
similarity index 95%
rename from src/main/java/de/ozgcloud/admin/errorhandling/AdminExceptionHandler.java
rename to src/main/java/de/ozgcloud/admin/common/errorhandling/ExceptionController.java
index 27f9c626b4586717558355e5a2671676ec0e570d..75a3dda5ce10f4d50ebaaabc31ec840ac9c54d3b 100644
--- a/src/main/java/de/ozgcloud/admin/errorhandling/AdminExceptionHandler.java
+++ b/src/main/java/de/ozgcloud/admin/common/errorhandling/ExceptionController.java
@@ -19,7 +19,7 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-package de.ozgcloud.admin.errorhandling;
+package de.ozgcloud.admin.common.errorhandling;
 
 import java.util.Map;
 
@@ -36,7 +36,7 @@ import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExcep
 import de.ozgcloud.common.errorhandling.TechnicalException;
 
 @RestControllerAdvice
-public class AdminExceptionHandler extends ResponseEntityExceptionHandler {
+public class ExceptionController extends ResponseEntityExceptionHandler {
 
 	static final Map<Class<? extends Exception>, HttpStatus> STATUS_BY_EXCEPTION = Map.of(
 			RuntimeException.class, HttpStatus.INTERNAL_SERVER_ERROR,
diff --git a/src/main/java/de/ozgcloud/admin/errorhandling/FunctionalException.java b/src/main/java/de/ozgcloud/admin/common/errorhandling/FunctionalException.java
similarity index 97%
rename from src/main/java/de/ozgcloud/admin/errorhandling/FunctionalException.java
rename to src/main/java/de/ozgcloud/admin/common/errorhandling/FunctionalException.java
index e0e57b3feb65073674c0645aac9fc997af8dbfed..5b2369b2a97772a1607b84ebaa9a46de2fec9643 100644
--- a/src/main/java/de/ozgcloud/admin/errorhandling/FunctionalException.java
+++ b/src/main/java/de/ozgcloud/admin/common/errorhandling/FunctionalException.java
@@ -19,7 +19,7 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-package de.ozgcloud.admin.errorhandling;
+package de.ozgcloud.admin.common.errorhandling;
 
 import java.io.Serial;
 import java.util.UUID;
diff --git a/src/main/java/de/ozgcloud/admin/environment/FrontendEnvironment.java b/src/main/java/de/ozgcloud/admin/environment/Environment.java
similarity index 87%
rename from src/main/java/de/ozgcloud/admin/environment/FrontendEnvironment.java
rename to src/main/java/de/ozgcloud/admin/environment/Environment.java
index 0f7ca897f9e77c5956cdcab164977ea35d694476..e2bfb54b4aeb2d33da4461d3eb6ae95d89eab93e 100644
--- a/src/main/java/de/ozgcloud/admin/environment/FrontendEnvironment.java
+++ b/src/main/java/de/ozgcloud/admin/environment/Environment.java
@@ -5,7 +5,7 @@ import lombok.Getter;
 
 @Getter
 @Builder
-public class FrontendEnvironment {
+public class Environment {
 	private boolean production;
 	private String remoteHost;
 	private String authServer;
diff --git a/src/main/java/de/ozgcloud/admin/environment/FrontendEnvironmentController.java b/src/main/java/de/ozgcloud/admin/environment/EnvironmentController.java
similarity index 81%
rename from src/main/java/de/ozgcloud/admin/environment/FrontendEnvironmentController.java
rename to src/main/java/de/ozgcloud/admin/environment/EnvironmentController.java
index b61f1d9c358751a1e974be75b9cc33b3f2551536..71cf34ce3180c793235693f7ec8582a06aa27c63 100644
--- a/src/main/java/de/ozgcloud/admin/environment/FrontendEnvironmentController.java
+++ b/src/main/java/de/ozgcloud/admin/environment/EnvironmentController.java
@@ -9,10 +9,10 @@ import org.springframework.web.bind.annotation.RestController;
 import de.ozgcloud.admin.RootController;
 import lombok.RequiredArgsConstructor;
 
-@RestController
+@RestController("ozgCloudEnvironmentController")
 @RequiredArgsConstructor
-@RequestMapping(FrontendEnvironmentController.PATH)
-public class FrontendEnvironmentController {
+@RequestMapping(EnvironmentController.PATH)
+public class EnvironmentController {
 
 	static final String PATH = "/api/environment"; // NOSONAR
 
@@ -21,8 +21,8 @@ public class FrontendEnvironmentController {
 	private final OAuth2Properties oAuthProperties;
 
 	@GetMapping
-	public FrontendEnvironment getEnvironment() {
-		return FrontendEnvironment.builder()
+	public Environment getEnvironment() {
+		return Environment.builder()
 				.production(environmentProperties.isProduction())
 				.remoteHost(linkTo(RootController.class).toUri().toString())
 				.authServer(oAuthProperties.getAuthServerUrl())
diff --git a/src/main/java/de/ozgcloud/admin/migration/M001_CreateEmptyPostfachIfMissing.java b/src/main/java/de/ozgcloud/admin/migration/M001_CreateEmptyPostfachIfMissing.java
new file mode 100644
index 0000000000000000000000000000000000000000..b871728d899c5b7eb209501167555d9325d17e49
--- /dev/null
+++ b/src/main/java/de/ozgcloud/admin/migration/M001_CreateEmptyPostfachIfMissing.java
@@ -0,0 +1,38 @@
+package de.ozgcloud.admin.migration;
+
+import io.mongock.api.annotations.ChangeUnit;
+import io.mongock.api.annotations.Execution;
+import io.mongock.api.annotations.RollbackExecution;
+import org.springframework.data.mongodb.core.MongoTemplate;
+import org.springframework.data.mongodb.core.query.Criteria;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.data.mongodb.core.query.Update;
+
+@ChangeUnit(id = "2024-02-20 17:00:00 OZG-4948-OZG-5058", order = "M001", author = "lmonnerjahn", runAlways = true)
+public class M001_CreateEmptyPostfachIfMissing {  // NOSONAR
+	static final String SETTINGS_COLLECTION = "settings";
+
+	static final String TYPE_NAME_KEY = "name";
+	static final String TYPE_NAME_POSTFACH_VALUE = "Postfach";
+
+	@Execution
+	public void doMigration(MongoTemplate template) {
+		template.upsert(buildQuery(), buildUpdate(), SETTINGS_COLLECTION);
+	}
+
+	private Query buildQuery() {
+		var criteria = Criteria.where(TYPE_NAME_KEY).is(TYPE_NAME_POSTFACH_VALUE);
+		return Query.query(criteria);
+	}
+
+	private Update buildUpdate() {
+		var update = new Update();
+		update.setOnInsert(TYPE_NAME_KEY, TYPE_NAME_POSTFACH_VALUE);
+		return update;
+	}
+
+	@RollbackExecution
+	public void rollback() {
+		// kein rollback implementiert
+	}
+}
diff --git a/src/main/java/de/ozgcloud/admin/migration/MongockFailedEventListener.java b/src/main/java/de/ozgcloud/admin/migration/MongockFailedEventListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..84e860cb2cbdee0312df576f903dd285e89e1bd9
--- /dev/null
+++ b/src/main/java/de/ozgcloud/admin/migration/MongockFailedEventListener.java
@@ -0,0 +1,39 @@
+/*
+ * 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.admin.migration;
+
+import io.mongock.runner.spring.base.events.SpringMigrationFailureEvent;
+import lombok.extern.log4j.Log4j2;
+import org.springframework.context.ApplicationListener;
+import org.springframework.stereotype.Component;
+
+@Log4j2
+@Component
+public class MongockFailedEventListener implements ApplicationListener<SpringMigrationFailureEvent> {
+
+	@Override
+	public void onApplicationEvent(SpringMigrationFailureEvent event) {
+		log.error("Mongock migration failed", event.getMigrationResult());
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/de/ozgcloud/admin/migration/MongockStartEventListener.java b/src/main/java/de/ozgcloud/admin/migration/MongockStartEventListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..ad1558351ae353658dbe653bfe2630e627373489
--- /dev/null
+++ b/src/main/java/de/ozgcloud/admin/migration/MongockStartEventListener.java
@@ -0,0 +1,39 @@
+/*
+ * 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.admin.migration;
+
+import io.mongock.runner.spring.base.events.SpringMigrationStartedEvent;
+import lombok.extern.log4j.Log4j2;
+import org.springframework.context.ApplicationListener;
+import org.springframework.stereotype.Component;
+
+@Log4j2
+@Component
+public class MongockStartEventListener implements ApplicationListener<SpringMigrationStartedEvent> {
+
+	@Override
+	public void onApplicationEvent(SpringMigrationStartedEvent event) {
+		log.info("Mongock start migration...");
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/de/ozgcloud/admin/migration/MongockSuccessEventListener.java b/src/main/java/de/ozgcloud/admin/migration/MongockSuccessEventListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..95a7f76ee988dc8f1e72b8db6341da77514e5b54
--- /dev/null
+++ b/src/main/java/de/ozgcloud/admin/migration/MongockSuccessEventListener.java
@@ -0,0 +1,39 @@
+/*
+ * 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.admin.migration;
+
+import io.mongock.runner.spring.base.events.SpringMigrationSuccessEvent;
+import lombok.extern.log4j.Log4j2;
+import org.springframework.context.ApplicationListener;
+import org.springframework.stereotype.Component;
+
+@Log4j2
+@Component
+public class MongockSuccessEventListener implements ApplicationListener<SpringMigrationSuccessEvent> {
+
+	@Override
+	public void onApplicationEvent(SpringMigrationSuccessEvent event) {
+		log.info("Mongock migration successfull", event.getMigrationResult());
+	}
+}
\ No newline at end of file
diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml
index 29082f7d8446f187cd3f16f077b94f28d41bf807..315e37b9756df692953d1c5761747bfc1e97f4ac 100644
--- a/src/main/resources/application.yaml
+++ b/src/main/resources/application.yaml
@@ -49,6 +49,12 @@ management:
       exposure:
         include: health,prometheus
 
+mongock:
+  runner-type: initializingbean
+  migration-scan-package:
+    - de.ozgcloud.admin.migration
+  enabled: true
+
 spring:
   application:
     name: OzgCloud_Administration
diff --git a/src/test/java/de/ozgcloud/admin/AdministrationApplicationTest.java b/src/test/java/de/ozgcloud/admin/AdministrationApplicationTest.java
index 7d88d4237191cb0b07aaad9235443c689c1efe59..7b7fb5056c8fd67bc11be9a1cc016610e1181146 100644
--- a/src/test/java/de/ozgcloud/admin/AdministrationApplicationTest.java
+++ b/src/test/java/de/ozgcloud/admin/AdministrationApplicationTest.java
@@ -21,10 +21,10 @@
  */
 package de.ozgcloud.admin;
 
+import de.ozgcloud.common.test.ITCase;
 import org.junit.jupiter.api.Test;
-import org.springframework.boot.test.context.SpringBootTest;
 
-@SpringBootTest
+@ITCase
 class AdministrationApplicationTest {
 
 	@Test
diff --git a/src/test/java/de/ozgcloud/admin/common/errorhandling/ExceptionControllerITCase.java b/src/test/java/de/ozgcloud/admin/common/errorhandling/ExceptionControllerITCase.java
new file mode 100644
index 0000000000000000000000000000000000000000..b4884dd0e4b23e908645251677c76064c9086e8a
--- /dev/null
+++ b/src/test/java/de/ozgcloud/admin/common/errorhandling/ExceptionControllerITCase.java
@@ -0,0 +1,111 @@
+package de.ozgcloud.admin.common.errorhandling;
+
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.*;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
+
+import java.util.Set;
+import java.util.stream.Stream;
+
+import jakarta.validation.ConstraintViolation;
+import jakarta.validation.ConstraintViolationException;
+import jakarta.validation.Validation;
+import jakarta.validation.Validator;
+import jakarta.validation.constraints.NotEmpty;
+
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.http.HttpStatus;
+import org.springframework.security.test.context.support.WithMockUser;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.ResultActions;
+
+import de.ozgcloud.admin.RootController;
+import de.ozgcloud.admin.RootModelAssembler;
+import de.ozgcloud.common.test.ITCase;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.SneakyThrows;
+
+@ITCase
+@AutoConfigureMockMvc
+@WithMockUser
+class ExceptionControllerITCase {
+
+	@Autowired
+	private MockMvc mockMvc;
+
+	@MockBean
+	private RootModelAssembler modelAssembler;
+
+	@Nested
+	class TestExceptions {
+		@ParameterizedTest
+		@MethodSource("exceptionAndExpectedStatus")
+		@SneakyThrows
+		void shouldHandleExceptionWithStatus(Class<? extends Exception> exceptionClass, HttpStatus expectedStatus) {
+			when(modelAssembler.toModel(any())).thenThrow(TestErrorController.EXCEPTION_PRODUCER.get(exceptionClass).produceException());
+
+			var result = performGet();
+
+			result.andExpect(status().is(expectedStatus.value()));
+		}
+
+		@ParameterizedTest
+		@MethodSource("exceptionAndExpectedStatus")
+		@SneakyThrows
+		void shouldRespondWithStatusInBody(Class<? extends Exception> exceptionClass, HttpStatus expectedStatus) {
+			when(modelAssembler.toModel(any())).thenThrow(exceptionClass);
+
+			var result = performGet();
+
+			result.andExpect(jsonPath("$.status").value(expectedStatus.value()));
+		}
+
+		private static Stream<Arguments> exceptionAndExpectedStatus() {
+			return ExceptionController.STATUS_BY_EXCEPTION.entrySet().stream().map(kv -> Arguments.of(kv.getKey(), kv.getValue()));
+		}
+
+	}
+
+	@Nested
+	class TestConstraintViolationException {
+		@Test
+		@SneakyThrows
+		void shouldHaveValidationMessage() {
+			when(modelAssembler.toModel(any())).thenAnswer((a) -> {
+				throw new ConstraintViolationException(getConstraintViolations());
+			});
+
+			var result = performGet();
+
+			result.andExpect(jsonPath("$.detail").value("string: Empty field"));
+		}
+
+		private Set<ConstraintViolation<ValidatedClass>> getConstraintViolations() {
+			Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
+			return validator.validate(ValidatedClass.builder().build());
+		}
+
+		@Getter
+		@Builder
+		private static class ValidatedClass {
+			@NotEmpty(message = "Empty field")
+			private String string;
+		}
+
+	}
+
+	@SneakyThrows
+	private ResultActions performGet() {
+		return mockMvc.perform(get(RootController.PATH));
+	}
+
+}
diff --git a/src/test/java/de/ozgcloud/admin/errorhandling/AdminExceptionHandlerITCase.java b/src/test/java/de/ozgcloud/admin/common/errorhandling/ExceptionControllerTest.java
similarity index 69%
rename from src/test/java/de/ozgcloud/admin/errorhandling/AdminExceptionHandlerITCase.java
rename to src/test/java/de/ozgcloud/admin/common/errorhandling/ExceptionControllerTest.java
index 646d2c0b24579a6d7cfd502fbbdf58cfc530806a..f33a3715b32778a78b725e096ea0bf99e1fd4047 100644
--- a/src/test/java/de/ozgcloud/admin/errorhandling/AdminExceptionHandlerITCase.java
+++ b/src/test/java/de/ozgcloud/admin/common/errorhandling/ExceptionControllerTest.java
@@ -19,9 +19,9 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-package de.ozgcloud.admin.errorhandling;
+package de.ozgcloud.admin.common.errorhandling;
 
-import static de.ozgcloud.admin.errorhandling.AdminExceptionHandler.*;
+import static de.ozgcloud.admin.common.errorhandling.ExceptionController.*;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
 
@@ -41,7 +41,7 @@ import org.springframework.test.web.servlet.setup.MockMvcBuilders;
 
 import lombok.SneakyThrows;
 
-class AdminExceptionHandlerITCase {
+class ExceptionControllerTest {
 
 	private MockMvc mockMvc;
 
@@ -49,7 +49,7 @@ class AdminExceptionHandlerITCase {
 	void setup() {
 		mockMvc = MockMvcBuilders
 				.standaloneSetup(new TestErrorController())
-				.setControllerAdvice(new AdminExceptionHandler()).build();
+				.setControllerAdvice(new ExceptionController()).build();
 	}
 
 	@DisplayName("Error handler")
@@ -74,13 +74,49 @@ class AdminExceptionHandlerITCase {
 			result.andExpect(jsonPath("$.status").value(expectedStatus.value()));
 		}
 
+		@ParameterizedTest
+		@MethodSource("exceptionAndExpectedStatus")
+		@SneakyThrows
+		void shouldRespondWithTitler(Class<? extends Exception> exceptionClass, HttpStatus expectedStatus) {
+			var result = doPerformWithError(exceptionClass);
+
+			result.andExpect(jsonPath("$.title").exists());
+		}
+
+		@ParameterizedTest
+		@MethodSource("exceptionAndExpectedStatus")
+		@SneakyThrows
+		void shouldRespondWithDetail(Class<? extends Exception> exceptionClass, HttpStatus expectedStatus) {
+			var result = doPerformWithError(exceptionClass);
+
+			result.andExpect(jsonPath("$.detail").exists());
+		}
+
+		@ParameterizedTest
+		@MethodSource("exceptionAndExpectedStatus")
+		@SneakyThrows
+		void shouldRespondWithInstance(Class<? extends Exception> exceptionClass, HttpStatus expectedStatus) {
+			var result = doPerformWithError(exceptionClass);
+
+			result.andExpect(jsonPath("$.instance").exists());
+		}
+
+		@ParameterizedTest
+		@MethodSource("exceptionAndExpectedStatus")
+		@SneakyThrows
+		void shouldRespondWithType(Class<? extends Exception> exceptionClass, HttpStatus expectedStatus) {
+			var result = doPerformWithError(exceptionClass);
+
+			result.andExpect(jsonPath("$.type").exists());
+		}
+
 		private static Stream<Arguments> exceptionAndExpectedStatus() {
 			return STATUS_BY_EXCEPTION.entrySet().stream().map(kv -> Arguments.of(kv.getKey(), kv.getValue()));
 		}
 
 		@SneakyThrows
 		private ResultActions doPerformWithError(Class<? extends Exception> exceptionClass) {
-			return mockMvc.perform(get("/test-error").param("errorClassName", exceptionClass.getName()));
+			return mockMvc.perform(get("/api/test-error").param("errorClassName", exceptionClass.getName()));
 		}
 	}
 
diff --git a/src/test/java/de/ozgcloud/admin/errorhandling/TestErrorController.java b/src/test/java/de/ozgcloud/admin/common/errorhandling/TestErrorController.java
similarity index 92%
rename from src/test/java/de/ozgcloud/admin/errorhandling/TestErrorController.java
rename to src/test/java/de/ozgcloud/admin/common/errorhandling/TestErrorController.java
index 4ad218f842cdc6e96a0c3b563e51aad7c9cdbeaf..c10446041aaba51ac761ac4e91ec01d6f9b7bb4b 100644
--- a/src/test/java/de/ozgcloud/admin/errorhandling/TestErrorController.java
+++ b/src/test/java/de/ozgcloud/admin/common/errorhandling/TestErrorController.java
@@ -19,7 +19,7 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-package de.ozgcloud.admin.errorhandling;
+package de.ozgcloud.admin.common.errorhandling;
 
 import java.util.Collections;
 import java.util.Map;
@@ -34,11 +34,9 @@ import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
 import de.ozgcloud.common.errorhandling.TechnicalException;
-import io.micrometer.common.lang.NonNullApi;
 
 @RestController
-@RequestMapping("/test-error")
-@NonNullApi
+@RequestMapping("/api/test-error")
 class TestErrorController {
 
 	@FunctionalInterface
@@ -54,13 +52,12 @@ class TestErrorController {
 			ConstraintViolationException.class, () -> new ConstraintViolationException(ERROR_MESSAGE, Collections.emptySet()),
 			ResourceNotFoundException.class, () -> new ResourceNotFoundException(ERROR_MESSAGE),
 			FunctionalException.class, () -> new FunctionalException(() -> ERROR_MESSAGE),
-			TechnicalException.class, () -> new TechnicalException(ERROR_MESSAGE)
-	);
+			TechnicalException.class, () -> new TechnicalException(ERROR_MESSAGE));
 
 	@GetMapping
 	String throwException(@RequestParam String errorClassName) throws Exception {
 		throw EXCEPTION_PRODUCER.get(
-				Class.forName(errorClassName)
-		).produceException();
+				Class.forName(errorClassName)).produceException();
 	}
+
 }
diff --git a/src/test/java/de/ozgcloud/admin/environment/FrontendEnvironmentControllerTest.java b/src/test/java/de/ozgcloud/admin/environment/EnvironmentControllerTest.java
similarity index 94%
rename from src/test/java/de/ozgcloud/admin/environment/FrontendEnvironmentControllerTest.java
rename to src/test/java/de/ozgcloud/admin/environment/EnvironmentControllerTest.java
index 67d81f084a8a4bea8e747713cbb205c9d9433ca3..bdeaf83b00de2410112833f1447e940fc088e9b5 100644
--- a/src/test/java/de/ozgcloud/admin/environment/FrontendEnvironmentControllerTest.java
+++ b/src/test/java/de/ozgcloud/admin/environment/EnvironmentControllerTest.java
@@ -22,11 +22,11 @@ import de.ozgcloud.admin.RootController;
 import lombok.SneakyThrows;
 
 @ExtendWith(MockitoExtension.class)
-class FrontendEnvironmentControllerTest {
+class EnvironmentControllerTest {
 
 	@Spy
 	@InjectMocks
-	private FrontendEnvironmentController controller;
+	private EnvironmentController controller;
 
 	@Mock
 	private ProductionProperties environmentProperties;
@@ -120,7 +120,7 @@ class FrontendEnvironmentControllerTest {
 
 		@SneakyThrows
 		private ResultActions doRequest() {
-			return mockMvc.perform(get(FrontendEnvironmentController.PATH));
+			return mockMvc.perform(get(EnvironmentController.PATH));
 		}
 
 	}
diff --git a/src/test/java/de/ozgcloud/admin/migration/M001_CreateEmptyPostfachIfMissingITCase.java b/src/test/java/de/ozgcloud/admin/migration/M001_CreateEmptyPostfachIfMissingITCase.java
new file mode 100644
index 0000000000000000000000000000000000000000..8eb5819980340878289af90178eea9b1b67b6fae
--- /dev/null
+++ b/src/test/java/de/ozgcloud/admin/migration/M001_CreateEmptyPostfachIfMissingITCase.java
@@ -0,0 +1,103 @@
+package de.ozgcloud.admin.migration;
+
+import static de.ozgcloud.admin.migration.M001_CreateEmptyPostfachIfMissing.*;
+import static org.assertj.core.api.Assertions.*;
+
+import java.util.List;
+
+import org.bson.Document;
+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.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.mongodb.core.MongoTemplate;
+
+import de.ozgcloud.common.test.DataITCase;
+
+@DataITCase
+class M001_CreateEmptyPostfachIfMissingITCase {
+	private final M001_CreateEmptyPostfachIfMissing changeUnit = new M001_CreateEmptyPostfachIfMissing();
+
+	private static final Document POSTFACH = MigrationTestFactory.createDummyPostfach();
+
+	@Autowired
+	private MongoTemplate template;
+
+	@DisplayName("Do migration")
+	@Nested
+	class TestDoMigration {
+		@BeforeEach
+		public void init() {
+			template.dropCollection(SETTINGS_COLLECTION);
+		}
+
+		@Test
+		void shouldAddPostfachIfEmpty() {
+			changeUnit.doMigration(template);
+
+			List<Document> settings = findAllSettings();
+
+			assertThat(settings).usingRecursiveFieldByFieldElementComparatorIgnoringFields("_id")
+					.containsExactly(MigrationTestFactory.createEmptyPostfach());
+		}
+
+		@Test
+		void shouldAddPostfachIfMissingInCollection() {
+			var settingItem = MigrationTestFactory.createSettingsItem("SomeType", new Document());
+			template.save(settingItem, SETTINGS_COLLECTION);
+
+			changeUnit.doMigration(template);
+
+			List<Document> settings = findAllSettings();
+			assertThat(settings)
+					.extracting(TYPE_NAME_KEY)
+					.containsExactly("SomeType", MigrationTestFactory.ITEM_TYPE_VALUE_POSTFACH);
+		}
+
+		@Test
+		void shouldKeepExistingPostfach() {
+			template.save(POSTFACH, SETTINGS_COLLECTION);
+
+			changeUnit.doMigration(template);
+
+			List<Document> settings = findAllSettings();
+			assertThat(settings).containsExactly(POSTFACH);
+		}
+
+		private List<Document> findAllSettings() {
+			return template.findAll(Document.class, SETTINGS_COLLECTION);
+		}
+
+	}
+
+	static class MigrationTestFactory {
+
+		public static final String ITEM_TYPE_KEY = "name";
+		public static final String ITEM_SETTINGS_KEY = "settings";
+		public static final String ITEM_ID = "_id";
+		public static final String ITEM_TYPE_VALUE_POSTFACH = "Postfach";
+		public static final String POSTFACH_ABSENDER_KEY = "absender";
+
+		static Document createDummyPostfach() {
+			var postfach = new Document();
+			postfach.put(POSTFACH_ABSENDER_KEY, "Some Value");
+			return createSettingsItem(ITEM_TYPE_VALUE_POSTFACH, postfach);
+		}
+
+		static Document createEmptyPostfach() {
+			var postfach = new Document();
+			postfach.put(ITEM_TYPE_KEY, ITEM_TYPE_VALUE_POSTFACH);
+			postfach.put(ITEM_ID, null);
+			return postfach;
+		}
+
+		static Document createSettingsItem(String itemType, Document itemValue) {
+			var settingsItem = new Document();
+			settingsItem.put(ITEM_TYPE_KEY, itemType);
+			settingsItem.put(ITEM_SETTINGS_KEY, itemValue);
+			return settingsItem;
+		}
+
+	}
+}
diff --git a/src/test/resources/application-itcase.yaml b/src/test/resources/application-itcase.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..fc717c37b9cfb97360022930cb07c950b16d1983
--- /dev/null
+++ b/src/test/resources/application-itcase.yaml
@@ -0,0 +1,2 @@
+mongock:
+  enabled: false
\ No newline at end of file