diff --git a/Jenkinsfile b/Jenkinsfile
index ec06a286b328e9db37cbb3560af803ce248dce2e..9bb110e4afb5ce6d635a114f7830aa44d82a9536 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -135,7 +135,7 @@ pipeline {
                     HELM_CHART_VERSION = generateHelmChartVersion()
 
                     dir('src/main/helm') {
-                        sh "helm lint -f test-values.yaml"
+                        sh "helm lint -f ../../test/helm-linter-values.yaml"
 
                         sh "helm unittest --helm3 -f '../../test/helm/*.yaml' -v '../../test/unit-values.yaml' ."
 
diff --git a/common/src/main/java/de/ozgcloud/eingang/common/vorgang/VorgangNummerSupplier.java b/common/src/main/java/de/ozgcloud/eingang/common/vorgang/VorgangNummerSupplier.java
index 5d1468262c469c9595dabe39e5a7159a3f70a2de..510b7c92779fa39758cf3da4855a7af4dec20fe1 100644
--- a/common/src/main/java/de/ozgcloud/eingang/common/vorgang/VorgangNummerSupplier.java
+++ b/common/src/main/java/de/ozgcloud/eingang/common/vorgang/VorgangNummerSupplier.java
@@ -1,32 +1,26 @@
 package de.ozgcloud.eingang.common.vorgang;
 
-import java.time.Instant;
 import java.time.LocalDate;
 
+import org.apache.commons.lang3.RandomStringUtils;
 import org.springframework.stereotype.Component;
 
+import lombok.RequiredArgsConstructor;
+
 @Component
+@RequiredArgsConstructor
 public class VorgangNummerSupplier {
 
-	static final String BASE30_ALPHABET = "23456789ABCDEFGHJKMNPQRSTVWXYZ";
+	static final String VORGANGNUMMER_TEMPLATE = "%d%X%02d-%s";
+	static final char[] BASE30_ALPHABET = { '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'M',
+			'N', 'P', 'Q', 'R', 'S', 'T', 'V', 'W', 'X', 'Y', 'Z' };
 	static final int SUFFIX_LENGTH = 6;
 
 	public String get() {
-		var resultBuilder = initWithPrefix();
-		long currentTimeSeconds = Instant.now().toEpochMilli();
-		for (int i = 0; i < SUFFIX_LENGTH; i++) {
-			resultBuilder.append(BASE30_ALPHABET.charAt((int) (currentTimeSeconds % 30)));
-			currentTimeSeconds /= 30;
-		}
-		return resultBuilder.toString();
-	}
-
-	StringBuilder initWithPrefix() {
 		var today = LocalDate.now();
 		var lastYearNumber = today.getYear() % 10;
-		var monthValue = "%02d".formatted(today.getMonthValue());
-		var dayValue = "%02d".formatted(today.getDayOfMonth());
-		return new StringBuilder().append(lastYearNumber).append(monthValue).append(dayValue).append("-");
+		return VORGANGNUMMER_TEMPLATE.formatted(lastYearNumber, today.getMonthValue(), today.getDayOfMonth(),
+				RandomStringUtils.random(SUFFIX_LENGTH, BASE30_ALPHABET));
 	}
 
 }
diff --git a/common/src/test/java/de/ozgcloud/eingang/common/vorgang/VorgangNummerSupplierTest.java b/common/src/test/java/de/ozgcloud/eingang/common/vorgang/VorgangNummerSupplierTest.java
index d474cd190edfb39454d96c98a67d2d1a0886690d..2fc9a524f5e23d2bebd9721eb5612d96ad879782 100644
--- a/common/src/test/java/de/ozgcloud/eingang/common/vorgang/VorgangNummerSupplierTest.java
+++ b/common/src/test/java/de/ozgcloud/eingang/common/vorgang/VorgangNummerSupplierTest.java
@@ -4,12 +4,15 @@ import static org.assertj.core.api.Assertions.*;
 import static org.mockito.Mockito.*;
 
 import java.time.LocalDate;
+import java.util.Random;
 
+import org.apache.commons.lang3.RandomStringUtils;
 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.test.util.ReflectionTestUtils;
 
 class VorgangNummerSupplierTest {
 
@@ -17,71 +20,67 @@ class VorgangNummerSupplierTest {
 	@InjectMocks
 	private VorgangNummerSupplier vorgangNummerSupplier;
 
-	@Nested
-	@DisplayName("Get Vorgang Nummer")
-	class TestGetVorgangNummer {
 
-		@Test
-		void shouldCallAddPrefix() {
-			vorgangNummerSupplier.get();
-
-			verify(vorgangNummerSupplier).initWithPrefix();
-		}
+	@Test
+	@DisplayName("should add random suffix of length 6")
+	void shouldAddSuffix() {
+		var result = vorgangNummerSupplier.get();
 
-		@Test
-		@DisplayName("should add random suffix of length 6")
-		void shouldAddSuffix() {
-			doReturn(new StringBuilder()).when(vorgangNummerSupplier).initWithPrefix();
+		assertThat(result).hasSize(11);
+	}
 
-			var result = vorgangNummerSupplier.get();
+	@Test
+	void shouldCallGetRandomString() {
+		try (var randomStringUtils = mockStatic(RandomStringUtils.class)) {
+			vorgangNummerSupplier.get();
 
-			assertThat(result).hasSize(6);
+			randomStringUtils.verify(() -> RandomStringUtils.random(VorgangNummerSupplier.SUFFIX_LENGTH, VorgangNummerSupplier.BASE30_ALPHABET));
 		}
 	}
 
-	@Nested
-	class TestAddPrefix {
+	@Test
+	void shouldHaveSize() {
+		var result = vorgangNummerSupplier.get();
 
-		@Test
-		void shouldHaveSize() {
-			var resultBuilder = vorgangNummerSupplier.initWithPrefix();
+		assertThat(getPrefix(result)).hasSize(5);
+	}
 
-			assertThat(resultBuilder).hasSize(6);
-		}
+	private String getPrefix(String string) {
+		return string.substring(0, string.indexOf('-') + 1);
+	}
 
-		@Test
-		void shouldAddLastYearNumberFirst() {
-			var lastYearNumber = "" + LocalDate.now().getYear() % 10;
+	@Test
+	void shouldAddLastYearNumberFirst() {
+		var lastYearNumber = "" + LocalDate.now().getYear() % 10;
 
-			var resultBuilder = vorgangNummerSupplier.initWithPrefix();
+		var result = vorgangNummerSupplier.get();
 
-			assertThat(resultBuilder.substring(0, 1)).isEqualTo(lastYearNumber);
-		}
+		assertThat(result.substring(0, 1)).isEqualTo(lastYearNumber);
+	}
 
-		@Test
-		void shouldAddMonthValueSecond() {
-			var monthValue = "%02d".formatted(LocalDate.now().getMonthValue());
+	@Test
+	void shouldAddMonthValueSecond() {
+		var monthHexValue = "%X".formatted(LocalDate.now().getMonthValue());
 
-			var resultBuilder = vorgangNummerSupplier.initWithPrefix();
+		var result = vorgangNummerSupplier.get();
 
-			assertThat(resultBuilder.substring(1, 3)).isEqualTo(monthValue);
-		}
+		assertThat(result.substring(1, 2)).isEqualTo(monthHexValue);
+	}
 
-		@Test
-		void shouldAddDayValueThird() {
-			var dayValue = "%02d".formatted(LocalDate.now().getDayOfMonth());
+	@Test
+	void shouldAddDayValueThird() {
+		var dayValue = "%02d".formatted(LocalDate.now().getDayOfMonth());
 
-			var resultBuilder = vorgangNummerSupplier.initWithPrefix();
+		var result = vorgangNummerSupplier.get();
 
-			assertThat(resultBuilder.substring(3, 5)).isEqualTo(dayValue);
-		}
+		assertThat(result.substring(2, 4)).isEqualTo(dayValue);
+	}
 
-		@Test
-		void shouldAddHyphenAtEnd() {
-			var resultBuilder = vorgangNummerSupplier.initWithPrefix();
+	@Test
+	void shouldAddHyphenAtEnd() {
+		var result = vorgangNummerSupplier.get();
 
-			assertThat(resultBuilder.charAt(5)).isEqualTo('-');
-		}
+		assertThat(result.charAt(4)).isEqualTo('-');
 	}
 
 }
\ No newline at end of file
diff --git a/enterprise-adapter/pom.xml b/enterprise-adapter/pom.xml
index 700bdf13443af604fb839c2acd11e8e991ef945d..c473beedb33594307ca3b95fbdad4a1ec709c2c5 100644
--- a/enterprise-adapter/pom.xml
+++ b/enterprise-adapter/pom.xml
@@ -35,9 +35,7 @@
 	<name>EM - Enterprise Interface Adapter</name>
 
 	<properties>
-		<spring-boot.build-image.imageName>
-			docker.ozg-sh.de/enterprise-adapter:build-latest
-		</spring-boot.build-image.imageName>
+		<spring-boot.build-image.imageName>docker.ozg-sh.de/enterprise-adapter:build-latest</spring-boot.build-image.imageName>
 	</properties>
 
 	<dependencies>
diff --git a/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/FormDataController.java b/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/FormDataController.java
index b79d3a951c53f0853ff0cdde4dbfef9c0966f56c..d860e7833dc3cb2c41fa2255247015d8a6798575 100644
--- a/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/FormDataController.java
+++ b/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/FormDataController.java
@@ -40,7 +40,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
 import org.springframework.web.multipart.MultipartFile;
 
 import de.ozgcloud.common.binaryfile.TempFileUtils;
-import de.ozgcloud.eingang.common.errorhandling.TechnicalException;
+import de.ozgcloud.common.errorhandling.TechnicalException;
 import de.ozgcloud.eingang.common.formdata.FormData;
 import de.ozgcloud.eingang.common.formdata.IncomingFile;
 import de.ozgcloud.eingang.common.formdata.IncomingFileGroup;
@@ -60,11 +60,13 @@ import lombok.extern.log4j.Log4j2;
 @RequiredArgsConstructor
 class FormDataController {
 
+	public static final String HTTP_TYPE_PROTOBUF = "application/x-protobuf";
+
 	private final FormCycleFormDataMapper mapper;
 	private final SemantikAdapter semantikAdapter;
 	private final VorgangNummerSupplier vorgangNummerSupplier;
 
-	@PostMapping(consumes = "multipart/form-data", produces = "application/protobuf")
+	@PostMapping(consumes = "multipart/form-data", produces = HTTP_TYPE_PROTOBUF)
 	public FormCycleConfirmationResponse receiveFormData(@RequestPart FormCycleFormData formData,
 			@RequestPart(required = false) Optional<Collection<MultipartFile>> representations,
 			@RequestPart(required = false) Optional<Collection<MultipartFile>> attachments) {
diff --git a/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/FormcycleAdapterApplication.java b/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/FormcycleAdapterApplication.java
index 8f0e8a7768ac9384a3c348d35a9a57f468cc8f3d..dddbd8f53cba6ef112fe68bc79e5689ebb89100b 100644
--- a/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/FormcycleAdapterApplication.java
+++ b/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/FormcycleAdapterApplication.java
@@ -23,12 +23,18 @@
  */
 package de.ozgcloud.eingang.formcycle;
 
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
 import java.util.TimeZone;
 
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.context.annotation.Bean;
+import org.springframework.http.MediaType;
+import org.springframework.http.converter.protobuf.ProtobufHttpMessageConverter;
 
+import de.ozgcloud.eingang.formcycle.common.errorhandling.FormcycleExceptionHandler;
+import de.ozgcloud.eingang.formcycle.common.protobuf.CustomProtobufHttpMessageConverter;
 import de.ozgcloud.eingang.semantik.enginebased.EngineBasedSemantikAdapter;
 import de.ozgcloud.eingang.semantik.enginebased.formcycle.FormCycleEngineBasedAdapter;
 
@@ -44,4 +50,23 @@ public class FormcycleAdapterApplication {
 	EngineBasedSemantikAdapter engineBasedAdapter() {
 		return new FormCycleEngineBasedAdapter();
 	}
+
+	@Bean
+	ProtobufHttpMessageConverter protobufMessageConverter() {
+		return addCustomProtobufMediaType(new CustomProtobufHttpMessageConverter());
+	}
+
+	@Deprecated(forRemoval = true, since = "2.1.0")
+	// FIXME: Remove this method after all customers have updated ozg-cloud plugin to version 1.4.0 or higher
+	private ProtobufHttpMessageConverter addCustomProtobufMediaType(ProtobufHttpMessageConverter protobufHttpMessageConverter) {
+		var supportetMediaTypes = new ArrayList<>(protobufHttpMessageConverter.getSupportedMediaTypes());
+		supportetMediaTypes.add(new MediaType("application", "protobuf", StandardCharsets.UTF_8));
+		protobufHttpMessageConverter.setSupportedMediaTypes(supportetMediaTypes);
+		return protobufHttpMessageConverter;
+	}
+
+	@Bean
+	FormcycleExceptionHandler restResposeEntityExceptionHandler() {
+		return new FormcycleExceptionHandler();
+	}
 }
diff --git a/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/common/errorhandling/FormcycleExceptionHandler.java b/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/common/errorhandling/FormcycleExceptionHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..d98bdc6aaf6a18ee25015f577945b356205ae3a2
--- /dev/null
+++ b/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/common/errorhandling/FormcycleExceptionHandler.java
@@ -0,0 +1,74 @@
+package de.ozgcloud.eingang.formcycle.common.errorhandling;
+
+import java.util.UUID;
+
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.context.request.WebRequest;
+import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
+
+import de.ozgcloud.common.errorhandling.ExceptionUtil;
+import de.ozgcloud.common.errorhandling.TechnicalException;
+import io.grpc.StatusRuntimeException;
+import lombok.extern.log4j.Log4j2;
+
+@ControllerAdvice
+@Log4j2
+public class FormcycleExceptionHandler extends ResponseEntityExceptionHandler {
+
+	static final String TECHNICAL_EXCEPTION_MESSAGE = "Cannot process request.";
+	static final String CREATE_VORGANG_EXCEPTION_MESSAGE = "Cannot create vorgang.";
+	static final String UNEXPECTED_EXCEPTION_MESSAGE = "An unexpected error occurred.";
+
+	private static final String EXCEPTION_ID_TEMPLATE = "(ExceptionId:";
+
+	@ExceptionHandler({ TechnicalException.class })
+	public ResponseEntity<InternalExceptionDto> handleTechnicalException(TechnicalException e, WebRequest request) {
+		LOG.error(TECHNICAL_EXCEPTION_MESSAGE, e);
+		return buildResponseEntity(TECHNICAL_EXCEPTION_MESSAGE, e.getExceptionId());
+	}
+
+	@ExceptionHandler({ StatusRuntimeException.class })
+	public ResponseEntity<InternalExceptionDto> handleStatusRuntimeException(StatusRuntimeException e, WebRequest request) {
+		var logMessage = TECHNICAL_EXCEPTION_MESSAGE;
+		var exceptionId = getExceptionId(e.getMessage());
+		if (!hasExceptionId(e.getMessage())) {
+			logMessage = ExceptionUtil.formatMessageWithExceptionId(CREATE_VORGANG_EXCEPTION_MESSAGE, exceptionId);
+		}
+		LOG.error(logMessage, e);
+		return buildResponseEntity(CREATE_VORGANG_EXCEPTION_MESSAGE, exceptionId);
+	}
+
+	boolean hasExceptionId(String message) {
+		return message.contains(EXCEPTION_ID_TEMPLATE);
+	}
+
+	String getExceptionId(String message) {
+		try {
+			return message.substring(message.indexOf(EXCEPTION_ID_TEMPLATE) + 14, message.indexOf(")"));
+		} catch (IndexOutOfBoundsException e) {
+			return createExceptionId();
+		}
+	}
+
+	@ExceptionHandler({ RuntimeException.class })
+	public ResponseEntity<InternalExceptionDto> handleUnexpectedException(RuntimeException e, WebRequest request) {
+		var exceptionId = createExceptionId();
+		var messageWithExceptionId = ExceptionUtil.formatMessageWithExceptionId(UNEXPECTED_EXCEPTION_MESSAGE, exceptionId);
+		LOG.error(messageWithExceptionId, e);
+		return buildResponseEntity(UNEXPECTED_EXCEPTION_MESSAGE, exceptionId);
+	}
+
+	String createExceptionId() {
+		return UUID.randomUUID().toString();
+	}
+
+	ResponseEntity<InternalExceptionDto> buildResponseEntity(String message, String exceptionId) {
+		return ResponseEntity.internalServerError().body(buildInternalExceptionDto(message, exceptionId));
+	}
+
+	InternalExceptionDto buildInternalExceptionDto(String message, String exceptionId) {
+		return InternalExceptionDto.builder().message(message).exceptionId(exceptionId).build();
+	}
+}
diff --git a/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/common/errorhandling/InternalExceptionDto.java b/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/common/errorhandling/InternalExceptionDto.java
new file mode 100644
index 0000000000000000000000000000000000000000..9e72ccd3baee345ffa744753b3bf01c189caa247
--- /dev/null
+++ b/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/common/errorhandling/InternalExceptionDto.java
@@ -0,0 +1,12 @@
+package de.ozgcloud.eingang.formcycle.common.errorhandling;
+
+import lombok.Builder;
+import lombok.Getter;
+
+@Builder
+@Getter
+public class InternalExceptionDto {
+
+	private String exceptionId;
+	private String message;
+}
diff --git a/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/common/protobuf/CustomProtobufHttpMessageConverter.java b/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/common/protobuf/CustomProtobufHttpMessageConverter.java
new file mode 100644
index 0000000000000000000000000000000000000000..6a6ab8e0fca7eb2ac7111aef84ec2d2c6039bcc4
--- /dev/null
+++ b/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/common/protobuf/CustomProtobufHttpMessageConverter.java
@@ -0,0 +1,19 @@
+package de.ozgcloud.eingang.formcycle.common.protobuf;
+
+import java.io.IOException;
+
+import org.springframework.http.HttpInputMessage;
+import org.springframework.http.converter.protobuf.ProtobufHttpMessageConverter;
+
+import com.google.protobuf.Message;
+
+@Deprecated(forRemoval = true, since = "2.1.0")
+// FIXME: Remove this class after all customers have updated ozg-cloud plugin to version 1.4.0 or higher
+public class CustomProtobufHttpMessageConverter extends ProtobufHttpMessageConverter {
+
+	@Override
+	protected Message readInternal(Class<? extends Message> clazz, HttpInputMessage inputMessage) throws IOException {
+		inputMessage.getHeaders().setContentType(ProtobufHttpMessageConverter.PROTOBUF);
+		return super.readInternal(clazz, inputMessage);
+	}
+}
diff --git a/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/common/protobuf/ProtobufMessageConverter.java b/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/common/protobuf/ProtobufMessageConverter.java
deleted file mode 100644
index b26262f97fa6f805b875ea187021b24d5f6d636e..0000000000000000000000000000000000000000
--- a/formcycle-adapter/formcycle-adapter-impl/src/main/java/de/ozgcloud/eingang/formcycle/common/protobuf/ProtobufMessageConverter.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * 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.eingang.formcycle.common.protobuf;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Type;
-
-import org.springframework.http.HttpInputMessage;
-import org.springframework.http.HttpOutputMessage;
-import org.springframework.http.MediaType;
-import org.springframework.http.converter.AbstractGenericHttpMessageConverter;
-import org.springframework.http.converter.HttpMessageNotReadableException;
-import org.springframework.http.converter.HttpMessageNotWritableException;
-import org.springframework.stereotype.Component;
-
-import com.google.protobuf.CodedOutputStream;
-
-import de.ozgcloud.common.errorhandling.TechnicalException;
-import lombok.extern.log4j.Log4j2;
-
-@Component
-@Log4j2
-public class ProtobufMessageConverter extends AbstractGenericHttpMessageConverter<Object> {
-
-	public ProtobufMessageConverter() {
-		super(new MediaType(com.google.common.net.MediaType.PROTOBUF.type(), com.google.common.net.MediaType.PROTOBUF.subtype()));
-	}
-
-	@Override
-	protected void writeInternal(Object t, Type type, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
-		try {
-			var writeMethod = Class.forName(type.getTypeName()).getMethod("writeTo", CodedOutputStream.class);
-			CodedOutputStream out = CodedOutputStream.newInstance(outputMessage.getBody());
-			writeMethod.invoke(t, out);
-			out.flush();
-		} catch (NoSuchMethodException | SecurityException | ClassNotFoundException | IllegalAccessException | IllegalArgumentException
-				| InvocationTargetException e) {
-			LOG.error("Error writing response", e);
-			throw new TechnicalException("Error writing response.", e);
-		}
-
-	}
-
-	@Override
-	public Object read(Type type, Class<?> contextClass, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
-		try {
-			return readInternal(Class.forName(type.getTypeName()), inputMessage);
-		} catch (HttpMessageNotReadableException | ClassNotFoundException | IOException e) {
-			LOG.error("Error getting target class", e);
-			throw new TechnicalException("Error getting target class", e);
-		}
-	}
-
-	@Override
-	protected Object readInternal(Class<? extends Object> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
-		try {
-			var parserMethod = clazz.getMethod("parseFrom", InputStream.class);
-			return parserMethod.invoke(null, inputMessage.getBody());
-		} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
-			LOG.error("Error on reading protobuf data.", e);
-			throw new TechnicalException("Error on reading protobuf data.", e);
-		}
-	}
-}
diff --git a/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/FormDataControllerITCase.java b/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/FormDataControllerITCase.java
index e25ac53a1168a14b152d7ec4bab8bc4694ff11ac..e3e878598707b5d02b85d7ef618ebd3b1f3b8cec 100644
--- a/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/FormDataControllerITCase.java
+++ b/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/FormDataControllerITCase.java
@@ -73,7 +73,7 @@ class FormDataControllerITCase {
 		private ResultActions doPostRequest() {
 			return mockMvc.perform(
 					multipart("/formData")
-							.file(new MockMultipartFile("formData", null, "application/protobuf", buildTestFormData()))
+							.file(new MockMultipartFile("formData", null, FormDataController.HTTP_TYPE_PROTOBUF, buildTestFormData()))
 							.file(IncomingFileTestFactory.asMultipartFile("representations"))
 							.file(asMultipartFile("attachments",
 									createBuilder().name(IncomingFileGroupTestFactory.VENDOR_ID_XXX + "__" + NAME).build())));
diff --git a/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/FormDataControllerTest.java b/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/FormDataControllerTest.java
index 1e9430b99f44ee7befc31568c96d3fe940622868..4ff5e49568537a304f76b9f1c568701b1e87240d 100644
--- a/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/FormDataControllerTest.java
+++ b/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/FormDataControllerTest.java
@@ -42,6 +42,7 @@ import org.mockito.Captor;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.Spy;
+import org.springframework.http.converter.protobuf.ProtobufHttpMessageConverter;
 import org.springframework.mock.web.MockMultipartFile;
 import org.springframework.test.web.servlet.MockMvc;
 import org.springframework.test.web.servlet.ResultActions;
@@ -55,7 +56,6 @@ import de.ozgcloud.eingang.common.formdata.IncomingFileTestFactory;
 import de.ozgcloud.eingang.common.formdata.ServiceKonto.PostfachAddress;
 import de.ozgcloud.eingang.common.vorgang.VorgangNummerSupplier;
 import de.ozgcloud.eingang.common.formdata.StringBasedIdentifier;
-import de.ozgcloud.eingang.formcycle.common.protobuf.ProtobufMessageConverter;
 import de.ozgcloud.eingang.semantik.SemantikAdapter;
 import lombok.SneakyThrows;
 
@@ -77,7 +77,7 @@ class FormDataControllerTest {
 	@BeforeEach
 	void init() {
 		mockMvc = MockMvcBuilders.standaloneSetup(controller)
-				.setMessageConverters(new ProtobufMessageConverter())
+				.setMessageConverters(new ProtobufHttpMessageConverter())
 				.build();
 	}
 
@@ -186,7 +186,7 @@ class FormDataControllerTest {
 			void shouldBeFineWithoutRepresentations() {
 				mockMvc.perform(
 						multipart("/formData")
-								.file(new MockMultipartFile("formData", null, "application/protobuf", buildTestFormData())))
+								.file(new MockMultipartFile("formData", null, FormDataController.HTTP_TYPE_PROTOBUF, buildTestFormData())))
 						.andExpect(status().isOk());
 			}
 		}
@@ -221,7 +221,7 @@ class FormDataControllerTest {
 		private ResultActions doPostRequest() {
 			return mockMvc.perform(
 					multipart("/formData")
-							.file(new MockMultipartFile("formData", null, "application/protobuf", buildTestFormData()))
+							.file(new MockMultipartFile("formData", null, FormDataController.HTTP_TYPE_PROTOBUF, buildTestFormData()))
 							.file(IncomingFileTestFactory.asMultipartFile("representations"))
 							.file(asMultipartFile("attachments",
 									createBuilder().name(IncomingFileGroupTestFactory.VENDOR_ID_XXX).build())));
diff --git a/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/common/errorhandling/FormcycleExceptionHandlerTest.java b/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/common/errorhandling/FormcycleExceptionHandlerTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..f5e8ffaf282d688e800ab64cd87d57a478c0fd81
--- /dev/null
+++ b/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/common/errorhandling/FormcycleExceptionHandlerTest.java
@@ -0,0 +1,126 @@
+package de.ozgcloud.eingang.formcycle.common.errorhandling;
+
+import static de.ozgcloud.eingang.formcycle.common.errorhandling.InternalExceptionDtoTestFactory.*;
+import static org.assertj.core.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+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.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+
+import de.ozgcloud.common.errorhandling.ExceptionUtil;
+import de.ozgcloud.common.errorhandling.TechnicalException;
+import io.grpc.StatusRuntimeException;
+
+class FormcycleExceptionHandlerTest {
+
+	@Spy
+	@InjectMocks
+	private FormcycleExceptionHandler exceptionHandler;
+
+	@Nested
+	class TestHandleTechnicalException {
+
+		@Mock
+		private TechnicalException technicalException;
+
+		@Test
+		void shouldCallBuildResponseEntity() {
+			when(technicalException.getExceptionId()).thenReturn(EXCEPTION_ID);
+
+			exceptionHandler.handleTechnicalException(technicalException, null);
+
+			verify(exceptionHandler).buildResponseEntity(FormcycleExceptionHandler.TECHNICAL_EXCEPTION_MESSAGE, EXCEPTION_ID);
+		}
+
+	}
+
+	@Nested
+	class TestHandleStatusRuntimeException {
+
+		@Mock
+		private StatusRuntimeException statusRuntimeException;
+
+		@Test
+		void shouldCallBuildResponseEntity() {
+			when(statusRuntimeException.getStackTrace()).thenReturn(new StackTraceElement[0]);
+			when(statusRuntimeException.getMessage()).thenReturn(ExceptionUtil.formatMessageWithExceptionId(MESSAGE, EXCEPTION_ID));
+
+			exceptionHandler.handleStatusRuntimeException(statusRuntimeException, null);
+
+			verify(exceptionHandler).buildResponseEntity(FormcycleExceptionHandler.CREATE_VORGANG_EXCEPTION_MESSAGE, EXCEPTION_ID);
+		}
+
+		@Nested
+		class TestGetExceptionId {
+
+			@Test
+			void shouldReturnExceptionIdFromMessage() {
+				var exceptionId = exceptionHandler.getExceptionId(messageWithExceptionId());
+
+				assertThat(exceptionId).isEqualTo(EXCEPTION_ID);
+			}
+
+			@Test
+			void shouldCreateNewExceptionId() {
+				var exceptionId = exceptionHandler.getExceptionId(MESSAGE);
+
+				assertThat(exceptionId).isNotEqualTo(EXCEPTION_ID);
+			}
+
+		}
+
+	}
+
+	@Nested
+	class TestBuildResponseEntity {
+
+		@Test
+		void shouldReturnInternaServerError() {
+			var response = buildResponseEntity();
+
+			assertThat(response.getStatusCode()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR);
+		}
+
+		@Test
+		void shouldCallBuildInternalExceptionDto() {
+			buildResponseEntity();
+
+			verify(exceptionHandler).buildInternalExceptionDto(InternalExceptionDtoTestFactory.MESSAGE, EXCEPTION_ID);
+		}
+
+		private ResponseEntity<InternalExceptionDto> buildResponseEntity() {
+			return exceptionHandler.buildResponseEntity(InternalExceptionDtoTestFactory.MESSAGE, EXCEPTION_ID);
+		}
+
+	}
+
+	@Nested
+	class TestBuildInternalExceptionDto {
+
+		@Test
+		void shouldSetExceptionId() {
+			var response = buildInternalExceptionDto();
+
+			assertThat(response.getExceptionId()).isEqualTo(EXCEPTION_ID);
+		}
+
+		@Test
+		void shouldSetMessage() {
+			var response = buildInternalExceptionDto();
+
+			assertThat(response.getMessage()).isEqualTo(InternalExceptionDtoTestFactory.MESSAGE);
+		}
+
+		private InternalExceptionDto buildInternalExceptionDto() {
+			return exceptionHandler.buildInternalExceptionDto(InternalExceptionDtoTestFactory.MESSAGE, EXCEPTION_ID);
+		}
+
+	}
+}
\ No newline at end of file
diff --git a/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/common/errorhandling/InternalExceptionDtoTestFactory.java b/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/common/errorhandling/InternalExceptionDtoTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..98a8e5f27c53fd8676f1233ae24e3bf7c42306eb
--- /dev/null
+++ b/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/common/errorhandling/InternalExceptionDtoTestFactory.java
@@ -0,0 +1,22 @@
+package de.ozgcloud.eingang.formcycle.common.errorhandling;
+
+import de.ozgcloud.common.errorhandling.ExceptionUtil;
+import de.ozgcloud.eingang.formcycle.common.errorhandling.InternalExceptionDto.InternalExceptionDtoBuilder;
+
+public class InternalExceptionDtoTestFactory {
+
+	public static final String EXCEPTION_ID = "exception-id";
+	public static final String MESSAGE = "exception message";
+
+	public static InternalExceptionDto create() {
+		return createBuilder().build();
+	}
+
+	private static InternalExceptionDtoBuilder createBuilder() {
+		return InternalExceptionDto.builder().exceptionId(EXCEPTION_ID).message(MESSAGE);
+	}
+
+	public static String messageWithExceptionId() {
+		return ExceptionUtil.formatMessageWithExceptionId(MESSAGE, EXCEPTION_ID);
+	}
+}
diff --git a/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/common/protobuf/ProtobufMessageConverterTest.java b/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/common/protobuf/ProtobufMessageConverterTest.java
deleted file mode 100644
index aa8b6462bfc72c3d2c872cf9f48883b9621fddee..0000000000000000000000000000000000000000
--- a/formcycle-adapter/formcycle-adapter-impl/src/test/java/de/ozgcloud/eingang/formcycle/common/protobuf/ProtobufMessageConverterTest.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * 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.eingang.formcycle.common.protobuf;
-
-import static org.assertj.core.api.Assertions.*;
-import static org.mockito.ArgumentMatchers.*;
-import static org.mockito.Mockito.*;
-
-import java.lang.reflect.Type;
-
-import org.junit.jupiter.api.Nested;
-import org.junit.jupiter.api.Test;
-import org.mockito.InjectMocks;
-import org.mockito.Spy;
-import org.springframework.http.HttpInputMessage;
-import org.springframework.http.HttpOutputMessage;
-
-import de.ozgcloud.common.errorhandling.TechnicalException;
-import de.ozgcloud.eingang.formcycle.common.protobuf.ProtobufMessageConverter;
-import lombok.SneakyThrows;
-
-class ProtobufMessageConverterTest {
-
-	@Spy
-	@InjectMocks
-	private ProtobufMessageConverter converter;
-
-	@Nested
-	class TestRead {
-
-		private HttpInputMessage inputMessage = mock(HttpInputMessage.class);
-
-		@Test
-		@SneakyThrows
-		void shouldCallReadInternal() {
-			doReturn(null).when(converter).readInternal(any(), any());
-
-			converter.read(String.class, Object.class, inputMessage);
-
-			verify(converter).readInternal(eq(String.class), same(inputMessage));
-		}
-
-		@Test
-		@SneakyThrows
-		void shouldThrowTechnicalException() {
-			var mockType = buildMockType();
-
-			assertThatThrownBy(() -> converter.read(mockType, Object.class, inputMessage)).isInstanceOf(TechnicalException.class);
-		}
-	}
-
-	@Nested
-	class TestReadInternal {
-		@Test
-		void shouldThrowTechnicalException() {
-			assertThatThrownBy(() -> converter.readInternal(Object.class, mock(HttpInputMessage.class)))
-					.isInstanceOf(TechnicalException.class);
-		}
-	}
-
-	@Nested
-	class TestWriteInternal {
-		@Test
-		void shouldThrowTechnicalException() {
-			var mockType = buildMockType();
-
-			assertThatThrownBy(() -> converter.writeInternal("test", mockType, mock(HttpOutputMessage.class)))
-					.isInstanceOf(TechnicalException.class);
-		}
-	}
-
-	private Type buildMockType() {
-		var mockType = mock(Type.class);
-		when(mockType.getTypeName()).thenReturn("quatsch");
-
-		return mockType;
-	}
-}
diff --git a/formcycle-adapter/formcycle-adapter-interface/pom.xml b/formcycle-adapter/formcycle-adapter-interface/pom.xml
index 5320f70c635a027707217dfc427b2d5b6372d1ae..28a72c95a2b5c17a1dcf768d0bb51e9e1a8ece6e 100644
--- a/formcycle-adapter/formcycle-adapter-interface/pom.xml
+++ b/formcycle-adapter/formcycle-adapter-interface/pom.xml
@@ -55,7 +55,7 @@
 			<groupId>de.ozgcloud.vorgang</groupId>
 			<artifactId>vorgang-manager-interface</artifactId>
 			<classifier>sources</classifier>
-			<scope>compile</scope>
+			<scope>provided</scope>
 			<version>${vorgang-manager.version}</version>
 		</dependency>
 
diff --git a/formsolutions-adapter/src/test/java/de/ozgcloud/eingang/formsolutions/FormsolutionsITCase.java b/formsolutions-adapter/src/test/java/de/ozgcloud/eingang/formsolutions/FormsolutionsITCase.java
index ce0ebc98e684dc3cac7c5a501ecd24bb16ff8fc5..8a2f3c291eb730fa9a0f93b6291bdd2e15dc9555 100644
--- a/formsolutions-adapter/src/test/java/de/ozgcloud/eingang/formsolutions/FormsolutionsITCase.java
+++ b/formsolutions-adapter/src/test/java/de/ozgcloud/eingang/formsolutions/FormsolutionsITCase.java
@@ -86,7 +86,7 @@ public class FormsolutionsITCase {
 		}
 
 		private GrpcCreateVorgangRequest getCreateVorgangRequest() {
-			verify(blockingStub, timeout(60000)).startCreation(createVorgangRequestCaptor.capture());
+			verify(blockingStub, timeout(1000)).startCreation(createVorgangRequestCaptor.capture());
 			return createVorgangRequestCaptor.getValue();
 		}
 	}
diff --git a/intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/CustomHeaderReader.java b/intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/CustomHeaderReader.java
new file mode 100644
index 0000000000000000000000000000000000000000..dad25e9f009aa064cc79e5837ccf4687d0dcdc89
--- /dev/null
+++ b/intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/CustomHeaderReader.java
@@ -0,0 +1,68 @@
+/*
+ * 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.eingang.intelliform;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.function.Consumer;
+
+import org.springframework.stereotype.Component;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+
+@Component
+public class CustomHeaderReader {
+
+	public static final String HEADER_POSTFACH_ID = "u:saml_legacypostkorbhandle";
+	public static final String HEADER_VORNAME = "u:saml_givenname";
+	public static final String HEADER_NACHNAME = "u:saml_surname";
+	public static final String HEADER_GEBURTSORT = "u:saml_placeofbirth";
+	public static final String HEADER_GEBURTSNAME = "u:saml_birthname";
+	public static final String HEADER_EMAIL = "u:saml_mail";
+	public static final String HEADER_TELEFON = "u:saml_telephonenumber";
+	public static final String HEADER_STRASSE = "u:saml_postaladdress";
+	public static final String HEADER_PLZ = "u:saml_postalcode";
+	public static final String HEADER_ORT = "u:saml_localityname";
+
+	public Map<String, Object> getHeader(Document document) {
+		var map = new HashMap<String, Object>();
+		Consumer<Attr> addHeader = attr -> map.put(attr.getName(), attr.getValue());
+		getAttribute(document, HEADER_POSTFACH_ID).ifPresent(addHeader);
+		getAttribute(document, HEADER_VORNAME).ifPresent(addHeader);
+		getAttribute(document, HEADER_NACHNAME).ifPresent(addHeader);
+		getAttribute(document, HEADER_GEBURTSNAME).ifPresent(addHeader);
+		getAttribute(document, HEADER_GEBURTSORT).ifPresent(addHeader);
+		getAttribute(document, HEADER_EMAIL).ifPresent(addHeader);
+		getAttribute(document, HEADER_TELEFON).ifPresent(addHeader);
+		getAttribute(document, HEADER_STRASSE).ifPresent(addHeader);
+		getAttribute(document, HEADER_PLZ).ifPresent(addHeader);
+		getAttribute(document, HEADER_ORT).ifPresent(addHeader);
+		return map;
+	}
+
+	Optional<Attr> getAttribute(Document document, String name) {
+		return Optional.ofNullable(document.getDocumentElement().getAttributeNode(name));
+	}
+}
\ No newline at end of file
diff --git a/intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/SemantikFormDataMapper.java b/intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/SemantikFormDataMapper.java
index 5d9faa593aa0a61b19dee676ab2a233106e010f3..f4796328f0f9469c17291a9f4dfda6655c1213cf 100644
--- a/intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/SemantikFormDataMapper.java
+++ b/intelliform-adapter/src/main/java/de/ozgcloud/eingang/intelliform/SemantikFormDataMapper.java
@@ -86,6 +86,9 @@ class SemantikFormDataMapper {
 	@Autowired
 	private final AttachmentsContentAdder attachmentsContentAdder;
 
+	@Autowired
+	private final CustomHeaderReader customHeaderReader;
+
 	public FormData mapToFormData(Deposit depositData) {
 		var xmlFormDataStream = getXmlFormData(depositData.getData());
 
@@ -156,6 +159,7 @@ class SemantikFormDataMapper {
 		map.put(HEADER_CUSTOMER_ID, document.getDocumentElement().getAttribute(HEADER_CUSTOMER_ID));
 		map.put(HEADER_CLIENT, document.getDocumentElement().getAttribute(HEADER_CLIENT));
 		map.put(HEADER_CLIENT_ID, document.getDocumentElement().getAttribute(HEADER_CLIENT_ID));
+		map.putAll(customHeaderReader.getHeader(document));
 		return map;
 	}
 }
\ No newline at end of file
diff --git a/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/CustomHeaderReaderTest.java b/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/CustomHeaderReaderTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..eb435c85ecd0d0dc5214f7a595abc7bd9632f396
--- /dev/null
+++ b/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/CustomHeaderReaderTest.java
@@ -0,0 +1,171 @@
+/*
+ * 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.eingang.intelliform;
+
+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 org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+class CustomHeaderReaderTest {
+
+	@InjectMocks
+	private CustomHeaderReader reader;
+
+	@Mock
+	private Document document;
+	@Mock
+	private Element element;
+	@Mock
+	private Attr attribute;
+
+	@BeforeEach
+	void setup() {
+		when(document.getDocumentElement()).thenReturn(element);
+	}
+
+	@Test
+	void shouldNotAddIfNotPresent() {
+		var formData = reader.getHeader(document);
+
+		assertThat(formData).isEmpty();
+	}
+
+	@Nested
+	class TestHeaderAdded {
+
+		@BeforeEach
+		void setup() {
+			when(element.getAttributeNode(any())).thenReturn(attribute);
+		}
+
+		@Test
+		void shouldAddPostfachId() {
+			when(attribute.getName()).thenReturn(CustomHeaderReader.HEADER_POSTFACH_ID);
+			when(attribute.getValue()).thenReturn(CustomHeaderTestFactory.POSTFACH_ID);
+
+			var formData = reader.getHeader(document);
+
+			assertThat(formData).containsEntry(CustomHeaderReader.HEADER_POSTFACH_ID, CustomHeaderTestFactory.POSTFACH_ID);
+		}
+
+		@Test
+		void shouldAddVorname() {
+			when(attribute.getName()).thenReturn(CustomHeaderReader.HEADER_VORNAME);
+			when(attribute.getValue()).thenReturn(CustomHeaderTestFactory.VORNAME);
+
+			var formData = reader.getHeader(document);
+
+			assertThat(formData).containsEntry(CustomHeaderReader.HEADER_VORNAME, CustomHeaderTestFactory.VORNAME);
+		}
+
+		@Test
+		void shouldAddNachname() {
+			when(attribute.getName()).thenReturn(CustomHeaderReader.HEADER_NACHNAME);
+			when(attribute.getValue()).thenReturn(CustomHeaderTestFactory.NACHNAME);
+
+			var formData = reader.getHeader(document);
+
+			assertThat(formData).containsEntry(CustomHeaderReader.HEADER_NACHNAME, CustomHeaderTestFactory.NACHNAME);
+		}
+
+		@Test
+		void shouldAddGeburtsname() {
+			when(attribute.getName()).thenReturn(CustomHeaderReader.HEADER_GEBURTSNAME);
+			when(attribute.getValue()).thenReturn(CustomHeaderTestFactory.GEBURTSNAME);
+
+			var formData = reader.getHeader(document);
+
+			assertThat(formData).containsEntry(CustomHeaderReader.HEADER_GEBURTSNAME, CustomHeaderTestFactory.GEBURTSNAME);
+		}
+
+		@Test
+		void shouldAddGeburtsort() {
+			when(attribute.getName()).thenReturn(CustomHeaderReader.HEADER_GEBURTSORT);
+			when(attribute.getValue()).thenReturn(CustomHeaderTestFactory.GEBURTSORT);
+
+			var formData = reader.getHeader(document);
+
+			assertThat(formData).containsEntry(CustomHeaderReader.HEADER_GEBURTSORT, CustomHeaderTestFactory.GEBURTSORT);
+		}
+
+		@Test
+		void shouldAddEmail() {
+			when(attribute.getName()).thenReturn(CustomHeaderReader.HEADER_EMAIL);
+			when(attribute.getValue()).thenReturn(CustomHeaderTestFactory.EMAIL);
+
+			var formData = reader.getHeader(document);
+
+			assertThat(formData).containsEntry(CustomHeaderReader.HEADER_EMAIL, CustomHeaderTestFactory.EMAIL);
+		}
+
+		@Test
+		void shouldAddTelefon() {
+			when(attribute.getName()).thenReturn(CustomHeaderReader.HEADER_TELEFON);
+			when(attribute.getValue()).thenReturn(CustomHeaderTestFactory.TELEFON);
+
+			var formData = reader.getHeader(document);
+
+			assertThat(formData).containsEntry(CustomHeaderReader.HEADER_TELEFON, CustomHeaderTestFactory.TELEFON);
+		}
+
+		@Test
+		void shouldAddStrasse() {
+			when(attribute.getName()).thenReturn(CustomHeaderReader.HEADER_STRASSE);
+			when(attribute.getValue()).thenReturn(CustomHeaderTestFactory.STRASSE);
+
+			var formData = reader.getHeader(document);
+
+			assertThat(formData).containsEntry(CustomHeaderReader.HEADER_STRASSE, CustomHeaderTestFactory.STRASSE);
+		}
+
+		@Test
+		void shouldAddPlz() {
+			when(attribute.getName()).thenReturn(CustomHeaderReader.HEADER_PLZ);
+			when(attribute.getValue()).thenReturn(CustomHeaderTestFactory.PLZ);
+
+			var formData = reader.getHeader(document);
+
+			assertThat(formData).containsEntry(CustomHeaderReader.HEADER_PLZ, CustomHeaderTestFactory.PLZ);
+		}
+
+		@Test
+		void shouldAddOrt() {
+			when(attribute.getName()).thenReturn(CustomHeaderReader.HEADER_ORT);
+			when(attribute.getValue()).thenReturn(CustomHeaderTestFactory.ORT);
+
+			var formData = reader.getHeader(document);
+
+			assertThat(formData).containsEntry(CustomHeaderReader.HEADER_ORT, CustomHeaderTestFactory.ORT);
+		}
+	}
+
+}
\ No newline at end of file
diff --git a/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/CustomHeaderTestFactory.java b/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/CustomHeaderTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..acb9fede61f17309e4417fac7149f5d03177c588
--- /dev/null
+++ b/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/CustomHeaderTestFactory.java
@@ -0,0 +1,58 @@
+/*
+ * 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.eingang.intelliform;
+
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class CustomHeaderTestFactory {
+
+	public static final String POSTFACH_ID = "postfach_id";
+	public static final String VORNAME = "vorname";
+	public static final String NACHNAME = "nachname";
+	public static final String GEBURTSNAME = "geburtsname";
+	public static final String GEBURTSORT = "geburtsort";
+	public static final String EMAIL = "email";
+	public static final String TELEFON = "telefon";
+	public static final String STRASSE = "strasse";
+	public static final String PLZ = "plz";
+	public static final String ORT = "ort";
+
+	public static Map<String, Object> create() {
+		var map = new HashMap<String, Object>();
+		map.put(CustomHeaderReader.HEADER_POSTFACH_ID, POSTFACH_ID);
+		map.put(CustomHeaderReader.HEADER_VORNAME, VORNAME);
+		map.put(CustomHeaderReader.HEADER_NACHNAME, NACHNAME);
+		map.put(CustomHeaderReader.HEADER_GEBURTSNAME, GEBURTSNAME);
+		map.put(CustomHeaderReader.HEADER_GEBURTSORT, GEBURTSORT);
+		map.put(CustomHeaderReader.HEADER_EMAIL, EMAIL);
+		map.put(CustomHeaderReader.HEADER_TELEFON, TELEFON);
+		map.put(CustomHeaderReader.HEADER_STRASSE, STRASSE);
+		map.put(CustomHeaderReader.HEADER_PLZ, PLZ);
+		map.put(CustomHeaderReader.HEADER_ORT, ORT);
+		return map;
+	}
+
+}
diff --git a/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/SemantikFormDataMapperTest.java b/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/SemantikFormDataMapperTest.java
index 36f64310aaf25183df3acdb36f93567032e43576..3bf90315f3d0be4e23ea2de093908455ad32b18e 100644
--- a/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/SemantikFormDataMapperTest.java
+++ b/intelliform-adapter/src/test/java/de/ozgcloud/eingang/intelliform/SemantikFormDataMapperTest.java
@@ -25,6 +25,8 @@ package de.ozgcloud.eingang.intelliform;
 
 import static de.ozgcloud.eingang.common.formdata.IncomingFileGroupTestFactory.*;
 import static org.assertj.core.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.*;
 
 import java.io.IOException;
 import java.util.HashMap;
@@ -33,8 +35,10 @@ import java.util.Map;
 
 import javax.xml.parsers.ParserConfigurationException;
 
+import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
+import org.mockito.Mock;
 import org.xml.sax.SAXException;
 
 import de.ozgcloud.eingang.common.formdata.FormData;
@@ -43,8 +47,16 @@ import de.ozgcloud.eingang.semantik.enginebased.FilesMapperHelper;
 
 class SemantikFormDataMapperTest {
 
-	private SemantikFormDataMapper mapper = new SemantikFormDataMapper(new XmlToJavaMapsMapper(), new FormDataIncomingFileMapper(),
-			new RepresentationsCalculator(), new DepositRequestIncomingFileMapper(), new AttachmentsContentAdder());
+	private SemantikFormDataMapper mapper;
+
+	@Mock
+	private CustomHeaderReader customHeaderReader;
+
+	@BeforeEach
+	void setup() {
+		mapper = new SemantikFormDataMapper(new XmlToJavaMapsMapper(), new FormDataIncomingFileMapper(),
+				new RepresentationsCalculator(), new DepositRequestIncomingFileMapper(), new AttachmentsContentAdder(), customHeaderReader);
+	}
 
 	@Nested
 	class TestMapFormData {
@@ -136,6 +148,17 @@ class SemantikFormDataMapperTest {
 						.containsEntry(SemantikFormDataMapper.HEADER_CLIENT_ID, "land");
 			}
 
+			@Test
+			void shouldAddBayernHeader() {
+				Map<String, Object> bayernHeader = Map.of(CustomHeaderReader.HEADER_POSTFACH_ID, CustomHeaderTestFactory.POSTFACH_ID);
+				when(customHeaderReader.getHeader(any())).thenReturn(bayernHeader);
+
+				var formData = mapToFormData(deposit);
+
+				verify(customHeaderReader).getHeader(any());
+				assertThat(getHeader(formData)).containsEntry(CustomHeaderReader.HEADER_POSTFACH_ID, CustomHeaderTestFactory.POSTFACH_ID);
+			}
+
 			@SuppressWarnings("unchecked")
 			private Map<String, Object> getHeader(FormData formData) {
 				return (Map<String, Object>) formData.getFormData().get(SemantikFormDataMapper.HEADER_FIELD);
diff --git a/pom.xml b/pom.xml
index 73b148393ff3c0d2ae2329717af68836f4072fb4..61e2d1200e8926055bcf9a0a9910f4ce50ff7965 100644
--- a/pom.xml
+++ b/pom.xml
@@ -37,7 +37,7 @@
 
 	<groupId>de.ozgcloud.eingang</groupId>
 	<artifactId>eingang-manager</artifactId>
-	<version>2.1.0-</version>
+	<version>2.2.0-SNAPSHOT</version>
 	<packaging>pom</packaging>
 	<name>OZG-Cloud Eingang Manager</name>
 
diff --git a/run_helm_test.sh b/run_helm_test.sh
index 7324e7d118cdd0dd4d8815201c07089ea5122d12..5c2ac8a359d9b3be43e39c05eddf49e36d5f2a2d 100755
--- a/run_helm_test.sh
+++ b/run_helm_test.sh
@@ -2,6 +2,6 @@
 
 set -e
 
-helm template  ./src/main/helm/ -f src/test/unit-values.yaml
-helm lint -f src/test/unit-values.yaml ./src/main/helm/
+helm template  ./src/main/helm/ -f src/test/helm-linter-values.yaml
+helm lint -f src/test/helm-linter-values.yaml ./src/main/helm/
 cd src/main/helm && helm unittest --helm3 -f '../../test/helm/*.yaml' -v '../../test/unit-values.yaml' .
\ No newline at end of file
diff --git a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmAntragstellerHeaderMapper.java b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmAntragstellerHeaderMapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..3171846b129f4f676a7392d2f857e0f72714705c
--- /dev/null
+++ b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmAntragstellerHeaderMapper.java
@@ -0,0 +1,67 @@
+package de.ozgcloud.eingang.semantik.enginebased.afm;
+
+import static java.util.Objects.*;
+import static org.apache.commons.lang3.StringUtils.*;
+
+import java.util.Collections;
+import java.util.Map;
+
+import org.springframework.stereotype.Component;
+
+import de.ozgcloud.eingang.common.errorhandling.TechnicalException;
+import de.ozgcloud.eingang.common.formdata.Antragsteller;
+import de.ozgcloud.eingang.common.formdata.FormData;
+
+@Component
+public class AfmAntragstellerHeaderMapper {
+
+	static final String KEY_POSTFACH_ID = "u:saml_legacypostkorbhandle";
+	static final String KEY_VORNAME = "u:saml_givenname";
+	static final String KEY_NACHNAME = "u:saml_surname";
+	static final String KEY_GEBURTSORT = "u:saml_placeofbirth";
+	public static final String KEY_GEBURTSNAME = "u:saml_birthname";
+	static final String KEY_EMAIL = "u:saml_mail";
+	static final String KEY_TELEFON = "u:saml_telephonenumber";
+	static final String KEY_STRASSE = "u:saml_postaladdress";
+	static final String KEY_PLZ = "u:saml_postalcode";
+	static final String KEY_ORT = "u:saml_localityname";
+
+	public FormData parseAntragstellerData(FormData formData) {
+		return formData.toBuilder().antragsteller(buildAntragsteller(getHeaders(formData))).build();
+	}
+
+	Antragsteller buildAntragsteller(Map<String, Object> headers) {
+		return Antragsteller.builder()
+				.postfachId((String) headers.get(KEY_POSTFACH_ID))
+				.vorname((String) headers.get(KEY_VORNAME))
+				.nachname((String) headers.get(KEY_NACHNAME))
+				.geburtsname((String) headers.get(KEY_GEBURTSNAME))
+				.geburtsort((String) headers.get(KEY_GEBURTSORT))
+				.email((String) headers.get(KEY_EMAIL))
+				.telefon((String) headers.get(KEY_TELEFON))
+				.strasse((String) headers.get(KEY_STRASSE))
+				.plz((String) headers.get(KEY_PLZ))
+				.ort((String) headers.get(KEY_ORT))
+				.build();
+	}
+
+	public boolean isResponsible(FormData formData) {
+		var headers = getHeaders(formData);
+		return headers.containsKey(KEY_POSTFACH_ID) && isPostfachIdNotBlank(headers.get(KEY_POSTFACH_ID));
+	}
+
+	@SuppressWarnings("unchecked")
+	Map<String, Object> getHeaders(FormData formData) {
+		return (Map<String, Object>) formData.getFormData().getOrDefault(AfmHeaderMapper.HEADER_FIELD, Collections.emptyMap());
+	}
+
+	boolean isPostfachIdNotBlank(Object postfachId) {
+		if (isNull(postfachId)) {
+			return false;
+		}
+		if (postfachId instanceof String id) {
+			return isNotBlank(id);
+		}
+		throw new TechnicalException("Unexpected type of postfach id: " + postfachId.getClass().getName());
+	}
+}
diff --git a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmAntragstellerMapper.java b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmAntragstellerMapper.java
index 68311943caa6e53772bfb97c3badb8994177d81e..4e5251da5812a678dd2234ab964de002cabd78e8 100644
--- a/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmAntragstellerMapper.java
+++ b/semantik-adapter/src/main/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmAntragstellerMapper.java
@@ -31,6 +31,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
 import de.ozgcloud.eingang.common.formdata.Antragsteller;
@@ -56,8 +57,14 @@ class AfmAntragstellerMapper implements AfmEngineBasedMapper {
 	static final String PLZ = "sh_plz";
 	static final String ORT = "ort";
 
+	@Autowired
+	private AfmAntragstellerHeaderMapper antragstellerHeaderMapper;
+
 	@Override
 	public FormData parseFormData(FormData formData) {
+		if (antragstellerHeaderMapper.isResponsible(formData)) {
+			return antragstellerHeaderMapper.parseAntragstellerData(formData);
+		}
 		var formDataMap = formData.getFormData();
 		var builder = Antragsteller.builder().postfachId(getPostfachId(formDataMap));
 
diff --git a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmAntragstellerHeaderMapperTest.java b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmAntragstellerHeaderMapperTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..953ff17d4427885712c3d95f1b9524b0b1dc1bc1
--- /dev/null
+++ b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmAntragstellerHeaderMapperTest.java
@@ -0,0 +1,241 @@
+package de.ozgcloud.eingang.semantik.enginebased.afm;
+
+import static org.assertj.core.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.*;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.NullAndEmptySource;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Spy;
+
+import de.ozgcloud.eingang.common.errorhandling.TechnicalException;
+import de.ozgcloud.eingang.common.formdata.AntragstellerTestFactory;
+import de.ozgcloud.eingang.common.formdata.FormData;
+
+class AfmAntragstellerHeaderMapperTest {
+
+	@Spy
+	@InjectMocks
+	private AfmAntragstellerHeaderMapper mapper;
+
+	@Nested
+	class TestParseAntragstellerData {
+
+		@Test
+		void shouldCallGetHeaders() {
+			var formData = FormData.builder().build();
+			doReturn(Collections.emptyMap()).when(mapper).getHeaders(any());
+
+			mapper.parseAntragstellerData(formData);
+
+			verify(mapper).getHeaders(formData);
+		}
+
+		@Test
+		void shouldCallBuildAntragsteller() {
+			var headerMap = AfmHeaderTestFactory.createCustomHeaderMap();
+			doReturn(headerMap).when(mapper).getHeaders(any());
+
+			mapper.parseAntragstellerData(FormData.builder().build());
+
+			verify(mapper).buildAntragsteller(headerMap);
+		}
+
+		@Test
+		void shouldSetAntragsteller() {
+			var antragsteller = AntragstellerTestFactory.create();
+			doReturn(antragsteller).when(mapper).buildAntragsteller(any());
+
+			var result = mapper.parseAntragstellerData(FormData.builder().build());
+
+			assertThat(result.getAntragsteller()).isEqualTo(antragsteller);
+		}
+
+		@Nested
+		class TestBuildAntragsteller {
+
+			private Map<String, Object> headers = AfmHeaderTestFactory.createCustomHeaderMap();
+			@Test
+			void shouldSetPostfachId() {
+				var result = mapper.buildAntragsteller(headers);
+
+				assertThat(result.getPostfachId()).isEqualTo(AfmHeaderTestFactory.CUSTOM_POSTFACH_ID);
+			}
+
+			@Test
+			void shouldSetVorname() {
+				var result = mapper.buildAntragsteller(headers);
+
+				assertThat(result.getVorname()).isEqualTo(AfmHeaderTestFactory.CUSTOM_VORNAME);
+			}
+
+			@Test
+			void shouldSetNachname() {
+				var result = mapper.buildAntragsteller(headers);
+
+				assertThat(result.getNachname()).isEqualTo(AfmHeaderTestFactory.CUSTOM_NACHNAME);
+			}
+
+			@Test
+			void shouldSetGeburtsname() {
+				var result = mapper.buildAntragsteller(headers);
+
+				assertThat(result.getGeburtsname()).isEqualTo(AfmHeaderTestFactory.CUSTOM_GEBURTSNAME);
+			}
+
+			@Test
+			void shouldSetGeburtsort() {
+				var result = mapper.buildAntragsteller(headers);
+
+				assertThat(result.getGeburtsort()).isEqualTo(AfmHeaderTestFactory.CUSTOM_GEBURTSORT);
+			}
+
+			@Test
+			void shoudlSetEmail() {
+				var result = mapper.buildAntragsteller(headers);
+
+				assertThat(result.getEmail()).isEqualTo(AfmHeaderTestFactory.CUSTOM_EMAIL);
+			}
+
+			@Test
+			void shouldSetTelefon() {
+				var result = mapper.buildAntragsteller(headers);
+
+				assertThat(result.getTelefon()).isEqualTo(AfmHeaderTestFactory.CUSTOM_TELEFON);
+			}
+
+			@Test
+			void shouldSetStrasse() {
+				var result = mapper.buildAntragsteller(headers);
+
+				assertThat(result.getStrasse()).isEqualTo(AfmHeaderTestFactory.CUSTOM_STRASSE);
+			}
+
+			@Test
+			void shouldSetPlz() {
+				var result = mapper.buildAntragsteller(headers);
+
+				assertThat(result.getPlz()).isEqualTo(AfmHeaderTestFactory.CUSTOM_PLZ);
+			}
+
+			@Test
+			void shouldSetOrt() {
+				var result = mapper.buildAntragsteller(headers);
+
+				assertThat(result.getOrt()).isEqualTo(AfmHeaderTestFactory.CUSTOM_ORT);
+			}
+		}
+	}
+
+	@Nested
+	class TestIsResponsible {
+
+		@Mock
+		private FormData formData;
+
+		@Test
+		void shouldApproveResponsibility() {
+			doReturn(true).when(mapper).isPostfachIdNotBlank(any());
+			doReturn(createHeaders(AfmAntragstellerHeaderMapper.KEY_POSTFACH_ID, "123")).when(mapper).getHeaders(any());
+
+			var isResponsible = mapper.isResponsible(formData);
+
+			assertTrue(isResponsible);
+		}
+
+		@Nested
+		class TestDenyResponsibility {
+
+			@Test
+			void shouldDenyWhenNoHeader() {
+				doReturn(Collections.emptyMap()).when(mapper).getHeaders(any());
+
+				var isResponsible = mapper.isResponsible(FormData.builder().build());
+
+				assertFalse(isResponsible);
+			}
+
+			@Test
+			void shouldDenyWhenNoPostfachId() {
+				doReturn(createHeaders(AfmAntragstellerHeaderMapper.KEY_VORNAME, "name")).when(mapper).getHeaders(any());
+
+				var isResponsible = mapper.isResponsible(formData);
+
+				assertFalse(isResponsible);
+			}
+
+			void shouldDenyWhenPostfachIdIsBlank() {
+				doReturn(createHeaders(AfmAntragstellerHeaderMapper.KEY_POSTFACH_ID, null)).when(mapper).getHeaders(any());
+				doReturn(false).when(mapper).isPostfachIdNotBlank(any());
+
+				var isResponsible = mapper.isResponsible(formData);
+
+				assertFalse(isResponsible);
+			}
+
+			@Nested
+			class TestIsPostfachIdNotBlank {
+
+				@ParameterizedTest
+				@NullAndEmptySource
+				void shouldReturnFalseWhenPostfachIdIsBlank(String postfachId) {
+					var isNotBlank = mapper.isPostfachIdNotBlank(postfachId);
+
+					assertFalse(isNotBlank);
+				}
+
+				@Test
+				void shouldApprove() {
+					var isNotBlank = mapper.isPostfachIdNotBlank("123");
+
+					assertTrue(isNotBlank);
+				}
+
+				@Test
+				void shouldFailOnUnexpectedType() {
+					var postfachId = new Object();
+
+					assertThrows(TechnicalException.class, () -> mapper.isPostfachIdNotBlank(postfachId));
+				}
+			}
+		}
+	}
+
+	@Nested
+	class TestGetHeaders {
+
+		@Test
+		void shouldReturnHeaders() {
+			var headers = createHeaders(AfmAntragstellerHeaderMapper.KEY_POSTFACH_ID, "123");
+			var formData =  FormData.builder().formData(createHeaders(AfmHeaderMapper.HEADER_FIELD, headers)).build();
+
+			var result = mapper.getHeaders(formData);
+
+			assertThat(result).isEqualTo(headers);
+		}
+
+		@Test
+		void shouldReturnEmptyMapWhenNoHeaders() {
+			var formData = FormData.builder().build();
+
+			var result = mapper.getHeaders(formData);
+
+			assertThat(result).isEmpty();
+		}
+	}
+
+	private Map<String, Object> createHeaders(String key, Object value) {
+		var map = new HashMap<String, Object>();
+		map.put(key, value);
+		return map;
+	}
+}
\ No newline at end of file
diff --git a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmAntragstellerMapperTest.java b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmAntragstellerMapperTest.java
index 47e58c47132daae7675ac23a34c1134764a08cc9..e40b13db45356729cd68b0fec172931b999c4c17 100644
--- a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmAntragstellerMapperTest.java
+++ b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmAntragstellerMapperTest.java
@@ -24,6 +24,8 @@
 package de.ozgcloud.eingang.semantik.enginebased.afm;
 
 import static org.assertj.core.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.*;
 
 import java.util.HashMap;
 import java.util.UUID;
@@ -33,6 +35,9 @@ 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.Mockito;
 
 import de.ozgcloud.eingang.common.formdata.Antragsteller;
 import de.ozgcloud.eingang.common.formdata.FormData;
@@ -40,7 +45,11 @@ import de.ozgcloud.eingang.semantik.enginebased.afm.AfmAntragstellerMapper;
 
 class AfmAntragstellerMapperTest {
 
-	private AfmAntragstellerMapper mapper = new AfmAntragstellerMapper();
+	@InjectMocks
+	private AfmAntragstellerMapper mapper;
+
+	@Mock
+	private AfmAntragstellerHeaderMapper antragstellerHeaderMapper;
 
 	private FormData formData = FormData.builder().formData(AfmAntragstellerTestFactory.createFormDataMap()).build();
 	
@@ -48,6 +57,17 @@ class AfmAntragstellerMapperTest {
 	@Nested
 	class TestParseFormData {
 
+		@Test
+		void shouldCallHeaderMapper() {
+			FormData expectedFormData = mock(FormData.class);
+			when(antragstellerHeaderMapper.isResponsible(any())).thenReturn(true);
+			when(antragstellerHeaderMapper.parseAntragstellerData(any())).thenReturn(expectedFormData);
+
+			var processedFormData = parseFormData(formData);
+
+			assertThat(processedFormData).isEqualTo(expectedFormData);
+		}
+
 		@Test
 		void shouldDoNothingOnNullAntragstaller() {
 			var formData = FormData.builder().formData(new HashMap<>()).build();
diff --git a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmHeaderTestFactory.java b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmHeaderTestFactory.java
index d3705fa4277593df269478566b7f1f221848d59b..28e807688770910087b28d5ec2a228c4f90789dd 100644
--- a/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmHeaderTestFactory.java
+++ b/semantik-adapter/src/test/java/de/ozgcloud/eingang/semantik/enginebased/afm/AfmHeaderTestFactory.java
@@ -38,6 +38,17 @@ public class AfmHeaderTestFactory {
 	public static final String FORM = "Kleiner Waffenschein gem. § 10 Abs. 4 Satz 4 Waffengesetz (WaffG)";
 	public static final String SENDER = "afm.schleswig-holstein.de";
 
+	public static final String CUSTOM_POSTFACH_ID = "postfach_id";
+	public static final String CUSTOM_VORNAME = "vorname";
+	public static final String CUSTOM_NACHNAME = "nachname";
+	public static final String CUSTOM_GEBURTSNAME = "Geburtsname";
+	public static final String CUSTOM_GEBURTSORT = "geburtsort";
+	public static final String CUSTOM_EMAIL = "email";
+	public static final String CUSTOM_TELEFON = "telefon";
+	public static final String CUSTOM_STRASSE = "strasse";
+	public static final String CUSTOM_PLZ = "plz";
+	public static final String CUSTOM_ORT = "ort";
+
 	public static final String POSTFACH_NAME_ID = "name-id-value";
 
 	public static final int REST_RESPONSE_NAME_MEMBER_SCOPE_MAILBOX_TYPE_VALUE = 1;
@@ -58,6 +69,22 @@ public class AfmHeaderTestFactory {
 		map.put(AfmHeaderMapper.FORM_ID, FORM_ID);
 		map.put(AfmHeaderMapper.FORM, FORM);
 		map.put(AfmHeaderMapper.SENDER, SENDER);
+		map.putAll(createCustomHeaderMap());
+		return map;
+	}
+
+	public static Map<String, Object> createCustomHeaderMap() {
+		var map = new HashMap<String, Object>();
+		map.put(AfmAntragstellerHeaderMapper.KEY_POSTFACH_ID, CUSTOM_POSTFACH_ID);
+		map.put(AfmAntragstellerHeaderMapper.KEY_VORNAME, CUSTOM_VORNAME);
+		map.put(AfmAntragstellerHeaderMapper.KEY_NACHNAME, CUSTOM_NACHNAME);
+		map.put(AfmAntragstellerHeaderMapper.KEY_GEBURTSNAME, CUSTOM_GEBURTSNAME);
+		map.put(AfmAntragstellerHeaderMapper.KEY_GEBURTSORT, CUSTOM_GEBURTSORT);
+		map.put(AfmAntragstellerHeaderMapper.KEY_EMAIL, CUSTOM_EMAIL);
+		map.put(AfmAntragstellerHeaderMapper.KEY_TELEFON, CUSTOM_TELEFON);
+		map.put(AfmAntragstellerHeaderMapper.KEY_STRASSE, CUSTOM_STRASSE);
+		map.put(AfmAntragstellerHeaderMapper.KEY_PLZ, CUSTOM_PLZ);
+		map.put(AfmAntragstellerHeaderMapper.KEY_ORT, CUSTOM_ORT);
 		return map;
 	}
 
diff --git a/src/main/helm/README.md b/src/main/helm/README.md
index a5f2ffa71abef0d610826b5f699d01e93a530d58..343f5028d591329a068cf876ba38de3dd9b642a5 100644
--- a/src/main/helm/README.md
+++ b/src/main/helm/README.md
@@ -1,35 +1,93 @@
-# Helm
-
-## Linter
-
-`helm lint -f test-values.yaml`
-
-## Unit-Tests
-
-Für Unit-Tests wird das helm [helm-unittest](https://github.com/quintush/helm-unittest) plugin benötigt. Die Unit-Tests liegen im Verzeichnis src/test/helm
-
-`helm unittest -f '../../test/helm/*.yaml' .`
-
-## SyntaxCheck
-
-`helm template --debug -f test-values.yaml .`
-
-## Package
-
-`helm package --version=[version] .`
-
-## Versionierung
-
-Jenkins verwendet die Version aus der pom.xml
-
-### Master Branch
-
-Im master Branch werden die ersten 7 Zeichen vom git commit hash an die Version gehangen.
-
-### Release Branch
-
-Ist nur die Version aus der pom.xml
-
-### Feature Branch
-
-In einem feature Branch wird der Branchname an die Version gehangen.
\ No newline at end of file
+# Intelliform Adapter
+
+Adapter zum empfangen von Formulardaten von einem IntellForm basierten Formularserver, zum Beispiel iAFM (integriertes Antrags- und Formularmanagement).
+
+## Routingkonfiguration
+
+### Vorgang-Manager Instanzen
+
+Für alle Vorgang-Manager-Instanzen, die von dem Adapter erreichbar sein sollen, muss in das _Environment_ ein Eintrag mit dem GRPC-Service ergänzt werden:
+
+```yaml
+grpc.client.vorgang-manager-*vorgang-manager-name*.address:*url und port*
+grpc.client.vorgang-manager-*vorgang-manager-name*.negotiationType: PLAINTEXT
+```
+
+### Fallback Strategy
+
+Die Fallback Stratey steuert wie mit Eingängen umgegangen werden soll, für die keine passende Vorgang-Manager-Instanze gefunden werden konnte.
+
+Folgende Optionen stehen zur Verfügung:
+
+- **DENY** der Antrag wird mit einer Fehlermeldung abgelehnt. Dies funktioniert nur, solange die Abarbeitung synchron erfolgt.
+
+- **FUNDSTELLE** der Antrag wird an eine zentrale Fundstelle weitergeleitet. Dafür muss der Name der Vorgang-Manager-Instanze, die als Fundstelle fungiert, eingetragen werden.
+
+### Routing Strategy
+
+Die Routing Strategy steuert wie das Routing konfiguriert wird und wieviele Vorgang-Manager-Instanzen berücksichtigt werden können.
+
+Folgende Optionen stehen zur Verfügung:
+
+- **MULTI** es kann an beliebig viele Vorgang-Manager-Instanzen geroutet werden. Dafür muss in der Environment ein Mapping der Organisationseinheit-Id auf den Namen einer Vorgang-Manager-Instanz konfiguriert werden.
+
+```yaml
+ozgcloud.adapter.organisationseinheiten.*id*: *vorgang-manager-name*
+```
+
+- **SINGLE** es wird immer nur an eine Vorgang-Manager-Instanze geroutet, der Name der Instanz ist im Feld 'Vorgang-Manager Name' anzugeben.
+
+### Beispielkonfiguration
+
+```yaml
+env:
+  springProfiles: "oc, dev"
+  grpc:
+    - name: grpc_client_vorgang-manager-test_address
+      value: "vorgang-manager.test:9090"
+    - name: grpc_client_vorgang-manager-test_negotiationType
+      value: PLAINTEXT
+    - name: ozgcloud.adapter.organisationseinheiten.1357913579
+      value: test
+image:
+  tag: snapshot-latest
+imageCredentials:
+  email: webmaster@ozg-sh.de
+  password:  
+  registry: docker.ozg-sh.de
+  username: ozgcloud
+ingress:
+  host: kiel-afm.dev.by.ozg-cloud.de
+replicaCount: 2
+resources:
+  limits:
+    cpu: 1
+    memory: 1200Mi
+  requests:
+    cpu: 100m
+    memory: 250Mi
+global:
+  cattle:
+    clusterId: c-8g78g
+    clusterName: ozg-dev
+    systemDefaultRegistry: ""
+  systemDefaultRegistry: ""
+routing:
+  fallbackStrategy: FUNDSTELLE
+  fundstelleVorgangManagerName: kiel
+  routingStrategy: MULTI
+  targetVorgangManagerName: kiel
+```
+
+### Benutzung beliebiger environment Werte
+
+In jedem der Projekte kann man beliebige weitere environments setzen. Dazu muss man in der jeweiligen values.yaml unter env.customList ein name value Paar setzen:
+
+```yaml
+env:
+  customList:
+    - name: Dinge
+      value: true
+    - name: ...
+      value: ...
+```
diff --git a/src/main/helm/app-readme.md b/src/main/helm/app-readme.md
deleted file mode 100644
index 343f5028d591329a068cf876ba38de3dd9b642a5..0000000000000000000000000000000000000000
--- a/src/main/helm/app-readme.md
+++ /dev/null
@@ -1,93 +0,0 @@
-# Intelliform Adapter
-
-Adapter zum empfangen von Formulardaten von einem IntellForm basierten Formularserver, zum Beispiel iAFM (integriertes Antrags- und Formularmanagement).
-
-## Routingkonfiguration
-
-### Vorgang-Manager Instanzen
-
-Für alle Vorgang-Manager-Instanzen, die von dem Adapter erreichbar sein sollen, muss in das _Environment_ ein Eintrag mit dem GRPC-Service ergänzt werden:
-
-```yaml
-grpc.client.vorgang-manager-*vorgang-manager-name*.address:*url und port*
-grpc.client.vorgang-manager-*vorgang-manager-name*.negotiationType: PLAINTEXT
-```
-
-### Fallback Strategy
-
-Die Fallback Stratey steuert wie mit Eingängen umgegangen werden soll, für die keine passende Vorgang-Manager-Instanze gefunden werden konnte.
-
-Folgende Optionen stehen zur Verfügung:
-
-- **DENY** der Antrag wird mit einer Fehlermeldung abgelehnt. Dies funktioniert nur, solange die Abarbeitung synchron erfolgt.
-
-- **FUNDSTELLE** der Antrag wird an eine zentrale Fundstelle weitergeleitet. Dafür muss der Name der Vorgang-Manager-Instanze, die als Fundstelle fungiert, eingetragen werden.
-
-### Routing Strategy
-
-Die Routing Strategy steuert wie das Routing konfiguriert wird und wieviele Vorgang-Manager-Instanzen berücksichtigt werden können.
-
-Folgende Optionen stehen zur Verfügung:
-
-- **MULTI** es kann an beliebig viele Vorgang-Manager-Instanzen geroutet werden. Dafür muss in der Environment ein Mapping der Organisationseinheit-Id auf den Namen einer Vorgang-Manager-Instanz konfiguriert werden.
-
-```yaml
-ozgcloud.adapter.organisationseinheiten.*id*: *vorgang-manager-name*
-```
-
-- **SINGLE** es wird immer nur an eine Vorgang-Manager-Instanze geroutet, der Name der Instanz ist im Feld 'Vorgang-Manager Name' anzugeben.
-
-### Beispielkonfiguration
-
-```yaml
-env:
-  springProfiles: "oc, dev"
-  grpc:
-    - name: grpc_client_vorgang-manager-test_address
-      value: "vorgang-manager.test:9090"
-    - name: grpc_client_vorgang-manager-test_negotiationType
-      value: PLAINTEXT
-    - name: ozgcloud.adapter.organisationseinheiten.1357913579
-      value: test
-image:
-  tag: snapshot-latest
-imageCredentials:
-  email: webmaster@ozg-sh.de
-  password:  
-  registry: docker.ozg-sh.de
-  username: ozgcloud
-ingress:
-  host: kiel-afm.dev.by.ozg-cloud.de
-replicaCount: 2
-resources:
-  limits:
-    cpu: 1
-    memory: 1200Mi
-  requests:
-    cpu: 100m
-    memory: 250Mi
-global:
-  cattle:
-    clusterId: c-8g78g
-    clusterName: ozg-dev
-    systemDefaultRegistry: ""
-  systemDefaultRegistry: ""
-routing:
-  fallbackStrategy: FUNDSTELLE
-  fundstelleVorgangManagerName: kiel
-  routingStrategy: MULTI
-  targetVorgangManagerName: kiel
-```
-
-### Benutzung beliebiger environment Werte
-
-In jedem der Projekte kann man beliebige weitere environments setzen. Dazu muss man in der jeweiligen values.yaml unter env.customList ein name value Paar setzen:
-
-```yaml
-env:
-  customList:
-    - name: Dinge
-      value: true
-    - name: ...
-      value: ...
-```
diff --git a/src/main/helm/questions.yml b/src/main/helm/questions.yml
deleted file mode 100644
index b8309442a20fed6e3e3db74661d36bc1204c3586..0000000000000000000000000000000000000000
--- a/src/main/helm/questions.yml
+++ /dev/null
@@ -1,106 +0,0 @@
-#
-# 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.
-#
-
-questions:
-  # --- Container ---
-  - variable: image.name
-    type: enum
-    default: intelliform-adapter
-    label: The deployed Image
-    group: Container
-    required: true
-    options:
-      - intelliform-adapter
-      - formsolutions-adapter
-  - variable: image.tag
-    default: latest
-    type: string
-    label: The deployed version tag
-    group: "Container"
-  - variable: replicaCount
-    group: "Container"
-    type: string
-    default: "2"
-    label: "Deployment Replica count"
-  - variable: env.overrideSpringProfiles
-    group: "Container"
-    type: string
-    label: "Override Spring boot profile"
-  - variable: ozgcloud.bezeichner
-    group: "OZGCLOUD"
-    label: "Bezeichner"
-    type: string
-    required: true
-  - variable: ozgcloud.environment
-    group: "OZGCLOUD"
-    label: "Environment"
-    type: string
-    required: true
-
-  - variable: ingress.enabled
-    type: boolean
-    label: Enable ingress
-    default: true
-    group: "Ingress"
-    show_subquestion_if: true
-    subquestions:
-      - variable: ingress.overrideHost
-        type: string
-        label: Override generated deposit Webservice URL
-        group: "Ingress"
-
-  - variable: routing.fallbackStrategy
-    label: Fallback Strategy
-    group: Routing
-    type: enum
-    default: DENY
-    required: true
-    options:
-      - FUNDSTELLE
-      - DENY
-    show_subquestion_if: FUNDSTELLE
-    subquestions:
-      - variable: routing.fundstelleVorgangManagerName
-        type: string
-        label: Fundstelle
-        required: true
-  - variable: routing.routingStrategy
-    label: Routing Strategy
-    type: enum
-    default: SINGLE
-    required: true
-    group: Routing
-    options:
-      - MULTI
-      - SINGLE
-    show_subquestion_if: SINGLE
-    subquestions:
-      - variable: routing.targetVorgangManagerName
-        type: string
-        label: Vorgang-Manager Name
-        required: true
-      - variable: routing.targetNamespace
-        type: string
-        label: Namespace
-        required: true
diff --git a/src/main/helm/templates/_helpers.tpl b/src/main/helm/templates/_helpers.tpl
index c7dfcd79523309e42ab91563882a39f65e4ecb60..82a7d4757fd619634da2fe4d771717eac04fd1e4 100644
--- a/src/main/helm/templates/_helpers.tpl
+++ b/src/main/helm/templates/_helpers.tpl
@@ -80,4 +80,18 @@ app.kubernetes.io/namespace: {{ include "app.namespace" . }}
 {{- else }}
 {{- printf "%s-afm.%s" (include "app.ozgcloudBezeichner" .) .Values.baseUrl }}
 {{- end }}
+{{- end -}}
+
+{{- define "app.serviceAccountName" -}}
+{{- if (.Values.serviceAccount).name }}
+{{- printf "%s" .Values.serviceAccount.name }}
+{{- else if eq (.Values.image).name "intelliform-adapter" }}
+{{- printf "afm-adapter-service-account" }}
+{{- else if eq (.Values.image).name "formsolutions-adapter" }}
+{{- printf "fs-adapter-service-account" }}
+{{- else if eq (.Values.image).name "formcycle-adapter" }}
+{{- printf "formcycle-adapter-service-account" }}
+{{- else if eq (.Values.image).name "enterprise-adapter" }}
+{{- printf "enterprise-adapter-service-account" }}
+{{- end }}
 {{- end -}}
\ No newline at end of file
diff --git a/src/main/helm/templates/deployment.yaml b/src/main/helm/templates/deployment.yaml
index cefff9be956d634f21a76a00f01b9269f24f8d21..b6850b78412c4d2e1327f89f840cafca8b517b9d 100644
--- a/src/main/helm/templates/deployment.yaml
+++ b/src/main/helm/templates/deployment.yaml
@@ -47,6 +47,9 @@ spec:
         {{- include "app.defaultLabels" . | indent 8 }}
         component: afm-adapter
     spec:
+      {{- if (.Values.serviceAccount).create }}
+      serviceAccountName: {{ include "app.serviceAccountName" . }}
+      {{- end }}
       topologySpreadConstraints:
       - maxSkew: 1
         topologyKey: kubernetes.io/hostname
@@ -118,7 +121,13 @@ spec:
           allowPrivilegeEscalation: false
           privileged: false
           readOnlyRootFilesystem: false
-          runAsNonRoot: false
+          runAsNonRoot: true
+          {{- with (.Values.securityContext).runAsUser }}
+          runAsUser: {{ . }}
+          {{- end }}
+          {{- with (.Values.securityContext).runAsGroup }}
+          runAsGroup: {{ . }}
+          {{- end }}
         stdin: true
         terminationMessagePath: /dev/termination-log
         terminationMessagePolicy: File
@@ -126,8 +135,16 @@ spec:
       dnsConfig: {}
       dnsPolicy: ClusterFirst
       imagePullSecrets:
+      {{- if .Values.imagePullSecret }}
+      - name: {{ .Values.imagePullSecret }}
+      {{ else }}
       - name: {{ include "app.name" . }}-image-pull-secret
+      {{- end }}
       restartPolicy: Always
+      {{- with .Values.hostAliases }}
+      hostAliases:
+{{ toYaml . | indent 8 }}
+      {{- end }}
       schedulerName: default-scheduler
       securityContext: {}
       terminationGracePeriodSeconds: 30
\ No newline at end of file
diff --git a/src/main/helm/templates/image-pull-secret.yaml b/src/main/helm/templates/image-pull-secret.yaml
index 17d65b7b75e0ebe440ece0451e78269e94596901..9ac29e90a738d57e16307c8335a60c032134f1c8 100644
--- a/src/main/helm/templates/image-pull-secret.yaml
+++ b/src/main/helm/templates/image-pull-secret.yaml
@@ -22,6 +22,7 @@
 # unter der Lizenz sind dem Lizenztext zu entnehmen.
 #
 
+{{- if not (.Values.imagePullSecret) }}
 apiVersion: v1
 kind: Secret
 metadata:
@@ -29,4 +30,5 @@ metadata:
   namespace: {{ include "app.namespace" . }}
 type: kubernetes.io/dockerconfigjson
 data:
-  .dockerconfigjson: {{ include "app.imagePullSecret" . }}
\ No newline at end of file
+  .dockerconfigjson: {{ include "app.imagePullSecret" . }}
+{{- end }}
\ No newline at end of file
diff --git a/src/main/helm/templates/ingress.yaml b/src/main/helm/templates/ingress.yaml
index e539e8e0d02d3fed66e97fded23f800b937bdc02..fe85cf3ea82a073c99575ed87a7e56bad6910bf8 100644
--- a/src/main/helm/templates/ingress.yaml
+++ b/src/main/helm/templates/ingress.yaml
@@ -27,7 +27,11 @@ apiVersion: networking.k8s.io/v1
 kind: Ingress
 metadata:
   annotations:
-    {{- if (.Values.ingress).use_staging_cert }}
+    {{- if (.Values.ingress).certManagerAnnotations -}}
+    {{- range (.Values.ingress).certManagerAnnotations }}
+{{ . | indent 4 }}
+    {{- end }}
+    {{- else if (.Values.ingress).use_staging_cert }}
     cert-manager.io/cluster-issuer: letsencrypt-staging
     {{- else }}
     cert-manager.io/cluster-issuer: letsencrypt-prod
@@ -53,7 +57,9 @@ spec:
   tls:
     - hosts:
       - {{ include "app.ingress.host" . }}
-      {{- if ne (.Values).cluster_env "dataport" }}
+      {{- if (.Values.ingress).tlsSecretName }}
+      secretName: {{ (.Values.ingress).tlsSecretName }}
+      {{- else if ne (.Values).cluster_env "dataport" }}
       secretName: {{ .Values.ozgcloud.bezeichner }}-{{ include "app.name" . }}-tls
       {{- end }}
 {{- end -}}
\ No newline at end of file
diff --git a/src/main/helm/templates/network_policy.yaml b/src/main/helm/templates/network_policy.yaml
index 18cf7b2ccffa80585d82fa23789554ff862f3600..929afd7c84be59aa8d39ca31148f72375a2c228b 100644
--- a/src/main/helm/templates/network_policy.yaml
+++ b/src/main/helm/templates/network_policy.yaml
@@ -49,13 +49,14 @@ spec:
   - to:
     - namespaceSelector:
         matchLabels:
-          kubernetes.io/metadata.name: kube-system
-      podSelector:
-        matchLabels:
-          k8s-app: kube-dns
+          kubernetes.io/metadata.name: {{ required "networkPolicy.dnsServerNamespace must be set" (.Values.networkPolicy).dnsServerNamespace }}
     ports:
       - port: 53
         protocol: UDP
       - port: 53
         protocol: TCP
+      - port: 5353
+        protocol: UDP
+      - port: 5353
+        protocol: TCP
 {{- end }} 
\ No newline at end of file
diff --git a/src/main/helm/templates/service_account.yaml b/src/main/helm/templates/service_account.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..0e13e6bcabf1933117c29487473453b63265922a
--- /dev/null
+++ b/src/main/helm/templates/service_account.yaml
@@ -0,0 +1,31 @@
+#
+# 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.
+#
+
+{{- if (.Values.serviceAccount).create }}
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: {{ include "app.serviceAccountName" . }}
+  namespace: {{ include "app.namespace" . }}
+{{- end }}
\ No newline at end of file
diff --git a/src/main/helm/values.yaml b/src/main/helm/values.yaml
index 4a2bd83c1c4eb04af79fbd4b6458eb4dc52a1c9c..240501d36a5cc48d18ae5bc3a324b985f47ca550 100644
--- a/src/main/helm/values.yaml
+++ b/src/main/helm/values.yaml
@@ -44,12 +44,6 @@ image:
 #    cpu: 100m # [default: 100m]
 #    memory: 250Mi # [default: 250Mi]
 
-imageCredentials:
-  registry: docker.ozg-sh.de
-  username: ozgcloud
-  password:  
-  email: webmaster@ozg-sh.de
-
 ingress:
   enabled: true
   # overrideHost: kiel-afm.dev.by.ozg-cloud.de
diff --git a/src/main/helm/test-values.yaml b/src/test/helm-linter-values.yaml
similarity index 92%
rename from src/main/helm/test-values.yaml
rename to src/test/helm-linter-values.yaml
index e72f46c87bf4c6b6ce3cf960e19effcd09fd53b8..dc7bf7d67561d23925b5ebd3cbac9a491af1ffc8 100644
--- a/src/main/helm/test-values.yaml
+++ b/src/test/helm-linter-values.yaml
@@ -25,4 +25,7 @@
 ozgcloud:
   environment: test
   bezeichner: helm
-  bundesland: sh
\ No newline at end of file
+  bundesland: sh
+
+networkPolicy:
+  dnsServerNamespace: test-dns-server-namespace
\ No newline at end of file
diff --git a/src/test/helm/deployment_container_security_context_test.yaml b/src/test/helm/deployment_container_security_context_test.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..18a7450337149faf441b8fd520fc4883388f1f6e
--- /dev/null
+++ b/src/test/helm/deployment_container_security_context_test.yaml
@@ -0,0 +1,65 @@
+#
+# 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.
+#
+
+suite: test deployment
+release:
+  name: eingang-manager
+  namespace: sh-helm-test
+templates:
+  - templates/deployment.yaml
+tests:
+  - it: check default values
+    asserts:
+      - isKind:
+          of: Deployment
+      - equal:
+          path: spec.template.spec.containers[0].securityContext.allowPrivilegeEscalation
+          value: false
+      - equal:
+          path: spec.template.spec.containers[0].securityContext.privileged
+          value: false
+      - equal:
+          path: spec.template.spec.containers[0].securityContext.readOnlyRootFilesystem
+          value: false
+      - equal:
+          path: spec.template.spec.containers[0].securityContext.runAsNonRoot
+          value: true
+      - isNull:
+          path: spec.template.spec.containers[0].securityContext.runAsUser
+      - isNull:
+          path: spec.template.spec.containers[0].securityContext.runAsGroup
+  - it: check runAsUser
+    set:
+      securityContext.runAsUser: 1000
+    asserts:
+      - equal:
+          path: spec.template.spec.containers[0].securityContext.runAsUser
+          value: 1000
+  - it: check runAsGroup
+    set:
+      securityContext.runAsGroup: 1000
+    asserts:
+      - equal:
+          path: spec.template.spec.containers[0].securityContext.runAsGroup
+          value: 1000
\ No newline at end of file
diff --git a/src/test/helm/deployment_host_aliases_test.yaml b/src/test/helm/deployment_host_aliases_test.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..689bf6fd2d5d9eabbb92a6f521397c665bde2f08
--- /dev/null
+++ b/src/test/helm/deployment_host_aliases_test.yaml
@@ -0,0 +1,50 @@
+#
+# 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.
+#
+
+suite: deployment host aliases
+release:
+  name: eingang-manager
+  namespace: sh-helm-test
+templates:
+  - templates/deployment.yaml
+tests:
+  - it: should not set hostAliases
+    asserts:
+      - isNull:
+          path: spec.template.spec.hostAliases
+  - it: should set hostAliases
+    set:
+      hostAliases:
+        - ip: "127.0.0.1"
+          hostname:
+          - "eins"
+          - "zwei"
+    asserts:
+      - contains:
+          path: spec.template.spec.hostAliases
+          content:
+            ip: "127.0.0.1"
+            hostname:
+            - "eins"
+            - "zwei"
diff --git a/src/test/helm/deployment_imagepull_secret_test.yaml b/src/test/helm/deployment_imagepull_secret_test.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..2c72debd4fe921192fd925b909f7e6b85c649685
--- /dev/null
+++ b/src/test/helm/deployment_imagepull_secret_test.yaml
@@ -0,0 +1,47 @@
+#
+# 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.
+#
+
+suite: test deployment
+release:
+  name: afm-adapter
+  namespace: sh-helm-test
+templates:
+  - templates/deployment.yaml
+tests:
+  - it: should use default imagePull secret
+    asserts:
+      - isKind:
+          of: Deployment
+      - equal:
+          path: spec.template.spec.imagePullSecrets[0].name
+          value: afm-adapter-image-pull-secret
+  - it: should set the imagePull secret
+    set:
+      imagePullSecret: image-pull-secret
+    asserts:
+      - isKind:
+          of: Deployment
+      - equal:
+          path: spec.template.spec.imagePullSecrets[0].name
+          value: image-pull-secret
\ No newline at end of file
diff --git a/src/test/helm/deployment_service_account_test.yaml b/src/test/helm/deployment_service_account_test.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..43aa6fcf59131f1fd9f4e0530a60b14551f89c9b
--- /dev/null
+++ b/src/test/helm/deployment_service_account_test.yaml
@@ -0,0 +1,80 @@
+#
+# 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.
+#
+
+suite: deployment service account
+release:
+  name: eingang-manager
+  namespace: sh-helm-test
+templates:
+  - templates/deployment.yaml
+tests:
+  - it: should use afm-adapter service account name
+    set:
+      image.name: intelliform-adapter
+      serviceAccount:
+        create: true
+    asserts:
+      - equal:
+          path: spec.template.spec.serviceAccountName
+          value: afm-adapter-service-account
+  - it: should use fs-adapter service account name
+    set:
+      image.name: formsolutions-adapter
+      serviceAccount:
+        create: true
+    asserts:
+      - equal:
+          path: spec.template.spec.serviceAccountName
+          value: fs-adapter-service-account
+  - it: should use formcycle-adapter service account name
+    set:
+      image.name: formcycle-adapter
+      serviceAccount:
+        create: true
+    asserts:
+      - equal:
+          path: spec.template.spec.serviceAccountName
+          value: formcycle-adapter-service-account
+  - it: should use enterprise-adapter service account name
+    set:
+      image.name: enterprise-adapter
+      serviceAccount:
+        create: true
+    asserts:
+      - equal:
+          path: spec.template.spec.serviceAccountName
+          value: enterprise-adapter-service-account
+  - it: should use service account with name
+    set:
+      serviceAccount:
+        create: true
+        name: helm-service-account
+    asserts:
+      - equal:
+          path: spec.template.spec.serviceAccountName
+          value: helm-service-account
+  - it: should use default service account
+    asserts:
+      - isNull:
+          path: spec.template.spec.serviceAccountName
\ No newline at end of file
diff --git a/src/test/helm/image-pull-secret-test.yaml b/src/test/helm/image-pull-secret-test.yaml
index 423d6268f8fea790bd466277a96f93c9594600a7..c95545170d0e4dd01fce0aab3a1c8953e3e20b5f 100644
--- a/src/test/helm/image-pull-secret-test.yaml
+++ b/src/test/helm/image-pull-secret-test.yaml
@@ -30,6 +30,12 @@ release:
   namespace: helm-test
 tests:
   - it: should match basic data
+    set:
+      imageCredentials:
+        registry: docker.ozg-sh.de
+        username: test
+        password: test1234
+        email: webmaster@ozg-sh.de
     asserts:
       - containsDocument:
           kind: Secret
@@ -40,3 +46,12 @@ tests:
       - equal:
           path: metadata.namespace
           value: helm-test
+      - isNotEmpty:
+          path: data.[.dockerconfigjson]
+
+  - it: should not create image pull secret
+    set:
+      imagePullSecret: "image-pull-secret"
+    asserts:
+      - hasDocuments:
+          count: 0
\ No newline at end of file
diff --git a/src/test/helm/network_policy_test.yaml b/src/test/helm/network_policy_test.yaml
index 96c857eb6260c8ed088cf1a5fb1d70f8fa39c318..1abf7b15ee0077fc1c4811d6b323e709ad83e5a1 100644
--- a/src/test/helm/network_policy_test.yaml
+++ b/src/test/helm/network_policy_test.yaml
@@ -30,14 +30,23 @@ templates:
   - templates/network_policy.yaml
 tests:
   - it: should match apiVersion
+    set:
+      networkPolicy:
+        dnsServerNamespace: test-dns-namespace
     asserts:
       - isAPIVersion:
           of: networking.k8s.io/v1
   - it: should match kind
+    set:
+      networkPolicy:
+        dnsServerNamespace: test-dns-namespace
     asserts:
       - isKind:
           of: NetworkPolicy
   - it: validate metadata
+    set:
+      networkPolicy:
+        dnsServerNamespace: test-dns-namespace
     asserts:
       - equal:
           path: metadata
@@ -45,6 +54,9 @@ tests:
             name: network-policy-afm-adapter
             namespace: by-helm-test
   - it: validate spec
+    set:
+      networkPolicy:
+        dnsServerNamespace: test-dns-namespace
     asserts:
       - equal:
           path: spec
@@ -69,20 +81,22 @@ tests:
             - to:
               - namespaceSelector:
                   matchLabels:
-                    kubernetes.io/metadata.name: kube-system
-                podSelector:
-                  matchLabels:
-                    k8s-app: kube-dns
+                    kubernetes.io/metadata.name: test-dns-namespace
               ports:
                 - port: 53
                   protocol: UDP
                 - port: 53
                   protocol: TCP
+                - port: 5353
+                  protocol: UDP
+                - port: 5353
+                  protocol: TCP
 
   - it: test network policy disabled
     set:
       networkPolicy:
         disabled: true
+        dnsServerNamespace: test-dns-namespace
     asserts:
       - hasDocuments:
           count: 0
@@ -91,6 +105,7 @@ tests:
     set:
       networkPolicy:
         disabled: false
+        dnsServerNamespace: test-dns-namespace
     asserts:
       - hasDocuments:
           count: 1
\ No newline at end of file
diff --git a/src/test/helm/service_account_test.yaml b/src/test/helm/service_account_test.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..52561bed188a291f689b81480f02126cd8aed6bc
--- /dev/null
+++ b/src/test/helm/service_account_test.yaml
@@ -0,0 +1,105 @@
+#
+# 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.
+#
+
+suite: test service account
+release:
+  name: eingang-manager
+  namespace: sh-helm-test
+templates:
+  - templates/service_account.yaml
+tests:
+  - it: should create default afm adapter service account name
+    set:
+      image.name: intelliform-adapter
+      serviceAccount:
+        create: true
+    asserts:
+      - isKind:
+          of: ServiceAccount
+      - equal:
+          path: metadata.name
+          value: afm-adapter-service-account
+      - equal:
+          path: metadata.namespace
+          value: sh-helm-test
+  - it: should create default fs adapter service account name
+    set:
+      image.name: formsolutions-adapter
+      serviceAccount:
+        create: true
+    asserts:
+      - isKind:
+          of: ServiceAccount
+      - equal:
+          path: metadata.name
+          value: fs-adapter-service-account
+      - equal:
+          path: metadata.namespace
+          value: sh-helm-test
+  - it: should create default formcycle adapter service account name
+    set:
+      image.name: formcycle-adapter
+      serviceAccount:
+        create: true
+    asserts:
+      - isKind:
+          of: ServiceAccount
+      - equal:
+          path: metadata.name
+          value: formcycle-adapter-service-account
+      - equal:
+          path: metadata.namespace
+          value: sh-helm-test
+  - it: should create default enterprise adapter service account name
+    set:
+      image.name: enterprise-adapter
+      serviceAccount:
+        create: true
+    asserts:
+      - isKind:
+          of: ServiceAccount
+      - equal:
+          path: metadata.name
+          value: enterprise-adapter-service-account
+      - equal:
+          path: metadata.namespace
+          value: sh-helm-test
+  - it: should create service account with name
+    set:
+      serviceAccount:
+        create: true
+        name: helm-service-account
+    asserts:
+      - isKind:
+          of: ServiceAccount
+      - equal:
+          path: metadata.name
+          value: helm-service-account
+      - equal:
+          path: metadata.namespace
+          value: sh-helm-test
+  - it: should not create service account
+    asserts:
+      - hasDocuments:
+        count: 0
\ No newline at end of file
diff --git a/src/test/unit-values.yaml b/src/test/unit-values.yaml
index fcf2eaf1056c00bb9462330e2229f294201302cf..4c10588096434157f0e0ce39098dfcb134dec497 100644
--- a/src/test/unit-values.yaml
+++ b/src/test/unit-values.yaml
@@ -36,9 +36,3 @@ image:
   repo: docker.ozg-sh.de
   name: intelliform-adapter
   tag: latest
-
-imageCredentials:
-  registry: docker.ozg-sh.de
-  username: ozgcloud
-  password:  
-  email: webmaster@ozg-sh.de
\ No newline at end of file
diff --git a/xta-adapter/src/main/helm/templates/_helpers.tpl b/xta-adapter/src/main/helm/templates/_helpers.tpl
index 62e0d295881ee2e179cb8d66eb006d33a050488d..203aab813c0e2dbb6505eb2af8acc5ca1631b146 100644
--- a/xta-adapter/src/main/helm/templates/_helpers.tpl
+++ b/xta-adapter/src/main/helm/templates/_helpers.tpl
@@ -61,4 +61,8 @@ helm.sh/chart: {{ include "app.chart" . }}
 {{- else if eq (include "app.kopEnvironment" . ) "dev" -}}
 {{  "*/15 * * * *" | quote }}
 {{- end -}}
+{{- end -}}
+
+{{- define "app.serviceAccountName" -}}
+{{ printf "%s" ( (.Values.serviceAccount).name | default "xta-adapter-service-account" ) }}
 {{- end -}}
\ No newline at end of file
diff --git a/xta-adapter/src/main/helm/templates/image-pull-secret.yaml b/xta-adapter/src/main/helm/templates/image-pull-secret.yaml
index 17d65b7b75e0ebe440ece0451e78269e94596901..9ac29e90a738d57e16307c8335a60c032134f1c8 100644
--- a/xta-adapter/src/main/helm/templates/image-pull-secret.yaml
+++ b/xta-adapter/src/main/helm/templates/image-pull-secret.yaml
@@ -22,6 +22,7 @@
 # unter der Lizenz sind dem Lizenztext zu entnehmen.
 #
 
+{{- if not (.Values.imagePullSecret) }}
 apiVersion: v1
 kind: Secret
 metadata:
@@ -29,4 +30,5 @@ metadata:
   namespace: {{ include "app.namespace" . }}
 type: kubernetes.io/dockerconfigjson
 data:
-  .dockerconfigjson: {{ include "app.imagePullSecret" . }}
\ No newline at end of file
+  .dockerconfigjson: {{ include "app.imagePullSecret" . }}
+{{- end }}
\ No newline at end of file
diff --git a/xta-adapter/src/main/helm/templates/network_policy.yaml b/xta-adapter/src/main/helm/templates/network_policy.yaml
index 7f4528b855e504f713b0c92a8e43c21bb94afada..4b42df74f377c19cf12fd6435b4451afb627bf0a 100644
--- a/xta-adapter/src/main/helm/templates/network_policy.yaml
+++ b/xta-adapter/src/main/helm/templates/network_policy.yaml
@@ -54,6 +54,10 @@ spec:
         protocol: UDP
       - port: 53
         protocol: TCP
+      - port: 5353
+        protocol: UDP
+      - port: 5353
+        protocol: TCP
   - to:
     - namespaceSelector:
         matchLabels:
diff --git a/xta-adapter/src/main/helm/templates/service_account.yaml b/xta-adapter/src/main/helm/templates/service_account.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..0e13e6bcabf1933117c29487473453b63265922a
--- /dev/null
+++ b/xta-adapter/src/main/helm/templates/service_account.yaml
@@ -0,0 +1,31 @@
+#
+# 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.
+#
+
+{{- if (.Values.serviceAccount).create }}
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: {{ include "app.serviceAccountName" . }}
+  namespace: {{ include "app.namespace" . }}
+{{- end }}
\ No newline at end of file
diff --git a/xta-adapter/src/main/helm/templates/xta_adapter_cronjob.yaml b/xta-adapter/src/main/helm/templates/xta_adapter_cronjob.yaml
index 61cac8717883a47d52e3992b23de6beb98a18782..dc0be81abbdbb5a3dbf65a27f7abb32746c86c2c 100644
--- a/xta-adapter/src/main/helm/templates/xta_adapter_cronjob.yaml
+++ b/xta-adapter/src/main/helm/templates/xta_adapter_cronjob.yaml
@@ -44,6 +44,9 @@ spec:
             workload: xta-adapter-cronjob
             ozg-component: xta-adapter
         spec:
+          {{- if (.Values.serviceAccount).create }}
+          serviceAccountName: {{ include "app.serviceAccountName" . }}
+          {{- end }}
           restartPolicy: Never
           containers:
             - name: xta-adapter
@@ -99,7 +102,13 @@ spec:
                 allowPrivilegeEscalation: false
                 privileged: false
                 readOnlyRootFilesystem: false
-                runAsNonRoot: false
+                runAsNonRoot: true
+                {{- with (.Values.securityContext).runAsUser }}
+                runAsUser: {{ . }}
+                {{- end }}
+                {{- with (.Values.securityContext).runAsGroup }}
+                runAsGroup: {{ . }}
+                {{- end }}
               resources:
               {{- with .Values.resources }}
 {{ toYaml . | indent 16 }}
@@ -146,4 +155,8 @@ spec:
               secret:
                 secretName: xta-keystore
           imagePullSecrets:
-            - name: {{ include "app.name" . }}-image-pull-secret
\ No newline at end of file
+            {{- if .Values.imagePullSecret }}
+            - name: {{ .Values.imagePullSecret }}
+            {{ else }}
+            - name: {{ include "app.name" . }}-image-pull-secret
+            {{- end }}
\ No newline at end of file
diff --git a/xta-adapter/src/main/helm/values.yaml b/xta-adapter/src/main/helm/values.yaml
index 2b3d383c69e987fbfe7c73bb0eded6b2bd109405..b7fd23ad6dcbad154f52411df043403824f33d86 100644
--- a/xta-adapter/src/main/helm/values.yaml
+++ b/xta-adapter/src/main/helm/values.yaml
@@ -30,12 +30,6 @@ image:
 # env:
 #   overrideSpringProfiles: "oc,prod"
 
-imageCredentials:
-  registry: docker.ozg-sh.de
-  username: ozgcloud
-  password:  
-  email: webmaster@ozg-sh.de
-
 routing:
   targetVorgangManagerName: vorgang-manager
   fallbackStrategy: DENY
diff --git a/xta-adapter/src/test/helm/cronjob_service_account_test.yaml b/xta-adapter/src/test/helm/cronjob_service_account_test.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..933e2c64f494bff262c48c680a46df70239662bd
--- /dev/null
+++ b/xta-adapter/src/test/helm/cronjob_service_account_test.yaml
@@ -0,0 +1,52 @@
+#
+# 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.
+#
+
+suite: test cronjob service account
+templates:
+  - templates/xta_adapter_cronjob.yaml
+release:
+  name: xta-adapter
+  namespace: helm-test
+tests:
+  - it: should use service account with default name
+    set:
+      serviceAccount:
+        create: true
+    asserts:
+      - equal:
+          path: spec.jobTemplate.spec.template.spec.serviceAccountName
+          value: xta-adapter-service-account
+  - it: should use service account with name
+    set:
+      serviceAccount:
+        create: true
+        name: helm-service-account
+    asserts:
+      - equal:
+          path: spec.jobTemplate.spec.template.spec.serviceAccountName
+          value: helm-service-account
+  - it: should use default service account
+    asserts:
+      - isNull:
+          path: spec.jobTemplate.spec.template.spec.serviceAccountName
diff --git a/xta-adapter/src/test/helm/image_pull_secret_test.yaml b/xta-adapter/src/test/helm/image_pull_secret_test.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..80bffcc068842596343a15aeaa1eff0d52930584
--- /dev/null
+++ b/xta-adapter/src/test/helm/image_pull_secret_test.yaml
@@ -0,0 +1,59 @@
+#
+# 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.
+#
+
+suite: test image pull secret
+templates:
+  - templates/image-pull-secret.yaml
+release:
+  name: xta-adapter
+  namespace: helm-test
+tests:
+  - it: should match basic data
+    set:
+      imageCredentials:
+        registry: docker.ozg-sh.de
+        username: test
+        password: test1234
+        email: webmaster@ozg-sh.de
+    asserts:
+      - hasDocuments:
+          count: 1
+      - containsDocument:
+          kind: Secret
+          apiVersion: v1
+      - equal:
+          path: metadata.name
+          value: xta-adapter-image-pull-secret
+      - equal:
+          path: metadata.namespace
+          value: helm-test
+      - isNotEmpty:
+          path: data.[.dockerconfigjson]
+
+  - it: should not create image pull secret
+    set:
+      imagePullSecret: "image-pull-secret"
+    asserts:
+      - hasDocuments:
+          count: 0
\ No newline at end of file
diff --git a/xta-adapter/src/test/helm/network_policy_test.yaml b/xta-adapter/src/test/helm/network_policy_test.yaml
index 92a40e9ea58220536df7b6dc3c7623a2f936c03e..75530cbc1039b70ebef9f3cd20689b739972e430 100644
--- a/xta-adapter/src/test/helm/network_policy_test.yaml
+++ b/xta-adapter/src/test/helm/network_policy_test.yaml
@@ -73,6 +73,10 @@ tests:
                   protocol: UDP
                 - port: 53
                   protocol: TCP
+                - port: 5353
+                  protocol: UDP
+                - port: 5353
+                  protocol: TCP
             - to:
               - namespaceSelector:
                   matchLabels:
@@ -111,6 +115,10 @@ tests:
                   protocol: UDP
                 - port: 53
                   protocol: TCP
+                - port: 5353
+                  protocol: UDP
+                - port: 5353
+                  protocol: TCP
             - to:
               - namespaceSelector:
                   matchLabels:
diff --git a/xta-adapter/src/test/helm/service_account_test.yaml b/xta-adapter/src/test/helm/service_account_test.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..e69fb10ec60f838348d3ab287f6d8eba19db67fb
--- /dev/null
+++ b/xta-adapter/src/test/helm/service_account_test.yaml
@@ -0,0 +1,62 @@
+#
+# 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.
+#
+
+suite: test service account
+release:
+  name: xta-adapter
+  namespace: sh-helm-test
+templates:
+  - templates/service_account.yaml
+tests:
+  - it: should create service account with default name
+    set:
+      serviceAccount:
+        create: true
+    asserts:
+      - isKind:
+          of: ServiceAccount
+      - equal:
+          path: metadata.name
+          value: xta-adapter-service-account
+      - equal:
+          path: metadata.namespace
+          value: sh-helm-test
+  - it: should create service account with name
+    set:
+      serviceAccount:
+        create: true
+        name: helm-service-account
+    asserts:
+      - isKind:
+          of: ServiceAccount
+      - equal:
+          path: metadata.name
+          value: helm-service-account
+      - equal:
+          path: metadata.namespace
+          value: sh-helm-test
+  - it: should not create service account
+    asserts:
+      - hasDocuments:
+        count: 0
\ No newline at end of file
diff --git a/xta-adapter/src/test/helm/xta_adapter_cronjob_basic_test.yaml b/xta-adapter/src/test/helm/xta_adapter_cronjob_basic_test.yaml
index 677ce10dc7fb886a0d2484cba11e0517ef8d1639..4667b03c48c34279b76865a0913a69758f745bbf 100644
--- a/xta-adapter/src/test/helm/xta_adapter_cronjob_basic_test.yaml
+++ b/xta-adapter/src/test/helm/xta_adapter_cronjob_basic_test.yaml
@@ -99,8 +99,25 @@ tests:
         value: false
     - equal:
         path: spec.jobTemplate.spec.template.spec.containers[0].securityContext.runAsNonRoot
-        value: false
-  
+        value: true
+    - isNull:
+        path: spec.jobTemplate.spec.template.spec.containers[0].securityContext.runAsUser
+    - isNull:
+        path: spec.jobTemplate.spec.template.spec.containers[0].securityContext.runAsGroup
+  - it: check runAsUser
+    set:
+      securityContext.runAsUser: 1000
+    asserts:
+      - equal:
+          path: spec.jobTemplate.spec.template.spec.containers[0].securityContext.runAsUser
+          value: 1000
+  - it: check runAsGroup
+    set:
+      securityContext.runAsGroup: 1000
+    asserts:
+      - equal:
+          path: spec.jobTemplate.spec.template.spec.containers[0].securityContext.runAsGroup
+          value: 1000
   - it: check pod labels
     template: xta_adapter_cronjob.yaml
     asserts:
diff --git a/xta-adapter/src/test/helm/xta_adapter_cronjob_image_pull_test.yaml b/xta-adapter/src/test/helm/xta_adapter_cronjob_image_pull_test.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..d74e945ac83c43e56c43f2065615719c412c9432
--- /dev/null
+++ b/xta-adapter/src/test/helm/xta_adapter_cronjob_image_pull_test.yaml
@@ -0,0 +1,43 @@
+#
+# 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.
+#
+
+suite: test xta adapter imagePull secret
+release:
+  name: xta-adapter
+  namespace: sh-helm-test
+templates:
+  - templates/xta_adapter_cronjob.yaml
+tests:
+  - it: should use default imagePull secret
+    asserts:
+      - equal:
+          path: spec.jobTemplate.spec.template.spec.imagePullSecrets[0].name
+          value: xta-adapter-image-pull-secret
+  - it: should set the imagePull secret
+    set:
+      imagePullSecret: image-pull-secret
+    asserts:
+      - equal:
+          path: spec.jobTemplate.spec.template.spec.imagePullSecrets[0].name
+          value: image-pull-secret
\ No newline at end of file