diff --git a/bescheid-manager/src/main/java/de/ozgcloud/bescheid/BescheidEventListener.java b/bescheid-manager/src/main/java/de/ozgcloud/bescheid/BescheidEventListener.java
index b663692ecd5ab4364b432572e57d4faca1ba2511..815fa7a7bf15292abdf7247c4a763e8764cbfe07 100644
--- a/bescheid-manager/src/main/java/de/ozgcloud/bescheid/BescheidEventListener.java
+++ b/bescheid-manager/src/main/java/de/ozgcloud/bescheid/BescheidEventListener.java
@@ -25,6 +25,7 @@ package de.ozgcloud.bescheid;
 
 import java.time.LocalDate;
 import java.util.Optional;
+import java.util.function.Consumer;
 import java.util.function.Predicate;
 
 import org.apache.commons.lang3.StringUtils;
@@ -42,6 +43,8 @@ import de.ozgcloud.bescheid.vorgang.VorgangId;
 import de.ozgcloud.command.Command;
 import de.ozgcloud.command.CommandCreatedEvent;
 import de.ozgcloud.command.CommandFailedEvent;
+import de.ozgcloud.document.BescheidDocumentCreatedEvent;
+import de.ozgcloud.document.DocumentService;
 import lombok.NonNull;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.log4j.Log4j2;
