diff --git a/Jenkinsfile b/Jenkinsfile
index 81a74c97531aa991385a034402a13fbbb38786b6..911a5f66401da2ca5bcc05f910a19b8a3cb2b5ee 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -44,6 +44,27 @@ pipeline {
                 }
             }
         }
+
+        stage('Set Version') {
+          when {
+            not {
+                anyOf {
+                    branch 'master'
+                    branch 'release'
+                }
+            }
+          }
+          steps {
+                script {
+                    FAILED_STAGE=env.STAGE_NAME
+                    JAR_TAG = getPomVersion('pom.xml').replace("SNAPSHOT", "${env.BRANCH_NAME}-SNAPSHOT")
+                }
+                configFileProvider([configFile(fileId: 'maven-settings', variable: 'MAVEN_SETTINGS')]) {
+                    sh "mvn -s $MAVEN_SETTINGS versions:set -DnewVersion=${JAR_TAG} -DprocessAllModules=true"
+                    
+                }
+          }
+        } 
         
         stage('Build VorgangManager') {
           steps {
@@ -58,18 +79,13 @@ pipeline {
         }
         
         stage('Deploy to Nexus'){
-            when {
-                anyOf {
-                    branch 'master'
-                    branch 'release'
-                }
-            }
             steps {
                 script {
                     FAILED_STAGE = env.STAGE_NAME
                 }
                 configFileProvider([configFile(fileId: 'maven-settings', variable: 'MAVEN_SETTINGS')]) {
                     sh 'mvn --no-transfer-progress -s $MAVEN_SETTINGS -DskipTests deploy -Dmaven.wagon.http.retryHandler.count=3'
+                    sh "mvn -s $MAVEN_SETTINGS versions:revert"
                 }
             }
         }
@@ -344,7 +360,7 @@ Void sendFailureMessage() {
                     "formatted_body":"VorgangManager: Build Failed. Stage: ${FAILED_STAGE} Build-ID: <a href='${BLUE_OCEAN_URL}'>${env.BUILD_NUMBER}</a>"}"""
        
     if (env.BRANCH_NAME == 'master') {
-        room = "!iQPAvQIiRwRpNOszjw:matrix.ozg-sh.de"
+        room = "!GjqhmouBtnDbwUkAjx:matrix.ozg-sh.de"
     }
     else if (env.BRANCH_NAME == 'release') {
         room = "!oWZpUGTFsxkJIYNfYg:matrix.ozg-sh.de"
diff --git a/bescheid-manager/pom.xml b/bescheid-manager/pom.xml
index 7a0bae459ad6ca5dea200d31d22a56b8ebcfc789..363df9597288ae0a92362a3dd5f3eca94eb4643d 100644
--- a/bescheid-manager/pom.xml
+++ b/bescheid-manager/pom.xml
@@ -5,19 +5,19 @@
 	<parent>
 		<groupId>de.ozgcloud.common</groupId>
 		<artifactId>ozgcloud-common-parent</artifactId>
-		<version>4.2.0</version>
+		<version>4.3.1</version>
 		<relativePath />
 	</parent>
 
 	<groupId>de.ozgcloud.bescheid</groupId>
 	<artifactId>bescheid-manager</artifactId>
 	<name>OZG-Cloud Bescheid Manager</name>
-	<version>1.14.0-SNAPSHOT</version>
+	<version>1.15.0</version>
 
 	<properties>
 		<vorgang-manager.version>2.9.0</vorgang-manager.version>
 		<nachrichten-manager.version>2.9.0</nachrichten-manager.version>
-		<api-lib.version>0.10.0</api-lib.version>
+		<api-lib.version>0.11.0</api-lib.version>
 	</properties>
 
 	<dependencies>
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 49fbce9beef117e017788ae682323792bdb7478e..ada68e5d7b3dcc83dd1aeacc8998ba32b8702820 100644
--- a/bescheid-manager/src/main/java/de/ozgcloud/bescheid/BescheidEventListener.java
+++ b/bescheid-manager/src/main/java/de/ozgcloud/bescheid/BescheidEventListener.java
@@ -23,6 +23,8 @@
  */
 package de.ozgcloud.bescheid;
 
+import static java.util.Objects.*;
+
 import java.time.LocalDate;
 import java.util.Arrays;
 import java.util.Optional;
@@ -42,10 +44,10 @@ import de.ozgcloud.bescheid.attacheditem.AttachedItemService;
 import de.ozgcloud.bescheid.binaryfile.BinaryFileService;
 import de.ozgcloud.bescheid.common.callcontext.CurrentUserService;
 import de.ozgcloud.bescheid.common.user.UserProfileService;
-import de.ozgcloud.bescheid.nachricht.NachrichtService;
 import de.ozgcloud.bescheid.vorgang.VorgangId;
 import de.ozgcloud.command.Command;
 import de.ozgcloud.command.CommandCreatedEvent;
+import de.ozgcloud.command.CommandExecutedEvent;
 import de.ozgcloud.command.CommandFailedEvent;
 import de.ozgcloud.common.errorhandling.TechnicalException;
 import de.ozgcloud.document.BescheidDocumentCreatedEvent;
@@ -78,8 +80,9 @@ class BescheidEventListener {
 	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())}";
 
-	public static final Predicate<Command> IS_SEND_BESCHEID_COMMAND = command -> SEND_BESCHEID_ORDER.equals(command.getOrder());
+	public static final Predicate<Command> IS_SEND_BESCHEID_COMMAND = command -> nonNull(command) && SEND_BESCHEID_ORDER.equals(command.getOrder());
 	private static final String IS_SEND_BESCHEID = "{T(de.ozgcloud.bescheid.BescheidEventListener).IS_SEND_BESCHEID_COMMAND.test(event.getSource())}";
+	private static final String IS_SEND_BESCHEID_ORDER = "{T(de.ozgcloud.bescheid.BescheidEventListener).IS_SEND_BESCHEID_COMMAND.test(event.getCommand())}";
 
 	static final String VORGANG_ID_BODY_KEY = "vorgangId";
 	static final String BESCHEID_VOM_BODY_KEY = "bescheidVom";
@@ -90,14 +93,12 @@ class BescheidEventListener {
 
 	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;
 	private final UserProfileService userProfileService;
-	private final BescheidFeatureProperties bescheidFeatureProperties;
 
 	@EventListener(condition = IS_CREATE_BESCHEID)
 	public void onCreateBescheidCommand(CommandCreatedEvent event) {
@@ -105,12 +106,6 @@ class BescheidEventListener {
 	}
 
 	void doCreateBescheid(Command command) {
-		if (bescheidFeatureProperties.isKielHackathonRoute()) {
-			var bescheid = doCreateBescheidBiz(command);
-			nachrichtService.createNachrichtDraft(bescheid);
-			eventPublisher.publishEvent(new BescheidCreatedEvent(command));
-			return;
-		}
 		var createdItemId = attachedItemService.createBescheidDraft(command);
 		eventPublisher.publishEvent(new BescheidCreatedEvent(command, createdItemId));
 	}
@@ -165,9 +160,9 @@ class BescheidEventListener {
 	void doSendBescheid(Command command) {
 		var bescheidItem = attachedItemService.getItem(command.getRelationId());
 		if (SendBy.MANUAL.hasValue(bescheidItem.getItem().get(Bescheid.FIELD_SEND_BY))) {
-			service.sendBescheidManually(bescheidItem, command.getRelationVersion());
+			service.sendBescheidManually(bescheidItem, command);
 		} else if (SendBy.NACHRICHT.hasValue(bescheidItem.getItem().get(Bescheid.FIELD_SEND_BY))) {
-			service.sendBescheidPostfachMail(bescheidItem, command.getRelationVersion());
+			service.sendBescheidPostfachMail(bescheidItem, command);
 		} else {
 			throw new TechnicalException("Bescheid has unexpected sendBy value: '%s'. Allowed values are %s."
 					.formatted(bescheidItem.getItem().get(Bescheid.FIELD_SEND_BY),
@@ -190,6 +185,15 @@ class BescheidEventListener {
 		return builder.build();
 	}
 
+	@EventListener(condition = IS_SEND_BESCHEID_ORDER)
+	public void onBescheidSent(CommandExecutedEvent event) {
+		runWithSecurityContext(event.getCommand(), this::setAntragBewilligung);
+	}
+
+	void setAntragBewilligung(Command command) {
+		service.setAntragBewilligung(attachedItemService.getItem(command.getRelationId()));
+	}
+
 	void runWithSecurityContext(Command command, Consumer<Command> commandExecutor) {
 		SecurityContext prevContext = null;
 		try {
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 ffc2ece833e690b658dd1689c38e5e28789d1689..fb010f5dff17f3406354455944fab3a4f168be2c 100644
--- a/bescheid-manager/src/main/java/de/ozgcloud/bescheid/BescheidService.java
+++ b/bescheid-manager/src/main/java/de/ozgcloud/bescheid/BescheidService.java
@@ -1,25 +1,35 @@
 package de.ozgcloud.bescheid;
 
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 import java.util.Optional;
+import java.util.stream.Stream;
 
 import jakarta.annotation.PostConstruct;
 
 import org.apache.commons.collections.MapUtils;
 import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.boot.info.BuildProperties;
 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.OzgCloudCreateSubCommandsRequest;
+import de.ozgcloud.apilib.common.command.grpc.CommandMapper;
 import de.ozgcloud.bescheid.attacheditem.AttachedItem;
 import de.ozgcloud.bescheid.attacheditem.AttachedItemService;
 import de.ozgcloud.bescheid.attributes.ClientAttributeService;
 import de.ozgcloud.bescheid.common.user.UserProfileService;
-import de.ozgcloud.bescheid.nachricht.NachrichtService;
 import de.ozgcloud.bescheid.vorgang.Vorgang;
 import de.ozgcloud.bescheid.vorgang.VorgangId;
 import de.ozgcloud.bescheid.vorgang.VorgangService;
+import de.ozgcloud.command.Command;
 import de.ozgcloud.common.binaryfile.FileId;
 import de.ozgcloud.common.errorhandling.TechnicalException;
 import de.ozgcloud.document.Document;
@@ -33,10 +43,24 @@ class BescheidService {
 
 	private static final String ERROR_MESSAGE_NO_SERVICE = "No Bescheid Endpoint is configured.";
 
+	static final String VORGANG_BESCHEIDEN_ORDER = "VORGANG_BESCHEIDEN";
+	static final String SUBCOMMANDS_EXECUTION_MODE = "PARALLEL";
+	static final String SEND_POSTFACH_NACHRICHT_ORDER = "SEND_POSTFACH_NACHRICHT";
+
+	static final String FIELD_POSTFACH_ID = "postfachId";
+	static final String FIELD_REPLY_OPTION = "replyOption";
+	static final String REPLY_OPTION = "FORBIDDEN";
+	static final String FIELD_SUBJECT = "subject";
+	static final String FIELD_MAIL_BODY = "mailBody";
+	static final String FIELD_ATTACHMENTS = "attachments";
+	static final String SUBJECT = "Ihr Bescheid zum Antrag";
+
 	private final VorgangService vorgangService;
 	private final AttachedItemService attachedItemService;
-	private final NachrichtService nachrichtService;
-	private final UserProfileService currentUserService;
+	private final UserProfileService userProfileService;
+	@Qualifier(BescheidManagerConfiguration.COMMAND_SERVICE_NAME)
+	private final OzgCloudCommandService commandService;
+	private final CommandMapper commandMapper;
 	private final ClientAttributeService bescheidClientAttributeService;
 	private final BuildProperties buildProperties;
 	private final Optional<BescheidRemoteService> remoteService;
@@ -72,9 +96,10 @@ class BescheidService {
 		}
 	}
 
-	public void sendBescheidManually(AttachedItem bescheidItem, long version) {
-		validateBescheidSendManually(bescheidItem, version);
-		setBescheidSent(bescheidItem);
+	public void sendBescheidManually(AttachedItem bescheidItem, Command parentCommand) {
+		validateBescheidSendManually(bescheidItem, parentCommand.getRelationVersion());
+		var vorgang = vorgangService.getById(VorgangId.from(bescheidItem.getVorgangId()));
+		addSubCommands(parentCommand.getId(), buildSetBescheidSentSubCommands(bescheidItem, vorgang, getUserId()));
 	}
 
 	void validateBescheidSendManually(AttachedItem bescheidItem, long version) {
@@ -85,11 +110,13 @@ class BescheidService {
 		}
 	}
 
-	public void sendBescheidPostfachMail(AttachedItem bescheidItem, long version) {
-		validateBescheidSendPostfach(bescheidItem, version);
+	public void sendBescheidPostfachMail(AttachedItem bescheidItem, Command parentCommand) {
+		validateBescheidSendPostfach(bescheidItem, parentCommand.getRelationVersion());
 		var vorgang = vorgangService.getById(VorgangId.from(bescheidItem.getVorgangId()));
-		setBescheidSent(bescheidItem);
-		nachrichtService.sendNachricht(buildBescheid(bescheidItem, vorgang.getServiceKonto()));
+		var userId = getUserId();
+		var subCommands = buildSetBescheidSentSubCommands(bescheidItem, vorgang, userId);
+		subCommands.add(buildSendPostfachNachrichtCommand(bescheidItem, vorgang.getServiceKonto(), userId));
+		addSubCommands(parentCommand.getId(), subCommands);
 	}
 
 	public void validateBescheidSendPostfach(AttachedItem bescheidItem, long version) {
@@ -98,10 +125,10 @@ class BescheidService {
 		if (Bescheid.SendBy.NACHRICHT.notValue(sendBy)) {
 			throw new TechnicalException("Bescheid has unexpected sendBy value: '%s'. Expected is %s".formatted(sendBy, Bescheid.SendBy.NACHRICHT));
 		}
-		if (StringUtils.isBlank(getNachrichtSubject(bescheidItem))) {
+		if (getNachrichtSubject(bescheidItem).isEmpty()) {
 			throw new TechnicalException("Bescheid has no nachricht subject");
 		}
-		if (StringUtils.isBlank(getNachrichtText(bescheidItem))) {
+		if (getNachrichtText(bescheidItem).isEmpty()) {
 			throw new TechnicalException("Bescheid has no nachricht text");
 		}
 	}
@@ -119,30 +146,93 @@ class BescheidService {
 		}
 	}
 
-	Bescheid buildBescheid(AttachedItem bescheidItem, Vorgang.ServiceKonto serviceKonto) {
-		return Bescheid.builder()
-				.vorgangId(VorgangId.from(bescheidItem.getVorgangId()))
-				.genehmigt(getBewilligt(bescheidItem))
-				.bescheidFileId(getBescheidFileId(bescheidItem))
-				.nachrichtSubject(Optional.ofNullable(getNachrichtSubject(bescheidItem)))
-				.nachrichtText(Optional.ofNullable(getNachrichtText(bescheidItem)))
-				.createdBy(currentUserService.getUserProfile().getId())
-				.serviceKonto(serviceKonto)
-				.attachments(getAttachments(bescheidItem))
+	Optional<String> getNachrichtSubject(AttachedItem bescheidItem) {
+		return Optional.ofNullable(MapUtils.getString(bescheidItem.getItem(), Bescheid.FIELD_NACHRICHT_SUBJECT)).map(StringUtils::trimToNull);
+	}
+
+	Optional<String> getNachrichtText(AttachedItem bescheidItem) {
+		return Optional.ofNullable(MapUtils.getString(bescheidItem.getItem(), Bescheid.FIELD_NACHRICHT_TEXT)).map(StringUtils::trimToNull);
+	}
+
+	String getUserId() {
+		return userProfileService.getUserProfile().getId().toString();
+	}
+
+	List<OzgCloudCommand> buildSetBescheidSentSubCommands(AttachedItem bescheidItem, Vorgang vorgang, String userId) {
+		var subCommands = new ArrayList<OzgCloudCommand>();
+		subCommands.add(buildVorgangBescheidenCommand(vorgang));
+		subCommands.add(buildSetBescheidSentStatusCommand(bescheidItem, userId));
+		return subCommands;
+	}
+
+	OzgCloudCommand buildVorgangBescheidenCommand(Vorgang vorgang) {
+		return OzgCloudCommand.builder()
+				.vorgangId(commandMapper.toOzgCloudVorgangId(vorgang.getId().toString()))
+				.relationId(commandMapper.mapRelationId(vorgang.getId().toString()))
+				.relationVersion(vorgang.getVersion())
+				.order(VORGANG_BESCHEIDEN_ORDER)
 				.build();
 	}
 
-	FileId getBescheidFileId(AttachedItem bescheidItem) {
-		var bescheidDocument = attachedItemService.getItem(MapUtils.getString(bescheidItem.getItem(), Bescheid.FIELD_BESCHEID_DOCUMENT));
-		return FileId.from(MapUtils.getString(bescheidDocument.getItem(), Document.FIELD_DOCUMENT_FILE));
+	OzgCloudCommand buildSetBescheidSentStatusCommand(AttachedItem bescheidItem, String userId) {
+		return OzgCloudCommand.builder()
+				.relationId(commandMapper.mapRelationId(bescheidItem.getId()))
+				.relationVersion(bescheidItem.getVersion())
+				.order(AttachedItemService.PATCH_ATTACHED_ITEM)
+				.bodyObject(Map.of(
+						AttachedItem.PROPERTY_ID, bescheidItem.getId(),
+						AttachedItem.PROPERTY_ITEM, buildBescheidSentStatusItem(userId)))
+				.build();
+	}
+
+	Map<String, Object> buildBescheidSentStatusItem(String userId) {
+		return Map.of(
+				Bescheid.FIELD_STATUS, Bescheid.Status.SENT.name(),
+				Bescheid.FIELD_SENT_INFO, buildSentInfoMap(userId));
+	}
+
+	Map<String, Object> buildSentInfoMap(String userId) {
+		return Map.of(
+				Bescheid.FIELD_SENT_AT, ZonedDateTime.now().format(DateTimeFormatter.ISO_DATE_TIME),
+				Bescheid.FIELD_SENT_BY, userId);
+	}
+
+	OzgCloudCommand buildSendPostfachNachrichtCommand(AttachedItem bescheidItem, Vorgang.ServiceKonto serviceKonto, String userId) {
+		var bodyObject = buildSendNachrichtCommandBody(bescheidItem, buildPostfachAddress(serviceKonto.getPostfachAddresses().getFirst(),
+				serviceKonto.getType()));
+		return OzgCloudCommand.builder()
+				.vorgangId(commandMapper.toOzgCloudVorgangId(bescheidItem.getVorgangId()))
+				.relationId(commandMapper.mapRelationId(bescheidItem.getVorgangId()))
+				.order(SEND_POSTFACH_NACHRICHT_ORDER)
+				.createdBy(commandMapper.toOzgCloudUserId(userId))
+				.bodyObject(bodyObject)
+				.build();
+	}
+
+	Map<String, Object> buildPostfachAddress(Vorgang.PostfachAddress postfachAddress, String serviceKontoType) {
+		return Map.of(Vorgang.PostfachAddress.FIELD_TYPE, postfachAddress.getType(),
+				Vorgang.PostfachAddress.FIELD_VERSION, postfachAddress.getVersion(),
+				Vorgang.PostfachAddress.FIELD_IDENTIFIER, postfachAddress.getIdentifier(),
+				Vorgang.ServiceKonto.FIELD_SERVICEKONTO_TYPE, serviceKontoType);
+	}
+
+	Map<String, Object> buildSendNachrichtCommandBody(AttachedItem bescheidItem, Map<String, Object> postfachAddress) {
+		return Map.of(
+				FIELD_REPLY_OPTION, REPLY_OPTION,
+				FIELD_SUBJECT, getNachrichtSubject(bescheidItem).orElse(SUBJECT),
+				FIELD_MAIL_BODY, getNachrichtText(bescheidItem).orElse(StringUtils.EMPTY),
+				FIELD_ATTACHMENTS, buildAttachments(bescheidItem),
+				Vorgang.ServiceKonto.FIELD_POSTFACH_ADDRESS, postfachAddress);
+
 	}
 
-	String getNachrichtSubject(AttachedItem bescheidItem) {
-		return MapUtils.getString(bescheidItem.getItem(), Bescheid.FIELD_NACHRICHT_SUBJECT);
+	List<String> buildAttachments(AttachedItem bescheidItem) {
+		return Stream.concat(Stream.of(getBescheidFileId(bescheidItem)), getAttachments(bescheidItem).stream()).map(FileId::toString).toList();
 	}
 
-	String getNachrichtText(AttachedItem bescheidItem) {
-		return MapUtils.getString(bescheidItem.getItem(), Bescheid.FIELD_NACHRICHT_TEXT);
+	FileId getBescheidFileId(AttachedItem bescheidItem) {
+		var bescheidDocument = attachedItemService.getItem(MapUtils.getString(bescheidItem.getItem(), Bescheid.FIELD_BESCHEID_DOCUMENT));
+		return FileId.from(MapUtils.getString(bescheidDocument.getItem(), Document.FIELD_DOCUMENT_FILE));
 	}
 
 	List<FileId> getAttachments(AttachedItem bescheidItem) {
@@ -160,18 +250,20 @@ class BescheidService {
 		return Collections.emptyList();
 	}
 
-	void setBescheidSent(AttachedItem bescheidItem) {
-		attachedItemService.setBescheidSentStatus(bescheidItem.getId(), bescheidItem.getVersion());
-		try {
-			vorgangService.bescheiden(bescheidItem.getVorgangId());
-		} catch (Exception e) {
-			attachedItemService.revertBescheidSendStatus(bescheidItem.getId(), bescheidItem.getVersion());
-			throw e;
-		}
-		setAntragBewilligung(bescheidItem);
+	void addSubCommands(String parentCommandId, List<OzgCloudCommand> subCommands) {
+		commandService.addSubCommands(buildCreateSubCommandsRequest(parentCommandId, subCommands));
+	}
+
+	OzgCloudCreateSubCommandsRequest buildCreateSubCommandsRequest(String parentCommandId, List<OzgCloudCommand> subCommands) {
+		return OzgCloudCreateSubCommandsRequest.builder()
+				.parentId(parentCommandId)
+				.executionMode(SUBCOMMANDS_EXECUTION_MODE)
+				.completedIfSubsCompleted(true)
+				.subCommands(subCommands)
+				.build();
 	}
 
-	void setAntragBewilligung(AttachedItem bescheidItem) {
+	public void setAntragBewilligung(AttachedItem bescheidItem) {
 		try {
 			bescheidClientAttributeService.setAntragResult(bescheidItem.getVorgangId(), getBewilligt(bescheidItem));
 		} catch (Exception e) {
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 4e2867be8883419b25ccbd4a055fd7de97f7eef2..24a67a215b953478b6bf2518432c37469eb94e42 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
@@ -25,8 +25,6 @@ package de.ozgcloud.bescheid.attacheditem;
 
 import static java.util.Objects.*;
 
-import java.time.ZonedDateTime;
-import java.time.format.DateTimeFormatter;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashMap;
@@ -37,7 +35,6 @@ import java.util.stream.Collectors;
 
 import org.apache.commons.collections.MapUtils;
 import org.apache.commons.lang3.StringUtils;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.stereotype.Service;
 
@@ -47,39 +44,33 @@ import de.ozgcloud.apilib.common.command.grpc.CommandMapper;
 import de.ozgcloud.bescheid.Bescheid;
 import de.ozgcloud.bescheid.BescheidCallContextAttachingInterceptor;
 import de.ozgcloud.bescheid.BescheidManagerConfiguration;
-import de.ozgcloud.bescheid.common.callcontext.CallContextUser;
-import de.ozgcloud.bescheid.common.callcontext.CurrentUserService;
 import de.ozgcloud.bescheid.common.freemarker.TemplateHandler;
 import de.ozgcloud.bescheid.vorgang.VorgangId;
 import de.ozgcloud.command.Command;
 import de.ozgcloud.common.errorhandling.TechnicalException;
 import de.ozgcloud.document.Document;
+import lombok.RequiredArgsConstructor;
 import lombok.extern.log4j.Log4j2;
 
 @Log4j2
 @Service
+@RequiredArgsConstructor
 public class AttachedItemService {
 
 	public static final String BESCHEID_ITEM_NAME = "Bescheid";
+	public static final String PATCH_ATTACHED_ITEM = "PATCH_ATTACHED_ITEM";
 	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";
-	static final String PATCH_ATTACHED_ITEM = "PATCH_ATTACHED_ITEM";
 
 	static final String DEFAULT_SUBJECT = "Ihr Bescheid zum Antrag";
 	static final String DEFAULT_TEMPLATE_FILE = "bescheid.nachrichtTemplate.txt.ftlh";
 
 	@Qualifier(BescheidManagerConfiguration.COMMAND_SERVICE_NAME)
-	@Autowired
-	private OzgCloudCommandService commandService;
-	@Autowired
-	private VorgangAttachedItemRemoteService remoteService;
-	@Autowired
-	private CommandMapper commandMapper;
-	@Autowired
-	private CurrentUserService currentUserService;
-	@Autowired
-	private TemplateHandler templateHandler;
+	private final OzgCloudCommandService commandService;
+	private final VorgangAttachedItemRemoteService remoteService;
+	private final CommandMapper commandMapper;
+	private final TemplateHandler templateHandler;
 
 	public Optional<AttachedItem> findBescheidItem(String vorgangId) {
 		return remoteService.findBescheidDraft(vorgangId);
@@ -121,7 +112,7 @@ public class AttachedItemService {
 
 	String overrideAttachedItem(AttachedItem bescheidItem, Command command) {
 		var attachedItem = buildAttachedItemAsMap(command, buildItemMapWithAllBescheidFields(command));
-		var finishedOzgCloudCommand = commandService.createAndWaitUntilDone(buildUpdateAttachedItemCommand(bescheidItem, attachedItem));
+		var finishedOzgCloudCommand = commandService.createAndWaitUntilDone(buildPatchAttachedItemCommand(bescheidItem, attachedItem));
 		return finishedOzgCloudCommand.getCreatedResource();
 	}
 
@@ -146,7 +137,7 @@ public class AttachedItemService {
 	}
 
 	private OzgCloudCommand buildUpdateBescheidDraftCommand(Command command, Optional<Document> document, AttachedItem bescheidItem) {
-		return buildUpdateAttachedItemCommand(bescheidItem, buildAttachedItemAsMap(command, buildBescheidItemAsMap(command, document)));
+		return buildPatchAttachedItemCommand(bescheidItem, buildAttachedItemAsMap(command, buildBescheidItemAsMap(command, document)));
 	}
 
 	Map<String, Object> buildBescheidItemAsMap(Command command, Optional<Document> newDocument) {
@@ -173,12 +164,12 @@ public class AttachedItemService {
 		return MapUtils.getString(item.getItem(), Bescheid.FIELD_BESCHEID_DOCUMENT);
 	}
 
-	OzgCloudCommand buildUpdateAttachedItemCommand(AttachedItem bescheidItem, Map<String, Object> bodyObject) {
+	OzgCloudCommand buildPatchAttachedItemCommand(AttachedItem bescheidItem, Map<String, Object> bodyObject) {
 		return OzgCloudCommand.builder()
 				.vorgangId(commandMapper.toOzgCloudVorgangId(bescheidItem.getVorgangId()))
 				.relationId(commandMapper.mapRelationId(bescheidItem.getId()))
 				.relationVersion(bescheidItem.getVersion())
-				.order(UPDATE_ATTACHED_ITEM_ORDER)
+				.order(PATCH_ATTACHED_ITEM)
 				.bodyObject(bodyObject)
 				.build();
 	}
@@ -267,65 +258,12 @@ public class AttachedItemService {
 				.build();
 	}
 
-	public void setBescheidSentStatus(String id, long version) {
-		createPatchCommand(id, version, buildBescheidSentStatusBodyObject(id));
-	}
-
-	Map<String, Object> buildBescheidSentStatusBodyObject(String bescheidId) {
-		return Map.of(AttachedItem.PROPERTY_ID, bescheidId,
-				AttachedItem.PROPERTY_ITEM, buildBescheidSentStatusItem());
-	}
-
-	Map<String, Object> buildBescheidSentStatusItem() {
-		var itemMap = buildItemMap(Bescheid.Status.SENT);
-		itemMap.put(Bescheid.FIELD_SENT_INFO, buildSentInfoMap());
-		return itemMap;
-	}
-
-	Map<String, Object> buildSentInfoMap() {
-		return Map.of(
-				Bescheid.FIELD_SENT_AT, ZonedDateTime.now().format(DateTimeFormatter.ISO_DATE_TIME),
-				Bescheid.FIELD_SENT_BY, getUserId());
-	}
-
-	String getUserId() {
-		return currentUserService.findUser().flatMap(CallContextUser::getUserId).orElse(StringUtils.EMPTY);
-	}
-
-	public void revertBescheidSendStatus(String id, long version) {
-		createPatchCommand(id, version, buildRevertBescheidSentStatusBodyObject(id));
-	}
-
-	private void createPatchCommand(String id, long version, Map<String, Object> itemMap) {
-		commandService.createAndWaitUntilDone(buildPatchBescheidCommand(id, version, itemMap));
-	}
-
-	Map<String, Object> buildRevertBescheidSentStatusBodyObject(String bescheidId) {
-		return Map.of(AttachedItem.PROPERTY_ID, bescheidId,
-				AttachedItem.PROPERTY_ITEM, buildRevertBescheidSentStatusItem());
-	}
-
-	Map<String, Object> buildRevertBescheidSentStatusItem() {
-		var itemMap = buildItemMap(Bescheid.Status.DRAFT);
-		itemMap.put(Bescheid.FIELD_SENT_INFO, null);
-		return itemMap;
-	}
-
 	Map<String, Object> buildItemMap(Bescheid.Status status) {
 		var itemMap = new HashMap<String, Object>();
 		itemMap.put(Bescheid.FIELD_STATUS, status.name());
 		return itemMap;
 	}
 
-	OzgCloudCommand buildPatchBescheidCommand(String bescheidId, long bescheidVersion, Map<String, Object> bodyObject) {
-		return OzgCloudCommand.builder()
-				.relationId(commandMapper.mapRelationId(bescheidId))
-				.relationVersion(bescheidVersion)
-				.order(PATCH_ATTACHED_ITEM)
-				.bodyObject(bodyObject)
-				.build();
-	}
-
 	public Collection<AttachedItem> findAllBescheid(VorgangId vorgangId) {
 		return remoteService.findAllBescheid(vorgangId);
 	}
diff --git a/bescheid-manager/src/main/java/de/ozgcloud/bescheid/common/user/UserProfileTestFactory.java b/bescheid-manager/src/main/java/de/ozgcloud/bescheid/common/user/UserProfileTestFactory.java
index 8b20aa41c65568e456538a45f3c363d1a18cbded..60949bbe87cf4d3b6c2a366dcc529d4be45c99bf 100644
--- a/bescheid-manager/src/main/java/de/ozgcloud/bescheid/common/user/UserProfileTestFactory.java
+++ b/bescheid-manager/src/main/java/de/ozgcloud/bescheid/common/user/UserProfileTestFactory.java
@@ -33,7 +33,8 @@ public class UserProfileTestFactory {
 
 	private static final LoremIpsum LOREM_IPSUM = LoremIpsum.getInstance();
 
-	public static final UserId ID = UserId.from(UUID.randomUUID().toString());
+	public static final String ID_STR = UUID.randomUUID().toString();
+	public static final UserId ID = UserId.from(ID_STR);
 
 	public static final String FIRST_NAME = LOREM_IPSUM.getFirstName();
 	public static final String LAST_NAME = LOREM_IPSUM.getLastName();
diff --git a/bescheid-manager/src/main/java/de/ozgcloud/bescheid/nachricht/Nachricht.java b/bescheid-manager/src/main/java/de/ozgcloud/bescheid/nachricht/Nachricht.java
deleted file mode 100644
index 1f352d1d9efab6714236d1fbd00b01b33c1ea0dc..0000000000000000000000000000000000000000
--- a/bescheid-manager/src/main/java/de/ozgcloud/bescheid/nachricht/Nachricht.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package de.ozgcloud.bescheid.nachricht;
-
-import java.time.ZonedDateTime;
-
-import de.ozgcloud.bescheid.UserId;
-import de.ozgcloud.bescheid.vorgang.Vorgang;
-import de.ozgcloud.bescheid.vorgang.VorgangId;
-import de.ozgcloud.common.binaryfile.FileId;
-import lombok.Builder;
-import lombok.Getter;
-import lombok.NonNull;
-
-@Getter
-@Builder
-public class Nachricht {
-
-	private NachrichtId id;
-	private VorgangId vorgangId;
-
-	@NonNull
-	private String subject;
-	@NonNull
-	private String mailBody;
-
-	private FileId bescheidFileId;
-
-	@NonNull
-	private UserId createdBy;
-	@Builder.Default
-	private ZonedDateTime createdAt = ZonedDateTime.now();
-
-	private Vorgang.PostfachAddress postfachAddress;
-}
diff --git a/bescheid-manager/src/main/java/de/ozgcloud/bescheid/nachricht/NachrichtId.java b/bescheid-manager/src/main/java/de/ozgcloud/bescheid/nachricht/NachrichtId.java
deleted file mode 100644
index b8fd29a9345542580177104549207a731e2c7139..0000000000000000000000000000000000000000
--- a/bescheid-manager/src/main/java/de/ozgcloud/bescheid/nachricht/NachrichtId.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package de.ozgcloud.bescheid.nachricht;
-
-import de.ozgcloud.common.datatype.StringBasedValue;
-
-public class NachrichtId extends StringBasedValue {
-
-	NachrichtId(String nachrichtId) {
-		super(nachrichtId);
-	}
-
-	public static NachrichtId from(String nachrichtId) {
-		return new NachrichtId(nachrichtId);
-	}
-}
diff --git a/bescheid-manager/src/main/java/de/ozgcloud/bescheid/nachricht/NachrichtMapper.java b/bescheid-manager/src/main/java/de/ozgcloud/bescheid/nachricht/NachrichtMapper.java
deleted file mode 100644
index 45bba2af3b3d076f92ed3b114fccd601a52ea2b4..0000000000000000000000000000000000000000
--- a/bescheid-manager/src/main/java/de/ozgcloud/bescheid/nachricht/NachrichtMapper.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package de.ozgcloud.bescheid.nachricht;
-
-import org.mapstruct.CollectionMappingStrategy;
-import org.mapstruct.Mapper;
-import org.mapstruct.Mapping;
-import org.mapstruct.NullValueCheckStrategy;
-import org.mapstruct.ReportingPolicy;
-
-import de.ozgcloud.bescheid.UserId;
-import de.ozgcloud.bescheid.vorgang.Vorgang;
-import de.ozgcloud.common.binaryfile.FileId;
-import de.ozgcloud.nachrichten.postfach.GrpcPostfachNachricht;
-import de.ozgcloud.vorgang.common.grpc.GrpcObjectMapper;
-import de.ozgcloud.vorgang.vorgang.GrpcPostfachAddress;
-
-@Mapper(collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED, //
-		nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, unmappedTargetPolicy = ReportingPolicy.ERROR, uses = { GrpcObjectMapper.class })
-public interface NachrichtMapper {
-
-	@Mapping(target = "createdAtBytes", ignore = true)
-	@Mapping(target = "mergePostfachAddress", ignore = true)
-	@Mapping(target = "mergeFrom", ignore = true)
-	@Mapping(target = "clearField", ignore = true)
-	@Mapping(target = "clearOneof", ignore = true)
-	@Mapping(target = "mergeUnknownFields", ignore = true)
-	@Mapping(target = "idBytes", ignore = true)
-	@Mapping(target = "mailBodyBytes", ignore = true)
-	@Mapping(target = "replyOptionBytes", ignore = true)
-	@Mapping(target = "subjectBytes", ignore = true)
-	@Mapping(target = "unknownFields", ignore = true)
-	@Mapping(target = "allFields", ignore = true)
-
-	@Mapping(target = "id", ignore = true)
-	@Mapping(target = "attachmentList", source = "bescheidFileId")
-	@Mapping(target = "replyOption", constant = "FORBIDDEN")
-	GrpcPostfachNachricht mapToGrpc(Nachricht nachricht);
-
-	@Mapping(target = "mergeFrom", ignore = true)
-	@Mapping(target = "clearField", ignore = true)
-	@Mapping(target = "clearOneof", ignore = true)
-	@Mapping(target = "mergeIdentifier", ignore = true)
-	@Mapping(target = "mergeUnknownFields", ignore = true)
-	@Mapping(target = "unknownFields", ignore = true)
-	@Mapping(target = "versionBytes", ignore = true)
-	@Mapping(target = "allFields", ignore = true)
-	GrpcPostfachAddress mapAddress(Vorgang.PostfachAddress address);
-
-	default String mapToString(FileId fileId) {
-		return fileId.toString();
-	}
-
-	default String mapToString(UserId userId) {
-		return userId.toString();
-	}
-}
diff --git a/bescheid-manager/src/main/java/de/ozgcloud/bescheid/nachricht/NachrichtRemoteService.java b/bescheid-manager/src/main/java/de/ozgcloud/bescheid/nachricht/NachrichtRemoteService.java
deleted file mode 100644
index 594c6eb77ab84ffa026550f5fa4c0c65b1f1b698..0000000000000000000000000000000000000000
--- a/bescheid-manager/src/main/java/de/ozgcloud/bescheid/nachricht/NachrichtRemoteService.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package de.ozgcloud.bescheid.nachricht;
-
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-
-import de.ozgcloud.nachrichten.postfach.GrpcSaveNachrichtDraftRequest;
-import de.ozgcloud.nachrichten.postfach.PostfachServiceGrpc.PostfachServiceBlockingStub;
-import io.grpc.ClientInterceptor;
-import net.devh.boot.grpc.client.inject.GrpcClient;
-
-@Service
-class NachrichtRemoteService {
-
-	@GrpcClient("nachrichten-manager")
-	private PostfachServiceBlockingStub serviceStub;
-
-	@Autowired
-	private NachrichtMapper mapper;
-
-	@Autowired
-	private ClientInterceptor bescheidCallContextInterceptor;
-
-	public void saveDraft(Nachricht nachricht) {
-		serviceStub.withInterceptors(bescheidCallContextInterceptor)
-				.saveNachrichtDraft(buildRequest(nachricht));
-	}
-
-	GrpcSaveNachrichtDraftRequest buildRequest(Nachricht nachricht) {
-		return GrpcSaveNachrichtDraftRequest.newBuilder()
-				.setVorgangId(nachricht.getVorgangId().toString())
-				.setNachricht(mapper.mapToGrpc(nachricht))
-				.build();
-	}
-}
diff --git a/bescheid-manager/src/main/java/de/ozgcloud/bescheid/nachricht/NachrichtService.java b/bescheid-manager/src/main/java/de/ozgcloud/bescheid/nachricht/NachrichtService.java
deleted file mode 100644
index ce261151ddaa6d682521e59cfbb806c21c033656..0000000000000000000000000000000000000000
--- a/bescheid-manager/src/main/java/de/ozgcloud/bescheid/nachricht/NachrichtService.java
+++ /dev/null
@@ -1,116 +0,0 @@
-package de.ozgcloud.bescheid.nachricht;
-
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.stream.Stream;
-
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Qualifier;
-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.common.freemarker.TemplateHandler;
-import de.ozgcloud.bescheid.vorgang.Vorgang;
-import de.ozgcloud.bescheid.vorgang.Vorgang.PostfachAddress;
-import de.ozgcloud.common.binaryfile.FileId;
-import de.ozgcloud.common.errorhandling.TechnicalException;
-import lombok.extern.log4j.Log4j2;
-
-@Service
-@Log4j2
-public class NachrichtService {
-
-	public static final String SEND_POSTFACH_NACHRICHT_ORDER = "SEND_POSTFACH_NACHRICHT";
-	public static final String FIELD_POSTFACH_ID = "postfachId";
-	static final String FIELD_REPLY_OPTION = "replyOption";
-	static final String REPLY_OPTION = "POSSIBLE";
-	static final String FIELD_SUBJECT = "subject";
-	static final String FIELD_MAIL_BODY = "mailBody";
-	static final String FIELD_ATTACHMENTS = "attachments";
-
-	@Autowired
-	private NachrichtRemoteService remoteService;
-	@Autowired
-	@Qualifier("bescheid_OzgCloudCommandService")
-	private OzgCloudCommandService commandService;
-	@Autowired
-	private CommandMapper commandMapper;
-	@Autowired
-	private TemplateHandler templateHandler;
-
-	static final String SUBJECT = "Ihr Bescheid zum Antrag";
-
-	private static final String TEMPLATE_FILE = "bescheid.nachrichtTemplate.txt.ftlh";
-
-	public void createNachrichtDraft(Bescheid bescheid) {
-		buildNachricht(bescheid).ifPresentOrElse(remoteService::saveDraft, () -> LOG.warn("No ServiceKonto given on Vorgang."));
-	}
-
-	Optional<Nachricht> buildNachricht(Bescheid bescheid) {
-		return getAddress(bescheid).map(address -> Nachricht.builder()
-				.vorgangId(bescheid.getVorgangId())
-				.postfachAddress(address)
-				.subject(bescheid.getNachrichtSubject().orElse(SUBJECT))
-				.mailBody(buildMessage(bescheid))
-				.createdBy(bescheid.getCreatedBy())
-				.bescheidFileId(bescheid.getBescheidFileId())
-				.build());
-	}
-
-	String buildMessage(Bescheid bescheid) {
-		return bescheid.getNachrichtText()
-				.orElseGet(() -> templateHandler.fillTemplate(TEMPLATE_FILE, bescheid));
-	}
-
-	public void sendNachricht(Bescheid bescheid) {
-		commandService.createAndWaitUntilDone(buildSendBescheidCommand(bescheid));
-	}
-
-	OzgCloudCommand buildSendBescheidCommand(Bescheid bescheid) {
-		return OzgCloudCommand.builder()
-				.vorgangId(commandMapper.toOzgCloudVorgangId(bescheid.getVorgangId().toString()))
-				.relationId(commandMapper.mapRelationId(bescheid.getVorgangId().toString()))
-				.order(SEND_POSTFACH_NACHRICHT_ORDER)
-				.createdBy(commandMapper.toOzgCloudUserId(bescheid.getCreatedBy().toString()))
-				.bodyObject(buildSendNachrichtCommandBody(bescheid))
-				.build();
-	}
-
-	Map<String, Object> buildSendNachrichtCommandBody(Bescheid bescheid) {
-		return Map.of(
-				FIELD_REPLY_OPTION, REPLY_OPTION,
-				FIELD_SUBJECT, bescheid.getNachrichtSubject().orElse(SUBJECT),
-				FIELD_MAIL_BODY, bescheid.getNachrichtText().orElse(StringUtils.EMPTY),
-				FIELD_ATTACHMENTS, buildAttachments(bescheid),
-				Vorgang.ServiceKonto.FIELD_POSTFACH_ADDRESS, buildPostfachAddress(bescheid));
-
-	}
-
-	List<String> buildAttachments(Bescheid bescheid) {
-		return Stream.concat(Stream.of(bescheid.getBescheidFileId()), bescheid.getAttachments().stream()).map(FileId::toString).toList();
-	}
-
-	Map<String, Object> buildPostfachAddress(Bescheid bescheid) {
-		var postfachAddress = getAddress(bescheid).orElseThrow(
-				() -> new TechnicalException("No ServiceKonto on Vorgang (id: %s)".formatted(bescheid.getVorgangId())));
-		return Map.of(PostfachAddress.FIELD_TYPE, postfachAddress.getType(),
-				PostfachAddress.FIELD_VERSION, postfachAddress.getVersion(),
-				PostfachAddress.FIELD_IDENTIFIER, postfachAddress.getIdentifier(),
-				Vorgang.ServiceKonto.FIELD_SERVICEKONTO_TYPE, bescheid.getServiceKonto().getType());
-	}
-
-	Optional<PostfachAddress> getAddress(Bescheid bescheid) {
-		var serviceKonto = bescheid.getServiceKonto();
-		if (Objects.nonNull(serviceKonto)) {
-			return Optional.of(serviceKonto.getPostfachAddresses().get(0));
-		}
-		return Optional.empty();
-	}
-
-}
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 b3ce8a3e1a88daa5cff3e3a4b6af9f6b46ce2e98..651017599265902ee54a2e1c153ecfe5dd744f57 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
@@ -20,6 +20,7 @@ import org.springframework.stereotype.Service;
 import org.springframework.web.reactive.function.BodyExtractors;
 import org.springframework.web.reactive.function.client.ClientResponse;
 import org.springframework.web.reactive.function.client.WebClient;
+import org.w3c.dom.Document;
 import org.w3c.dom.Text;
 import org.xml.sax.SAXException;
 
@@ -55,6 +56,9 @@ class SmartDocumentsBescheidRemoteService implements BescheidRemoteService {
 	private static final String FILE_TYPE_PDF = "PDF";
 	private static final String FILE_TYPE_XML = "XML";
 
+	static final String NACHRICHTEN_TEXT_EXPRESSION = "/root/SmartDocument/Fields/NachrichtenText/text()"; // NOSONAR
+	static final String FIELD_TEMPLATE_EXPRESSION = "/root/SmartDocument/Fields/Field[@ID=\"Template.56E7AA0956C7486292E9A02114CB231C\"]/text()"; //NOSONAR
+
 	@SuppressWarnings("deprecation") // SD requires forced UTF-8 encoding
 	private static final MediaType JSON_MEDIA_TYPE_FOR_SD = MediaType.APPLICATION_JSON_UTF8;
 
@@ -116,31 +120,48 @@ class SmartDocumentsBescheidRemoteService implements BescheidRemoteService {
 	}
 
 	Optional<String> getNachrichtText(SmartDocumentsResponse response) {
-		return getXMLFile(response).flatMap(this::extractTextFormXmlFile);
+		return getXMLFile(response).flatMap(this::extractTextFromXmlFile);
 	}
 
-	Optional<String> extractTextFormXmlFile(File xmlFile) {
+	Optional<String> extractTextFromXmlFile(File xmlFile) {
 		try {
-			return doExtractText(xmlFile);
-		} catch (XPathExpressionException | SAXException | IOException | ParserConfigurationException e) {
-			LOG.warn("XML-Parsing error on extracting Nachricht-Text: {}", e.getMessage(), e);
-		} catch (ClassCastException e) {
-			LOG.warn("Error on extraction Nachricht-Text. XPath return unexpected Type.", e);
+			var document = parseXml(xmlFile);
+			if (document.isPresent()) {
+				return document.flatMap(this::getNachrichtenText).or(() -> getFieldTemplateText(document.get())).map(Text::getTextContent);
+			}
 		} catch (RuntimeException e) {
 			LOG.warn("Unexpected Error on extracting NachrichtText: {}", e.getMessage(), e);
 		}
 		return Optional.empty();
 	}
 
-	Optional<String> doExtractText(File xmlFile)
-			throws SAXException, IOException, ParserConfigurationException, XPathExpressionException {
-		var xPath = XPathFactory.newInstance().newXPath();
+	Optional<Document> parseXml(File xmlFile) {
+		try {
+			return Optional.of(DocumentBuilderFactory.newDefaultInstance().newDocumentBuilder().parse(xmlFile));
+		} catch (SAXException | IOException | ParserConfigurationException e) {
+			LOG.warn("XML-Parsing error on extracting Nachricht-Text: {}", e.getMessage(), e);
+		}
+		return Optional.empty();
+	}
+
+	Optional<Text> getNachrichtenText(Document document) {
+		return evaluateXPath(document, NACHRICHTEN_TEXT_EXPRESSION);
+	}
 
-		var document = DocumentBuilderFactory.newDefaultInstance().newDocumentBuilder().parse(xmlFile);
-		var expr = xPath.compile("/root/SmartDocument/Fields/NachrichtenText/text()");
+	Optional<Text> getFieldTemplateText(Document document) {
+		return evaluateXPath(document, FIELD_TEMPLATE_EXPRESSION);
+	}
 
-		return Optional.ofNullable((Text) expr.evaluate(document, XPathConstants.NODE))
-				.map(Text::getTextContent);
+	Optional<Text> evaluateXPath(Document document, String xpathExpression) {
+		try {
+			var expr = XPathFactory.newInstance().newXPath().compile(xpathExpression);
+			return Optional.ofNullable(expr.evaluate(document, XPathConstants.NODE)).map(Text.class::cast);
+		} catch (ClassCastException e) {
+			LOG.warn("Error on extraction Nachricht-Text. XPath return unexpected Type.", e);
+		} catch (XPathExpressionException e) {
+			LOG.warn("Cannot evaluate XPath: {}", xpathExpression, e);
+		}
+		return Optional.empty();
 	}
 
 	Optional<File> getXMLFile(SmartDocumentsResponse response) {
@@ -178,9 +199,9 @@ class SmartDocumentsBescheidRemoteService implements BescheidRemoteService {
 
 	private SmartDocumentsRequest.SmartDocument buildSDSection(Vorgang vorgang) {
 		return SmartDocumentsRequest.SmartDocument.builder().selection(Selection.builder()
-				.templateGroup(properties.getTemplateGroup())
-				.template(vorgang.getVorgangName())
-				.build())
+						.templateGroup(properties.getTemplateGroup())
+						.template(vorgang.getVorgangName())
+						.build())
 				.build();
 	}
 
diff --git a/bescheid-manager/src/main/java/de/ozgcloud/bescheid/vorgang/VorgangService.java b/bescheid-manager/src/main/java/de/ozgcloud/bescheid/vorgang/VorgangService.java
index 09b366285262b009acc54f131611760025ef1c5d..98689c96ea25c66ffcfbe9cab54556b148b7fc65 100644
--- a/bescheid-manager/src/main/java/de/ozgcloud/bescheid/vorgang/VorgangService.java
+++ b/bescheid-manager/src/main/java/de/ozgcloud/bescheid/vorgang/VorgangService.java
@@ -1,46 +1,18 @@
 package de.ozgcloud.bescheid.vorgang;
 
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Qualifier;
 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 lombok.NonNull;
+import lombok.RequiredArgsConstructor;
 
 @Service("bescheid_VorgangService")
+@RequiredArgsConstructor
 public class VorgangService {
 
-	static final String VORGANG_BESCHEIDEN = "VORGANG_BESCHEIDEN";
-
-	@Autowired
-	private VorgangRemoteService remoteService;
-	@Autowired
-	@Qualifier("bescheid_OzgCloudCommandService")
-	private OzgCloudCommandService commandService;
-	@Autowired
-	private CommandMapper commandMapper;
+	private final VorgangRemoteService remoteService;
 
 	public Vorgang getById(@NonNull VorgangId id) {
 		return remoteService.getById(id);
 	}
 
-	public void bescheiden(String vorgangId) {
-		bescheiden(getById(VorgangId.from(vorgangId)));
-	}
-
-	private void bescheiden(Vorgang vorgang) {
-		commandService.createAndWaitUntilDone(buildBescheidenCommand(vorgang));
-	}
-
-	OzgCloudCommand buildBescheidenCommand(Vorgang vorgang) {
-		return OzgCloudCommand.builder()
-				.vorgangId(commandMapper.toOzgCloudVorgangId(vorgang.getId().toString()))
-				.relationId(commandMapper.mapRelationId(vorgang.getId().toString()))
-				.relationVersion(vorgang.getVersion())
-				.order(VORGANG_BESCHEIDEN)
-				.build();
-	}
-
 }
diff --git a/bescheid-manager/src/main/resources/templates/bescheid.nachrichtTemplate.txt.ftlh b/bescheid-manager/src/main/resources/templates/bescheid.nachrichtTemplate.txt.ftlh
index a53a9cb966f6dad7b608d517f81938d3d611500a..368804ed6ea51f622c32a2e90a21d5f1dd00763f 100644
--- a/bescheid-manager/src/main/resources/templates/bescheid.nachrichtTemplate.txt.ftlh
+++ b/bescheid-manager/src/main/resources/templates/bescheid.nachrichtTemplate.txt.ftlh
@@ -1,6 +1,6 @@
 Sehr geehrte/r Antragsteller/in,
 
-im folgenden erhalten Sie Ihren Bescheid.
+im Folgenden erhalten Sie Ihren Bescheid.
 
 Mit freundlichen Grüßen
 
diff --git a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/BescheidEventListenerITCase.java b/bescheid-manager/src/test/java/de/ozgcloud/bescheid/BescheidEventListenerITCase.java
index 96c5ef5dafcba70a2f79b18ae9d7aa8b24bf8670..a4c77b54a873cf167eb1ce027467114391322744 100644
--- a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/BescheidEventListenerITCase.java
+++ b/bescheid-manager/src/test/java/de/ozgcloud/bescheid/BescheidEventListenerITCase.java
@@ -9,6 +9,7 @@ import org.junit.jupiter.api.Test;
 import org.mockito.Mock;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.boot.test.mock.mockito.SpyBean;
 import org.springframework.context.ApplicationEventPublisher;
 
 import de.ozgcloud.apilib.common.command.OzgCloudCommandService;
@@ -19,16 +20,19 @@ import de.ozgcloud.bescheid.common.user.UserProfile;
 import de.ozgcloud.bescheid.common.user.UserProfileService;
 import de.ozgcloud.command.Command;
 import de.ozgcloud.command.CommandCreatedEventTestFactory;
+import de.ozgcloud.command.CommandExecutedEvent;
 import de.ozgcloud.command.CommandTestFactory;
 import de.ozgcloud.common.test.ITCase;
 
 @ITCase
 class BescheidEventListenerITCase {
 
+	private static final Command COMMAND_WITH_OTHER_ORDER = CommandTestFactory.createBuilder().order("OTHER").build();
+
 	@Autowired
 	private ApplicationEventPublisher publisher;
-	@Autowired
-	private BescheidFeatureProperties bescheidFeatureProperties;
+	@SpyBean
+	private BescheidEventListener listener;
 
 	@MockBean
 	private BescheidService service;
@@ -56,21 +60,16 @@ class BescheidEventListenerITCase {
 
 		private final Command command = CommandTestFactory.createBuilder().order(BescheidEventListener.CREATE_BESCHEID_ORDER).build();
 
-		@BeforeEach
-		void init() {
-			bescheidFeatureProperties.setKielHackathonRoute(true);
-		}
-
 		@Test
 		void shouldCallService() {
 			publisher.publishEvent(CommandCreatedEventTestFactory.withCommand(command));
 
-			verify(service).createBescheid(any());
+			verify(attachedItemService).createBescheidDraft(command);
 		}
 
 		@Test
 		void shouldNotReactOnOtherOrder() {
-			publisher.publishEvent(CommandCreatedEventTestFactory.withCommand(CommandTestFactory.createBuilder().order("OTHER").build()));
+			publisher.publishEvent(CommandCreatedEventTestFactory.withCommand(COMMAND_WITH_OTHER_ORDER));
 
 			verifyNoInteractions(service);
 		}
@@ -90,7 +89,7 @@ class BescheidEventListenerITCase {
 
 		@Test
 		void shouldNotReactOnOtherOrder() {
-			publisher.publishEvent(CommandCreatedEventTestFactory.withCommand(CommandTestFactory.createBuilder().order("OTHER").build()));
+			publisher.publishEvent(CommandCreatedEventTestFactory.withCommand(COMMAND_WITH_OTHER_ORDER));
 
 			verifyNoInteractions(attachedItemService);
 		}
@@ -110,9 +109,29 @@ class BescheidEventListenerITCase {
 
 		@Test
 		void shouldNotReactOnOtherOrder() {
-			publisher.publishEvent(CommandCreatedEventTestFactory.withCommand(CommandTestFactory.createBuilder().order("OTHER").build()));
+			publisher.publishEvent(CommandCreatedEventTestFactory.withCommand(COMMAND_WITH_OTHER_ORDER));
 
 			verifyNoInteractions(attachedItemService);
 		}
 	}
+
+	@Nested
+	class TestBescheidSent {
+
+		private static final Command COMMAND = CommandTestFactory.createBuilder().order(BescheidEventListener.SEND_BESCHEID_ORDER).build();
+
+		@Test
+		void shouldCallMethod() {
+			publisher.publishEvent(new CommandExecutedEvent(COMMAND));
+
+			verify(listener).setAntragBewilligung(COMMAND);
+		}
+
+		@Test
+		void shouldNotReactOnOtherOrder() {
+			publisher.publishEvent(new CommandExecutedEvent(COMMAND_WITH_OTHER_ORDER));
+
+			verifyNoInteractions(listener);
+		}
+	}
 }
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 823d76cd45304b38173621fa521a6e3cbec6820e..ba29a266aeb99969217d43cee2a15a485b12718a 100644
--- a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/BescheidEventListenerTest.java
+++ b/bescheid-manager/src/test/java/de/ozgcloud/bescheid/BescheidEventListenerTest.java
@@ -32,9 +32,9 @@ import de.ozgcloud.bescheid.common.freemarker.TemplateHandler;
 import de.ozgcloud.bescheid.common.user.UserProfile;
 import de.ozgcloud.bescheid.common.user.UserProfileService;
 import de.ozgcloud.bescheid.common.user.UserProfileTestFactory;
-import de.ozgcloud.bescheid.nachricht.NachrichtService;
 import de.ozgcloud.command.Command;
 import de.ozgcloud.command.CommandCreatedEventTestFactory;
+import de.ozgcloud.command.CommandExecutedEvent;
 import de.ozgcloud.command.CommandFailedEvent;
 import de.ozgcloud.command.CommandTestFactory;
 import de.ozgcloud.common.errorhandling.TechnicalException;
@@ -54,12 +54,8 @@ class BescheidEventListenerTest {
 	@Mock
 	private BinaryFileService fileService;
 	@Mock
-	private NachrichtService nachrichtService;
-	@Mock
 	private AttachedItemService attachedItemService;
 	@Mock
-	private BescheidFeatureProperties featureProperties;
-	@Mock
 	private DocumentService documentService;
 
 	@Mock
@@ -104,77 +100,36 @@ class BescheidEventListenerTest {
 		@Captor
 		private ArgumentCaptor<BescheidCreatedEvent> eventCaptor;
 
-		@Nested
-		class TestKielConfigured {
-
-			@BeforeEach
-			void init() {
-				when(featureProperties.isKielHackathonRoute()).thenReturn(true);
-			}
-
-			@Test
-			void shouldCallDoCreateBescheidBiz() {
-				listener.doCreateBescheid(COMMAND);
-
-				verify(listener).doCreateBescheidBiz(COMMAND);
-				verify(attachedItemService, never()).createBescheidDraft(any());
-			}
-
-			@Test
-			void shouldCallNachrichtService() {
-				var bescheid = BescheidTestFactory.create();
-				doReturn(bescheid).when(listener).doCreateBescheidBiz(any());
-
-				listener.doCreateBescheid(COMMAND);
-
-				verify(nachrichtService).createNachrichtDraft(bescheid);
-			}
-
-			@Test
-			void shouldPublishBescheidCreatedEvent() {
-				listener.doCreateBescheid(COMMAND);
+		@Test
+		void shouldCallCreateBescheidDraft() {
+			listener.doCreateBescheid(COMMAND);
 
-				verify(eventPublisher).publishEvent(eventCaptor.capture());
-				assertThat(eventCaptor.getValue().getSource()).isEqualTo(CommandTestFactory.ID);
-			}
+			verify(attachedItemService).createBescheidDraft(COMMAND);
 		}
 
-		@Nested
-		class TestNotKielConfigured {
-
-			@Test
-			void shouldCallCreateBescheidDraft() {
-				listener.doCreateBescheid(COMMAND);
-
-				verify(attachedItemService).createBescheidDraft(COMMAND);
-				verify(listener, never()).doCreateBescheidBiz(any());
-			}
-
-			@Test
-			@DisplayName("should publish BescheidCreatedEvent after creating BescheidDraft")
-			void shouldPublishBescheidCreatedEventWithCommand() {
-				var createdResource = "item-id";
-				when(attachedItemService.createBescheidDraft(any())).thenReturn(createdResource);
+		@Test
+		@DisplayName("should publish BescheidCreatedEvent after creating BescheidDraft")
+		void shouldPublishBescheidCreatedEventWithCommand() {
+			var createdResource = "item-id";
+			when(attachedItemService.createBescheidDraft(any())).thenReturn(createdResource);
 
-				listener.doCreateBescheid(COMMAND);
+			listener.doCreateBescheid(COMMAND);
 
-				verify(eventPublisher).publishEvent(eventCaptor.capture());
-				assertThat(eventCaptor.getValue().getCommand()).isSameAs(COMMAND);
-			}
+			verify(eventPublisher).publishEvent(eventCaptor.capture());
+			assertThat(eventCaptor.getValue().getCommand()).isSameAs(COMMAND);
+		}
 
-			@Test
-			@DisplayName("should publish BescheidCreatedEvent with created resource")
-			void shouldPublishBescheidCreatedEventWithCreatedResource() {
-				var createdResource = "item-id";
-				when(attachedItemService.createBescheidDraft(any())).thenReturn(createdResource);
+		@Test
+		@DisplayName("should publish BescheidCreatedEvent with created resource")
+		void shouldPublishBescheidCreatedEventWithCreatedResource() {
+			var createdResource = "item-id";
+			when(attachedItemService.createBescheidDraft(any())).thenReturn(createdResource);
 
-				listener.doCreateBescheid(COMMAND);
+			listener.doCreateBescheid(COMMAND);
 
-				verify(eventPublisher).publishEvent(eventCaptor.capture());
-				assertThat(eventCaptor.getValue().getCreatedResource()).isEqualTo(createdResource);
-			}
+			verify(eventPublisher).publishEvent(eventCaptor.capture());
+			assertThat(eventCaptor.getValue().getCreatedResource()).isEqualTo(createdResource);
 		}
-
 	}
 
 	@Nested
@@ -551,8 +506,8 @@ class BescheidEventListenerTest {
 			void shouldCallSendBescheid() {
 				listener.doSendBescheid(COMMAND);
 
-				verify(service).sendBescheidManually(bescheidItem, AttachedItemTestFactory.VERSION);
-				verify(service, never()).sendBescheidPostfachMail(any(), anyLong());
+				verify(service).sendBescheidManually(bescheidItem, COMMAND);
+				verify(service, never()).sendBescheidPostfachMail(any(), any());
 			}
 
 			@Test
@@ -585,8 +540,8 @@ class BescheidEventListenerTest {
 			void shouldCallBescheidService() {
 				listener.doSendBescheid(COMMAND);
 
-				verify(service).sendBescheidPostfachMail(bescheidItem, AttachedItemTestFactory.VERSION);
-				verify(service, never()).sendBescheidManually(any(), anyLong());
+				verify(service).sendBescheidPostfachMail(bescheidItem, COMMAND);
+				verify(service, never()).sendBescheidManually(any(), any());
 			}
 
 			@Test
@@ -599,6 +554,49 @@ class BescheidEventListenerTest {
 		}
 	}
 
+	@Nested
+	class TestOnBescheidSent {
+
+		private static final Command COMMAND = CommandTestFactory.create();
+
+		@Test
+		void shouldCallRunWithSecurityContext() {
+			listener.onBescheidSent(new CommandExecutedEvent(COMMAND));
+
+			verify(listener).runWithSecurityContext(eq(COMMAND), any());
+		}
+
+		@Test
+		void shouldExecuteSetAntragBewilligung() {
+			listener.onBescheidSent(new CommandExecutedEvent(COMMAND));
+
+			verify(listener).setAntragBewilligung(COMMAND);
+		}
+	}
+
+	@Nested
+	class TestSetAntragBewilligung {
+
+		private static final Command COMMAND = CommandTestFactory.create();
+
+		@Test
+		void shouldCallGetItem() {
+			listener.setAntragBewilligung(COMMAND);
+
+			verify(attachedItemService).getItem(CommandTestFactory.RELATION_ID);
+		}
+
+		@Test
+		void shouldCallSetAntragBewilligung() {
+			var item = AttachedItemTestFactory.createBescheid();
+			when(attachedItemService.getItem(any())).thenReturn(item);
+
+			listener.setAntragBewilligung(COMMAND);
+
+			verify(service).setAntragBewilligung(item);
+		}
+	}
+
 	@Nested
 	class TestRunWithSecurityContext {
 
diff --git a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/BescheidServiceTest.java b/bescheid-manager/src/test/java/de/ozgcloud/bescheid/BescheidServiceTest.java
index 6697f5fe8687a7524464e3a2fb01b1f86ff4cd62..c810b402d1b51e1b1cea5017f3fcaf7530c1d690 100644
--- a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/BescheidServiceTest.java
+++ b/bescheid-manager/src/test/java/de/ozgcloud/bescheid/BescheidServiceTest.java
@@ -1,15 +1,21 @@
 package de.ozgcloud.bescheid;
 
 import static org.assertj.core.api.Assertions.*;
+import static org.assertj.core.api.InstanceOfAssertFactories.*;
 import static org.junit.jupiter.api.Assertions.*;
 import static org.mockito.ArgumentMatchers.*;
 import static org.mockito.Mockito.*;
 
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.ChronoUnit;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 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.DisplayName;
 import org.junit.jupiter.api.Nested;
@@ -26,20 +32,30 @@ import org.mockito.Spy;
 import org.springframework.boot.info.BuildProperties;
 import org.springframework.test.util.ReflectionTestUtils;
 
+import de.ozgcloud.apilib.common.command.OzgCloudCommand;
+import de.ozgcloud.apilib.common.command.OzgCloudCommandService;
+import de.ozgcloud.apilib.common.command.OzgCloudCreateSubCommandsRequest;
+import de.ozgcloud.apilib.common.command.grpc.CommandMapper;
+import de.ozgcloud.apilib.common.datatypes.GenericId;
+import de.ozgcloud.apilib.user.OzgCloudUserId;
+import de.ozgcloud.apilib.vorgang.OzgCloudVorgangId;
 import de.ozgcloud.bescheid.attacheditem.AttachedItem;
 import de.ozgcloud.bescheid.attacheditem.AttachedItemService;
 import de.ozgcloud.bescheid.attacheditem.AttachedItemTestFactory;
 import de.ozgcloud.bescheid.attributes.ClientAttributeService;
 import de.ozgcloud.bescheid.common.user.UserProfile;
 import de.ozgcloud.bescheid.common.user.UserProfileService;
-import de.ozgcloud.bescheid.nachricht.NachrichtService;
+import de.ozgcloud.bescheid.common.user.UserProfileTestFactory;
+import de.ozgcloud.bescheid.vorgang.PostfachAddressTestFactory;
 import de.ozgcloud.bescheid.vorgang.ServiceKontoTestFactory;
 import de.ozgcloud.bescheid.vorgang.Vorgang;
 import de.ozgcloud.bescheid.vorgang.VorgangId;
 import de.ozgcloud.bescheid.vorgang.VorgangService;
 import de.ozgcloud.bescheid.vorgang.VorgangTestFactory;
+import de.ozgcloud.command.Command;
 import de.ozgcloud.command.CommandTestFactory;
 import de.ozgcloud.common.binaryfile.FileId;
+import de.ozgcloud.common.datatype.StringBasedValue;
 import de.ozgcloud.common.errorhandling.TechnicalException;
 import de.ozgcloud.document.DocumentTestFactory;
 
@@ -52,19 +68,19 @@ class BescheidServiceTest {
 	@Mock
 	private VorgangService vorgangService;
 	@Mock
-	private BescheidRemoteService remoteService;
-	@Mock
 	private AttachedItemService attachedItemService;
 	@Mock
-	private NachrichtService nachrichtService;
-	@Mock
 	private UserProfileService userProfileService;
 	@Mock
-	private UserProfile callContextUser;
+	private OzgCloudCommandService commandService;
+	@Mock
+	private CommandMapper commandMapper;
 	@Mock
 	private ClientAttributeService clientAttributeService;
 	@Mock
 	private BuildProperties buildProperties;
+	@Mock
+	private BescheidRemoteService remoteService;
 
 	@BeforeEach
 	void init() {
@@ -110,11 +126,23 @@ class BescheidServiceTest {
 	@Nested
 	class TestSendBescheidManually {
 
+		private static final Vorgang VORGANG = VorgangTestFactory.create();
+
+		@Mock
+		private OzgCloudCommand subCommand;
+
+		@Captor
+		private ArgumentCaptor<VorgangId> vorgangIdCaptor;
+
 		private final AttachedItem bescheidItem = AttachedItemTestFactory.createBescheid();
 
 		@BeforeEach
 		void init() {
 			doNothing().when(service).validateBescheidSendManually(any(), anyLong());
+			doNothing().when(service).addSubCommands(any(), any());
+			doReturn(UserProfileTestFactory.ID_STR).when(service).getUserId();
+			doReturn(List.of(subCommand)).when(service).buildSetBescheidSentSubCommands(any(), any(), any());
+			when(vorgangService.getById(any())).thenReturn(VORGANG);
 		}
 
 		@Test
@@ -125,14 +153,37 @@ class BescheidServiceTest {
 		}
 
 		@Test
-		void shouldCallSendBescheid() {
+		void shouldCallGetVorgang() {
 			sendBescheid();
 
-			verify(service).setBescheidSent(bescheidItem);
+			verify(vorgangService).getById(vorgangIdCaptor.capture());
+			assertThat(vorgangIdCaptor.getValue()).hasToString(CommandTestFactory.VORGANG_ID);
+		}
+
+		@Test
+		void shouldCallGetUserId() {
+			sendBescheid();
+
+			verify(service).getUserId();
+		}
+
+		@Test
+		void shouldCallBuildSetBescheidSentSubCommands() {
+			sendBescheid();
+
+			verify(service).buildSetBescheidSentSubCommands(bescheidItem, VORGANG, UserProfileTestFactory.ID_STR);
+		}
+
+		@Test
+		void shouldCallAddSubCommands() {
+			sendBescheid();
+
+			verify(service).addSubCommands(CommandTestFactory.ID, List.of(subCommand));
 		}
 
 		private void sendBescheid() {
-			service.sendBescheidManually(bescheidItem, AttachedItemTestFactory.VERSION);
+			var parentCommand = CommandTestFactory.createBuilder().relationVersion(AttachedItemTestFactory.VERSION).build();
+			service.sendBescheidManually(bescheidItem, parentCommand);
 		}
 	}
 
@@ -171,38 +222,42 @@ class BescheidServiceTest {
 	@Nested
 	class TestSendBescheidPostfachMail {
 
-		private AttachedItem bescheidItem;
+		private static final Command PARENT_COMMAND = CommandTestFactory.createBuilder().relationVersion(AttachedItemTestFactory.VERSION).build();
+		private static final Vorgang.ServiceKonto SERVICE_KONTO = ServiceKontoTestFactory.create();
+		private static final Vorgang VORGANG = VorgangTestFactory.createBuilder().serviceKonto(SERVICE_KONTO).build();
+
+		private static final AttachedItem BESCHEID_ITEM = AttachedItemTestFactory.createBescheid();
+
 		@Mock
-		private AttachedItem bescheidSendItem;
+		private OzgCloudCommand setBescheidSentSubCommand;
+		@Mock
+		private OzgCloudCommand sendPostfachNachrichtSubCommand;
 		@Captor
 		private ArgumentCaptor<VorgangId> vorgangIdCaptor;
+		@Captor
+		private ArgumentCaptor<List<OzgCloudCommand>> subCommandsCaptor;
 
 		@BeforeEach
 		void init() {
-			var item = AttachedItemTestFactory.createBescheidItem();
-			item.put(Bescheid.FIELD_SEND_BY, Bescheid.SendBy.NACHRICHT.name());
-			bescheidItem = AttachedItemTestFactory.createBescheidBuilder().item(item).build();
-
 			doNothing().when(service).validateBescheidSendPostfach(any(), anyLong());
-			lenient().when(callContextUser.getId()).thenReturn(UserId.from("user-id"));
-			lenient().when(userProfileService.getUserProfile()).thenReturn(callContextUser);
+			doNothing().when(service).addSubCommands(any(), any());
+			doReturn(UserProfileTestFactory.ID_STR).when(service).getUserId();
+			var subCommands = new ArrayList<OzgCloudCommand>();
+			subCommands.add(setBescheidSentSubCommand);
+			doReturn(subCommands).when(service).buildSetBescheidSentSubCommands(any(), any(), any());
+			doReturn(sendPostfachNachrichtSubCommand).when(service).buildSendPostfachNachrichtCommand(any(), any(), any());
+			when(vorgangService.getById(any())).thenReturn(VORGANG);
 		}
 
 		@Test
 		void shouldCallValidateBescheid() {
-			doReturn(BescheidTestFactory.create()).when(service).buildBescheid(any(), any());
-			when(vorgangService.getById(any())).thenReturn(VorgangTestFactory.create());
-
 			sendBescheid();
 
-			verify(service).validateBescheidSendPostfach(bescheidItem, AttachedItemTestFactory.VERSION);
+			verify(service).validateBescheidSendPostfach(BESCHEID_ITEM, AttachedItemTestFactory.VERSION);
 		}
 
 		@Test
 		void shouldCallVorgangService() {
-			doReturn(BescheidTestFactory.create()).when(service).buildBescheid(any(), any());
-			when(vorgangService.getById(any())).thenReturn(VorgangTestFactory.create());
-
 			sendBescheid();
 
 			verify(vorgangService).getById(vorgangIdCaptor.capture());
@@ -210,40 +265,36 @@ class BescheidServiceTest {
 		}
 
 		@Test
-		void shouldCallBuildBescheid() {
-			doReturn(BescheidTestFactory.create()).when(service).buildBescheid(any(), any());
-			var serviceKonto = ServiceKontoTestFactory.create();
-			var vorgang = VorgangTestFactory.createBuilder().serviceKonto(serviceKonto).build();
-			doReturn(vorgang).when(vorgangService).getById(any());
-
+		void shouldCallGetUserId() {
 			sendBescheid();
 
-			verify(service).buildBescheid(bescheidItem, serviceKonto);
+			verify(service).getUserId();
 		}
 
 		@Test
-		void shouldCallNachrichtService() {
-			var bescheid = BescheidTestFactory.create();
-			doReturn(bescheid).when(service).buildBescheid(any(), any());
-			when(vorgangService.getById(any())).thenReturn(VorgangTestFactory.create());
-
+		void shouldCallBuildSetBescheidSentSubCommands() {
 			sendBescheid();
 
-			verify(nachrichtService).sendNachricht(bescheid);
+			verify(service).buildSetBescheidSentSubCommands(BESCHEID_ITEM, VORGANG, UserProfileTestFactory.ID_STR);
 		}
 
 		@Test
-		void shouldCallSendBescheid() {
-			doReturn(BescheidTestFactory.create()).when(service).buildBescheid(any(), any());
-			when(vorgangService.getById(any())).thenReturn(VorgangTestFactory.create());
+		void shouldCallBuildSendPostfachNachrichtCommand() {
+			sendBescheid();
+
+			verify(service).buildSendPostfachNachrichtCommand(BESCHEID_ITEM, SERVICE_KONTO, UserProfileTestFactory.ID_STR);
+		}
 
+		@Test
+		void shouldCallAddSubCommands() {
 			sendBescheid();
 
-			verify(service).setBescheidSent(bescheidItem);
+			verify(service).addSubCommands(eq(CommandTestFactory.ID), subCommandsCaptor.capture());
+			assertThat(subCommandsCaptor.getValue()).containsExactly(setBescheidSentSubCommand, sendPostfachNachrichtSubCommand);
 		}
 
 		private void sendBescheid() {
-			service.sendBescheidPostfachMail(bescheidItem, AttachedItemTestFactory.VERSION);
+			service.sendBescheidPostfachMail(BESCHEID_ITEM, PARENT_COMMAND);
 		}
 	}
 
@@ -352,114 +403,6 @@ class BescheidServiceTest {
 		}
 	}
 
-	@Nested
-	class TestBuildBescheid {
-
-		private static final AttachedItem BESCHEID_ITEM = AttachedItemTestFactory.createBescheid();
-		private static final Vorgang.ServiceKonto SERVICE_KONTO = ServiceKontoTestFactory.create();
-		private static final String CREATED_BY = "user-id";
-
-		@BeforeEach
-		void init() {
-			when(callContextUser.getId()).thenReturn(UserId.from(CREATED_BY));
-			when(userProfileService.getUserProfile()).thenReturn(callContextUser);
-			doReturn(FileId.from(DocumentTestFactory.DOCUMENT_FILE)).when(service).getBescheidFileId(any());
-		}
-
-		@Test
-		void shouldSetVorgangId() {
-			var result = buildBescheid();
-
-			assertThat(result.getVorgangId()).hasToString(CommandTestFactory.VORGANG_ID);
-		}
-
-		@Test
-		void shouldCallGetBewilligt() {
-			buildBescheid();
-
-			verify(service).getBewilligt(BESCHEID_ITEM);
-		}
-
-		@Test
-		void shouldSetGenehmigt() {
-			doReturn(true).when(service).getBewilligt(any());
-
-			var result = buildBescheid();
-
-			assertThat(result.isGenehmigt()).isTrue();
-		}
-
-		@Test
-		void shouldCallGetAttachments() {
-			buildBescheid();
-
-			verify(service).getAttachments(BESCHEID_ITEM);
-		}
-
-		@Test
-		void shouldSetAttachments() {
-			var expectedAttachments = List.of(FileId.from(AttachedItemTestFactory.ATTACHMENT));
-			doReturn(expectedAttachments).when(service).getAttachments(any());
-
-			var result = buildBescheid();
-
-			assertThat(result.getAttachments()).containsExactlyElementsOf(expectedAttachments);
-		}
-
-		@Test
-		void shouldCallGetBescheidFileId() {
-			buildBescheid();
-
-			verify(service).getBescheidFileId(BESCHEID_ITEM);
-		}
-
-		@Test
-		void shouldSetBescheidFileId() {
-			var result = buildBescheid();
-
-			assertThat(result.getBescheidFileId()).hasToString(DocumentTestFactory.DOCUMENT_FILE);
-		}
-
-		@Test
-		void shouldSetNachrichtSubject() {
-			var result = buildBescheid();
-
-			assertThat(result.getNachrichtSubject()).contains(AttachedItemTestFactory.NACHRICHT_SUBJECT);
-		}
-
-		@Test
-		void shouldSetNachrichtText() {
-			var result = buildBescheid();
-
-			assertThat(result.getNachrichtText()).contains(AttachedItemTestFactory.NACHRICHT_TEXT);
-		}
-
-		@Test
-		void shouldCallCurrentUserService() {
-			buildBescheid();
-
-			verify(userProfileService).getUserProfile();
-		}
-
-		@Test
-		void shouldSetCreatedBy() {
-			var result = buildBescheid();
-
-			assertThat(result.getCreatedBy()).hasToString(CREATED_BY);
-		}
-
-		@Test
-		void shouldSetServiceKonto() {
-			var result = buildBescheid();
-
-			assertThat(result.getServiceKonto()).usingRecursiveComparison().isEqualTo(SERVICE_KONTO);
-		}
-
-		private Bescheid buildBescheid() {
-			return service.buildBescheid(BESCHEID_ITEM, SERVICE_KONTO);
-		}
-	}
-
 	@Nested
 	class TestGetAttachments {
 
@@ -540,6 +483,33 @@ class BescheidServiceTest {
 		}
 	}
 
+	@Nested
+	class TestAddSubCommands {
+
+		@Mock
+		private OzgCloudCommand subCommand;
+		@Mock
+		private OzgCloudCreateSubCommandsRequest createSubCommandsRequest;
+
+		@Test
+		void shouldCallBuildCreateSubCommandsRequest() {
+			var subCommands = List.of(subCommand);
+
+			service.addSubCommands(CommandTestFactory.ID, subCommands);
+
+			verify(service).buildCreateSubCommandsRequest(CommandTestFactory.ID, subCommands);
+		}
+
+		@Test
+		void shouldCallCommandService() {
+			doReturn(createSubCommandsRequest).when(service).buildCreateSubCommandsRequest(any(), any());
+
+			service.addSubCommands(CommandTestFactory.ID, List.of(subCommand));
+
+			verify(commandService).addSubCommands(createSubCommandsRequest);
+		}
+	}
+
 	@Nested
 	class TestGetBescheidFileId {
 
@@ -573,7 +543,7 @@ class BescheidServiceTest {
 
 			var result = service.getNachrichtSubject(bescheidItem);
 
-			assertThat(result).isEqualTo(AttachedItemTestFactory.NACHRICHT_SUBJECT);
+			assertThat(result).contains(AttachedItemTestFactory.NACHRICHT_SUBJECT);
 		}
 	}
 
@@ -587,49 +557,537 @@ class BescheidServiceTest {
 
 			var result = service.getNachrichtText(bescheidItem);
 
-			assertThat(result).isEqualTo(AttachedItemTestFactory.NACHRICHT_TEXT);
+			assertThat(result).contains(AttachedItemTestFactory.NACHRICHT_TEXT);
 		}
 	}
 
 	@Nested
-	class TestSendBescheid {
+	class TestGetUserId {
 
-		private final AttachedItem bescheidItem = AttachedItemTestFactory.createBescheid();
 		@Mock
-		private AttachedItem bescheidSendItem;
+		private UserProfile userProfile;
+
+		@BeforeEach
+		void init() {
+			when(userProfileService.getUserProfile()).thenReturn(userProfile);
+			when(userProfile.getId()).thenReturn(UserProfileTestFactory.ID);
+
+		}
 
 		@Test
-		void shouldCallSetBescheidStatusSent() {
-			sendBescheid();
+		void shouldCallGetUserProfile() {
+			service.getUserId();
 
-			verify(attachedItemService).setBescheidSentStatus(AttachedItemTestFactory.ID, AttachedItemTestFactory.VERSION);
+			verify(userProfileService).getUserProfile();
 		}
 
 		@Test
-		void shouldCallBescheiden() {
-			sendBescheid();
+		void shouldReturnUserId() {
+			var result = service.getUserId();
+
+			assertThat(result).isEqualTo(UserProfileTestFactory.ID_STR);
+		}
+	}
+
+	@Nested
+	class TestBuildSetBescheidSentCommands {
+
+		@Mock
+		private AttachedItem bescheidItem;
+		@Mock
+		private Vorgang vorgang;
+		@Mock
+		private OzgCloudCommand vorgangBescheidenCommand;
+		@Mock
+		private OzgCloudCommand setBescheidSentStatusCommand;
 
-			verify(vorgangService).bescheiden(CommandTestFactory.VORGANG_ID);
+		@BeforeEach
+		void inti() {
+			doReturn(vorgangBescheidenCommand).when(service).buildVorgangBescheidenCommand(any());
+			doReturn(setBescheidSentStatusCommand).when(service).buildSetBescheidSentStatusCommand(any(), any());
 		}
 
 		@Test
-		void shouldCallRevertBescheidStatusSent() {
-			doThrow(new TechnicalException("error")).when(vorgangService).bescheiden(anyString());
+		void shouldCallBuildVorgangBescheidenCommand() {
+			buildSetBescheidSentCommands();
 
-			assertThrows(TechnicalException.class, this::sendBescheid);
+			verify(service).buildVorgangBescheidenCommand(vorgang);
+		}
 
-			verify(attachedItemService).revertBescheidSendStatus(AttachedItemTestFactory.ID, AttachedItemTestFactory.VERSION);
+		@Test
+		void shouldCallBuildSetBescheidSentStatusCommand() {
+			buildSetBescheidSentCommands();
+
+			verify(service).buildSetBescheidSentStatusCommand(bescheidItem, UserProfileTestFactory.ID_STR);
 		}
 
 		@Test
-		void shouldCallSetAntragResult() {
-			sendBescheid();
+		void shouldReturnResult() {
+			var result = buildSetBescheidSentCommands();
 
-			verify(service).setAntragBewilligung(bescheidItem);
+			assertThat(result).containsExactly(vorgangBescheidenCommand, setBescheidSentStatusCommand);
 		}
 
-		private void sendBescheid() {
-			service.setBescheidSent(bescheidItem);
+		private List<OzgCloudCommand> buildSetBescheidSentCommands() {
+			return service.buildSetBescheidSentSubCommands(bescheidItem, vorgang, UserProfileTestFactory.ID_STR);
+		}
+	}
+
+	@Nested
+	class TestBuildVorgangBescheidenCommand {
+
+		private static final OzgCloudVorgangId VORGANG_ID = OzgCloudVorgangId.from(VorgangTestFactory.ID.toString());
+		private static final StringBasedValue RELATION_ID = GenericId.from(VorgangTestFactory.ID.toString());
+
+		@BeforeEach
+		void init() {
+			when(commandMapper.toOzgCloudVorgangId(anyString())).thenReturn(VORGANG_ID);
+			when(commandMapper.mapRelationId(anyString())).thenReturn(RELATION_ID);
+		}
+
+		@Test
+		void shouldCallMapVorgangId() {
+			buildVorgangBescheidenCommand();
+
+			verify(commandMapper).toOzgCloudVorgangId(VorgangTestFactory.ID.toString());
+		}
+
+		@Test
+		void shouldSetVorgangId() {
+			var result = buildVorgangBescheidenCommand();
+
+			assertThat(result.getVorgangId()).isEqualTo(VORGANG_ID);
+		}
+
+		@Test
+		void shouldCallMapRelationId() {
+			buildVorgangBescheidenCommand();
+
+			verify(commandMapper).mapRelationId(VorgangTestFactory.ID.toString());
+		}
+
+		@Test
+		void shouldSetRelationId() {
+			var result = buildVorgangBescheidenCommand();
+
+			assertThat(result.getRelationId()).isEqualTo(RELATION_ID);
+		}
+
+		@Test
+		void shouldSetRelationVersion() {
+			var result = buildVorgangBescheidenCommand();
+
+			assertThat(result.getRelationVersion()).isEqualTo(VorgangTestFactory.VERSION);
+		}
+
+		@Test
+		void shouldSetOrder() {
+			var result = buildVorgangBescheidenCommand();
+
+			assertThat(result.getOrder()).isEqualTo(BescheidService.VORGANG_BESCHEIDEN_ORDER);
+		}
+
+		private OzgCloudCommand buildVorgangBescheidenCommand() {
+			return service.buildVorgangBescheidenCommand(VorgangTestFactory.create());
+		}
+	}
+
+	@Nested
+	class TestBuildSetBescheidSentStatusCommand {
+
+		private static final StringBasedValue RELATION_ID = GenericId.from(VorgangTestFactory.ID.toString());
+		private static final AttachedItem BESCHEID_ITEM = AttachedItemTestFactory.createBescheid();
+
+		@BeforeEach
+		void init() {
+			when(commandMapper.mapRelationId(any())).thenReturn(RELATION_ID);
+		}
+
+		@Test
+		void shouldCallMapRelationId() {
+			buildSetBescheidSentStatusCommand();
+
+			verify(commandMapper).mapRelationId(AttachedItemTestFactory.ID);
+		}
+
+		@Test
+		void shouldSetRelationId() {
+			var result = buildSetBescheidSentStatusCommand();
+
+			assertThat(result.getRelationId()).isEqualTo(RELATION_ID);
+		}
+
+		@Test
+		void shouldSetRelationVersion() {
+			var result = buildSetBescheidSentStatusCommand();
+
+			assertThat(result.getRelationVersion()).isEqualTo(AttachedItemTestFactory.VERSION);
+		}
+
+		@Test
+		void shouldSetOrder() {
+			var result = buildSetBescheidSentStatusCommand();
+
+			assertThat(result.getOrder()).isEqualTo(AttachedItemService.PATCH_ATTACHED_ITEM);
+		}
+
+		@Test
+		void shouldSetPropertyId() {
+			var result = buildSetBescheidSentStatusCommand();
+
+			assertThat(result.getBodyObject()).containsEntry(AttachedItem.PROPERTY_ID, AttachedItemTestFactory.ID);
+		}
+
+		@Test
+		void shouldCallBuildBescheidSentStatusItem() {
+			buildSetBescheidSentStatusCommand();
+
+			verify(service).buildBescheidSentStatusItem(UserProfileTestFactory.ID_STR);
+		}
+
+		@Test
+		void shouldSetPropertyItem() {
+			var itemMap = Map.of("key", "value");
+			doReturn(itemMap).when(service).buildBescheidSentStatusItem(any());
+
+			var result = buildSetBescheidSentStatusCommand();
+
+			assertThat(result.getBodyObject()).containsEntry(AttachedItem.PROPERTY_ITEM, itemMap);
+		}
+
+		private OzgCloudCommand buildSetBescheidSentStatusCommand() {
+			return service.buildSetBescheidSentStatusCommand(BESCHEID_ITEM, UserProfileTestFactory.ID_STR);
+		}
+	}
+
+	@Nested
+	class TestBuildBescheidSentStatusItem {
+
+		@Test
+		void shouldSetStatus() {
+			var result = service.buildBescheidSentStatusItem(UserProfileTestFactory.ID_STR);
+
+			assertThat(result).containsEntry(Bescheid.FIELD_STATUS, Bescheid.Status.SENT.name());
+		}
+
+		@Test
+		void shouldCallBuildSentInfoMap() {
+			service.buildBescheidSentStatusItem(UserProfileTestFactory.ID_STR);
+
+			verify(service).buildSentInfoMap(UserProfileTestFactory.ID_STR);
+		}
+
+		@Test
+		void shouldSetSentInfo() {
+			var sentInfoMap = Map.of("key", "value");
+			doReturn(sentInfoMap).when(service).buildSentInfoMap(any());
+
+			var result = service.buildBescheidSentStatusItem(UserProfileTestFactory.ID_STR);
+
+			assertThat(result).containsEntry(Bescheid.FIELD_SENT_INFO, sentInfoMap);
+		}
+	}
+
+	@Nested
+	class TestBuildSentInfoMap {
+
+		@Test
+		void shouldSetSentAt() {
+			var result = service.buildSentInfoMap(UserProfileTestFactory.ID_STR);
+
+			assertThat(getSentAt(result)).isCloseTo(ZonedDateTime.now(), within(1, ChronoUnit.SECONDS));
+		}
+
+		@Test
+		void shouldSetSentBy() {
+			var result = service.buildSentInfoMap(UserProfileTestFactory.ID_STR);
+
+			assertThat(result).containsEntry(Bescheid.FIELD_SENT_BY, UserProfileTestFactory.ID_STR);
+		}
+
+		private ZonedDateTime getSentAt(Map<String, Object> sentInfoMap) {
+			return ZonedDateTime.parse((String) sentInfoMap.get(Bescheid.FIELD_SENT_AT), DateTimeFormatter.ISO_DATE_TIME);
+		}
+	}
+
+	@Nested
+	class TestBuildSendPostfachNachrichtCommand {
+
+		private static final AttachedItem BESCHEID_ITEM = AttachedItemTestFactory.createBescheid();
+		private static final Vorgang.PostfachAddress POSTFACH_ADDRESS = PostfachAddressTestFactory.create();
+		private static final Vorgang.ServiceKonto SERVICE_KONTO = ServiceKontoTestFactory.createBuilder().clearPostfachAddresses()
+				.postfachAddress(POSTFACH_ADDRESS).build();
+		private static final OzgCloudUserId OZG_CLOUD_ID = OzgCloudUserId.from(UserProfileTestFactory.ID_STR);
+		private static final Map<String, Object> OBJECT_MAP = Map.of("key", "value");
+		private static final OzgCloudVorgangId VORGANG_ID = OzgCloudVorgangId.from(VorgangTestFactory.ID.toString());
+		private static final StringBasedValue RELATION_ID = GenericId.from(VorgangTestFactory.ID.toString());
+
+		@BeforeEach
+		void init() {
+			when(commandMapper.toOzgCloudVorgangId(anyString())).thenReturn(VORGANG_ID);
+			when(commandMapper.mapRelationId(anyString())).thenReturn(RELATION_ID);
+			when(commandMapper.toOzgCloudUserId(anyString())).thenReturn(OZG_CLOUD_ID);
+			doReturn(OBJECT_MAP).when(service).buildSendNachrichtCommandBody(any(), any());
+		}
+
+		@Test
+		void shouldCallBuildPostfachAddress() {
+			buildSendPostfachNachrichtCommand();
+
+			verify(service).buildPostfachAddress(POSTFACH_ADDRESS, ServiceKontoTestFactory.TYPE);
+		}
+
+		@Test
+		void shouldCallBuildSenNachrichtCommandBody() {
+			var postfachAddressMap = Map.<String, Object>of("key", "value");
+			doReturn(postfachAddressMap).when(service).buildPostfachAddress(any(), any());
+
+			buildSendPostfachNachrichtCommand();
+
+			verify(service).buildSendNachrichtCommandBody(BESCHEID_ITEM, postfachAddressMap);
+		}
+
+		@Test
+		void shouldSetBodyObject() {
+			var result = buildSendPostfachNachrichtCommand();
+
+			assertThat(result.getBodyObject()).isSameAs(OBJECT_MAP);
+		}
+
+		@Test
+		void shouldCallMapVorgangId() {
+			buildSendPostfachNachrichtCommand();
+
+			verify(commandMapper).toOzgCloudVorgangId(CommandTestFactory.VORGANG_ID);
+		}
+
+		@Test
+		void shouldSetVorgangId() {
+			var result = buildSendPostfachNachrichtCommand();
+
+			assertThat(result.getVorgangId()).isEqualTo(VORGANG_ID);
+		}
+
+		@Test
+		void shouldCallMapRelationId() {
+			buildSendPostfachNachrichtCommand();
+
+			verify(commandMapper).mapRelationId(CommandTestFactory.VORGANG_ID);
+		}
+
+		@Test
+		void shouldSetRelationId() {
+			var result = buildSendPostfachNachrichtCommand();
+
+			assertThat(result.getRelationId()).isEqualTo(RELATION_ID);
+		}
+
+		@Test
+		void shouldSetOrder() {
+			var result = buildSendPostfachNachrichtCommand();
+
+			assertThat(result.getOrder()).isEqualTo(BescheidService.SEND_POSTFACH_NACHRICHT_ORDER);
+		}
+
+		@Test
+		void shouldCallMapToOzgCloudUserId() {
+			buildSendPostfachNachrichtCommand();
+
+			verify(commandMapper).toOzgCloudUserId(UserProfileTestFactory.ID_STR);
+		}
+
+		@Test
+		void shouldSetCreatedBy() {
+			var result = buildSendPostfachNachrichtCommand();
+
+			assertThat(result.getCreatedBy()).isEqualTo(OZG_CLOUD_ID);
+		}
+
+		private OzgCloudCommand buildSendPostfachNachrichtCommand() {
+			return service.buildSendPostfachNachrichtCommand(BESCHEID_ITEM, SERVICE_KONTO, UserProfileTestFactory.ID_STR);
+		}
+	}
+
+	@Nested
+	class TestBuildPostfachAddress {
+
+		@Test
+		void shouldSetType() {
+			var result = buildPostfachAddress();
+
+			assertThat(result).containsEntry(Vorgang.PostfachAddress.FIELD_TYPE, PostfachAddressTestFactory.TYPE);
+		}
+
+		@Test
+		void shouldSetVersion() {
+			var result = buildPostfachAddress();
+
+			assertThat(result).containsEntry(Vorgang.PostfachAddress.FIELD_VERSION, PostfachAddressTestFactory.VERSION);
+		}
+
+		@Test
+		void shouldSetIdentifier() {
+			var result = buildPostfachAddress();
+
+			assertThat(result).extracting(Vorgang.PostfachAddress.FIELD_IDENTIFIER, MAP)
+					.containsEntry(BescheidService.FIELD_POSTFACH_ID, PostfachAddressTestFactory.POSTFACH_ID);
+		}
+
+		@Test
+		void shouldSetServicekontoType() {
+			var result = buildPostfachAddress();
+
+			assertThat(result).containsEntry(Vorgang.ServiceKonto.FIELD_SERVICEKONTO_TYPE, ServiceKontoTestFactory.TYPE);
+		}
+
+		private Map<String, Object> buildPostfachAddress() {
+			return service.buildPostfachAddress(PostfachAddressTestFactory.create(), ServiceKontoTestFactory.TYPE);
+		}
+	}
+
+	@Nested
+	class TestBuildSendNachrichtCommandBody {
+
+		private static final Map<String, Object> SERVICE_KONTO_MAP = Map.of("key", "value");
+
+		@Mock
+		private AttachedItem bescheidItem;
+
+		private Map<String, Object> buildSendNachrichtCommandBody() {
+			return service.buildSendNachrichtCommandBody(bescheidItem, SERVICE_KONTO_MAP);
+		}
+
+		@Nested
+		class TestWithValuesFromBescheidItem {
+
+			@BeforeEach
+			void init() {
+				doReturn(Optional.of(AttachedItemTestFactory.NACHRICHT_SUBJECT)).when(service).getNachrichtSubject(any());
+				doReturn(Optional.of(AttachedItemTestFactory.NACHRICHT_TEXT)).when(service).getNachrichtText(any());
+				doReturn(List.of(AttachedItemTestFactory.ATTACHMENT)).when(service).buildAttachments(any());
+			}
+
+			@Test
+			void shouldSetReplyOption() {
+				var result = buildSendNachrichtCommandBody();
+
+				assertThat(result).containsEntry(BescheidService.FIELD_REPLY_OPTION, BescheidService.REPLY_OPTION);
+			}
+
+			@Test
+			void shouldCallGetNachrichtSubject() {
+				buildSendNachrichtCommandBody();
+
+				verify(service).getNachrichtSubject(bescheidItem);
+			}
+
+			@Test
+			void shouldSetSubject() {
+				var result = buildSendNachrichtCommandBody();
+
+				assertThat(result).containsEntry(BescheidService.FIELD_SUBJECT, AttachedItemTestFactory.NACHRICHT_SUBJECT);
+			}
+
+			@Test
+			void shouldCallGetNachrichtText() {
+				buildSendNachrichtCommandBody();
+
+				verify(service).getNachrichtText(bescheidItem);
+			}
+
+			@Test
+			void shouldSetMailBody() {
+				var result = buildSendNachrichtCommandBody();
+
+				assertThat(result).containsEntry(BescheidService.FIELD_MAIL_BODY, AttachedItemTestFactory.NACHRICHT_TEXT);
+			}
+
+			@Test
+			void shouldCallBuildAttachments() {
+				buildSendNachrichtCommandBody();
+
+				verify(service).buildAttachments(bescheidItem);
+			}
+
+			@Test
+			void shouldSetAttachments() {
+				var result = buildSendNachrichtCommandBody();
+
+				assertThat(result).extracting(BescheidService.FIELD_ATTACHMENTS, LIST).containsExactly(AttachedItemTestFactory.ATTACHMENT);
+			}
+
+			@Test
+			void shouldSetPostfachAddress() {
+				var result = buildSendNachrichtCommandBody();
+
+				assertThat(result).containsEntry(Vorgang.ServiceKonto.FIELD_POSTFACH_ADDRESS, SERVICE_KONTO_MAP);
+			}
+		}
+
+		@Nested
+		class TestWithDefaultValues {
+
+			@BeforeEach
+			void init() {
+				doReturn(Optional.empty()).when(service).getNachrichtSubject(any());
+				doReturn(Optional.empty()).when(service).getNachrichtText(any());
+				doReturn(Collections.emptyList()).when(service).buildAttachments(any());
+			}
+
+			@Test
+			void shouldSetSubject() {
+				var result = buildSendNachrichtCommandBody();
+
+				assertThat(result).containsEntry(BescheidService.FIELD_SUBJECT, BescheidService.SUBJECT);
+			}
+
+			@Test
+			void shouldSetMailBody() {
+				var result = buildSendNachrichtCommandBody();
+
+				assertThat(result).containsEntry(BescheidService.FIELD_MAIL_BODY, StringUtils.EMPTY);
+			}
+		}
+	}
+
+	@Nested
+	class TestBuildAttachments {
+
+		private static final String BESCHEID_FILE_ID = "bescheid-file-id";
+		private static final String ATTACHMENT_FILE_ID = "attachment-file-id";
+
+		@Mock
+		private AttachedItem bescheidItem;
+
+		@BeforeEach
+		void init() {
+			doReturn(FileId.from(BESCHEID_FILE_ID)).when(service).getBescheidFileId(any());
+			doReturn(List.of(FileId.from(ATTACHMENT_FILE_ID))).when(service).getAttachments(any());
+		}
+
+		@Test
+		void shouldCallGetBescheidFileId() {
+			buildAttachments();
+
+			verify(service).getBescheidFileId(bescheidItem);
+		}
+
+		@Test
+		void shouldCallGetAttachments() {
+			buildAttachments();
+
+			verify(service).getAttachments(bescheidItem);
+		}
+
+		@Test
+		void shouldReturnAllAttachments() {
+			var result = buildAttachments();
+
+			assertThat(result).containsExactly(BESCHEID_FILE_ID, ATTACHMENT_FILE_ID);
+		}
+
+		private List<String> buildAttachments() {
+			return service.buildAttachments(bescheidItem);
 		}
 	}
 
diff --git a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/BescheidTestApplication.java b/bescheid-manager/src/test/java/de/ozgcloud/bescheid/BescheidTestApplication.java
index 28c3e88f5c362906b9288319b4062347daeea5f2..9bbaa5728dc689fe6d70fe510af8ae909b65ae7f 100644
--- a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/BescheidTestApplication.java
+++ b/bescheid-manager/src/test/java/de/ozgcloud/bescheid/BescheidTestApplication.java
@@ -1,6 +1,8 @@
 package de.ozgcloud.bescheid;
 
 import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.info.BuildProperties;
+import org.springframework.boot.test.mock.mockito.MockBean;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.ComponentScan;
 import org.springframework.security.authentication.AuthenticationTrustResolver;
@@ -10,6 +12,9 @@ import org.springframework.security.authentication.AuthenticationTrustResolverIm
 @ComponentScan({ "de.ozgcloud.*" })
 public class BescheidTestApplication {
 
+	@MockBean
+	private BuildProperties buildProperties;
+
 	@Bean
 	AuthenticationTrustResolver trustResolver() {
 		return new AuthenticationTrustResolverImpl();
diff --git a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/attacheditem/AttachedItemServiceTest.java b/bescheid-manager/src/test/java/de/ozgcloud/bescheid/attacheditem/AttachedItemServiceTest.java
index b70261e5222ae98734dfe4960ac3a20f98bb0ff8..9f4272fed782bba1aef9ea7236c4430752002e88 100644
--- a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/attacheditem/AttachedItemServiceTest.java
+++ b/bescheid-manager/src/test/java/de/ozgcloud/bescheid/attacheditem/AttachedItemServiceTest.java
@@ -28,15 +28,12 @@ import static org.junit.jupiter.api.Assertions.*;
 import static org.mockito.ArgumentMatchers.*;
 import static org.mockito.Mockito.*;
 
-import java.time.ZonedDateTime;
-import java.time.temporal.ChronoUnit;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 
-import org.apache.commons.collections.MapUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.DisplayName;
@@ -61,8 +58,6 @@ import de.ozgcloud.apilib.vorgang.OzgCloudVorgangId;
 import de.ozgcloud.bescheid.Bescheid;
 import de.ozgcloud.bescheid.Bescheid.SendBy;
 import de.ozgcloud.bescheid.BescheidCallContextAttachingInterceptor;
-import de.ozgcloud.bescheid.common.callcontext.CallContextUser;
-import de.ozgcloud.bescheid.common.callcontext.CurrentUserService;
 import de.ozgcloud.bescheid.common.freemarker.TemplateHandler;
 import de.ozgcloud.bescheid.vorgang.VorgangId;
 import de.ozgcloud.bescheid.vorgang.VorgangTestFactory;
@@ -86,8 +81,6 @@ class AttachedItemServiceTest {
 	@Mock
 	private VorgangAttachedItemRemoteService remoteService;
 	@Mock
-	private CurrentUserService currentUserService;
-	@Mock
 	private TemplateHandler templateHandler;
 
 	@Nested
@@ -451,12 +444,12 @@ class AttachedItemServiceTest {
 
 			doUpdateBescheidDraft();
 
-			verify(service).buildUpdateAttachedItemCommand(bescheidItem, expectedBodyObject);
+			verify(service).buildPatchAttachedItemCommand(bescheidItem, expectedBodyObject);
 		}
 
 		@Test
 		void shouldCallCommandService() {
-			doReturn(updateAttachedItemCommand).when(service).buildUpdateAttachedItemCommand(any(), any());
+			doReturn(updateAttachedItemCommand).when(service).buildPatchAttachedItemCommand(any(), any());
 
 			doUpdateBescheidDraft();
 
@@ -672,12 +665,12 @@ class AttachedItemServiceTest {
 
 			service.overrideAttachedItem(bescheidItem, command);
 
-			verify(service).buildUpdateAttachedItemCommand(bescheidItem, bodyObject);
+			verify(service).buildPatchAttachedItemCommand(bescheidItem, bodyObject);
 		}
 
 		@Test
 		void shouldCallCommandService() {
-			doReturn(updateItemCommand).when(service).buildUpdateAttachedItemCommand(any(), any());
+			doReturn(updateItemCommand).when(service).buildPatchAttachedItemCommand(any(), any());
 
 			service.overrideAttachedItem(AttachedItemTestFactory.createBescheid(), command);
 
@@ -853,7 +846,7 @@ class AttachedItemServiceTest {
 
 		@Test
 		void shouldCallVorgangIdMapper() {
-			service.buildUpdateAttachedItemCommand(AttachedItemTestFactory.createBescheid(), Map.of());
+			service.buildPatchAttachedItemCommand(AttachedItemTestFactory.createBescheid(), Map.of());
 
 			verify(commandMapper).toOzgCloudVorgangId(CommandTestFactory.VORGANG_ID);
 		}
@@ -863,14 +856,14 @@ class AttachedItemServiceTest {
 			var expectedVorgangId = OzgCloudVorgangId.from(CommandTestFactory.VORGANG_ID);
 			when(commandMapper.toOzgCloudVorgangId(any())).thenReturn(expectedVorgangId);
 
-			var result = service.buildUpdateAttachedItemCommand(AttachedItemTestFactory.createBescheid(), Map.of());
+			var result = service.buildPatchAttachedItemCommand(AttachedItemTestFactory.createBescheid(), Map.of());
 
 			assertThat(result.getVorgangId()).isEqualTo(expectedVorgangId);
 		}
 
 		@Test
 		void shouldCallRelationIdMapper() {
-			service.buildUpdateAttachedItemCommand(AttachedItemTestFactory.createBescheid(), Map.of());
+			service.buildPatchAttachedItemCommand(AttachedItemTestFactory.createBescheid(), Map.of());
 
 			verify(commandMapper).mapRelationId(AttachedItemTestFactory.ID);
 		}
@@ -880,30 +873,30 @@ class AttachedItemServiceTest {
 			var expectedId = GenericId.from("relationId");
 			when(commandMapper.mapRelationId(any())).thenReturn(expectedId);
 
-			var result = service.buildUpdateAttachedItemCommand(AttachedItemTestFactory.createBescheid(), Map.of());
+			var result = service.buildPatchAttachedItemCommand(AttachedItemTestFactory.createBescheid(), Map.of());
 
 			assertThat(result.getRelationId()).isEqualTo(expectedId);
 		}
 
 		@Test
 		void shouldSetRelationVersion() {
-			var result = service.buildUpdateAttachedItemCommand(AttachedItemTestFactory.createBescheid(), Map.of());
+			var result = service.buildPatchAttachedItemCommand(AttachedItemTestFactory.createBescheid(), Map.of());
 
 			assertThat(result.getRelationVersion()).isEqualTo(AttachedItemTestFactory.VERSION);
 		}
 
 		@Test
 		void shouldSetOrder() {
-			var result = service.buildUpdateAttachedItemCommand(AttachedItemTestFactory.createBescheid(), Map.of());
+			var result = service.buildPatchAttachedItemCommand(AttachedItemTestFactory.createBescheid(), Map.of());
 
-			assertThat(result.getOrder()).isEqualTo(AttachedItemService.UPDATE_ATTACHED_ITEM_ORDER);
+			assertThat(result.getOrder()).isEqualTo(AttachedItemService.PATCH_ATTACHED_ITEM);
 		}
 
 		@Test
 		void shouldSetBodyObject() {
 			var bodyObject = Map.<String, Object>of("key", "value");
 
-			var result = service.buildUpdateAttachedItemCommand(AttachedItemTestFactory.createBescheid(), bodyObject);
+			var result = service.buildPatchAttachedItemCommand(AttachedItemTestFactory.createBescheid(), bodyObject);
 
 			assertThat(result.getBodyObject()).containsAllEntriesOf(bodyObject);
 		}
@@ -1039,257 +1032,6 @@ class AttachedItemServiceTest {
 		}
 	}
 
-	@Nested
-	class TestSetBescheidSentStatus {
-
-		private static final Map<String, Object> BODY_OBJECT_MAP = Map.of("key", "value");
-
-		@Mock
-		private OzgCloudCommand command;
-
-		@BeforeEach
-		void init() {
-			doReturn(BODY_OBJECT_MAP).when(service).buildBescheidSentStatusBodyObject(any());
-		}
-
-		@Test
-		void shouldCallBuildPatchBescheidCommand() {
-			setBescheidStatusSent();
-
-			verify(service).buildPatchBescheidCommand(AttachedItemTestFactory.ID, AttachedItemTestFactory.VERSION, BODY_OBJECT_MAP);
-		}
-
-		@Test
-		void shouldCallCommandService() {
-			doReturn(command).when(service).buildPatchBescheidCommand(any(), anyLong(), any());
-
-			setBescheidStatusSent();
-
-			verify(commandService).createAndWaitUntilDone(command);
-		}
-
-		private void setBescheidStatusSent() {
-			service.setBescheidSentStatus(AttachedItemTestFactory.ID, AttachedItemTestFactory.VERSION);
-		}
-	}
-
-	@Nested
-	class TestBuildBescheidSentStatusBodyObject {
-
-		@Test
-		void shouldSetId() {
-			var result = service.buildBescheidSentStatusBodyObject(AttachedItemTestFactory.ID);
-
-			assertThat(result).containsEntry(AttachedItem.PROPERTY_ID, AttachedItemTestFactory.ID);
-		}
-
-		@Test
-		void shouldCallBuildBescheidSentStatusItem() {
-			service.buildBescheidSentStatusBodyObject(AttachedItemTestFactory.ID);
-
-			verify(service).buildBescheidSentStatusItem();
-		}
-
-		@Test
-		void shouldSetBescheidBodyObject() {
-			var expectedItemMap = Map.of("key", "value");
-			doReturn(expectedItemMap).when(service).buildBescheidSentStatusItem();
-
-			var result = service.buildBescheidSentStatusBodyObject(AttachedItemTestFactory.ID);
-
-			assertThat(result).containsEntry(AttachedItem.PROPERTY_ITEM, expectedItemMap);
-		}
-
-	}
-
-	@Nested
-	class TestBuildBescheidSentStatusItem {
-
-		@Test
-		void shouldSetStatus() {
-			var result = service.buildBescheidSentStatusItem();
-
-			assertThat(result).containsEntry(Bescheid.FIELD_STATUS, Bescheid.Status.SENT.name());
-		}
-	}
-
-	@Nested
-	class TestBuildSentInfoMap {
-
-		@Test
-		void shouldSetSentAt() {
-			var result = service.buildSentInfoMap();
-
-			assertThat(getSentAt(result)).isCloseTo(ZonedDateTime.now(), within(2, ChronoUnit.SECONDS));
-		}
-
-		@Test
-		void shouldCallGetUser() {
-			service.buildSentInfoMap();
-
-			verify(currentUserService).findUser();
-		}
-
-		@Test
-		void shouldSetSentBy() {
-			var userId = "user-id";
-			doReturn(userId).when(service).getUserId();
-
-			var result = service.buildSentInfoMap();
-
-			assertThat(result).containsEntry(Bescheid.FIELD_SENT_BY, userId);
-		}
-
-		private ZonedDateTime getSentAt(Map<String, Object> sentInfo) {
-			return ZonedDateTime.parse(MapUtils.getString(sentInfo, Bescheid.FIELD_SENT_AT));
-		}
-	}
-
-	@Nested
-	class TestGetUserId {
-
-		@Mock
-		private CallContextUser callContextUser;
-
-		@Test
-		void shouldCallFindUser() {
-			service.getUserId();
-
-			verify(currentUserService).findUser();
-		}
-
-		@Test
-		void shouldCallGetUserIdOnCallContexUser() {
-			when(currentUserService.findUser()).thenReturn(Optional.of(callContextUser));
-
-			service.getUserId();
-
-			verify(callContextUser).getUserId();
-		}
-
-		@Test
-		void shouldReturnUserId() {
-			var expectedUserId = "user-id";
-			when(callContextUser.getUserId()).thenReturn(Optional.of(expectedUserId));
-			when(currentUserService.findUser()).thenReturn(Optional.of(callContextUser));
-
-			var result = service.getUserId();
-
-			assertThat(result).isEqualTo(expectedUserId);
-		}
-
-		@Test
-		void shouldReturnEmptyWhenNoUserFound() {
-			var result = service.getUserId();
-
-			assertThat(result).isEmpty();
-		}
-
-		@Test
-		void shouldReturnEmptyWhenNoUserIdFound() {
-			when(currentUserService.findUser()).thenReturn(Optional.of(callContextUser));
-
-			var result = service.getUserId();
-
-			assertThat(result).isEmpty();
-		}
-	}
-
-	@Nested
-	class TestRevertBescheidStatusSent {
-
-		private static final Map<String, Object> BODY_OBJECT_MAP = Map.of("key", "value");
-
-		@Mock
-		private OzgCloudCommand command;
-
-		@Test
-		void shouldCallBuildRevertBescheidSentStatusBodyObject() {
-			revertBescheidStatusSent();
-
-			verify(service).buildRevertBescheidSentStatusBodyObject(AttachedItemTestFactory.ID);
-		}
-
-		@Test
-		void shouldCallBuildPatchBescheidCommand() {
-			doReturn(BODY_OBJECT_MAP).when(service).buildRevertBescheidSentStatusBodyObject(any());
-
-			revertBescheidStatusSent();
-
-			verify(service).buildPatchBescheidCommand(AttachedItemTestFactory.ID, AttachedItemTestFactory.VERSION, BODY_OBJECT_MAP);
-		}
-
-		@Test
-		void shouldCallCommandService() {
-			doReturn(command).when(service).buildPatchBescheidCommand(any(), anyLong(), any());
-
-			revertBescheidStatusSent();
-
-			verify(commandService).createAndWaitUntilDone(command);
-		}
-
-		private void revertBescheidStatusSent() {
-			service.revertBescheidSendStatus(AttachedItemTestFactory.ID, AttachedItemTestFactory.VERSION);
-		}
-
-	}
-
-	@Nested
-	class TestBuildRevertBescheidSentStatusBodyObject {
-
-		@Test
-		void shouldSetId() {
-			var result = service.buildRevertBescheidSentStatusBodyObject(AttachedItemTestFactory.ID);
-
-			assertThat(result).containsEntry(AttachedItem.PROPERTY_ID, AttachedItemTestFactory.ID);
-		}
-
-		@Test
-		void shouldCallBuildRevertBescheidSentStatusItem() {
-			service.buildRevertBescheidSentStatusBodyObject(AttachedItemTestFactory.ID);
-
-			verify(service).buildRevertBescheidSentStatusItem();
-		}
-
-		@Test
-		void shouldSetBescheidBodyObject() {
-			var expectedItemMap = Map.of("key", "value");
-			doReturn(expectedItemMap).when(service).buildRevertBescheidSentStatusItem();
-
-			var result = service.buildRevertBescheidSentStatusBodyObject(AttachedItemTestFactory.ID);
-
-			assertThat(result).containsEntry(AttachedItem.PROPERTY_ITEM, expectedItemMap);
-		}
-	}
-
-	@Nested
-	class TestBuildRevertBescheidSentStatusItem {
-
-		@Test
-		void shouldCallBuildItemMap() {
-			service.buildRevertBescheidSentStatusItem();
-
-			verify(service).buildItemMap(Bescheid.Status.DRAFT);
-		}
-
-		@Test
-		void shouldReturnResultsOfBuildItemMap() {
-			var expectedItemMap = new HashMap<String, Object>(Map.of("key", "value"));
-			doReturn(expectedItemMap).when(service).buildItemMap(any());
-
-			var result = service.buildRevertBescheidSentStatusItem();
-
-			assertThat(result).containsEntry("key", "value");
-		}
-
-		@Test
-		void shouldSetSentInfoNull() {
-			var result = service.buildRevertBescheidSentStatusItem();
-
-			assertThat(result).containsEntry(Bescheid.FIELD_SENT_INFO, null);
-		}
-	}
-
 	@Nested
 	class TestBuildItemMap {
 
@@ -1301,54 +1043,6 @@ class AttachedItemServiceTest {
 		}
 	}
 
-	@Nested
-	class TestBuildPatchBescheidCommand {
-
-		private static final Map<String, Object> BODY_OBJECT_MAP = Map.of("key", "value");
-
-		@Test
-		void shouldCallRelationIdMapper() {
-			buildPatchBescheidCommand();
-
-			verify(commandMapper).mapRelationId(AttachedItemTestFactory.ID);
-		}
-
-		@Test
-		void shouldSetRelationId() {
-			var expectedId = GenericId.from(AttachedItemTestFactory.ID);
-			when(commandMapper.mapRelationId(any())).thenReturn(expectedId);
-
-			var result = buildPatchBescheidCommand();
-
-			assertThat(result.getRelationId()).isEqualTo(expectedId);
-		}
-
-		@Test
-		void shouldSetRelationVersion() {
-			var result = buildPatchBescheidCommand();
-
-			assertThat(result.getRelationVersion()).isEqualTo(AttachedItemTestFactory.VERSION);
-		}
-
-		@Test
-		void shouldSetOrder() {
-			var result = buildPatchBescheidCommand();
-
-			assertThat(result.getOrder()).isEqualTo(AttachedItemService.PATCH_ATTACHED_ITEM);
-		}
-
-		@Test
-		void shouldSetBodyObject() {
-			var result = buildPatchBescheidCommand();
-
-			assertThat(result.getBodyObject()).isSameAs(BODY_OBJECT_MAP);
-		}
-
-		private OzgCloudCommand buildPatchBescheidCommand() {
-			return service.buildPatchBescheidCommand(AttachedItemTestFactory.ID, AttachedItemTestFactory.VERSION, BODY_OBJECT_MAP);
-		}
-	}
-
 	@Nested
 	class TestFindAllBescheid {
 
diff --git a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/common/freemarker/TemplateHandlerITCase.java b/bescheid-manager/src/test/java/de/ozgcloud/bescheid/common/freemarker/TemplateHandlerITCase.java
index 61873f64571613f97a8a55b58cb23c7d4751a2f4..071cb7d7ee00b57de1a217ccef7e4522df18a4c9 100644
--- a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/common/freemarker/TemplateHandlerITCase.java
+++ b/bescheid-manager/src/test/java/de/ozgcloud/bescheid/common/freemarker/TemplateHandlerITCase.java
@@ -6,7 +6,6 @@ import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.info.BuildProperties;
 import org.springframework.boot.test.mock.mockito.MockBean;
 
 import de.ozgcloud.apilib.common.command.OzgCloudCommandService;
@@ -21,8 +20,6 @@ class TemplateHandlerITCase {
 	@Autowired
 	private TemplateHandler handler;
 	@MockBean
-	private BuildProperties properties;
-	@MockBean
 	private OzgCloudCommandService commandService;
 	@MockBean
 	private CommandMapper commandMapper;
diff --git a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/nachricht/GrpcPostfachNachrichtTestFactory.java b/bescheid-manager/src/test/java/de/ozgcloud/bescheid/nachricht/GrpcPostfachNachrichtTestFactory.java
deleted file mode 100644
index c42e9fb32e68ea5a86de3e41e682927c87d77019..0000000000000000000000000000000000000000
--- a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/nachricht/GrpcPostfachNachrichtTestFactory.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package de.ozgcloud.bescheid.nachricht;
-
-import de.ozgcloud.nachrichten.postfach.GrpcPostfachNachricht;
-
-public class GrpcPostfachNachrichtTestFactory {
-
-	public static final GrpcPostfachNachricht create() {
-		return createBuilder().build();
-	}
-
-	public static final GrpcPostfachNachricht.Builder createBuilder() {
-		return GrpcPostfachNachricht.newBuilder()
-				.setCreatedAt(NachrichtTestFactory.CREATED_AT.toString())
-				.setMailBody(NachrichtTestFactory.MAIL_BODY)
-				.setSubject(NachrichtTestFactory.SUBJECT);
-	}
-}
diff --git a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/nachricht/NachrichtMapperTest.java b/bescheid-manager/src/test/java/de/ozgcloud/bescheid/nachricht/NachrichtMapperTest.java
deleted file mode 100644
index ac7a466e044dcd7e0c5a95b3a0f1f6e1332e1230..0000000000000000000000000000000000000000
--- a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/nachricht/NachrichtMapperTest.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package de.ozgcloud.bescheid.nachricht;
-
-import static org.assertj.core.api.Assertions.*;
-
-import org.junit.jupiter.api.Nested;
-import org.junit.jupiter.api.Test;
-import org.mapstruct.factory.Mappers;
-import org.mockito.InjectMocks;
-
-class NachrichtMapperTest {
-
-	@InjectMocks
-	private NachrichtMapper mapper = Mappers.getMapper(NachrichtMapper.class);;
-
-	@Nested
-	class TestMapToGrpc {
-		@Test
-		void shouldMapNachricht() {
-			var mapped = mapper.mapToGrpc(NachrichtTestFactory.create());
-
-			assertThat(mapped).usingRecursiveComparison()
-					.ignoringFields("replyOption_", "memoizedHashCode")
-					.isEqualTo(GrpcPostfachNachrichtTestFactory.create());
-		}
-
-		@Test
-		void shouldIgnoreMissingFileId() {
-			var mapped = mapper.mapToGrpc(NachrichtTestFactory.createBuilder().bescheidFileId(null).build());
-
-			assertThat(mapped.getAttachmentList()).isEmpty();
-		}
-
-		@Test
-		void shouldSetReplyOption() {
-			var mapped = mapper.mapToGrpc(NachrichtTestFactory.create());
-
-			assertThat(mapped.getReplyOption()).isEqualTo("FORBIDDEN");
-		}
-
-		@Test
-		void shouldNotMapId() {
-			var mapped = mapper.mapToGrpc(NachrichtTestFactory.create());
-
-			assertThat(mapped.getId()).isEmpty();
-		}
-	}
-
-}
diff --git a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/nachricht/NachrichtRemoteServiceTest.java b/bescheid-manager/src/test/java/de/ozgcloud/bescheid/nachricht/NachrichtRemoteServiceTest.java
deleted file mode 100644
index fb796252a7f562a824b4f1b1e9dd1a323e7fc8ed..0000000000000000000000000000000000000000
--- a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/nachricht/NachrichtRemoteServiceTest.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package de.ozgcloud.bescheid.nachricht;
-
-import static org.assertj.core.api.Assertions.*;
-import static org.mockito.ArgumentMatchers.*;
-import static org.mockito.Mockito.*;
-
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Nested;
-import org.junit.jupiter.api.Test;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-
-import de.ozgcloud.bescheid.vorgang.VorgangTestFactory;
-import de.ozgcloud.nachrichten.postfach.GrpcPostfachNachricht;
-
-class NachrichtRemoteServiceTest {
-
-	@InjectMocks
-	private NachrichtRemoteService remoteService;
-
-	@Mock
-	private NachrichtMapper mapper;
-
-	@Nested
-	class TestSaveDarft {
-		@Nested
-		class BuildRequest {
-			private Nachricht nachricht = NachrichtTestFactory.create();
-			private GrpcPostfachNachricht grpcNachricht = GrpcPostfachNachrichtTestFactory.create();
-
-			@BeforeEach
-			void initMocks() {
-				when(mapper.mapToGrpc(any())).thenReturn(grpcNachricht);
-			}
-
-			@Test
-			void shouldCallMapper() {
-				remoteService.buildRequest(nachricht);
-
-				verify(mapper).mapToGrpc(nachricht);
-			}
-
-			@Test
-			void shouldSetNachricht() {
-				var request = remoteService.buildRequest(nachricht);
-
-				assertThat(request.getNachricht()).isSameAs(grpcNachricht);
-			}
-
-			@Test
-			void shouldSetVorgangId() {
-				var request = remoteService.buildRequest(nachricht);
-
-				assertThat(request.getVorgangId()).isEqualTo(VorgangTestFactory.ID.toString());
-			}
-		}
-	}
-
-}
diff --git a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/nachricht/NachrichtServiceITCase.java b/bescheid-manager/src/test/java/de/ozgcloud/bescheid/nachricht/NachrichtServiceITCase.java
deleted file mode 100644
index e0280020426fe92f6dce27b0f223738f57e108b5..0000000000000000000000000000000000000000
--- a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/nachricht/NachrichtServiceITCase.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package de.ozgcloud.bescheid.nachricht;
-
-import static org.assertj.core.api.Assertions.*;
-
-import org.junit.jupiter.api.DisplayName;
-import org.junit.jupiter.api.Nested;
-import org.junit.jupiter.api.Test;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.info.BuildProperties;
-import org.springframework.boot.test.mock.mockito.MockBean;
-
-import de.ozgcloud.apilib.common.command.OzgCloudCommandService;
-import de.ozgcloud.apilib.common.command.grpc.CommandMapper;
-import de.ozgcloud.bescheid.BescheidTestFactory;
-import de.ozgcloud.common.test.ITCase;
-
-@ITCase
-class NachrichtServiceITCase {
-
-	@Autowired
-	private NachrichtService service;
-	@MockBean
-	private OzgCloudCommandService commandService;
-	@MockBean
-	private CommandMapper commandMapper;
-	@MockBean
-	private BuildProperties buildProperties;
-
-	@DisplayName("Build message")
-	@Nested
-	class TestBuildMessage {
-		@Test
-		void shouldBuildMessage() {
-			var message = service.buildMessage(BescheidTestFactory.create());
-
-			assertThat(message).isNotBlank();
-		}
-	}
-}
\ No newline at end of file
diff --git a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/nachricht/NachrichtServiceTest.java b/bescheid-manager/src/test/java/de/ozgcloud/bescheid/nachricht/NachrichtServiceTest.java
deleted file mode 100644
index f18ffbc9d6851d39b9dfe8676d98f7676013dbe5..0000000000000000000000000000000000000000
--- a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/nachricht/NachrichtServiceTest.java
+++ /dev/null
@@ -1,350 +0,0 @@
-package de.ozgcloud.bescheid.nachricht;
-
-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.List;
-import java.util.Map;
-import java.util.Optional;
-
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Nested;
-import org.junit.jupiter.api.Test;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.Spy;
-
-import de.ozgcloud.apilib.common.command.OzgCloudCommand;
-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.user.OzgCloudUserId;
-import de.ozgcloud.apilib.vorgang.OzgCloudVorgangId;
-import de.ozgcloud.bescheid.Bescheid;
-import de.ozgcloud.bescheid.BescheidTestFactory;
-import de.ozgcloud.bescheid.attacheditem.AttachedItemTestFactory;
-import de.ozgcloud.bescheid.common.freemarker.TemplateHandler;
-import de.ozgcloud.bescheid.vorgang.PostfachAddressTestFactory;
-import de.ozgcloud.bescheid.vorgang.ServiceKontoTestFactory;
-import de.ozgcloud.bescheid.vorgang.Vorgang;
-import de.ozgcloud.bescheid.vorgang.VorgangTestFactory;
-import de.ozgcloud.common.errorhandling.TechnicalException;
-
-class NachrichtServiceTest {
-
-	@Spy
-	@InjectMocks
-	private NachrichtService service;
-
-	@Mock
-	private NachrichtRemoteService remoteService;
-	@Mock
-	private OzgCloudCommandService commandService;
-	@Mock
-	private CommandMapper commandMapper;
-	@Mock
-	private TemplateHandler templateHandler;
-
-	@Nested
-	class TestCreateNachrichtDraft {
-
-		private final Nachricht nachricht = NachrichtTestFactory.create();
-
-		@Test
-		void shouldCallRemoteService() {
-			doReturn(Optional.of(nachricht)).when(service).buildNachricht(any());
-
-			service.createNachrichtDraft(BescheidTestFactory.create());
-
-			verify(remoteService).saveDraft(nachricht);
-		}
-
-		@Nested
-		class BuildNachricht {
-
-			@BeforeEach
-			void init() {
-				doReturn(NachrichtTestFactory.MAIL_BODY).when(service).buildMessage(any());
-			}
-
-			@Test
-			void shouldFillMailBody() {
-				var nachricht = service.buildNachricht(BescheidTestFactory.create()).get();
-
-				assertThat(nachricht.getMailBody()).isEqualTo(NachrichtTestFactory.MAIL_BODY);
-			}
-
-			@Test
-			void shouldSetSubject() {
-				var nachricht = service.buildNachricht(BescheidTestFactory.create()).get();
-
-				assertThat(nachricht.getSubject()).isEqualTo(BescheidTestFactory.NACHRICHT_SUBJECT);
-			}
-
-			@Test
-			void shouldSetDefaultSubject() {
-				var bescheid = BescheidTestFactory.createBuilder().nachrichtSubject(Optional.empty()).build();
-
-				var nachricht = service.buildNachricht(bescheid).get();
-
-				assertThat(nachricht.getSubject()).isEqualTo(NachrichtService.SUBJECT);
-			}
-
-			@Test
-			void shouldSetUser() {
-				var nachricht = service.buildNachricht(BescheidTestFactory.create()).get();
-
-				assertThat(nachricht.getCreatedBy()).isEqualTo(BescheidTestFactory.CREATED_BY);
-			}
-
-			@Test
-			void shouldSetVorgangId() {
-				var nachricht = service.buildNachricht(BescheidTestFactory.create()).get();
-
-				assertThat(nachricht.getVorgangId()).isEqualTo(VorgangTestFactory.ID);
-			}
-		}
-	}
-
-	@Nested
-	class TestBuildMessage {
-		@Test
-		void shouldUseTextFromBescheid() {
-			var message = service.buildMessage(BescheidTestFactory.create());
-
-			assertThat(message).isEqualTo(BescheidTestFactory.NACHRICHT_TEXT);
-		}
-
-		@Test
-		void shouldUseDefaultTemplate() {
-			doReturn("FROM_TEMPLATE").when(templateHandler).fillTemplate(any(), any());
-
-			var message = service.buildMessage(BescheidTestFactory.createBuilder().nachrichtText(Optional.empty()).build());
-
-			assertThat(message).isEqualTo("FROM_TEMPLATE");
-		}
-	}
-
-	@Nested
-	class TestSendNachricht {
-
-		@Mock
-		private OzgCloudCommand ozgCloudCommand;
-
-		@BeforeEach
-		void init() {
-			doReturn(ozgCloudCommand).when(service).buildSendBescheidCommand(any());
-		}
-
-		@Test
-		void shouldCallBuildBescheidCommand() {
-			var bescheid = BescheidTestFactory.create();
-
-			service.sendNachricht(bescheid);
-
-			verify(service).buildSendBescheidCommand(bescheid);
-		}
-
-		@Test
-		void shouldCallCommandService() {
-			service.sendNachricht(BescheidTestFactory.create());
-
-			verify(commandService).createAndWaitUntilDone(ozgCloudCommand);
-		}
-
-	}
-
-	@Nested
-	class TestBuildSendBescheidCommand {
-
-		private static final Map<String, Object> bodyObject = Map.of("key", "value");
-		private final Bescheid bescheid = BescheidTestFactory.create();
-
-		@BeforeEach
-		void init() {
-			doReturn(bodyObject).when(service).buildSendNachrichtCommandBody(any());
-		}
-
-		@Test
-		void shouldCallVorgangIdMapper() {
-			buildCommand();
-
-			verify(commandMapper).toOzgCloudVorgangId(VorgangTestFactory.ID.toString());
-		}
-
-		@Test
-		void shouldSetVorgangId() {
-			var vorgangId = OzgCloudVorgangId.from(VorgangTestFactory.ID.toString());
-			when(commandMapper.toOzgCloudVorgangId(anyString())).thenReturn(vorgangId);
-
-			var result = buildCommand();
-
-			assertThat(result.getVorgangId()).isEqualTo(vorgangId);
-		}
-
-		@Test
-		void shouldCallMapRelationId() {
-			buildCommand();
-
-			verify(commandMapper).mapRelationId(VorgangTestFactory.ID.toString());
-		}
-
-		@Test
-		void shouldSetRelationId() {
-			var relationId = GenericId.from("relation-id");
-			when(commandMapper.mapRelationId(anyString())).thenReturn(relationId);
-
-			var result = buildCommand();
-
-			assertThat(result.getRelationId()).isEqualTo(relationId);
-		}
-
-		@Test
-		void shouldSetOrder() {
-			var result = buildCommand();
-
-			assertThat(result.getOrder()).isEqualTo(NachrichtService.SEND_POSTFACH_NACHRICHT_ORDER);
-		}
-
-		@Test
-		void shouldCallCreatedBy() {
-			buildCommand();
-
-			verify(commandMapper).toOzgCloudUserId(BescheidTestFactory.CREATED_BY.toString());
-		}
-
-		@Test
-		void shouldSetCreatedBy() {
-			var userId = OzgCloudUserId.from(BescheidTestFactory.CREATED_BY.toString());
-			when(commandMapper.toOzgCloudUserId(anyString())).thenReturn(userId);
-
-			var result = buildCommand();
-
-			assertThat(result.getCreatedBy()).isEqualTo(userId);
-		}
-
-		@Test
-		void shouldCallBuildSendNachrichtCommandBody() {
-			buildCommand();
-
-			verify(service).buildSendNachrichtCommandBody(bescheid);
-		}
-
-		@Test
-		void shouldSetBodyObject() {
-			var result = buildCommand();
-
-			assertThat(result.getBodyObject()).isEqualTo(bodyObject);
-		}
-
-		private OzgCloudCommand buildCommand() {
-			return service.buildSendBescheidCommand(bescheid);
-		}
-	}
-
-	@Nested
-	class TestBuildSendNachrichtCommandBody {
-
-		private final Bescheid bescheid = BescheidTestFactory.create();
-
-		@Test
-		void shouldCallBuildPostfachAddress() {
-			service.buildSendNachrichtCommandBody(bescheid);
-
-			verify(service).buildPostfachAddress(bescheid);
-		}
-
-		@Test
-		void shouldSetPostfachAddress() {
-			var postfachAddressMap = Map.<String, Object>of("key", "value");
-			doReturn(postfachAddressMap).when(service).buildPostfachAddress(any());
-
-			var result = service.buildSendNachrichtCommandBody(bescheid);
-
-			assertThat(result).containsEntry(Vorgang.ServiceKonto.FIELD_POSTFACH_ADDRESS, postfachAddressMap);
-		}
-
-		@Test
-		void shouldSetReplyOption() {
-			var result = service.buildSendNachrichtCommandBody(bescheid);
-
-			assertThat(result).containsEntry(NachrichtService.FIELD_REPLY_OPTION, NachrichtService.REPLY_OPTION);
-		}
-
-		@Test
-		void shouldSetSubject() {
-			var result = service.buildSendNachrichtCommandBody(bescheid);
-
-			assertThat(result).containsEntry(NachrichtService.FIELD_SUBJECT, BescheidTestFactory.NACHRICHT_SUBJECT);
-		}
-
-		@Test
-		void shouldSetMailBody() {
-			var result = service.buildSendNachrichtCommandBody(bescheid);
-
-			assertThat(result).containsEntry(NachrichtService.FIELD_MAIL_BODY, BescheidTestFactory.NACHRICHT_TEXT);
-		}
-
-		@Test
-		void shouldSetAttachments() {
-			var result = service.buildSendNachrichtCommandBody(bescheid);
-
-			assertThat(result).containsEntry(NachrichtService.FIELD_ATTACHMENTS,
-					List.of(BescheidTestFactory.BESCHEID_FILE_ID, AttachedItemTestFactory.ATTACHMENT));
-		}
-	}
-
-	@Nested
-	class TestBuildPostfachAddress {
-
-		@Test
-		void shouldCallGetAddress() {
-			var bescheid = BescheidTestFactory.create();
-
-			service.buildPostfachAddress(bescheid);
-
-			verify(service).getAddress(bescheid);
-		}
-
-		@Test
-		void shouldThrowExceptionIfNoServiceKonto() {
-			doReturn(Optional.empty()).when(service).getAddress(any());
-			var bescheid = BescheidTestFactory.create();
-
-			assertThrows(TechnicalException.class, () -> service.buildPostfachAddress(bescheid));
-		}
-
-		@Test
-		void shouldSetAddressType() {
-			var result = service.buildPostfachAddress(BescheidTestFactory.create());
-
-			assertThat(result).containsEntry(Vorgang.PostfachAddress.FIELD_TYPE, PostfachAddressTestFactory.TYPE);
-		}
-
-		@Test
-		void shouldSetAddressVersion() {
-			var result = service.buildPostfachAddress(BescheidTestFactory.create());
-
-			assertThat(result).containsEntry(Vorgang.PostfachAddress.FIELD_VERSION, PostfachAddressTestFactory.VERSION);
-		}
-
-		@Test
-		void shouldSetAddressIdentifier() {
-			var result = service.buildPostfachAddress(BescheidTestFactory.create());
-
-			assertThat(result).extracting(Vorgang.PostfachAddress.FIELD_IDENTIFIER, MAP)
-					.containsEntry(NachrichtService.FIELD_POSTFACH_ID, PostfachAddressTestFactory.POSTFACH_ID);
-		}
-
-		@Test
-		void shouldSetServiceKontoType() {
-			var result = service.buildPostfachAddress(BescheidTestFactory.create());
-
-			assertThat(result).containsEntry(Vorgang.ServiceKonto.FIELD_SERVICEKONTO_TYPE, ServiceKontoTestFactory.TYPE);
-		}
-
-	}
-
-}
diff --git a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/nachricht/NachrichtTestFactory.java b/bescheid-manager/src/test/java/de/ozgcloud/bescheid/nachricht/NachrichtTestFactory.java
deleted file mode 100644
index a82751dcc7ac14b7ba16a677d2fd2ad3476e73a9..0000000000000000000000000000000000000000
--- a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/nachricht/NachrichtTestFactory.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package de.ozgcloud.bescheid.nachricht;
-
-import java.time.ZonedDateTime;
-import java.util.UUID;
-
-import de.ozgcloud.bescheid.UserId;
-import de.ozgcloud.bescheid.vorgang.VorgangTestFactory;
-
-public class NachrichtTestFactory {
-
-	public static final NachrichtId ID = NachrichtId.from(UUID.randomUUID().toString());
-
-	public static final String SUBJECT = "subject of message";
-	public static final String MAIL_BODY = "Lorem ipsum";
-
-	public static final UserId CREATED_BY = UserId.from(UUID.randomUUID().toString());
-	public static final ZonedDateTime CREATED_AT = ZonedDateTime.now().withNano(0);
-
-	public static Nachricht create() {
-		return createBuilder().build();
-	}
-
-	public static Nachricht.NachrichtBuilder createBuilder() {
-		return Nachricht.builder()
-				.id(ID)
-				.vorgangId(VorgangTestFactory.ID)
-				.subject(SUBJECT)
-				.mailBody(MAIL_BODY)
-				.createdBy(CREATED_BY)
-				.createdAt(CREATED_AT);
-	}
-}
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 3126ecfe5b5f98c41749c406cd426253a65b053e..764fc28f4882f0f160b07deef03f080c4c8b975d 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
@@ -2,7 +2,10 @@ package de.ozgcloud.bescheid.smartdocuments;
 
 import static org.assertj.core.api.Assertions.*;
 
+import java.io.File;
+
 import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
@@ -14,9 +17,10 @@ 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.binaryfile.TempFileUtils;
 import de.ozgcloud.common.test.ITCase;
+import de.ozgcloud.common.test.TestUtils;
 
-@Disabled
 @SpringBootTest(classes = BescheidTestApplication.class)
 @ITCase
 @ActiveProfiles({ "itcase", "local" })
@@ -29,6 +33,7 @@ class SmartDocumentsBescheidRemoteServiceITCase {
 	@MockBean
 	private CommandMapper commandMapper;
 
+	@Disabled("This test request SmartDocuments service")
 	@Test
 	void createBescheid() {
 		var bescheid = remoteService.create(BescheidRequestTestFactory.create(), VorgangTestFactory.create());
@@ -38,4 +43,37 @@ class SmartDocumentsBescheidRemoteServiceITCase {
 		assertThat(bescheid.getBescheidFileName()).isNotEmpty();
 	}
 
+	@Nested
+	class TestGetNachrichtenText {
+
+		private static final String NACHRICHTEN_TEXT = "Nachrichtentext";
+		private static final String FIELD_TEMPLATE_TEXT = "Nachrichten Field Text";
+
+		@Test
+		void shouldGetNachrichtenText() {
+			var nachrichtenText = remoteService.extractTextFromXmlFile(loadFile("SD_answer.xml"));
+
+			assertThat(nachrichtenText).contains(NACHRICHTEN_TEXT);
+		}
+
+		@Test
+		void shouldGetFieldTemplateText() {
+			var fieldTemplateText = remoteService.extractTextFromXmlFile(loadFile("SD_answer_field_template.xml"));
+
+			assertThat(fieldTemplateText).contains(FIELD_TEMPLATE_TEXT);
+		}
+
+		@Test
+		void shouldExpectMissingTextNode() {
+			File xmlFileWithoutText = TempFileUtils.writeTmpFile(TestUtils.loadFile("SD_answer_without_text.xml"));
+
+			var text = remoteService.extractTextFromXmlFile(xmlFileWithoutText);
+
+			assertThat(text).isEmpty();
+		}
+
+		private File loadFile(String fileName) {
+			return TempFileUtils.writeTmpFile(TestUtils.loadFile(fileName));
+		}
+	}
 }
diff --git a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/smartdocuments/SmartDocumentsBescheidRemoteServiceTest.java b/bescheid-manager/src/test/java/de/ozgcloud/bescheid/smartdocuments/SmartDocumentsBescheidRemoteServiceTest.java
index 695e1cad6f1f865c19181e4b510d51ce03a12b96..4db4b0e81338307b7af8df53bf85667096e738e3 100644
--- a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/smartdocuments/SmartDocumentsBescheidRemoteServiceTest.java
+++ b/bescheid-manager/src/test/java/de/ozgcloud/bescheid/smartdocuments/SmartDocumentsBescheidRemoteServiceTest.java
@@ -7,19 +7,20 @@ import static org.mockito.Mockito.*;
 import java.io.File;
 import java.util.Optional;
 
+import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.Spy;
+import org.w3c.dom.Document;
+import org.w3c.dom.Text;
 
 import de.ozgcloud.bescheid.BescheidRequestTestFactory;
 import de.ozgcloud.bescheid.BescheidTestFactory;
 import de.ozgcloud.bescheid.common.user.UserProfileTestFactory;
 import de.ozgcloud.bescheid.smartdocuments.SmartDocumentsRequest.CustomerData.UserData;
 import de.ozgcloud.bescheid.vorgang.VorgangTestFactory;
-import de.ozgcloud.common.binaryfile.TempFileUtils;
-import de.ozgcloud.common.test.TestUtils;
 import lombok.SneakyThrows;
 
 class SmartDocumentsBescheidRemoteServiceTest {
@@ -30,6 +31,10 @@ class SmartDocumentsBescheidRemoteServiceTest {
 
 	@Mock
 	private SmartDocumentsProperties properties;
+	@Mock
+	private Text xmlText;
+	@Mock
+	private File xmlFile;
 
 	@Nested
 	class TestBuildBescheid {
@@ -57,7 +62,15 @@ class SmartDocumentsBescheidRemoteServiceTest {
 
 	@Nested
 	class TestGetNachrichtText {
-		private final File xmlFile = TempFileUtils.writeTmpFile(TestUtils.loadFile("SD_answer.xml"));
+
+		@Test
+		void shouldCallGetXMLFile() {
+			var response = SmartDocumentsResponseTestFactory.create();
+
+			service.getNachrichtText(response);
+
+			verify(service).getXMLFile(response);
+		}
 
 		@Test
 		void shouldCallExtractText() {
@@ -65,36 +78,171 @@ class SmartDocumentsBescheidRemoteServiceTest {
 
 			service.getNachrichtText(SmartDocumentsResponseTestFactory.create());
 
-			verify(service).extractTextFormXmlFile(notNull());
+			verify(service).extractTextFromXmlFile(xmlFile);
+		}
+	}
+
+	@Nested
+	class TestExtractTextFromXmlFileSuccessfully {
+
+		private static final String NACHRICHT_TEXT = "NachrichtText";
+
+		@Mock
+		private Document document;
+
+		@SneakyThrows
+		@BeforeEach
+		void init() {
+			doReturn(Optional.of(document)).when(service).parseXml(any());
+		}
+
+		@SneakyThrows
+		@Test
+		void shouldCallParseXml() {
+			service.extractTextFromXmlFile(xmlFile);
+
+			verify(service).parseXml(xmlFile);
+		}
+
+		@Test
+		void shouldCallGetNachrichtenText() {
+			doReturn(Optional.of(xmlText)).when(service).getNachrichtenText(any());
+
+			service.extractTextFromXmlFile(xmlFile);
+
+			verify(service).getNachrichtenText(document);
+		}
+
+		@Test
+		void shouldReturnNachrichtenText() {
+			doReturn(Optional.of(xmlText)).when(service).getNachrichtenText(any());
+			when(xmlText.getTextContent()).thenReturn(NACHRICHT_TEXT);
+
+			var text = service.extractTextFromXmlFile(xmlFile);
+
+			assertThat(text).contains(NACHRICHT_TEXT);
+		}
+
+		@Test
+		void shouldNotCallGetFieldTemplateText() {
+			doReturn(Optional.of(xmlText)).when(service).getNachrichtenText(any());
+
+			service.extractTextFromXmlFile(xmlFile);
+
+			verify(service, never()).getFieldTemplateText(document);
 		}
 
-		@Nested
-		class ExtractingText {
+		@Test
+		void shouldCallGetFieldTemplateText() {
+			doReturn(Optional.empty()).when(service).getNachrichtenText(any());
+			doReturn(Optional.of(xmlText)).when(service).getFieldTemplateText(any());
+
+			service.extractTextFromXmlFile(xmlFile);
 
-			@Test
-			void shouldReturnText() {
-				var text = service.extractTextFormXmlFile(xmlFile);
+			verify(service).getFieldTemplateText(document);
+		}
 
-				assertThat(text).isPresent().get().isNotNull();
-			}
+		@Test
+		void shouldReturnFieldTemplateText() {
+			doReturn(Optional.empty()).when(service).getNachrichtenText(any());
+			doReturn(Optional.of(xmlText)).when(service).getFieldTemplateText(any());
+			when(xmlText.getTextContent()).thenReturn(NACHRICHT_TEXT);
 
-			@Test
-			void shouldHandleError() {
-				var text = service.extractTextFormXmlFile(null);
+			var text = service.extractTextFromXmlFile(xmlFile);
 
-				assertThat(text).isEmpty();
-			}
+			assertThat(text).contains(NACHRICHT_TEXT);
+		}
+	}
 
-			@Test
-			@SneakyThrows
-			void shouldExpectMissingTextNode() {
-				File xmlFileWithoutText = TempFileUtils.writeTmpFile(TestUtils.loadFile("SD_answer_without_text.xml"));
+	@Nested
+	class TestExtractTextFormXmlFileFails {
 
-				var text = service.doExtractText(xmlFileWithoutText);
+		@Mock
+		private Document document;
 
-				assertThat(text).isEmpty();
-			}
+		@SneakyThrows
+		@Test
+		void shouldHandleMissingXmlDocument() {
+			doReturn(Optional.empty()).when(service).parseXml(any());
+
+			var text = service.extractTextFromXmlFile(xmlFile);
+
+			assertThat(text).isEmpty();
+		}
+
+		@Test
+		@SneakyThrows
+		void shouldExpectMissingTextNode() {
+			doReturn(Optional.of(document)).when(service).parseXml(any());
+			doReturn(Optional.empty()).when(service).getFieldTemplateText(any());
+
+			var text = service.extractTextFromXmlFile(xmlFile);
+
+			assertThat(text).isEmpty();
+		}
+	}
+
+	@Nested
+	class TestGetNachrichtenText {
+
+		@Mock
+		private Text text;
+		@Mock
+		private Document document;
+
+		@BeforeEach
+		void init() {
+			doReturn(Optional.of(text)).when(service).evaluateXPath(any(), any());
+		}
+
+		@Test
+		void shouldCallEvaluatePath() {
+			getNachrichtenText();
+
+			verify(service).evaluateXPath(document, SmartDocumentsBescheidRemoteService.NACHRICHTEN_TEXT_EXPRESSION);
+		}
+
+		@Test
+		void shouldReturnText() {
+			var result = getNachrichtenText();
+
+			assertThat(result).contains(text);
+		}
+
+		private Optional<Text> getNachrichtenText() {
+			return service.getNachrichtenText(document);
+		}
+	}
+
+	@Nested
+	class TestGetFieldTemplateText {
+
+		@Mock
+		private Text text;
+		@Mock
+		private Document document;
+
+		@BeforeEach
+		void init() {
+			doReturn(Optional.of(text)).when(service).evaluateXPath(any(), any());
+		}
+
+		@Test
+		void shouldCallEvaluatePath() {
+			getFieldTemplateText();
+
+			verify(service).evaluateXPath(document, SmartDocumentsBescheidRemoteService.FIELD_TEMPLATE_EXPRESSION);
+		}
+
+		@Test
+		void shouldReturnText() {
+			var result = getFieldTemplateText();
+
+			assertThat(result).contains(text);
+		}
 
+		private Optional<Text> getFieldTemplateText() {
+			return service.getFieldTemplateText(document);
 		}
 	}
 }
diff --git a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/vorgang/PostfachAddressTestFactory.java b/bescheid-manager/src/test/java/de/ozgcloud/bescheid/vorgang/PostfachAddressTestFactory.java
index 7f7ef749025025cc565b4b04b6a5db8183eb3fb1..5d01a8b7573c16643a61e602ff06bc94aa0cd155 100644
--- a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/vorgang/PostfachAddressTestFactory.java
+++ b/bescheid-manager/src/test/java/de/ozgcloud/bescheid/vorgang/PostfachAddressTestFactory.java
@@ -26,12 +26,13 @@ package de.ozgcloud.bescheid.vorgang;
 import java.util.Map;
 import java.util.UUID;
 
-import de.ozgcloud.bescheid.nachricht.NachrichtService;
 import de.ozgcloud.bescheid.vorgang.Vorgang.PostfachAddress.PostfachAddressBuilder;
 
 public class PostfachAddressTestFactory {
 
 	public static final String POSTFACH_ID = UUID.randomUUID().toString();
+	public static final String FIELD_POSTFACH_ID = "postfachId";
+
 	public static final int TYPE = 1;
 	public static final String VERSION = "1.0";
 
@@ -43,6 +44,6 @@ public class PostfachAddressTestFactory {
 		return Vorgang.PostfachAddress.builder()
 				.type(TYPE)
 				.version(VERSION)
-				.identifier(Map.of(NachrichtService.FIELD_POSTFACH_ID, POSTFACH_ID));
+				.identifier(Map.of(FIELD_POSTFACH_ID, POSTFACH_ID));
 	}
 }
diff --git a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/vorgang/VorgangServiceTest.java b/bescheid-manager/src/test/java/de/ozgcloud/bescheid/vorgang/VorgangServiceTest.java
index 424a4330012bc1fd605dede82c56eac40c435f67..cc93692c7831628dd87ada5bf0cf21f2250b5bb4 100644
--- a/bescheid-manager/src/test/java/de/ozgcloud/bescheid/vorgang/VorgangServiceTest.java
+++ b/bescheid-manager/src/test/java/de/ozgcloud/bescheid/vorgang/VorgangServiceTest.java
@@ -11,12 +11,6 @@ import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.Spy;
 
-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.apilib.common.datatypes.GenericId;
-import de.ozgcloud.apilib.vorgang.OzgCloudVorgangId;
-
 class VorgangServiceTest {
 
 	@Spy
@@ -25,10 +19,6 @@ class VorgangServiceTest {
 
 	@Mock
 	private VorgangRemoteService remoteService;
-	@Mock
-	private OzgCloudCommandService commandService;
-	@Mock
-	private CommandMapper commandMapper;
 
 	@Nested
 	class TestGetById {
@@ -54,99 +44,4 @@ class VorgangServiceTest {
 			assertThat(result).isEqualTo(vorgang);
 		}
 	}
-
-	@Nested
-	class TestBescheiden {
-
-		private final static Vorgang VORGANG = VorgangTestFactory.create();
-
-		@Mock
-		private OzgCloudCommand ozgCloudCommand;
-
-		@BeforeEach
-		void init() {
-			doReturn(VORGANG).when(service).getById(any(VorgangId.class));
-		}
-
-		@Test
-		void shouldCallGetBeyId() {
-			service.bescheiden(VorgangTestFactory.ID.toString());
-
-			verify(service).getById(VorgangTestFactory.ID);
-		}
-
-		@Test
-		void shouldCallBuildBescheidenCommand() {
-			service.bescheiden(VorgangTestFactory.ID.toString());
-
-			verify(service).buildBescheidenCommand(VORGANG);
-		}
-
-		@Test
-		void shouldCallCommandService() {
-			doReturn(ozgCloudCommand).when(service).buildBescheidenCommand(any());
-
-			service.bescheiden(VorgangTestFactory.ID.toString());
-
-			verify(commandService).createAndWaitUntilDone(ozgCloudCommand);
-		}
-	}
-
-	@Nested
-	class TestBuildBescheidenCommand {
-
-		private final static Vorgang VORGANG = VorgangTestFactory.create();
-
-		@Test
-		void shouldCallCommandMapperToOzgCloudVorgangId() {
-			service.buildBescheidenCommand(VORGANG);
-
-			verify(commandMapper).toOzgCloudVorgangId(VorgangTestFactory.ID.toString());
-		}
-
-		@Test
-		void shouldSetVorgangId() {
-			var expectedId = OzgCloudVorgangId.from(VorgangTestFactory.ID.toString());
-			when(commandMapper.toOzgCloudVorgangId(any())).thenReturn(expectedId);
-
-			var result = service.buildBescheidenCommand(VORGANG);
-
-			assertThat(result.getVorgangId()).isEqualTo(expectedId);
-		}
-
-		@Test
-		void shouldCallCommandMapperMapRelationId() {
-			service.buildBescheidenCommand(VORGANG);
-
-			verify(commandMapper).mapRelationId(VorgangTestFactory.ID.toString());
-		}
-
-		@Test
-		void shouldSetRelationId() {
-			var expectedId = GenericId.from(VorgangTestFactory.ID.toString());
-			when(commandMapper.mapRelationId(any())).thenReturn(expectedId);
-
-			var result = service.buildBescheidenCommand(VORGANG);
-
-			assertThat(result.getRelationId()).isEqualTo(expectedId);
-		}
-
-		@Test
-		void shouldSetRelationVersion() {
-			var expectedVersion = VORGANG.getVersion();
-
-			var result = service.buildBescheidenCommand(VORGANG);
-
-			assertThat(result.getRelationVersion()).isEqualTo(expectedVersion);
-		}
-
-		@Test
-		void shouldSetOrder() {
-			var expectedOrder = VorgangService.VORGANG_BESCHEIDEN;
-
-			var result = service.buildBescheidenCommand(VORGANG);
-
-			assertThat(result.getOrder()).isEqualTo(expectedOrder);
-		}
-	}
 }
diff --git a/bescheid-manager/src/test/resources/SD_answer.xml b/bescheid-manager/src/test/resources/SD_answer.xml
index df9d905e472c9b0a077421064ad61a990389ede5..172f70cc754469dec0ee76b32714c0ea1b127c5c 100644
--- a/bescheid-manager/src/test/resources/SD_answer.xml
+++ b/bescheid-manager/src/test/resources/SD_answer.xml
@@ -258,13 +258,7 @@
          <Field ID="FEC37A441C9D46189533DBD9CFD0E0E8"><![CDATA[STEUBER]]></Field>
          <Field ID="FECCC52ABB614390BAE2577AD8C44262"><![CDATA[24103]]></Field>
          <Field ID="root/CustomerData/Dateiname"><![CDATA[Fleet_9-Verk-AO_01-08_06.12.2023-06.12.2023]]></Field>
-         <NachrichtenText>Sehr geehrte/r Antragstellende,
-
-anliegend erhalten Sie die verkehrsrechtliche Anordnung für die Aufstellung der von Ihnen beantragten Beschilderung. Die Prüfung der Straßenverkehrsbehörde bezieht sich nur auf die Vollständigkeit des Antrages und die Plausibilität der Angaben. Die richtige Auswahl der aufzustellenden Verkehrszeichen oder Überschneidung mit anderen Anträgen wurde dabei nicht geprüft.
-
-BITTE DRINGEND BEACHTEN
-Der Antrag einer mobilen Haltverbotszone ist MINDESTENS 1 Woche vor Aufstellung der Beschilderung zu stellen. Des Weiteren gilt die Beschilderung erst als angeordnet, wenn die Antragstellenden das von der Straßenverkehrsbehörde unterschriebene Anmeldeformular zurückerhalten haben (Fax, E-Mail, Post). Vorab sind keine Schilder aufzustellen!!!
-</NachrichtenText>
+         <NachrichtenText>Nachrichtentext</NachrichtenText>
       </Fields>
       <DocumentProperties>
          <Guid>7ACEA5AE7C3642978ACCC48182EBCD6E</Guid>
diff --git a/bescheid-manager/src/test/resources/SD_answer_field_template.xml b/bescheid-manager/src/test/resources/SD_answer_field_template.xml
new file mode 100644
index 0000000000000000000000000000000000000000..7ad2b6b9bdd219cf10ac96c711d43fff926a4009
--- /dev/null
+++ b/bescheid-manager/src/test/resources/SD_answer_field_template.xml
@@ -0,0 +1,299 @@
+<?xml version='1.0' encoding='UTF-8'?><!--
+  ~ 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.
+  -->
+<root>
+	<SmartDocument Version="2.0">
+		<Selection>
+			<TypistID>072D2DBF07C049858DFB716BDBAAE83A</TypistID>
+			<UserGroupID>
+				DA9D309EF1374D8A920CC9878DD3D629
+			</UserGroupID>
+			<AuthorID>072D2DBF07C049858DFB716BDBAAE83A
+			</AuthorID>
+			<TemplateGroupID>94A1C1208DF0479CB58E3CFB0A6057BC</TemplateGroupID>
+			<Template>
+				KFAS_LIVE_KI_10_Haltverbot_befristet
+			</Template>
+			<TemplateID VersionID="87731D1F4AB74952979B58497D95EA86">
+				7ACEA5AE7C3642978ACCC48182EBCD6E
+			</TemplateID>
+			<Blocks>
+				<Block VersionID="15DCCB4DFE1A414796EBA44352C7AAFF">
+					CC2A9C0E14164B9A967CEE8DCD41B3B5
+				</Block>
+				<Placeholders>
+					<Placeholder ID="125E766AF0424D4992F8F04C806F75EB">
+						CC2A9C0E14164B9A967CEE8DCD41B3B5
+					</Placeholder>
+				</Placeholders>
+			</Blocks>
+			<FixedValues/>
+		</Selection>
+		<Variables/>
+		<QuestionAnswers>
+			<Question ID="07BE1279C0504852AEFBB264D165E139" Description="Tagesdatum" OriginalValue="2024-06-25">
+				25.06.2024
+			</Question>
+			<Question ID="23BB945F7BA44321B09A0A984D541DD1" Description="Tage Halteverbot"
+					  ContentId="23BB945F7BA44321B09A0A984D541DD1" IsFormatted="true" ContentType="XML">
+				<Records>
+					<Record>
+						<Field Name="71F5F35C4FD94982A1F8321A73E9B593">
+							<Value>nein</Value>
+							<QuestionAnswers>
+								<Question ID="58F6E456AE1F4E13907D78E158BF4847" Description="Freitag">
+									<Answer ID="313DC774D89E45D8864FC33983C95923" Description="Nein" IsFormatted="true"
+											ContentId="313DC774D89E45D8864FC33983C95923"/>
+								</Question>
+							</QuestionAnswers>
+						</Field>
+						<Field Name="B66C9D21D31A4293852EEDCAB57C593B">
+							<Value>ja</Value>
+							<QuestionAnswers>
+								<Question ID="EF33891FF01A42B0BEFB1E78E3FC023D" Description="Samstag">
+									<Answer ID="F22F6FE074784CCD950430166F42B33F" Description="Ja" IsFormatted="true"
+											ContentId="F22F6FE074784CCD950430166F42B33F"/>
+								</Question>
+							</QuestionAnswers>
+						</Field>
+						<Field Name="67082AAB675E457180A7014531C46CB3">
+							<Value>ja</Value>
+							<QuestionAnswers>
+								<Question ID="60C6CD1F29084A26BEC493A862583AAB" Description="Montag">
+									<Answer ID="8EAE05F9D89C46AE8CCB08A24104CC17" Description="Ja" IsFormatted="true"
+											ContentId="8EAE05F9D89C46AE8CCB08A24104CC17"/>
+								</Question>
+							</QuestionAnswers>
+						</Field>
+						<Field Name="3FD23F8F98EF459A95B50448DEDFF20E">
+							<Value>ja</Value>
+							<QuestionAnswers>
+								<Question ID="C8BC6BFFE8BE4E6BBDC4CBCD34377DB2" Description="Mittwoch">
+									<Answer ID="97B676CAC9B74D00B574F319B2D20BB5" Description="Ja" IsFormatted="true"
+											ContentId="97B676CAC9B74D00B574F319B2D20BB5"/>
+								</Question>
+							</QuestionAnswers>
+						</Field>
+						<Field Name="09658B4DA4BB4295822A42C0AA8FC2EC">
+							<Value>nein</Value>
+							<QuestionAnswers>
+								<Question ID="39BF39565D4043078ABEEC9601A091E7" Description="Donnerstag">
+									<Answer ID="8D4A19B4D3AF448FB720E9160E7A40D2" Description="Nein" IsFormatted="true"
+											ContentId="8D4A19B4D3AF448FB720E9160E7A40D2"/>
+								</Question>
+							</QuestionAnswers>
+						</Field>
+						<Field Name="975867EBE97547ACA6B8D85F1D8D39C8">
+							<Value>nein</Value>
+							<QuestionAnswers>
+								<Question ID="03906ABB93494C6EB087D87C4C70217C" Description="Dienstag">
+									<Answer ID="B9ACD0E74C6B41BEA700C9EB8FCFFC25" Description="Nein" IsFormatted="true"
+											ContentId="B9ACD0E74C6B41BEA700C9EB8FCFFC25"/>
+								</Question>
+							</QuestionAnswers>
+						</Field>
+						<Field Name="AF89873144744EDC9A1B78776F3D25F5">
+							<Value>nein</Value>
+							<QuestionAnswers>
+								<Question ID="06349259221C4DEFBB4FE9FD33D76403" Description="Sonntag">
+									<Answer ID="853ED74B536C4BD8AF95193450F18201" Description="Nein" IsFormatted="true"
+											ContentId="853ED74B536C4BD8AF95193450F18201"/>
+								</Question>
+							</QuestionAnswers>
+						</Field>
+					</Record>
+				</Records>
+			</Question>
+			<Question ID="28CB094DAD1A4604B08CE7C5D2177C03" Description="Beschilderung">
+				<Answer ID="605F18E32DE04FF2B058BD66F2DE9C06" Description="Nein" IsFormatted="true"
+						ContentId="605F18E32DE04FF2B058BD66F2DE9C06"/>
+			</Question>
+			<Question ID="736372FDB0A2407CBBFB15DE71FD1450" Description="Geschlecht Antragssteller">
+				<Answer ID="CCFD78217BC84D339F582F4B5703A7B6" Description="keine Angabe" IsFormatted="true"
+						ContentId="CCFD78217BC84D339F582F4B5703A7B6"/>
+			</Question>
+			<Question ID="97E309BDBDB548F48D162D289056B313" Description="Uhrzeit Halteverbot">
+				<Answer ID="E45BE1342D5F43D59E21986C377DA1B0" Description="ganztägig" IsFormatted="true"
+						ContentId="E45BE1342D5F43D59E21986C377DA1B0"/>
+			</Question>
+			<Question ID="992F241A1DF4497A8B4568E69B9C567C" Description="Vor Ort geltende Parkregelung">
+				<Answer ID="9875A84F77164A9C88426FD6A01D784F" Description="Parken am Fahrbahnrand" IsFormatted="true"
+						ContentId="9875A84F77164A9C88426FD6A01D784F"/>
+			</Question>
+			<Question ID="9BD81FB0E5FF4235A094BE3D21544615" Description="Name Ansprechperson / Firma"
+					  AlternativeParentID="736372FDB0A2407CBBFB15DE71FD1450">
+				<Answer ID="FC9E396BAA894B52A475BCE1184230D9" Description="keine Angabe" IsFormatted="true"
+						ContentId="FC9E396BAA894B52A475BCE1184230D9"/>
+			</Question>
+			<Question ID="9CE081D9122E43B1B778863AE32AB29F" Description="Protokoll">
+				<Answer ID="8490AF83642D4D26A408A2C431F52183" Description="Nein" IsFormatted="true"
+						ContentId="8490AF83642D4D26A408A2C431F52183"/>
+			</Question>
+			<Question ID="B651AC699A4F4B768DC34DE87BBD578C" Description="Gründe für Halteverbot"
+					  ContentId="B651AC699A4F4B768DC34DE87BBD578C" IsFormatted="true" ContentType="XML">
+				<Records/>
+			</Question>
+			<Question ID="C33A6D64E1B542CB97520C1F32D18C35" Description="Unterschrift">
+				<Answer ID="68A02377AE9D473C9F6BAFF4EF150DE5" Description="Reusche" IsFormatted="true"
+						ContentId="68A02377AE9D473C9F6BAFF4EF150DE5"/>
+			</Question>
+			<Question ID="C7C9CCBF9633499EAB08D1BBB84BFD98" Description="Richtigkeit">
+				<Answer ID="6DF6B7C6A88D4F2282B8366027B0032D" Description="Nein" IsFormatted="true"
+						ContentId="6DF6B7C6A88D4F2282B8366027B0032D"/>
+			</Question>
+			<Question ID="C7D1A20B17CD4C96BF55A2738B8A4631" Description="Kenntnisnahme">
+				<Answer ID="50BBC8449BEB4AFEB774AC706F1D66B9" Description="Nein" IsFormatted="true"
+						ContentId="50BBC8449BEB4AFEB774AC706F1D66B9"/>
+			</Question>
+		</QuestionAnswers>
+		<Fields>
+			<Field ID="3C5C7920FB444A9DB2F5239339599BD7"/>
+			<Field ID="41237CC02584421A8D65990E7F78F833"/>
+			<Field ID="423CB6F4AEB54A44BC67F97626ADC06C"/>
+			<Field ID="442D48B946C64853B78DB99D9341AAC8">16:23</Field>
+			<Field ID="4D4178B6F808409391990233D33BF54C"/>
+			<Field ID="5AE5217E97F845B48D4274894BC2F043">03:25</Field>
+			<Field ID="635CEB0B41DE44EFB2207122CCB8EE1D"/>
+			<Field ID="6B06CD242FC64865BFC5B770BB03EAA4"/>
+			<Field ID="769E3AC926154741AABE870EB802E2AD"/>
+			<Field ID="7AF097E4E741455685CD543ABB7CE337"/>
+			<Field ID="8CA72E11F95F4352AE6FB8001BE79508">25.05.2023</Field>
+			<Field ID="8D38662ADBF2408B8C8DDB5294A5A5A9"/>
+			<Field ID="CA36A227CFEC4B89A40CA8B0CF4460C0">23</Field>
+			<Field ID="CC330D642D7D465FA611D029F6A06344">KFAS_LIVE_KI_10_Haltverbot_befristet-JhQDdq2F</Field>
+			<Field ID="D316B8AE41A3496495C058CCB3766F3A"/>
+			<Field ID="DB270EC247D5476A9D8BFA008E872D7D">Kiel</Field>
+			<Field ID="DE7F7E00C8C246AEA9FFDF7F89E2FB03">05.05.2023</Field>
+			<Field ID="F1826BE2F3D04E508F6401E8AA1D08C1"/>
+			<Field ID="FEC37A441C9D46189533DBD9CFD0E0E8"/>
+			<Field ID="FECCC52ABB614390BAE2577AD8C44262">24114</Field>
+			<Field ID="Template.56E7AA0956C7486292E9A02114CB231C">Nachrichten Field Text</Field>
+			<Field ID="root/CustomerData/Dateiname">_23-Verk-AO_05-23_05.05.2023-25.05.2023</Field>
+		</Fields>
+		<DocumentProperties>
+			<Guid>7ACEA5AE7C3642978ACCC48182EBCD6E</Guid>
+			<BuiltIn>
+				<creator>MGM</creator>
+			</BuiltIn>
+			<Extended/>
+			<Custom>
+				<Author name="Author" type="lpwstr" property="true" variable="false" xml="false">MGM</Author>
+				<Typist name="Typist" type="lpwstr" property="true" variable="false" xml="false">MGM</Typist>
+				<TemplateId name="TemplateId" type="lpwstr" property="true" variable="false" xml="false">
+					7ACEA5AE7C3642978ACCC48182EBCD6E
+				</TemplateId>
+				<Template name="Template" type="lpwstr" property="true" variable="false" xml="false">
+					KFAS_LIVE_KI_10_Haltverbot_befristet
+				</Template>
+			</Custom>
+		</DocumentProperties>
+	</SmartDocument>
+	<CustomerData>
+		<bescheid>
+			<bescheidVom>2023-06-26</bescheidVom>
+			<genehmigt>true</genehmigt>
+		</bescheid>
+		<userData>
+			<firstName>Theo</firstName>
+			<lastName>Test</lastName>
+		</userData>
+		<vorgang>
+			<vorgangName>KFAS_LIVE_KI_10_Haltverbot_befristet</vorgangName>
+			<eingang>
+				<zustaendigeStelle>
+					<organisationseinheitenId>10363455</organisationseinheitenId>
+					<email/>
+				</zustaendigeStelle>
+				<antragsteller/>
+				<formData>
+					<Antrag_abschlie_en>
+						<Ich_best_tige__dass_die_Beschilderung_entsprechend_den_wichtigen_Hinweisen_durchgef_hrt_wird>
+							ja
+						</Ich_best_tige__dass_die_Beschilderung_entsprechend_den_wichtigen_Hinweisen_durchgef_hrt_wird>
+						<Ich_best_tige_hiermit__dass_ein_Protokoll_entsprechend_den_wichtigen_Hinweisen_erstellt_wird>
+							ja
+						</Ich_best_tige_hiermit__dass_ein_Protokoll_entsprechend_den_wichtigen_Hinweisen_erstellt_wird>
+						<Hiermit_best_tige_ich_die_Kenntnisnahme_des_Vorgehens_bei_parkenden_KFZ>ja
+						</Hiermit_best_tige_ich_die_Kenntnisnahme_des_Vorgehens_bei_parkenden_KFZ>
+						<Hiermit_best_tige_ich_die_Richtigkeit_der_gemachten_Angaben>ja
+						</Hiermit_best_tige_ich_die_Richtigkeit_der_gemachten_Angaben>
+					</Antrag_abschlie_en>
+					<Stammdaten__Antragstellende_Person_>
+						<Adresse_Kiel_vorbef_llt_mit_Kontaktdaten>
+							<AS_E-Mail>Bjoern.Reusche@kiel.de</AS_E-Mail>
+							<Postleitzahl>24114</Postleitzahl>
+							<AS_Telefon>015142536149</AS_Telefon>
+							<Wohnort>Kiel</Wohnort>
+							<Stra_e>Je?stra?e</Stra_e>
+							<Hausnummer>23</Hausnummer>
+						</Adresse_Kiel_vorbef_llt_mit_Kontaktdaten>
+						<Nachname>Reusche</Nachname>
+						<Angabe_zur_Person__Firma>m?nnlich</Angabe_zur_Person__Firma>
+						<Verantwortliche_Person_f_r_die_Aufstellung_der_Beschilderung/>
+						<Vorname>Bj?rn</Vorname>
+					</Stammdaten__Antragstellende_Person_>
+					<Angaben_zur_Parkregelung_und_zur_Beschilderung>
+						<Objektgruppe_Hinweis_kein_Abschleppen_m_glich/>
+						<Ort_des_Haltverbotes>
+							<Postleitzahl>24114</Postleitzahl>
+							<Wohnort>Kiel</Wohnort>
+							<Stra_e>Je?stra?e</Stra_e>
+							<Hausnummer>23</Hausnummer>
+						</Ort_des_Haltverbotes>
+						<L_nge_der_Fl_che_in_Metern>25</L_nge_der_Fl_che_in_Metern>
+						<Gr_nde>
+							<Container>nein</Container>
+							<Baufahrzeug>nein</Baufahrzeug>
+							<Materiallagerung>nein</Materiallagerung>
+							<Umzug>ja</Umzug>
+							<Hubsteiger__Kran>nein</Hubsteiger__Kran>
+							<Sonstiges>ja</Sonstiges>
+						</Gr_nde>
+						<Beginn_des_Haltverbotes>05.05.2023</Beginn_des_Haltverbotes>
+						<Bitte_erl_utern_Sie_Ihren_Grund>Verl?ngerung bisher ab 01.04.2023
+						</Bitte_erl_utern_Sie_Ihren_Grund>
+						<Uhrzeit>
+							<Ende_des_Haltverbotes__Uhrzeit_>16:23</Ende_des_Haltverbotes__Uhrzeit_>
+							<Beginn_des_Haltverbotes__Uhrzeit_>03:25</Beginn_des_Haltverbotes__Uhrzeit_>
+						</Uhrzeit>
+						<Vor_Ort_geltende_Parkregelung>Parken am Fahrbahnrand</Vor_Ort_geltende_Parkregelung>
+						<Tage_Haltverbot>
+							<Freitag>nein</Freitag>
+							<Samstag>ja</Samstag>
+							<Montag>ja</Montag>
+							<Mittwoch>ja</Mittwoch>
+							<Donnerstag>nein</Donnerstag>
+							<Dienstag>nein</Dienstag>
+							<Sonntag>nein</Sonntag>
+						</Tage_Haltverbot>
+						<Ende_des_Haltverbotes>25.05.2023</Ende_des_Haltverbotes>
+					</Angaben_zur_Parkregelung_und_zur_Beschilderung>
+					<Informationen_und_Hinweise_zu_erforderlichen_Unterlagen/>
+				</formData>
+			</eingang>
+			<vorgangNummer>KFAS_LIVE_KI_10_Haltverbot_befristet-JhQDdq2F</vorgangNummer>
+			<aktenzeichen>KFAS_LIVE_KI_10_Haltverbot_befristet-JhQDdq2F</aktenzeichen>
+		</vorgang>
+		<Dateiname>_23-Verk-AO_05-23_05.05.2023-25.05.2023</Dateiname>
+	</CustomerData>
+</root>
diff --git a/lombok.config b/lombok.config
index d07dd9b0e2b0281fbf514a968b9451cb6af62f93..a06fa130e8af26b659f2d3a0cb1114cd966a9b0e 100644
--- a/lombok.config
+++ b/lombok.config
@@ -27,4 +27,5 @@ lombok.log.slf4j.flagUsage = ERROR
 lombok.log.log4j.flagUsage = ERROR
 lombok.data.flagUsage = ERROR
 lombok.nonNull.exceptionType = IllegalArgumentException
-lombok.addLombokGeneratedAnnotation = true
\ No newline at end of file
+lombok.addLombokGeneratedAnnotation = true
+lombok.copyableAnnotations += org.springframework.beans.factory.annotation.Qualifier
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index b8aec14705c319a0b4710203f947b9e23d43df88..69d76ac375559970cfc8cb8bdb96f91e0ac11bda 100644
--- a/pom.xml
+++ b/pom.xml
@@ -29,7 +29,7 @@
 	<modelVersion>4.0.0</modelVersion>
 	<groupId>de.ozgcloud.vorgang</groupId>
 	<artifactId>vorgang-manager</artifactId>
-	<version>2.10.0-SNAPSHOT</version>
+	<version>2.11.0</version>
 
 	<name>OZG-Cloud Vorgang Manager</name>
 	<packaging>pom</packaging>
diff --git a/src/main/helm/templates/_helpers.tpl b/src/main/helm/templates/_helpers.tpl
index 7c94e6cfd9851532d35296171f68cff8ba0e46b2..0b1337c8ab4554f6f66827c60f7113b8d6863d86 100644
--- a/src/main/helm/templates/_helpers.tpl
+++ b/src/main/helm/templates/_helpers.tpl
@@ -101,4 +101,26 @@ app.kubernetes.io/namespace: {{ include "app.namespace" . }}
 {{- $customList = append $customList (dict "name" $key "value" $value) }}
 {{- end -}}
 {{- $customList | toYaml -}}
-{{- end -}}
\ No newline at end of file
+{{- end -}}
+
+
+{{- define "app.bayernidAbsenderName" -}}
+{{- quote (required "ozgcloud.bayernid.absender.name must be set if ozgcloud.bayernid is enabled" (((.Values.ozgcloud).bayernid).absender).name) -}} 
+{{- end -}}
+
+{{- define "app.bayernidAbsenderMandant" -}}
+{{- if (((.Values.ozgcloud).bayernid).absender).mandant -}}
+{{ quote .Values.ozgcloud.bayernid.absender.mandant }}
+{{- else -}}
+{{ include "app.bayernidAbsenderName" . }}
+{{- end -}}
+{{- end -}}
+
+{{- define "app.bayernidAbsenderDienst" -}}
+{{- if (((.Values.ozgcloud).bayernid).absender).dienst -}}
+{{  quote .Values.ozgcloud.bayernid.absender.dienst }}
+{{- else -}}
+{{ include "app.bayernidAbsenderName" . }}
+{{- end -}}
+{{- end -}}
+
diff --git a/src/main/helm/templates/deployment.yaml b/src/main/helm/templates/deployment.yaml
index 938946431b8c929bd0bd636f933072eedbe44fca..cbb3ae56d5105372f34de651e87da7b08d689402 100644
--- a/src/main/helm/templates/deployment.yaml
+++ b/src/main/helm/templates/deployment.yaml
@@ -137,6 +137,10 @@ spec:
           - name: spring_ssl_bundle_pem_es-root-ca_truststore_certificate
             value: "/bindings/ca-certificates/es-root-ca.pem"
           {{- end }}
+          {{- if ((.Values.ozgcloud).mongodbsearch).enabled }}
+          - name: ozgcloud_mongodbsearch_enabled
+            value: {{ quote .Values.ozgcloud.mongodbsearch.enabled }}
+          {{- end }}
           {{- with include "app.getCustomList" . }}
 {{ . | indent 10 }}
           {{- end }}
@@ -170,17 +174,27 @@ spec:
           - name: grpc_client_bayern-id_negotiationType
             value: {{ (((.Values.ozgcloud).bayernid).proxy).negotiationType | default "PLAINTEXT" }}
           - name: ozgcloud_bayernid_absender_name
-            value: {{ quote (required "ozgcloud.bayernid.absender.name must be set if ozgcloud.bayernid is enabled" (((.Values.ozgcloud).bayernid).absender).name) }}
+            value: {{ include "app.bayernidAbsenderName" . }}
           - name: ozgcloud_bayernid_absender_anschrift
             value: {{ quote (required "ozgcloud.bayernid.absender.anschrift must be set if ozgcloud.bayernid is enabled" (((.Values.ozgcloud).bayernid).absender).anschrift) }}
           - name: ozgcloud_bayernid_absender_dienst
-            value: {{ quote (required "ozgcloud.bayernid.absender.dienst must be set if ozgcloud.bayernid is enabled" (((.Values.ozgcloud).bayernid).absender).dienst) }}
+            value: {{ include "app.bayernidAbsenderDienst" . }}
           - name: ozgcloud_bayernid_absender_mandant
-            value: {{ quote (required "ozgcloud.bayernid.absender.mandant must be set if ozgcloud.bayernid is enabled" (((.Values.ozgcloud).bayernid).absender).mandant) }}
+            value: {{ include "app.bayernidAbsenderMandant" . }}
           - name: ozgcloud_bayernid_absender_gemeindeSchluessel
             value: {{ quote (required "ozgcloud.bayernid.absender.gemeindeSchluessel must be set if ozgcloud.bayernid is enabled" (((.Values.ozgcloud).bayernid).absender).gemeindeSchluessel) }}
           {{- end }}
+
+          {{- if ((.Values.ozgcloud).muk).enabled }}
+          - name: ozgcloud_muk_sender
+            value: {{ quote (required "ozgcloud.muk.sender must be set if ozgcloud.muk is enabled" ((.Values.ozgcloud).muk).sender) }}
+          - name: ozgcloud_muk_server
+            value: {{ quote (required "ozgcloud.muk.server must be set if ozgcloud.muk is enabled" ((.Values.ozgcloud).muk).server) }}
+          {{- end }}
           
+
+
+
           {{- if ((.Values.ozgcloud).antragraum).enabled }}
           - name: ozgcloud_antragraum_enabled
             value: {{ quote .Values.ozgcloud.antragraum.enabled }}
diff --git a/src/main/helm/templates/network_policy.yaml b/src/main/helm/templates/network_policy.yaml
index 0437702163106cd37fa6be06609c547b8907a3f3..28fab29f9e443b50b32b87d68c9ffdedc0220d4d 100644
--- a/src/main/helm/templates/network_policy.yaml
+++ b/src/main/helm/templates/network_policy.yaml
@@ -109,6 +109,18 @@ spec:
         podSelector: 
           matchLabels:
             component: info-manager
+{{- end }}
+{{- if (.Values.zufiManager).enabled }}
+  - to:
+    - namespaceSelector:
+        matchLabels:
+          kubernetes.io/metadata.name: {{ required "zufiManager.namespace must be set if zufiManager server is enabled" (.Values.zufiManager).namespace }}
+      podSelector: 
+        matchLabels:
+          component: zufi-server
+    ports:
+      - port: 9090
+        protocol: TCP
 {{- end }}
   - to:
     - namespaceSelector:
diff --git a/src/test/helm/deployment_bayernid_test.yaml b/src/test/helm/deployment_bayernid_test.yaml
index 2a73c2761d442304840198966a1641a74081124a..5b4837870b547f1c80384011bbf8dce8305eacc4 100644
--- a/src/test/helm/deployment_bayernid_test.yaml
+++ b/src/test/helm/deployment_bayernid_test.yaml
@@ -42,10 +42,8 @@ tests:
             address: https://proxy.address.local
           absender:
             postkorbId: "postkorbId"
-            name: "name"
             anschrift: "anschrift"
-            dienst: "dienst"
-            mandant: "mandant"
+            name: "name"
             gemeindeSchluessel: "gemeindeSchluessel"
     asserts:
       - contains:
@@ -66,18 +64,18 @@ tests:
       - contains:
           path: spec.template.spec.containers[0].env
           content:
-            name: ozgcloud_bayernid_absender_dienst
-            value: "dienst"
+            name: ozgcloud_bayernid_absender_gemeindeSchluessel
+            value: "gemeindeSchluessel"
       - contains:
           path: spec.template.spec.containers[0].env
           content:
-            name: ozgcloud_bayernid_absender_mandant
-            value: "mandant"
+            name: ozgcloud_bayernid_absender_dienst
+            value: "name"
       - contains:
           path: spec.template.spec.containers[0].env
           content:
-            name: ozgcloud_bayernid_absender_gemeindeSchluessel
-            value: "gemeindeSchluessel"
+            name: ozgcloud_bayernid_absender_mandant
+            value: "name"
       - contains:
           path: spec.template.spec.containers[0].env
           content:
@@ -99,8 +97,6 @@ tests:
           absender:
             postkorbId: "postkorbId"
             anschrift: "anschrift"
-            dienst: "dienst"
-            mandant: "mandant"
             gemeindeSchluessel: "gemeindeSchluessel"
     asserts:
       - failedTemplate:
@@ -115,15 +111,14 @@ tests:
             address: https://proxy.address.local
           absender:
             postkorbId: "postkorbId"
-            name: "name"
-            dienst: "dienst"
-            mandant: "mandant"
+            name: "name_dienst_mandant"
             gemeindeSchluessel: "gemeindeSchluessel"
     asserts:
       - failedTemplate:
           errorMessage: "ozgcloud.bayernid.absender.anschrift must be set if ozgcloud.bayernid is enabled"
 
-  - it: should fail if absender dienst is not set
+
+  - it: should fail if absender gemeindeSchluessel is not set
     set:
       ozgcloud:
         bayernid:
@@ -132,82 +127,86 @@ tests:
             address: https://proxy.address.local
           absender:
             postkorbId: "postkorbId"
-            name: "name"
             anschrift: "anschrift"
-            mandant: "mandant"
-            gemeindeSchluessel: "gemeindeSchluessel"
+            name: "name_dienst_mandant"
     asserts:
       - failedTemplate:
-          errorMessage: "ozgcloud.bayernid.absender.dienst must be set if ozgcloud.bayernid is enabled"
+          errorMessage: "ozgcloud.bayernid.absender.gemeindeSchluessel must be set if ozgcloud.bayernid is enabled"
 
-  - it: should fail if absender mandant is not set
+  - it: should fail if bayernid proxy is enabled but proxy address is not configured
     set:
       ozgcloud:
         bayernid:
           enabled: true
-          proxy:
-            address: https://proxy.address.local
           absender:
             postkorbId: "postkorbId"
-            name: "name"
             anschrift: "anschrift"
-            dienst: "dienst"
+            name: "name_dienst_mandant"
             gemeindeSchluessel: "gemeindeSchluessel"
     asserts:
       - failedTemplate:
-          errorMessage: "ozgcloud.bayernid.absender.mandant must be set if ozgcloud.bayernid is enabled"
+          errorMessage: "ozgcloud.bayernid.proxy.address must be set if ozgcloud.bayernid is enabled"
 
-  - it: should fail if absender gemeindeSchluessel is not set
+  - it: should set the bayernid proxy grpc negotiationType
     set:
       ozgcloud:
         bayernid:
           enabled: true
           proxy:
             address: https://proxy.address.local
+            negotiationType: NOT_DEFAULT
           absender:
             postkorbId: "postkorbId"
-            name: "name"
             anschrift: "anschrift"
-            dienst: "dienst"
-            mandant: "mandant"
+            name: "name_dienst_mandant"
+            gemeindeSchluessel: "gemeindeSchluessel"
     asserts:
-      - failedTemplate:
-          errorMessage: "ozgcloud.bayernid.absender.gemeindeSchluessel must be set if ozgcloud.bayernid is enabled"
+      - contains:
+          path: spec.template.spec.containers[0].env
+          content:
+            name: grpc_client_bayern-id_negotiationType
+            value: NOT_DEFAULT
 
-  - it: should fail if bayernid proxy is enabled but proxy address is not configured
+  - it: should overwrite with absender name if mandant is set
     set:
       ozgcloud:
         bayernid:
           enabled: true
+          proxy:
+            address: https://proxy.address.local
           absender:
             postkorbId: "postkorbId"
-            name: "name"
             anschrift: "anschrift"
-            dienst: "dienst"
+            name: "name"
             mandant: "mandant"
             gemeindeSchluessel: "gemeindeSchluessel"
     asserts:
-      - failedTemplate:
-          errorMessage: "ozgcloud.bayernid.proxy.address must be set if ozgcloud.bayernid is enabled"
-
-  - it: should set the bayernid proxy grpc negotiationType
+      - contains:
+          path: spec.template.spec.containers[0].env
+          content:
+            name: ozgcloud_bayernid_enabled
+            value: "true"
+      - contains:
+          path: spec.template.spec.containers[0].env
+          content:
+            name: ozgcloud_bayernid_absender_mandant
+            value: "mandant"
+  - it: should overwrite with absender name if dienst is set
     set:
       ozgcloud:
         bayernid:
           enabled: true
           proxy:
             address: https://proxy.address.local
-            negotiationType: NOT_DEFAULT
           absender:
             postkorbId: "postkorbId"
-            name: "name"
             anschrift: "anschrift"
+            name: "name"
             dienst: "dienst"
-            mandant: "mandant"
             gemeindeSchluessel: "gemeindeSchluessel"
     asserts:
       - contains:
           path: spec.template.spec.containers[0].env
           content:
-            name: grpc_client_bayern-id_negotiationType
-            value: NOT_DEFAULT
+            name: ozgcloud_bayernid_absender_dienst
+            value: "dienst"
diff --git a/src/test/helm/deployment_mongodb_test.yaml b/src/test/helm/deployment_mongodb_test.yaml
index 7daf5d3196bd7c34413c8aff2741a9159c3a1fdd..ad8a4cb17c47cdca0b5cc89daf2055ec9a24109e 100644
--- a/src/test/helm/deployment_mongodb_test.yaml
+++ b/src/test/helm/deployment_mongodb_test.yaml
@@ -93,3 +93,21 @@ tests:
           content:
             name: spring_data_mongodb_database
             value: vorgang-manager-database
+
+  - it: check mongodb full text search disabled
+    asserts:
+      - notContains:
+          path: spec.template.spec.containers[0].env
+          content:
+            name: ozgcloud_mongodbsearch_enabled
+            value: "true"
+
+  - it: check mongodb full text search enabled
+    set:
+      ozgcloud.mongodbsearch.enabled: true
+    asserts:
+      - contains:
+          path: spec.template.spec.containers[0].env
+          content:
+            name: ozgcloud_mongodbsearch_enabled
+            value: "true"
diff --git a/src/test/helm/deployment_muk_test.yaml b/src/test/helm/deployment_muk_test.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..33c02db5fd14acf174884dc8f09517d0403bf1b1
--- /dev/null
+++ b/src/test/helm/deployment_muk_test.yaml
@@ -0,0 +1,89 @@
+#
+# Copyright (C) 2023 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 muk
+release:
+  name: vorgang-manager
+  namespace: sh-helm-test
+templates:
+  - templates/deployment.yaml
+set:
+  ozgcloud:
+    environment: dev
+  imagePullSecret: test-image-pull-secret
+tests:
+  - it: should set muk values
+    set:
+      ozgcloud:
+        muk:
+          enabled: true
+          server: muk.test.ozg.de
+          sender: "name"
+    asserts:
+      - contains:
+          path: spec.template.spec.containers[0].env
+          content:
+            name: ozgcloud_muk_sender
+            value: "name"
+      - contains:
+          path: spec.template.spec.containers[0].env
+          content:
+            name: ozgcloud_muk_server
+            value: muk.test.ozg.de
+  - it: should not by default set muk values
+    asserts:
+      - notContains:
+          path: spec.template.spec.containers[0].env
+          content:
+            name: ozgcloud_muk_sender
+          any: true
+      - notContains:
+          path: spec.template.spec.containers[0].env
+          content:
+            name: ozgcloud_muk_server
+          any: true
+       
+  - it: should fail if sender name is not set
+    set:
+      ozgcloud:
+        muk:
+          enabled: true
+          server: muk.test.ozg.de  
+    asserts:
+      - failedTemplate:
+          errorMessage: "ozgcloud.muk.sender must be set if ozgcloud.muk is enabled"
+
+
+  - it: should fail if muk server is not set
+    set:
+      ozgcloud:
+        muk:
+          enabled: true
+          sender: "name"
+    asserts:
+      - failedTemplate:
+          errorMessage: "ozgcloud.muk.server must be set if ozgcloud.muk is enabled"
+
+
+
diff --git a/src/test/helm/network_policy_test.yaml b/src/test/helm/network_policy_test.yaml
index 6348f8be5667775ec59dd74d3a1ab935baa25005..f63746306c5edeaa76f17028551c04243a137d31 100644
--- a/src/test/helm/network_policy_test.yaml
+++ b/src/test/helm/network_policy_test.yaml
@@ -27,21 +27,28 @@ release:
   namespace: by-helm-test
 templates:
   - templates/network_policy.yaml
-set: 
-  networkPolicy:
-    dnsServerNamespace: test-dns-namespace
+
 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
@@ -50,6 +57,9 @@ tests:
             namespace: by-helm-test
 
   - it: should set policy target matchLabel
+    set: 
+      networkPolicy:
+        dnsServerNamespace: test-dns-namespace
     asserts:
       - equal:
           path: spec.podSelector
@@ -59,18 +69,27 @@ tests:
 
 
   - it: should add policyType Egress
+    set: 
+      networkPolicy:
+        dnsServerNamespace: test-dns-namespace
     asserts:
       - contains:
           path: spec.policyTypes
           content: Egress
 
   - it: should add policyType Ingress
+    set: 
+      networkPolicy:
+        dnsServerNamespace: test-dns-namespace
     asserts:
       - contains:
           path: spec.policyTypes
           content: Ingress
 
   - it: should add ingress rule for eingangsmanager and alfa
+    set: 
+      networkPolicy:
+        dnsServerNamespace: test-dns-namespace
     asserts:
       - contains:
           path: spec.ingress
@@ -90,6 +109,8 @@ tests:
 
   - it: should add ingress rule for antragraum if antragraum is enabled
     set:
+      networkPolicy:
+        dnsServerNamespace: test-dns-namespace
       ozgcloud:
         antragraum:
           enabled: true
@@ -109,6 +130,8 @@ tests:
 
   - it: should not add ingress rule for antragraum if antragraum is disabled
     set:
+      networkPolicy:
+        dnsServerNamespace: test-dns-namespace
       ozgcloud:
         antragraum:
           enabled: false
@@ -126,6 +149,8 @@ tests:
 
   - it: should throw error if antragraum is enabled but antragraum namespace is not set
     set:
+      networkPolicy:
+        dnsServerNamespace: test-dns-namespace
       ozgcloud:
         antragraum:
           enabled: true
@@ -135,6 +160,9 @@ tests:
 
 
   - it: should add egress rule to elasticsearch
+    set:
+      networkPolicy:
+        dnsServerNamespace: test-dns-namespace
     asserts:
       - contains:
           path: spec.egress
@@ -151,6 +179,9 @@ tests:
                   protocol: TCP
 
   - it: should add egress rule to mongodb
+    set:
+      networkPolicy:
+        dnsServerNamespace: test-dns-namespace
     asserts:
       - contains:
           path: spec.egress
@@ -164,6 +195,9 @@ tests:
                   protocol: TCP
 
   - it: should add egress rule to user-manager
+    set:
+      networkPolicy:
+        dnsServerNamespace: test-dns-namespace
     asserts:
       - contains:
           path: spec.egress
@@ -178,6 +212,8 @@ tests:
 
   - it: should add egress rule to nachrichten-bayernid-proxy if bayernid is enabled
     set:
+      networkPolicy:
+        dnsServerNamespace: test-dns-namespace
       ozgcloud:
         bayernid:
           enabled: true
@@ -200,6 +236,8 @@ tests:
 
   - it: should not add egress rule to bayernid-proxy if bayernid is disabled
     set:
+      networkPolicy:
+        dnsServerNamespace: test-dns-namespace
       ozgcloud:
         bayernid:
           enabled: false
@@ -220,6 +258,8 @@ tests:
   
   - it: should throw error if bayernid-proxy is enabled but bayernid namespace is not set
     set:
+      networkPolicy:
+        dnsServerNamespace: test-dns-namespace
       ozgcloud:
         bayernid:
           enabled: true
@@ -229,6 +269,8 @@ tests:
 
   - it: should add egress rule to info-manager if antragraum is enabled
     set:
+      networkPolicy:
+        dnsServerNamespace: test-dns-namespace
       ozgcloud:
         antragraum:
           enabled: true
@@ -247,6 +289,8 @@ tests:
 
   - it: should not add egress rule to info-manager if antragraum is disabled
     set:
+      networkPolicy:
+        dnsServerNamespace: test-dns-namespace
       ozgcloud:
         antragraum:
           enabled: false
@@ -262,8 +306,83 @@ tests:
                   matchLabels:
                     component: info-manager
 
+  - it: should add egress rule to zufi server if zufi is enabled
+    set:
+      networkPolicy:
+        dnsServerNamespace: test-dns-namespace
+      zufiManager:
+        enabled: true
+        namespace: zufi
+    asserts:
+      - contains:
+          path: spec.egress
+          content:
+            to:
+            - podSelector: 
+                matchLabels:
+                  component: zufi-server
+              namespaceSelector:
+                matchLabels:
+                      kubernetes.io/metadata.name: zufi
+            ports:
+            - port: 9090
+              protocol: TCP         
+                  
+
+  - it: should not add egress rule to zufi server if zufi is disabled
+    set:
+      networkPolicy:
+        dnsServerNamespace: test-dns-namespace
+      zufiManager:
+        enabled: false
+        namespace: zufi
+    asserts:
+      - notContains:
+          path: spec.egress
+          content:
+            to:
+            - namespaceSelector:
+                matchLabels:
+                  kubernetes.io/metadata.name: zufi
+              podSelector: 
+                matchLabels:
+                  component: zufi-server
+          any: true
+  
+  - it: should throw error if zufi is enabled but zufi namespace is not set
+    set:
+      networkPolicy:
+        dnsServerNamespace: test-dns-namespace
+      zufiManager:
+        enabled: true
+    asserts:
+      - failedTemplate:
+          errorMessage: zufiManager.namespace must be set if zufiManager server is enabled
+
+  - it: should not enable zufi netpol by default
+    set:
+      zufiManager:
+        namespace: zufi
+      networkPolicy:
+        dnsServerNamespace: test-dns-namespace
+    asserts:
+      - notContains:
+          path: spec.egress
+          content: 
+            to:
+            - namespaceSelector:
+                matchLabels:
+                  kubernetes.io/metadata.name: zufi
+              podSelector: 
+                matchLabels:
+                  component: zufi-server
+          any: true
+
 
   - it: should add egress rule to dns service
+    set:
+      networkPolicy:
+        dnsServerNamespace: test-dns-namespace
     asserts:
       - contains:
           path: spec.egress
@@ -285,6 +404,7 @@ tests:
   - it: add ingress rule local by values
     set:
       networkPolicy:
+        dnsServerNamespace: test-dns-namespace
         ssoPublicIp: 51.89.117.53/32
         additionalIngressConfigGlobal:
         - from:
@@ -302,6 +422,7 @@ tests:
   - it: add ingress rule global by values
     set:
       networkPolicy:
+        dnsServerNamespace: test-dns-namespace
         ssoPublicIp: 51.89.117.53/32
         additionalIngressConfigLocal:
         - from:
@@ -320,6 +441,7 @@ tests:
   - it: add egress rules local by values
     set:
       networkPolicy:
+        dnsServerNamespace: test-dns-namespace
         additionalEgressConfigGlobal:
         - to:
           - ipBlock:
@@ -351,6 +473,7 @@ tests:
   - it: add egress rules global by values
     set:
       networkPolicy:
+        dnsServerNamespace: test-dns-namespace
         additionalEgressConfigLocal:
         - to:
           - ipBlock:
@@ -380,6 +503,22 @@ tests:
     set:
       networkPolicy:
         disabled: false
+        dnsServerNamespace: test-dns-namespace
+    asserts:
+      - hasDocuments:
+          count: 1
+  - it: test network policy dnsServerNamespace must be set message
+    set:
+      networkPolicy:
+        disabled: false
+    asserts:
+      - failedTemplate:
+          errorMessage: networkPolicy.dnsServerNamespace must be set
+
+  - it: test network policy should be enabled by default
+    set:
+      networkPolicy:
+        dnsServerNamespace: test-dns-server-namespace
     asserts:
       - hasDocuments:
           count: 1
\ No newline at end of file
diff --git a/vorgang-manager-base/pom.xml b/vorgang-manager-base/pom.xml
index 1d761fc80a6fe434e581a1c7086173c68a23d140..13c6cee9c7ebd19a755214ee3f78296d08d5c171 100644
--- a/vorgang-manager-base/pom.xml
+++ b/vorgang-manager-base/pom.xml
@@ -6,13 +6,13 @@
 	<parent>
 		<groupId>de.ozgcloud.common</groupId>
 		<artifactId>ozgcloud-common-parent</artifactId>
-		<version>4.2.0</version>
+		<version>4.3.1</version>
 		<relativePath />
 	</parent>
 
 	<groupId>de.ozgcloud.vorgang</groupId>
 	<artifactId>vorgang-manager-base</artifactId>
-	<version>2.10.0-SNAPSHOT</version>
+	<version>2.11.0</version>
 
 	<name>OZG-Cloud Vorgang Manager Base</name>
 
diff --git a/vorgang-manager-command/pom.xml b/vorgang-manager-command/pom.xml
index a925adb4f7fd6f221cb12c537a830c964746f155..0218816d637929d230adbbe0101508d2640878da 100644
--- a/vorgang-manager-command/pom.xml
+++ b/vorgang-manager-command/pom.xml
@@ -4,13 +4,13 @@
 	<parent>
 		<groupId>de.ozgcloud.common</groupId>
 		<artifactId>ozgcloud-common-dependencies</artifactId>
-		<version>4.2.0</version>
+		<version>4.3.1</version>
 		<relativePath/>
 	</parent>
 	
 	<groupId>de.ozgcloud.command</groupId>
 	<artifactId>command-manager</artifactId>
-	<version>2.10.0-SNAPSHOT</version>
+	<version>2.11.0</version>
 	<name>OZG-Cloud Command Manager</name>
 
 	<properties>
diff --git a/vorgang-manager-command/src/main/java/de/ozgcloud/command/CommandStatus.java b/vorgang-manager-command/src/main/java/de/ozgcloud/command/CommandStatus.java
index 926ca62da79c8ac64c56bc9fd4d9f0fc59e84aea..31bbfd577e335865cdebef9b37de0c5613c52f18 100644
--- a/vorgang-manager-command/src/main/java/de/ozgcloud/command/CommandStatus.java
+++ b/vorgang-manager-command/src/main/java/de/ozgcloud/command/CommandStatus.java
@@ -24,5 +24,5 @@
 package de.ozgcloud.command;
 
 public enum CommandStatus {
-	PENDING, FINISHED, ERROR, REVOKE_PENDING, REVOKED;
+	NEW, PENDING, CANCELED, FINISHED, ERROR, REVOKE_PENDING, REVOKED
 }
\ No newline at end of file
diff --git a/vorgang-manager-interface/pom.xml b/vorgang-manager-interface/pom.xml
index 82b9fd15bf7446722b17111e93d1edb70509123e..56ed88df8b7238fa7a5cd224e0e1b960a134a2c9 100644
--- a/vorgang-manager-interface/pom.xml
+++ b/vorgang-manager-interface/pom.xml
@@ -30,13 +30,13 @@
 	<parent>
 		<groupId>de.ozgcloud.common</groupId>
 		<artifactId>ozgcloud-common-dependencies</artifactId>
-		<version>4.2.0</version>
+		<version>4.3.1</version>
 		<relativePath/>
 	</parent>
 
 	<groupId>de.ozgcloud.vorgang</groupId>
 	<artifactId>vorgang-manager-interface</artifactId>
-	<version>2.10.0-SNAPSHOT</version>
+	<version>2.11.0</version>
 
 	<name>OZG-Cloud Vorgang Manager gRPC Interface</name>
 	<description>Interface (gRPC) for Vorgang Manager Server</description>
diff --git a/vorgang-manager-server/pom.xml b/vorgang-manager-server/pom.xml
index 8803d73a38204b69940da7542fdf439e99fe2990..e4f8fcb56d9daf4a1753d9b118646529eabb91a0 100644
--- a/vorgang-manager-server/pom.xml
+++ b/vorgang-manager-server/pom.xml
@@ -32,13 +32,13 @@
 	<parent>
 		<groupId>de.ozgcloud.common</groupId>
 		<artifactId>ozgcloud-common-parent</artifactId>
-		<version>4.3.0</version>
+		<version>4.3.1</version>
 		<relativePath />
 	</parent>
 
 	<groupId>de.ozgcloud.vorgang</groupId>
 	<artifactId>vorgang-manager-server</artifactId>
-	<version>2.10.0-SNAPSHOT</version>
+	<version>2.11.0</version>
 
 	<name>OZG-Cloud Vorgang Manager Server</name>
 	<description>Server Implementierung des VorgangManagers</description>
@@ -50,12 +50,12 @@
 		<spring-boot.build-image.imageName>docker.ozg-sh.de/vorgang-manager:build-latest</spring-boot.build-image.imageName>
 
 		<ozgcloud.license.version>1.3.0</ozgcloud.license.version>
-		<zufi-manager-interface.version>1.0.0-SNAPSHOT</zufi-manager-interface.version>
+		<zufi-manager-interface.version>1.0.0</zufi-manager-interface.version>
 
 		<user-manager-interface.version>2.1.0</user-manager-interface.version>
-		<bescheid-manager.version>1.13.0</bescheid-manager.version>
-		<processor-manager.version>0.4.0</processor-manager.version>
-		<nachrichten-manager.version>2.9.0</nachrichten-manager.version>
+		<bescheid-manager.version>1.15.0</bescheid-manager.version>
+		<processor-manager.version>0.4.1</processor-manager.version>
+		<nachrichten-manager.version>2.10.0</nachrichten-manager.version>
 		<ozgcloud-starter.version>0.10.0</ozgcloud-starter.version>
 		<notification-manager.version>2.8.0</notification-manager.version>
 
@@ -369,6 +369,7 @@
 						<env>
 							<BPE_DELIM_JAVA_TOOL_OPTIONS xml:space="preserve"> </BPE_DELIM_JAVA_TOOL_OPTIONS>
 							<BPE_APPEND_JAVA_TOOL_OPTIONS>-Dfile.encoding=UTF-8</BPE_APPEND_JAVA_TOOL_OPTIONS>
+							<BPE_APPEND_LC_ALL>en_US.UTF-8</BPE_APPEND_LC_ALL>
 						</env>
 					</image>
 					<profiles>
diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/VorgangManagerCallContextProvider.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/VorgangManagerCallContextProvider.java
index 62811097900c5e6daee5d06831962184579d63b8..3fe994644fae00480fdda6814cae0dcbec5abb5a 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/VorgangManagerCallContextProvider.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/VorgangManagerCallContextProvider.java
@@ -31,6 +31,7 @@ import org.springframework.stereotype.Component;
 import de.ozgcloud.apilib.common.callcontext.CallContext;
 import de.ozgcloud.apilib.common.callcontext.OzgCloudCallContextProvider;
 import de.ozgcloud.apilib.user.OzgCloudUserId;
+import de.ozgcloud.vorgang.callcontext.CallContextUser;
 import de.ozgcloud.vorgang.callcontext.CurrentUserService;
 import de.ozgcloud.vorgang.callcontext.VorgangManagerClientCallContextAttachingInterceptor;
 import lombok.RequiredArgsConstructor;
@@ -45,11 +46,11 @@ public class VorgangManagerCallContextProvider implements OzgCloudCallContextPro
 	@Override
 	public CallContext provideContext() {
 		var callContextBuilder = CallContext.builder().clientName(VorgangManagerClientCallContextAttachingInterceptor.VORGANG_MANAGER_CLIENT_NAME);
-		getUserId().ifPresent(callContextBuilder::userId);
+		findUserId().ifPresent(callContextBuilder::userId);
 		return callContextBuilder.build();
 	}
 
-	Optional<OzgCloudUserId> getUserId() {
-		return currentUserService.getUser().getUserId().map(OzgCloudUserId::from);
+	Optional<OzgCloudUserId> findUserId() {
+		return currentUserService.findUser().flatMap(CallContextUser::getUserId).map(OzgCloudUserId::from);
 	}
 }
diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/VorgangProcessorConfiguration.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/VorgangProcessorConfiguration.java
index 56d602a31ebc0a372e80cb958e604f85c5e7fef1..9fdab580da21c2a57572b28612b428f8a198fbd7 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/VorgangProcessorConfiguration.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/VorgangProcessorConfiguration.java
@@ -7,29 +7,15 @@ import de.ozgcloud.apilib.common.callcontext.OzgCloudCallContextProvider;
 import de.ozgcloud.apilib.user.GrpcOzgCloudUserProfileService;
 import de.ozgcloud.apilib.user.OzgCloudUserProfileService;
 import de.ozgcloud.apilib.user.UserProfileMapper;
-import de.ozgcloud.apilib.vorgang.OzgCloudVorgangService;
-import de.ozgcloud.apilib.vorgang.grpc.GrpcOzgCloudVorgangService;
-import de.ozgcloud.apilib.vorgang.grpc.OzgCloudVorgangMapper;
-import de.ozgcloud.apilib.vorgang.grpc.OzgCloudVorgangStubMapper;
 import de.ozgcloud.user.grpc.userprofile.UserProfileServiceGrpc.UserProfileServiceBlockingStub;
-import de.ozgcloud.vorgang.vorgang.VorgangServiceGrpc.VorgangServiceBlockingStub;
 import net.devh.boot.grpc.client.inject.GrpcClient;
 
 @Configuration
 class VorgangProcessorConfiguration {
 
-	@GrpcClient("vorgang-manager")
-	private VorgangServiceBlockingStub vorgangServiceStub;
-
 	@GrpcClient("user-manager")
 	private UserProfileServiceBlockingStub userProfileServiceGrpc;
 
-	@Bean
-	OzgCloudVorgangService ozgCloudVorgangService(OzgCloudVorgangMapper mapper, OzgCloudVorgangStubMapper stubMapper,
-			OzgCloudCallContextProvider contextProvider) {
-		return new GrpcOzgCloudVorgangService(vorgangServiceStub, mapper, stubMapper, contextProvider);
-	}
-
 	@Bean
 	OzgCloudUserProfileService ozgCloudUserProfileService(UserProfileMapper mapper, OzgCloudCallContextProvider contextProvider) {
 		return new GrpcOzgCloudUserProfileService(userProfileServiceGrpc, mapper, contextProvider);
diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemCustomRepository.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemCustomRepository.java
index 60d9b646de80c056a7f4df16a06c69861ab571e8..0fcd73c898e729dc7d06ef4f9f862976e4f60676 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemCustomRepository.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemCustomRepository.java
@@ -27,6 +27,10 @@ import java.util.Map;
 
 interface VorgangAttachedItemCustomRepository {
 
+	void update(String itemId, long version, Map<String, Object> properyMap);
+
+	void forceUpdate(String itemId, Map<String, Object> propertyMap);
+
 	void patch(String itemId, long version, Map<String, Object> propertyMap);
 
 	void forcePatch(String itemId, Map<String, Object> propertyMap);
diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemCustomRepositoryImpl.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemCustomRepositoryImpl.java
index 66c828d24149e338c647d9eff9d1f7e34347c033..21a29bfe93e5821cf99dceee801fbc234908a6a4 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemCustomRepositoryImpl.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemCustomRepositoryImpl.java
@@ -60,23 +60,41 @@ public class VorgangAttachedItemCustomRepositoryImpl implements VorgangAttachedI
 	}
 
 	boolean doVorgangAttachedItemExist(String itemId) {
-		return mongoOperations.exists(query(isId(itemId)), VorgangAttachedItem.COLLECTION_NAME);
+		return mongoOperations.exists(createQueryById(itemId), VorgangAttachedItem.class);
+	}
+
+	@Override
+	public void update(String itemId, long version, Map<String, Object> properyMap) {
+		var updateResult = mongoOperations.updateFirst(query(byIdAndVersion(itemId, version)), buildUpdateForItemAndVersion(properyMap),
+				VorgangAttachedItem.class);
+		collisionVerifier.verify(updateResult, itemId);
+	}
+
+	@Override
+	public void forceUpdate(String itemId, Map<String, Object> propertyMap) {
+		mongoOperations.updateFirst(createQueryById(itemId), buildUpdateForItemAndVersion(propertyMap), VorgangAttachedItem.class);
+	}
+
+	private Update buildUpdateForItemAndVersion(Map<String, Object> propertyMap) {
+		var item = new Document();
+		item.putAll(propertyMap);
+		return new Update().set(VorgangAttachedItem.FIELDNAME_ITEM, item).inc(VorgangAttachedItem.FIELDNAME_VERSION, 1);
 	}
 
 	@Override
 	public void patch(String itemId, long version, Map<String, Object> propertyMap) {
-		mongoOperations.updateFirst(
+		var patchedResult = mongoOperations.updateFirst(
 				query(byIdAndVersion(itemId, version)),
-				createUpdateForItemAndVersion(propertyMap),
+				createPatchUpdateForItemAndVersion(propertyMap),
 				VorgangAttachedItem.class);
-
+		collisionVerifier.verify(patchedResult, itemId);
 	}
 
 	@Override
 	public void forcePatch(String itemId, Map<String, Object> propertiesMap) {
 		mongoOperations.updateFirst(
 				createQueryById(itemId),
-				createUpdateForItemAndVersion(propertiesMap),
+				createPatchUpdateForItemAndVersion(propertiesMap),
 				VorgangAttachedItem.class);
 	}
 
@@ -100,12 +118,12 @@ public class VorgangAttachedItemCustomRepositoryImpl implements VorgangAttachedI
 		return where(VorgangAttachedItem.FIELDNAME_IS_DELETED).is(false);
 	}
 
-	private Update createUpdateForItemAndVersion(Map<String, Object> propertyMap) {
+	private Update createPatchUpdateForItemAndVersion(Map<String, Object> propertyMap) {
 		return Update.fromDocument(buildItemPatchDocument(propertyMap)).inc(VorgangAttachedItem.FIELDNAME_VERSION, 1);
 	}
 
 	private Document buildItemPatchDocument(Map<String, Object> propertiesMap) {
-		Map<String, Object> resultMap = new HashMap<>(propertiesMap.size());
+		var resultMap = new HashMap<String, Object>(propertiesMap.size());
 		propertiesMap.forEach((k, v) -> resultMap.put("%s.%s".formatted(VorgangAttachedItem.FIELDNAME_ITEM, k), v));
 		return new Document(resultMap);
 	}
@@ -122,5 +140,4 @@ public class VorgangAttachedItemCustomRepositoryImpl implements VorgangAttachedI
 				Update.update(VorgangAttachedItem.FIELDNAME_IS_DELETED, deleted), VorgangAttachedItem.COLLECTION_NAME);
 		collisionVerifier.verify(updateResult, itemId);
 	}
-
 }
\ No newline at end of file
diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemEventListener.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemEventListener.java
index b32e3bd29b0bcaa5dfd0378b1f1f1406092ceab0..cf991372cac1e53ef918bf360128a4939f9ccb6c 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemEventListener.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemEventListener.java
@@ -23,28 +23,32 @@
  */
 package de.ozgcloud.vorgang.attached_item;
 
+import java.util.HashMap;
+import java.util.Map;
 import java.util.Objects;
+import java.util.Set;
 import java.util.function.Predicate;
 
+import jakarta.validation.ValidationException;
+
 import org.apache.commons.lang3.StringUtils;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.ApplicationEventPublisher;
 import org.springframework.context.event.EventListener;
 import org.springframework.stereotype.Component;
 
-import jakarta.validation.ValidationException;
-
 import de.ozgcloud.command.Command;
 import de.ozgcloud.command.CommandCreatedEvent;
 import de.ozgcloud.command.CommandFailedEvent;
-import de.ozgcloud.command.CommandRevokeFailedEvent;
-import de.ozgcloud.command.CommandRevokedEvent;
 import de.ozgcloud.command.RevokeCommandEvent;
+import de.ozgcloud.vorgang.command.CommandService;
 import de.ozgcloud.vorgang.command.Order;
+import de.ozgcloud.vorgang.command.PersistedCommand;
 import de.ozgcloud.vorgang.vorgang.VorgangDeletedEvent;
+import lombok.RequiredArgsConstructor;
 import lombok.extern.log4j.Log4j2;
 
 @Component
+@RequiredArgsConstructor
 @Log4j2
 class VorgangAttachedItemEventListener {
 
@@ -58,42 +62,52 @@ class VorgangAttachedItemEventListener {
 	public static final Predicate<Command> IS_PATCH_ITEM_ORDER = command -> Order.PATCH_ATTACHED_ITEM.isMeant(command.getOrder());
 	public static final Predicate<Command> IS_DELETE_ITEM_ORDER = command -> Order.DELETE_ATTACHED_ITEM.isMeant(command.getOrder());
 
-	@Autowired
-	private VorgangAttachedItemService service;
-	@Autowired
-	private VorgangAttachedItemMapper mapper;
-	@Autowired
-	private ApplicationEventPublisher publisher;
+	private final VorgangAttachedItemService service;
+	private final VorgangAttachedItemMapper mapper;
+
+	private final ApplicationEventPublisher publisher;
+
+	private final CommandService commandService;
 
 	@EventListener(condition = IS_CREATE_ITEM_ORDER_CONDITION)
 	public void createItem(CommandCreatedEvent event) {
 		var command = event.getSource();
 		validateCreateCommand(command);
 
-		var item = mapper.fill(command.getBodyObject());
-		service.create(command.getId(), item.toBuilder().id(null).version(0).build());
+		var item = mapper.fill(command.getBodyObject()).toBuilder().id(null).version(0).build();
+		service.create(command.getId(), item);
 	}
 
-	private void validateCreateCommand(Command command) {
+	void validateCreateCommand(Command command) {
 		if (!StringUtils.equals(command.getRelationId(), command.getVorgangId())) {
 			throw new ValidationException("Command invalid creation command: vorgangId and relationId must be equals");
 		}
-
 	}
 
 	@EventListener(condition = IS_UPDATE_ITEM_ORDER_CONDITION)
 	public void updateItem(CommandCreatedEvent event) {
 		var command = event.getSource();
-		var itemBuilder = mapper.fill(command.getBodyObject())
-				.toBuilder().id(command.getRelationId());
+		var filledItem = mapper.fill(command.getBodyObject()).toBuilder().id(command.getRelationId()).build();
+
+		setCommandPreviousState(command.getId(), getVorgangAttachedItem(command.getRelationId()).getItem());
 
-		if (Objects.nonNull(command.getRelationVersion())) {
-			itemBuilder.version(command.getRelationVersion());
-			service.update(command.getId(), itemBuilder.build());
+		doUpdate(command, filledItem);
+	}
+
+	private void doUpdate(Command command, VorgangAttachedItem filledItem) {
+		if (isVersionSet(command)) {
+			service.update(command.getId(), filledItem.toBuilder().version(command.getRelationVersion()).build());
 		} else {
-			service.forceUpdate(command.getId(), itemBuilder.build());
+			service.forceUpdate(command.getId(), filledItem.getId(), filledItem.getItem());
 		}
+	}
+
+	private boolean isVersionSet(Command command) {
+		return Objects.nonNull(command.getRelationVersion()) && command.getRelationVersion() > 0;
+	}
 
+	VorgangAttachedItem getVorgangAttachedItem(String id) {
+		return service.getById(id);
 	}
 
 	@EventListener(condition = IS_PATCH_ITEM_ORDER_CONDITION)
@@ -101,9 +115,20 @@ class VorgangAttachedItemEventListener {
 		var command = event.getSource();
 		var item = mapper.fill(command.getBodyObject());
 
+		setCommandPreviousState(command.getId(), getExistingItemMapEntries(command.getRelationId(), item.getItem().keySet()));
+
 		service.patch(command, item.getItem());
 	}
 
+	Map<String, Object> getExistingItemMapEntries(String id, Set<String> keys) {
+		return getVorgangAttachedItem(id).getItem().entrySet().stream().filter(entry -> keys.contains(entry.getKey()))
+				.collect(HashMap::new, (itemMap, entry) -> itemMap.put(entry.getKey(), entry.getValue()), HashMap::putAll);
+	}
+
+	void setCommandPreviousState(String commandId, Map<String, Object> itemMap) {
+		commandService.setPreviousState(commandId, itemMap);
+	}
+
 	@EventListener(condition = IS_DELETE_ITEM_ORDER_CONDITION)
 	public void deleteItem(CommandCreatedEvent event) {
 		var command = event.getSource();
@@ -129,16 +154,31 @@ class VorgangAttachedItemEventListener {
 		}
 	}
 
+	@EventListener(condition = IS_CREATE_ITEM_ORDER_CONDITION)
+	public void onRevokeCreateItem(RevokeCommandEvent event) {
+		service.revokeCreate(event.getSource());
+	}
+
 	@EventListener(condition = IS_DELETE_ITEM_ORDER_CONDITION)
 	public void onRevokeDeleteItem(RevokeCommandEvent event) {
+		service.revokeDelete(event.getSource());
+	}
+
+	@EventListener(condition = IS_UPDATE_ITEM_ORDER_CONDITION)
+	public void onRevokeUpdateItem(RevokeCommandEvent event) {
 		var command = event.getSource();
-		try {
-			service.unmarkAsDeleteByIdAndVersion(command.getRelationId(), command.getRelationVersion());
-			publisher.publishEvent(new CommandRevokedEvent(command));
-		} catch (RuntimeException e) {
-			LOG.error("Revoke of delete item command failed", e);
-			publisher.publishEvent(new CommandRevokeFailedEvent(command.getId(), e.getMessage()));
-		}
+		var persistedCommand = getPersistedCommand(command.getId());
+		service.revokeUpdate(command, persistedCommand.getPreviousState());
+	}
+
+	@EventListener(condition = IS_PATCH_ITEM_ORDER_CONDITION)
+	public void onRevokePatchItem(RevokeCommandEvent event) {
+		var command = event.getSource();
+		var persistedCommand = getPersistedCommand(command.getId());
+		service.revokePatch(command, persistedCommand.getPreviousState());
 	}
 
+	private PersistedCommand getPersistedCommand(String commandId) {
+		return (PersistedCommand) commandService.getById(commandId);
+	}
 }
diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemMapper.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemMapper.java
index b4ebb33584da5dd2745b959dbcee27d8a3fc3bdd..74edfabb0549cae70fba2d7443ba3d9ed3008c20 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemMapper.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemMapper.java
@@ -24,7 +24,6 @@
 package de.ozgcloud.vorgang.attached_item;
 
 import java.util.Map;
-import java.util.Optional;
 
 import org.apache.commons.collections.MapUtils;
 import org.mapstruct.Mapper;
@@ -41,25 +40,18 @@ public interface VorgangAttachedItemMapper {
 	public static final String PROPERTY_ITEM_NAME = "itemName";
 	public static final String PROPERTY_ITEM = "item";
 
-	@SuppressWarnings("unchecked")
 	default VorgangAttachedItem fill(Map<String, Object> propertyMap) {
-
 		return VorgangAttachedItem.builder()
-				.id(extractIdFromItem(propertyMap))
 				.client(MapUtils.getString(propertyMap, PROPERTY_CLIENT))
 				.vorgangId(MapUtils.getString(propertyMap, PROPERTY_VORGANG_ID))
 				.itemName(MapUtils.getString(propertyMap, PROPERTY_ITEM_NAME))
-				.item((Map<String, Object>) propertyMap.get(PROPERTY_ITEM))
+				.item(getPropertyItem(propertyMap))
 				.version(MapUtils.getLong(propertyMap, PROPERTY_VERSION, 0L))
 				.build();
 	}
 
-	// TODO remove mapping of id from Map
 	@SuppressWarnings("unchecked")
-	default String extractIdFromItem(Map<String, Object> propertyMap) {
-		return (String) Optional.ofNullable(propertyMap.get(PROPERTY_ID))
-				.orElseGet(() -> ((Map<String, Object>) propertyMap.get(PROPERTY_ITEM)).get(PROPERTY_ID));
-
+	default Map<String, Object> getPropertyItem(Map<String, Object> propertyMap) {
+		return (Map<String, Object>) propertyMap.get(PROPERTY_ITEM);
 	}
-
 }
diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemService.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemService.java
index cf25401a6607aa4468ddad30e456b9f35924904f..06aafc83380e42ac5d8ab5bdbd82ac5ff5f9914f 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemService.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemService.java
@@ -31,25 +31,28 @@ import java.util.stream.Stream;
 
 import jakarta.validation.Valid;
 
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.ApplicationEventPublisher;
 import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
 
 import de.ozgcloud.command.Command;
+import de.ozgcloud.command.CommandRevokeFailedEvent;
+import de.ozgcloud.command.CommandRevokedEvent;
 import de.ozgcloud.vorgang.common.errorhandling.NotFoundException;
 import lombok.NonNull;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.log4j.Log4j2;
 
-@Service
+@Log4j2
 @Validated
+@RequiredArgsConstructor
+@Service
 public class VorgangAttachedItemService {
 
 	static final boolean NOT_DELETED = false;
 
-	@Autowired
-	private VorgangAttachedItemRepository repository;
-	@Autowired
-	private ApplicationEventPublisher publisher;
+	private final VorgangAttachedItemRepository repository;
+	private final ApplicationEventPublisher publisher;
 
 	public VorgangAttachedItem create(@NonNull String commandId, @Valid VorgangAttachedItem item) {
 		var saved = repository.save(prepareForCreation(item));
@@ -74,13 +77,21 @@ public class VorgangAttachedItemService {
 	}
 
 	public void update(String commandId, VorgangAttachedItem item) {
-		repository.patch(item.getId(), item.getVersion(), item.getItem());
+		doUpdate(item.getId(), item.getVersion(), item.getItem());
 
 		publisher.publishEvent(new VorgangAttachedItemUpdatedEvent(commandId));
 	}
 
-	public void forceUpdate(String commandId, VorgangAttachedItem item) {
-		repository.forcePatch(item.getId(), item.getItem());
+	public void revokeUpdate(Command command, Map<String, Object> itemMap) {
+		handleRevoke(command, () -> doUpdate(command.getRelationId(), command.getRelationVersion() + 1, itemMap));
+	}
+
+	void doUpdate(String id, long version, Map<String, Object> body) {
+		repository.update(id, version, body);
+	}
+
+	public void forceUpdate(String commandId, String itemId, Map<String, Object> itemMap) {
+		repository.forceUpdate(itemId, itemMap);
 
 		publisher.publishEvent(new VorgangAttachedItemUpdatedEvent(commandId));
 	}
@@ -115,11 +126,19 @@ public class VorgangAttachedItemService {
 	}
 
 	public void patch(Command command, Map<String, Object> body) {
-		repository.patch(command.getRelationId(), command.getRelationVersion(), body);
+		doPatch(command, command.getRelationVersion(), body);
 
 		publisher.publishEvent(new VorgangAttachedItemUpdatedEvent(command.getId()));
 	}
 
+	public void revokePatch(Command command, Map<String, Object> itemMap) {
+		handleRevoke(command, () -> doPatch(command, command.getRelationVersion() + 1, itemMap));
+	}
+
+	void doPatch(Command command, Long relationVersion, Map<String, Object> body) {
+		repository.patch(command.getRelationId(), relationVersion, body);
+	}
+
 	public VorgangAttachedItem getById(String id) {
 		var attachedItem = repository.findByIdAndDeleted(id, NOT_DELETED).orElseThrow(() -> new NotFoundException(VorgangAttachedItem.class, id));
 
@@ -136,12 +155,33 @@ public class VorgangAttachedItemService {
 		repository.updateDeleted(true, itemId, version);
 	}
 
-	public void unmarkAsDeleteByIdAndVersion(String itemId, long version) {
-		repository.updateDeleted(false, itemId, version);
-	}
-
 	public void deleteByVorgangId(String vorgangId) {
 		repository.deleteByVorgangId(vorgangId);
 	}
 
+	public void revokeCreate(Command command) {
+		handleRevoke(command, () -> delete(command.getRelationId(), command.getRelationVersion()));
+	}
+
+	void delete(String id, long version) {
+		repository.delete(id, version);
+	}
+
+	public void revokeDelete(Command command) {
+		handleRevoke(command, () -> unmarkAsDeleteByIdAndVersion(command.getRelationId(), command.getRelationVersion()));
+	}
+
+	void unmarkAsDeleteByIdAndVersion(String itemId, long version) {
+		repository.updateDeleted(false, itemId, version);
+	}
+
+	void handleRevoke(Command command, Runnable runnable) {
+		try {
+			runnable.run();
+			publisher.publishEvent(new CommandRevokedEvent(command));
+		} catch (RuntimeException e) {
+			LOG.error("Revoke item command failed(order: {})", command.getOrder(), e);
+			publisher.publishEvent(new CommandRevokeFailedEvent(command.getId(), e.getMessage()));
+		}
+	}
 }
\ No newline at end of file
diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/CommandRepository.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/CommandRepository.java
index 6222d4569a6002727397d8df8c4a7b185f711219..a9f57bac1d65ca9aba3af9671ab6d2efb2948558 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/CommandRepository.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/CommandRepository.java
@@ -35,15 +35,21 @@ import java.util.Optional;
 import java.util.stream.Stream;
 
 import org.apache.commons.collections.MapUtils;
+import org.apache.commons.lang3.ArrayUtils;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.mongodb.core.FindAndModifyOptions;
 import org.springframework.data.mongodb.core.MongoOperations;
+import org.springframework.data.mongodb.core.aggregation.Aggregation;
+import org.springframework.data.mongodb.core.aggregation.ComparisonOperators.Eq;
+import org.springframework.data.mongodb.core.aggregation.ConditionalOperators.Switch;
+import org.springframework.data.mongodb.core.aggregation.ConditionalOperators.Switch.CaseOperator;
+import org.springframework.data.mongodb.core.aggregation.SetOperation;
 import org.springframework.data.mongodb.core.query.Criteria;
 import org.springframework.data.mongodb.core.query.Query;
 import org.springframework.data.mongodb.core.query.Update;
+import org.springframework.data.mongodb.core.query.UpdateDefinition;
 import org.springframework.stereotype.Repository;
 
-import com.google.common.collect.ObjectArrays;
-
 import de.ozgcloud.command.Command;
 import de.ozgcloud.command.CommandStatus;
 
@@ -51,7 +57,8 @@ import de.ozgcloud.command.CommandStatus;
 class CommandRepository {
 
 	private static final String MONGODB_ID = "id";
-	private static final String MONGODB_STATUS = "status";
+	static final String MONGODB_STATUS = "status";
+	private static final String MONGODB_REFERENCE_STATUS = "$status";
 	private static final String MONGODB_FINISHED_AT = "finishedAt";
 	private static final String MONGODB_RELATION_VERSION = "relationVersion";
 	private static final String MONGODB_ERROR_MSG = "errorMessage";
@@ -62,8 +69,8 @@ class CommandRepository {
 	private static final String MONGODB_ASSIGNED_TO = "body.assignedTo";
 	private static final String MONGODB_CREATED_RESOURCE = "createdResource";
 	private static final String MONGODB_PARENT_ID = PersistedCommand.FIELD_BODY_OBJECT + "." + PersistedCommand.PROPERTY_PARENT_ID;
-	private static final String MONGODB_COMPLETE_IF_SUBS_COMPLETED =
-			PersistedCommand.FIELD_BODY_OBJECT + "." + PersistedCommand.PROPERTY_COMPLETE_IF_SUBS_COMPLETED;
+	private static final String MONGODB_COMPLETE_IF_SUBS_COMPLETED = PersistedCommand.FIELD_BODY_OBJECT + "."
+			+ PersistedCommand.PROPERTY_COMPLETE_IF_SUBS_COMPLETED;
 	private static final String MONGODB_CLASS = "_class";
 
 	@Autowired
@@ -101,6 +108,10 @@ class CommandRepository {
 				Command.class);
 	}
 
+	public Command updateCommandStatusAndReturnPrevious(String commandId, CommandStatus status) {
+		return mongoOperations.findAndModify(queryById(commandId), new Update().set(MONGODB_STATUS, status), Command.class);
+	}
+
 	void setErrorMessage(String commandId, String errorMsg) {
 		mongoOperations.updateFirst(queryById(commandId),
 				new Update()
@@ -119,7 +130,7 @@ class CommandRepository {
 				Command.class);
 	}
 
-	Optional<Command> getById(String commandId) {
+	Optional<Command> findById(String commandId) {
 		return Optional.ofNullable(mongoOperations.findById(commandId, Command.class));
 	}
 
@@ -195,12 +206,9 @@ class CommandRepository {
 		mongoOperations.updateFirst(queryById(commandId), update, Command.class);
 	}
 
-	public Optional<String> getNotFailedParentId(String commandId) {
-		return getParentId(commandId)
-				.map(this::queryNotFailedCommandById)
-				.map(this::includeIdAndClass)
-				.flatMap(this::findOne)
-				.map(Command::getId);
+	public boolean isCommandFailed(String commandId) {
+		return mongoOperations.exists(query(new Criteria().andOperator(criteriaById(commandId), where(MONGODB_STATUS).is(CommandStatus.ERROR))),
+				Command.class);
 	}
 
 	public Optional<String> getParentId(String commandId) {
@@ -209,10 +217,6 @@ class CommandRepository {
 		return findOne(query).map(Command::getBodyObject).map(this::getParentIdProperty);
 	}
 
-	private Query queryById(String commandId) {
-		return query(criteriaById(commandId));
-	}
-
 	private Criteria criteriaById(String commandId) {
 		return where(MONGODB_ID).is(commandId);
 	}
@@ -221,12 +225,6 @@ class CommandRepository {
 		return MapUtils.getString(body, PersistedCommand.PROPERTY_PARENT_ID);
 	}
 
-	Query queryNotFailedCommandById(String commandId) {
-		return query(new Criteria().andOperator(
-				where(MONGODB_ID).is(commandId),
-				where(MONGODB_STATUS).ne(CommandStatus.ERROR)));
-	}
-
 	Optional<Command> findOne(Query query) {
 		return Optional.ofNullable(mongoOperations.findOne(query, Command.class));
 	}
@@ -243,19 +241,55 @@ class CommandRepository {
 		return mongoOperations.exists(buildQueryNotInStatus(parentId, CommandStatus.FINISHED, CommandStatus.REVOKED), Command.class);
 	}
 
-	public Stream<String> findNotFailedSubCommandIds(String parentId) {
-		return mongoOperations.stream(includeIdAndClass(buildQueryNotInStatus(parentId, CommandStatus.ERROR)), Command.class).map(Command::getId);
-	}
-
-	private Query buildQueryNotInStatus(String parentId, CommandStatus status, CommandStatus... statuses) {
-		Object[] excludeStatuses = ObjectArrays.concat(status, statuses);
+	Query buildQueryNotInStatus(String parentId, CommandStatus status, CommandStatus... statuses) {
+		Object[] excludeStatuses = ArrayUtils.add(statuses, status);
 		return query(new Criteria().andOperator(
-				where(MONGODB_PARENT_ID).is(parentId),
+				buildIsParentIdCriteria(parentId),
 				where(MONGODB_STATUS).nin(excludeStatuses)));
 	}
 
+	public Stream<String> findSubCommandIds(String parentId) {
+		return mongoOperations.stream(includeIdAndClass(query(buildIsParentIdCriteria(parentId))), Command.class).map(Command::getId);
+	}
+
+	private Criteria buildIsParentIdCriteria(String parentId) {
+		return where(MONGODB_PARENT_ID).is(parentId);
+	}
+
 	Query includeIdAndClass(Query query) {
 		query.fields().include(MONGODB_CLASS, MONGODB_ID);
 		return query;
 	}
+
+	public Command setRevokeStatus(String id) {
+		return mongoOperations.findAndModify(queryById(id), buildUpdateStatusRevoke(), FindAndModifyOptions.options().returnNew(true), Command.class);
+	}
+
+	private UpdateDefinition buildUpdateStatusRevoke() {
+		var switchOperation = Switch.switchCases(
+				CaseOperator.when(Eq.valueOf(MONGODB_STATUS).equalToValue(CommandStatus.NEW)).then(CommandStatus.CANCELED),
+				CaseOperator.when(Eq.valueOf(MONGODB_STATUS).equalToValue(CommandStatus.PENDING)).then(CommandStatus.REVOKE_PENDING),
+				CaseOperator.when(Eq.valueOf(MONGODB_STATUS).equalToValue(CommandStatus.FINISHED)).then(CommandStatus.REVOKE_PENDING))
+				.defaultTo(MONGODB_REFERENCE_STATUS);
+		return Aggregation.newUpdate(SetOperation.set(MONGODB_STATUS).toValue(switchOperation));
+	}
+
+	public Optional<Command> setRevokeStatusIfNotPending(String id) {
+		var updateCommand = mongoOperations.findAndModify(queryById(id), buildUpdateStatusRevokeIfNotPending(),
+				FindAndModifyOptions.options().returnNew(true), Command.class);
+		return Optional.ofNullable(updateCommand);
+	}
+
+	private Query queryById(String commandId) {
+		return query(criteriaById(commandId));
+	}
+
+	private UpdateDefinition buildUpdateStatusRevokeIfNotPending() {
+		var switchOperation = Switch.switchCases(
+				CaseOperator.when(Eq.valueOf(MONGODB_STATUS).equalToValue(CommandStatus.NEW)).then(CommandStatus.CANCELED),
+				CaseOperator.when(Eq.valueOf(MONGODB_STATUS).equalToValue(CommandStatus.FINISHED)).then(CommandStatus.REVOKE_PENDING)
+		).defaultTo(MONGODB_REFERENCE_STATUS);
+		return Aggregation.newUpdate(SetOperation.set(MONGODB_STATUS).toValue(switchOperation));
+	}
+
 }
diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/CommandService.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/CommandService.java
index 9b2e19c7f3172cea9a1dcc813bcc4e37774f7793..2f661a37b47f0da8143fdd5332e8385da4ecb1e5 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/CommandService.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/CommandService.java
@@ -33,11 +33,9 @@ import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.UUID;
-import java.util.function.Consumer;
 import java.util.stream.Stream;
 
 import org.apache.commons.collections4.MapUtils;
-import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.ApplicationEventPublisher;
 import org.springframework.stereotype.Service;
@@ -55,12 +53,11 @@ import de.ozgcloud.vorgang.callcontext.CallContextUser;
 import de.ozgcloud.vorgang.callcontext.CurrentUserService;
 import de.ozgcloud.vorgang.callcontext.User;
 import de.ozgcloud.vorgang.common.errorhandling.NotFoundException;
+import de.ozgcloud.vorgang.common.errorhandling.RevokeFailedException;
 import lombok.NonNull;
-import lombok.extern.log4j.Log4j2;
 
 @Service
 @Validated
-@Log4j2
 public class CommandService {
 
 	@Autowired
@@ -109,10 +106,6 @@ public class CommandService {
 		return command;
 	}
 
-	public Optional<Command> findCommand(String commandId) {
-		return repository.getById(commandId);
-	}
-
 	public Stream<Command> findFinishedVorgangLoeschenCommandsOlderThen(@NonNull ZonedDateTime createdAfter) {
 		return repository.findCommands(Order.VORGANG_LOESCHEN, CommandStatus.FINISHED, createdAfter);
 	}
@@ -122,62 +115,90 @@ public class CommandService {
 	}
 
 	public void setCommandFinished(String commandId, String createdResource) {
-		Optional.ofNullable(createdResource).ifPresentOrElse(
-				resource -> repository.finishCommand(commandId, resource),
+		var command = getById(commandId);
+		if (shouldRevoke(command)) {
+			repository.setRevokeStatus(commandId);
+			publishRevokeCommandEvent(command);
+			return;
+		}
+		Optional.ofNullable(createdResource).ifPresentOrElse(resource -> repository.finishCommand(commandId, resource),
 				() -> repository.finishCommand(commandId));
-		getCompletableParentId(commandId).filter(parentId -> !repository.existsNotFinishedSubCommands(parentId))
-				.ifPresent(this::publishCommandExecutedEvent);
+		getCompletableParentId(command).ifPresent(this::publishCommandExecutedEvent);
+	}
+
+	boolean shouldRevoke(Command command) {
+		return command.getStatus() == CommandStatus.REVOKE_PENDING || isParentCommandFailed(command);
+	}
+
+	boolean isParentCommandFailed(Command command) {
+		return getParentId(command).filter(repository::isCommandFailed).isPresent();
+	}
+
+	Optional<String> getCompletableParentId(Command command) {
+		return getParentId(command).filter(repository::isCompleteIfSubsCompleted)
+				.filter(parentId -> !repository.existsNotFinishedSubCommands(parentId));
 	}
 
-	Optional<String> getCompletableParentId(String commandId) {
-		return repository.getParentId(commandId).filter(repository::isCompleteIfSubsCompleted);
+	Optional<String> getParentId(Command command) {
+		return Optional.ofNullable(command.getBodyObject()).map(body -> MapUtils.getString(body, PROPERTY_PARENT_ID));
 	}
 
 	public void publishCommandExecutedEvent(String commandId) {
-		findCommand(commandId).ifPresent(command -> publisher.publishEvent(new CommandExecutedEvent(command)));
+		findById(commandId).ifPresent(command -> publisher.publishEvent(new CommandExecutedEvent(command)));
 	}
 
-	public void setCommandError(String id, String errorMessage) {
-		repository.setErrorMessage(id, errorMessage);
-		var publishCommandFailedEvent = createCommandFailedEventPublisher("Command %s failed: %s".formatted(id, errorMessage));
-		repository.findNotFailedSubCommandIds(id).filter(notFailedCommandId -> !StringUtils.equals(notFailedCommandId, id))
-				.forEach(publishCommandFailedEvent);
-		repository.getNotFailedParentId(id).ifPresent(publishCommandFailedEvent);
+	public void setCommandError(String commandId, String errorMessage) {
+		repository.setErrorMessage(commandId, errorMessage);
+		repository.getParentId(commandId).map(this::setErrorStatus).filter(this::notErrorStatus)
+				.map(Command::getId).ifPresent(parentId -> handleCommandError(commandId, parentId));
 	}
 
-	Consumer<String> createCommandFailedEventPublisher(String errorMessage) {
-		return commandId -> publisher.publishEvent(new CommandFailedEvent(commandId, errorMessage));
+	Command setErrorStatus(String commandId) {
+		return Optional.ofNullable(repository.updateCommandStatusAndReturnPrevious(commandId, CommandStatus.ERROR))
+				.orElseThrow(() -> new NotFoundException(Command.class, commandId));
 	}
 
-	public void setCommandRevoked(String commandId) {
-		updateCommandStatus(commandId, CommandStatus.REVOKED);
+	boolean notErrorStatus(Command command) {
+		return command.getStatus() != CommandStatus.ERROR;
 	}
 
-	public void setCommandRevokePending(final String commandId) {
-		updateCommandStatus(commandId, CommandStatus.REVOKE_PENDING);
+	void handleCommandError(String commandId, String parentId) {
+		publishCommandFailedEvent(parentId, "Command %s failed because subcommand %s failed".formatted(parentId, commandId));
+		revokeSubCommands(parentId);
+	}
 
-		publishRevokeCommandEvent(commandId);
+	void publishCommandFailedEvent(String commandId, String errorMessage) {
+		publisher.publishEvent(new CommandFailedEvent(commandId, errorMessage));
 	}
 
-	void publishRevokeCommandEvent(final String commandId) {
-		var commandOptional = repository.getById(commandId);
-		commandOptional.ifPresentOrElse(command -> {
-			if (MapUtils.isEmpty(((PersistedCommand) command).getPreviousState())) {
-				handleError(commandId, "Command %s can not be revoked because it has no previous state.");
-			}
-			publisher.publishEvent(new RevokeCommandEvent(command));
-		}, () -> handleError(commandId, "No Command with id %s found."));
+	void revokeSubCommands(String parentId) {
+		repository.findSubCommandIds(parentId).forEach(this::revokeCommandSilent);
 	}
 
-	private void handleError(String commandId, String messageTemplate) {
-		var message = messageTemplate.formatted(commandId);
-		LOG.error(message);
-		publisher.publishEvent(new CommandFailedEvent(commandId, message));
-		throw new TechnicalException(message);
+	public void setCommandRevoked(String commandId) {
+		repository.updateCommandStatus(commandId, CommandStatus.REVOKED);
 	}
 
-	void updateCommandStatus(String commandId, CommandStatus status) {
-		repository.updateCommandStatus(commandId, status);
+	public Command revokeCommand(String commandId) {
+		var updatedCommand = revokeCommandSilent(commandId).orElseThrow(() -> new NotFoundException(Command.class, commandId));
+		if (!isRevokePending(updatedCommand)) {
+			throw new RevokeFailedException(commandId, "Unexpected status '%s'. (expected: REVOKE_PENDING)".formatted(updatedCommand.getStatus()));
+		}
+		return updatedCommand;
+	}
+
+	Optional<Command> revokeCommandSilent(String commandId) {
+		var updatedCommand = repository.setRevokeStatusIfNotPending(commandId);
+		updatedCommand.filter(this::isRevokePending).ifPresent(this::publishRevokeCommandEvent);
+		return updatedCommand;
+	}
+
+	boolean isRevokePending(Command command) {
+		return command.getStatus() == CommandStatus.REVOKE_PENDING;
+	}
+
+	void publishRevokeCommandEvent(Command command) {
+		publisher.publishEvent(new RevokeCommandEvent(command));
 	}
 
 	public boolean existsPendingCommands(String vorgangId) {
@@ -205,20 +226,28 @@ public class CommandService {
 	}
 
 	public Stream<Command> createSubCommands(CreateSubCommandsRequest request) {
-		var parentCommand = getNotFailedCommand(request.getParentId());
+		var parentCommand = getPendingCommand(request.getParentId());
 		repository.addSubCommands(parentCommand.getId(), buildSubCommandValues(request));
 		return request.getSubCommands().stream().map(subCommand -> buildCreateCommandRequest(subCommand, parentCommand))
 				.map(this::createCommand);
 	}
 
-	Command getNotFailedCommand(String commandId) {
-		var command = findCommand(commandId).orElseThrow(() -> new NotFoundException(Command.class, commandId));
-		if (command.getStatus() == CommandStatus.ERROR) {
-			throw new TechnicalException("Cannot add sub commands to failed command ('%s')".formatted(commandId));
+	Command getPendingCommand(String commandId) {
+		var command = getById(commandId);
+		if (command.getStatus() != CommandStatus.PENDING) {
+			throw new TechnicalException("Cannot add sub commands to command '%s'. Parent command must have status PENDING".formatted(commandId));
 		}
 		return command;
 	}
 
+	public Command getById(String commandId) {
+		return findById(commandId).orElseThrow(() -> new NotFoundException(Command.class, commandId));
+	}
+
+	public Optional<Command> findById(String commandId) {
+		return repository.findById(commandId);
+	}
+
 	Map<String, Object> buildSubCommandValues(CreateSubCommandsRequest request) {
 		var executionMode = request.getExecutionMode();
 		return Map.of(
diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/GrpcCommandService.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/GrpcCommandService.java
index 4237a4c2f986161b0b76880b2aa50409e751fd68..5e83fe5ab0aa3c5f0c85b8fe4dc04bc51ec20a34 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/GrpcCommandService.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/GrpcCommandService.java
@@ -36,7 +36,6 @@ import org.springframework.context.ApplicationEventPublisher;
 import de.ozgcloud.command.Command;
 import de.ozgcloud.command.CommandExecutedEvent;
 import de.ozgcloud.command.CommandStatus;
-import de.ozgcloud.common.errorhandling.TechnicalException;
 import de.ozgcloud.vorgang.command.CommandResponse.ResponseCode;
 import de.ozgcloud.vorgang.common.errorhandling.NotFoundException;
 import de.ozgcloud.vorgang.common.security.PolicyService;
@@ -92,11 +91,6 @@ public class GrpcCommandService extends CommandServiceImplBase {
 		responseObserver.onCompleted();
 	}
 
-	// TODO check - is this function still in use?
-	boolean isStatusChangeOrder(String order) {
-		return order.startsWith("VORGANG");
-	}
-
 	@Override
 	public void getCommand(GrpcGetCommandRequest request, StreamObserver<GrpcCommand> responseObserver) {
 		policyService.checkPermissionByCommand(request.getId());
@@ -110,23 +104,13 @@ public class GrpcCommandService extends CommandServiceImplBase {
 	@Override
 	public void revokeCommand(GrpcRevokeCommandRequest request, StreamObserver<GrpcCommandResponse> responseObserver) {
 		policyService.checkPermissionByCommand(request.getId());
-
-		String commandId = request.getId();
-
-		try {
-			commandService.setCommandRevokePending(commandId);
-
-			Command updatedCommand = getCommand(commandId);
-
-			responseObserver.onNext(mapToGrpcResponse(updatedCommand));
-			responseObserver.onCompleted();
-		} catch (TechnicalException e) {
-			responseObserver.onError(e);
-		}
+		var updatedCommand = commandService.revokeCommand(request.getId());
+		responseObserver.onNext(mapToGrpcResponse(updatedCommand));
+		responseObserver.onCompleted();
 	}
 
 	Command getCommand(String commandId) {
-		return commandService.findCommand(commandId).orElseThrow(() -> new NotFoundException(Command.class, commandId));
+		return commandService.findById(commandId).orElseThrow(() -> new NotFoundException(Command.class, commandId));
 	}
 
 	private GrpcCommandResponse mapToGrpcResponse(Command response) {
@@ -180,7 +164,7 @@ public class GrpcCommandService extends CommandServiceImplBase {
 
 	@Override
 	public void setCommandExecuted(GrpcSetCommandExecutedRequest request, StreamObserver<GrpcEmpty> responseObserver) {
-		commandService.findCommand(request.getCommandId())
+		commandService.findById(request.getCommandId())
 				.map(command -> new CommandExecutedEvent(command, trimToNull(request.getCreatedResource())))
 				.ifPresentOrElse(publisher::publishEvent,
 						() -> LOG.warn("Command with ID '%s' not found. Cannot mark as executed.".formatted(request.getCommandId())));
diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/PersistPostfachNachrichtByCommandService.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/PersistPostfachNachrichtByCommandService.java
index b6360403db1c64d915838671a4a7ab390d540a21..4c7bb459c80b6c4e5a3aa39a88afcad0d0ebf9aa 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/PersistPostfachNachrichtByCommandService.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/PersistPostfachNachrichtByCommandService.java
@@ -22,13 +22,8 @@ package de.ozgcloud.vorgang.command;
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.net.URLConnection;
-import java.time.ZonedDateTime;
-import java.time.format.DateTimeFormatter;
 import java.util.Base64;
-import java.util.Collections;
-import java.util.HashMap;
 import java.util.Map;
-import java.util.Objects;
 import java.util.Optional;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
@@ -37,21 +32,15 @@ import java.util.stream.Stream;
 
 import jakarta.activation.MimetypesFileTypeMap;
 
-import org.apache.commons.lang3.StringUtils;
 import org.apache.http.entity.ContentType;
 import org.springframework.stereotype.Service;
 
 import de.ozgcloud.common.errorhandling.TechnicalException;
 import de.ozgcloud.nachrichten.postfach.AttachmentFile;
 import de.ozgcloud.nachrichten.postfach.PersistPostfachNachrichtService;
-import de.ozgcloud.nachrichten.postfach.PostfachAddress;
 import de.ozgcloud.nachrichten.postfach.PostfachNachricht;
-import de.ozgcloud.nachrichten.postfach.StringBasedIdentifier;
 import de.ozgcloud.vorgang.attached_item.VorgangAttachedItem;
-import de.ozgcloud.vorgang.attached_item.VorgangAttachedItemMapper;
 import de.ozgcloud.vorgang.attached_item.VorgangAttachedItemService;
-import de.ozgcloud.vorgang.callcontext.CallContext;
-import de.ozgcloud.vorgang.callcontext.User;
 import de.ozgcloud.vorgang.files.FileService;
 import de.ozgcloud.vorgang.files.OzgFile;
 import de.ozgcloud.vorgang.files.UploadedFilesReference;
@@ -71,108 +60,12 @@ class PersistPostfachNachrichtByCommandService implements PersistPostfachNachric
 	static final String ITEM_NAME = "PostfachMail";
 	static final String ATTACHMENT_NAME = "PostfachAttachment";
 
-	private final CommandService service;
 	private final VorgangAttachedItemService attachedItemService;
 	private final FileService fileService;
 
 	@Override
 	public void persistNachricht(Optional<String> userId, PostfachNachricht nachricht) {
-		var builder = CreateCommandRequest.builder()
-				.callContext(buildCallContext(userId))
-				.vorgangId(nachricht.getVorgangId());
-
-		var request = StringUtils.isBlank(nachricht.getId()) ? buildPersistCommand(builder, nachricht) : buildUpdateCommand(builder, nachricht);
-
-		service.createCommand(request);
-	}
-
-	CreateCommandRequest buildPersistCommand(CreateCommandRequest.CreateCommandRequestBuilder builder, PostfachNachricht nachricht) {
-		return builder.order(Order.CREATE_ATTACHED_ITEM.name())
-				.relationId(nachricht.getVorgangId())
-				.bodyObject(buildItem(nachricht)).build();
-	}
-
-	CreateCommandRequest buildUpdateCommand(CreateCommandRequest.CreateCommandRequestBuilder builder, PostfachNachricht nachricht) {
-		return builder.order(Order.UPDATE_ATTACHED_ITEM.name())
-				.relationId(nachricht.getId())
-				.bodyObject(buildUpdateItem(nachricht)).build();
-	}
-
-	private CallContext buildCallContext(Optional<String> userId) {
-		var builder = CallContext.builder();
-		userId.map(id -> User.builder().id(id).build()).ifPresent(builder::user);
-
-		return builder.build();
-	}
-
-	private Map<String, Object> buildItem(PostfachNachricht nachricht) {
-		return Map.of(
-				VorgangAttachedItemMapper.PROPERTY_CLIENT, CLIENT,
-				VorgangAttachedItemMapper.PROPERTY_VORGANG_ID, nachricht.getVorgangId(),
-				VorgangAttachedItemMapper.PROPERTY_ITEM_NAME, ITEM_NAME,
-				VorgangAttachedItemMapper.PROPERTY_ITEM, buildNachrichtMap(nachricht));
-
-	}
-
-	private Map<String, Object> buildUpdateItem(PostfachNachricht nachricht) {
-		return Map.of(
-				VorgangAttachedItemMapper.PROPERTY_CLIENT, CLIENT,
-				VorgangAttachedItemMapper.PROPERTY_ITEM, buildNachrichtMap(nachricht));
-
-	}
-
-	Map<String, Object> buildNachrichtMap(PostfachNachricht nachricht) {
-		var result = new HashMap<>(Map.of(
-				PostfachNachricht.FIELD_VORGANG_ID, nachricht.getVorgangId(),
-				PostfachNachricht.FIELD_CREATED_AT, nachricht.getCreatedAt().format(DateTimeFormatter.ISO_DATE_TIME),
-				PostfachNachricht.FIELD_DIRECTION, nachricht.getDirection().name(),
-				PostfachNachricht.FIELD_REPLY_OPTION, nachricht.getReplyOption().name(),
-				PostfachNachricht.FIELD_SUBJECT, nachricht.getSubject(),
-				PostfachNachricht.FIELD_MAIL_BODY, nachricht.getMailBody(),
-				PostfachNachricht.FIELD_ATTACHMENTS, nachricht.getAttachments()));
-
-		putIfNonNull(result, PostfachNachricht.FIELD_POSTFACH_ID, nachricht.getPostfachId());
-		putIfNonNull(result, PostfachNachricht.FIELD_MESSAGE_ID, nachricht.getMessageId());
-		putIfNonNull(result, PostfachNachricht.FIELD_CREATED_BY, nachricht.getCreatedBy());
-		putIfNonNull(result, PostfachNachricht.FIELD_SENT_SUCCESSFUL, nachricht.getSentSuccessful());
-		putIfNonNull(result, PostfachNachricht.FIELD_MESSAGE_CODE, nachricht.getMessageCode());
-		putIfNonNull(result, PostfachNachricht.REFERENCED_NACHRICHT_FIELD, nachricht.getReferencedNachricht());
-		putDateIfNonNull(result, PostfachNachricht.FIELD_SENT_AT, nachricht.getSentAt());
-
-		Optional.ofNullable(nachricht.getPostfachAddress()).map(this::buildPostfachAddressMap)
-				.ifPresent(postfachMaiMap -> result.put(PostfachNachricht.POSTFACH_ADDRESS_FIELD, postfachMaiMap));
-
-		return Collections.unmodifiableMap(result);
-	}
-
-	private Map<String, Object> putIfNonNull(Map<String, Object> mapIn, String key, Object value) {
-		if (Objects.nonNull(value)) {
-			mapIn.put(key, value);
-		}
-		return mapIn;
-	}
-
-	private Map<String, Object> putDateIfNonNull(Map<String, Object> mapIn, String key, Object value) {
-		if (Objects.nonNull(value)) {
-			mapIn.put(key, ((ZonedDateTime) value).format(DateTimeFormatter.ISO_DATE_TIME));
-		}
-		return mapIn;
-	}
-
-	private Map<String, Object> buildPostfachAddressMap(PostfachAddress postfachAddress) {
-		var resultMap = new HashMap<String, Object>();
-		resultMap.put(PostfachAddress.IDENTIFIER_FIELD, buildPostfachAddressIdentifierMap(postfachAddress));
-		resultMap.put(PostfachAddress.VERSION_FIELD, postfachAddress.getVersion());
-		resultMap.put(PostfachAddress.TYPE_FIELD, postfachAddress.getType());
-		Optional.ofNullable(postfachAddress.getServiceKontoType()).ifPresentOrElse(
-				serviceKontoType -> resultMap.put(PostfachAddress.SERVICEKONTO_TYPE_FIELD, serviceKontoType),
-				() -> LOG.warn("ServiceKontoType is null"));
-		return Collections.unmodifiableMap(resultMap);
-	}
-
-	private Map<String, Object> buildPostfachAddressIdentifierMap(PostfachAddress postfachAddress) {
-		var identifier = (StringBasedIdentifier) postfachAddress.getIdentifier();
-		return Map.of(PostfachNachricht.FIELD_POSTFACH_ID, identifier.getPostfachId());
+		throw new UnsupportedOperationException("Not implemented.");
 	}
 
 	@Override
diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/common/errorhandling/ExceptionHandler.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/common/errorhandling/ExceptionHandler.java
index d5a1c169125ab7a84e1d734ad6e85f6adf5adccf..11318a0cf33d16cc95296cef55b61c1f08a878b8 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/common/errorhandling/ExceptionHandler.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/common/errorhandling/ExceptionHandler.java
@@ -41,11 +41,14 @@ import net.devh.boot.grpc.server.advice.GrpcExceptionHandler;
 @GrpcAdvice
 public class ExceptionHandler {
 
+	private static final String ERROR_MESSAGE = "Grpc internal server error";
+
 	static final String KEY_ERROR_CODE = "ERROR_CODE";
 	static final String KEY_EXCEPTION_ID = "EXCEPTION_ID";
 
 	@GrpcExceptionHandler
 	public StatusException handleNotFoundException(NotFoundException e) {
+		LOG.error(ERROR_MESSAGE, e);
 		return createStatusException(buildNotFoundStatus(e), buildMetadata(e));
 	}
 
@@ -55,6 +58,7 @@ public class ExceptionHandler {
 
 	@GrpcExceptionHandler
 	public StatusException handleFunctionalException(FunctionalException e) {
+		LOG.error(ERROR_MESSAGE, e);
 		return createStatusException(buildInternalStatus(e), buildMetadata(e));
 	}
 
@@ -77,6 +81,7 @@ public class ExceptionHandler {
 
 	@GrpcExceptionHandler
 	public StatusException handleTechnicalException(TechnicalException e) {
+		LOG.error(ERROR_MESSAGE, e);
 		return createStatusException(buildInternalStatus(e), buildMetadata(e.getExceptionId()));
 	}
 
@@ -88,7 +93,7 @@ public class ExceptionHandler {
 	public StatusException handleRuntimeException(RuntimeException e) {
 		var exceptionId = createExceptionId();
 		var messageWithExceptionId = ExceptionUtil.formatMessageWithExceptionId(e.getMessage(), exceptionId);
-		LOG.error("Grpc internal server error: " + messageWithExceptionId, e);
+		LOG.error("Grpc internal server error: {}", messageWithExceptionId, e);
 
 		return createStatusException(buildInternalStatus(e, messageWithExceptionId), buildMetadata(exceptionId));
 	}
@@ -123,7 +128,7 @@ public class ExceptionHandler {
 	public StatusException handleAccessDeniedException(AccessDeniedException e) {
 		var exceptionId = createExceptionId();
 		var messageWithExceptionId = ExceptionUtil.formatMessageWithExceptionId(e.getMessage(), exceptionId);
-		LOG.error("Grpc permission denied error: " + messageWithExceptionId, e);
+		LOG.error("Grpc permission denied error: {}", messageWithExceptionId, e);
 
 		return createStatusException(buildPermissionDeniedStatus(e, messageWithExceptionId), buildMetadata(exceptionId));
 	}
@@ -134,6 +139,7 @@ public class ExceptionHandler {
 
 	@GrpcExceptionHandler
 	public StatusException handleSearchServiceUnavailableException(SearchServiceUnavailableException e) {
+		LOG.error(ERROR_MESSAGE, e);
 		return createStatusException(buildUnavailableStatus(e), buildMetadata(e.getExceptionId()));
 	}
 
diff --git a/bescheid-manager/src/main/java/de/ozgcloud/bescheid/BescheidFeatureProperties.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/common/errorhandling/RevokeFailedException.java
similarity index 62%
rename from bescheid-manager/src/main/java/de/ozgcloud/bescheid/BescheidFeatureProperties.java
rename to vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/common/errorhandling/RevokeFailedException.java
index 1b0011890ab72654176613f9dfd31ec1eb41fdc8..133b8970b815aaf02ad3284a24babd821ea13b0a 100644
--- a/bescheid-manager/src/main/java/de/ozgcloud/bescheid/BescheidFeatureProperties.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/common/errorhandling/RevokeFailedException.java
@@ -21,21 +21,20 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-package de.ozgcloud.bescheid;
+package de.ozgcloud.vorgang.common.errorhandling;
 
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.context.annotation.Configuration;
+import java.util.Map;
 
-import lombok.Getter;
-import lombok.Setter;
+import de.ozgcloud.common.errorhandling.FunctionalErrorCode;
 
-@Configuration
-@ConfigurationProperties(prefix = "ozgcloud.feature.bescheid")
-@Getter
-@Setter
-public class BescheidFeatureProperties {
+public class RevokeFailedException extends FunctionalException {
 
-	private boolean storeAsDocument = false;
+	static final String KEY_COMMAND_ID = "Id";
 
-	private boolean kielHackathonRoute = false;
+	private static final String MESSAGE_TEMPLATE = "Can not revoke command with id '%s'. %s";
+	private static final FunctionalErrorCode ERROR_CODE = () -> "error.revoke_failed";
+
+	public RevokeFailedException(String commandId, String message) {
+		super(MESSAGE_TEMPLATE.formatted(commandId, message), ERROR_CODE, Map.of(KEY_COMMAND_ID, commandId));
+	}
 }
diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/common/migration/M010_CreateIndexesInVorgang.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/common/migration/M010_CreateIndexesInVorgang.java
new file mode 100644
index 0000000000000000000000000000000000000000..172953ca2820282a18a978e7ac012e7379cd55eb
--- /dev/null
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/common/migration/M010_CreateIndexesInVorgang.java
@@ -0,0 +1,68 @@
+/*
+ * 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.vorgang.common.migration;
+
+import org.bson.Document;
+import org.springframework.data.mongodb.core.MongoTemplate;
+import org.springframework.data.mongodb.core.index.CompoundIndexDefinition;
+import org.springframework.data.mongodb.core.index.IndexDefinition;
+
+import io.mongock.api.annotations.ChangeUnit;
+import io.mongock.api.annotations.Execution;
+import io.mongock.api.annotations.RollbackExecution;
+
+@ChangeUnit(id = "2024-06-12 17:00:00 OZG-5661", order = "M010", author = "ebardin")
+public class M010_CreateIndexesInVorgang { // NOSONAR
+
+	static final String COLLECTION_NAME = "vorgang";
+	static final String COMPOUND_INDEX_NAME = "inCreation_OrgaId_assignedTo_status_createdAt";
+
+	static final String FIELD_IN_CREATION = "inCreation";
+	static final String FIELD_STATUS = "status";
+	static final String FIELD_CREATED_AT = "createdAt";
+	static final String FIELD_ASSIGNED_TO = "assignedTo";
+	static final String FIELD_EINGANGS = "eingangs";
+	static final String FIELD_ORGANISATIONSEINHEITEN_ID = FIELD_EINGANGS + ".zustaendigeStelle.organisationseinheitenId";
+
+	@Execution
+	public void doMigration(MongoTemplate template) {
+		template.indexOps(COLLECTION_NAME).ensureIndex(buildCompoundIndexDefinition());
+	}
+
+	IndexDefinition buildCompoundIndexDefinition() {
+		var indexKeys = new Document();
+		indexKeys.put(FIELD_IN_CREATION, 1);
+		indexKeys.put(FIELD_ORGANISATIONSEINHEITEN_ID, 1);
+		indexKeys.put(FIELD_ASSIGNED_TO, 1);
+		indexKeys.put(FIELD_STATUS, 1);
+		indexKeys.put(FIELD_CREATED_AT, 1);
+		return new CompoundIndexDefinition(indexKeys).named(COMPOUND_INDEX_NAME);
+	}
+
+	@RollbackExecution
+	public void rollback() {
+		// kein rollback implementiert
+	}
+
+}
diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/common/migration/M011_SetDefaultCollaborationLevel.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/common/migration/M011_SetDefaultCollaborationLevel.java
new file mode 100644
index 0000000000000000000000000000000000000000..b87ca0ed026919f0c81ea26687e1eae8f82efdd5
--- /dev/null
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/common/migration/M011_SetDefaultCollaborationLevel.java
@@ -0,0 +1,39 @@
+package de.ozgcloud.vorgang.common.migration;
+
+import org.springframework.data.mongodb.core.MongoTemplate;
+import org.springframework.data.mongodb.core.query.Criteria;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.data.mongodb.core.query.Update;
+
+import io.mongock.api.annotations.ChangeUnit;
+import io.mongock.api.annotations.Execution;
+import io.mongock.api.annotations.RollbackExecution;
+
+@ChangeUnit(id = "2024-07-29 17:30:00 OZG-6259", order = "M011", author = "mkuester", runAlways = true)
+public class M011_SetDefaultCollaborationLevel { // NOSONAR
+
+	private static final String VORGANG_COLLECTION = "vorgang";
+
+	static final String HEADER_FIELD = "header";
+	static final String COLLABORATION_LEVEL_FIELD = "collaborationLevel";
+	static final String HEADER_COLLABORATION_LEVEL_FIELD = HEADER_FIELD + "." + COLLABORATION_LEVEL_FIELD;
+	private static final int DEFAULT_COLLABORATION_LEVEL = 0;
+
+	@Execution
+	public void doMigration(MongoTemplate template) {
+		template.updateMulti(createFilterQuery(), createUpdate(), VORGANG_COLLECTION);
+	}
+
+	private Query createFilterQuery() {
+		return new Query(Criteria.where(HEADER_COLLABORATION_LEVEL_FIELD).exists(false));
+	}
+
+	private Update createUpdate() {
+		return new Update().set(HEADER_COLLABORATION_LEVEL_FIELD, DEFAULT_COLLABORATION_LEVEL);
+	}
+
+	@RollbackExecution
+	public void rollback() {
+		// kein rollback implementiert
+	}
+}
\ No newline at end of file
diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/common/search/MongodbFullTextSearchIndexInitializer.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/common/search/MongodbFullTextSearchIndexInitializer.java
new file mode 100644
index 0000000000000000000000000000000000000000..105b8bdffbb95a96514c9fe65c0100da5820a12a
--- /dev/null
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/common/search/MongodbFullTextSearchIndexInitializer.java
@@ -0,0 +1,59 @@
+/*
+ * 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.vorgang.common.search;
+
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.event.ContextRefreshedEvent;
+import org.springframework.context.event.EventListener;
+import org.springframework.data.mongodb.core.MongoOperations;
+import org.springframework.data.mongodb.core.index.TextIndexDefinition;
+import org.springframework.stereotype.Component;
+
+import de.ozgcloud.vorgang.vorgang.Vorgang;
+import lombok.RequiredArgsConstructor;
+
+@ConditionalOnProperty(prefix = "ozgcloud.mongodbsearch", name = "enabled", havingValue = "true")
+@Component
+@RequiredArgsConstructor
+public class MongodbFullTextSearchIndexInitializer {
+
+	static final String TEXT_INDEX_NAME = "textIndex";
+	static final String TEXT_INDEX_LANGUAGE = "german";
+
+	private final MongoOperations mongoOperations;
+
+	@EventListener(ContextRefreshedEvent.class)
+	public void initWildcardTextIndex() {
+		mongoOperations.indexOps(Vorgang.COLLECTION_NAME).ensureIndex(buildWildcardTextIndexDefinition());
+	}
+
+	TextIndexDefinition buildWildcardTextIndexDefinition() {
+		return new TextIndexDefinition.TextIndexDefinitionBuilder()
+				.named(TEXT_INDEX_NAME)
+				.onAllFields()
+				.withDefaultLanguage(TEXT_INDEX_LANGUAGE)
+				.build();
+	}
+
+}
diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/common/search/SearchEventListener.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/common/search/SearchEventListener.java
index 6575b816370c075ac0ce7ef8c5251fa095dd4920..c844c3f36cc550abab150590103780d6b28bdc84 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/common/search/SearchEventListener.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/common/search/SearchEventListener.java
@@ -74,7 +74,7 @@ public class SearchEventListener {
 	}
 
 	private void updateVorgangById(String commandId) {
-		commandService.findCommand(commandId).ifPresentOrElse(this::updateVorgang, () -> {
+		commandService.findById(commandId).ifPresentOrElse(this::updateVorgang, () -> {
 			throw new IllegalStateException(MessageFormat.format("Kein Command mit der ID {0} gefunden", commandId));
 		});
 	}
diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/common/search/SearchService.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/common/search/SearchService.java
index 19533cbeee1904c697846e124744baf09a841c31..1d7a92f2e8d7be97c40a63f717454a23c3702942 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/common/search/SearchService.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/common/search/SearchService.java
@@ -23,10 +23,12 @@
  */
 package de.ozgcloud.vorgang.common.search;
 
+import static java.util.Objects.*;
+
 import java.util.Collections;
 
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
 import org.springframework.dao.DataAccessResourceFailureException;
 import org.springframework.data.domain.Page;
 import org.springframework.stereotype.Service;
@@ -37,10 +39,10 @@ import de.ozgcloud.vorgang.vorgang.Vorgang;
 import de.ozgcloud.vorgang.vorgang.VorgangHeader;
 
 @Service
-@ConditionalOnProperty(prefix = "ozgcloud.elasticsearch", name = "address")
+@ConditionalOnExpression("!'${ozgcloud.elasticsearch.address:}'.isEmpty() || ${ozgcloud.mongodbsearch.enabled:false}")
 public class SearchService {
 
-	@Autowired
+	@Autowired(required = false)
 	private SearchVorgangRepository repository;
 
 	@Autowired
@@ -49,16 +51,15 @@ public class SearchService {
 	@Autowired
 	private IndexedVorgangMapper mapper;
 
+	// TODO die Methode scheint überfüssig zu sein. Man könnte stattsie und ' updateVorgang' eine Methode z.B. 'addOrUpdateVorgang' nutzen.
 	public void addVorgang(Vorgang vorgang) {
-		repository.save(mapper.fromVorgang(vorgang));
+		updateVorgang(vorgang);
 	}
 
 	public void updateVorgang(Vorgang vorgang) {
-		repository.save(mapper.fromVorgang(vorgang));
-	}
-
-	public boolean existsById(String vorgangId) {
-		return repository.existsById(vorgangId);
+		if (nonNull(repository)) {
+			repository.save(mapper.fromVorgang(vorgang));
+		}
 	}
 
 	public Page<VorgangHeader> find(FindVorgangRequest findVorgangRequest) {
@@ -70,7 +71,9 @@ public class SearchService {
 	}
 
 	public void deleteVorgang(String vorgangId) {
-		repository.deleteById(vorgangId);
+		if (nonNull(repository)) {
+			repository.deleteById(vorgangId);
+		}
 	}
 
 	public void setAktenzeichen(String vorgangId, String aktenzeichen) {
diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/common/search/SearchVorgangCustomRepository.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/common/search/SearchVorgangCustomRepository.java
index 7c1a2a19abae7c802e7054c3713d1dfdd6255879..3a58f8f74cfc1c23b8fdc5f217ddc64e488d4244 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/common/search/SearchVorgangCustomRepository.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/common/search/SearchVorgangCustomRepository.java
@@ -25,13 +25,11 @@ package de.ozgcloud.vorgang.common.search;
 
 import java.util.Map;
 
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
 import org.springframework.data.domain.Page;
 
 import de.ozgcloud.vorgang.vorgang.FindVorgangRequest;
 import de.ozgcloud.vorgang.vorgang.VorgangHeader;
 
-@ConditionalOnProperty(prefix = "ozgcloud.elasticsearch", name = "address")
 interface SearchVorgangCustomRepository {
 	Page<VorgangHeader> searchBy(FindVorgangRequest request);
 
diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/common/search/SearchVorgangCustomRepositoryImpl.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/common/search/SearchVorgangCustomRepositoryImpl.java
index cfd983a2828f8edc7d56c2f0457292615becbaca..47fe7b83020c3fbd880df9c0abd3aceaeef23ccd 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/common/search/SearchVorgangCustomRepositoryImpl.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/common/search/SearchVorgangCustomRepositoryImpl.java
@@ -39,6 +39,7 @@ import java.util.stream.Stream;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.PageRequest;
 import org.springframework.data.elasticsearch.client.elc.NativeQueryBuilder;
@@ -61,6 +62,7 @@ import de.ozgcloud.vorgang.vorgang.FindVorgangRequest;
 import de.ozgcloud.vorgang.vorgang.Vorgang;
 import de.ozgcloud.vorgang.vorgang.VorgangHeader;
 
+@ConditionalOnProperty(prefix = "ozgcloud.elasticsearch", name = "address")
 @Repository
 class SearchVorgangCustomRepositoryImpl implements SearchVorgangCustomRepository {
 
diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/common/search/SearchVorgangCustomRepositoryMongo.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/common/search/SearchVorgangCustomRepositoryMongo.java
new file mode 100644
index 0000000000000000000000000000000000000000..51570c813a3d09f2ba0373b598384429f736dbaa
--- /dev/null
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/common/search/SearchVorgangCustomRepositoryMongo.java
@@ -0,0 +1,76 @@
+/*
+ * 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.vorgang.common.search;
+
+import java.util.Arrays;
+import java.util.Map;
+
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.mongodb.core.MongoOperations;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.data.mongodb.core.query.TextCriteria;
+import org.springframework.data.mongodb.core.query.TextQuery;
+import org.springframework.data.support.PageableExecutionUtils;
+import org.springframework.stereotype.Repository;
+
+import de.ozgcloud.vorgang.vorgang.FindVorgangRequest;
+import de.ozgcloud.vorgang.vorgang.VorgangHeader;
+import lombok.RequiredArgsConstructor;
+
+@ConditionalOnProperty(prefix = "ozgcloud.mongodbsearch", name = "enabled", havingValue = "true")
+@RequiredArgsConstructor
+@Repository
+public class SearchVorgangCustomRepositoryMongo implements SearchVorgangCustomRepository {
+
+	private final MongoOperations mongoOperations;
+
+	@Override
+	public Page<VorgangHeader> searchBy(final FindVorgangRequest request) {
+		var query = buildQuery(request);
+		var vorgangs = mongoOperations.stream(query, VorgangHeader.class).skip(request.getOffset()).limit(request.getLimit()).toList();
+		return PageableExecutionUtils.getPage(vorgangs, buildPageable(request), vorgangs::size);
+	}
+
+	private Query buildQuery(FindVorgangRequest request) {
+		return TextQuery.queryText(buildTextCriteria(request.getSearchBy())).sortByScore();
+	}
+
+	TextCriteria buildTextCriteria(String searchBy) {
+		var textCriteria = TextCriteria.forDefaultLanguage();
+		Arrays.stream(searchBy.split(StringUtils.SPACE)).forEach(textCriteria::matchingPhrase);
+		return textCriteria;
+	}
+
+	PageRequest buildPageable(FindVorgangRequest request) {
+		return PageRequest.of(request.getOffset() / request.getLimit(), request.getLimit());
+	}
+
+	@Override
+	public void update(final String vorangId, final Map<String, Object> patch) {
+		// update implemented in vorgang.vorgang.VorgangRepository
+	}
+}
diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/registry/ZufiRemoteService.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/registry/ZufiRemoteService.java
index 3aa2a888cfbd90f119e22290567d807bc636659b..bc436dedd25d7bd9ee4ef1ad95f7cfffb1612e8b 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/registry/ZufiRemoteService.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/registry/ZufiRemoteService.java
@@ -28,7 +28,7 @@ class ZufiRemoteService {
 	}
 
 	private GrpcVorgangManagerRegistrationRequest buildRequest(List<String> organistationsEinheitenIds, String address) {
-		return GrpcVorgangManagerRegistrationRequest.newBuilder().addAllOrganisationsEinheitenIds(organistationsEinheitenIds)
+		return GrpcVorgangManagerRegistrationRequest.newBuilder().addAllOrganisationsEinheitIds(organistationsEinheitenIds)
 				.setServiceAddress(address).build();
 	}
 }
diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/status/StatusEventListener.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/status/StatusEventListener.java
index 4596de8fd1ea0477bd122b1af94e571076ee48ac..5c7db826fa425ebafb747b911bc8d6afbd3d5e7f 100644
--- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/status/StatusEventListener.java
+++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/status/StatusEventListener.java
@@ -120,7 +120,7 @@ class StatusEventListener {
 	Command setPreviousState(Command command) {
 		var vorgang = vorgangService.getById(command.getVorgangId());
 		commandService.setPreviousState(command.getId(), getPreviousStateMap(vorgang));
-		return commandService.findCommand(command.getId())
+		return commandService.findById(command.getId())
 				.orElseThrow(() -> new NoSuchElementException("No command with Id %s found".formatted(command.getId())));
 	}
 
diff --git a/vorgang-manager-server/src/main/resources/application-local.yml b/vorgang-manager-server/src/main/resources/application-local.yml
index b1aa3707359cf0cc5a250ea5b76b2a86016d7c06..3c001700cf121f982f772d96606412189ad50db3 100644
--- a/vorgang-manager-server/src/main/resources/application-local.yml
+++ b/vorgang-manager-server/src/main/resources/application-local.yml
@@ -65,9 +65,6 @@ ozgcloud:
   user:
     cleanup:
       cron: 0 */5 * * * *
-  elasticsearch:
-    initEnabled: true
-    index: test-index
   feature:
     bescheid:
       enable-dummy-document-processor: true
@@ -85,10 +82,14 @@ spring:
       - with-elastic
 ozgcloud:
   elasticsearch:
+    initEnabled: true
+    index: test-index
     address: localhost:9200
     username: elastic
     password: password
     useSsl: false
+  mongodbsearch:
+    enabled: false
 
 ---
 
@@ -126,3 +127,14 @@ grpc:
     bayern-id:
       address: static://127.0.0.1:9099
       negotiationType: PLAINTEXT
+      
+---
+
+spring:
+  config:
+    activate:
+      on-profile:
+      - with-mongodbsearch
+ozgcloud:
+  mongodbsearch:
+    enabled: true
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/bescheid/BescheidEventListenerITCase.java b/vorgang-manager-server/src/test/java/de/ozgcloud/bescheid/BescheidITCase.java
similarity index 91%
rename from vorgang-manager-server/src/test/java/de/ozgcloud/bescheid/BescheidEventListenerITCase.java
rename to vorgang-manager-server/src/test/java/de/ozgcloud/bescheid/BescheidITCase.java
index 9e40a8290c82c77854dd2a9d502f46377f962b95..deabb903e2e37c99c2e45d41c8d88006e0077764 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/bescheid/BescheidEventListenerITCase.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/bescheid/BescheidITCase.java
@@ -26,6 +26,7 @@ package de.ozgcloud.bescheid;
 import static de.ozgcloud.bescheid.BescheidEventListener.*;
 import static org.assertj.core.api.Assertions.*;
 import static org.awaitility.Awaitility.*;
+import static org.mockito.ArgumentMatchers.*;
 import static org.mockito.Mockito.*;
 
 import java.time.ZonedDateTime;
@@ -44,7 +45,6 @@ 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;
@@ -59,7 +59,6 @@ import de.ozgcloud.apilib.user.OzgCloudUserProfile;
 import de.ozgcloud.apilib.user.OzgCloudUserProfileService;
 import de.ozgcloud.bescheid.attacheditem.AttachedItemService;
 import de.ozgcloud.command.Command;
-import de.ozgcloud.command.CommandCreatedEvent;
 import de.ozgcloud.command.CommandStatus;
 import de.ozgcloud.common.test.DataITCase;
 import de.ozgcloud.document.BescheidDocumentCreatedEvent;
@@ -73,8 +72,8 @@ import de.ozgcloud.vorgang.VorgangManagerServerApplication;
 import de.ozgcloud.vorgang.attached_item.VorgangAttachedItem;
 import de.ozgcloud.vorgang.attached_item.VorgangAttachedItemTestFactory;
 import de.ozgcloud.vorgang.callcontext.CallContextAuthenticationTokenTestFactory;
+import de.ozgcloud.vorgang.callcontext.WithMockCustomUser;
 import de.ozgcloud.vorgang.command.CommandService;
-import de.ozgcloud.vorgang.command.CommandTestFactory;
 import de.ozgcloud.vorgang.command.CreateCommandRequest;
 import de.ozgcloud.vorgang.servicekonto.ServiceKontoTestFactory;
 import de.ozgcloud.vorgang.status.StatusChangedEvent;
@@ -87,20 +86,18 @@ import de.ozgcloud.vorgang.vorgang.VorgangTestFactory;
 		"grpc.client.ozgcloud-command-manager.address=in-process:test",
 		"grpc.client.vorgang-manager.address=in-process:test",
 		"grpc.client.nachrichten-manager.address=in-process:test",
-		"grpc.client.pluto.address=in-process:test",
 		"grpc.client.command-manager.address=in-process:test",
 		"ozgcloud.feature.bescheid.enable-dummy-document-processor=true",
 })
 @DataITCase
 @DirtiesContext
-class BescheidEventListenerITCase {
+@WithMockCustomUser
+class BescheidITCase {
 
 	private static final String USER_ID = "user-id";
 
 	@Autowired
 	private CommandService commandService;
-	@Autowired
-	private ApplicationEventPublisher eventPublisher;
 	@SpyBean
 	private TestEventListener bescheiTestEventListener;
 
@@ -133,7 +130,7 @@ class BescheidEventListenerITCase {
 			var vorgangId = mongoOperations.save(VorgangTestFactory.createBuilder().id(null).build()).getId();
 			var bescheidItemId = mongoOperations.save(createBescheidAttachedItem(vorgangId)).getId();
 
-			eventPublisher.publishEvent(buildCommandCreatedEvent(vorgangId, bescheidItemId));
+			commandService.createCommand(buildCreatedCommandRequest(vorgangId, bescheidItemId));
 
 			await().atMost(60, TimeUnit.SECONDS).untilAsserted(() -> {
 				verify(bescheiTestEventListener).onBescheidDocumentCreated(bescheidDocumentCreatedEventCaptor.capture());
@@ -146,7 +143,7 @@ class BescheidEventListenerITCase {
 			var vorgangId = mongoOperations.save(VorgangTestFactory.createBuilder().id(null).build()).getId();
 			var bescheidItemId = mongoOperations.save(createBescheidAttachedItem(vorgangId)).getId();
 
-			eventPublisher.publishEvent(buildCommandCreatedEvent(vorgangId, bescheidItemId));
+			commandService.createCommand(buildCreatedCommandRequest(vorgangId, bescheidItemId));
 
 			await().atMost(60, TimeUnit.SECONDS).untilAsserted(() -> {
 				verify(bescheiTestEventListener).onBescheidDocumentCreated(bescheidDocumentCreatedEventCaptor.capture());
@@ -164,15 +161,14 @@ class BescheidEventListenerITCase {
 					.build();
 		}
 
-		private CommandCreatedEvent buildCommandCreatedEvent(String vorgangId, String bescheidItemId) {
-			var command = CommandTestFactory.createBuilder()
+		private CreateCommandRequest buildCreatedCommandRequest(String vorgangId, String bescheidItemId) {
+			return CreateCommandRequest.builder()
 					.vorgangId(vorgangId)
 					.relationId(bescheidItemId)
 					.order(BescheidEventListener.CREATE_BESCHEID_DOCUMENT_ORDER)
 					.bodyObject(Map.of(BESCHEID_VOM_BODY_KEY, "2024-01-01",
 							GENEHMIGT_BODY_KEY, true))
 					.build();
-			return new CommandCreatedEvent(command);
 		}
 
 		private GridFSFile getBescheidDocumentFile() {
@@ -195,14 +191,21 @@ class BescheidEventListenerITCase {
 		@Captor
 		private ArgumentCaptor<StatusChangedEvent> statusChangedEventCaptor;
 
+		private VorgangAttachedItem bescheidItem;;
+		private String vorgangId;
+
+		@BeforeEach
+		void mock() {
+			vorgangId = mongoOperations.save(VorgangTestFactory.createBuilder().id(null).build()).getId();
+			bescheidItem = mongoOperations.save(createBescheidAttachedItemWithDocument(vorgangId));
+		}
+
 		@Test
 		void shouldSetBescheidStatusToSent() {
-			var vorgangId = mongoOperations.save(VorgangTestFactory.createBuilder().id(null).build()).getId();
-			var bescheidItem = mongoOperations.save(createBescheidAttachedItemWithDocument(vorgangId));
-
-			eventPublisher.publishEvent(buildCommandCreatedEvent(vorgangId, bescheidItem));
+			commandService.createCommand(buildCreateCommandRequest());
 
 			await().atMost(60, TimeUnit.SECONDS).untilAsserted(() -> {
+				assertThat(loadBescheid(bescheidItem.getId()).getVersion()).isEqualTo(2);
 				verify(bescheiTestEventListener).onBescheidSentEvent(bescheidSentEventCaptor.capture());
 				assertThat(loadBescheid(bescheidItem.getId()).getItem()).containsEntry(Bescheid.FIELD_STATUS, Bescheid.Status.SENT.name());
 			});
@@ -210,13 +213,10 @@ class BescheidEventListenerITCase {
 
 		@Test
 		void shouldSetVorgangStatusToBeschieden() {
-			var vorgangId = mongoOperations.save(VorgangTestFactory.createBuilder().id(null).build()).getId();
-			var bescheidItem = mongoOperations.save(createBescheidAttachedItemWithDocument(vorgangId));
-			var event = buildCommandCreatedEvent(vorgangId, bescheidItem);
-
-			eventPublisher.publishEvent(event);
+			commandService.createCommand(buildCreateCommandRequest());
 
 			await().atMost(60, TimeUnit.SECONDS).untilAsserted(() -> {
+				assertThat(loadBescheid(bescheidItem.getId()).getVersion()).isEqualTo(2);
 				verify(bescheiTestEventListener).onBescheidStatusChangedEvent(statusChangedEventCaptor.capture());
 				assertThat(loadVorgang(vorgangId).getStatus()).isEqualTo(Vorgang.Status.BESCHIEDEN);
 			});
@@ -235,8 +235,8 @@ class BescheidEventListenerITCase {
 					.build();
 		}
 
-		private CommandCreatedEvent buildCommandCreatedEvent(String vorgangId, VorgangAttachedItem bescheidItem) {
-			var command = CommandTestFactory.createBuilder()
+		private CreateCommandRequest buildCreateCommandRequest() {
+			return CreateCommandRequest.builder()
 					.vorgangId(vorgangId)
 					.relationId(bescheidItem.getId())
 					.relationVersion(bescheidItem.getVersion())
@@ -244,7 +244,6 @@ class BescheidEventListenerITCase {
 					.bodyObject(Map.of(BESCHEID_VOM_BODY_KEY, "2024-01-01",
 							GENEHMIGT_BODY_KEY, true))
 					.build();
-			return new CommandCreatedEvent(command);
 		}
 
 		private VorgangAttachedItem loadBescheid(String bescheidId) {
@@ -312,7 +311,7 @@ class BescheidEventListenerITCase {
 			await().atMost(60, TimeUnit.SECONDS).untilAsserted(() -> {
 				verify(bescheiTestEventListener).onBescheidSentEvent(bescheidSentEventCaptor.capture());
 				var sentInfoMap = MapUtils.getMap(loadBescheid(bescheidItem.getId()).getItem(), Bescheid.FIELD_SENT_INFO);
-				assertThat(sentInfoMap.get(Bescheid.FIELD_SENT_BY)).asString().isNotBlank();
+				assertThat(MapUtils.getString(sentInfoMap, Bescheid.FIELD_SENT_BY)).isNotBlank();
 			});
 		}
 
@@ -339,6 +338,7 @@ class BescheidEventListenerITCase {
 			});
 		}
 
+		@DirtiesContext
 		@Test
 		void shouldSendPostfachNachricht() {
 			var expectedPostfachAddress = PostfachAddressTestFactory.createBuilder()
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/nachrichten/postfach/PersistPostfachNachrichtServiceImplITCase.java b/vorgang-manager-server/src/test/java/de/ozgcloud/nachrichten/postfach/PersistPostfachNachrichtServiceImplITCase.java
index cbd18b8e88f7de97c722790032fab203b0bfeffc..fd8fec55986287b729195fe60ddd04e081334ad9 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/nachrichten/postfach/PersistPostfachNachrichtServiceImplITCase.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/nachrichten/postfach/PersistPostfachNachrichtServiceImplITCase.java
@@ -24,14 +24,15 @@
 package de.ozgcloud.nachrichten.postfach;
 
 import static org.assertj.core.api.Assertions.*;
+import static org.awaitility.Awaitility.*;
 
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.UUID;
 import java.util.concurrent.TimeUnit;
 
 import org.apache.commons.collections.MapUtils;
-import org.awaitility.Awaitility;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Nested;
@@ -55,6 +56,7 @@ import lombok.SneakyThrows;
 		"grpc.server.inProcessName=test",
 		"grpc.client.vorgang-manager.address=in-process:test",
 		"grpc.client.ozgcloud-command-manager.address=in-process:test",
+		"grpc.client.pluto.address=in-process:test",
 })
 @DataITCase
 @DirtiesContext
@@ -63,6 +65,8 @@ class PersistPostfachNachrichtServiceImplITCase {
 	@Autowired
 	private PersistPostfachNachrichtServiceImpl service;
 
+	@Autowired
+	private PostfachNachrichtMapper postfachNachrichtMapper;
 	@Autowired
 	private MongoOperations mongoOperations;
 
@@ -75,6 +79,36 @@ class PersistPostfachNachrichtServiceImplITCase {
 		vorgangId = mongoOperations.save(VorgangTestFactory.createBuilder().id(null).build(), Vorgang.COLLECTION_NAME).getId();
 	}
 
+	@Nested
+	class TestPersistPostfachNachricht {
+
+		@Test
+		void shouldPersistPostfachNachricht() {
+			var postfachNachricht = PostfachNachrichtTestFactory.createBuilder().id(null).vorgangId(vorgangId).build();
+			service.persistNachricht(Optional.empty(), postfachNachricht);
+
+			assertThat(loadPostfachNachrichts()).hasSize(1).first().usingRecursiveComparison().ignoringFields("id").isEqualTo(postfachNachricht);
+		}
+
+		@Test
+		void shouldUpdatePersistedNachricht() {
+			var persistedNachrichtId = mongoOperations.save(VorgangAttachedItemTestFactory.createBuilder().id(null).version(0)
+					.itemName(PersistPostfachNachrichtServiceImpl.ITEM_NAME).item(PostfachNachrichtTestFactory.asMap()).build()).getId();
+			var postfachNachricht = PostfachNachrichtTestFactory.createBuilder().id(persistedNachrichtId).vorgangId(vorgangId)
+					.subject("updated subject").mailBody("updated body").build();
+
+			service.persistNachricht(Optional.empty(), postfachNachricht);
+
+			assertThat(loadPostfachNachrichts()).hasSize(1).first().usingRecursiveComparison().ignoringFields("id").isEqualTo(postfachNachricht);
+		}
+
+		private List<PostfachNachricht> loadPostfachNachrichts() {
+			return await().atMost(60, TimeUnit.MINUTES)
+					.until(() -> mongoOperations.findAll(VorgangAttachedItem.class), list -> !list.isEmpty()).stream()
+					.map(VorgangAttachedItem::getItem).map(postfachNachrichtMapper::fromMapToPostfachMail).toList();
+		}
+	}
+
 	@DisplayName("Find rueckfragen")
 	@Nested
 	class TestFindRueckfragen {
@@ -101,7 +135,7 @@ class PersistPostfachNachrichtServiceImplITCase {
 		void shouldPersistAnswer() {
 			service.persistAnswer(referencedNachrichtId, createPostfachNachricht());
 
-			Awaitility.await().atMost(60, TimeUnit.SECONDS).untilAsserted(() -> {
+			await().atMost(60, TimeUnit.SECONDS).untilAsserted(() -> {
 				var persistedAnswers = findAllVorgangAttachedItems();
 				assertThat(persistedAnswers).hasSize(1).first()
 						.extracting(VorgangAttachedItem::getItem)
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/nachrichten/postfach/PostfachEventListenerITCase.java b/vorgang-manager-server/src/test/java/de/ozgcloud/nachrichten/postfach/PostfachEventListenerITCase.java
index 502e0829ebbc47f6cd630cd9030ee7222acc3b00..516b1ea807fd936a7d7c91b034f8bba505c02017 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/nachrichten/postfach/PostfachEventListenerITCase.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/nachrichten/postfach/PostfachEventListenerITCase.java
@@ -75,7 +75,7 @@ class PostfachEventListenerITCase {
 
 		@BeforeEach
 		void initServices() {
-			when(commandService.findCommand(any())).thenReturn(Optional.of(CommandTestFactory.create()));
+			when(commandService.findById(any())).thenReturn(Optional.of(CommandTestFactory.create()));
 		}
 
 		@Test
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 cf6ab1233d729c31002070698f877d7e3d0c809b..8c657211a40fd0c72b8e13aeff1de606304a4601 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
@@ -71,10 +71,14 @@ import de.ozgcloud.vorgang.files.OzgFile;
 import io.grpc.stub.StreamObserver;
 
 @SpringBootTest(classes = { VorgangManagerServerApplication.class, OsiPostfachProperties.class }, properties = {
+		"grpc.server.in-process-name=postfachitcase",
 		"ozgcloud.osi.postfach.proxyapi.url=http://localhost/ApiProxy/V1/Message",
 		"ozgcloud.osi.postfach.proxyapi.key=1234",
 		"ozgcloud.osi.postfach.proxyapi.realm=test-realm",
-		"ozgcloud.osi.postfach.notification.mail-from=test@local.host"
+		"ozgcloud.osi.postfach.notification.mail-from=test@local.host",
+		"grpc.client.ozgcloud-command-manager.address=in-process:postfachitcase",
+		"grpc.client.command-manager.address=in-process:postfachitcase",
+
 })
 @WithMockUser
 @DataITCase
@@ -93,8 +97,6 @@ class PostfachMailITCase {
 	@MockBean
 	private PolicyService policyService;
 
-	private MockRestServiceServer mockServer;
-
 	@Mock
 	private StreamObserver<GrpcFindPostfachMailsResponse> responseObserver;
 	@Captor
@@ -105,6 +107,7 @@ class PostfachMailITCase {
 
 	@SpyBean
 	private CommandService commandService;
+	private MockRestServiceServer mockServer;
 
 	@BeforeEach
 	void prepareDatabase() {
@@ -133,7 +136,7 @@ class PostfachMailITCase {
 
 			callGrpcEndpoint();
 
-			mockServer.verify();
+			await().atMost(60, TimeUnit.SECONDS).untilAsserted(() -> mockServer.verify());
 		}
 
 		@Nested
@@ -144,6 +147,7 @@ class PostfachMailITCase {
 				mockServerSendSuccess();
 
 				callGrpcEndpoint();
+
 				var mails = await().atMost(60, TimeUnit.SECONDS)
 						.until(PostfachMailITCase.this::callGrpcListEndpoint, PostfachMailITCase.this::hasAtLeastOneElement);
 
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/processor/ProcessorITCase.java b/vorgang-manager-server/src/test/java/de/ozgcloud/processor/ProcessorITCase.java
index 2688640366bfcfc09504f2db123a0dfba3fa12dc..495d3665e76fb0e5badd9cceaadb0e6b8a99dd18 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/processor/ProcessorITCase.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/processor/ProcessorITCase.java
@@ -79,7 +79,7 @@ class ProcessorITCase {
 		var commandBuilder = PersistedCommand.builder().id("42").status(CommandStatus.PENDING).createdAt(ZonedDateTime.now());
 
 		when(commandService.createCommand(any())).thenReturn(commandBuilder.build());
-		when(commandService.findCommand("42"))
+		when(commandService.findById("42"))
 				.thenReturn(Optional.of(commandBuilder.status(CommandStatus.FINISHED).finishedAt(ZonedDateTime.now()).build()));
 	}
 
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/VorgangManagerCallContextProviderTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/VorgangManagerCallContextProviderTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..1ab89f43444d623ec62d3cd493d4b2155e06c276
--- /dev/null
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/VorgangManagerCallContextProviderTest.java
@@ -0,0 +1,118 @@
+/*
+ * 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.vorgang;
+
+import static org.assertj.core.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+import java.util.Optional;
+
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Spy;
+
+import de.ozgcloud.apilib.user.OzgCloudUserId;
+import de.ozgcloud.vorgang.callcontext.CallContextUser;
+import de.ozgcloud.vorgang.callcontext.CurrentUserService;
+import de.ozgcloud.vorgang.callcontext.VorgangManagerClientCallContextAttachingInterceptor;
+
+class VorgangManagerCallContextProviderTest {
+
+	private static final String USER_ID = "userId";
+
+	@Spy
+	@InjectMocks
+	private VorgangManagerCallContextProvider contextProvider;
+
+	@Mock
+	private CurrentUserService currentUserService;
+
+	@Nested
+	class TestProvideContext {
+
+		@Test
+		void shouldSetClientName() {
+			var result = contextProvider.provideContext();
+
+			assertThat(result.getClientName()).isEqualTo(VorgangManagerClientCallContextAttachingInterceptor.VORGANG_MANAGER_CLIENT_NAME);
+		}
+
+		@Test
+		void shouldCallFindUserId() {
+			contextProvider.provideContext();
+
+			verify(contextProvider).findUserId();
+		}
+
+		@Test
+		void shouldSetUserId() {
+			var userId = OzgCloudUserId.from(USER_ID);
+			when(contextProvider.findUserId()).thenReturn(Optional.of(userId));
+
+			var result = contextProvider.provideContext();
+
+			assertThat(result.getUserId()).isEqualTo(userId);
+		}
+	}
+
+	@Nested
+	class TestFindUserId {
+
+		@Test
+		void shouldCallCurrentUserService() {
+			contextProvider.findUserId();
+
+			verify(currentUserService).findUser();
+		}
+
+		@Test
+		void shouldReturnUserId() {
+			var callContextUser = CallContextUser.builder().userId(Optional.of(USER_ID)).build();
+			when(currentUserService.findUser()).thenReturn(Optional.of(callContextUser));
+
+			var result = contextProvider.findUserId();
+
+			assertThat(result).contains(OzgCloudUserId.from(USER_ID));
+		}
+
+		@Test
+		void shouldReturnIfNoUser() {
+			var result = contextProvider.findUserId();
+
+			assertThat(result).isEmpty();
+		}
+
+		@Test
+		void shouldReturnIfNoUserId() {
+			var callContextUser = CallContextUser.builder().userId(Optional.empty()).build();
+			when(currentUserService.findUser()).thenReturn(Optional.of(callContextUser));
+
+			var result = contextProvider.findUserId();
+
+			assertThat(result).isEmpty();
+		}
+	}
+}
\ No newline at end of file
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemEventListenerITCase.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemEventListenerITCase.java
index 248ebc6edb9c5dcc677b60457a71151448a67089..1ef45402d363fe6e8a0a695dd349c88383f31773 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemEventListenerITCase.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemEventListenerITCase.java
@@ -30,6 +30,7 @@ import static org.mockito.Mockito.*;
 import java.util.Map;
 import java.util.concurrent.TimeUnit;
 
+import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -37,6 +38,7 @@ import org.springframework.boot.test.mock.mockito.MockBean;
 import org.springframework.boot.test.mock.mockito.SpyBean;
 import org.springframework.context.ApplicationEventPublisher;
 
+import de.ozgcloud.command.Command;
 import de.ozgcloud.command.RevokeCommandEvent;
 import de.ozgcloud.common.test.ITCase;
 import de.ozgcloud.vorgang.command.CommandCreatedEventTestFactory;
@@ -64,6 +66,12 @@ class VorgangAttachedItemEventListenerITCase {
 
 	@Nested
 	class TestOnCreateItemCommand {
+
+		@BeforeEach
+		void mock() {
+			when(service.create(any(), any())).thenReturn(VorgangAttachedItemTestFactory.create());
+		}
+
 		@Test
 		void shouldCallListener() {
 			var command = CommandTestFactory.createBuilder().order(Order.CREATE_ATTACHED_ITEM.name()).relationId(VorgangTestFactory.ID)
@@ -78,6 +86,12 @@ class VorgangAttachedItemEventListenerITCase {
 
 	@Nested
 	class TestOnUpdateItemCommand {
+
+		@BeforeEach
+		void mock() {
+			when(service.getById(any())).thenReturn(VorgangAttachedItemTestFactory.create());
+		}
+
 		@Test
 		void shouldCallListener() {
 			var command = CommandTestFactory.createBuilder().order(Order.UPDATE_ATTACHED_ITEM.name())
@@ -92,7 +106,14 @@ class VorgangAttachedItemEventListenerITCase {
 
 	@Nested
 	class TestOnPatchItemCommand {
-		private Map<String, Object> bodyMap = Map.of("id", VorgangAttachedItemTestFactory.ID, "item", Map.of("done", true));
+
+		private final Map<String, Object> bodyMap = Map.of(VorgangAttachedItem.FIELDNAME_ID, VorgangAttachedItemTestFactory.ID,
+				VorgangAttachedItem.FIELDNAME_ITEM, Map.of("done", true));
+
+		@BeforeEach
+		void mock() {
+			when(service.getById(any())).thenReturn(VorgangAttachedItemTestFactory.create());
+		}
 
 		@Test
 		void shouldCallListener() {
@@ -134,17 +155,13 @@ class VorgangAttachedItemEventListenerITCase {
 	@Nested
 	class TestOnRevokeDeleteItem {
 
+		private final Command command = CommandTestFactory.createBuilder().order(Order.DELETE_ATTACHED_ITEM.name()).build();
+
 		@Test
 		void shouldCallUnmarkAsDeleted() {
-			var command = CommandTestFactory.createBuilder().order(Order.DELETE_ATTACHED_ITEM.name()).build();
-			var event = new RevokeCommandEvent(command);
+			publisher.publishEvent(new RevokeCommandEvent(command));
 
-			publisher.publishEvent(event);
-
-			await().atMost(5, TimeUnit.SECONDS).untilAsserted(
-					() -> verify(service).unmarkAsDeleteByIdAndVersion(CommandTestFactory.RELATION_ID, CommandTestFactory.RELATION_VERSION));
+			await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> verify(service).revokeDelete(command));
 		}
-
 	}
-
-}
+}
\ No newline at end of file
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemEventListenerTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemEventListenerTest.java
index 7b83059e27150e6459fb4f4a08d72e672fd7dc5b..28611d93e880d5012906f5dc8da81aea4c5a2846 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemEventListenerTest.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemEventListenerTest.java
@@ -27,14 +27,20 @@ import static org.assertj.core.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 java.util.Set;
 
 import jakarta.validation.ValidationException;
 
+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.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.NullSource;
+import org.junit.jupiter.params.provider.ValueSource;
 import org.mapstruct.factory.Mappers;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Captor;
@@ -44,9 +50,9 @@ import org.mockito.Spy;
 import org.springframework.context.ApplicationEventPublisher;
 
 import de.ozgcloud.command.Command;
-import de.ozgcloud.command.CommandRevokeFailedEvent;
 import de.ozgcloud.command.RevokeCommandEvent;
 import de.ozgcloud.vorgang.command.CommandCreatedEventTestFactory;
+import de.ozgcloud.vorgang.command.CommandService;
 import de.ozgcloud.vorgang.command.CommandTestFactory;
 import de.ozgcloud.vorgang.vorgang.VorgangDeletedEventTestFactory;
 import de.ozgcloud.vorgang.vorgang.VorgangTestFactory;
@@ -61,26 +67,27 @@ class VorgangAttachedItemEventListenerTest {
 	private VorgangAttachedItemService service;
 	@Mock
 	private ApplicationEventPublisher publisher;
+	@Mock
+	private CommandService commandService;
 	@Spy
 	private VorgangAttachedItemMapper mapper = Mappers.getMapper(VorgangAttachedItemMapper.class);
 
+	@DisplayName("Create item")
 	@Nested
 	class TestCreateItem {
 
-		private Map<String, Object> bodyMap = VorgangAttachedItemTestFactory.asMap();
+		private final Map<String, Object> bodyMap = VorgangAttachedItemTestFactory.asMap();
 
-		private Command command = CommandTestFactory.createBuilder().bodyObject(bodyMap).relationId(VorgangTestFactory.ID).build();
+		private final Command command = CommandTestFactory.createBuilder().bodyObject(bodyMap).relationId(VorgangTestFactory.ID).build();
 
 		@Captor
 		private ArgumentCaptor<VorgangAttachedItem> itemCaptor;
+		@Captor
+		private ArgumentCaptor<VorgangAttachedItemCreatedEvent> vorgangAttachedItemCreatedEventCaptor;
 
-		@Test
-		void shouldThrowExceptionOnIdDismatching() {
-			var command = CommandTestFactory.createBuilder().vorgangId("other").build();
-			var event = CommandCreatedEventTestFactory.create(command);
-
-			assertThatThrownBy(() -> listener.createItem(event)).isInstanceOf(ValidationException.class);
-
+		@BeforeEach
+		void mock() {
+			when(service.create(any(), any())).thenReturn(VorgangAttachedItemTestFactory.create());
 		}
 
 		@DisplayName("should call service")
@@ -91,7 +98,7 @@ class VorgangAttachedItemEventListenerTest {
 			void withItem() {
 				listener.createItem(CommandCreatedEventTestFactory.create(command));
 
-				verify(service).create(anyString(), itemCaptor.capture());
+				verify(service).create(eq(CommandTestFactory.ID), itemCaptor.capture());
 				assertThat(itemCaptor.getValue()).usingRecursiveComparison()
 						.ignoringFields(VorgangAttachedItem.FIELDNAME_ID, VorgangAttachedItem.FIELDNAME_VERSION)
 						.isEqualTo(VorgangAttachedItemTestFactory.create());
@@ -101,7 +108,7 @@ class VorgangAttachedItemEventListenerTest {
 			void withIdAndVersionAsNull() {
 				listener.createItem(CommandCreatedEventTestFactory.create(command));
 
-				verify(service).create(anyString(), itemCaptor.capture());
+				verify(service).create(eq(CommandTestFactory.ID), itemCaptor.capture());
 				var item = itemCaptor.getValue();
 
 				assertThat(item.getId()).isNull();
@@ -112,37 +119,73 @@ class VorgangAttachedItemEventListenerTest {
 			void withCommandId() {
 				listener.createItem(CommandCreatedEventTestFactory.create(command));
 
-				verify(service).create(eq(CommandTestFactory.ID), any());
+				verify(service).create(any(), any());
 			}
+		}
+	}
 
+	@DisplayName("Validate create command")
+	@Nested
+	class TestValidateCreateCommand {
+
+		@Test
+		void shouldThrowExceptionOnIdMismatching() {
+			var command = CommandTestFactory.createBuilder().vorgangId("other").build();
+
+			assertThatThrownBy(() -> listener.validateCreateCommand(command)).isInstanceOf(ValidationException.class);
 		}
 	}
 
+	@DisplayName("Update item")
 	@Nested
 	class TestUpdateItem {
-		private Map<String, Object> bodyMap = VorgangAttachedItemTestFactory.asMap();
+		private final Map<String, Object> bodyMap = VorgangAttachedItemTestFactory.asMap();
 
 		private Command command = buildCommand(bodyMap);
 
 		@Captor
 		private ArgumentCaptor<VorgangAttachedItem> itemCaptor;
+		@Captor
+		private ArgumentCaptor<Map<String, Object>> itemMapCaptor;
+		@Captor
+		private ArgumentCaptor<VorgangAttachedItemUpdatedEvent> eventCaptor;
+
+		@BeforeEach
+		void mock() {
+			doReturn(VorgangAttachedItemTestFactory.create()).when(listener).getVorgangAttachedItem(any());
+		}
+
+		@Test
+		void shouldGetVorgangAttachedItem() {
+			doUpdateItem();
+
+			verify(listener).getVorgangAttachedItem(VorgangAttachedItemTestFactory.ID);
+		}
+
+		@Test
+		void shouldCallSetCommandPreviousState() {
+			doUpdateItem();
+
+			verify(listener).setCommandPreviousState(CommandTestFactory.ID, VorgangAttachedItemTestFactory.STRING_MAP);
+		}
 
 		@DisplayName("service Call")
 		@Nested
 		class TestCallService {
+
 			@Test
 			void shouldHaveItem() {
-				listener.updateItem(CommandCreatedEventTestFactory.create(command));
+				doUpdateItem();
 
-				verify(service).update(anyString(), itemCaptor.capture());
+				verify(service).update(eq(CommandTestFactory.ID), itemCaptor.capture());
 				assertThat(itemCaptor.getValue()).usingRecursiveComparison().isEqualTo(VorgangAttachedItemTestFactory.create());
 			}
 
 			@Test
 			void shouldHaveCommand() {
-				listener.updateItem(CommandCreatedEventTestFactory.create(command));
+				doUpdateItem();
 
-				verify(service).update(eq(CommandTestFactory.ID), any());
+				verify(service).update(any(), any());
 			}
 
 			@Test
@@ -152,9 +195,27 @@ class VorgangAttachedItemEventListenerTest {
 
 				listener.updateItem(CommandCreatedEventTestFactory.create(buildCommand(bMap)));
 
-				verify(service).update(anyString(), itemCaptor.capture());
+				verify(service).update(eq(CommandTestFactory.ID), itemCaptor.capture());
 				assertThat(itemCaptor.getValue().getId()).isEqualTo(VorgangAttachedItemTestFactory.ID);
 			}
+
+			@DisplayName("should call forceUpdate when")
+			@ParameterizedTest(name = "relationVersion is {0}")
+			@NullSource
+			@ValueSource(longs = { -10, 0 })
+			void shouldCallForceUpdate(Long relationVersion) {
+				command = CommandTestFactory.createBuilder().relationId(VorgangAttachedItemTestFactory.ID).relationVersion(relationVersion)
+						.bodyObject(bodyMap)
+						.build();
+
+				listener.updateItem(CommandCreatedEventTestFactory.create(command));
+
+				verify(service).forceUpdate(CommandTestFactory.ID, VorgangAttachedItemTestFactory.ID, VorgangAttachedItemTestFactory.STRING_MAP);
+			}
+		}
+
+		private void doUpdateItem() {
+			listener.updateItem(CommandCreatedEventTestFactory.create(command));
 		}
 
 		private Command buildCommand(Map<String, Object> bodyMap) {
@@ -163,11 +224,77 @@ class VorgangAttachedItemEventListenerTest {
 		}
 	}
 
+	@DisplayName("Get vorgangAttachedItem")
+	@Nested
+	class TestGetVorgangAttachedItem {
+
+		@BeforeEach
+		void mock() {
+			when(service.getById(any())).thenReturn(VorgangAttachedItemTestFactory.create());
+		}
+
+		@Test
+		void shouldCallService() {
+			listener.getVorgangAttachedItem(VorgangAttachedItemTestFactory.ID);
+
+			verify(service).getById(VorgangAttachedItemTestFactory.ID);
+		}
+
+		@Test
+		void shouldReturnValue() {
+			var item = listener.getVorgangAttachedItem(VorgangAttachedItemTestFactory.ID);
+
+			assertThat(item).usingRecursiveComparison().isEqualTo(VorgangAttachedItemTestFactory.create());
+		}
+	}
+
+	@DisplayName("Set command previous state")
+	@Nested
+	class TestSetCommandPreviousState {
+
+		@Test
+		void shouldCallCommandService() {
+			listener.setCommandPreviousState(CommandTestFactory.ID, VorgangAttachedItemTestFactory.STRING_MAP);
+
+			verify(commandService).setPreviousState(CommandTestFactory.ID, VorgangAttachedItemTestFactory.STRING_MAP);
+		}
+	}
+
+	@DisplayName("Patch item")
 	@Nested
 	class TestPatchItem {
-		private Map<String, Object> bodyMap = Map.of("id", VorgangAttachedItemTestFactory.ID, "item", Map.of("number", "73"));
 
-		private Command command = buildCommand(bodyMap);
+		@Captor
+		private ArgumentCaptor<VorgangAttachedItemUpdatedEvent> eventCaptor;
+
+		private final Map<String, Object> itemMap = Map.of("number", "73");
+		private final Set<String> itemKeys = Set.of("number");
+		private final Map<String, Object> bodyMap = Map.of("id", VorgangAttachedItemTestFactory.ID, VorgangAttachedItem.FIELDNAME_ITEM,
+				itemMap);
+
+		private final Command command = CommandTestFactory.createBuilder().relationId(VorgangAttachedItemTestFactory.ID)
+				.relationVersion(VorgangAttachedItemTestFactory.VERSION).bodyObject(bodyMap).build();
+
+		private final Map<String, Object> patchMap = Collections.emptyMap();
+
+		@BeforeEach
+		void mock() {
+			doReturn(patchMap).when(listener).getExistingItemMapEntries(any(), any());
+		}
+
+		@Test
+		void shouldBuildPatchMap() {
+			doPatchItem();
+
+			verify(listener).getExistingItemMapEntries(CommandTestFactory.RELATION_ID, itemKeys);
+		}
+
+		@Test
+		void shouldCallSetCommandPreviousState() {
+			doPatchItem();
+
+			verify(listener).setCommandPreviousState(CommandTestFactory.ID, patchMap);
+		}
 
 		@DisplayName("service Call")
 		@Nested
@@ -175,22 +302,66 @@ class VorgangAttachedItemEventListenerTest {
 			@SuppressWarnings("unchecked")
 			@Test
 			void shouldHaveItem() {
-				listener.patchItem(CommandCreatedEventTestFactory.create(command));
+				doPatchItem();
 
-				verify(service).patch(any(), (Map<String, Object>) eq(bodyMap.get("item")));
+				verify(service).patch(any(), (Map<String, Object>) eq(bodyMap.get(VorgangAttachedItem.FIELDNAME_ITEM)));
 			}
 
 			@Test
 			void shouldHaveCommand() {
-				listener.patchItem(CommandCreatedEventTestFactory.create(command));
+				doPatchItem();
 
 				verify(service).patch(eq(command), any());
 			}
 		}
 
-		private Command buildCommand(Map<String, Object> bodyMap) {
-			return CommandTestFactory.createBuilder().relationId(VorgangAttachedItemTestFactory.ID)
-					.relationVersion(VorgangAttachedItemTestFactory.VERSION).bodyObject(bodyMap).build();
+		private void doPatchItem() {
+			listener.patchItem(CommandCreatedEventTestFactory.create(command));
+		}
+	}
+
+	@DisplayName("Build patch map")
+	@Nested
+	class TestBuildPatchMap {
+
+		private final Set<String> commandPatchKeySet = Set.of("KeyToPatch", "KeyWithNullValueToPatch");
+		private final Map<String, Object> itemMap = buildItemMap();
+
+		private Map<String, Object> buildItemMap() {
+			var itemMap = new HashMap<String, Object>();
+			itemMap.put("KeyToPatch", "ValueToPatch");
+			itemMap.put("KeyToIgnore", "ValueToIgnore");
+			itemMap.put("KeyWithNullValueToPatch", null);
+			return itemMap;
+		}
+
+		private final VorgangAttachedItem vorgangAttachedItem = VorgangAttachedItemTestFactory.createBuilder().item(itemMap).build();
+
+		@BeforeEach
+		void mock() {
+			when(service.getById(any())).thenReturn(vorgangAttachedItem);
+		}
+
+		@Test
+		void shouldCallGetVorgangAttachedItem() {
+			listener.getExistingItemMapEntries(VorgangAttachedItemTestFactory.ID, commandPatchKeySet);
+
+			verify(service).getById(VorgangAttachedItemTestFactory.ID);
+		}
+
+		@Test
+		void shouldReturnMapWithPatchEntry() {
+			var patchMap = listener.getExistingItemMapEntries(VorgangAttachedItemTestFactory.ID, commandPatchKeySet);
+
+			assertThat(patchMap).hasSize(2).containsEntry("KeyToPatch", "ValueToPatch");
+		}
+
+		@Test
+		void shouldReturnMapWithNullPatchEntry() {
+			var patchMap = listener.getExistingItemMapEntries(VorgangAttachedItemTestFactory.ID, commandPatchKeySet);
+
+			assertThat(patchMap).hasSize(2).containsKey("KeyWithNullValueToPatch");
+			assertThat(patchMap.get("KeyWithNullValueToPatch")).isNull();
 		}
 	}
 
@@ -198,7 +369,7 @@ class VorgangAttachedItemEventListenerTest {
 	@DisplayName("Delete item")
 	class TestDeleteItem {
 
-		private Command command = CommandTestFactory.createBuilder().relationId(VorgangAttachedItemTestFactory.ID)
+		private final Command command = CommandTestFactory.createBuilder().relationId(VorgangAttachedItemTestFactory.ID)
 				.relationVersion(VorgangAttachedItemTestFactory.VERSION).build();
 
 		@Nested
@@ -242,27 +413,87 @@ class VorgangAttachedItemEventListenerTest {
 		}
 	}
 
+	@DisplayName("On revoke create item")
 	@Nested
-	class TestRevokeCommand {
+	class TestOnRevokeCreateItem {
 
-		@Nested
-		class TestDeleteItem {
+		private final Command command = CommandTestFactory.create();
+		private final RevokeCommandEvent revokeEvent = new RevokeCommandEvent(command);
 
-			@Test
-			void shouldCallService() {
-				listener.onRevokeDeleteItem(new RevokeCommandEvent(CommandTestFactory.createBuilder().build()));
+		@Test
+		void shouldCallService() {
+			listener.onRevokeCreateItem(revokeEvent);
 
-				verify(service).unmarkAsDeleteByIdAndVersion(CommandTestFactory.RELATION_ID, CommandTestFactory.RELATION_VERSION);
-			}
+			verify(service).revokeCreate(command);
+		}
+	}
 
-			@Test
-			void shouldCallHandleException() {
-				doThrow(new RuntimeException()).when(service).unmarkAsDeleteByIdAndVersion(anyString(), anyLong());
+	@DisplayName("On revoke delete item")
+	@Nested
+	class TestOnRevokeDeleteItem {
 
-				listener.onRevokeDeleteItem(new RevokeCommandEvent(CommandTestFactory.createBuilder().build()));
+		private final Command command = CommandTestFactory.create();
+		private final RevokeCommandEvent revokeEvent = new RevokeCommandEvent(command);
 
-				verify(publisher).publishEvent(any(CommandRevokeFailedEvent.class));
-			}
+		@Test
+		void shouldCallService() {
+			listener.onRevokeDeleteItem(revokeEvent);
+
+			verify(service).revokeDelete(command);
+		}
+	}
+
+	@DisplayName("On revoke update item")
+	@Nested
+	class TestOnRevokeUpdateItem {
+
+		private final Command command = CommandTestFactory.create();
+		private final RevokeCommandEvent revokeEvent = new RevokeCommandEvent(command);
+
+		@BeforeEach
+		void mock() {
+			when(commandService.getById(any())).thenReturn(command);
+		}
+
+		@Test
+		void shouldGetCommand() {
+			listener.onRevokeUpdateItem(revokeEvent);
+
+			verify(commandService).getById(CommandTestFactory.ID);
+		}
+
+		@Test
+		void shouldCallService() {
+			listener.onRevokeUpdateItem(revokeEvent);
+
+			verify(service).revokeUpdate(command, CommandTestFactory.PREVIOUS_STATE);
+		}
+	}
+
+	@DisplayName("On revoke patch item")
+	@Nested
+	class TestOnRevokePatchItem {
+
+		private final Command command = CommandTestFactory.create();
+		private final RevokeCommandEvent revokeEvent = new RevokeCommandEvent(command);
+
+		@BeforeEach
+		void mock() {
+			when(commandService.getById(any())).thenReturn(CommandTestFactory.create());
+		}
+
+		@Test
+		void shouldGetCommand() {
+			listener.onRevokePatchItem(revokeEvent);
+
+			verify(commandService).getById(CommandTestFactory.ID);
+		}
+
+		@Test
+		void shouldCallService() {
+			listener.onRevokePatchItem(revokeEvent);
+
+			verify(service).revokePatch(command, CommandTestFactory.PREVIOUS_STATE);
 		}
 	}
-}
+}
\ No newline at end of file
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemITCase.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemITCase.java
index 79ce07e580ab83de2d02838ad6837fc009116650..cfaf9ff74c00daa0d1405a656fb898ce181a0256 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemITCase.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemITCase.java
@@ -29,6 +29,8 @@ import static org.junit.jupiter.api.Assertions.*;
 import static org.mockito.Mockito.*;
 
 import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 import java.util.Optional;
 import java.util.concurrent.TimeUnit;
 
@@ -46,13 +48,16 @@ import org.springframework.data.mongodb.core.MongoOperations;
 import org.springframework.security.access.AccessDeniedException;
 
 import de.ozgcloud.command.Command;
-import de.ozgcloud.command.CommandCreatedEvent;
+import de.ozgcloud.command.CommandStatus;
 import de.ozgcloud.common.test.DataITCase;
 import de.ozgcloud.vorgang.callcontext.CallContextUserTestFactory;
 import de.ozgcloud.vorgang.callcontext.CurrentUserService;
-import de.ozgcloud.vorgang.command.CommandCreatedEventTestFactory;
+import de.ozgcloud.vorgang.command.CommandService;
 import de.ozgcloud.vorgang.command.CommandTestFactory;
+import de.ozgcloud.vorgang.command.CreateCommandRequest;
+import de.ozgcloud.vorgang.command.CreateCommandRequestTestFactory;
 import de.ozgcloud.vorgang.command.Order;
+import de.ozgcloud.vorgang.command.RevokeCommandEventTestFactory;
 import de.ozgcloud.vorgang.vorgang.Vorgang;
 import de.ozgcloud.vorgang.vorgang.VorgangTestFactory;
 import de.ozgcloud.vorgang.vorgang.ZustaendigeStelleTestFactory;
@@ -73,23 +78,30 @@ class VorgangAttachedItemITCase {
 	private ApplicationEventPublisher publisher;
 	@Autowired
 	private MongoOperations mongoOperations;
+	@Autowired
+	private CommandService commandService;
 
 	@BeforeEach
 	void prepareDatabase() {
+		mongoOperations.dropCollection(Vorgang.COLLECTION_NAME);
 		mongoOperations.dropCollection(VorgangAttachedItem.COLLECTION_NAME);
+		mongoOperations.dropCollection(Command.COLLECTION_NAME);
 	}
 
 	@DisplayName("Create item")
 	@Nested
 	class TestCreateItem {
 
-		private Command command = CommandTestFactory.createBuilder().order(Order.CREATE_ATTACHED_ITEM.toString())
-				.relationId(VorgangTestFactory.ID).bodyObject(VorgangAttachedItemTestFactory.asMap()).build();
-		private CommandCreatedEvent event = CommandCreatedEventTestFactory.create(command);
+		private final CreateCommandRequest createCommandRequest = CreateCommandRequestTestFactory.createBuilder()
+				.order(Order.CREATE_ATTACHED_ITEM.name())
+				.relationId(VorgangTestFactory.ID)
+				.bodyObject(VorgangAttachedItemTestFactory.asMap())
+				.build();
 
 		@Test
 		void shouldPersistInDatabase() {
-			publisher.publishEvent(event);
+			commandService.createCommand(createCommandRequest);
+
 			await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> {
 				var loadedItems = mongoOperations.findAll(VorgangAttachedItem.class);
 
@@ -106,8 +118,7 @@ class VorgangAttachedItemITCase {
 	@Nested
 	class TestUpdateItem {
 
-		private Command command;
-		private CommandCreatedEvent event;
+		private CreateCommandRequest createCommandRequest;
 
 		private VorgangAttachedItem persistedItem;
 
@@ -123,18 +134,16 @@ class VorgangAttachedItemITCase {
 
 			var bodyObjectMap = new HashMap<>(VorgangAttachedItemTestFactory.asMap());
 			bodyObjectMap.put(VorgangAttachedItem.FIELDNAME_ITEM, itemMap);
-			command = CommandTestFactory.createBuilder()
+			createCommandRequest = CreateCommandRequestTestFactory.createBuilder()
 					.order(Order.UPDATE_ATTACHED_ITEM.name())
 					.relationId(persistedItem.getId())
 					.relationVersion(persistedItem.getVersion())
 					.bodyObject(bodyObjectMap).build();
-
-			event = CommandCreatedEventTestFactory.create(command);
 		}
 
 		@Test
 		void shouldIncrementVersion() {
-			publisher.publishEvent(event);
+			commandService.createCommand(createCommandRequest);
 
 			await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> {
 				var loaded = mongoOperations.findAll(VorgangAttachedItem.class);
@@ -258,4 +267,221 @@ class VorgangAttachedItemITCase {
 			return responseCaptor.getValue();
 		}
 	}
+
+	@DisplayName("Revoke create item")
+	@Nested
+	class TestRevokeCreateItem {
+
+		private VorgangAttachedItem persistedItem;
+
+		@BeforeEach
+		void mock() {
+			persistedItem = mongoOperations.save(VorgangAttachedItemTestFactory.createBuilder().id(null).version(0).build());
+		}
+
+		@Test
+		void shouldDeleteVorgangAttachedItem() {
+			publisher.publishEvent(RevokeCommandEventTestFactory.create(createRevokeCommand()));
+
+			await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> assertThat(findVorgangAttachedItems()).isEmpty());
+		}
+
+		private Command createRevokeCommand() {
+			return CommandTestFactory.createBuilder().order(Order.CREATE_ATTACHED_ITEM.name())
+					.relationId(persistedItem.getId())
+					.relationVersion(persistedItem.getVersion())
+					.bodyObject(VorgangAttachedItemTestFactory.asMap()).build();
+		}
+	}
+
+	@DisplayName("Revoke update item")
+	@Nested
+	class TestRevokeUpdateItem {
+
+		private final Map<String, Object> createItem = Map.<String, Object>of("EntryToRecoverByRevokeKey", "EntryToRecoverByRevokeValue",
+				VorgangAttachedItemTestFactory.ITEM_FIELD_NAME, VorgangAttachedItemTestFactory.ITEM_FIELD_STRING_VALUE);
+		private VorgangAttachedItem persistedItem;
+
+		private final Map<String, Object> updateItem = Map.<String, Object>of(
+				VorgangAttachedItemTestFactory.ITEM_FIELD_NAME, "RevertByRevokeValue",
+				"NewToRemoveByRevokeKey", "NewToRemoveByRevokeValue");
+		private Command updatedCommand;
+		private String vorgangId;
+
+		@BeforeEach
+		void mock() {
+			vorgangId = mongoOperations.save(VorgangTestFactory.createBuilder().id(null).version(0).build()).getId();
+			createVorgangAttachedItem();
+
+			persistedItem = findVorgangAttachedItems().get(0);
+
+			updateVorgangAttchedItem();
+		}
+
+		private void createVorgangAttachedItem() {
+			commandService.createCommand(createAttachedItemCommandRequest());
+
+			await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> {
+				assertThat(findCommands()).hasSize(1);
+				var vorgangAttachedItems = findVorgangAttachedItems();
+				assertThat(vorgangAttachedItems).hasSize(1);
+				assertThat(vorgangAttachedItems.get(0).getVersion()).isEqualTo(1);
+				assertThat(vorgangAttachedItems.get(0).getItem()).isEqualTo(createItem);
+			});
+		}
+
+		private CreateCommandRequest createAttachedItemCommandRequest() {
+			return CreateCommandRequestTestFactory.createBuilder()
+					.order(Order.CREATE_ATTACHED_ITEM.name())
+					.vorgangId(vorgangId)
+					.relationId(vorgangId)
+					.relationVersion(0L)
+					.bodyObject(createCreateCommandBodyObject(0L, createItem))
+					.build();
+		}
+
+		private void updateVorgangAttchedItem() {
+			updatedCommand = commandService.createCommand(createUpdateCommandRequest());
+
+			await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> {
+				assertThat(findCommands()).hasSize(2);
+				assertThat(findVorgangAttachedItems()).hasSize(1);
+				assertThat(findVorgangAttachedItems().get(0).getVersion()).isEqualTo(2);
+				assertThat(findVorgangAttachedItems().get(0).getItem()).isEqualTo(updateItem);
+			});
+		}
+
+		private CreateCommandRequest createUpdateCommandRequest() {
+			return CreateCommandRequestTestFactory.createBuilder()
+					.order(Order.UPDATE_ATTACHED_ITEM.name())
+					.vorgangId(vorgangId)
+					.relationId(persistedItem.getId())
+					.relationVersion(persistedItem.getVersion())
+					.bodyObject(createCreateCommandBodyObject(1L, updateItem))
+					.build();
+		}
+
+		private Map<String, Object> createCreateCommandBodyObject(Long relationVersion, Map<String, Object> bodyMap) {
+			var bodyObjectMap = new HashMap<>(VorgangAttachedItemTestFactory.asMap());
+			bodyObjectMap.put(VorgangAttachedItem.FIELDNAME_ITEM, new HashMap<>(bodyMap));
+			bodyObjectMap.put(VorgangAttachedItem.FIELDNAME_VORGANG_ID, vorgangId);
+			bodyObjectMap.put(VorgangAttachedItem.FIELDNAME_VERSION, relationVersion);
+			return bodyObjectMap;
+		}
+
+		@Test
+		void shouldRestoreItemValues() {
+			commandService.revokeCommand(updatedCommand.getId());
+
+			await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> {
+				var vorgangAttachedItem = findVorgangAttachedItems().get(0);
+				assertThat(findVorgangAttachedItems()).hasSize(1);
+				assertThat(vorgangAttachedItem.getVersion()).isEqualTo(3);
+				var updateCommand = mongoOperations.findById(updatedCommand.getId(), Command.class);
+				assertThat(updateCommand.getStatus()).isEqualTo(CommandStatus.REVOKED);
+				assertThat(vorgangAttachedItem.getItem()).containsEntry("EntryToRecoverByRevokeKey", "EntryToRecoverByRevokeValue");
+				assertThat(vorgangAttachedItem.getItem()).containsEntry(VorgangAttachedItemTestFactory.ITEM_FIELD_NAME,
+						VorgangAttachedItemTestFactory.ITEM_FIELD_STRING_VALUE);
+				assertThat(vorgangAttachedItem.getItem()).doesNotContainKey("NewToRemoveByRevokeKey");
+			});
+		}
+	}
+
+	@DisplayName("Revoke patch item")
+	@Nested
+	class TestRevokePatchItem {
+
+		private final Map<String, Object> createItem = Map.<String, Object>of(VorgangAttachedItemTestFactory.ITEM_FIELD_NAME,
+				VorgangAttachedItemTestFactory.ITEM_FIELD_STRING_VALUE);
+		private VorgangAttachedItem persistedItem;
+
+		private final Map<String, Object> patchItem = Map.<String, Object>of(VorgangAttachedItemTestFactory.ITEM_FIELD_NAME, "UpdatedStringValue");
+		private Command patchedCommand;
+		private String vorgangId;
+
+		@BeforeEach
+		void mock() {
+			vorgangId = mongoOperations.save(VorgangTestFactory.createBuilder().id(null).version(0).build()).getId();
+			createVorgangAttachedItem();
+
+			persistedItem = findVorgangAttachedItems().get(0);
+
+			patchVorgangAttchedItem();
+		}
+
+		private void createVorgangAttachedItem() {
+			commandService.createCommand(createAttachedItemCommandRequest());
+			await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> {
+				assertThat(findCommands()).hasSize(1);
+				var vorgangAttachedItems = findVorgangAttachedItems();
+				assertThat(vorgangAttachedItems).hasSize(1);
+				assertThat(vorgangAttachedItems.get(0).getVersion()).isEqualTo(1);
+				assertThat(vorgangAttachedItems.get(0).getItem()).containsEntry(VorgangAttachedItemTestFactory.ITEM_FIELD_NAME,
+						VorgangAttachedItemTestFactory.ITEM_FIELD_STRING_VALUE);
+			});
+		}
+
+		private CreateCommandRequest createAttachedItemCommandRequest() {
+			return CreateCommandRequestTestFactory.createBuilder()
+					.order(Order.CREATE_ATTACHED_ITEM.name())
+					.vorgangId(vorgangId)
+					.relationId(vorgangId)
+					.relationVersion(0L)
+					.bodyObject(createCreateCommandBodyObject(0L, createItem))
+					.build();
+		}
+
+		private void patchVorgangAttchedItem() {
+			patchedCommand = commandService.createCommand(createPatchCommandRequest());
+
+			await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> {
+				assertThat(findCommands()).hasSize(2);
+				var vorgangAttachedItems = findVorgangAttachedItems();
+				assertThat(vorgangAttachedItems).hasSize(1);
+				assertThat(vorgangAttachedItems.get(0).getVersion()).isEqualTo(2);
+				assertThat(vorgangAttachedItems.get(0).getItem()).containsEntry(VorgangAttachedItemTestFactory.ITEM_FIELD_NAME, "UpdatedStringValue");
+			});
+		}
+
+		private CreateCommandRequest createPatchCommandRequest() {
+			return CreateCommandRequestTestFactory.createBuilder()
+					.order(Order.PATCH_ATTACHED_ITEM.name())
+					.vorgangId(vorgangId)
+					.relationId(persistedItem.getId())
+					.relationVersion(persistedItem.getVersion())
+					.bodyObject(createCreateCommandBodyObject(1L, patchItem))
+					.build();
+		}
+
+		private Map<String, Object> createCreateCommandBodyObject(Long relationVersion, Map<String, Object> bodyMap) {
+			var bodyObjectMap = new HashMap<>(VorgangAttachedItemTestFactory.asMap());
+			bodyObjectMap.put(VorgangAttachedItem.FIELDNAME_ITEM, new HashMap<>(bodyMap));
+			bodyObjectMap.put(VorgangAttachedItem.FIELDNAME_VORGANG_ID, vorgangId);
+			bodyObjectMap.put(VorgangAttachedItem.FIELDNAME_VERSION, relationVersion);
+			return bodyObjectMap;
+		}
+
+		@Test
+		void shouldRestoreItemValues() {
+			commandService.revokeCommand(patchedCommand.getId());
+
+			await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> {
+				var updateCommand = mongoOperations.findById(patchedCommand.getId(), Command.class);
+				assertThat(updateCommand.getStatus()).isEqualTo(CommandStatus.REVOKED);
+				assertThat(findVorgangAttachedItems()).hasSize(1);
+				var vorgangAttachedItem = findVorgangAttachedItems().get(0);
+				assertThat(vorgangAttachedItem.getVersion()).isEqualTo(3);
+				assertThat(findVorgangAttachedItems().get(0).getItem()).containsEntry(VorgangAttachedItemTestFactory.ITEM_FIELD_NAME,
+						VorgangAttachedItemTestFactory.ITEM_FIELD_STRING_VALUE);
+			});
+		}
+	}
+
+	private List<VorgangAttachedItem> findVorgangAttachedItems() {
+		return mongoOperations.findAll(VorgangAttachedItem.class);
+	}
+
+	private List<Command> findCommands() {
+		return mongoOperations.findAll(Command.class);
+	}
 }
\ No newline at end of file
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemMapperTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemMapperTest.java
index 93c89a4951f318bff83ecea305ef89a26a2f74f7..db159bbd05feb088276177df9becc3ab69dca57a 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemMapperTest.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemMapperTest.java
@@ -40,7 +40,7 @@ class VorgangAttachedItemMapperTest {
 	void shouldBeFilled() {
 		var item = mapper.fill(itemAsMap);
 
-		assertThat(item).usingRecursiveComparison().isEqualTo(VorgangAttachedItemTestFactory.create());
+		assertThat(item).usingRecursiveComparison().ignoringFields(VorgangAttachedItem.FIELDNAME_ID)
+				.isEqualTo(VorgangAttachedItemTestFactory.create());
 	}
-
-}
+}
\ No newline at end of file
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemRepositoryITCase.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemRepositoryITCase.java
index 8145e0f6cd15c9f4c51d9323b9e2f2fae33ff819..8292b3c695855fa04b2e12cfc06e7cae04b2ca6f 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemRepositoryITCase.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemRepositoryITCase.java
@@ -28,6 +28,7 @@ import static org.junit.jupiter.api.Assertions.*;
 
 import java.util.Collections;
 import java.util.ConcurrentModificationException;
+import java.util.HashMap;
 import java.util.Map;
 
 import org.junit.jupiter.api.BeforeEach;
@@ -43,6 +44,8 @@ import de.ozgcloud.vorgang.vorgang.VorgangTestFactory;
 @DataITCase
 class VorgangAttachedItemRepositoryITCase {
 
+	private static final Map<String, Object> UPDATE_ITEM_MAP = Map.of("dontTouch", 600);
+
 	@Autowired
 	private VorgangAttachedItemRepository repository;
 	@Autowired
@@ -145,19 +148,90 @@ class VorgangAttachedItemRepositoryITCase {
 		}
 	}
 
+	@Nested
+	class TestUpdate {
+
+		@BeforeEach
+		void init() {
+			persistedItem = mongoOperations.save(VorgangAttachedItemTestFactory.createBuilder().id(null).version(0).build());
+		}
+
+		@Test
+		void shouldUpdate() {
+			var result = updateItem();
+
+			assertThat(result.getItem()).containsExactlyEntriesOf(UPDATE_ITEM_MAP);
+			assertThat(result.getVersion()).isEqualTo(2);
+		}
+
+		@Test
+		void shouldNotUpdateDeletedItem() {
+			persistedItem = mongoOperations.save(VorgangAttachedItemTestFactory.createBuilder().id(null).version(0).deleted(true).build());
+
+			var result = updateItem();
+
+			assertThat(result.getItem()).isEqualTo(VorgangAttachedItemTestFactory.STRING_MAP);
+			assertThat(result.getVersion()).isEqualTo(1);
+		}
+
+		@Test
+		void shouldFailOnCollision() {
+			var itemId = persistedItem.getId();
+
+			assertThrows(ConcurrentModificationException.class, () -> repository.update(itemId, 0, UPDATE_ITEM_MAP));
+		}
+
+		VorgangAttachedItem updateItem() {
+			repository.update(persistedItem.getId(), persistedItem.getVersion(), UPDATE_ITEM_MAP);
+			return mongoOperations.findById(persistedItem.getId(), VorgangAttachedItem.class);
+		}
+
+	}
+
+	@Nested
+	class TestForceUpdate {
+
+		@BeforeEach
+		void init() {
+			persistedItem = mongoOperations.save(VorgangAttachedItemTestFactory.createBuilder().id(null).version(0).build());
+		}
+
+		@Test
+		void shouldUpdate() {
+			var result = forceUpdateItem();
+
+			assertThat(result.getItem()).containsExactlyEntriesOf(UPDATE_ITEM_MAP);
+			assertThat(result.getVersion()).isEqualTo(2);
+		}
+
+		@Test
+		void shouldNotUpdateDeletedItem() {
+			persistedItem = mongoOperations.save(VorgangAttachedItemTestFactory.createBuilder().id(null).version(0).deleted(true).build());
+
+			var result = forceUpdateItem();
+
+			assertThat(result.getItem()).isEqualTo(VorgangAttachedItemTestFactory.STRING_MAP);
+			assertThat(result.getVersion()).isEqualTo(1);
+		}
+
+		VorgangAttachedItem forceUpdateItem() {
+			repository.forceUpdate(persistedItem.getId(), UPDATE_ITEM_MAP);
+			return mongoOperations.findById(persistedItem.getId(), VorgangAttachedItem.class);
+		}
+
+	}
+
 	@Nested
 	class TestPatch {
 
 		@BeforeEach
 		void prepareDatabase() {
-			mongoOperations.dropCollection(VorgangAttachedItem.COLLECTION_NAME);
-
 			persistedItem = mongoOperations.save(VorgangAttachedItemTestFactory.createBuilder().id(null).version(0).build());
 		}
 
 		@Test
 		void shouldUpdateFieldValue() {
-			repository.patch(persistedItem.getId(), persistedItem.getVersion(), buildPatchMap());
+			repository.patch(persistedItem.getId(), persistedItem.getVersion(), UPDATE_ITEM_MAP);
 
 			var loaded = findVorgangAttachedItem();
 			assertThat(loaded).isNotNull();
@@ -178,7 +252,7 @@ class VorgangAttachedItemRepositoryITCase {
 
 		@Test
 		void shouldIncreaseVersion() {
-			repository.patch(persistedItem.getId(), persistedItem.getVersion(), buildPatchMap());
+			repository.patch(persistedItem.getId(), persistedItem.getVersion(), UPDATE_ITEM_MAP);
 
 			var loaded = findVorgangAttachedItem();
 			assertThat(loaded).isNotNull();
@@ -186,45 +260,51 @@ class VorgangAttachedItemRepositoryITCase {
 		}
 
 		@Test
-		void shouldNotUpdateOnWrongVersion() {
-			repository.patch(persistedItem.getId(), 42, buildPatchMap());
-
-			var loaded = findVorgangAttachedItem();
+		void shouldThrowExceptionWhenVersionMismatch() {
+			mongoOperations.save(persistedItem);
 
-			assertThat(loaded).usingRecursiveComparison().isEqualTo(persistedItem);
+			var itemId = persistedItem.getId();
+			assertThrows(ConcurrentModificationException.class, () -> repository.patch(itemId, 42, UPDATE_ITEM_MAP));
 		}
 
 		@Test
 		void shouldNotPatchDeletedItem() {
 			var deletedItem = mongoOperations.save(VorgangAttachedItemTestFactory.createBuilder().id(null).version(0).deleted(true).build());
 
-			repository.patch(deletedItem.getId(), deletedItem.getVersion(), buildPatchMap());
+			repository.patch(deletedItem.getId(), deletedItem.getVersion(), UPDATE_ITEM_MAP);
 
 			var loaded = mongoOperations.findById(deletedItem.getId(), VorgangAttachedItem.class);
 			assertThat(loaded).usingRecursiveComparison().isEqualTo(deletedItem);
 		}
 
-		private Map<String, Object> buildPatchMap() {
-			return Map.of("dontTouch", 600);
-		}
 	}
 
 	@Nested
-	class TestForceUpdate {
+	class TestForcePatch {
+
+		@Test
+		void shouldPatch() {
+			var expectedItemMap = new HashMap<>(VorgangAttachedItemTestFactory.STRING_MAP);
+			expectedItemMap.putAll(UPDATE_ITEM_MAP);
+			var attachedItem = mongoOperations.save(VorgangAttachedItemTestFactory.createBuilder().id(null).version(0).build());
+
+			repository.forcePatch(attachedItem.getId(), UPDATE_ITEM_MAP);
+
+			var result = mongoOperations.findById(attachedItem.getId(), VorgangAttachedItem.class);
+			assertThat(result.getItem()).containsExactlyEntriesOf(expectedItemMap);
+			assertThat(result.getVersion()).isEqualTo(2);
+		}
 
 		@Test
 		void shouldNotPatchDeletedItem() {
 			var deletedItem = mongoOperations.save(VorgangAttachedItemTestFactory.createBuilder().id(null).version(0).deleted(true).build());
 
-			repository.forcePatch(deletedItem.getId(), buildPatchMap());
+			repository.forcePatch(deletedItem.getId(), UPDATE_ITEM_MAP);
 
 			var loaded = mongoOperations.findById(deletedItem.getId(), VorgangAttachedItem.class);
 			assertThat(loaded).usingRecursiveComparison().isEqualTo(deletedItem);
 		}
 
-		private Map<String, Object> buildPatchMap() {
-			return Map.of("dontTouch", 600);
-		}
 	}
 
 	@Nested
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemServiceITCase.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemServiceITCase.java
index eccdc065fd841e0119aa7074808c44d9aa23655c..6bafdceabe71af6f52b99993f7a89d309f612924 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemServiceITCase.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemServiceITCase.java
@@ -2,6 +2,8 @@ package de.ozgcloud.vorgang.attached_item;
 
 import static org.assertj.core.api.Assertions.*;
 
+import jakarta.validation.ConstraintViolationException;
+
 import org.apache.commons.lang3.StringUtils;
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
@@ -11,7 +13,6 @@ import org.springframework.context.ApplicationEventPublisher;
 
 import de.ozgcloud.common.test.ITCase;
 import de.ozgcloud.vorgang.command.CommandTestFactory;
-import jakarta.validation.ConstraintViolationException;
 
 @ITCase
 class VorgangAttachedItemServiceITCase {
@@ -30,25 +31,21 @@ class VorgangAttachedItemServiceITCase {
 		void shouldDenyMissingClientName() {
 			var item = VorgangAttachedItemTestFactory.createBuilder().client(StringUtils.EMPTY).build();
 
-			assertThatThrownBy(() -> service.create(CommandTestFactory.ID, item))
-					.isInstanceOf(ConstraintViolationException.class);
+			assertThatThrownBy(() -> service.create(CommandTestFactory.ID, item)).isInstanceOf(ConstraintViolationException.class);
 		}
 
 		@Test
 		void shouldDenyMissingVorgangId() {
 			var item = VorgangAttachedItemTestFactory.createBuilder().vorgangId(StringUtils.EMPTY).build();
 
-			assertThatThrownBy(() -> service.create(CommandTestFactory.ID, item))
-					.isInstanceOf(ConstraintViolationException.class);
+			assertThatThrownBy(() -> service.create(CommandTestFactory.ID, item)).isInstanceOf(ConstraintViolationException.class);
 		}
 
 		@Test
 		void shouldDenyMissingItemName() {
 			var item = VorgangAttachedItemTestFactory.createBuilder().itemName(StringUtils.EMPTY).build();
 
-			assertThatThrownBy(() -> service.create(CommandTestFactory.ID, item))
-					.isInstanceOf(ConstraintViolationException.class);
+			assertThatThrownBy(() -> service.create(CommandTestFactory.ID, item)).isInstanceOf(ConstraintViolationException.class);
 		}
 	}
-
 }
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemServiceTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemServiceTest.java
index 126d872284154d990daa7e429e7d866ca4988fae..932e678e5585088726653434c5e55ee0210fc3a9 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemServiceTest.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemServiceTest.java
@@ -36,12 +36,16 @@ import java.util.UUID;
 import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.Spy;
 import org.springframework.context.ApplicationEventPublisher;
 
 import de.ozgcloud.command.Command;
+import de.ozgcloud.command.CommandRevokeFailedEvent;
+import de.ozgcloud.command.CommandRevokedEvent;
 import de.ozgcloud.nachrichten.postfach.PostfachNachrichtTestFactory;
 import de.ozgcloud.vorgang.command.CommandTestFactory;
 import de.ozgcloud.vorgang.common.errorhandling.NotFoundException;
@@ -108,42 +112,51 @@ class VorgangAttachedItemServiceTest {
 				assertThat(prepared.isDeleted()).isFalse();
 			}
 		}
-
 	}
 
+	@DisplayName("Update item")
 	@Nested
 	class TestUpdateItem {
 
+		@Captor
+		private ArgumentCaptor<VorgangAttachedItemUpdatedEvent> eventCaptor;
+
 		@Test
-		void shouldCallRepository() {
+		void shouldCallDoUpate() {
 			service.update(CommandTestFactory.ID, VorgangAttachedItemTestFactory.create());
 
-			verify(repository).patch(any(), anyLong(), any());
+			verify(service).doUpdate(VorgangAttachedItemTestFactory.ID, VERSION, STRING_MAP);
 		}
 
 		@Test
 		void shouldPublishEvent() {
 			service.update(CommandTestFactory.ID, VorgangAttachedItemTestFactory.create());
 
-			verify(publisher).publishEvent(any(VorgangAttachedItemUpdatedEvent.class));
+			verify(publisher).publishEvent(eventCaptor.capture());
+			assertThat(eventCaptor.getValue()).extracting(VorgangAttachedItemUpdatedEvent::getSource).isEqualTo(CommandTestFactory.ID);
 		}
 	}
 
+	@DisplayName("Force update")
 	@Nested
 	class TestForceUpdateItem {
 
+		@Captor
+		private ArgumentCaptor<VorgangAttachedItemUpdatedEvent> eventCaptor;
+
 		@Test
 		void shouldCallRepository() {
-			service.forceUpdate(CommandTestFactory.ID, VorgangAttachedItemTestFactory.create());
+			service.forceUpdate(CommandTestFactory.ID, VorgangAttachedItemTestFactory.ID, VorgangAttachedItemTestFactory.STRING_MAP);
 
-			verify(repository).forcePatch(eq(VorgangAttachedItemTestFactory.ID), any());
+			verify(repository).forceUpdate(VorgangAttachedItemTestFactory.ID, VorgangAttachedItemTestFactory.STRING_MAP);
 		}
 
 		@Test
 		void shouldPublishEvent() {
-			service.forceUpdate(CommandTestFactory.ID, VorgangAttachedItemTestFactory.create());
+			service.forceUpdate(CommandTestFactory.ID, VorgangAttachedItemTestFactory.ID, VorgangAttachedItemTestFactory.STRING_MAP);
 
-			verify(publisher).publishEvent(any(VorgangAttachedItemUpdatedEvent.class));
+			verify(publisher).publishEvent(eventCaptor.capture());
+			assertThat(eventCaptor.getValue()).extracting(VorgangAttachedItemUpdatedEvent::getSource).isEqualTo(CommandTestFactory.ID);
 		}
 	}
 
@@ -156,7 +169,6 @@ class VorgangAttachedItemServiceTest {
 
 			verify(repository).findByIdAndDeleted(PostfachNachrichtTestFactory.ID, VorgangAttachedItemService.NOT_DELETED);
 		}
-
 	}
 
 	@Nested
@@ -195,23 +207,24 @@ class VorgangAttachedItemServiceTest {
 	@Nested
 	class TestPatch {
 
-		@Test
-		void shouldCallRepository() {
-			Map<String, Object> propertyMap = Map.of(VorgangAttachedItemTestFactory.ITEM_FIELD_NAME,
-					VorgangAttachedItemTestFactory.ITEM_FIELD_INT_VALUE);
-			var item = VorgangAttachedItemTestFactory.createBuilder().item(propertyMap).build();
-			var command = buildCommand(propertyMap);
+		private final Command command = CommandTestFactory.create();
+
+		@Captor
+		private ArgumentCaptor<VorgangAttachedItemUpdatedEvent> eventCaptor;
 
-			service.patch(command, item.getItem());
+		@Test
+		void shouldCallDoPatch() {
+			service.patch(command, VorgangAttachedItemTestFactory.STRING_MAP);
 
-			verify(repository).patch(VorgangAttachedItemTestFactory.ID, VorgangAttachedItemTestFactory.VERSION, propertyMap);
+			verify(service).doPatch(command, CommandTestFactory.RELATION_VERSION, VorgangAttachedItemTestFactory.STRING_MAP);
 		}
 
-		private Command buildCommand(Map<String, Object> bodyMap) {
-			return CommandTestFactory.createBuilder()
-					.relationId(VorgangAttachedItemTestFactory.ID)
-					.relationVersion(VorgangAttachedItemTestFactory.VERSION)
-					.bodyObject(bodyMap).build();
+		@Test
+		void shouldPublishEvent() {
+			service.update(CommandTestFactory.ID, VorgangAttachedItemTestFactory.create());
+
+			verify(publisher).publishEvent(eventCaptor.capture());
+			assertThat(eventCaptor.getValue()).extracting(VorgangAttachedItemUpdatedEvent::getSource).isEqualTo(CommandTestFactory.ID);
 		}
 	}
 
@@ -230,8 +243,8 @@ class VorgangAttachedItemServiceTest {
 	}
 
 	@Nested
-
 	class TestGetById {
+
 		@Test
 		void shouldReturnAttachedItem() {
 			var item = VorgangAttachedItemTestFactory.create();
@@ -297,7 +310,7 @@ class VorgangAttachedItemServiceTest {
 
 	@Nested
 	@DisplayName("Delete item by vorgangId")
-	class TestDelete {
+	class TestDeleteByVorgangId {
 
 		@Test
 		void shouldCallDeleteMethod() {
@@ -307,4 +320,164 @@ class VorgangAttachedItemServiceTest {
 		}
 
 	}
+
+	@DisplayName("Delete")
+	@Nested
+	class TestDelete {
+
+		@Test
+		void shouldCallRepository() {
+			service.delete(VorgangAttachedItemTestFactory.ID, VorgangAttachedItemTestFactory.VERSION);
+
+			verify(repository).delete(VorgangAttachedItemTestFactory.ID, VorgangAttachedItemTestFactory.VERSION);
+		}
+	}
+
+	@DisplayName("Do patch")
+	@Nested
+	class TestDoPatch {
+
+		@Test
+		void shouldCallRepository() {
+			service.doPatch(CommandTestFactory.create(), CommandTestFactory.RELATION_VERSION, STRING_MAP);
+
+			verify(repository).patch(CommandTestFactory.RELATION_ID, CommandTestFactory.RELATION_VERSION, STRING_MAP);
+		}
+	}
+
+	@DisplayName("Do Update")
+	@Nested
+	class TestDoUpdate {
+
+		@Test
+		void shouldCallRepository() {
+			service.doUpdate(VorgangAttachedItemTestFactory.ID, VorgangAttachedItemTestFactory.VERSION, STRING_MAP);
+
+			verify(repository).update(VorgangAttachedItemTestFactory.ID, VorgangAttachedItemTestFactory.VERSION, STRING_MAP);
+		}
+	}
+
+	@DisplayName("Revoke create")
+	@Nested
+	class TestRevokeCreate {
+
+		private final Command command = CommandTestFactory.create();
+
+		@Test
+		void shouldCallHandleRevoke() {
+			service.revokeCreate(command);
+
+			verify(service).handleRevoke(eq(command), any(Runnable.class));
+		}
+
+		@Test
+		void shouldCallDelete() {
+			service.revokeCreate(command);
+
+			verify(service).delete(CommandTestFactory.RELATION_ID, CommandTestFactory.RELATION_VERSION);
+		}
+	}
+
+	@DisplayName("Revoke delete")
+	@Nested
+	class TestRevokeDelete {
+
+		private final Command command = CommandTestFactory.create();
+
+		@Test
+		void shouldCallHandleRevoke() {
+			service.revokeDelete(command);
+
+			verify(service).handleRevoke(eq(command), any(Runnable.class));
+		}
+
+		@Test
+		void shouldCallDelete() {
+			service.revokeDelete(command);
+
+			verify(service).unmarkAsDeleteByIdAndVersion(CommandTestFactory.RELATION_ID, CommandTestFactory.RELATION_VERSION);
+		}
+	}
+
+	@DisplayName("Revoke Patch")
+	@Nested
+	class TestRevokePatch {
+
+		private final Command command = CommandTestFactory.create();
+
+		@Test
+		void shouldCallHandleRevoke() {
+			service.revokePatch(command, STRING_MAP);
+
+			verify(service).handleRevoke(eq(command), any(Runnable.class));
+		}
+
+		@Test
+		void shouldCallPatch() {
+			service.revokePatch(command, STRING_MAP);
+
+			verify(service).doPatch(command, CommandTestFactory.RELATION_VERSION + 1, STRING_MAP);
+		}
+	}
+
+	@DisplayName("Revoke Update")
+	@Nested
+	class TestRevokeUpdate {
+
+		private final Command command = CommandTestFactory.create();
+
+		@Test
+		void shouldCallHandleRevoke() {
+			service.revokeUpdate(command, STRING_MAP);
+
+			verify(service).handleRevoke(eq(command), any(Runnable.class));
+		}
+
+		@Test
+		void shouldCallPatch() {
+			service.revokeUpdate(command, STRING_MAP);
+
+			verify(service).doUpdate(CommandTestFactory.RELATION_ID, CommandTestFactory.RELATION_VERSION + 1, STRING_MAP);
+		}
+	}
+
+	@DisplayName("Handle revoke")
+	@Nested
+	class TestHandleRevoke {
+
+		@Captor
+		private ArgumentCaptor<CommandRevokedEvent> commandRevokedEventCaptor;
+		@Captor
+		private ArgumentCaptor<CommandRevokeFailedEvent> commandRevokedFailedEventCaptor;
+
+		@Mock
+		private Runnable runnable;
+
+		private final Command command = CommandTestFactory.create();
+
+		@Test
+		void shouldCallServiceFunction() {
+			service.handleRevoke(command, runnable);
+
+			verify(runnable).run();
+		}
+
+		@Test
+		void shouldPublishCommandRevokedEvent() {
+			service.handleRevoke(command, runnable);
+
+			verify(publisher).publishEvent(commandRevokedEventCaptor.capture());
+			assertThat(commandRevokedEventCaptor.getValue().getSource()).isEqualTo(command);
+		}
+
+		@Test
+		void shouldPublishCommandRevokeFailedEventOnException() {
+			doThrow(new RuntimeException()).when(runnable).run();
+
+			service.handleRevoke(command, runnable);
+
+			verify(publisher).publishEvent(commandRevokedFailedEventCaptor.capture());
+			assertThat(commandRevokedFailedEventCaptor.getValue().getSource()).isEqualTo(CommandTestFactory.ID);
+		}
+	}
 }
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemTestFactory.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemTestFactory.java
index 58bf4f855c2a2d04302354cdc898ca1e5afbde38..b0a8dbbf4dc0a6fe293e7e68d0d4b5b141be81b9 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemTestFactory.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/attached_item/VorgangAttachedItemTestFactory.java
@@ -40,25 +40,16 @@ public class VorgangAttachedItemTestFactory {
 	public static final long VERSION = 1L;
 
 	public static final String CLIENT = LoremIpsum.getInstance().getFirstName() + "Client";
-	public static final String ITEM_NAME = "test";
 
+	public static final String ITEM_NAME = "test";
 	public static final String ITEM_FIELD_NAME = "number";
 	public static final Integer ITEM_FIELD_INT_VALUE = 42;
 	public static final String ITEM_FIELD_STRING_VALUE = "73";
 
-	public static final String FIELD_NAME_VORGANG_ID = "vorgangId";
-	public static final String FIELD_NAME_VORGANG_VERSION = "vorgangVersion";
-	public static final String FIELD_NAME_CREATED_AT = "createdAt";
-	public static final String CREATED_BY_FIELD_NAME = "createdBy";
-	public static final String CREATED_BY_NAME_FIELD_NAME = "createdByName";
-	public static final String BETREFF_FIELD_NAME = "betreff";
-	public static final String BESCHREIBUNG_FIELD_NAME = "beschreibung";
-	public static final String ATTACHMENTS_FIELD_NAME = "attachments";
-
 	public static final FileId ATTACHMENT_ID = FileId.createNew();
 	static final List<FileId> ATTACHMENTS = List.of(ATTACHMENT_ID, ATTACHMENT_ID);
 
-	static final Map<String, Object> STRING_MAP = Map.of(ITEM_FIELD_NAME, ITEM_FIELD_STRING_VALUE);
+	public static final Map<String, Object> STRING_MAP = Map.of(ITEM_FIELD_NAME, ITEM_FIELD_STRING_VALUE);
 
 	public static VorgangAttachedItem create() {
 		return createBuilder().build();
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandEventListenerTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandEventListenerTest.java
index 153af77891fc1df9973ceb7aee9b90251fd32bc7..fe0a42a246cc4018afe82709c0da52cb3a6109cd 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandEventListenerTest.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandEventListenerTest.java
@@ -95,4 +95,5 @@ class CommandEventListenerTest {
 			verify(commandService).setCommandRevoked(CommandTestFactory.ID);
 		}
 	}
+
 }
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandITCase.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandITCase.java
index 5a6b4241e64b294b555226694b24e3d72bc97281..cbb89a295b4dde09f94322dc54cad4cf97f7c172 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandITCase.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandITCase.java
@@ -127,7 +127,7 @@ class CommandITCase {
 			var response = responseCaptor.getValue();
 
 			await().atMost(60, TimeUnit.SECONDS).untilAsserted(() -> {
-				var command = commandService.findCommand(response.getCommand().getId());
+				var command = commandService.findById(response.getCommand().getId());
 
 				assertThat(command).isPresent().get().satisfies(cmd -> {
 					assertThat(cmd.getId()).isNotNull();
@@ -309,7 +309,7 @@ class CommandITCase {
 				mongoOperations.dropCollection(Vorgang.class);
 				mongoOperations.save(VorgangTestFactory.createBuilder().status(Status.ANGENOMMEN).build());
 
-				mongoOperations.save(CommandTestFactory.createBuilder()
+				mongoOperations.save(CommandTestFactory.createBuilder().status(CommandStatus.FINISHED)
 						.relationId(VorgangTestFactory.ID).relationVersion(VorgangTestFactory.VERSION - 1)
 						.previousState(Map.of(Vorgang.MONGODB_FIELDNAME_STATUS, Status.NEU)).build());
 			}
@@ -369,7 +369,7 @@ class CommandITCase {
 			void persistVorgangWithVorgangVerwerfenCommand() {
 				mongoOperations.save(VorgangTestFactory.createBuilder().status(Status.VERWORFEN).build());
 
-				mongoOperations.save(CommandTestFactory.createBuilder().relationId(VorgangTestFactory.ID)
+				mongoOperations.save(CommandTestFactory.createBuilder().status(CommandStatus.FINISHED).relationId(VorgangTestFactory.ID)
 						.relationVersion(VorgangTestFactory.VERSION - 1).order(Order.VORGANG_VERWERFEN.toString())
 						.previousState(Map.of(Vorgang.MONGODB_FIELDNAME_STATUS, Status.IN_BEARBEITUNG))
 						.build());
@@ -380,7 +380,7 @@ class CommandITCase {
 				callServiceRevokeCommand();
 
 				await().atMost(60, TimeUnit.SECONDS).untilAsserted(() -> {
-					var command = commandService.findCommand(responseCaptor.getValue().getCommand().getId());
+					var command = commandService.findById(responseCaptor.getValue().getCommand().getId());
 
 					assertThat(command).isPresent().get().extracting(Command::getStatus).isEqualTo(CommandStatus.REVOKED);
 				});
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandRepositoryITCase.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandRepositoryITCase.java
index cebb7e89bf49c7a6b6e4f4e71df53c4ec6f22020..6f99e9b91bef7f1664e80194b2755173a0c1da37 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandRepositoryITCase.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandRepositoryITCase.java
@@ -105,7 +105,7 @@ class CommandRepositoryITCase {
 
 			repository.finishCommand(command.getId());
 
-			var result = repository.getById(command.getId());
+			var result = repository.findById(command.getId());
 			assertThat(result).isPresent().get().extracting(Command::getStatus).isEqualTo(CommandStatus.FINISHED);
 		}
 
@@ -117,7 +117,7 @@ class CommandRepositoryITCase {
 
 			repository.finishCommand(command.getId());
 
-			var result = repository.getById(command.getId());
+			var result = repository.findById(command.getId());
 			assertThat(result).isPresent().get().extracting(Command::getStatus).isEqualTo(commandStatus);
 		}
 
@@ -127,7 +127,7 @@ class CommandRepositoryITCase {
 
 			repository.finishCommand(command.getId());
 
-			var result = repository.getById(command.getId()).get();
+			var result = repository.findById(command.getId()).get();
 			assertThat(result.getFinishedAt()).isNotNull();
 		}
 
@@ -137,7 +137,7 @@ class CommandRepositoryITCase {
 
 			repository.finishCommand(command.getId(), CommandTestFactory.CREATED_RESOURCE);
 
-			var result = repository.getById(command.getId()).get();
+			var result = repository.findById(command.getId()).get();
 			assertThat(result.getStatus()).isEqualTo(CommandStatus.FINISHED);
 		}
 
@@ -147,7 +147,7 @@ class CommandRepositoryITCase {
 
 			repository.finishCommand(command.getId(), CommandTestFactory.CREATED_RESOURCE);
 
-			var result = repository.getById(command.getId()).get();
+			var result = repository.findById(command.getId()).get();
 			assertThat(result.getFinishedAt()).isNotNull();
 		}
 
@@ -159,7 +159,7 @@ class CommandRepositoryITCase {
 
 			repository.finishCommand(savedCommand.getId(), CommandTestFactory.CREATED_RESOURCE);
 
-			var result = repository.getById(savedCommand.getId()).get();
+			var result = repository.findById(savedCommand.getId()).get();
 			assertThat(result.getCreatedResource()).isEqualTo(CommandTestFactory.CREATED_RESOURCE);
 		}
 
@@ -170,7 +170,7 @@ class CommandRepositoryITCase {
 
 			repository.finishCommand(savedCommand.getId(), CommandTestFactory.CREATED_RESOURCE);
 
-			var result = repository.getById(savedCommand.getId()).get();
+			var result = repository.findById(savedCommand.getId()).get();
 			assertThat(result.getCreatedResource()).isEqualTo(CommandTestFactory.CREATED_RESOURCE);
 		}
 	}
@@ -198,7 +198,7 @@ class CommandRepositoryITCase {
 		}
 
 		private void verifyCommandExists(String id) {
-			Optional<Command> command = repository.getById(id);
+			Optional<Command> command = repository.findById(id);
 
 			assertThat(command).isPresent();
 			assertThat(command.get().getId()).isEqualTo(id);
@@ -218,7 +218,7 @@ class CommandRepositoryITCase {
 		void shouldUpdateCommandStatus(CommandStatus status) {
 			repository.updateCommandStatus(CommandTestFactory.ID, status);
 
-			Optional<Command> command = repository.getById(CommandTestFactory.ID);
+			Optional<Command> command = repository.findById(CommandTestFactory.ID);
 
 			assertThat(command).isPresent();
 			assertThat(command.get().getStatus()).isEqualTo(status);
@@ -238,7 +238,7 @@ class CommandRepositoryITCase {
 		void shouldUpdateCommandStatus(CommandStatus status) {
 			repository.updateCommandStatusAndVersion(CommandTestFactory.ID, status, 78L);
 
-			Optional<Command> command = repository.getById(CommandTestFactory.ID);
+			Optional<Command> command = repository.findById(CommandTestFactory.ID);
 
 			assertThat(command).isPresent();
 			assertThat(command.get().getRelationVersion()).isEqualTo(78L);
@@ -246,6 +246,31 @@ class CommandRepositoryITCase {
 		}
 	}
 
+	@Nested
+	class TestUpdateCommandStatusAndReturnPrevious {
+
+		@BeforeEach
+		void persistVorgangWithCommand() {
+			repository.save(CommandTestFactory.create());
+		}
+
+		@Test
+		void shouldUpdateStatus() {
+			repository.updateCommandStatusAndReturnPrevious(CommandTestFactory.ID, CommandStatus.ERROR);
+
+			var command = mongoOperations.findById(CommandTestFactory.ID, Command.class);
+			assertThat(command.getStatus()).isEqualTo(CommandStatus.ERROR);
+		}
+
+		@Test
+		void shouldReturnPreviousCommand() {
+			Command previousCommand = repository.updateCommandStatusAndReturnPrevious(CommandTestFactory.ID, CommandStatus.ERROR);
+
+			assertThat(previousCommand.getStatus()).isEqualTo(CommandStatus.PENDING);
+		}
+
+	}
+
 	@Nested
 	class TestGetPendingCommands {
 
@@ -297,7 +322,7 @@ class CommandRepositoryITCase {
 			}
 
 			@Test
-				// TODO schreibe ein Testcase für Order, Status und Zeit
+			// TODO schreibe ein Testcase für Order, Status und Zeit
 			void shouldFindCommand() {
 				var command = repository.save(createCommandBuilder()
 						.status(CommandStatus.FINISHED)
@@ -330,7 +355,7 @@ class CommandRepositoryITCase {
 		void shouldSavePreviousStateValue() {
 			repository.patch(command.getId(), Map.of(PREVIOUS_STATE_STATUS_FIELD_KEY, PREVIOUS_STATE_STATUS_VALUE));
 
-			var persitedCommand = repository.getById(command.getId());
+			var persitedCommand = repository.findById(command.getId());
 
 			assertThat(persitedCommand).isPresent().get()
 					.extracting(command -> ((PersistedCommand) command).getPreviousState(), as(InstanceOfAssertFactories.MAP))
@@ -409,7 +434,7 @@ class CommandRepositoryITCase {
 
 			repository.addSubCommands(commandId, Map.of("addedKey", "addedValue"));
 
-			var result = repository.getById(commandId);
+			var result = repository.findById(commandId);
 			assertThat(result).isPresent().get().extracting(Command::getBodyObject, as(InstanceOfAssertFactories.MAP))
 					.containsAllEntriesOf(expectedMap);
 		}
@@ -417,7 +442,7 @@ class CommandRepositoryITCase {
 	}
 
 	@Nested
-	class TestGetNotFailedParentId {
+	class TestIsCommandFailed {
 
 		@BeforeEach
 		void init() {
@@ -426,28 +451,22 @@ class CommandRepositoryITCase {
 
 		@Test
 		void shouldReturnParentId() {
-			var parentId = mongoOperations.save(CommandTestFactory.createBuilder().bodyObject(Map.of(
+			var commandId = mongoOperations.save(CommandTestFactory.createBuilder().bodyObject(Map.of(
 					PersistedCommand.PROPERTY_COMPLETE_IF_SUBS_COMPLETED, true)).build()).getId();
-			var commandId = mongoOperations.save(
-							CommandTestFactory.createBuilder().id(null).bodyObject(Map.of(PersistedCommand.PROPERTY_PARENT_ID, parentId)).build())
-					.getId();
 
-			var result = repository.getNotFailedParentId(commandId);
+			var result = repository.isCommandFailed(commandId);
 
-			assertThat(result).contains(parentId);
+			assertThat(result).isFalse();
 		}
 
 		@Test
 		void shouldReturnEmpty() {
-			var parentId = mongoOperations.save(CommandTestFactory.createBuilder().status(CommandStatus.ERROR).bodyObject(Map.of(
+			var commandId = mongoOperations.save(CommandTestFactory.createBuilder().status(CommandStatus.ERROR).bodyObject(Map.of(
 					PersistedCommand.PROPERTY_COMPLETE_IF_SUBS_COMPLETED, true)).build()).getId();
-			var commandId = mongoOperations.save(
-							CommandTestFactory.createBuilder().id(null).bodyObject(Map.of(PersistedCommand.PROPERTY_PARENT_ID, parentId)).build())
-					.getId();
 
-			var result = repository.getNotFailedParentId(commandId);
+			var result = repository.isCommandFailed(commandId);
 
-			assertThat(result).isEmpty();
+			assertThat(result).isTrue();
 		}
 	}
 
@@ -464,7 +483,7 @@ class CommandRepositoryITCase {
 		@Test
 		void shouldReturnParentId() {
 			var commandId = mongoOperations.save(
-							CommandTestFactory.createBuilder().id(null).bodyObject(Map.of(PersistedCommand.PROPERTY_PARENT_ID, PARENT_ID)).build())
+					CommandTestFactory.createBuilder().id(null).bodyObject(Map.of(PersistedCommand.PROPERTY_PARENT_ID, PARENT_ID)).build())
 					.getId();
 
 			var parentId = repository.getParentId(commandId);
@@ -562,8 +581,8 @@ class CommandRepositoryITCase {
 
 		private static final String PARENT_ID = "parent-id";
 
-		private final PersistedCommandBuilder commandWithParentIdBuilder = CommandTestFactory.createBuilder().id(null).bodyObject(Map.of(
-				PersistedCommand.PROPERTY_PARENT_ID, PARENT_ID));
+		private static final Command COMMAND_WITH_PARENT_ID = CommandTestFactory.createBuilder().id(null).bodyObject(Map.of(
+				PersistedCommand.PROPERTY_PARENT_ID, PARENT_ID)).build();
 
 		@BeforeEach
 		void init() {
@@ -571,32 +590,108 @@ class CommandRepositoryITCase {
 		}
 
 		@Test
-		void shouldIgnoreErrorStatus() {
-			mongoOperations.save(commandWithParentIdBuilder.status(CommandStatus.ERROR).build());
+		void shouldFindSubCommandIds() {
+			var commandId = mongoOperations.save(COMMAND_WITH_PARENT_ID).getId();
 
-			var result = repository.findNotFailedSubCommandIds(PARENT_ID);
+			var result = repository.findSubCommandIds(PARENT_ID);
+
+			assertThat(result).hasSize(1).first().isEqualTo(commandId);
+		}
+
+		@Test
+		void shouldReturnEmpty() {
+			mongoOperations.save(COMMAND_WITH_PARENT_ID);
+
+			var result = repository.findSubCommandIds("other-parent-id");
 
 			assertThat(result).isEmpty();
 		}
+	}
 
-		@DisplayName("should find commands")
-		@ParameterizedTest(name = "with status {0}")
-		@EnumSource(value = CommandStatus.class, names = { "ERROR" }, mode = EnumSource.Mode.EXCLUDE)
-		void shouldFindCommands(CommandStatus status) {
-			mongoOperations.save(commandWithParentIdBuilder.status(status).build());
+	@Nested
+	class TestSetRevokeStatus {
 
-			var result = repository.findNotFailedSubCommandIds(PARENT_ID);
+		@Test
+		void shouldSetCanceled() {
+			var command = mongoOperations.save(CommandTestFactory.createBuilder().id(null).status(CommandStatus.NEW).build());
 
-			assertThat(result).hasSize(1);
+			repository.setRevokeStatus(command.getId());
+
+			var result = repository.findById(command.getId());
+			assertThat(result).isPresent().get().extracting(Command::getStatus).isEqualTo(CommandStatus.CANCELED);
 		}
 
 		@Test
-		void shouldReturnEmpty() {
-			mongoOperations.save(commandWithParentIdBuilder.build());
+		void shouldSetRevokePendingWhenPending() {
+			var command = mongoOperations.save(CommandTestFactory.createBuilder().id(null).build());
 
-			var result = repository.findNotFailedSubCommandIds("other-parent-id");
+			repository.setRevokeStatus(command.getId());
 
-			assertThat(result).isEmpty();
+			var result = repository.findById(command.getId());
+			assertThat(result).isPresent().get().extracting(Command::getStatus).isEqualTo(CommandStatus.REVOKE_PENDING);
+		}
+
+		@Test
+		void shouldSetRevokePendingWhenFinished() {
+			var command = mongoOperations.save(CommandTestFactory.createBuilder().id(null).status(CommandStatus.FINISHED).build());
+
+			repository.setRevokeStatus(command.getId());
+
+			var result = repository.findById(command.getId());
+			assertThat(result).isPresent().get().extracting(Command::getStatus).isEqualTo(CommandStatus.REVOKE_PENDING);
+		}
+
+		@DisplayName("should not update when")
+		@ParameterizedTest(name = "status is {0}")
+		@EnumSource(value = CommandStatus.class, names = { "NEW", "PENDING", "FINISHED" }, mode = EnumSource.Mode.EXCLUDE)
+		void shouldNotUpdate(CommandStatus status) {
+			var command = mongoOperations.save(CommandTestFactory.createBuilder().id(null).status(status).build());
+
+			repository.setRevokeStatus(command.getId());
+
+			var result = repository.findById(command.getId());
+			assertThat(result).isPresent().get().extracting(Command::getStatus).isEqualTo(status);
+		}
+	}
+
+	@Nested
+	class TestSetRevokeStatusIfNotPending {
+
+		@Test
+		void shouldSetCanceled() {
+			var command = createCommand(CommandStatus.NEW);
+
+			repository.setRevokeStatusIfNotPending(command.getId());
+
+			assertThat(getCommandStatus(command)).isEqualTo(CommandStatus.CANCELED);
+		}
+
+		@Test
+		void shouldSetRevokePendingWhenFinished() {
+			var command = createCommand(CommandStatus.FINISHED);
+
+			repository.setRevokeStatusIfNotPending(command.getId());
+
+			assertThat(getCommandStatus(command)).isEqualTo(CommandStatus.REVOKE_PENDING);
+		}
+
+		@DisplayName("should not update when")
+		@ParameterizedTest(name = "status is {0}")
+		@EnumSource(value = CommandStatus.class, names = { "NEW", "FINISHED" }, mode = EnumSource.Mode.EXCLUDE)
+		void shouldNotUpdate(CommandStatus status) {
+			var command = createCommand(status);
+
+			repository.setRevokeStatusIfNotPending(command.getId());
+
+			assertThat(getCommandStatus(command)).isEqualTo(status);
+		}
+
+		private Command createCommand(CommandStatus status) {
+			return mongoOperations.save(CommandTestFactory.createBuilder().id(null).status(status).build());
+		}
+
+		private CommandStatus getCommandStatus(Command command) {
+			return mongoOperations.findById(command.getId(), Command.class).getStatus();
 		}
 	}
 }
\ No newline at end of file
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandRevokedEventTestFactory.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandRevokedEventTestFactory.java
index a54027a07cd0861344dfb06b26026d7a2123e208..526d0a592966588a4a52d33b38ccb9bd783b5b93 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandRevokedEventTestFactory.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandRevokedEventTestFactory.java
@@ -4,6 +4,7 @@ import de.ozgcloud.command.Command;
 import de.ozgcloud.command.CommandRevokedEvent;
 
 public class CommandRevokedEventTestFactory {
+
 	public static CommandRevokedEvent create(Command command) {
 		return new CommandRevokedEvent(command);
 	}
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandServiceITCase.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandServiceITCase.java
index 5a051d3cc4b06c4afecacc3fff00e08e5e0fc554..36429601be30bae6182023940b10249ba1bd6a6f 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandServiceITCase.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandServiceITCase.java
@@ -24,10 +24,14 @@
 package de.ozgcloud.vorgang.command;
 
 import static org.assertj.core.api.Assertions.*;
+import static org.awaitility.Awaitility.*;
+import static org.mockito.ArgumentMatchers.*;
 import static org.mockito.Mockito.*;
 
+import java.util.Map;
 import java.util.Optional;
 import java.util.UUID;
+import java.util.concurrent.TimeUnit;
 
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Nested;
@@ -75,15 +79,12 @@ class CommandServiceITCase {
 
 		@Test
 		void persistCommand() {
-			Command persistedCommand = commandService.saveCommand(
+			var persistedCommand = commandService.saveCommand(
 					CommandTestFactory.createBuilder()
 							.relationId(CommandTestFactory.RELATION_ID)
 							.relationVersion(CommandTestFactory.RELATION_VERSION).build());
 
-			Optional<Command> commandOpt = commandService.findCommand(persistedCommand.getId());
-			assertThat(commandOpt).isPresent();
-
-			Command command = commandOpt.get();
+			var command = commandService.getById(persistedCommand.getId());
 			assertThat(command.getId()).hasSize(36);
 			assertThat(command.getCreatedAt()).isNotNull();
 			assertThat(command.getStatus()).isEqualTo(CommandStatus.PENDING);
@@ -92,36 +93,37 @@ class CommandServiceITCase {
 
 		@Test
 		void persistCommandHappyPath() {
-			CreateCommandRequest request = CreateCommandRequestTestFactory
+			var request = CreateCommandRequestTestFactory
 					.createBuilder()
 					.relationId(CommandTestFactory.RELATION_ID)
 					.relationVersion(CommandTestFactory.RELATION_VERSION)
 					.build();
 
-			Command persistedCommand = commandService.createCommand(request);
-			verify(commandService, timeout(60000)).setCommandFinished(eq(persistedCommand.getId()), any());
-
-			Optional<Command> commandOpt = commandService.findCommand(persistedCommand.getId());
-			assertThat(commandOpt).isPresent();
-
-			Command command = commandOpt.get();
-			assertThat(command.getId()).hasSize(36);
-			assertThat(command.getCreatedAt()).isNotNull();
-			assertThat(command.getCreatedBy()).isEqualTo(request.getCallContext().getUser().getId());
-			assertThat(command.getStatus()).isEqualTo(CommandStatus.FINISHED);
-			assertThat(command.getRelationId()).isEqualTo(CommandTestFactory.RELATION_ID);
+			var persistedCommand = commandService.createCommand(request);
+
+			await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> {
+				verify(commandService).setCommandFinished(eq(persistedCommand.getId()), any());
+				var command = commandService.getById(persistedCommand.getId());
+				assertThat(command.getId()).hasSize(36);
+				assertThat(command.getCreatedAt()).isNotNull();
+				assertThat(command.getCreatedBy()).isEqualTo(request.getCallContext().getUser().getId());
+				assertThat(command.getStatus()).isEqualTo(CommandStatus.FINISHED);
+				assertThat(command.getRelationId()).isEqualTo(CommandTestFactory.RELATION_ID);
+			});
 		}
 	}
 
 	@Nested
 	class TestVorgangCommandFinished {
 
+		private Vorgang vorgang;
+
 		@BeforeEach
 		void persistVorgang() {
 			mongoOperations.dropCollection(Vorgang.class);
 			mongoOperations.dropCollection(Command.class);
 
-			mongoOperations.save(VorgangTestFactory.create());
+			vorgang = mongoOperations.save(VorgangTestFactory.create());
 			mongoOperations.save(CommandTestFactory.createBuilder().relationId(VorgangTestFactory.ID).build());
 		}
 
@@ -129,7 +131,7 @@ class CommandServiceITCase {
 		void setCommandFinishedHappyPath() {
 			commandService.setCommandFinished(CommandTestFactory.ID);
 
-			Command command = mongoOperations.findById(CommandTestFactory.ID, Command.class);
+			var command = mongoOperations.findById(CommandTestFactory.ID, Command.class);
 
 			assertThat(command.getId()).hasSize(36);
 			assertThat(command.getCreatedAt()).isNotNull();
@@ -137,6 +139,37 @@ class CommandServiceITCase {
 			assertThat(command.getStatus()).isEqualTo(CommandStatus.FINISHED);
 			assertThat(command.getRelationId()).isEqualTo(VorgangTestFactory.ID);
 		}
+
+		@Test
+		void shouldRevokeFinishedCommand() {
+			var commandId = saveSubCommandWithFailedParent();
+
+			commandService.setCommandFinished(commandId);
+
+			await().atMost(60, TimeUnit.SECONDS).untilAsserted(() -> {
+				var commandStatus = mongoOperations.findById(commandId, Command.class).getStatus();
+				assertThat(commandStatus).isEqualTo(CommandStatus.REVOKED);
+			});
+		}
+
+		private String saveSubCommandWithFailedParent() {
+			var parentId = mongoOperations.save(createFailedParentCommand()).getId();
+			return mongoOperations.save(createSubCommand(parentId)).getId();
+		}
+
+		private Command createFailedParentCommand() {
+			return CommandTestFactory.createBuilder().id(null).status(CommandStatus.ERROR)
+					.bodyObject(Map.of(
+							PersistedCommand.PROPERTY_EXECUTION_MODE, SubCommandExecutionMode.PARALLEL.name(),
+							PersistedCommand.PROPERTY_COMPLETE_IF_SUBS_COMPLETED, true
+					)).build();
+		}
+
+		private Command createSubCommand(String parentId) {
+			return CommandTestFactory.createBuilder().id(null).vorgangId(vorgang.getId())
+					.previousState(Map.of(CommandRepository.MONGODB_STATUS, Vorgang.Status.NEU.name()))
+					.bodyObject(Map.of(PersistedCommand.PROPERTY_PARENT_ID, parentId)).build();
+		}
 	}
 
 	@Nested
@@ -161,7 +194,7 @@ class CommandServiceITCase {
 
 		@Test
 		void shouldReturnCommand1() {
-			Optional<Command> command = commandService.findCommand(command1.getId());
+			Optional<Command> command = commandService.findById(command1.getId());
 
 			assertThat(command).isPresent();
 			assertThat(command.get().getId()).isEqualTo(command1.getId());
@@ -173,7 +206,7 @@ class CommandServiceITCase {
 
 		@Test
 		void shouldReturnCommand2() {
-			Optional<Command> command = commandService.findCommand(command2.getId());
+			Optional<Command> command = commandService.findById(command2.getId());
 
 			assertThat(command).isPresent();
 			assertThat(command.get().getId()).isEqualTo(command2.getId());
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandServiceTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandServiceTest.java
index b34413c437df90ab5766b7421d7a527dd81c8319..85714d30f81e92ba77ce0c7f575e89dcc04343fa 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandServiceTest.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandServiceTest.java
@@ -39,6 +39,8 @@ 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.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.EnumSource;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Captor;
 import org.mockito.InjectMocks;
@@ -48,7 +50,6 @@ import org.springframework.context.ApplicationEventPublisher;
 
 import de.ozgcloud.command.Command;
 import de.ozgcloud.command.CommandExecutedEvent;
-import de.ozgcloud.command.CommandFailedEvent;
 import de.ozgcloud.command.CommandStatus;
 import de.ozgcloud.command.RevokeCommandEvent;
 import de.ozgcloud.common.errorhandling.TechnicalException;
@@ -57,6 +58,7 @@ import de.ozgcloud.vorgang.callcontext.CallContextUserTestFactory;
 import de.ozgcloud.vorgang.callcontext.CurrentUserService;
 import de.ozgcloud.vorgang.callcontext.UserTestFactory;
 import de.ozgcloud.vorgang.common.errorhandling.NotFoundException;
+import de.ozgcloud.vorgang.common.errorhandling.RevokeFailedException;
 import de.ozgcloud.vorgang.vorgang.VorgangTestFactory;
 
 class CommandServiceTest {
@@ -162,19 +164,19 @@ class CommandServiceTest {
 
 		@BeforeEach
 		void mockOperationRepository() {
-			when(repository.getById(any())).thenReturn(Optional.of(CommandTestFactory.create()));
+			when(repository.findById(any())).thenReturn(Optional.of(CommandTestFactory.create()));
 		}
 
 		@Test
 		void shouldCallOperationRepository() {
-			service.findCommand(commandId);
+			service.findById(commandId);
 
-			verify(repository).getById(any());
+			verify(repository).findById(any());
 		}
 
 		@Test
 		void shouldReturnCommand() {
-			Optional<Command> command = service.findCommand(commandId);
+			Optional<Command> command = service.findById(commandId);
 
 			assertThat(command).isPresent();
 			assertThat(command.get().getId()).isEqualTo(commandId);
@@ -203,119 +205,304 @@ class CommandServiceTest {
 	class TestSetCommandFinished {
 
 		@Test
-		void shouldCallFinishCommand() {
-			service.setCommandFinished(CommandTestFactory.ID);
+		void shouldThrowExceptionIfCommandNotFound() {
+			doThrow(NotFoundException.class).when(service).getById(anyString());
 
-			verify(service).setCommandFinished(CommandTestFactory.ID, null);
+			assertThrows(NotFoundException.class, () -> service.setCommandFinished(CommandTestFactory.ID));
 		}
 
-		@Test
-		void shouldCallRepositoryFinishCommand() {
-			service.setCommandFinished(CommandTestFactory.ID, null);
+		@Nested
+		class TestRevokePendingCommand {
+
+			private static final Command REVOKE_PENDING_COMMAND = CommandTestFactory.createBuilder().status(CommandStatus.REVOKE_PENDING).build();
+
+			@BeforeEach
+			void init() {
+				doReturn(true).when(service).shouldRevoke(any());
+				doReturn(REVOKE_PENDING_COMMAND).when(service).getById(anyString());
+			}
+
+			@Test
+			void shouldCallIsRevokeCommand() {
+				setCommandFinished();
+
+				verify(service).shouldRevoke(REVOKE_PENDING_COMMAND);
+			}
+
+			@Test
+			void shouldCallRepository() {
+				setCommandFinished();
+
+				verify(repository).setRevokeStatus(CommandTestFactory.ID);
+			}
+
+			@Test
+			void shouldCallPublishRevokeCommandEvent() {
+				setCommandFinished();
+
+				verify(service).publishRevokeCommandEvent(REVOKE_PENDING_COMMAND);
+			}
+
+			@Test
+			void shouldNotCallFinishCommandIfRevokePending() {
+				setCommandFinished();
+
+				verify(repository, never()).finishCommand(anyString());
+				verify(repository, never()).finishCommand(anyString(), anyString());
+			}
 
-			verify(repository).finishCommand(CommandTestFactory.ID);
+			void setCommandFinished() {
+				service.setCommandFinished(CommandTestFactory.ID, CommandTestFactory.CREATED_RESOURCE);
+			}
 		}
 
-		@Test
-		void shouldCallRepositoryFinishCommandWithCreatedResource() {
-			service.setCommandFinished(CommandTestFactory.ID, CommandTestFactory.CREATED_RESOURCE);
+		@Nested
+		class TestFinishCommand {
+
+			private static final Command FINISHED_COMMAND = CommandTestFactory.createBuilder().status(CommandStatus.FINISHED).build();
+
+			@BeforeEach
+			void init() {
+				doReturn(false).when(service).isParentCommandFailed(any());
+				doReturn(FINISHED_COMMAND).when(service).getById(anyString());
+			}
+
+			@Test
+			void shouldCallSetCommandFinish() {
+				service.setCommandFinished(CommandTestFactory.ID);
 
-			verify(repository).finishCommand(CommandTestFactory.ID, CommandTestFactory.CREATED_RESOURCE);
+				verify(service).setCommandFinished(CommandTestFactory.ID, null);
+			}
+
+			@Test
+			void shouldCallGetCommand() {
+				setCommandFinished();
+
+				verify(service).getById(CommandTestFactory.ID);
+			}
+
+			@Test
+			void shouldCallRepositoryFinishCommand() {
+				service.setCommandFinished(CommandTestFactory.ID, null);
+
+				verify(repository).finishCommand(CommandTestFactory.ID);
+			}
+
+			@Test
+			void shouldCallRepositoryFinishCommandWithCreatedResource() {
+				setCommandFinished();
+
+				verify(repository).finishCommand(CommandTestFactory.ID, CommandTestFactory.CREATED_RESOURCE);
+			}
+
+			@Test
+			void shouldCallGetCompletableParentId() {
+				setCommandFinished();
+
+				verify(service).getCompletableParentId(FINISHED_COMMAND);
+			}
+
+			@Test
+			void shouldCallPublishCommandExecutedEvent() {
+				var parentId = "parent-id";
+				doReturn(Optional.of(parentId)).when(service).getCompletableParentId(any());
+
+				setCommandFinished();
+
+				verify(service).publishCommandExecutedEvent(parentId);
+			}
+
+			@DisplayName("should not call publishCommandExecutedEvent when no completable parent id")
+			@Test
+			void shouldNotPublishWhenNoParentId() {
+				doReturn(Optional.empty()).when(service).getCompletableParentId(any());
+
+				setCommandFinished();
+
+				verify(service, never()).publishCommandExecutedEvent(anyString());
+			}
+
+			void setCommandFinished() {
+				service.setCommandFinished(CommandTestFactory.ID, CommandTestFactory.CREATED_RESOURCE);
+			}
 		}
+	}
+
+	@Nested
+	class TestShouldRevoke {
 
 		@Test
-		void shouldCallGetCompletableParentId() {
-			service.setCommandFinished(CommandTestFactory.ID);
+		void shouldReturnTrueWhenRevokePending() {
+			var command = CommandTestFactory.createBuilder().status(CommandStatus.REVOKE_PENDING).build();
 
-			verify(service).getCompletableParentId(CommandTestFactory.ID);
+			var result = service.shouldRevoke(command);
+
+			assertThat(result).isTrue();
 		}
 
 		@Test
-		void shouldCallExistsNotFinishedSubCommands() {
-			var parentId = "parent-id";
-			doReturn(Optional.of(parentId)).when(service).getCompletableParentId(any());
+		void shouldRevokeTrueWhenParentFailed() {
+			doReturn(true).when(service).isParentCommandFailed(any());
 
-			service.setCommandFinished(CommandTestFactory.ID, CommandTestFactory.CREATED_RESOURCE);
+			var result = service.shouldRevoke(CommandTestFactory.create());
 
-			verify(repository).existsNotFinishedSubCommands(parentId);
+			assertThat(result).isTrue();
 		}
+	}
+
+	@Nested
+	class TestIsParentCommandFailed {
 
 		@Test
-		void shouldCallPublishCommandExecutedEvent() {
-			var parentId = "parent-id";
-			doReturn(Optional.of(parentId)).when(service).getCompletableParentId(any());
+		void shouldCallGetParentId() {
+			var command = CommandTestFactory.create();
 
-			service.setCommandFinished(CommandTestFactory.ID, CommandTestFactory.CREATED_RESOURCE);
+			service.isParentCommandFailed(command);
 
-			verify(service).publishCommandExecutedEvent(parentId);
+			verify(service).getParentId(command);
 		}
 
-		@DisplayName("should not call publishCommandExecutedEvent when no parent id")
 		@Test
-		void shouldNotCallPublishCommandExecutedEvent() {
-			doReturn(Optional.empty()).when(service).getCompletableParentId(any());
+		void shouldReturnFalseWhenParentMissing() {
+			doReturn(Optional.empty()).when(service).getParentId(any());
 
-			service.setCommandFinished(CommandTestFactory.ID, CommandTestFactory.CREATED_RESOURCE);
+			var result = isParentCommandFailed();
 
-			verify(service, never()).publishCommandExecutedEvent(anyString());
+			assertThat(result).isFalse();
 		}
 
-		@DisplayName("should not call publishCommandExecutedEvent when not all subcommands are finished")
-		@Test
-		void shouldNotCallPublishCommandExecutedEvent1() {
-			var parentId = "parent-id";
-			doReturn(Optional.of(parentId)).when(service).getCompletableParentId(any());
-			when(repository.existsNotFinishedSubCommands(any())).thenReturn(true);
+		@Nested
+		class TestWithParent {
+
+			private static final String PARENT_ID = "parent-id";
+
+			@BeforeEach
+			void init() {
+				doReturn(Optional.of(PARENT_ID)).when(service).getParentId(any());
+			}
 
-			service.setCommandFinished(CommandTestFactory.ID, CommandTestFactory.CREATED_RESOURCE);
+			@Test
+			void shouldCallRepository() {
+				isParentCommandFailed();
+
+				verify(repository).isCommandFailed(PARENT_ID);
+			}
+
+			@Test
+			void shouldReturnTrueWhenParentNotFailed() {
+				when(repository.isCommandFailed(any())).thenReturn(true);
+
+				var result = isParentCommandFailed();
+
+				assertThat(result).isTrue();
+			}
 
-			verify(service, never()).publishCommandExecutedEvent(anyString());
+			@Test
+			void shouldReturnFalseWhenParentFailed() {
+				var result = isParentCommandFailed();
+
+				assertThat(result).isFalse();
+			}
+		}
+
+		boolean isParentCommandFailed() {
+			return service.isParentCommandFailed(CommandTestFactory.create());
 		}
 	}
 
 	@Nested
 	class TestGetCompletableParentId {
 
+		private static final Command COMMAND = CommandTestFactory.create();
+
 		@Test
-		void shouldGetParentId() {
-			service.getCompletableParentId(CommandTestFactory.ID);
+		void shouldCallGetParentId() {
+			service.getCompletableParentId(COMMAND);
 
-			verify(repository).getParentId(CommandTestFactory.ID);
+			verify(service).getParentId(COMMAND);
 		}
 
 		@Test
-		void shouldFilterIfParentCompletableBySubCommands() {
-			var expectedParentId = "parent-id";
-			when(repository.getParentId(anyString())).thenReturn(Optional.of(expectedParentId));
+		void shouldReturnEmptyWhenNoParentId() {
+			doReturn(Optional.empty()).when(service).getParentId(any());
+
+			var result = service.getCompletableParentId(COMMAND);
+
+			assertThat(result).isEmpty();
+		}
+
+		@Nested
+		class TestCompleteIfSubsCompleted {
+
+			private static final String PARENT_ID = "parent-id";
+
+			@BeforeEach
+			void init() {
+				doReturn(Optional.of(PARENT_ID)).when(service).getParentId(any());
+			}
+
+			@Test
+			void shouldCallIsCompleteIfSubsCompleted() {
+				service.getCompletableParentId(COMMAND);
+
+				verify(repository).isCompleteIfSubsCompleted(PARENT_ID);
+			}
+
+			@Test
+			void shouldCallExistsNotFinishedSubCommands() {
+				when(repository.isCompleteIfSubsCompleted(anyString())).thenReturn(true);
+
+				service.getCompletableParentId(COMMAND);
+
+				verify(repository).existsNotFinishedSubCommands(PARENT_ID);
+			}
 
-			service.getCompletableParentId(CommandTestFactory.ID);
+			@Test
+			void shouldReturnParentId() {
+				when(repository.isCompleteIfSubsCompleted(anyString())).thenReturn(true);
+
+				var result = service.getCompletableParentId(COMMAND);
+
+				assertThat(result).contains(PARENT_ID);
+			}
 
-			verify(repository).isCompleteIfSubsCompleted(expectedParentId);
+			@Test
+			void shouldReturnEmptyWhenNotCompletableBySubCommands() {
+				var result = service.getCompletableParentId(COMMAND);
+
+				assertThat(result).isEmpty();
+			}
 		}
 
+	}
+
+	@Nested
+	class TestGetParentId {
+
 		@Test
-		void shouldReturnParentId() {
-			var expectedParentId = "parent-id";
-			doReturn(Optional.of(expectedParentId)).when(repository).getParentId(anyString());
-			when(repository.isCompleteIfSubsCompleted(anyString())).thenReturn(true);
+		void shouldReturnResult() {
+			var parentId = "parent-id";
+			var command = CommandTestFactory.createBuilder().bodyObject(Map.of(PersistedCommand.PROPERTY_PARENT_ID, parentId)).build();
 
-			var result = service.getCompletableParentId(CommandTestFactory.ID);
+			var result = service.getParentId(command);
 
-			assertThat(result).contains(expectedParentId);
+			assertThat(result).contains(parentId);
 		}
 
 		@Test
-		void shouldReturnEmptyWhenNoParentId() {
-			var result = service.getCompletableParentId(CommandTestFactory.ID);
+		void shouldReturnEmptyWhenNoBodyObject() {
+			var command = CommandTestFactory.createBuilder().bodyObject(null).build();
+
+			var result = service.getParentId(command);
 
 			assertThat(result).isEmpty();
 		}
 
 		@Test
-		void shouldReturnEmptyWhenNotCompletableBySubCommands() {
-			doReturn(Optional.of("parent-id")).when(repository).getParentId(anyString());
+		void shouldReturnEmptyWhenNoParentId() {
+			var command = CommandTestFactory.createBuilder().bodyObject(Map.of()).build();
 
-			var result = service.getCompletableParentId(CommandTestFactory.ID);
+			var result = service.getParentId(command);
 
 			assertThat(result).isEmpty();
 		}
@@ -331,13 +518,13 @@ class CommandServiceTest {
 		void shouldCallFindCommand() {
 			service.publishCommandExecutedEvent(CommandTestFactory.ID);
 
-			verify(service).findCommand(CommandTestFactory.ID);
+			verify(service).findById(CommandTestFactory.ID);
 		}
 
 		@Test
 		void shouldCallPublishMethod() {
 			var expectedCommand = CommandTestFactory.create();
-			doReturn(Optional.of(expectedCommand)).when(service).findCommand(anyString());
+			doReturn(Optional.of(expectedCommand)).when(service).findById(anyString());
 
 			service.publishCommandExecutedEvent(CommandTestFactory.ID);
 
@@ -351,111 +538,171 @@ class CommandServiceTest {
 	class TestSetCommandError {
 
 		private static final String ERROR_MESSAGE = "error message";
-
-		@Captor
-		private ArgumentCaptor<CommandFailedEvent> eventCaptor;
+		private static final String PARENT_ID = "parent-id";
 
 		@Test
-		void shouldCallRepository() {
+		void shouldCallRepositorySetErrorMessage() {
 			service.setCommandError(CommandTestFactory.ID, ERROR_MESSAGE);
 
 			verify(repository).setErrorMessage(CommandTestFactory.ID, ERROR_MESSAGE);
 		}
 
 		@Test
-		void shouldCallFindNotFailedSubCommandIds() {
+		void shouldCallRepositoryGetParentId() {
 			service.setCommandError(CommandTestFactory.ID, ERROR_MESSAGE);
 
-			verify(repository).findNotFailedSubCommandIds(CommandTestFactory.ID);
+			verify(repository).getParentId(CommandTestFactory.ID);
 		}
 
-		@Test
-		void shouldPublishCommandFailedEvent() {
-			var notFailedCommandId = "not-failed-command-id";
-			when(repository.findNotFailedSubCommandIds(anyString())).thenReturn(Stream.of(notFailedCommandId));
+		@Nested
+		class TestFailParentAndRevokeSubCommands {
 
-			service.setCommandError(CommandTestFactory.ID, ERROR_MESSAGE);
+			private static final Command COMMAND_BEFORE_SET_ERROR_STATUS = CommandTestFactory.createBuilder().id(PARENT_ID).build();
 
-			verify(publisher).publishEvent(eventCaptor.capture());
-			assertThat(eventCaptor.getValue().getSource()).isEqualTo(notFailedCommandId);
+			@BeforeEach
+			void init() {
+				when(repository.getParentId(anyString())).thenReturn(Optional.of(PARENT_ID));
+				doReturn(COMMAND_BEFORE_SET_ERROR_STATUS).when(service).setErrorStatus(anyString());
+			}
+
+			@Test
+			void shouldCallSetErrorStatus() {
+				service.setCommandError(CommandTestFactory.ID, ERROR_MESSAGE);
+
+				verify(service).setErrorStatus(PARENT_ID);
+			}
+
+			@Test
+			void shouldCallNotErrorStatus() {
+				service.setCommandError(CommandTestFactory.ID, ERROR_MESSAGE);
+
+				verify(service).notErrorStatus(COMMAND_BEFORE_SET_ERROR_STATUS);
+			}
+
+			@Test
+			void shouldCallHandleCommandError() {
+				service.setCommandError(CommandTestFactory.ID, ERROR_MESSAGE);
+
+				verify(service).handleCommandError(CommandTestFactory.ID, PARENT_ID);
+			}
 		}
 
-		@Test
-		void shouldFilterOwnId() {
-			when(repository.findNotFailedSubCommandIds(anyString())).thenReturn(Stream.of(CommandTestFactory.ID));
+		@Nested
+		class TestParentIdMissing {
 
-			service.setCommandError(CommandTestFactory.ID, ERROR_MESSAGE);
+			@BeforeEach
+			void init() {
+				doReturn(Optional.empty()).when(repository).getParentId(anyString());
+			}
+
+			@Test
+			void shouldNotCallHandleCommandError() {
+				service.setCommandError(CommandTestFactory.ID, ERROR_MESSAGE);
 
-			verify(publisher, never()).publishEvent(any());
+				verify(service, never()).handleCommandError(anyString(), anyString());
+			}
 		}
 
-		@Test
-		void shouldNotCallPublishCommandFailedEventIfNoNotFailedSubCommands() {
-			service.setCommandError(CommandTestFactory.ID, ERROR_MESSAGE);
+		@Nested
+		class TestParentAlreadyFailed {
+
+			@Mock
+			private Command failedParentCommand;
+
+			@BeforeEach
+			void init() {
+				when(repository.getParentId(anyString())).thenReturn(Optional.of(PARENT_ID));
+				doReturn(failedParentCommand).when(service).setErrorStatus(anyString());
+				doReturn(false).when(service).notErrorStatus(any());
+			}
 
-			verify(publisher, never()).publishEvent(any());
+			@Test
+			void shouldNotCallHandleCommandError() {
+				service.setCommandError(CommandTestFactory.ID, ERROR_MESSAGE);
+
+				verify(service, never()).handleCommandError(anyString(), anyString());
+			}
 		}
 
+	}
+
+	@Nested
+	class TestSetErrorStatus {
+
 		@Test
-		void shouldCallGetNotFailedParentId() {
-			service.setCommandError(CommandTestFactory.ID, ERROR_MESSAGE);
+		void shouldCallRepositoryUpdateStatus() {
+			when(repository.updateCommandStatusAndReturnPrevious(anyString(), any())).thenReturn(CommandTestFactory.create());
+
+			service.setErrorStatus(CommandTestFactory.ID);
 
-			verify(repository).getNotFailedParentId(CommandTestFactory.ID);
+			verify(repository).updateCommandStatusAndReturnPrevious(CommandTestFactory.ID, CommandStatus.ERROR);
 		}
 
 		@Test
-		void shouldCallPublishCommandFailedEventForParent() {
-			var parentId = "parent-id";
-			when(repository.getNotFailedParentId(anyString())).thenReturn(Optional.of(parentId));
+		void shouldReturnCommand() {
+			var command = CommandTestFactory.create();
+			when(repository.updateCommandStatusAndReturnPrevious(anyString(), any())).thenReturn(command);
 
-			service.setCommandError(CommandTestFactory.ID, ERROR_MESSAGE);
+			var result = service.setErrorStatus(CommandTestFactory.ID);
 
-			verify(publisher).publishEvent(eventCaptor.capture());
-			assertThat(eventCaptor.getValue().getSource()).isEqualTo(parentId);
+			assertThat(result).isSameAs(command);
 		}
 
 		@Test
-		void shouldNotCallPublishCommandFailedEventForParentIfNoParent() {
-			service.setCommandError(CommandTestFactory.ID, ERROR_MESSAGE);
-
-			verify(publisher, never()).publishEvent(any());
+		void shouldThrowExceptionIfNotFound() {
+			assertThrows(NotFoundException.class, () -> service.setErrorStatus(CommandTestFactory.ID));
 		}
 	}
 
 	@Nested
-	class TestCreateCommandFailedEventPublisher {
+	class TestNotErrorStatus {
 
-		private static final String EXPECTED_ERROR_MESSAGE = "error message";
+		@DisplayName("should return true when")
+		@ParameterizedTest(name = "command status is {0}")
+		@EnumSource(value = CommandStatus.class, names = { "ERROR" }, mode = EnumSource.Mode.EXCLUDE)
+		void shouldReturnTrue(CommandStatus status) {
+			var command = CommandTestFactory.createBuilder().status(status).build();
 
-		@Captor
-		private ArgumentCaptor<CommandFailedEvent> eventCaptor;
+			var result = service.notErrorStatus(command);
+
+			assertThat(result).isTrue();
+		}
 
 		@Test
-		void shouldPublishCommandFailedEvent() {
-			publishCommandFailedEvent();
+		void shouldReturnFalse() {
+			var command = CommandTestFactory.createBuilder().status(CommandStatus.ERROR).build();
 
-			verify(publisher).publishEvent(eventCaptor.capture());
-			assertThat(eventCaptor.getValue()).isInstanceOf(CommandFailedEvent.class);
+			var result = service.notErrorStatus(command);
+
+			assertThat(result).isFalse();
 		}
+	}
+
+	@Nested
+	class TestHandleCommandError {
+
+		private static final String PARENT_ID = "parent-id";
+
+		@Captor
+		private ArgumentCaptor<String> errorMessageCaptor;
 
 		@Test
-		void shouldSetCommandIdInFailedEvent() {
-			publishCommandFailedEvent();
+		void shouldCallPublishCommandFailedEvent() {
+			handleCommandError();
 
-			verify(publisher).publishEvent(eventCaptor.capture());
-			assertThat(eventCaptor.getValue().getErrorMessage()).isEqualTo(EXPECTED_ERROR_MESSAGE);
+			verify(service).publishCommandFailedEvent(eq(PARENT_ID), errorMessageCaptor.capture());
+			assertThat(errorMessageCaptor.getValue()).contains(PARENT_ID, CommandTestFactory.ID);
 		}
 
 		@Test
-		void shouldSetErrorMessageInFailedEvent() {
-			publishCommandFailedEvent();
+		void shouldCallRevokeSubCommands() {
+			handleCommandError();
 
-			verify(publisher).publishEvent(eventCaptor.capture());
-			assertThat(eventCaptor.getValue().getErrorMessage()).isEqualTo(EXPECTED_ERROR_MESSAGE);
+			verify(service).revokeSubCommands(PARENT_ID);
 		}
 
-		private void publishCommandFailedEvent() {
-			service.createCommandFailedEventPublisher(EXPECTED_ERROR_MESSAGE).accept(CommandTestFactory.ID);
+		private void handleCommandError() {
+			service.handleCommandError(CommandTestFactory.ID, PARENT_ID);
 		}
 	}
 
@@ -471,62 +718,126 @@ class CommandServiceTest {
 	}
 
 	@Nested
-	class TestRevokeCommandPending {
+	class TestRevokeCommand {
 
-		final String commandId = CommandTestFactory.ID;
+		private static final Command REVOKE_PENDING_COMMAND = CommandTestFactory.createBuilder().status(CommandStatus.REVOKE_PENDING).build();
 
 		@Test
-		void shouldThrowException() {
-			assertThatExceptionOfType(TechnicalException.class).isThrownBy(() -> service.setCommandRevokePending(commandId));
+		void shouldCallRevokeCommandSilent() {
+			doReturn(Optional.of(REVOKE_PENDING_COMMAND)).when(service).revokeCommandSilent(anyString());
+
+			service.revokeCommand(CommandTestFactory.ID);
+
+			verify(service).revokeCommandSilent(CommandTestFactory.ID);
 		}
 
 		@Test
-		void shouldUpdateCommandStatus() {
-			when(repository.getById(commandId)).thenReturn(Optional.of(CommandTestFactory.create()));
+		void shouldCallIsRevokePending() {
+			doReturn(Optional.of(REVOKE_PENDING_COMMAND)).when(service).revokeCommandSilent(anyString());
 
-			service.setCommandRevokePending(commandId);
+			service.revokeCommand(CommandTestFactory.ID);
 
-			verify(repository).updateCommandStatus(anyString(), any(CommandStatus.class));
+			verify(service).isRevokePending(REVOKE_PENDING_COMMAND);
 		}
 
 		@Test
-		void shouldCallPublishRevokeCommandEvent() {
-			when(repository.getById(commandId)).thenReturn(Optional.of(CommandTestFactory.create()));
+		void shouldReturnCommand() {
+			doReturn(Optional.of(REVOKE_PENDING_COMMAND)).when(service).revokeCommandSilent(anyString());
+
+			var result = service.revokeCommand(CommandTestFactory.ID);
 
-			service.setCommandRevokePending(commandId);
+			assertThat(result).isSameAs(REVOKE_PENDING_COMMAND);
+		}
+
+		@Test
+		void shouldThrowNotFoundException() {
+			doReturn(Optional.empty()).when(service).revokeCommandSilent(anyString());
+
+			assertThrows(NotFoundException.class, () -> service.revokeCommand(CommandTestFactory.ID));
+		}
+
+		@Test
+		void shouldThrowRevokeFailedException() {
+			doReturn(Optional.of(CommandTestFactory.create())).when(service).revokeCommandSilent(anyString());
+			doReturn(false).when(service).isRevokePending(any());
 
-			verify(service).publishRevokeCommandEvent(any(String.class));
+			assertThrows(RevokeFailedException.class, () -> service.revokeCommand(CommandTestFactory.ID));
 		}
 	}
 
 	@Nested
-	class TestFiringRevokeCommand {
+	class TestRevokeCommandSilent {
 
-		final String commandId = CommandTestFactory.ID;
+		private static final Command COMMAND = CommandTestFactory.create();
+
+		@BeforeEach
+		void init() {
+			when(repository.setRevokeStatusIfNotPending(anyString())).thenReturn(Optional.of(COMMAND));
+		}
 
 		@Test
-		void shoudlFireEvent() {
-			when(repository.getById(commandId)).thenReturn(Optional.of(CommandTestFactory.create()));
+		void shouldCallRepository() {
+			service.revokeCommandSilent(CommandTestFactory.ID);
+
+			verify(repository).setRevokeStatusIfNotPending(CommandTestFactory.ID);
+		}
 
-			service.publishRevokeCommandEvent(commandId);
+		@Test
+		void shouldCallIsRevokePending() {
+			service.revokeCommandSilent(CommandTestFactory.ID);
 
-			verify(publisher).publishEvent(any(RevokeCommandEvent.class));
+			verify(service).isRevokePending(COMMAND);
 		}
 
 		@Test
-		void shoudlThrowTechnicalExceptionBecauseCommandNotFound() {
-			when(repository.getById(commandId)).thenReturn(Optional.empty());
+		void shouldCallPublishRevokeCommandEvent() {
+			doReturn(true).when(service).isRevokePending(any());
 
-			assertThatExceptionOfType(TechnicalException.class).isThrownBy(() -> service.publishRevokeCommandEvent(commandId));
+			service.revokeCommandSilent(CommandTestFactory.ID);
+
+			verify(service).publishRevokeCommandEvent(COMMAND);
 		}
+	}
+
+	@Nested
+	class TestIsRevokePending {
 
 		@Test
-		void shoudlThrowTechnicalExceptionBecauseNoPreviousState() {
-			when(repository.getById(commandId)).thenReturn(Optional.of(CommandTestFactory.createBuilder().previousState(null).build()));
+		void shouldReturnTrue() {
+			var command = CommandTestFactory.createBuilder().status(CommandStatus.REVOKE_PENDING).build();
 
-			assertThatExceptionOfType(TechnicalException.class).isThrownBy(() -> service.publishRevokeCommandEvent(commandId));
+			var result = service.isRevokePending(command);
+
+			assertThat(result).isTrue();
 		}
 
+		@DisplayName("should return false when")
+		@ParameterizedTest(name = "command status is {0}")
+		@EnumSource(value = CommandStatus.class, names = { "REVOKE_PENDING" }, mode = EnumSource.Mode.EXCLUDE)
+		void shouldReturnFalse(CommandStatus status) {
+			var command = CommandTestFactory.createBuilder().status(status).build();
+
+			var result = service.isRevokePending(command);
+
+			assertThat(result).isFalse();
+		}
+	}
+
+	@Nested
+	class TestPublishRevokeCommandEvent {
+
+		@Captor
+		private ArgumentCaptor<RevokeCommandEvent> eventCaptor;
+
+		@Test
+		void shouldPublishEvent() {
+			var command = CommandTestFactory.create();
+
+			service.publishRevokeCommandEvent(command);
+
+			verify(publisher).publishEvent(eventCaptor.capture());
+			assertThat(eventCaptor.getValue().getSource()).isSameAs(command);
+		}
 	}
 
 	@Nested
@@ -615,14 +926,14 @@ class CommandServiceTest {
 		@BeforeEach
 		void init() {
 			doReturn(SUB_COMMAND_VALUES).when(service).buildSubCommandValues(any());
-			doReturn(PARENT_COMMAND).when(service).getNotFailedCommand(any());
+			doReturn(PARENT_COMMAND).when(service).getPendingCommand(any());
 		}
 
 		@Test
 		void shouldCallGetNotFailedCommand() {
 			service.createSubCommands(CreateSubCommandsRequestTestFactory.create());
 
-			verify(service).getNotFailedCommand(CreateSubCommandsRequestTestFactory.PARENT_ID);
+			verify(service).getPendingCommand(CreateSubCommandsRequestTestFactory.PARENT_ID);
 		}
 
 		@Test
@@ -673,38 +984,33 @@ class CommandServiceTest {
 	}
 
 	@Nested
-	class TestGetNotFailedCommand {
+	class TestGetPendingCommand {
 
 		@Test
 		void shouldCallFindCommand() {
-			doReturn(Optional.of(CommandTestFactory.create())).when(service).findCommand(anyString());
+			doReturn(Optional.of(CommandTestFactory.create())).when(service).findById(anyString());
 
-			service.getNotFailedCommand(CommandTestFactory.ID);
+			service.getPendingCommand(CommandTestFactory.ID);
 
-			verify(service).findCommand(CommandTestFactory.ID);
+			verify(service).findById(CommandTestFactory.ID);
 		}
 
-		@Test
-		void shouldThrowExceptionIfCommandNotFound() {
-			doReturn(Optional.empty()).when(service).findCommand(anyString());
+		@DisplayName("should throw exception when")
+		@ParameterizedTest(name = "command status is {0}")
+		@EnumSource(value = CommandStatus.class, names = { "PENDING" }, mode = EnumSource.Mode.EXCLUDE)
+		void shouldThrowExceptionIfCommandFailed(CommandStatus status) {
+			var command = CommandTestFactory.createBuilder().status(status).build();
+			doReturn(command).when(service).getById(anyString());
 
-			assertThrows(NotFoundException.class, () -> service.getNotFailedCommand(CommandTestFactory.ID));
-		}
-
-		@Test
-		void shouldThrowExceptionIfCommandFailed() {
-			var command = CommandTestFactory.createBuilder().status(CommandStatus.ERROR).build();
-			doReturn(Optional.of(command)).when(service).findCommand(anyString());
-
-			assertThrows(TechnicalException.class, () -> service.getNotFailedCommand(CommandTestFactory.ID));
+			assertThrows(TechnicalException.class, () -> service.getPendingCommand(CommandTestFactory.ID));
 		}
 
 		@Test
 		void shouldReturnCommand() {
 			var command = CommandTestFactory.create();
-			doReturn(Optional.of(command)).when(service).findCommand(anyString());
+			doReturn(Optional.of(command)).when(service).findById(anyString());
 
-			var result = service.getNotFailedCommand(CommandTestFactory.ID);
+			var result = service.getPendingCommand(CommandTestFactory.ID);
 
 			assertThat(result).isSameAs(command);
 		}
@@ -807,4 +1113,5 @@ class CommandServiceTest {
 			assertThat(result).containsAllEntriesOf(BODY_OBJ);
 		}
 	}
+
 }
\ No newline at end of file
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/GrpcCommandServiceITCase.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/GrpcCommandServiceITCase.java
index 3343f674fda73345c563128d368532ee235f60d1..7df40567d8e858171053fe352454a7e67decde01 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/GrpcCommandServiceITCase.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/GrpcCommandServiceITCase.java
@@ -21,7 +21,6 @@ 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.data.mongodb.core.MongoOperations;
-import org.springframework.security.test.context.support.WithMockUser;
 import org.springframework.test.annotation.DirtiesContext;
 
 import de.ozgcloud.command.Command;
@@ -29,19 +28,20 @@ import de.ozgcloud.command.CommandStatus;
 import de.ozgcloud.common.test.DataITCase;
 import de.ozgcloud.vorgang.attached_item.VorgangAttachedItem;
 import de.ozgcloud.vorgang.attached_item.VorgangAttachedItemTestFactory;
+import de.ozgcloud.vorgang.callcontext.WithMockCustomUser;
 import de.ozgcloud.vorgang.clientattribute.ClientAttributeReadPermitted;
 import de.ozgcloud.vorgang.common.grpc.GrpcObjectMapper;
 import de.ozgcloud.vorgang.grpc.command.CommandServiceGrpc.CommandServiceBlockingStub;
 import de.ozgcloud.vorgang.grpc.command.GrpcAddSubCommandsRequest;
 import de.ozgcloud.vorgang.grpc.command.GrpcCommand;
-import de.ozgcloud.vorgang.grpc.command.GrpcCommandsResponse;
 import de.ozgcloud.vorgang.grpc.command.GrpcCreateCommand;
 import de.ozgcloud.vorgang.grpc.command.GrpcCreateCommandRequest;
 import de.ozgcloud.vorgang.grpc.command.GrpcFindCommandsRequest;
-import de.ozgcloud.vorgang.grpc.command.GrpcGetCommandRequest;
+import de.ozgcloud.vorgang.grpc.command.GrpcRevokeCommandRequest;
 import de.ozgcloud.vorgang.vorgang.Vorgang;
 import de.ozgcloud.vorgang.vorgang.VorgangTestFactory;
 import io.grpc.StatusRuntimeException;
+import lombok.extern.log4j.Log4j2;
 import net.devh.boot.grpc.client.inject.GrpcClient;
 
 @SpringBootTest(properties = {
@@ -50,7 +50,8 @@ import net.devh.boot.grpc.client.inject.GrpcClient;
 })
 @DirtiesContext
 @DataITCase
-@WithMockUser
+@WithMockCustomUser
+@Log4j2
 class GrpcCommandServiceITCase {
 
 	@GrpcClient("inProcess")
@@ -111,6 +112,29 @@ class GrpcCommandServiceITCase {
 		}
 	}
 
+	@Nested
+	class TestRevokeCommand {
+
+		@Test
+		void shouldHaveSetStatus() {
+			var vorgang = mongoOperations.save(VorgangTestFactory.createBuilder().id(null).build());
+			var command = mongoOperations.save(CommandTestFactory.createBuilder().id(null).status(CommandStatus.FINISHED).vorgangId(vorgang.getId())
+					.previousState(Map.of(Vorgang.MONGODB_FIELDNAME_STATUS, "NEW")).build());
+
+			var result = serviceBlockingStub.revokeCommand(GrpcRevokeCommandRequest.newBuilder().setId(command.getId()).build());
+
+			assertThat(result.getCommand().getStatus()).isEqualTo(CommandStatus.REVOKE_PENDING.name());
+		}
+
+		@Test
+		void shouldThrowExceptionIfCommandNotFound() {
+			var revokeRequest = GrpcRevokeCommandRequest.newBuilder().setId("not-existing-id").build();
+
+			assertThrows(StatusRuntimeException.class, () -> serviceBlockingStub.revokeCommand(revokeRequest));
+		}
+
+	}
+
 	@Nested
 	class TestLoadOutdatedOrders {
 
@@ -131,7 +155,6 @@ class GrpcCommandServiceITCase {
 	}
 
 	@Nested
-			// TODO Tests überarbeiten: asserts in Test-Methoden verschieben
 	class TestAddSubCommands {
 
 		private static final String PARENT_TEST_ORDER = "PARENT_TEST_ORDER";
@@ -157,51 +180,39 @@ class GrpcCommandServiceITCase {
 
 			var grpcCommandsResponse = serviceBlockingStub.addSubCommands(request);
 
-			await().atMost(60, TimeUnit.SECONDS).untilAsserted(() -> assertCommandIsFinished(parentCommand));
-			grpcCommandsResponse.getCommandList().forEach(this::assertCommandIsFinished);
+			await().atMost(60, TimeUnit.SECONDS).untilAsserted(() -> {
+				var command = loadCommand(parentCommand);
+				assertThat(command.getStatus()).isEqualTo(CommandStatus.FINISHED);
+			});
+			grpcCommandsResponse.getCommandList().stream().map(this::loadCommand).forEach(command ->
+					assertThat(command.getStatus()).isEqualTo(CommandStatus.FINISHED)
+			);
 		}
 
 		@Test
-		void shouldSetErrorWhenOneOfParallelsFails() {
+		void shouldSetErrorStatusForParentCommand() {
 			var request = buildAddSubCommandsRequest(parentCommand.getId(), buildCreateCommand(), buildFailedCreateCommand(), buildCreateCommand());
 
-			var grpcCommandsResponse = serviceBlockingStub.addSubCommands(request);
+			serviceBlockingStub.addSubCommands(request);
 
-			await().atMost(60, TimeUnit.SECONDS).untilAsserted(() -> assertCommandIsFailed(parentCommand));
-			grpcCommandsResponse.getCommandList().forEach(this::assertCommandIsFailed);
-		}
-
-		@Test
-		void shouldSetErrorWhenOneSequentialFails() {
-			var executedCommands = addSuccessfullySubCommands();
-
-			var failedCommand = addFailedSubCommands();
-
-			failedCommand.getCommandList().forEach(this::assertCommandIsFailed);
-			executedCommands.getCommandList().forEach(this::assertCommandIsFailed);
+			await().atMost(60, TimeUnit.SECONDS).untilAsserted(() -> {
+				var command = loadCommand(parentCommand);
+				assertThat(command.getStatus()).isEqualTo(CommandStatus.ERROR);
+				assertThat(command.getErrorMessage()).isNotBlank();
+			});
 		}
 
 		@Test
-		void shouldThrowErrorWhenParentFailedAlready() {
-			addFailedSubCommands();
-
-			assertThrows(StatusRuntimeException.class, this::addSuccessfullySubCommands);
-		}
-
-		private GrpcCommandsResponse addSuccessfullySubCommands() {
-			var successfullyRequest = buildAddSubCommandsRequest(parentCommand.getId(), buildCreateCommand());
-			var executedCommands = serviceBlockingStub.addSubCommands(successfullyRequest);
-			await().atMost(60, TimeUnit.SECONDS).untilAsserted(() -> assertCommandIsFinished(parentCommand));
-			return executedCommands;
-		}
-
-		private GrpcCommandsResponse addFailedSubCommands() {
-			var failedRequest = buildAddSubCommandsRequest(parentCommand.getId(), buildFailedCreateCommand());
+		void shouldRevokeSubCommands() {
+			var request = buildAddSubCommandsRequest(parentCommand.getId(), buildCreateCommand(), buildFailedCreateCommand(), buildCreateCommand());
 
-			var executedCommands = serviceBlockingStub.addSubCommands(failedRequest);
+			var grpcCommandsResponse = serviceBlockingStub.addSubCommands(request);
 
-			await().atMost(60, TimeUnit.SECONDS).untilAsserted(() -> assertCommandIsFailed(parentCommand));
-			return executedCommands;
+			await().atMost(60, TimeUnit.SECONDS).untilAsserted(() -> {
+				var revokedCommand = grpcCommandsResponse.getCommandList().stream().map(this::loadCommand)
+						.filter(command -> command.getStatus() != CommandStatus.ERROR).toList();
+				assertThat(revokedCommand).hasSize(2);
+			});
 		}
 
 		private GrpcCommand createParentCommand() {
@@ -244,15 +255,13 @@ class GrpcCommandServiceITCase {
 					.build();
 		}
 
-		private void assertCommandIsFinished(GrpcCommand command) {
-			var commandResponse = serviceBlockingStub.getCommand(GrpcGetCommandRequest.newBuilder().setId(command.getId()).build());
-			assertThat(commandResponse.getStatus()).isEqualTo(CommandStatus.FINISHED.name());
+		private Command loadCommand(GrpcCommand grpcCommand) {
+			return mongoOperations.findById(grpcCommand.getId(), Command.class);
 		}
 
-		private void assertCommandIsFailed(GrpcCommand command) {
-			var commandResponse = serviceBlockingStub.getCommand(GrpcGetCommandRequest.newBuilder().setId(command.getId()).build());
-			assertThat(commandResponse.getStatus()).isEqualTo(CommandStatus.ERROR.name());
+		private void assertCommandIsFinished(GrpcCommand grpcCommand) {
+			var command = mongoOperations.findById(grpcCommand.getId(), Command.class);
+			assertThat(command.getStatus()).isEqualTo(CommandStatus.FINISHED);
 		}
-
 	}
 }
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/GrpcCommandServiceTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/GrpcCommandServiceTest.java
index 3924b31aeb817ab048897bf4de28ddec744b416e..6807b332b138383be4bff92001a809aba224d3ac 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/GrpcCommandServiceTest.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/GrpcCommandServiceTest.java
@@ -36,9 +36,6 @@ 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.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.EnumSource;
-import org.junit.jupiter.params.provider.EnumSource.Mode;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Captor;
 import org.mockito.InjectMocks;
@@ -66,7 +63,6 @@ import de.ozgcloud.vorgang.grpc.command.GrpcRevokeCommandRequest;
 import de.ozgcloud.vorgang.grpc.command.GrpcSetCommandExecutedRequest;
 import de.ozgcloud.vorgang.vorgang.VorgangTestFactory;
 import io.grpc.stub.StreamObserver;
-import lombok.SneakyThrows;
 
 class GrpcCommandServiceTest {
 
@@ -106,7 +102,7 @@ class GrpcCommandServiceTest {
 		void mockMapper() {
 			when(createCommandRequestMapper.fromGrpc(any(GrpcCreateCommandRequest.class))).thenReturn(createComandRequest);
 			when(commandService.createCommand(any(CreateCommandRequest.class))).thenReturn(persistedCommand);
-			when(commandService.findCommand(anyString())).thenReturn(Optional.of(CommandTestFactory.create()));
+			when(commandService.findById(anyString())).thenReturn(Optional.of(CommandTestFactory.create()));
 			when(commandResponseMapper.toGrpc(any(CommandResponse.class))).thenReturn(response);
 		}
 
@@ -147,29 +143,6 @@ class GrpcCommandServiceTest {
 		}
 	}
 
-	@Nested
-	class TestIsStatusChangeOrder {
-
-		@ParameterizedTest
-		@EnumSource(mode = Mode.INCLUDE, names = { "VORGANG_ANNEHMEN", "VORGANG_VERWERFEN", "VORGANG_ZURUECKHOLEN", "VORGANG_BEARBEITEN",
-				"VORGANG_BESCHEIDEN", "VORGANG_ZURUECKSTELLEN", "VORGANG_ABSCHLIESSEN", "VORGANG_WIEDEREROEFFNEN" })
-		void shouldReturnTrue(Order order) {
-			var result = service.isStatusChangeOrder(order.name());
-
-			assertThat(result).isTrue();
-		}
-
-		@ParameterizedTest
-		@EnumSource(mode = Mode.EXCLUDE, names = { "VORGANG_ANNEHMEN", "VORGANG_VERWERFEN", "VORGANG_ZURUECKHOLEN", "VORGANG_BEARBEITEN",
-				"VORGANG_BESCHEIDEN", "VORGANG_ZURUECKSTELLEN", "VORGANG_ABSCHLIESSEN", "VORGANG_WIEDEREROEFFNEN", "VORGANG_ZUM_LOESCHEN_MARKIEREN",
-				"VORGANG_LOESCHEN" })
-		void shouldReturnFalse(Order order) {
-			var result = service.isStatusChangeOrder(order.name());
-
-			assertThat(result).isFalse();
-		}
-	}
-
 	@DisplayName("Get command")
 	@Nested
 	class TestGetCommand {
@@ -182,7 +155,7 @@ class GrpcCommandServiceTest {
 
 		@BeforeEach
 		void init() {
-			when(commandService.findCommand(any())).thenReturn(Optional.of(CommandTestFactory.create()));
+			when(commandService.findById(any())).thenReturn(Optional.of(CommandTestFactory.create()));
 			when(commandMapper.toGrpc(any())).thenReturn(GrpcCommand.newBuilder().setId(CommandTestFactory.ID).build());
 		}
 
@@ -197,7 +170,7 @@ class GrpcCommandServiceTest {
 		void shouldCallVorgangCommandService() throws Exception {
 			callGetVorgangCommand();
 
-			verify(commandService).findCommand(CommandTestFactory.ID);
+			verify(commandService).findById(CommandTestFactory.ID);
 		}
 
 		@Test
@@ -226,59 +199,67 @@ class GrpcCommandServiceTest {
 	@Nested
 	class TestRevokeCommand {
 
+		private static final GrpcRevokeCommandRequest REVOKE_COMMAND_REQUEST = GrpcRevokeCommandRequest.newBuilder().setId(CommandTestFactory.ID)
+				.build();
+
 		@Mock
 		private StreamObserver<GrpcCommandResponse> responseObserver;
-		private final GrpcRevokeCommandRequest request = GrpcRevokeCommandRequest.newBuilder().setId(CommandTestFactory.ID).build();
 
-		@BeforeEach
-		void mockCommandService() {
-			Command vorgangCommand = CommandTestFactory.createBuilder().id(CommandTestFactory.ID).build();
+		@Mock
+		private GrpcCommandResponse commandsResponse;
 
-			when(commandService.findCommand(any())).thenReturn(Optional.of(vorgangCommand));
+		@Captor
+		private ArgumentCaptor<CommandResponse> responseCaptor;
+
+		private Command updatedCommand;
+
+		private void callRevokeCommand() {
+			service.revokeCommand(REVOKE_COMMAND_REQUEST, responseObserver);
+		}
+
+		@BeforeEach
+		void init() {
+			updatedCommand = CommandTestFactory.createBuilder().id(CommandTestFactory.ID).build();
 		}
 
 		@Test
-		void shouldCallPolicyService() throws Exception {
+		void shouldCallPolicyService() {
 			callRevokeCommand();
 
-			verify(policyService).checkPermissionByCommand(anyString());
+			verify(policyService).checkPermissionByCommand(CommandTestFactory.ID);
 		}
 
 		@Test
-		void shouldCallServiceRevokeCommand() throws Exception {
+		void shouldCallServiceRevokeCommand() {
 			callRevokeCommand();
 
-			verify(commandService).setCommandRevokePending(request.getId());
+			verify(commandService).revokeCommand(CommandTestFactory.ID);
 		}
 
 		@Test
-		void shouldCallMapper() throws Exception {
+		void shouldCallMapper() {
+			when(commandService.revokeCommand(any())).thenReturn(updatedCommand);
+
 			callRevokeCommand();
 
-			verify(commandResponseMapper).toGrpc(any());
+			verify(commandResponseMapper).toGrpc(responseCaptor.capture());
+			assertThat(responseCaptor.getValue()).extracting(CommandResponse::getCommand).isSameAs(updatedCommand);
 		}
 
-		@Nested
-		class TestProceedRevokeCommand {
-
-			private final PersistedCommand command = CommandTestFactory.create();
-
-			@BeforeEach
-			void init() {
-				when(commandService.findCommand(anyString())).thenReturn(Optional.of(command));
-			}
+		@Test
+		void shouldCallOnNext() {
+			when(commandResponseMapper.toGrpc(any())).thenReturn(commandsResponse);
 
-			@Test
-			@SneakyThrows
-			void shouldLoadCommand() {
-				callRevokeCommand();
+			callRevokeCommand();
 
-				verify(service).getCommand(CommandTestFactory.ID);
-			}
+			verify(responseObserver).onNext(commandsResponse);
 		}
 
-		private void callRevokeCommand() throws Exception {
-			service.revokeCommand(request, responseObserver);
+		@Test
+		void shouldCloseStream() {
+			callRevokeCommand();
+
+			verify(responseObserver).onCompleted();
 		}
 	}
 
@@ -411,14 +392,14 @@ class GrpcCommandServiceTest {
 
 		@BeforeEach
 		void init() {
-			when(commandService.findCommand(any())).thenReturn(Optional.of(CommandTestFactory.create()));
+			when(commandService.findById(any())).thenReturn(Optional.of(CommandTestFactory.create()));
 		}
 
 		@Test
 		void shouldLoadCommand() {
 			service.setCommandExecuted(buildRequest(), responseObserver);
 
-			verify(commandService).findCommand(CommandTestFactory.ID);
+			verify(commandService).findById(CommandTestFactory.ID);
 		}
 
 		@Test
@@ -430,7 +411,7 @@ class GrpcCommandServiceTest {
 
 		@Test
 		void shouldHandleMissingCommand() {
-			when(commandService.findCommand(any())).thenReturn(Optional.empty());
+			when(commandService.findById(any())).thenReturn(Optional.empty());
 
 			service.setCommandExecuted(buildRequest(), responseObserver);
 
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/PersistPostfachMailByCommandServiceITCase.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/PersistPostfachMailByCommandServiceITCase.java
index 6f386a9017ddec6bc2e7dd1c452a997caf4e6379..ca948a0825554fb26818b1bd978bfbf0183c878e 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/PersistPostfachMailByCommandServiceITCase.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/PersistPostfachMailByCommandServiceITCase.java
@@ -26,7 +26,6 @@ package de.ozgcloud.vorgang.command;
 import static org.assertj.core.api.Assertions.*;
 
 import java.util.Map;
-import java.util.Optional;
 
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.DisplayName;
@@ -36,12 +35,9 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.mongodb.core.MongoOperations;
 import org.springframework.security.test.context.support.WithMockUser;
 
-import de.ozgcloud.command.Command;
 import de.ozgcloud.common.test.DataITCase;
-import de.ozgcloud.nachrichten.postfach.PostfachNachrichtTestFactory;
 import de.ozgcloud.vorgang.attached_item.VorgangAttachedItem;
 import de.ozgcloud.vorgang.attached_item.VorgangAttachedItemTestFactory;
-import de.ozgcloud.vorgang.callcontext.UserTestFactory;
 import de.ozgcloud.vorgang.vorgang.Vorgang;
 import de.ozgcloud.vorgang.vorgang.VorgangTestFactory;
 
@@ -63,25 +59,6 @@ class PersistPostfachMailByCommandServiceITCase {
 		persistedVorgang = mongoOperations.save(VorgangTestFactory.createWithOrganisationEinheitId("73").toBuilder().id(null).version(0).build());
 	}
 
-	@DisplayName("persist mail")
-	@Nested
-	class TestPersistMail {
-
-		@BeforeEach
-		void initDatabase() {
-			mongoOperations.dropCollection(Command.COLLECTION_NAME);
-		}
-
-		@Test
-		void shouldCreateCommand() {
-			service.persistNachricht(Optional.of(UserTestFactory.ID),
-					PostfachNachrichtTestFactory.createBuilder().vorgangId(persistedVorgang.getId()).build());
-
-			var commands = mongoOperations.findAll(Command.class);
-			assertThat(commands).hasSize(1);
-		}
-	}
-
 	@DisplayName("with existing postfach nachricht")
 	@Nested
 	class TestWithExistingPostfachNachricht {
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/PersistPostfachNachrichtByCommandServiceTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/PersistPostfachNachrichtByCommandServiceTest.java
index 3384f06ff55b5146b18eed76d584e7dc8ae078d2..7075a16dbee0496c3b2663dc8111fe3ef1300098 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/PersistPostfachNachrichtByCommandServiceTest.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/PersistPostfachNachrichtByCommandServiceTest.java
@@ -24,7 +24,6 @@
 package de.ozgcloud.vorgang.command;
 
 import static org.assertj.core.api.Assertions.*;
-import static org.junit.jupiter.api.Assertions.*;
 import static org.mockito.ArgumentMatchers.*;
 import static org.mockito.Mockito.*;
 
@@ -49,10 +48,8 @@ import de.ozgcloud.nachrichten.postfach.PostfachAddressTestFactory;
 import de.ozgcloud.nachrichten.postfach.PostfachNachrichtTestFactory;
 import de.ozgcloud.nachrichten.postfach.osi.MessageAttachmentTestFactory;
 import de.ozgcloud.nachrichten.postfach.osi.MessageTestFactory;
-import de.ozgcloud.vorgang.attached_item.VorgangAttachedItemMapper;
 import de.ozgcloud.vorgang.attached_item.VorgangAttachedItemService;
 import de.ozgcloud.vorgang.attached_item.VorgangAttachedItemTestFactory;
-import de.ozgcloud.vorgang.callcontext.UserTestFactory;
 import de.ozgcloud.vorgang.files.FileId;
 import de.ozgcloud.vorgang.files.FileService;
 import de.ozgcloud.vorgang.files.OzgFile;
@@ -64,119 +61,21 @@ class PersistPostfachNachrichtByCommandServiceTest {
 	@InjectMocks
 	private PersistPostfachNachrichtByCommandService service;
 	@Mock
-	private CommandService commandService;
-	@Mock
 	private VorgangAttachedItemService attachedItemService;
 	@Mock
 	private FileService fileService;
 
-	@DisplayName("Persist mail")
+	@DisplayName("Persist nachricht")
 	@Nested
-	class TestPersistMail {
-
-		@Captor
-		private ArgumentCaptor<CreateCommandRequest> requestCaptor;
-
-		@Test
-		void shouldCallCommandService() {
-			callService();
-
-			verify(commandService).createCommand(notNull());
-		}
-
-		@Test
-		void shouldContainVorgangId() {
-			var request = callService();
-
-			assertThat(request.getVorgangId()).isEqualTo(MessageTestFactory.VORGANG_ID);
-		}
-
-		@Test
-		void shouldContainRelationInformations() {
-			var request = callService();
-
-			assertThat(request.getRelationId()).isEqualTo(MessageTestFactory.VORGANG_ID);
-			assertThat(request.getRelationVersion()).isNull();
-		}
+	class TestPersistNachricht {
 
 		@Test
-		void shouldHaveOrder() {
-			var request = callService();
-
-			assertThat(request.getOrder()).isEqualTo(Order.CREATE_ATTACHED_ITEM.name());
-		}
-
-		@Test
-		void shouldHaveCallContext() {
-			var request = callService();
-
-			assertThat(request.getCallContext()).isNotNull();
-			assertThat(request.getCallContext().getUser().getId()).isEqualTo(UserTestFactory.ID);
-		}
-
-		@Test
-		void shouldHaveVorgangAttachedItem() {
-			var request = callService();
-
-			assertThat(request.getBodyObject())
-					.containsEntry(VorgangAttachedItemMapper.PROPERTY_VORGANG_ID, MessageTestFactory.VORGANG_ID)
-					.containsEntry(VorgangAttachedItemMapper.PROPERTY_CLIENT, "OzgCloud_NachrichtenManager")
-					.containsEntry(VorgangAttachedItemMapper.PROPERTY_ITEM_NAME, "PostfachMail")
-					.containsKey(VorgangAttachedItemMapper.PROPERTY_ITEM);
-		}
-
-		@Test
-		void shouldNotAddUser() {
-			service.persistNachricht(Optional.empty(), PostfachNachrichtTestFactory.create());
-			verify(commandService).createCommand(requestCaptor.capture());
-
-			assertThat(requestCaptor.getValue().getCallContext().getUser()).isNull();
-		}
-
-		private CreateCommandRequest callService() {
-			service.persistNachricht(Optional.of(UserTestFactory.ID), PostfachNachrichtTestFactory.createBuilder().id(null).build());
-			verify(commandService).createCommand(requestCaptor.capture());
-
-			return requestCaptor.getValue();
-		}
-
-		@DisplayName("build mail map")
-		@Nested
-		class TestBuildMailMap {
-
-			@Test
-			void shouldContainAllFieldsIgnoringId() {
-				var map = service.buildNachrichtMap(PostfachNachrichtTestFactory.createBuilder().id(null).build());
-
-				var mapWithoutId = PostfachNachrichtTestFactory.asMap();
-				mapWithoutId.remove("id");
-
-				assertThat(map).containsAllEntriesOf(mapWithoutId);
-			}
-
-			@Test
-			void shouldIgnoreEmptyMessageId() {
-				assertDoesNotThrow(() -> service.buildNachrichtMap(PostfachNachrichtTestFactory.createBuilder().messageId(null).build()));
-			}
-
-			@Test
-			void shouldIgnoreEmptyCreatedBy() {
-				assertDoesNotThrow(() -> service.buildNachrichtMap(PostfachNachrichtTestFactory.createBuilder().createdBy(null).build()));
-			}
-
-			@Test
-			void shouldHandleNullAsPostfachId() {
-				var postfachMail = PostfachNachrichtTestFactory.createBuilder().postfachId(null).build();
-
-				assertDoesNotThrow(() -> service.buildNachrichtMap(postfachMail));
-			}
-
-			@Test
-			void shouldProceedWithEmptyPostfachAddress() {
-				var postfachMail = PostfachNachrichtTestFactory.createBuilder().postfachAddress(null).build();
+		void shouldThrowException() {
+			var postfachNachricht = PostfachNachrichtTestFactory.create();
+			var userId = Optional.<String>empty();
 
-				assertDoesNotThrow(() -> service.buildNachrichtMap(postfachMail));
-			}
+			assertThatThrownBy(() -> service.persistNachricht(userId, postfachNachricht))
+					.isInstanceOf(UnsupportedOperationException.class);
 		}
 	}
 
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/RevokeCommandEventTestFactory.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/RevokeCommandEventTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..61b93ce3d08e3afe118e21fe0d2017310f2c9714
--- /dev/null
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/RevokeCommandEventTestFactory.java
@@ -0,0 +1,11 @@
+package de.ozgcloud.vorgang.command;
+
+import de.ozgcloud.command.Command;
+import de.ozgcloud.command.RevokeCommandEvent;
+
+public class RevokeCommandEventTestFactory {
+
+	public static RevokeCommandEvent create(Command command) {
+		return new RevokeCommandEvent(command);
+	}
+}
\ No newline at end of file
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/common/migration/M010_CreateIndexesInVorgangTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/common/migration/M010_CreateIndexesInVorgangTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..d2751ccceaf4480dec515641851e051de8eba4f1
--- /dev/null
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/common/migration/M010_CreateIndexesInVorgangTest.java
@@ -0,0 +1,132 @@
+/*
+ * 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.vorgang.common.migration;
+
+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.mockito.Spy;
+import org.springframework.data.mongodb.core.MongoTemplate;
+import org.springframework.data.mongodb.core.index.IndexDefinition;
+import org.springframework.data.mongodb.core.index.IndexOperations;
+
+class M010_CreateIndexesInVorgangTest {
+
+	@Spy
+	@InjectMocks
+	private M010_CreateIndexesInVorgang migration;
+
+	@Mock
+	private MongoTemplate template;
+	@Mock
+	private IndexOperations indexOperations;
+
+	@Nested
+	class TestDoMigration {
+
+		@Mock
+		private IndexDefinition indexDefinition;
+
+		@BeforeEach
+		void init() {
+			when(template.indexOps(anyString())).thenReturn(indexOperations);
+		}
+
+		@Test
+		void shouldGetIndexOperations() {
+			migration.doMigration(template);
+
+			verify(template).indexOps(M010_CreateIndexesInVorgang.COLLECTION_NAME);
+		}
+
+		@Test
+		void shouldCallBuildCompoundIndexDefinition() {
+			migration.doMigration(template);
+
+			verify(migration).buildCompoundIndexDefinition();
+		}
+
+		@Test
+		void shouldEnsureComponentIndex() {
+			doReturn(indexDefinition).when(migration).buildCompoundIndexDefinition();
+
+			migration.doMigration(template);
+
+			verify(indexOperations).ensureIndex(indexDefinition);
+		}
+
+	}
+
+	@Nested
+	class TestBuildCompoundIndex {
+
+		@Test
+		void shouldSetInCreation() {
+			var indexDefinition = migration.buildCompoundIndexDefinition();
+
+			assertThat(indexDefinition.getIndexKeys()).containsEntry(M010_CreateIndexesInVorgang.FIELD_IN_CREATION, 1);
+		}
+
+		@Test
+		void shouldSetOrganisationseinheitenId() {
+			var indexDefinition = migration.buildCompoundIndexDefinition();
+
+			assertThat(indexDefinition.getIndexKeys()).containsEntry(M010_CreateIndexesInVorgang.FIELD_ORGANISATIONSEINHEITEN_ID, 1);
+		}
+
+		@Test
+		void shouldSetAssignedTo() {
+			var indexDefinition = migration.buildCompoundIndexDefinition();
+
+			assertThat(indexDefinition.getIndexKeys()).containsEntry(M010_CreateIndexesInVorgang.FIELD_ASSIGNED_TO, 1);
+		}
+
+		@Test
+		void shouldSetStatus() {
+			var indexDefinition = migration.buildCompoundIndexDefinition();
+
+			assertThat(indexDefinition.getIndexKeys()).containsEntry(M010_CreateIndexesInVorgang.FIELD_STATUS, 1);
+		}
+
+		@Test
+		void shouldSetCreatedAt() {
+			var indexDefinition = migration.buildCompoundIndexDefinition();
+
+			assertThat(indexDefinition.getIndexKeys()).containsEntry(M010_CreateIndexesInVorgang.FIELD_CREATED_AT, 1);
+		}
+
+		@Test
+		void shouldSetName() {
+			var indexDefinition = migration.buildCompoundIndexDefinition();
+
+			assertThat(indexDefinition.getIndexOptions()).containsEntry("name", M010_CreateIndexesInVorgang.COMPOUND_INDEX_NAME);
+		}
+	}
+
+}
\ No newline at end of file
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/common/migration/M011_SetDefaultCollaborationLevelITCase.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/common/migration/M011_SetDefaultCollaborationLevelITCase.java
new file mode 100644
index 0000000000000000000000000000000000000000..9b5b8b9a499aaf17baf73c073dbf0f75ef7cc694
--- /dev/null
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/common/migration/M011_SetDefaultCollaborationLevelITCase.java
@@ -0,0 +1,142 @@
+package de.ozgcloud.vorgang.common.migration;
+
+import static org.assertj.core.api.Assertions.*;
+
+import org.bson.Document;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.mongodb.core.MongoTemplate;
+import org.springframework.data.mongodb.core.query.Query;
+
+import com.thedeanda.lorem.LoremIpsum;
+
+import de.ozgcloud.common.test.DataITCase;
+
+@DataITCase
+class M011_SetDefaultCollaborationLevelITCase {
+
+	private final M011_SetDefaultCollaborationLevel migration = new M011_SetDefaultCollaborationLevel();
+
+	private final String nameField = "name";
+	private final String nameFieldValue = LoremIpsum.getInstance().getWords(1);
+
+	private final String organisationsEinheitField = "organisationsEinheitId";
+	private final String organisationsEinheitFieldValue = LoremIpsum.getInstance().getWords(1);
+
+	@Autowired
+	private MongoTemplate template;
+	@Autowired
+	private MigrationDbTestUtils dbTestUtils;
+
+	@DisplayName("Do migration")
+	@Nested
+	class TestDoMigration {
+
+		@BeforeEach
+		void mock() {
+			dbTestUtils.dropVorgangCollection();
+		}
+
+		@DisplayName("on missing collaboration level")
+		@Nested
+		class TestOnMissingCollaborationLevel {
+
+			@BeforeEach
+			void initVorgang() {
+				dbTestUtils.saveVorgang(createVorgangWithName());
+			}
+
+			@Test
+			void shouldSetDefaultCollaborationLevel() {
+				migration.doMigration(template);
+
+				assertThat(getVorgangHeader()).containsEntry(M011_SetDefaultCollaborationLevel.COLLABORATION_LEVEL_FIELD, 0);
+			}
+
+			@Test
+			void shouldKeepVorgangData() {
+				migration.doMigration(template);
+
+				assertThat(getVorgang()).containsEntry(nameField, nameFieldValue);
+			}
+
+			@Test
+			void shouldKeepHeaderData() {
+				migration.doMigration(template);
+
+				assertThat(getVorgangHeader()).containsEntry(organisationsEinheitField,
+						organisationsEinheitFieldValue);
+			}
+		}
+
+		@DisplayName("on existing collaboration level")
+		@Nested
+		class TestOnExistingCollaborationLevel {
+
+			@BeforeEach
+			void initVorgang() {
+				dbTestUtils.saveVorgang(createVorgangWithCollaborationLevel());
+			}
+
+			@Test
+			void shouldKeepCollaborationLevel() {
+				migration.doMigration(template);
+
+				assertThat(getVorgangHeader()).containsEntry(M011_SetDefaultCollaborationLevel.COLLABORATION_LEVEL_FIELD, 1);
+			}
+
+			@Test
+			void shouldKeepVorgangData() {
+				migration.doMigration(template);
+
+				assertThat(getVorgang()).containsEntry(nameField, nameFieldValue);
+			}
+
+			@Test
+			void shouldKeepHeaderData() {
+				migration.doMigration(template);
+
+				assertThat(getVorgangHeader()).containsEntry(organisationsEinheitField,
+						organisationsEinheitFieldValue);
+			}
+		}
+
+		private Document createVorgangWithCollaborationLevel() {
+			var vorgang = createVorgangWithName();
+			vorgang.append(M011_SetDefaultCollaborationLevel.HEADER_FIELD, createHeaderWithCollaborationLevel());
+			return vorgang;
+		}
+
+		private Document createHeaderWithCollaborationLevel() {
+			var header = createHeaderWithOrganisationsEinheitId();
+			header.append(M011_SetDefaultCollaborationLevel.COLLABORATION_LEVEL_FIELD, 1);
+			return header;
+		}
+
+		private Document createVorgangWithName() {
+			var vorgang = new Document();
+			vorgang.append(nameField, nameFieldValue);
+			vorgang.append(M011_SetDefaultCollaborationLevel.HEADER_FIELD, createHeaderWithOrganisationsEinheitId());
+			return vorgang;
+		}
+
+		private Document createHeaderWithOrganisationsEinheitId() {
+			var header = new Document();
+			header.append(organisationsEinheitField, organisationsEinheitFieldValue);
+			return header;
+		}
+
+		private Document getVorgangHeader() {
+			return (Document) getVorgang().get(M011_SetDefaultCollaborationLevel.HEADER_FIELD);
+		}
+
+		private Document getVorgang() {
+			var vorgaenge = dbTestUtils.findVorgang(new Query());
+			assertThat(vorgaenge).hasSize(1);
+			return vorgaenge.get(0);
+		}
+	}
+}
\ No newline at end of file
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/common/search/MongodbFullTextSearchIndexInitializerITCase.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/common/search/MongodbFullTextSearchIndexInitializerITCase.java
new file mode 100644
index 0000000000000000000000000000000000000000..c623040a7e824441be13e2bcb82676e0f19e2ec2
--- /dev/null
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/common/search/MongodbFullTextSearchIndexInitializerITCase.java
@@ -0,0 +1,63 @@
+/*
+ * 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.vorgang.common.search;
+
+import static org.assertj.core.api.Assertions.*;
+import static org.awaitility.Awaitility.*;
+
+import java.time.Duration;
+import java.util.Optional;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.data.mongodb.core.MongoOperations;
+import org.springframework.data.mongodb.core.index.IndexInfo;
+
+import de.ozgcloud.common.test.DataITCase;
+import de.ozgcloud.vorgang.vorgang.Vorgang;
+
+@SpringBootTest(properties = {
+		"ozgcloud.mongodbsearch.enabled=true"
+})
+@DataITCase
+class MongodbFullTextSearchIndexInitializerITCase {
+
+	@Autowired
+	private MongoOperations mongoOperations;
+
+	@Test
+	void shouldEnsureIndex() {
+		await().atMost(Duration.ofSeconds(60)).untilAsserted(() ->
+				assertThat(mongoOperations.indexOps(Vorgang.COLLECTION_NAME).getIndexInfo()).isNotEmpty());
+
+		assertThat(getTextIndex()).isPresent();
+	}
+
+	private Optional<IndexInfo> getTextIndex() {
+		return mongoOperations.indexOps(Vorgang.COLLECTION_NAME).getIndexInfo().stream()
+				.filter(index -> MongodbFullTextSearchIndexInitializer.TEXT_INDEX_NAME.equals(index.getName())).findFirst();
+	}
+
+}
\ No newline at end of file
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/common/search/MongodbFullTextSearchIndexInitializerTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/common/search/MongodbFullTextSearchIndexInitializerTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..6e93887973173fa3a6e986891adfe6c5fd28e9b9
--- /dev/null
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/common/search/MongodbFullTextSearchIndexInitializerTest.java
@@ -0,0 +1,111 @@
+/*
+ * 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.vorgang.common.search;
+
+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.mockito.Spy;
+import org.springframework.data.mongodb.core.MongoOperations;
+import org.springframework.data.mongodb.core.index.IndexOperations;
+import org.springframework.data.mongodb.core.index.TextIndexDefinition;
+
+import de.ozgcloud.vorgang.vorgang.Vorgang;
+
+class MongodbFullTextSearchIndexInitializerTest {
+
+	@Spy
+	@InjectMocks
+	private MongodbFullTextSearchIndexInitializer indexInitializer;
+
+	@Mock
+	private MongoOperations mongoOperations;
+
+	@Nested
+	class TestInitWildcardTextIndex {
+
+		@Mock
+		private IndexOperations indexOperations;
+		@Mock
+		private TextIndexDefinition textIndexDefinition;
+
+		@BeforeEach
+		void init() {
+			when(mongoOperations.indexOps(anyString())).thenReturn(indexOperations);
+		}
+
+		@Test
+		void shouldCallEnsureIndex() {
+			indexInitializer.initWildcardTextIndex();
+
+			verify(mongoOperations).indexOps(Vorgang.COLLECTION_NAME);
+		}
+
+		@Test
+		void shouldCallBuildWildcardTextIndexDefinition() {
+			indexInitializer.initWildcardTextIndex();
+
+			verify(indexInitializer).buildWildcardTextIndexDefinition();
+		}
+
+		@Test
+		void shouldCallEnsureIndexWithBuildWildcardTextIndexDefinition() {
+			doReturn(textIndexDefinition).when(indexInitializer).buildWildcardTextIndexDefinition();
+
+			indexInitializer.initWildcardTextIndex();
+
+			verify(indexOperations).ensureIndex(textIndexDefinition);
+		}
+	}
+
+	@Nested
+	class TestBuildWildcardTextIndexDefinition {
+
+		@Test
+		void shouldSetIndexName() {
+			var result = indexInitializer.buildWildcardTextIndexDefinition();
+
+			assertThat(result.getIndexOptions()).containsEntry("name", MongodbFullTextSearchIndexInitializer.TEXT_INDEX_NAME);
+		}
+
+		@Test
+		void shouldSetDefaultLanguage() {
+			var result = indexInitializer.buildWildcardTextIndexDefinition();
+
+			assertThat(result.getIndexOptions()).containsEntry("default_language", MongodbFullTextSearchIndexInitializer.TEXT_INDEX_LANGUAGE);
+		}
+
+		@Test
+		void shouldCreateWildcardTextIndex() {
+			var result = indexInitializer.buildWildcardTextIndexDefinition();
+
+			assertThat(result.getIndexKeys()).containsEntry("$**", "text");
+		}
+	}
+}
\ No newline at end of file
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/common/search/SearchEventListenerTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/common/search/SearchEventListenerTest.java
index 3b2a5913798dce1392dc9c53031fa31fa763c8b4..359c21709666e3ec0f2c5c8e07d5317ba351dc79 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/common/search/SearchEventListenerTest.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/common/search/SearchEventListenerTest.java
@@ -112,7 +112,7 @@ class SearchEventListenerTest {
 
 		@BeforeEach
 		void init() {
-			when(commandService.findCommand(any())).thenReturn(Optional.of(CommandTestFactory.create()));
+			when(commandService.findById(any())).thenReturn(Optional.of(CommandTestFactory.create()));
 			when(vorgangService.getById(anyString())).thenReturn(vorgang);
 		}
 
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/common/search/SearchServiceITCase.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/common/search/SearchServiceITCase.java
index e54948ec4f0108debde76cf2a8e8635ebc5b1b87..867f0f4b9f6355f1d4e4b3d1498e4daeb77543eb 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/common/search/SearchServiceITCase.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/common/search/SearchServiceITCase.java
@@ -89,7 +89,7 @@ public class SearchServiceITCase {
 		@BeforeEach
 		void init() {
 			Command cmd = CommandTestFactory.createBuilder().build();
-			when(commandService.findCommand(CommandTestFactory.ID)).thenReturn(Optional.of(cmd));
+			when(commandService.findById(CommandTestFactory.ID)).thenReturn(Optional.of(cmd));
 
 			elasticsearchOperations.indexOps(IndexedVorgang.class).delete();
 
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/common/search/SearchServiceTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/common/search/SearchServiceTest.java
index 65228c43a6fffd553c3520cb7d08ab8a0de3c69a..185953de74bc5b83361db559720fb272c8712fe9 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/common/search/SearchServiceTest.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/common/search/SearchServiceTest.java
@@ -80,18 +80,6 @@ class SearchServiceTest {
 		}
 	}
 
-	@DisplayName("Exists by id")
-	@Nested
-	class TestExistsById {
-
-		@Test
-		void shouldCallRepositoryExistsById() {
-			searchService.existsById(VorgangTestFactory.ID);
-
-			verify(repository).existsById(VorgangTestFactory.ID);
-		}
-	}
-
 	@DisplayName("Search")
 	@Nested
 	class TestSearch {
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/common/search/SearchVorgangCustomRepositoryMongoITCase.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/common/search/SearchVorgangCustomRepositoryMongoITCase.java
new file mode 100644
index 0000000000000000000000000000000000000000..751afdf88ad5545f59f9838787490ddfec73a703
--- /dev/null
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/common/search/SearchVorgangCustomRepositoryMongoITCase.java
@@ -0,0 +1,151 @@
+/*
+ * 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.vorgang.common.search;
+
+import static org.awaitility.Awaitility.*;
+
+import java.time.Duration;
+import java.util.Optional;
+
+import org.assertj.core.api.Assertions;
+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.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.data.mongodb.core.MongoOperations;
+import org.springframework.data.mongodb.core.index.IndexInfo;
+
+import de.ozgcloud.common.test.DataITCase;
+import de.ozgcloud.vorgang.vorgang.AntragstellerTestFactory;
+import de.ozgcloud.vorgang.vorgang.EingangTestFactory;
+import de.ozgcloud.vorgang.vorgang.FilterCriteria;
+import de.ozgcloud.vorgang.vorgang.FindVorgangRequest;
+import de.ozgcloud.vorgang.vorgang.Vorgang;
+import de.ozgcloud.vorgang.vorgang.VorgangTestFactory;
+
+@SpringBootTest(properties = { "ozgcloud.mongodbsearch.enabled=true" })
+@DataITCase
+public class SearchVorgangCustomRepositoryMongoITCase {
+
+	@Autowired
+	private SearchVorgangCustomRepositoryMongo repostitory;
+
+	@Autowired
+	private MongoOperations mongoOperations;
+
+	@Nested
+	class TestSpecialCharacters {
+
+		@BeforeEach
+		void init() {
+			await().atMost(Duration.ofSeconds(10)).until(() -> getTextIndex().isPresent());
+			mongoOperations.remove(Vorgang.class).all();
+		}
+
+		@DisplayName("should find vorgang when vorgangName")
+		@ParameterizedTest(name = "contains {0}")
+		@ValueSource(strings = { "_", "+", "-", "=", "&&", "||", "!", "(", ")", "{", "}", "[", "]", "^", "\"", "~", "*", "?", ":", "\\", "/", "<",
+				">", "$", "%", "&", "#", "@" })
+		void shouldFindInVorgangName(String character) {
+			var vorgangName = "AbC%sTest".formatted(character);
+			mongoOperations.save(VorgangTestFactory.createBuilder().name(vorgangName).build());
+
+			var vorgangHeaders = repostitory.searchBy(searchRequest(character));
+
+			Assertions.assertThat(vorgangHeaders.getContent()).hasSize(1).first()
+					.extracting("name").isEqualTo(vorgangName);
+		}
+
+		@Test
+		void shouldFindInVorgangNummer() {
+			mongoOperations.save(VorgangTestFactory.create());
+
+			var vorgangHeaders = repostitory.searchBy(buildSearchRequest("VOR-GANG"));
+
+			Assertions.assertThat(vorgangHeaders.getContent()).hasSize(1).first()
+					.extracting("nummer").isEqualTo(VorgangTestFactory.VORGANG_NUMMER);
+		}
+
+		@Test
+		void shouldFindInAntragstellerName() {
+			var antragsteller = AntragstellerTestFactory.createBuilder().nachname("MusterMann").build();
+			var eingang = EingangTestFactory.createBuilder().antragsteller(antragsteller).build();
+			mongoOperations.save(VorgangTestFactory.createBuilder().clearEingangs().eingang(eingang).build());
+
+			var vorgangHeaders = repostitory.searchBy(buildSearchRequest("mustermann"));
+
+			Assertions.assertThat(vorgangHeaders.getContent()).hasSize(1);
+		}
+
+		@Test
+		void shouldFindInAntragstellerVorname() {
+			var antragsteller = AntragstellerTestFactory.createBuilder().vorname("Alexander").build();
+			var eingang = EingangTestFactory.createBuilder().antragsteller(antragsteller).build();
+			mongoOperations.save(VorgangTestFactory.createBuilder().clearEingangs().eingang(eingang).build());
+
+			var vorgangHeaders = repostitory.searchBy(buildSearchRequest("alexand"));
+
+			Assertions.assertThat(vorgangHeaders.getContent()).hasSize(1);
+		}
+
+		@Test
+		void shouldFindInAktenzeichen() {
+			var foundVorgang = mongoOperations.save(VorgangTestFactory.createBuilder().id(null).aktenzeichen("123-456").build());
+			mongoOperations.save(VorgangTestFactory.createBuilder().id(null).build());
+
+			var vorgangHeaders = repostitory.searchBy(buildSearchRequest("123-"));
+
+			Assertions.assertThat(vorgangHeaders.getContent()).hasSize(1).first().extracting("id").isEqualTo(foundVorgang.getId());
+		}
+
+		@Test
+		void shouldFindInMultipleFields() {
+			var antragsteller = AntragstellerTestFactory.createBuilder().nachname("Müller").build();
+			mongoOperations.save(VorgangTestFactory.createBuilder().id(null).name("Mäuse")
+							.eingang(EingangTestFactory.createBuilder().antragsteller(antragsteller).build())
+							.build(), Vorgang.COLLECTION_NAME);
+
+			var result = repostitory.searchBy(buildSearchRequest("mull mau"));
+
+			Assertions.assertThat(result.getContent()).hasSize(1);
+		}
+
+		private Optional<IndexInfo> getTextIndex() {
+			return mongoOperations.indexOps(Vorgang.COLLECTION_NAME).getIndexInfo().stream()
+					.filter(index -> MongodbFullTextSearchIndexInitializer.TEXT_INDEX_NAME.equals(index.getName())).findFirst();
+		}
+
+		private FindVorgangRequest searchRequest(String character) {
+			return FindVorgangRequest.builder().filterBy(FilterCriteria.builder().build()).searchBy("abc%st".formatted(character)).build();
+		}
+
+		private FindVorgangRequest buildSearchRequest(String searchBy) {
+			return FindVorgangRequest.builder().filterBy(FilterCriteria.builder().build()).searchBy(searchBy).build();
+		}
+	}
+}
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/status/StatusEventListenerITCase.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/status/StatusEventListenerITCase.java
index bb751bec059f5f0bb76e50af39caa5d755a928fe..2b3c260fd811ad45c157eb172fdcd4a20ffae1b2 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/status/StatusEventListenerITCase.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/status/StatusEventListenerITCase.java
@@ -45,7 +45,7 @@ class StatusEventListenerITCase {
 	void init() {
 		when(vorgangService.getById(anyString())).thenReturn(VorgangTestFactory.create());
 
-		when(commandService.findCommand(anyString())).thenReturn(Optional.of(CommandTestFactory.create()));
+		when(commandService.findById(anyString())).thenReturn(Optional.of(CommandTestFactory.create()));
 	}
 
 	@DisplayName("Test creating status events")
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/status/StatusEventListenerTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/status/StatusEventListenerTest.java
index dca80473467488a16fe29282bb80103c4002acfa..91866958ed434e56b7f297e4a8825085802fbb2b 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/status/StatusEventListenerTest.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/status/StatusEventListenerTest.java
@@ -68,7 +68,7 @@ class StatusEventListenerTest {
 		void init() {
 			when(event.getSource()).thenReturn(command);
 			when(vorgangService.getById(any())).thenReturn(VorgangTestFactory.create());
-			when(commandService.findCommand(any())).thenReturn(Optional.of(CommandTestFactory.create()));
+			when(commandService.findById(any())).thenReturn(Optional.of(CommandTestFactory.create()));
 		}
 
 		@Test
@@ -82,7 +82,7 @@ class StatusEventListenerTest {
 		void shouldCallCommandService() {
 			eventListener.abschiessen(event);
 
-			verify(commandService).findCommand(any());
+			verify(commandService).findById(any());
 		}
 
 		@Test
@@ -195,7 +195,7 @@ class StatusEventListenerTest {
 
 		@Test
 		void shouldHandleNoSuchElementException() {
-			when(commandService.findCommand(any())).thenReturn(Optional.empty());
+			when(commandService.findById(any())).thenReturn(Optional.empty());
 			when(vorgangService.getById(any())).thenReturn(VorgangTestFactory.create());
 
 			eventListener.annehmen(CommandCreatedEventTestFactory.create(CommandTestFactory.create()));
diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/GrpcVorgangServiceFindQueryITCase.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/GrpcVorgangServiceFindQueryITCase.java
index e5fcd28b7fe4eff5bbd198103ab8a3a676f9faa7..62a1e5ff733572ad745d2b05b0990a36a9292e25 100644
--- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/GrpcVorgangServiceFindQueryITCase.java
+++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/GrpcVorgangServiceFindQueryITCase.java
@@ -37,8 +37,6 @@ class GrpcVorgangServiceFindQueryITCase {
 
 	private static final String VORGAENGE_WITH_UNGELESENE_NACHRICHTEN_PATH = "ClientAttribute.OzgCloud_NachrichtenManager.hasNewPostfachNachricht";
 
-	@Autowired
-	private VorgangHeaderRepository repository;
 	@Autowired
 	private MongoOperations mongoOperations;
 
@@ -72,7 +70,8 @@ class GrpcVorgangServiceFindQueryITCase {
 				GrpcQuery.newBuilder()
 						.addExpressions(GrpcVorgangQueryExpression.newBuilder()
 								.setOperator(GrpcQueryOperator.EXISTS)
-								.setPath("ClientAttribute.%s.nextWiedervorlageFrist".formatted(CriteriaUtil.DEFAULT_CLIENT)))).build();
+								.setPath("ClientAttribute.%s.nextWiedervorlageFrist".formatted(CriteriaUtil.DEFAULT_CLIENT))))
+				.build();
 
 		var result = vorgangServiceStub.findVorgang(request);
 
@@ -108,8 +107,7 @@ class GrpcVorgangServiceFindQueryITCase {
 						.addExpressions(GrpcVorgangQueryExpression.newBuilder()
 								.setOperator(GrpcQueryOperator.LESS_THEN_OR_EQUAL_TO)
 								.setPath("Vorgang." + Vorgang.MONGODB_FIELDNAME_CREATED_AT)
-								.setOperandStringValue(VorgangTestFactory.CREATED_AT.toString()))
-				)
+								.setOperandStringValue(VorgangTestFactory.CREATED_AT.toString())))
 				.build();
 
 		var result = vorgangServiceStub.findVorgang(request);
diff --git a/vorgang-manager-utils/pom.xml b/vorgang-manager-utils/pom.xml
index 538d56028531189daa140542a6e5d3a58d70ed6a..a5a9d10d8b83fd072be371a5ffca85413d9aee0d 100644
--- a/vorgang-manager-utils/pom.xml
+++ b/vorgang-manager-utils/pom.xml
@@ -30,14 +30,14 @@
 	<parent>
 		<groupId>de.ozgcloud.common</groupId>
 		<artifactId>ozgcloud-common-dependencies</artifactId>
-		<version>4.2.0</version>
+		<version>4.3.1</version>
 		<relativePath/>
 	</parent>
 
 	<groupId>de.ozgcloud.vorgang</groupId>
 	<artifactId>vorgang-manager-utils</artifactId>
 	<name>OZG-Cloud Vorgang Manager Utils</name>
-	<version>2.10.0-SNAPSHOT</version>
+	<version>2.11.0</version>
 
 	<properties>
 		<maven-compiler-plugin.version>3.10.1</maven-compiler-plugin.version>
diff --git a/vorgang-manager-utils/src/main/java/de/ozgcloud/vorgang/common/grpc/FormDataMappingUtils.java b/vorgang-manager-utils/src/main/java/de/ozgcloud/vorgang/common/grpc/FormDataMappingUtils.java
index e2d04eb7aa6802d558e320c719f574a1fd27c142..26ce9a4bfd51d6599523467afd695711263b441f 100644
--- a/vorgang-manager-utils/src/main/java/de/ozgcloud/vorgang/common/grpc/FormDataMappingUtils.java
+++ b/vorgang-manager-utils/src/main/java/de/ozgcloud/vorgang/common/grpc/FormDataMappingUtils.java
@@ -9,6 +9,7 @@ import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
+import java.util.function.Predicate;
 
 import org.apache.commons.collections.MapUtils;
 import org.apache.commons.lang3.tuple.Pair;
@@ -17,6 +18,11 @@ import de.ozgcloud.vorgang.vorgang.GrpcFormField;
 
 class FormDataMappingUtils {
 
+	private static final Predicate<Object> IS_VALUE = obj -> obj instanceof String
+			|| obj instanceof Number
+			|| obj instanceof LocalDate
+			|| obj instanceof Boolean;
+
 	static final String VALUE_KEY = "value";
 	static final String LABEL_KEY = "label";
 	static final String CONTROL_DATA_KEY = "controlData";
@@ -72,13 +78,9 @@ class FormDataMappingUtils {
 
 	static boolean isValue(Object value) {
 		if (value instanceof Map<?, ?> valueMap) {
-			return valueMap.containsKey(VALUE_KEY) &&
-					(valueMap.get(VALUE_KEY) instanceof String
-							|| valueMap.get(VALUE_KEY) instanceof Number
-							|| valueMap.get(VALUE_KEY) instanceof LocalDate
-							|| valueMap.get(VALUE_KEY) instanceof Boolean);
+			return valueMap.containsKey(VALUE_KEY) && IS_VALUE.test(valueMap.get(VALUE_KEY));
 		} else {
-			return value instanceof String;
+			return IS_VALUE.test(value);
 		}
 	}
 
diff --git a/vorgang-manager-utils/src/test/java/de/ozgcloud/vorgang/common/grpc/GrpcFormDataMapperTest.java b/vorgang-manager-utils/src/test/java/de/ozgcloud/vorgang/common/grpc/GrpcFormDataMapperTest.java
index 3e9143321168141832df7261dc8b3069c5606acb..7694a8c144e0af1fd16d10ad76accb914103e471 100644
--- a/vorgang-manager-utils/src/test/java/de/ozgcloud/vorgang/common/grpc/GrpcFormDataMapperTest.java
+++ b/vorgang-manager-utils/src/test/java/de/ozgcloud/vorgang/common/grpc/GrpcFormDataMapperTest.java
@@ -115,6 +115,13 @@ class GrpcFormDataMapperTest {
 
 				assertThat(grpcField.getLabel()).isEqualTo(FIELD_LABEL);
 			}
+
+			@Test
+			void shouldHaveNumeric() {
+				var grpcField = mapper.mapToField(FIELD_NAME, Map.of(VALUE_KEY, 42, LABEL_KEY, FIELD_LABEL));
+
+				assertThat(grpcField.getValue()).isEqualTo("42");
+			}
 		}
 	}
 
@@ -167,7 +174,6 @@ class GrpcFormDataMapperTest {
 
 		@Test
 		void shouldHaveSubFormField() {
-
 			GrpcFormData formData = mapper.mapToFormData(Map.of("key", Map.of("subKey", "value")));
 
 			assertThat(formData.getForm(0).getFieldList()).hasSize(1);
@@ -175,6 +181,15 @@ class GrpcFormDataMapperTest {
 			assertThat(formData.getForm(0).getField(0).getName()).isEqualTo("subKey");
 			assertThat(formData.getForm(0).getField(0).getValue()).isEqualTo("value");
 		}
+
+		@Test
+		void shouldHaveNumericSubFormField() {
+			GrpcFormData formData = mapper.mapToFormData(Map.of("key", Map.of("subKey", 42)));
+
+			assertThat(formData.getForm(0).getFieldList()).hasSize(1);
+			assertThat(formData.getForm(0).getField(0).getValue()).isEqualTo("42");
+		}
+
 	}
 
 	@DisplayName("Mapped SubFormField")