@@ -54,30 +57,33 @@ class BescheidEventListener {
 	public static final String CREATE_BESCHEID_ORDER = "CREATE_BESCHEID";
 	public static final String DELETE_BESCHEID_ORDER = "DELETE_BESCHEID";
 	public static final String UPDATE_BESCHEID_ORDER = "UPDATE_BESCHEID";
+	public static final String CREATE_BESCHEID_DOCUMENT_ORDER = "CREATE_BESCHEID_DOCUMENT";
 
-	public static final Predicate<Command> IS_CREATE_BESCHEID_COMMAND = command -> command.getOrder().equals(CREATE_BESCHEID_ORDER);
+	public static final Predicate<Command> IS_CREATE_BESCHEID_COMMAND = command -> CREATE_BESCHEID_ORDER.equals(command.getOrder());
 	private static final String IS_CREATE_BESCHEID = "{T(de.ozgcloud.bescheid.BescheidEventListener).IS_CREATE_BESCHEID_COMMAND.test(event.getSource())}";
 
-	public static final Predicate<Command> IS_DELETE_BESCHEID_COMMAND = command -> command.getOrder().equals(DELETE_BESCHEID_ORDER);
+	public static final Predicate<Command> IS_DELETE_BESCHEID_COMMAND = command -> DELETE_BESCHEID_ORDER.equals(command.getOrder());
 	private static final String IS_DELETE_BESCHEID = "{T(de.ozgcloud.bescheid.BescheidEventListener).IS_DELETE_BESCHEID_COMMAND.test(event.getSource())}";
 
-	public static final Predicate<Command> IS_UPDATE_BESCHEID_COMMAND = command -> command.getOrder().equals(UPDATE_BESCHEID_ORDER);
+	public static final Predicate<Command> IS_UPDATE_BESCHEID_COMMAND = command -> UPDATE_BESCHEID_ORDER.equals(command.getOrder());
 	private static final String IS_UPDATE_BESCHEID = "{T(de.ozgcloud.bescheid.BescheidEventListener).IS_UPDATE_BESCHEID_COMMAND.test(event.getSource())}";
 
+	public static final Predicate<Command> IS_CREATE_BESCHEID_DOCUMENT_COMMAND = command -> CREATE_BESCHEID_DOCUMENT_ORDER.equals(command.getOrder());
+	private static final String IS_CREATE_BESCHEID_DOCUMENT = "{T(de.ozgcloud.bescheid.BescheidEventListener).IS_CREATE_BESCHEID_DOCUMENT_COMMAND.test(event.getSource())}";
+
 	private static final String TEMPLATE_GROUP_KIEL = "Kiel";
 	static final String VORGANG_ID_BODYKEY = "vorgangId";
 	static final String BESCHEID_VOM_BODYKEY = "bescheidVom";
 	static final String GENEHMIGT_BODYKEY = "genehmigt";
 
 	private static final String LOG_MESSAGE_TEMPLATE = "{}. Command failed.";
-	private static final String CREATE_BESCHEID_ERROR_MESSAGE = "Error on executing Create Bescheid Command.";
-	private static final String DELETE_BESCHEID_ERROR_MESSAGE = "Error on executing Delete Bescheid Command.";
-	private static final String UPDATE_BESCHEID_ERROR_MESSAGE = "Error on executing Update Bescheid Command.";
+	private static final String ERROR_MESSAGE_TEMPLATE = "Error on executing %s Command.";
 
 	private final BescheidService service;
 	private final BinaryFileService fileService;
 	private final NachrichtService nachrichtService;
 	private final AttachedItemService attachedItemService;
+	private final DocumentService documentService;
 
 	private final ApplicationEventPublisher eventPublisher;
 	private final CurrentUserService userService;
@@ -85,27 +91,13 @@ class BescheidEventListener {
 
 	@EventListener(condition = IS_CREATE_BESCHEID)
 	public void onCreateBescheidCommand(CommandCreatedEvent event) {
-		Command command = event.getSource();
-
-		doCreateBescheid(command);
-	}
-
-	private void doCreateBescheid(Command command) {
-		SecurityContext prevContext = null;
-		try {
-			prevContext = userService.startSecurityContext(command);
-			execute(command);
-		} catch (Exception e) {
-			LOG.error(LOG_MESSAGE_TEMPLATE, CREATE_BESCHEID_ERROR_MESSAGE, e);
-			eventPublisher.publishEvent(new CommandFailedEvent(command.getId(), buildErrorMessage(CREATE_BESCHEID_ERROR_MESSAGE, e)));
-		} finally {
-			userService.resetSecurityContext(prevContext);
-		}
+		runWithSecurityContext(event.getSource(), this::doCreateBescheid);
 	}
 
-	void execute(Command command) {
+	void doCreateBescheid(Command command) {
 		if (isKielEnvironment()) {
-			doCreateBescheidBiz(command);
+			var bescheid = doCreateBescheidBiz(command);
+			nachrichtService.createNachrichtDraft(bescheid);
 			eventPublisher.publishEvent(new BescheidCreatedEvent(command));
 			return;
 		}
@@ -115,15 +107,43 @@ class BescheidEventListener {
 
 	boolean isKielEnvironment() {
 		Predicate<SmartDocumentsProperties> configuredForKiel = properties -> TEMPLATE_GROUP_KIEL.equals(properties.getTemplateGroup());
-		var smartDocumentsProperties1 = smartDocumentsProperties.filter(configuredForKiel);
-		return smartDocumentsProperties1.isPresent();
+		return smartDocumentsProperties.filter(configuredForKiel).isPresent();
 	}
 
-	public void doCreateBescheidBiz(@NonNull Command command) {
-		var bescheid = service.createBescheid(createRequest(command));
-		bescheid = fileService.uploadBescheidFile(bescheid);
+	@EventListener(condition = IS_DELETE_BESCHEID)
+	public void onDeleteBescheid(CommandCreatedEvent event) {
+		runWithSecurityContext(event.getSource(), this::doDeleteBescheid);
+	}
+
+	void doDeleteBescheid(Command command) {
+		attachedItemService.deleteBescheidDraft(command);
+		eventPublisher.publishEvent(new BescheidDeletedEvent(command));
+	}
+
+	@EventListener(condition = IS_UPDATE_BESCHEID)
+	public void onUpdateBescheidCommand(CommandCreatedEvent event) {
+		runWithSecurityContext(event.getSource(), this::doUpdateBescheid);
+	}
 
-		nachrichtService.createNachrichtDraft(bescheid);
+	void doUpdateBescheid(Command command) {
+		attachedItemService.updateBescheidDraft(command);
+		eventPublisher.publishEvent(new BescheidUpdatedEvent(command));
+	}
+
+	@EventListener(condition = IS_CREATE_BESCHEID_DOCUMENT)
+	public void onCreatedBescheidDocument(CommandCreatedEvent event) {
+		runWithSecurityContext(event.getSource(), this::doCreateBescheidDocument);
+	}
+
+	void doCreateBescheidDocument(Command command) {
+		var bescheid = doCreateBescheidBiz(command);
+		var bescheidDocument = documentService.createBescheidDocument(command, bescheid);
+		eventPublisher.publishEvent(new BescheidDocumentCreatedEvent(command, bescheidDocument));
+	}
+
+	Bescheid doCreateBescheidBiz(@NonNull Command command) {
+		var bescheid = service.createBescheid(createRequest(command));
+		return fileService.uploadBescheidFile(bescheid);
 	}
 
 	BescheidRequest createRequest(Command command) {
@@ -141,36 +161,20 @@ class BescheidEventListener {
 		return builder.build();
 	}
 
-	@EventListener(condition = IS_DELETE_BESCHEID)
-	public void onDeleteBescheid(CommandCreatedEvent event) {
-		SecurityContext prevContext = null;
-		Command command = event.getSource();
-		try {
-			prevContext = userService.startSecurityContext(command);
-			attachedItemService.deleteBescheidDraft(command);
-			eventPublisher.publishEvent(new BescheidDeletedEvent(command));
-		} catch (Exception e) {
-			LOG.error(LOG_MESSAGE_TEMPLATE, DELETE_BESCHEID_ERROR_MESSAGE, e);
-			eventPublisher.publishEvent(new CommandFailedEvent(command.getId(), buildErrorMessage(DELETE_BESCHEID_ERROR_MESSAGE, e)));
-		} finally {
-			userService.resetSecurityContext(prevContext);
-		}
-	}
-	@EventListener(condition = IS_UPDATE_BESCHEID)
-	public void onUpdateBescheidCommand(CommandCreatedEvent event) {
-		Command command = event.getSource();
+	void runWithSecurityContext(Command command, Consumer<Command> commandExecutor) {
 		SecurityContext prevContext = null;
 		try {
 			prevContext = userService.startSecurityContext(command);
-			attachedItemService.updateBescheidDraft(command);
-			eventPublisher.publishEvent(new BescheidUpdatedEvent(command));
+			commandExecutor.accept(command);
 		} catch (Exception e) {
-			LOG.error(LOG_MESSAGE_TEMPLATE, UPDATE_BESCHEID_ERROR_MESSAGE, e);
-			eventPublisher.publishEvent(new CommandFailedEvent(command.getId(), buildErrorMessage(UPDATE_BESCHEID_ERROR_MESSAGE, e)));
+			var errorMessage = ERROR_MESSAGE_TEMPLATE.formatted(command.getOrder());
+			LOG.error(LOG_MESSAGE_TEMPLATE, errorMessage, e);
+			eventPublisher.publishEvent(new CommandFailedEvent(command.getId(), buildErrorMessage(errorMessage, e)));
 		} finally {
 			userService.resetSecurityContext(prevContext);
 		}
 	}
+
 	private String buildErrorMessage(String message, Exception cause) {
 		try {
 			StringBuilder sb = new StringBuilder(message);
@@ -182,7 +186,7 @@ class BescheidEventListener {
 			return sb.toString();
 		} catch (Exception e2) {
 			LOG.error("Error in building Error Message (sick).", e2);
-			return CREATE_BESCHEID_ERROR_MESSAGE;
+			return message;
 		}
 	}
 
diff --git a/bescheid-manager/src/main/java/de/ozgcloud/bescheid/BescheidFeatureProperties.java b/bescheid-manager/src/main/java/de/ozgcloud/bescheid/BescheidFeatureProperties.java
new file mode 100644
index 0000000000000000000000000000000000000000..538ae8150df7b0214c8a4cfdb619d1cb1cda3305
--- /dev/null
+++ b/bescheid-manager/src/main/java/de/ozgcloud/bescheid/BescheidFeatureProperties.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den
+ * Ministerpräsidenten des Landes Schleswig-Holstein
+ * Staatskanzlei
+ * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+ *
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+package de.ozgcloud.bescheid;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+import lombok.Getter;
+
+@Configuration
+@ConfigurationProperties(prefix = "ozgcloud.feature.bescheid")
+@Getter
+public class BescheidFeatureProperties {
+
+	private boolean storeAsDocument = false;
+}
diff --git a/bescheid-manager/src/main/java/de/ozgcloud/bescheid/BescheidService.java b/bescheid-manager/src/main/java/de/ozgcloud/bescheid/BescheidService.java
index 3ee94d186e7973d2bfd1a484688cfb223be23e55..70e3922dc1f9ef381c95048de545bd127c328bc5 100644
--- a/bescheid-manager/src/main/java/de/ozgcloud/bescheid/BescheidService.java
+++ b/bescheid-manager/src/main/java/de/ozgcloud/bescheid/BescheidService.java
@@ -15,6 +15,7 @@ import lombok.extern.log4j.Log4j2;
 @Log4j2
 class BescheidService {
 
+	// TODO: Fehlernachricht anpassen
 	private static final String ERROR_MESSAGE_NO_SERVICE = "'CREATE_BESCHEID' Command received but no Bescheid Endpoint is configured.";
 
 	@Autowired
@@ -24,7 +25,7 @@ class BescheidService {
 
 	@PostConstruct
 	void logStatus() {
-		if (Objects.isNull(ERROR_MESSAGE_NO_SERVICE)) {
+		if (Objects.isNull(remoteService)) {
 			LOG.info("No BescheidRemoteService configured - Bescheid creation is not possible.");
 		} else {
 			LOG.info("Bescheid-Manager is configured.");
diff --git a/bescheid-manager/src/main/java/de/ozgcloud/bescheid/attacheditem/AttachedItemService.java b/bescheid-manager/src/main/java/de/ozgcloud/bescheid/attacheditem/AttachedItemService.java
index 53e246ff9d1e9d293badd27fdca83e97771977ae..a0a02756fcb0c3c655dd8381918e9e4467121b0f 100644
--- a/bescheid-manager/src/main/java/de/ozgcloud/bescheid/attacheditem/AttachedItemService.java
+++ b/bescheid-manager/src/main/java/de/ozgcloud/bescheid/attacheditem/AttachedItemService.java
@@ -47,7 +47,7 @@ import lombok.extern.log4j.Log4j2;
 @Log4j2
 public class AttachedItemService {
 
-	static final String BESCHEID_ITEM_NAME = "Bescheid";
+	public static final String BESCHEID_ITEM_NAME = "Bescheid";
 	static final String CREATE_ATTACHED_ITEM_ORDER = "CREATE_ATTACHED_ITEM";
 	static final String UPDATE_ATTACHED_ITEM_ORDER = "UPDATE_ATTACHED_ITEM";
 	static final String DELETE_ATTACHED_ITEM = "DELETE_ATTACHED_ITEM";
diff --git a/bescheid-manager/src/main/java/de/ozgcloud/bescheid/dummy/DummyBescheidRemoteService.java b/bescheid-manager/src/main/java/de/ozgcloud/bescheid/dummy/DummyBescheidRemoteService.java
index 403defced86ffae1733612770f145c5f1581ca27..694e6b999b7dce08195e5648db629199daa63d27 100644
--- a/bescheid-manager/src/main/java/de/ozgcloud/bescheid/dummy/DummyBescheidRemoteService.java
+++ b/bescheid-manager/src/main/java/de/ozgcloud/bescheid/dummy/DummyBescheidRemoteService.java
@@ -1,6 +1,6 @@
 package de.ozgcloud.bescheid.dummy;
 
-import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
 import org.springframework.stereotype.Service;
 
 import com.google.common.net.MediaType;
@@ -12,7 +12,7 @@ import de.ozgcloud.bescheid.vorgang.Vorgang;
 import de.ozgcloud.common.binaryfile.TempFileUtils;
 
 @Service
-@ConditionalOnMissingBean(BescheidRemoteService.class)
+@ConditionalOnProperty("ozgcloud.feature.bescheid.enable-dummy-document-processor")
 class DummyBescheidRemoteService implements BescheidRemoteService {
 
 	private static final String DUMMY_BESCHEID_FILE_NAME = "dummy-bescheid.pdf";
diff --git a/bescheid-manager/src/main/java/de/ozgcloud/bescheid/smartdocuments/SmartDocumentsBescheidRemoteService.java b/bescheid-manager/src/main/java/de/ozgcloud/bescheid/smartdocuments/SmartDocumentsBescheidRemoteService.java
index 87bd9af60ce30a442052172f5b14d7aeb6f21e9d..6dd87bd4b8bb2423fe933e8d4e098e056890f8fc 100644
--- a/bescheid-manager/src/main/java/de/ozgcloud/bescheid/smartdocuments/SmartDocumentsBescheidRemoteService.java
+++ b/bescheid-manager/src/main/java/de/ozgcloud/bescheid/smartdocuments/SmartDocumentsBescheidRemoteService.java
@@ -126,7 +126,7 @@ class SmartDocumentsBescheidRemoteService implements BescheidRemoteService {
 			var expr = xPath.compile("/root/SmartDocument/Fields/NachrichtenText/text()");
 			var text = (Text) expr.evaluate(document, XPathConstants.NODE);
 
-			return Optional.of(text.getTextContent());
+			return Optional.ofNullable(text.getTextContent());
 		} catch (XPathExpressionException | SAXException | IOException | ParserConfigurationException e) {
 			LOG.error("XML-Parsing error on extracting Nachricht-Text: {}", e.getMessage(), e);
 		} catch (ClassCastException e) {
diff --git a/bescheid-manager/src/main/java/de/ozgcloud/document/DocumentService.java b/bescheid-manager/src/main/java/de/ozgcloud/document/DocumentService.java
index f290e57572d8bf1a95a9dec9a8b54671a6b179c8..25838cf4939ce8d9b2db28ac1f2bf404a83304e7 100644
--- a/bescheid-manager/src/main/java/de/ozgcloud/document/DocumentService.java
+++ b/bescheid-manager/src/main/java/de/ozgcloud/document/DocumentService.java
@@ -23,16 +23,20 @@
  */
 package de.ozgcloud.document;
 
+import static java.util.Objects.*;
+
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Optional;
 
 import org.apache.commons.collections.MapUtils;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.stereotype.Service;
 
 import de.ozgcloud.apilib.common.command.OzgCloudCommand;
 import de.ozgcloud.apilib.common.command.OzgCloudCommandService;
 import de.ozgcloud.apilib.common.command.grpc.CommandMapper;
+import de.ozgcloud.bescheid.Bescheid;
 import de.ozgcloud.bescheid.BescheidCallContextAttachingInterceptor;
 import de.ozgcloud.bescheid.attacheditem.AttachedItemService;
 import de.ozgcloud.bescheid.attacheditem.BescheidItem;
@@ -50,6 +54,7 @@ public class DocumentService {
 	static final String CREATE_ATTACHED_ITEM_ORDER = "CREATE_ATTACHED_ITEM";
 	static final String FIELD_DOCUMENT_TYPE = "type";
 	static final String FIELD_DOCUMENT_FILE = "documentFile";
+	static final String FIELD_NACHRICHT_TEXT = "nachrichtText";
 
 	private final AttachedItemService attachedItemService;
 	private final OzgCloudCommandService commandService;
@@ -57,8 +62,16 @@ public class DocumentService {
 	private final DocumentMapper documentMapper;
 
 	public String createBescheidDocument(Command command) {
+		return createBescheidDocument(command, buildItemMap(command));
+	}
+
+	public String createBescheidDocument(Command command, Bescheid bescheid) {
+		return createBescheidDocument(command, buildItemMap(bescheid));
+	}
+
+	String createBescheidDocument(Command command, Map<String, Object> itemMap) {
 		validateBescheidItem(command.getRelationId());
-		var ozgCloudCommand = buildCreateDocumentOzgCommand(command);
+		var ozgCloudCommand = buildCreateDocumentOzgCommand(command, buildAttachedItem(command, itemMap));
 		var executedCommand = commandService.createAndWaitUntilDone(ozgCloudCommand);
 		return executedCommand.getCreatedResource();
 	}
@@ -71,21 +84,21 @@ public class DocumentService {
 		}
 	}
 
-	OzgCloudCommand buildCreateDocumentOzgCommand(Command command) {
+	OzgCloudCommand buildCreateDocumentOzgCommand(Command command, Map<String, Object> bodyObject) {
 		return OzgCloudCommand.builder()
 				.order(CREATE_ATTACHED_ITEM_ORDER)
 				.vorgangId(commandMapper.toOzgCloudVorgangId(command.getVorgangId()))
 				.relationId(commandMapper.mapRelationId(command.getVorgangId()))
-				.bodyObject(buildAttachedItem(command))
+				.bodyObject(bodyObject)
 				.build();
 	}
 
-	Map<String, Object> buildAttachedItem(Command command) {
+	Map<String, Object> buildAttachedItem(Command command, Map<String, Object> itemMap) {
 		var result = new HashMap<String, Object>();
 		result.put(BescheidItem.PROPERTY_VORGANG_ID, command.getVorgangId());
 		result.put(BescheidItem.PROPERTY_CLIENT, BescheidCallContextAttachingInterceptor.BESCHEID_MANAGER_CLIENT_NAME);
 		result.put(BescheidItem.PROPERTY_ITEM_NAME, DOCUMENT_ITEM_NAME);
-		result.put(BescheidItem.PROPERTY_ITEM, buildItemMap(command));
+		result.put(BescheidItem.PROPERTY_ITEM, itemMap);
 		return result;
 	}
 
@@ -95,6 +108,15 @@ public class DocumentService {
 		return Map.of(FIELD_DOCUMENT_TYPE, DOCUMENT_TYPE, FIELD_DOCUMENT_FILE, fileId);
 	}
 
+	Map<String, Object> buildItemMap(Bescheid bescheid) {
+		if (isNull(bescheid.getBescheidFileId())) {
+			throw new TechnicalException("Bescheid file id is missing.");
+		}
+		return Map.of(FIELD_DOCUMENT_TYPE, DOCUMENT_TYPE,
+				FIELD_DOCUMENT_FILE, bescheid.getBescheidFileId().toString(),
+				FIELD_NACHRICHT_TEXT, bescheid.getNachrichtText().orElse(StringUtils.EMPTY));
+	}
+
 	public Document getDocument(String id) {
 		return documentMapper.fromAttachedItem(attachedItemService.getItem(id));
 	}
diff --git a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/BescheidEventListenerTest.java b/bescheid-manager/src/test/java/de/ozgcloud/bescheid/BescheidEventListenerTest.java
index 5964ad0da6fd99680853a85519c0958a150607ae..b72a618a2a721d34481538f788a18d12558eb962 100644
--- a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/BescheidEventListenerTest.java
+++ b/bescheid-manager/src/test/java/de/ozgcloud/bescheid/BescheidEventListenerTest.java
@@ -8,8 +8,10 @@ import static org.mockito.Mockito.*;
 
 import java.util.Map;
 import java.util.Optional;
+import java.util.function.Consumer;
 
 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.ArgumentCaptor;
@@ -28,11 +30,12 @@ import de.ozgcloud.bescheid.common.callcontext.UserProfile;
 import de.ozgcloud.bescheid.common.callcontext.UserProfileTestFactory;
 import de.ozgcloud.bescheid.nachricht.NachrichtService;
 import de.ozgcloud.bescheid.smartdocuments.SmartDocumentsProperties;
-import de.ozgcloud.bescheid.vorgang.VorgangId;
 import de.ozgcloud.command.Command;
 import de.ozgcloud.command.CommandCreatedEventTestFactory;
 import de.ozgcloud.command.CommandFailedEvent;
 import de.ozgcloud.command.CommandTestFactory;
+import de.ozgcloud.document.BescheidDocumentCreatedEvent;
+import de.ozgcloud.document.DocumentService;
 
 class BescheidEventListenerTest {
 
@@ -48,6 +51,10 @@ class BescheidEventListenerTest {
 	private NachrichtService nachrichtService;
 	@Mock
 	private AttachedItemService attachedItemService;
+	@Mock
+	private BescheidFeatureProperties featureProperties;
+	@Mock
+	private DocumentService documentService;
 
 	@Mock
 	private ApplicationEventPublisher eventPublisher;
@@ -57,91 +64,36 @@ class BescheidEventListenerTest {
 	@Nested
 	class TestOnCreateBescheidCommand {
 
-		private Command command = CommandTestFactory.createBuilder()
-				.bodyObject(
-						Map.of(VORGANG_ID_BODYKEY, VORGANG_ID.toString(),
-								BESCHEID_VOM_BODYKEY, BESCHEID_VOM_STRING,
-								GENEHMIGT_BODYKEY, GENEHMIGT))
-				.build();
-
-		@Mock
-		private SecurityContext secContext;
+		private Command command = CommandTestFactory.create();
 
 		@Test
-		void shouldCreateBescheid() {
-			doReturn(true).when(listener).isKielEnvironment();
-
+		void shouldCallRunWithSecurityContext() {
 			listener.onCreateBescheidCommand(CommandCreatedEventTestFactory.withCommand(command));
 
-			verify(listener).execute(command);
+			verify(listener).runWithSecurityContext(eq(command), any());
 		}
 
 		@Test
-		void shouldPublishErrorEventOnException() {
-			doReturn(true).when(listener).isKielEnvironment();
-			doThrow(new RuntimeException("ups")).when(listener).doCreateBescheidBiz(any());
-
+		void shouldExecuteCreateBescheid() {
 			listener.onCreateBescheidCommand(CommandCreatedEventTestFactory.withCommand(command));
 
-			verify(eventPublisher).publishEvent(any(CommandFailedEvent.class));
-		}
-
-		@Nested
-		class HandleSecurityContext {
-
-			@BeforeEach
-			void init() {
-				when(userService.startSecurityContext(any())).thenReturn(secContext);
-			}
-
-			@Test
-			void shouldStartSecurityContext() {
-				listener.onCreateBescheidCommand(CommandCreatedEventTestFactory.withCommand(command));
-
-				verify(userService).startSecurityContext(command);
-			}
-
-			@Test
-			void shouldResetSecurityContext() {
-				listener.onCreateBescheidCommand(CommandCreatedEventTestFactory.withCommand(command));
-
-				verify(userService).resetSecurityContext(secContext);
-			}
-
-			@Test
-			void shouldResetSecurityContextAfterException() {
-				doReturn(true).when(listener).isKielEnvironment();
-				doThrow(new RuntimeException("ups")).when(listener).doCreateBescheidBiz(any());
-
-				listener.onCreateBescheidCommand(CommandCreatedEventTestFactory.withCommand(command));
-
-				verify(userService).resetSecurityContext(secContext);
-			}
-		}
-
-		@Nested
-		class CreateBescheidRequest {
-			@Test
-			void shouldContainUserProfile() {
-				UserProfile user = UserProfileTestFactory.create();
-				when(userService.getUserProfile()).thenReturn(user);
-
-				var request = listener.createRequest(command);
-
-				assertThat(request.getCreateFor()).isSameAs(user);
-			}
+			verify(listener).doCreateBescheid(command);
 		}
-
 	}
 
 	@Nested
-	class TestExecute {
+	class TestDoCreateBescheid {
+
+		private static final Command COMMAND = CommandTestFactory.createBuilder()
+				.bodyObject(
+						Map.of(VORGANG_ID_BODYKEY, VORGANG_ID.toString(),
+								BESCHEID_VOM_BODYKEY, BESCHEID_VOM_STRING,
+								GENEHMIGT_BODYKEY, GENEHMIGT))
+				.build();
 
 		@Captor
 		private ArgumentCaptor<BescheidCreatedEvent> eventCaptor;
 
-		private Command command = CommandTestFactory.create();
-
 		@Nested
 		class TestKielConfigured {
 
@@ -152,26 +104,29 @@ class BescheidEventListenerTest {
 
 			@Test
 			void shouldCallDoCreateBescheidBiz() {
-				listener.execute(command);
+				listener.doCreateBescheid(COMMAND);
 
-				verify(listener).doCreateBescheidBiz(command);
+				verify(listener).doCreateBescheidBiz(COMMAND);
+				verify(attachedItemService, never()).createBescheidDraft(any());
 			}
 
 			@Test
-			void shouldNotCallVorgangAttachedItemService() {
-				listener.execute(command);
+			void shouldCallNachrichtService() {
+				var bescheid = BescheidTestFactory.create();
+				doReturn(bescheid).when(listener).doCreateBescheidBiz(any());
 
-				verify(attachedItemService, never()).createBescheidDraft(any());
+				listener.doCreateBescheid(COMMAND);
+
+				verify(nachrichtService).createNachrichtDraft(bescheid);
 			}
 
 			@Test
-			void shouldCallPublishEvent() {
-				listener.execute(command);
+			void shouldPublishBescheidCreatedEvent() {
+				listener.doCreateBescheid(COMMAND);
 
 				verify(eventPublisher).publishEvent(eventCaptor.capture());
-				assertThat(eventCaptor.getValue().getCreatedResource()).isNull();
+				assertThat(eventCaptor.getValue().getSource()).isEqualTo(CommandTestFactory.ID);
 			}
-
 		}
 
 		@Nested
@@ -183,82 +138,40 @@ class BescheidEventListenerTest {
 			}
 
 			@Test
-			void shouldNotCallDoCreateBescheidBiz() {
-				listener.execute(command);
+			void shouldCallCreateBescheidDraft() {
+				listener.doCreateBescheid(COMMAND);
 
+				verify(attachedItemService).createBescheidDraft(COMMAND);
 				verify(listener, never()).doCreateBescheidBiz(any());
 			}
 
 			@Test
-			void shouldCallVorgangAttachedItemService() {
-				listener.execute(command);
+			@DisplayName("should publish BescheidCreatedEvent after creating BescheidDraft")
+			void shouldPublishBescheidCreatedEventWithCommand() {
+				var createdResource = "item-id";
+				when(attachedItemService.createBescheidDraft(any())).thenReturn(createdResource);
+
+				listener.doCreateBescheid(COMMAND);
 
-				verify(attachedItemService).createBescheidDraft(command);
+				verify(eventPublisher).publishEvent(eventCaptor.capture());
+				assertThat(eventCaptor.getValue().getCommand()).isSameAs(COMMAND);
 			}
 
 			@Test
-			void shouldCallPublishEvent() {
-				var expectedItemId = "createdItemId";
-				when(attachedItemService.createBescheidDraft(any())).thenReturn(expectedItemId);
+			@DisplayName("should publish BescheidCreatedEvent with created resource")
+			void shouldPublishBescheidCreatedEventWithCreatedResource() {
+				var createdResource = "item-id";
+				when(attachedItemService.createBescheidDraft(any())).thenReturn(createdResource);
 
-				listener.execute(command);
+				listener.doCreateBescheid(COMMAND);
 
 				verify(eventPublisher).publishEvent(eventCaptor.capture());
-				assertThat(eventCaptor.getValue().getCreatedResource()).isEqualTo(expectedItemId);
+				assertThat(eventCaptor.getValue().getCreatedResource()).isEqualTo(createdResource);
 			}
 		}
 
 	}
 
-	@Nested
-	class CreateBescheid {
-
-		private Command command = CommandTestFactory.createBuilder()
-				.bodyObject(
-						Map.of(VORGANG_ID_BODYKEY, VORGANG_ID.toString(),
-								BESCHEID_VOM_BODYKEY, BESCHEID_VOM_STRING,
-								GENEHMIGT_BODYKEY, GENEHMIGT))
-				.build();
-
-		@Captor
-		private ArgumentCaptor<BescheidRequest> requestCaptor;
-
-		private Bescheid bescheid = BescheidTestFactory.create();
-		private Bescheid bescheidWithFileId = BescheidTestFactory.create();
-
-		@BeforeEach
-		void init() {
-			when(service.createBescheid(any())).thenReturn(bescheid);
-			when(fileService.uploadBescheidFile(any())).thenReturn(bescheidWithFileId);
-			when(userService.getUserProfile()).thenReturn(UserProfileTestFactory.create());
-		}
-
-		@Test
-		void shouldCreateBescheid() {
-			listener.doCreateBescheidBiz(command);
-
-			verify(service).createBescheid(requestCaptor.capture());
-			assertThat(requestCaptor.getValue()).usingRecursiveComparison()
-					.isEqualTo(BescheidRequestTestFactory.createBuilder()
-							.vorgangId(VorgangId.from(CommandTestFactory.VORGANG_ID))
-							.build());
-		}
-
-		@Test
-		void shouldSaveFile() {
-			listener.doCreateBescheidBiz(command);
-
-			verify(fileService).uploadBescheidFile(bescheid);
-		}
-
-		@Test
-		void shouldSaveNachricht() {
-			listener.doCreateBescheidBiz(command);
-
-			verify(nachrichtService).createNachrichtDraft(bescheidWithFileId);
-		}
-	}
-
 	@Nested
 	class TestIsKielEnvironment {
 
@@ -295,149 +208,325 @@ class BescheidEventListenerTest {
 		}
 	}
 
+	@Nested
+	class TestCreateBescheidRequest {
+
+		private static final Command COMMAND = CommandTestFactory.createBuilder()
+				.vorgangId(VORGANG_ID.toString())
+				.bodyObject(
+						Map.of(BESCHEID_VOM_BODYKEY, BESCHEID_VOM_STRING,
+								GENEHMIGT_BODYKEY, false))
+				.build();
+
+		@Test
+		void shouldSetVorgangId() {
+			var request = createBescheidRequest();
+
+			assertThat(request.getVorgangId()).isEqualTo(VORGANG_ID);
+		}
+
+		@Test
+		void shouldSetBescheidVom() {
+			var request = createBescheidRequest();
+
+			assertThat(request.getBescheidVom()).isEqualTo(BESCHEID_VOM);
+		}
+
+		@Test
+		void shouldSetGenehmigt() {
+			var request = createBescheidRequest();
+
+			assertThat(request.isGenehmigt()).isFalse();
+		}
+
+		@Test
+		void shouldSetDefaultGenehmigt() {
+			Command command = CommandTestFactory.createBuilder()
+					.vorgangId(VORGANG_ID.toString())
+					.bodyObject(
+							Map.of(BESCHEID_VOM_BODYKEY, BESCHEID_VOM_STRING))
+					.build();
+
+			var request = listener.createRequest(command);
+
+			assertThat(request.isGenehmigt()).isTrue();
+		}
+
+		@Test
+		void shouldContainUserProfile() {
+			UserProfile user = UserProfileTestFactory.create();
+			when(userService.getUserProfile()).thenReturn(user);
+
+			var request = listener.createRequest(COMMAND);
+
+			assertThat(request.getCreateFor()).isSameAs(user);
+		}
+
+		private BescheidRequest createBescheidRequest() {
+			return listener.createRequest(COMMAND);
+		}
+	}
+
 	@Nested
 	class TestOnDeleteBescheid {
 
+		private Command command = CommandTestFactory.create();
+
+		@Test
+		void shouldCallRunWithSecurityContext() {
+			listener.onDeleteBescheid(CommandCreatedEventTestFactory.withCommand(command));
+
+			verify(listener).runWithSecurityContext(eq(command), any());
+		}
+
+		@Test
+		void shouldExecuteCreateBescheid() {
+			listener.onDeleteBescheid(CommandCreatedEventTestFactory.withCommand(command));
+
+			verify(listener).doDeleteBescheid(command);
+		}
+	}
+
+	@Nested
+	class TestDoDeleteBescheid {
+
 		@Captor
 		private ArgumentCaptor<BescheidDeletedEvent> bescheidDeletedEventCaptor;
-		@Captor
-		private ArgumentCaptor<CommandFailedEvent> commandFailedEventCaptor;
 
 		private Command command = CommandTestFactory.create();
 
 		@Test
 		void shouldCallAttachedItemService() {
-			listener.onDeleteBescheid(CommandCreatedEventTestFactory.withCommand(command));
+			listener.doDeleteBescheid(command);
 
 			verify(attachedItemService).deleteBescheidDraft(command);
 		}
 
 		@Test
 		void shouldPublishCommandExecutedEvent() {
-			listener.onDeleteBescheid(CommandCreatedEventTestFactory.withCommand(command));
+			listener.doDeleteBescheid(command);
 
 			verify(eventPublisher).publishEvent(bescheidDeletedEventCaptor.capture());
 			assertThat(bescheidDeletedEventCaptor.getValue().getCommand()).isSameAs(command);
 		}
 
+	}
+
+	@Nested
+	class TestOnUpdateBescheid {
+
+		private Command command = CommandTestFactory.create();
+
 		@Test
-		void shouldPublishErrorEventOnException() {
-			doThrow(new RuntimeException("ups")).when(attachedItemService).deleteBescheidDraft(any());
+		void shouldCallRunWithSecurityContext() {
+			listener.onUpdateBescheidCommand(CommandCreatedEventTestFactory.withCommand(command));
 
-			listener.onDeleteBescheid(CommandCreatedEventTestFactory.withCommand(command));
+			verify(listener).runWithSecurityContext(eq(command), any());
+		}
 
-			verify(eventPublisher).publishEvent(commandFailedEventCaptor.capture());
-			assertThat(commandFailedEventCaptor.getValue().getSource()).isEqualTo(command.getId());
-			assertThat(commandFailedEventCaptor.getValue().getErrorMessage()).isNotEmpty();
+		@Test
+		void shouldExecuteCreateBescheid() {
+			listener.onUpdateBescheidCommand(CommandCreatedEventTestFactory.withCommand(command));
+
+			verify(listener).doUpdateBescheid(command);
 		}
 
-		@Nested
-		class HandleSecurityContext {
+	}
 
-			@Mock
-			private SecurityContext secContext;
+	@Nested
+	class TestDoUpdateBescheid {
 
-			@BeforeEach
-			void init() {
-				when(userService.startSecurityContext(any())).thenReturn(secContext);
-			}
+		@Captor
+		private ArgumentCaptor<BescheidUpdatedEvent> bescheidUpdatedEventCaptor;
 
-			@Test
-			void shouldStartSecurityContext() {
-				listener.onCreateBescheidCommand(CommandCreatedEventTestFactory.withCommand(command));
+		private Command command = CommandTestFactory.createBuilder().build();
 
-				verify(userService).startSecurityContext(command);
-			}
+		@Test
+		void shouldCallUpdateBescheidDraft() {
+			listener.doUpdateBescheid(command);
 
-			@Test
-			void shouldResetSecurityContext() {
-				listener.onCreateBescheidCommand(CommandCreatedEventTestFactory.withCommand(command));
+			verify(attachedItemService).updateBescheidDraft(command);
+		}
 
-				verify(userService).resetSecurityContext(secContext);
-			}
+		@Test
+		void shouldPublishBescheidUpdatedEvent() {
+			listener.doUpdateBescheid(command);
 
-			@Test
-			void shouldResetSecurityContextAfterException() {
-				doReturn(true).when(listener).isKielEnvironment();
-				doThrow(new RuntimeException("ups")).when(listener).doCreateBescheidBiz(any());
+			verify(eventPublisher).publishEvent(bescheidUpdatedEventCaptor.capture());
+			assertThat(bescheidUpdatedEventCaptor.getValue().getCommand()).isSameAs(command);
+		}
 
-				listener.onCreateBescheidCommand(CommandCreatedEventTestFactory.withCommand(command));
+	}
 
-				verify(userService).resetSecurityContext(secContext);
-			}
+	@Nested
+	class TestOnCreateBescheidDocument {
+
+		private Command command = CommandTestFactory.create();
+
+		@Test
+		void shouldCallRunWithSecurityContext() {
+			listener.onCreatedBescheidDocument(CommandCreatedEventTestFactory.withCommand(command));
+
+			verify(listener).runWithSecurityContext(eq(command), any());
+		}
+
+		@Test
+		void shouldExecuteCreateBescheidDocument() {
+			listener.onCreatedBescheidDocument(CommandCreatedEventTestFactory.withCommand(command));
+
+			verify(listener).doCreateBescheidDocument(command);
 		}
 	}
 
 	@Nested
-	class TestOnUpdateBescheid {
+	class TestDoCreateBescheidDocument {
+
+		private static final Command COMMAND = CommandTestFactory.create();
+		private static final Bescheid BESCHEID = BescheidTestFactory.create();
 
 		@Captor
-		private ArgumentCaptor<BescheidUpdatedEvent> bescheidUpdatedEventCaptor;
-		@Captor
-		private ArgumentCaptor<CommandFailedEvent> updateFailedEventCaptor;
+		private ArgumentCaptor<BescheidDocumentCreatedEvent> eventCaptor;
 
-		private Command command = CommandTestFactory.createBuilder().build();
+		@BeforeEach
+		void init() {
+			doReturn(BESCHEID).when(listener).doCreateBescheidBiz(any());
+		}
 
 		@Test
-		void shouldCallUpdateBescheidDraft() {
-			listener.onUpdateBescheidCommand(CommandCreatedEventTestFactory.withCommand(command));
+		void shouldCallCreateBescheidBiz() {
+			listener.doCreateBescheidDocument(COMMAND);
 
-			verify(attachedItemService).updateBescheidDraft(command);
+			verify(listener).doCreateBescheidBiz(COMMAND);
 		}
 
 		@Test
-		void shouldPublishBescheidUpdatedEvent() {
-			listener.onUpdateBescheidCommand(CommandCreatedEventTestFactory.withCommand(command));
+		void shouldCallCreateBescheidDocument() {
+			listener.doCreateBescheidDocument(COMMAND);
 
-			verify(eventPublisher).publishEvent(bescheidUpdatedEventCaptor.capture());
-			assertThat(bescheidUpdatedEventCaptor.getValue().getCommand()).isSameAs(command);
+			verify(documentService).createBescheidDocument(COMMAND, BESCHEID);
 		}
 
 		@Test
-		void shouldPublishCommandFailedEvent() {
-			doThrow(new RuntimeException("ups")).when(attachedItemService).updateBescheidDraft(any());
+		@DisplayName("should publish BescheidDocumentCreatedEvent with command")
+		void shouldPublishEventWithCommand() {
+			listener.doCreateBescheidDocument(COMMAND);
 
-			listener.onUpdateBescheidCommand(CommandCreatedEventTestFactory.withCommand(command));
+			verify(eventPublisher).publishEvent(eventCaptor.capture());
+			assertThat(eventCaptor.getValue().getCommand()).isEqualTo(COMMAND);
+		}
 
-			verify(eventPublisher).publishEvent(updateFailedEventCaptor.capture());
-			assertThat(updateFailedEventCaptor.getValue().getSource()).isEqualTo(command.getId());
+		@Test
+		@DisplayName("should publish BescheidDocumentCreatedEvent with createdResource")
+		void shouldPublishEventWithCreatedResource() {
+			var bescheidDocument = "document-id";
+			when(documentService.createBescheidDocument(any(), any(Bescheid.class))).thenReturn(bescheidDocument);
+
+			listener.doCreateBescheidDocument(COMMAND);
+
+			verify(eventPublisher).publishEvent(eventCaptor.capture());
+			assertThat(eventCaptor.getValue().getCreatedResource()).isEqualTo(bescheidDocument);
 		}
+	}
 
-		@Nested
-		class HandleSecurityContext {
+	@Nested
+	class TestCreateBescheidBiz {
 
-			@Mock
-			private SecurityContext secContext;
+		private Command command = CommandTestFactory.create();
 
-			@BeforeEach
-			void init() {
-				when(userService.startSecurityContext(any())).thenReturn(secContext);
-			}
+		@Test
+		void shouldCallCreateRequest() {
+			listener.doCreateBescheidBiz(command);
 
-			@Test
-			void shouldStartSecurityContext() {
-				listener.onUpdateBescheidCommand(CommandCreatedEventTestFactory.withCommand(command));
+			verify(listener).createRequest(command);
+		}
 
-				verify(userService).startSecurityContext(command);
-			}
+		@Test
+		void shouldCallBescheidService() {
+			var bescheidRequest = BescheidRequestTestFactory.create();
+			doReturn(bescheidRequest).when(listener).createRequest(any());
 
-			@Test
-			void shouldResetSecurityContext() {
-				listener.onUpdateBescheidCommand(CommandCreatedEventTestFactory.withCommand(command));
+			listener.doCreateBescheidBiz(command);
 
-				verify(userService).resetSecurityContext(secContext);
-			}
+			verify(service).createBescheid(bescheidRequest);
+		}
 
-			@Test
-			void shouldResetSecurityContextAfterException() {
-				doThrow(new RuntimeException("ups")).when(attachedItemService).updateBescheidDraft(any());
+		@Test
+		void shouldCallFileService() {
+			var bescheid = BescheidTestFactory.create();
+			when(service.createBescheid(any())).thenReturn(bescheid);
 
-				listener.onUpdateBescheidCommand(CommandCreatedEventTestFactory.withCommand(command));
+			listener.doCreateBescheidBiz(command);
 
-				verify(userService).resetSecurityContext(secContext);
-			}
+			verify(fileService).uploadBescheidFile(bescheid);
 		}
 
+		@Test
+		void shouldReturnBescheid() {
+			var bescheid = BescheidTestFactory.create();
+			when(fileService.uploadBescheidFile(any())).thenReturn(bescheid);
+
+			var result = listener.doCreateBescheidBiz(command);
 
+			assertThat(result).isSameAs(bescheid);
+		}
+	}
+
+	@Nested
+	class TestRunWithSecurityContext {
+
+		private Command command = CommandTestFactory.createBuilder().build();
+
+		@Mock
+		private Consumer<Command> commandExecutor;
+		@Mock
+		private SecurityContext secContext;
+		@Captor
+		private ArgumentCaptor<CommandFailedEvent> commandFailedEventCaptor;
+
+		@BeforeEach
+		void init() {
+			when(userService.startSecurityContext(any())).thenReturn(secContext);
+		}
+
+		@Test
+		void shouldStartSecurityContext() {
+			listener.runWithSecurityContext(command, commandExecutor);
+
+			verify(userService).startSecurityContext(command);
+		}
+
+		@Test
+		void shouldExecuteCommand() {
+			listener.runWithSecurityContext(command, commandExecutor);
+
+			verify(commandExecutor).accept(command);
+		}
+
+		@Test
+		void shouldResetSecurityContext() {
+			listener.runWithSecurityContext(command, commandExecutor);
+
+			verify(userService).resetSecurityContext(secContext);
+		}
+
+		@Test
+		void shouldResetSecurityContextAfterException() {
+			doThrow(new RuntimeException("ups")).when(commandExecutor).accept(any());
+
+			listener.runWithSecurityContext(command, commandExecutor);
+
+			verify(userService).resetSecurityContext(secContext);
+		}
+
+		@Test
+		void shouldPublishCommandFailedEvent() {
+			doThrow(new RuntimeException("ups")).when(commandExecutor).accept(any());
+
+			listener.runWithSecurityContext(command, commandExecutor);
+
+			verify(eventPublisher).publishEvent(commandFailedEventCaptor.capture());
+			assertThat(commandFailedEventCaptor.getValue().getSource()).isEqualTo(command.getId());
+			assertThat(commandFailedEventCaptor.getValue().getErrorMessage()).isNotEmpty();
+		}
 	}
 }
diff --git a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/BescheidTestFactory.java b/bescheid-manager/src/test/java/de/ozgcloud/bescheid/BescheidTestFactory.java
index e4ccee014906c47e7bf442205002675ca054cad5..f240745e31fd6bc411591a72b8ca607f13e45551 100644
--- a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/BescheidTestFactory.java
+++ b/bescheid-manager/src/test/java/de/ozgcloud/bescheid/BescheidTestFactory.java
@@ -19,6 +19,7 @@ public class BescheidTestFactory {
 
 	public static final byte[] TEST_BESCHEID = "testbescheid".getBytes();
 	public static final File BESCHEID_FILE = TempFileUtils.writeTmpFile(TEST_BESCHEID);
+	public static final String BESCHEID_FILE_ID = "bescheid-file-id";
 
 	public static final String CONTENT_TYPE = MediaType.APPLICATION_PDF_VALUE;
 	public static final String NACHRICHT_TEXT = LoremIpsum.getInstance().getWords(5);
diff --git a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/smartdocuments/SmartDocumentsBescheidRemoteServiceITCase.java b/bescheid-manager/src/test/java/de/ozgcloud/bescheid/smartdocuments/SmartDocumentsBescheidRemoteServiceITCase.java
index 6bbf4083b967a58576187f18ff047699cc6b8f24..3126ecfe5b5f98c41749c406cd426253a65b053e 100644
--- a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/smartdocuments/SmartDocumentsBescheidRemoteServiceITCase.java
+++ b/bescheid-manager/src/test/java/de/ozgcloud/bescheid/smartdocuments/SmartDocumentsBescheidRemoteServiceITCase.java
@@ -1,21 +1,33 @@
 package de.ozgcloud.bescheid.smartdocuments;
 
+import static org.assertj.core.api.Assertions.*;
+
 import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
 import org.springframework.test.context.ActiveProfiles;
 
-import de.ozgcloud.common.test.ITCase;
+import de.ozgcloud.apilib.common.command.OzgCloudCommandService;
+import de.ozgcloud.apilib.common.command.grpc.CommandMapper;
 import de.ozgcloud.bescheid.BescheidRequestTestFactory;
+import de.ozgcloud.bescheid.BescheidTestApplication;
 import de.ozgcloud.bescheid.vorgang.VorgangTestFactory;
+import de.ozgcloud.common.test.ITCase;
 
 @Disabled
+@SpringBootTest(classes = BescheidTestApplication.class)
 @ITCase
 @ActiveProfiles({ "itcase", "local" })
 class SmartDocumentsBescheidRemoteServiceITCase {
 
 	@Autowired
 	private SmartDocumentsBescheidRemoteService remoteService;
+	@MockBean
+	private OzgCloudCommandService ozgCloudCommandService;
+	@MockBean
+	private CommandMapper commandMapper;
 
 	@Test
 	void createBescheid() {
@@ -23,6 +35,7 @@ class SmartDocumentsBescheidRemoteServiceITCase {
 
 		System.out.println(bescheid.getBescheidFileName());
 		System.out.println(bescheid.getBescheidFile().getAbsolutePath());
+		assertThat(bescheid.getBescheidFileName()).isNotEmpty();
 	}
 
 }
diff --git a/bescheid-manager/src/test/java/de/ozgcloud/document/DocumentServiceTest.java b/bescheid-manager/src/test/java/de/ozgcloud/document/DocumentServiceTest.java
index 736947b3a9ede6e9fbd04893ae3f6079887b4fcd..a9b9669ca351e63c42e259ec75d193b24c98355a 100644
--- a/bescheid-manager/src/test/java/de/ozgcloud/document/DocumentServiceTest.java
+++ b/bescheid-manager/src/test/java/de/ozgcloud/document/DocumentServiceTest.java
@@ -28,7 +28,9 @@ import static org.junit.jupiter.api.Assertions.*;
 import static org.mockito.Mockito.*;
 
 import java.util.Map;
+import java.util.Optional;
 
+import org.apache.commons.lang3.StringUtils;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
@@ -42,13 +44,16 @@ import de.ozgcloud.apilib.common.command.OzgCloudCommandService;
 import de.ozgcloud.apilib.common.command.grpc.CommandMapper;
 import de.ozgcloud.apilib.common.datatypes.GenericId;
 import de.ozgcloud.apilib.vorgang.OzgCloudVorgangId;
+import de.ozgcloud.bescheid.Bescheid;
 import de.ozgcloud.bescheid.BescheidCallContextAttachingInterceptor;
+import de.ozgcloud.bescheid.BescheidTestFactory;
 import de.ozgcloud.bescheid.attacheditem.AttachedItemService;
 import de.ozgcloud.bescheid.attacheditem.AttachedItemTestFactory;
 import de.ozgcloud.bescheid.attacheditem.BescheidItem;
 import de.ozgcloud.bescheid.attacheditem.BescheidItemTestFactory;
 import de.ozgcloud.command.Command;
 import de.ozgcloud.command.CommandTestFactory;
+import de.ozgcloud.common.binaryfile.FileId;
 import de.ozgcloud.common.errorhandling.TechnicalException;
 
 class DocumentServiceTest {
@@ -69,9 +74,7 @@ class DocumentServiceTest {
 	@Mock
 	private DocumentMapper documentMapper;
 
-	private Command command = CommandTestFactory.createBuilder()
-			.relationId(RELATION_ID)
-			.bodyObject(Map.of(DocumentService.FIELD_DOCUMENT_FILE, FILE_ID)).build();
+	private Command command = CommandTestFactory.createBuilder().relationId(RELATION_ID).build();
 
 	@Nested
 	class TestCreateBescheidDocument {
@@ -81,42 +84,112 @@ class DocumentServiceTest {
 		@Mock
 		private OzgCloudCommand ozgCommand;
 
-		@BeforeEach
-		void init() {
-			when(commandService.createAndWaitUntilDone(any())).thenReturn(ozgCommand);
-			doNothing().when(service).validateBescheidItem(any());
-		}
+		@Nested
+		class TestWithCommand {
 
-		@Test
-		void shouldCallValidateBescheidItem() {
-			service.createBescheidDocument(command);
+			private Command command = CommandTestFactory.createBuilder().relationId(RELATION_ID)
+					.bodyObject(Map.of(DocumentService.FIELD_DOCUMENT_FILE, FILE_ID)).build();
 
-			verify(service).validateBescheidItem(RELATION_ID);
-		}
+			@BeforeEach
+			void init() {
+				doReturn(CREATED_ATTACHED_ITEM_ID).when(service).createBescheidDocument(any(), anyMap());
+			}
 
-		@Test
-		void shouldCallBuildOzgCommand() {
-			service.createBescheidDocument(command);
+			@Test
+			void shouldCallBuildItemMap() {
+				service.createBescheidDocument(command);
+
+				verify(service).buildItemMap(command);
+			}
+
+			@Test
+			void shouldCallCreateBescheidDocument() {
+				var itemMap = Map.of("key", (Object) "value");
+				doReturn(itemMap).when(service).buildItemMap(any(Command.class));
+
+				service.createBescheidDocument(command);
+
+				verify(service).createBescheidDocument(command, itemMap);
+			}
 
-			verify(service).buildCreateDocumentOzgCommand(command);
+			@Test
+			void shouldReturnDocumentId() {
+				String result = service.createBescheidDocument(command);
+
+				assertThat(result).isEqualTo(CREATED_ATTACHED_ITEM_ID);
+			}
 		}
 
-		@Test
-		void shouldCallCommandService() {
-			doReturn(ozgCommand).when(service).buildCreateDocumentOzgCommand(any());
+		@Nested
+		class TestWithBescheid {
+
+			private Bescheid bescheid = BescheidTestFactory.create().withBescheidFileId(FileId.from(BescheidTestFactory.BESCHEID_FILE_ID));
+
+			@BeforeEach
+			void init() {
+				doReturn(CREATED_ATTACHED_ITEM_ID).when(service).createBescheidDocument(any(), anyMap());
+			}
+
+			@Test
+			void shouldCallBuildItemMap() {
+				service.createBescheidDocument(command, bescheid);
+
+				verify(service).buildItemMap(bescheid);
+			}
+
+			@Test
+			void shouldCallCreateBescheidDocument() {
+				var itemMap = Map.of("key", (Object) "value");
+				doReturn(itemMap).when(service).buildItemMap(any(Bescheid.class));
 
-			service.createBescheidDocument(command);
+				service.createBescheidDocument(command, bescheid);
 
-			verify(commandService).createAndWaitUntilDone(ozgCommand);
+				verify(service).createBescheidDocument(command, itemMap);
+			}
+
+			@Test
+			void shouldReturnDocumentId() {
+				String result = service.createBescheidDocument(command, bescheid);
+
+				assertThat(result).isEqualTo(CREATED_ATTACHED_ITEM_ID);
+			}
 		}
 
-		@Test
-		void shouldReturnDocumentId() {
-			when(ozgCommand.getCreatedResource()).thenReturn(CREATED_ATTACHED_ITEM_ID);
+		@Nested
+		class TestWithCommandAndItemMap {
+
+			private static final Map<String, Object> BODY_OBJECT = Map.of(DocumentService.FIELD_DOCUMENT_FILE, FILE_ID);
+
+			@BeforeEach
+			void init() {
+				when(commandService.createAndWaitUntilDone(any())).thenReturn(ozgCommand);
+				doNothing().when(service).validateBescheidItem(any());
+			}
+
+			@Test
+			void shouldCallValidateBescheidItem() {
+				service.createBescheidDocument(command, BODY_OBJECT);
+
+				verify(service).validateBescheidItem(RELATION_ID);
+			}
+
+			@Test
+			void shouldCallCommandService() {
+				doReturn(ozgCommand).when(service).buildCreateDocumentOzgCommand(any(), anyMap());
 
-			String documentId = service.createBescheidDocument(command);
+				service.createBescheidDocument(command, BODY_OBJECT);
 
-			assertThat(documentId).isEqualTo(CREATED_ATTACHED_ITEM_ID);
+				verify(commandService).createAndWaitUntilDone(ozgCommand);
+			}
+
+			@Test
+			void shouldReturnDocumentId() {
+				when(ozgCommand.getCreatedResource()).thenReturn(CREATED_ATTACHED_ITEM_ID);
+
+				String documentId = service.createBescheidDocument(command, BODY_OBJECT);
+
+				assertThat(documentId).isEqualTo(CREATED_ATTACHED_ITEM_ID);
+			}
 		}
 	}
 
@@ -153,6 +226,7 @@ class DocumentServiceTest {
 
 			assertDoesNotThrow(this::validateBescheidItem);
 		}
+
 		void validateBescheidItem() {
 			service.validateBescheidItem(BescheidItemTestFactory.ID);
 		}
@@ -161,16 +235,18 @@ class DocumentServiceTest {
 	@Nested
 	class TestBuildCreateDocumentOzgCommand {
 
+		private static final Map<String, Object> BODY_OBJECT = Map.of(DocumentService.FIELD_DOCUMENT_FILE, FILE_ID);
+
 		@Test
 		void shouldSetOrder() {
-			var ozgCommand = service.buildCreateDocumentOzgCommand(command);
+			var ozgCommand = service.buildCreateDocumentOzgCommand(command, BODY_OBJECT);
 
 			assertThat(ozgCommand.getOrder()).isEqualTo(DocumentService.CREATE_ATTACHED_ITEM_ORDER);
 		}
 
 		@Test
 		void shouldCallVorgangIdMapper() {
-			service.buildCreateDocumentOzgCommand(command);
+			service.buildCreateDocumentOzgCommand(command, BODY_OBJECT);
 
 			verify(commandMapper).toOzgCloudVorgangId(CommandTestFactory.VORGANG_ID);
 		}
@@ -180,14 +256,14 @@ class DocumentServiceTest {
 			var expectedVorgangId = OzgCloudVorgangId.from("vorgang-id");
 			when(commandMapper.toOzgCloudVorgangId(any())).thenReturn(expectedVorgangId);
 
-			var ozgCommand = service.buildCreateDocumentOzgCommand(command);
+			var ozgCommand = buildCreateDocumentOzgCommand();
 
 			assertThat(ozgCommand.getVorgangId()).isEqualTo(expectedVorgangId);
 		}
 
 		@Test
 		void shouldCallRelationIdMapper() {
-			service.buildCreateDocumentOzgCommand(command);
+			buildCreateDocumentOzgCommand();
 
 			verify(commandMapper).mapRelationId(CommandTestFactory.VORGANG_ID);
 		}
@@ -197,32 +273,28 @@ class DocumentServiceTest {
 			var expectedRelationId = GenericId.from("relation-id");
 			when(commandMapper.mapRelationId(any())).thenReturn(expectedRelationId);
 
-			var ozgCommand = service.buildCreateDocumentOzgCommand(command);
+			var ozgCommand = buildCreateDocumentOzgCommand();
 
 			assertThat(ozgCommand.getRelationId()).isEqualTo(expectedRelationId);
 		}
 
 		@Test
-		void shouldCallBuildAttachedItem() {
-			service.buildCreateDocumentOzgCommand(command);
+		void shouldSetBodyObject() {
+			var ozgCommand = buildCreateDocumentOzgCommand();
 
-			verify(service).buildAttachedItem(command);
+			assertThat(ozgCommand.getBodyObject()).isEqualTo(BODY_OBJECT);
 		}
 
-		@Test
-		void shouldSetAttachedItem() {
-			var expectedAttachedItem = Map.of("key", (Object) "value");
-			doReturn(expectedAttachedItem).when(service).buildAttachedItem(any());
-
-			var ozgCommand = service.buildCreateDocumentOzgCommand(command);
-
-			assertThat(ozgCommand.getBodyObject()).isEqualTo(expectedAttachedItem);
+		private OzgCloudCommand buildCreateDocumentOzgCommand() {
+			return service.buildCreateDocumentOzgCommand(command, BODY_OBJECT);
 		}
 	}
 
 	@Nested
 	class TestBuildAttachedItem {
 
+		private static final Map<String, Object> ITEM_MAP = Map.of("key", (Object) "value");
+
 		@Test
 		void shouldSetVorgangId() {
 			var attachedItem = buildAttachedItem();
@@ -246,53 +318,99 @@ class DocumentServiceTest {
 		}
 
 		@Test
-		void shouldCallBuildDocumentMap() {
-			buildAttachedItem();
-
-			verify(service).buildItemMap(command);
-		}
-
-		@Test
-		void shouldSetDocument() {
-			var expectedDocument = Map.of("key", (Object) "value");
-			doReturn(expectedDocument).when(service).buildItemMap(any());
-
+		void shouldSetItem() {
 			var attachedItem = buildAttachedItem();
 
-			assertThat(attachedItem).containsEntry(BescheidItem.PROPERTY_ITEM, expectedDocument);
+			assertThat(attachedItem).containsEntry(BescheidItem.PROPERTY_ITEM, ITEM_MAP);
 		}
 
 		private Map<String, Object> buildAttachedItem() {
-			return service.buildAttachedItem(command);
+			return service.buildAttachedItem(command, ITEM_MAP);
 		}
 	}
 
 	@Nested
 	class TestBuildItemMap {
 
-		@Test
-		void shouldDetDocumentType() {
-			var itemMap = buildItemMap();
+		@Nested
+		class TestBuildFromCommand {
 
-			assertThat(itemMap).containsEntry(DocumentService.FIELD_DOCUMENT_TYPE, DocumentService.DOCUMENT_TYPE);
-		}
+			private Command command = CommandTestFactory.createBuilder().relationId(RELATION_ID)
+					.bodyObject(Map.of(DocumentService.FIELD_DOCUMENT_FILE, FILE_ID)).build();
 
-		@Test
-		void shouldSetDocumentFile() {
-			var itemMap = buildItemMap();
+			@Test
+			void shouldDetDocumentType() {
+				var itemMap = buildItemMap();
 
-			assertThat(itemMap).containsEntry(DocumentService.FIELD_DOCUMENT_FILE, FILE_ID);
-		}
+				assertThat(itemMap).containsEntry(DocumentService.FIELD_DOCUMENT_TYPE, DocumentService.DOCUMENT_TYPE);
+			}
 
-		@Test
-		void shouldThrowExceptionIfDocumentFileIsMissing() {
-			command = CommandTestFactory.createBuilder().bodyObject(Map.of()).build();
+			@Test
+			void shouldSetDocumentFile() {
+				var itemMap = buildItemMap();
+
+				assertThat(itemMap).containsEntry(DocumentService.FIELD_DOCUMENT_FILE, FILE_ID);
+			}
+
+			@Test
+			void shouldThrowExceptionIfDocumentFileIsMissing() {
+				command = CommandTestFactory.createBuilder().bodyObject(Map.of()).build();
+
+				assertThrows(TechnicalException.class, () -> service.buildItemMap(command));
+			}
 
-			assertThrows(TechnicalException.class, () -> service.buildItemMap(command));
+			private Map<String, Object> buildItemMap() {
+				return service.buildItemMap(command);
+			}
 		}
 
-		private Map<String, Object> buildItemMap() {
-			return service.buildItemMap(command);
+		@Nested
+		class TestBuildFromBescheid {
+
+			private Bescheid bescheid = BescheidTestFactory.create().withBescheidFileId(FileId.from(BescheidTestFactory.BESCHEID_FILE_ID));
+
+			@Test
+			void shouldDetDocumentType() {
+				var itemMap = buildItemMap();
+
+				assertThat(itemMap).containsEntry(DocumentService.FIELD_DOCUMENT_TYPE, DocumentService.DOCUMENT_TYPE);
+			}
+
+			@Test
+			void shouldSetDocumentFile() {
+				var itemMap = buildItemMap();
+
+				assertThat(itemMap).containsEntry(DocumentService.FIELD_DOCUMENT_FILE, BescheidTestFactory.BESCHEID_FILE_ID);
+			}
+
+			@Test
+			void shouldSetNachrichtText() {
+				var itemMap = buildItemMap();
+
+				assertThat(itemMap).containsEntry(DocumentService.FIELD_NACHRICHT_TEXT, BescheidTestFactory.NACHRICHT_TEXT);
+			}
+
+			@Test
+			void shouldSetEmptyNachrichtText() {
+				bescheid = BescheidTestFactory.createBuilder().bescheidFileId(FileId.from(BescheidTestFactory.BESCHEID_FILE_ID))
+						.nachrichtText(Optional.empty()).build();
+
+				var itemMap = buildItemMap();
+
+				assertThat(itemMap).containsEntry(DocumentService.FIELD_NACHRICHT_TEXT, StringUtils.EMPTY);
+			}
+
+			@Test
+			void shouldThrowExceptionIfFileIdMissing() {
+				bescheid = BescheidTestFactory.create();
+
+				assertThrows(TechnicalException.class, () -> service.buildItemMap(bescheid));
+
+			}
+
+			private Map<String, Object> buildItemMap() {
+				return service.buildItemMap(bescheid);
+			}
 		}
 	}
 
diff --git a/vorgang-manager-server/src/main/resources/application-local.yml b/vorgang-manager-server/src/main/resources/application-local.yml
index 346ab37983c1d9a1e395e8ba52c0d31823caca68..f575ac6f04eaec08c1ea13a5f28d849eebe0576c 100644
--- a/vorgang-manager-server/src/main/resources/application-local.yml
+++ b/vorgang-manager-server/src/main/resources/application-local.yml
@@ -53,6 +53,9 @@ ozgcloud:
   elasticsearch:
     initEnabled: true
     index: test-index
+  feature:
+    bescheid:
+      enable-dummy-document-processor: true
 
 
 mongock:
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/bescheid/BescheidDocumentITCase.java b/vorgang-manager-server/src/test/java/de/ozgcloud/bescheid/BescheidDocumentITCase.java
new file mode 100644
index 0000000000000000000000000000000000000000..54cfc7b0679835e54404911bcb0c8945533ed8d7
--- /dev/null
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/bescheid/BescheidDocumentITCase.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den
+ * Ministerpräsidenten des Landes Schleswig-Holstein
+ * Staatskanzlei
+ * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+ *
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+package de.ozgcloud.bescheid;
+
+import static de.ozgcloud.bescheid.BescheidEventListener.*;
+import static org.assertj.core.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import org.awaitility.Awaitility;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.boot.test.mock.mockito.SpyBean;
+import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.test.annotation.DirtiesContext;
+
+import de.ozgcloud.bescheid.common.callcontext.CurrentUserService;
+import de.ozgcloud.command.Command;
+import de.ozgcloud.command.CommandCreatedEvent;
+import de.ozgcloud.command.CommandFailedEvent;
+import de.ozgcloud.common.test.ITCase;
+import de.ozgcloud.vorgang.VorgangManagerServerApplication;
+import de.ozgcloud.vorgang.command.CommandTestFactory;
+
+class BescheidDocumentITCase {
+
+	@Nested
+	@SpringBootTest(classes = VorgangManagerServerApplication.class)
+	@ITCase
+	@DirtiesContext
+	class TestDocumentProzessorNotConfigured {
+
+		@Autowired
+		private ApplicationEventPublisher eventPublisher;
+		@SpyBean
+		private BescheidEventListener eventListener;
+		@SpyBean
+		private TestEventListener testEventListener;
+
+		@MockBean
+		private CurrentUserService currentUserService;
+
+		@Captor
+		private ArgumentCaptor<CommandFailedEvent> commandFailedEventCaptor;
+
+		@Test
+		void shouldFailWhenNoDocumentProcessor() {
+			var command = buildCreateDocumentCommand();
+
+			eventPublisher.publishEvent(new CommandCreatedEvent(command));
+
+			Awaitility.await().atMost(60, TimeUnit.SECONDS).untilAsserted(() -> {
+				verify(testEventListener).onCommandFailed(commandFailedEventCaptor.capture());
+				assertThat(commandFailedEventCaptor.getValue().getSource()).isEqualTo(command.getId());
+				assertThat(commandFailedEventCaptor.getValue().getErrorMessage()).isNotEmpty();
+			});
+
+		}
+
+		private Command buildCreateDocumentCommand() {
+			return CommandTestFactory.createBuilder()
+					.vorgangId("vorgang-id")
+					.relationId("bescheidItem-id")
+					.order(BescheidEventListener.CREATE_BESCHEID_DOCUMENT_ORDER)
+					.bodyObject(Map.of(BESCHEID_VOM_BODYKEY, "2024-01-01",
+							GENEHMIGT_BODYKEY, true))
+					.build();
+		}
+
+	}
+}
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/bescheid/BescheidEventListenerITCase.java b/vorgang-manager-server/src/test/java/de/ozgcloud/bescheid/BescheidEventListenerITCase.java
new file mode 100644
index 0000000000000000000000000000000000000000..7ad895b21ec134170700f9a29ddac0df905f05cd
--- /dev/null
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/bescheid/BescheidEventListenerITCase.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den
+ * Ministerpräsidenten des Landes Schleswig-Holstein
+ * Staatskanzlei
+ * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+ *
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+package de.ozgcloud.bescheid;
+
+import static de.ozgcloud.bescheid.BescheidEventListener.*;
+import static org.assertj.core.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import org.awaitility.Awaitility;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.boot.test.mock.mockito.SpyBean;
+import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.data.mongodb.core.MongoOperations;
+import org.springframework.data.mongodb.core.query.Criteria;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.data.mongodb.gridfs.GridFsTemplate;
+import org.springframework.test.annotation.DirtiesContext;
+
+import com.mongodb.client.gridfs.model.GridFSFile;
+
+import de.ozgcloud.bescheid.attacheditem.AttachedItemService;
+import de.ozgcloud.bescheid.attacheditem.BescheidItem;
+import de.ozgcloud.bescheid.common.callcontext.CallContextUser;
+import de.ozgcloud.bescheid.common.callcontext.CurrentUserService;
+import de.ozgcloud.bescheid.common.callcontext.UserProfile;
+import de.ozgcloud.command.CommandCreatedEvent;
+import de.ozgcloud.common.test.DataITCase;
+import de.ozgcloud.document.BescheidDocumentCreatedEvent;
+import de.ozgcloud.document.Document;
+import de.ozgcloud.vorgang.VorgangManagerServerApplication;
+import de.ozgcloud.vorgang.attached_item.VorgangAttachedItem;
+import de.ozgcloud.vorgang.attached_item.VorgangAttachedItemTestFactory;
+import de.ozgcloud.vorgang.command.CommandTestFactory;
+import de.ozgcloud.vorgang.vorgang.Vorgang;
+import de.ozgcloud.vorgang.vorgang.VorgangTestFactory;
+
+@SpringBootTest(classes = VorgangManagerServerApplication.class, properties = {
+		"grpc.server.inProcessName=test",
+		"grpc.server.port=-1",
+		"grpc.client.ozgcloud-command-manager.address=in-process:test",
+		"grpc.client.vorgang-manager.address=in-process:test",
+		"ozgcloud.feature.bescheid.enable-dummy-document-processor=true",
+})
+@DataITCase
+@DirtiesContext
+class BescheidEventListenerITCase {
+
+	@Autowired
+	private ApplicationEventPublisher eventPublisher;
+	@SpyBean
+	private TestEventListener bescheidDocumentCreatedEventListener;
+
+	@Autowired
+	private MongoOperations mongoOperations;
+	@Autowired
+	private GridFsTemplate gridFsTemplate;
+
+	@MockBean
+	private CurrentUserService currentUserService;
+	@Mock
+	private CallContextUser callContextUser;
+	@Mock
+	private UserProfile userProfile;
+
+	@Captor
+	private ArgumentCaptor<BescheidDocumentCreatedEvent> bescheidDocumentCreatedEventCaptor;
+
+	@BeforeEach
+	void init() {
+		mongoOperations.dropCollection(VorgangAttachedItem.COLLECTION_NAME);
+		mongoOperations.dropCollection(Vorgang.COLLECTION_NAME);
+		when(currentUserService.getUser()).thenReturn(callContextUser);
+		when(currentUserService.getUserProfile()).thenReturn(userProfile);
+	}
+
+	@Test
+	void shouldCreateBescheidDocument() {
+		var vorgangId = mongoOperations.save(VorgangTestFactory.createBuilder().id(null).build()).getId();
+		var bescheidItemId = mongoOperations.save(createBescheidAttachedItem(vorgangId)).getId();
+
+		eventPublisher.publishEvent(buildCommandCreatedEvent(vorgangId, bescheidItemId));
+
+		Awaitility.await().atMost(60, TimeUnit.SECONDS).untilAsserted(() -> {
+			verify(bescheidDocumentCreatedEventListener).onBescheidDocumentCreated(bescheidDocumentCreatedEventCaptor.capture());
+			assertThat(getBescheidDocument()).isNotNull();
+		});
+	}
+
+	@Test
+	void shouldCreateDocumentFile() {
+		var vorgangId = mongoOperations.save(VorgangTestFactory.createBuilder().id(null).build()).getId();
+		var bescheidItemId = mongoOperations.save(createBescheidAttachedItem(vorgangId)).getId();
+
+		eventPublisher.publishEvent(buildCommandCreatedEvent(vorgangId, bescheidItemId));
+
+		Awaitility.await().atMost(60, TimeUnit.SECONDS).untilAsserted(() -> {
+			verify(bescheidDocumentCreatedEventListener).onBescheidDocumentCreated(bescheidDocumentCreatedEventCaptor.capture());
+			assertThat(getBescheidDocumentFile()).isNotNull();
+		});
+	}
+
+	private VorgangAttachedItem createBescheidAttachedItem(String vorgangId) {
+		return VorgangAttachedItemTestFactory.createBuilder()
+				.id(null)
+				.version(0L)
+				.vorgangId(vorgangId)
+				.itemName(AttachedItemService.BESCHEID_ITEM_NAME)
+				.item(Map.of(BescheidItem.FIELD_STATUS, BescheidItem.Status.DRAFT.name()))
+				.build();
+	}
+
+	private CommandCreatedEvent buildCommandCreatedEvent(String vorgangId, String bescheidItemId) {
+		var command = CommandTestFactory.createBuilder()
+				.vorgangId(vorgangId)
+				.relationId(bescheidItemId)
+				.order(BescheidEventListener.CREATE_BESCHEID_DOCUMENT_ORDER)
+				.bodyObject(Map.of(BESCHEID_VOM_BODYKEY, "2024-01-01",
+						GENEHMIGT_BODYKEY, true))
+				.build();
+		return new CommandCreatedEvent(command);
+	}
+
+	private VorgangAttachedItem getBescheidDocument() {
+		var documentId = bescheidDocumentCreatedEventCaptor.getValue().getCreatedResource();
+		return mongoOperations.findById(documentId, VorgangAttachedItem.class);
+	}
+
+	private GridFSFile getBescheidDocumentFile() {
+		var fileId = getBescheidDocument().getItem().get(Document.FIELD_DOCUMENT_FILE).toString();
+		return gridFsTemplate.findOne(Query.query(Criteria.where("_id").is(fileId)));
+	}
+}
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/bescheid/TestEventListener.java b/vorgang-manager-server/src/test/java/de/ozgcloud/bescheid/TestEventListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..d83594222eb584cd76212de870f9d3ee0ba753a0
--- /dev/null
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/bescheid/TestEventListener.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den
+ * Ministerpräsidenten des Landes Schleswig-Holstein
+ * Staatskanzlei
+ * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+ *
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+package de.ozgcloud.bescheid;
+
+import org.springframework.context.event.EventListener;
+
+import de.ozgcloud.command.CommandFailedEvent;
+import de.ozgcloud.document.BescheidDocumentCreatedEvent;
+
+class TestEventListener {
+
+	@EventListener
+	public void onBescheidDocumentCreated(BescheidDocumentCreatedEvent event) {
+	}
+
+	@EventListener
+	public void onCommandFailed(CommandFailedEvent event) {
+	}
+}
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/nachrichten/postfach/PostfachMailITCase.java b/vorgang-manager-server/src/test/java/de/ozgcloud/nachrichten/postfach/PostfachMailITCase.java
index 055a48e234bab978031fcbfa3d91176df3c20640..8db9ce23a49f33ee2b2a058eb33906fd56882813 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/nachrichten/postfach/PostfachMailITCase.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/nachrichten/postfach/PostfachMailITCase.java
@@ -150,7 +150,7 @@ class PostfachMailITCase {
 				assertThat(mails.get(0).getCreatedAt()).isNotNull();
 				assertThat(mails.get(0).getDirection()).isEqualTo(GrpcDirection.OUT);
 				assertThat(mails.get(0).getSentAt()).isNotNull();
-				assertThat(ZonedDateTime.parse(mails.get(0).getSentAt())).isCloseTo(ZonedDateTime.now(), within(2, ChronoUnit.SECONDS));
+				assertThat(ZonedDateTime.parse(mails.get(0).getSentAt())).isCloseTo(ZonedDateTime.now(), within(61, ChronoUnit.SECONDS));
 				assertThat(mails.get(0).getSentSuccessful()).isTrue();
 			}
 		}
@@ -175,7 +175,7 @@ class PostfachMailITCase {
 				await().atMost(60, TimeUnit.SECONDS).untilAsserted(() -> {
 					assertThat(callGrpcListEndpoint()).hasSize(1).first().satisfies(mail -> {
 						assertThat(mail.getSentAt()).isNotNull();
-						assertThat(ZonedDateTime.parse(mail.getSentAt())).isCloseTo(ZonedDateTime.now(), within(2, ChronoUnit.SECONDS));
+						assertThat(ZonedDateTime.parse(mail.getSentAt())).isCloseTo(ZonedDateTime.now(), within(61, ChronoUnit.SECONDS));
 						assertThat(mail.getSentSuccessful()).isFalse();
 					});
 				});