diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/bescheid/BescheidHistorieProcessor.java b/alfa-service/src/main/java/de/ozgcloud/alfa/bescheid/BescheidHistorieProcessor.java
index 06f71be59ea10d9874401bf59c538229ca3d18f7..bc3ba70897c28c7f9780b87f85d69ce126f3f5fd 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/bescheid/BescheidHistorieProcessor.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/bescheid/BescheidHistorieProcessor.java
@@ -26,6 +26,7 @@ package de.ozgcloud.alfa.bescheid;
 import java.util.Comparator;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.function.Predicate;
 import java.util.stream.Stream;
 
@@ -48,43 +49,34 @@ class BescheidHistorieProcessor implements HistorieProcessor {
 
 	private final VorgangAttachedItemService vorgangAttachedItemService;
 
-	private static final Predicate<Command> IS_NOT_CREATE_BESCHEID_COMMAND = Predicate
-			.not(command -> command.getCommandOrder() == CommandOrder.CREATE_BESCHEID);
-	private static final Predicate<Command> IS_NOT_DELETE_BESCHEID_COMMAND = Predicate
-			.not(command -> command.getCommandOrder() == CommandOrder.DELETE_BESCHEID);
-	private static final Predicate<Command> IS_UPDATE_BESCHEID_COMMAND = command -> command.getCommandOrder() == CommandOrder.UPDATE_BESCHEID;
+	private static final Set<CommandOrder> BESCHEID_ORDER_TO_REMOVE = Set.of(CommandOrder.CREATE_BESCHEID, CommandOrder.DELETE_BESCHEID);
+	private static final Predicate<Command> IS_NOT_BESCHEID_ORDER_TO_REMOVE = Predicate
+			.not(command -> BESCHEID_ORDER_TO_REMOVE.contains(command.getCommandOrder()));
 
+	private static final Set<CommandOrder> VORGANG_ATTACHED_ITEM_ORDER_TO_REMOVE = Set.of(CommandOrder.CREATE_ATTACHED_ITEM,
+			CommandOrder.UPDATE_ATTACHED_ITEM, CommandOrder.PATCH_ATTACHED_ITEM);
 	private static final Predicate<Command> IS_BESCHEID_ATTACHED_ITEM = command -> BESCHEID_ITEM_NAME
 			.equals(MapUtils.getString(command.getBody(), VorgangAttachedItem.FIELD_ITEM_NAME, StringUtils.EMPTY));
-	private static final Predicate<Command> IS_NOT_CREATE_ATTACHED_ITEM = Predicate
-			.not(command -> command.getCommandOrder() == CommandOrder.CREATE_ATTACHED_ITEM
-					&& IS_BESCHEID_ATTACHED_ITEM.test(command));
-	private static final Predicate<Command> IS_NOT_UPDATE_ATTACHED_ITEM = Predicate
-			.not(command -> command.getCommandOrder() == CommandOrder.UPDATE_ATTACHED_ITEM
-					&& IS_BESCHEID_ATTACHED_ITEM.test(command));
-	private static final Predicate<Command> IS_NOT_PATCH_ATTACHED_ITEM = Predicate
-			.not(command -> command.getCommandOrder() == CommandOrder.PATCH_ATTACHED_ITEM
-					&& IS_BESCHEID_ATTACHED_ITEM.test(command));
+	private static final Predicate<Command> IS_NOT_VORGANG_ATTACHED_BESCHEID_ITEM_ORDER_TO_REMOVE = Predicate
+			.not(command -> VORGANG_ATTACHED_ITEM_ORDER_TO_REMOVE.contains(command.getCommandOrder()) && IS_BESCHEID_ATTACHED_ITEM.test(command));
+
+	private static final Predicate<Command> IS_UPDATE_BESCHEID_COMMAND = command -> command.getCommandOrder() == CommandOrder.UPDATE_BESCHEID;
 
 	@Override
-	public List<Command> process(List<Command> commands) {
-		var relevantCommands = filterByOrder(commands);
+	public Stream<Command> process(Stream<Command> commands) {
+		var relevantCommands = filterByOrder(commands).toList();
 		return filterBescheidRelatedCommands(relevantCommands);
 	}
 
-	List<Command> filterByOrder(List<Command> commands) {
-		return commands.stream()
-				.filter(IS_NOT_CREATE_BESCHEID_COMMAND)
-				.filter(IS_NOT_DELETE_BESCHEID_COMMAND)
-				.filter(IS_NOT_CREATE_ATTACHED_ITEM)
-				.filter(IS_NOT_UPDATE_ATTACHED_ITEM)
-				.filter(IS_NOT_PATCH_ATTACHED_ITEM)
-				.toList();
+	Stream<Command> filterByOrder(Stream<Command> commands) {
+		return commands
+				.filter(IS_NOT_BESCHEID_ORDER_TO_REMOVE)
+				.filter(IS_NOT_VORGANG_ATTACHED_BESCHEID_ITEM_ORDER_TO_REMOVE);
 	}
 
-	List<Command> filterBescheidRelatedCommands(List<Command> commands) {
+	Stream<Command> filterBescheidRelatedCommands(List<Command> commands) {
 		var excludeCommandIds = getExcludedBescheidRelatedCommandIds(commands);
-		return commands.stream().filter(command -> !excludeCommandIds.contains(command.getId())).toList();
+		return commands.stream().filter(command -> !excludeCommandIds.contains(command.getId()));
 	}
 
 	List<String> getExcludedBescheidRelatedCommandIds(List<Command> commands) {
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/bescheid/DocumentHistorieProcessor.java b/alfa-service/src/main/java/de/ozgcloud/alfa/bescheid/DocumentHistorieProcessor.java
index 028aa66f2141bf2084692ef4ca20904a5edc709d..616c96c686d2344d4199ca1158960aa892842ef7 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/bescheid/DocumentHistorieProcessor.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/bescheid/DocumentHistorieProcessor.java
@@ -23,8 +23,8 @@
  */
 package de.ozgcloud.alfa.bescheid;
 
-import java.util.List;
 import java.util.function.Predicate;
+import java.util.stream.Stream;
 
 import org.apache.commons.collections.MapUtils;
 import org.apache.commons.lang3.StringUtils;
@@ -47,15 +47,16 @@ class DocumentHistorieProcessor implements HistorieProcessor {
 
 	private static final Predicate<Command> IS_DOCUMENT_ATTACHED_ITEM = command -> DOCUMENT_ITEM_NAME
 			.equals(MapUtils.getString(command.getBody(), VorgangAttachedItem.FIELD_ITEM_NAME, StringUtils.EMPTY));
-	private static final Predicate<Command> IS_NOT_CREATE_ATTACHED_ITEM = command -> !(command.getCommandOrder() == CommandOrder.CREATE_ATTACHED_ITEM
+	private static final Predicate<Command> IS_NOT_CREATE_ATTACHED_DOCUMENT_ITEM = command -> !(command
+			.getCommandOrder() == CommandOrder.CREATE_ATTACHED_ITEM
 			&& IS_DOCUMENT_ATTACHED_ITEM.test(command));
 
 	@Override
-	public List<Command> process(List<Command> commands) {
+	public Stream<Command> process(Stream<Command> commands) {
 		return filterIrrelevantCommands(commands);
 	}
 
-	List<Command> filterIrrelevantCommands(List<Command> commands) {
-		return commands.stream().filter(IS_NOT_DOCUMENT_COMMAND).filter(IS_NOT_CREATE_ATTACHED_ITEM).toList();
+	Stream<Command> filterIrrelevantCommands(Stream<Command> commands) {
+		return commands.filter(IS_NOT_DOCUMENT_COMMAND).filter(IS_NOT_CREATE_ATTACHED_DOCUMENT_ITEM);
 	}
 }
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/common/attacheditem/VorgangAttachedItemHistorieProcessor.java b/alfa-service/src/main/java/de/ozgcloud/alfa/common/attacheditem/VorgangAttachedItemHistorieProcessor.java
new file mode 100644
index 0000000000000000000000000000000000000000..ecbd3482e02823170ba6c0bfcb1b3a737fcabba7
--- /dev/null
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/common/attacheditem/VorgangAttachedItemHistorieProcessor.java
@@ -0,0 +1,22 @@
+package de.ozgcloud.alfa.common.attacheditem;
+
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+
+import org.springframework.stereotype.Component;
+
+import de.ozgcloud.alfa.common.command.Command;
+import de.ozgcloud.alfa.common.command.CommandOrder;
+import de.ozgcloud.alfa.historie.HistorieProcessor;
+
+@Component
+class VorgangAttachedItemHistorieProcessor implements HistorieProcessor {
+
+	private static final Predicate<Command> IS_NOT_DELETE_ATTACHED_ITEM = command -> CommandOrder.DELETE_ATTACHED_ITEM != command.getCommandOrder();
+
+	@Override
+	public Stream<Command> process(Stream<Command> commands) {
+		return commands.filter(IS_NOT_DELETE_ATTACHED_ITEM);
+	}
+
+}
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/historie/HistorieCommandHandler.java b/alfa-service/src/main/java/de/ozgcloud/alfa/historie/HistorieCommandHandler.java
deleted file mode 100644
index 3da6312c0c7c5787c74fad6a9ba7270db2e15c52..0000000000000000000000000000000000000000
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/historie/HistorieCommandHandler.java
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * 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.
- */
-package de.ozgcloud.alfa.historie;
-
-import java.util.Map;
-import java.util.Optional;
-import java.util.function.Predicate;
-
-import org.apache.commons.collections.MapUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-
-import de.ozgcloud.alfa.common.attacheditem.VorgangAttachedItem;
-import de.ozgcloud.alfa.common.attacheditem.VorgangAttachedItemService;
-import de.ozgcloud.alfa.common.command.Command;
-import de.ozgcloud.alfa.common.command.CommandBodyMapper;
-import de.ozgcloud.alfa.common.command.CommandOrder;
-import de.ozgcloud.alfa.common.command.CommandService;
-import de.ozgcloud.alfa.common.command.CommandStatus;
-import de.ozgcloud.alfa.common.command.LegacyOrder;
-import de.ozgcloud.alfa.kommentar.Kommentar;
-import de.ozgcloud.alfa.loeschanforderung.DeleteLoeschAnforderung;
-import de.ozgcloud.alfa.wiedervorlage.Wiedervorlage;
-
-/**
- * Bitte zukuenftig als Implementierung von {@link HistorieProcessor} in den
- * jeweiligen fachlichen packages umsetzen.
- *
- * TODO: Aktuellen Code auf Processoren umstellen
- */
-@Component
-class HistorieCommandHandler {
-
-	static final String DIRECTION_INCOMMING = "IN";
-	static final String DIRECTION_OUTGOING = "OUT";
-	static final String DIRECTION = "direction";
-	static final String OZGCLOUD_NACHRICHTEN_MANAGER = "OzgCloud_NachrichtenManager";
-	static final String CLIENT = "client";
-
-	private static final Predicate<Command> IS_CREATE_ATTACHED_ITEM = command -> command.getCommandOrder() == CommandOrder.CREATE_ATTACHED_ITEM;
-
-	@Autowired
-	private VorgangAttachedItemService vorgangAttachedItemService;
-
-	@Autowired
-	private CommandService commandService;
-
-	public boolean isHistorieCommand(Command command) {
-		return !isOutgoingPostfachNachrichtByOzgCloudNachrichtenManager(command)
-				&& !isCreateLoeschAnforderungVorgangAttachedItem(command)
-				&& !isLoeschAnforderungZuruecknehmenRevoked(command)
-				&& !isDeleteVorgangAttachedItem(command);
-	}
-
-	boolean isOutgoingPostfachNachrichtByOzgCloudNachrichtenManager(Command command) {
-		return command.getCommandOrder().equals(CommandOrder.CREATE_ATTACHED_ITEM) && isOzgCloudNachrichtenManager(command) && isOutgoing(command);
-	}
-
-	private boolean isOzgCloudNachrichtenManager(Command command) {
-		return StringUtils.equals(MapUtils.getString(command.getBody(), CLIENT), OZGCLOUD_NACHRICHTEN_MANAGER);
-	}
-
-	private boolean isOutgoing(Command command) {
-		return isDirection(command, DIRECTION_OUTGOING);
-	}
-
-	boolean isCreateLoeschAnforderungVorgangAttachedItem(Command command) {
-		return Optional.of(command)
-				.filter(IS_CREATE_ATTACHED_ITEM)
-				.map(Command::getBody)
-				.map(bodyMap -> MapUtils.getString(bodyMap, VorgangAttachedItem.FIELD_ITEM_NAME))
-				.map(vorgangAttachedItemService::isLoeschAnforderung)
-				.orElse(false);
-	}
-
-	boolean isLoeschAnforderungZuruecknehmenRevoked(Command command) {
-		if (command.getCommandOrder() != CommandOrder.LOESCH_ANFORDERUNG_ZURUECKNEHMEN) {
-			return false;
-		}
-		var changeStatusCommand = commandService.getById(getChangeStatusCommandId(command));
-		return changeStatusCommand.getStatus() == CommandStatus.REVOKED;
-	}
-
-	private String getChangeStatusCommandId(Command command) {
-		return MapUtils.getString(command.getBody(), DeleteLoeschAnforderung.CHANGE_STATUS_COMMAND_ID_FIELD);
-	}
-
-	boolean isDeleteVorgangAttachedItem(Command command) {
-		return command.getCommandOrder() == CommandOrder.DELETE_ATTACHED_ITEM;
-	}
-
-	public Command translateOrder(Command command) {
-		HistorieCommandHandler translator = new HistorieCommandHandler();
-		return switch (command.getCommandOrder()) {
-			case CREATE_ATTACHED_ITEM:
-				yield translator.mapCreateOrder(command);
-			case UPDATE_ATTACHED_ITEM:
-				yield translator.mapUpdateOrder(command);
-			case PATCH_ATTACHED_ITEM:
-				yield translator.mapPatchOrder(command);
-			case SEND_POSTFACH_MAIL:
-				yield command.toBuilder().order(CommandOrder.SEND_POSTFACH_NACHRICHT.name()).build();
-			default:
-				yield command;
-		};
-	}
-
-	private Command mapCreateOrder(Command command) {
-		var resultBuilder = command.toBuilder();
-		var itemName = getItemName(command);
-
-		itemName.ifPresent(name -> {
-			if (name.equals(Kommentar.class.getSimpleName())) {
-				resultBuilder.order(LegacyOrder.CREATE_KOMMENTAR).build();
-			} else if (name.equals(Wiedervorlage.class.getSimpleName())) {
-				resultBuilder.order(LegacyOrder.CREATE_WIEDERVORLAGE).build();
-			} else if (isOzgCloudNachrichtenManager(command) && isIncomming(command)) {
-				resultBuilder.order(CommandOrder.RECEIVE_POSTFACH_NACHRICHT.name()).build();
-			}
-		});
-
-		return resultBuilder.build();
-	}
-
-	private boolean isIncomming(Command command) {
-		return isDirection(command, DIRECTION_INCOMMING);
-	}
-
-	private boolean isDirection(Command command, String expectedDirection) {
-		return StringUtils.equals(MapUtils.getString(getItemMap(command), DIRECTION), expectedDirection);
-	}
-
-	private Command mapUpdateOrder(Command command) {
-		var resultBuilder = command.toBuilder();
-		var itemName = getItemName(command);
-
-		itemName.ifPresent(name -> {
-			if (name.equals(Kommentar.class.getSimpleName())) {
-				resultBuilder.order(LegacyOrder.EDIT_KOMMENTAR).build();
-			} else if (name.equals(Wiedervorlage.class.getSimpleName())) {
-				resultBuilder.order(LegacyOrder.EDIT_WIEDERVORLAGE).build();
-			}
-		});
-
-		return resultBuilder.build();
-	}
-
-	private Optional<String> getItemName(Command command) {
-		return Optional.ofNullable(MapUtils.getString(command.getBody(), CommandBodyMapper.ITEM_NAME_PROPERTY));
-	}
-
-	private Command mapPatchOrder(Command command) {
-		var resultBuilder = command.toBuilder();
-		var isDone = getDoneValue(command);
-
-		isDone.ifPresent(done -> {
-			if (done.booleanValue()) {
-				resultBuilder.order(LegacyOrder.WIEDERVORLAGE_ERLEDIGEN).build();
-			} else {
-				resultBuilder.order(LegacyOrder.WIEDERVORLAGE_WIEDEREROEFFNEN).build();
-			}
-		});
-
-		return resultBuilder.build();
-	}
-
-	private Optional<Boolean> getDoneValue(Command command) {
-		return Optional.ofNullable(MapUtils.getBoolean(getItemMap(command), Wiedervorlage.DONE_FIELD));
-	}
-
-	@SuppressWarnings("unchecked")
-	private Map<String, Object> getItemMap(Command command) {
-		return MapUtils.getMap(command.getBody(), CommandBodyMapper.ITEM_PROPERTY);
-	}
-}
\ No newline at end of file
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/historie/HistorieProcessor.java b/alfa-service/src/main/java/de/ozgcloud/alfa/historie/HistorieProcessor.java
index e28cb6a96dcc9748fafd419e0acd4e5ec6b7e815..ce40562ed12f1396c40839dbb837130e1b636915 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/historie/HistorieProcessor.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/historie/HistorieProcessor.java
@@ -23,11 +23,11 @@
  */
 package de.ozgcloud.alfa.historie;
 
-import java.util.List;
+import java.util.stream.Stream;
 
 import de.ozgcloud.alfa.common.command.Command;
 
 public interface HistorieProcessor {
 
-	List<Command> process(List<Command> commands);
+	Stream<Command> process(Stream<Command> commands);
 }
\ No newline at end of file
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/historie/HistorieService.java b/alfa-service/src/main/java/de/ozgcloud/alfa/historie/HistorieService.java
index 28cf9b859c1b07fb16971ac69715067da0872691..89cee62e20fe8102680db68687af819b1df58bc2 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/historie/HistorieService.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/historie/HistorieService.java
@@ -23,18 +23,13 @@
  */
 package de.ozgcloud.alfa.historie;
 
-import java.util.HashSet;
 import java.util.List;
-import java.util.Set;
 import java.util.stream.Stream;
 
-import org.apache.commons.collections.MapUtils;
 import org.springframework.stereotype.Service;
 
 import de.ozgcloud.alfa.common.command.Command;
-import de.ozgcloud.alfa.common.command.CommandOrder;
 import de.ozgcloud.alfa.common.command.CommandService;
-import de.ozgcloud.alfa.loeschanforderung.DeleteLoeschAnforderung;
 import lombok.RequiredArgsConstructor;
 
 @RequiredArgsConstructor
@@ -42,55 +37,17 @@ import lombok.RequiredArgsConstructor;
 class HistorieService {
 
 	private final CommandService commandService;
-	private final HistorieCommandHandler historieCommandHandler;
 	private final List<HistorieProcessor> processors;
 
 	public Stream<Command> findFinishedCommands(String vorgangId) {
-		var reduceBy = new HashSet<String>();
-		var commands = commandService.findFinishedCommands(vorgangId)
-				.filter(historieCommandHandler::isHistorieCommand)
-				.map(command -> considerReduceByIds(reduceBy, command))
-				.map(historieCommandHandler::translateOrder).toList();
-
-		commands = commands.stream().filter(command -> !reduceBy.contains(command.getId()))
-				.toList();
+		var commands = commandService.findFinishedCommands(vorgangId);
 		return processCommands(commands);
 	}
 
-	private Stream<Command> processCommands(List<Command> commands) {
-		return new CommandHistorieProcessor().process(commands).stream();
-	}
-
-	class CommandHistorieProcessor {
-		private List<Command> processedCommands;
-
-		public List<Command> process(List<Command> commands) {
-			processedCommands = commands;
-			processors.forEach(processor -> processedCommands = processor.process(processedCommands));
-			return processedCommands;
-		}
-	}
-
-	private Command considerReduceByIds(Set<String> reduceBy, Command command) {
-		if (isLoeschAnforderungZuruecknehmenCommand(command)) {
-			reduceBy.addAll(getCommandBodyIds(command));
+	Stream<Command> processCommands(Stream<Command> commands) {
+		for (var processor : processors) {
+			commands = processor.process(commands);
 		}
-		return command;
-	}
-
-	private boolean isLoeschAnforderungZuruecknehmenCommand(Command command) {
-		return command.getCommandOrder() == CommandOrder.LOESCH_ANFORDERUNG_ZURUECKNEHMEN;
-	}
-
-	private Set<String> getCommandBodyIds(Command command) {
-		return Set.of(getDeleteAttachedItemCommandId(command), getChangeStatusCommandId(command));
-	}
-
-	private String getDeleteAttachedItemCommandId(Command command) {
-		return MapUtils.getString(command.getBody(), DeleteLoeschAnforderung.DELETE_ATTACHED_ITEM_COMMAND_ID_FIELD);
-	}
-
-	private String getChangeStatusCommandId(Command command) {
-		return MapUtils.getString(command.getBody(), DeleteLoeschAnforderung.CHANGE_STATUS_COMMAND_ID_FIELD);
+		return commands;
 	}
 }
\ No newline at end of file
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/kommentar/KommentarHistorieProcessor.java b/alfa-service/src/main/java/de/ozgcloud/alfa/kommentar/KommentarHistorieProcessor.java
new file mode 100644
index 0000000000000000000000000000000000000000..06eda922582db8ab01d599e3f99db3aeca1ca2ac
--- /dev/null
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/kommentar/KommentarHistorieProcessor.java
@@ -0,0 +1,53 @@
+package de.ozgcloud.alfa.kommentar;
+
+import java.util.Optional;
+import java.util.stream.Stream;
+
+import org.apache.commons.collections.MapUtils;
+import org.springframework.stereotype.Component;
+
+import de.ozgcloud.alfa.common.command.Command;
+import de.ozgcloud.alfa.common.command.CommandBodyMapper;
+import de.ozgcloud.alfa.common.command.CommandOrder;
+import de.ozgcloud.alfa.common.command.LegacyOrder;
+import de.ozgcloud.alfa.historie.HistorieProcessor;
+
+@Component
+class KommentarHistorieProcessor implements HistorieProcessor {
+
+	@Override
+	public Stream<Command> process(Stream<Command> commands) {
+		return commands.map(this::translateCreateKommentar).map(this::translateEditKommentar);
+	}
+
+	Command translateCreateKommentar(Command command) {
+		if (isCreateAttachedItemCommand(command) && hasKommentarItemName(command)) {
+			return command.toBuilder().order(LegacyOrder.CREATE_KOMMENTAR).build();
+		}
+		return command;
+	}
+
+	private boolean isCreateAttachedItemCommand(Command command) {
+		return CommandOrder.CREATE_ATTACHED_ITEM == command.getCommandOrder();
+	}
+
+	Command translateEditKommentar(Command command) {
+		if (isUpdateAttachedItemCommand(command) && hasKommentarItemName(command)) {
+			return command.toBuilder().order(LegacyOrder.EDIT_KOMMENTAR).build();
+		}
+		return command;
+	}
+
+	private boolean isUpdateAttachedItemCommand(Command command) {
+		return CommandOrder.UPDATE_ATTACHED_ITEM == command.getCommandOrder();
+	}
+
+	private boolean hasKommentarItemName(Command command) {
+		return getItemName(command).filter(itemName -> Kommentar.class.getSimpleName().equals(itemName)).isPresent();
+	}
+
+	private Optional<String> getItemName(Command command) {
+		return Optional.ofNullable(MapUtils.getString(command.getBody(), CommandBodyMapper.ITEM_NAME_PROPERTY));
+	}
+
+}
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungHistorieProcessor.java b/alfa-service/src/main/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungHistorieProcessor.java
new file mode 100644
index 0000000000000000000000000000000000000000..45ecd8907c4844361a93f6f33b031172d2834e95
--- /dev/null
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungHistorieProcessor.java
@@ -0,0 +1,80 @@
+package de.ozgcloud.alfa.loeschanforderung;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.stream.Stream;
+
+import org.apache.commons.collections.MapUtils;
+import org.springframework.stereotype.Component;
+
+import de.ozgcloud.alfa.common.attacheditem.VorgangAttachedItem;
+import de.ozgcloud.alfa.common.attacheditem.VorgangAttachedItemService;
+import de.ozgcloud.alfa.common.command.Command;
+import de.ozgcloud.alfa.common.command.CommandOrder;
+import de.ozgcloud.alfa.common.command.CommandService;
+import de.ozgcloud.alfa.common.command.CommandStatus;
+import de.ozgcloud.alfa.historie.HistorieProcessor;
+import lombok.RequiredArgsConstructor;
+
+@Component
+@RequiredArgsConstructor
+class LoeschAnforderungHistorieProcessor implements HistorieProcessor {
+
+	private final CommandService commandService;
+	private final VorgangAttachedItemService vorgangAttachedItemService;
+
+	@Override
+	public Stream<Command> process(Stream<Command> commands) {
+		var commandIdsToRemove = new HashSet<String>();
+		var reducedCommands = commands.filter(this::isNotRevokedLoeschAnforderungZuruecknehmen)
+				.filter(this::isNotCreateLoeschAnforderungVorgangAttachedItem)
+				.map(command -> addLoeschAnforderungZuruecknehmenRelatedCommandIds(commandIdsToRemove, command))
+				.toList();
+		return reducedCommands.stream()
+				.filter(command -> !commandIdsToRemove.contains(command.getId()));
+	}
+
+	boolean isNotRevokedLoeschAnforderungZuruecknehmen(Command command) {
+		if (!isLoeschAnforderungZuruecknehmen(command)) {
+			return true;
+		}
+		var changeStatusCommand = commandService.getById(getChangeStatusCommandId(command));
+		return CommandStatus.REVOKED != changeStatusCommand.getStatus();
+	}
+
+	boolean isNotCreateLoeschAnforderungVorgangAttachedItem(Command command) {
+		if (!isCreateAttachedItem(command)) {
+			return true;
+		}
+		return !vorgangAttachedItemService.isLoeschAnforderung(MapUtils.getString(command.getBody(), VorgangAttachedItem.FIELD_ITEM_NAME));
+	}
+
+	private boolean isCreateAttachedItem(Command command) {
+		return CommandOrder.CREATE_ATTACHED_ITEM.equals(command.getCommandOrder());
+	}
+
+	Command addLoeschAnforderungZuruecknehmenRelatedCommandIds(Set<String> commandIdsToRemove, Command command) {
+		if (isLoeschAnforderungZuruecknehmen(command)) {
+			commandIdsToRemove.addAll(getCommandBodyIds(command));
+		}
+		return command;
+	}
+
+	private boolean isLoeschAnforderungZuruecknehmen(Command command) {
+		return CommandOrder.LOESCH_ANFORDERUNG_ZURUECKNEHMEN.equals(command.getCommandOrder());
+
+	}
+
+	private Set<String> getCommandBodyIds(Command command) {
+		return Set.of(getDeleteAttachedItemCommandId(command), getChangeStatusCommandId(command));
+	}
+
+	private String getDeleteAttachedItemCommandId(Command command) {
+		return MapUtils.getString(command.getBody(), DeleteLoeschAnforderung.DELETE_ATTACHED_ITEM_COMMAND_ID_FIELD);
+	}
+
+	String getChangeStatusCommandId(Command command) {
+		return MapUtils.getString(command.getBody(), DeleteLoeschAnforderung.CHANGE_STATUS_COMMAND_ID_FIELD);
+	}
+
+}
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/PostfachNachrichtHistorieProcessor.java b/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/PostfachNachrichtHistorieProcessor.java
new file mode 100644
index 0000000000000000000000000000000000000000..6af60c857ed773039bb1f5c86f2e29850e834a7d
--- /dev/null
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/PostfachNachrichtHistorieProcessor.java
@@ -0,0 +1,78 @@
+package de.ozgcloud.alfa.postfach;
+
+import java.util.Map;
+import java.util.stream.Stream;
+
+import org.apache.commons.collections.MapUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Component;
+
+import de.ozgcloud.alfa.common.command.Command;
+import de.ozgcloud.alfa.common.command.CommandBodyMapper;
+import de.ozgcloud.alfa.common.command.CommandOrder;
+import de.ozgcloud.alfa.historie.HistorieProcessor;
+
+@Component
+class PostfachNachrichtHistorieProcessor implements HistorieProcessor {
+
+	static final String DIRECTION_INCOMMING = "IN";
+	static final String DIRECTION_OUTGOING = "OUT";
+	static final String DIRECTION = "direction";
+	static final String OZGCLOUD_NACHRICHTEN_MANAGER = "OzgCloud_NachrichtenManager";
+	static final String CLIENT = "client";
+
+	@Override
+	public Stream<Command> process(Stream<Command> commands) {
+		return commands
+				.filter(this::isNotOutgoingPostfachNachrichtByNachrichtenManager)
+				.map(this::translateSendPostfachMailCommand)
+				.map(this::translateReceivePostfachNachrichtCommand);
+	}
+
+	boolean isNotOutgoingPostfachNachrichtByNachrichtenManager(Command command) {
+		return !(isCreateAttachedItem(command) && isOzgCloudNachrichtenManager(command) && isOutgoing(command));
+	}
+
+	private boolean isOutgoing(Command command) {
+		return isDirection(command, DIRECTION_OUTGOING);
+	}
+
+	public Command translateSendPostfachMailCommand(Command command) {
+		if (CommandOrder.SEND_POSTFACH_MAIL == command.getCommandOrder()) {
+			return command.toBuilder().order(CommandOrder.SEND_POSTFACH_NACHRICHT.name()).build();
+		}
+		return command;
+	}
+
+	public Command translateReceivePostfachNachrichtCommand(Command command) {
+		if (isIncomingNachrichtByNachrichtenManager(command)) {
+			return command.toBuilder().order(CommandOrder.RECEIVE_POSTFACH_NACHRICHT.name()).build();
+		}
+		return command;
+	}
+
+	boolean isIncomingNachrichtByNachrichtenManager(Command command) {
+		return isCreateAttachedItem(command) && isOzgCloudNachrichtenManager(command) && isIncomming(command);
+	}
+
+	private boolean isCreateAttachedItem(Command command) {
+		return command.getCommandOrder().equals(CommandOrder.CREATE_ATTACHED_ITEM);
+	}
+
+	private boolean isOzgCloudNachrichtenManager(Command command) {
+		return StringUtils.equals(MapUtils.getString(command.getBody(), CLIENT), OZGCLOUD_NACHRICHTEN_MANAGER);
+	}
+
+	private boolean isIncomming(Command command) {
+		return isDirection(command, DIRECTION_INCOMMING);
+	}
+
+	private boolean isDirection(Command command, String expectedDirection) {
+		return StringUtils.equals(MapUtils.getString(getItemMap(command), DIRECTION), expectedDirection);
+	}
+
+	@SuppressWarnings("unchecked")
+	private Map<String, Object> getItemMap(Command command) {
+		return MapUtils.getMap(command.getBody(), CommandBodyMapper.ITEM_PROPERTY);
+	}
+}
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageHistorieProcessor.java b/alfa-service/src/main/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageHistorieProcessor.java
new file mode 100644
index 0000000000000000000000000000000000000000..352b53f04707694244b3eef02d1062a70e8ad52c
--- /dev/null
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageHistorieProcessor.java
@@ -0,0 +1,88 @@
+package de.ozgcloud.alfa.wiedervorlage;
+
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Stream;
+
+import org.apache.commons.collections.MapUtils;
+import org.springframework.stereotype.Component;
+
+import de.ozgcloud.alfa.common.command.Command;
+import de.ozgcloud.alfa.common.command.CommandBodyMapper;
+import de.ozgcloud.alfa.common.command.CommandOrder;
+import de.ozgcloud.alfa.common.command.LegacyOrder;
+import de.ozgcloud.alfa.historie.HistorieProcessor;
+
+@Component
+class WiedervorlageHistorieProcessor implements HistorieProcessor {
+
+	@Override
+	public Stream<Command> process(Stream<Command> commands) {
+		return commands
+				.map(this::translateCreateAttachedItem)
+				.map(this::translateUpdateAttachedItem)
+				.map(this::translatePatchAttachedItem);
+	}
+
+	Command translateCreateAttachedItem(Command command) {
+		if (isCreateWiederVorlage(command)) {
+			return command.toBuilder().order(LegacyOrder.CREATE_WIEDERVORLAGE).build();
+		}
+		return command;
+	}
+
+	private boolean isCreateWiederVorlage(Command command) {
+		return CommandOrder.CREATE_ATTACHED_ITEM == command.getCommandOrder()
+				&& isWiedervorlageItem(command);
+	}
+
+	Command translateUpdateAttachedItem(Command command) {
+		if (isEditWiedervorlage(command)) {
+			return command.toBuilder().order(LegacyOrder.EDIT_WIEDERVORLAGE).build();
+		}
+		return command;
+	}
+
+	private boolean isEditWiedervorlage(Command command) {
+		return CommandOrder.UPDATE_ATTACHED_ITEM == command.getCommandOrder()
+				&& isWiedervorlageItem(command);
+	}
+
+	Command translatePatchAttachedItem(Command command) {
+		if (isPatchWiedervorlage(command)) {
+			return translatePatchWiedervorlage(command);
+		}
+		return command;
+	}
+
+	private boolean isPatchWiedervorlage(Command command) {
+		return CommandOrder.PATCH_ATTACHED_ITEM == command.getCommandOrder() && isWiedervorlageItem(command);
+	}
+
+	private boolean isWiedervorlageItem(Command command) {
+		return getItemName(command).filter(name -> name.equals(Wiedervorlage.class.getSimpleName())).isPresent();
+	}
+
+	private Optional<String> getItemName(Command command) {
+		return Optional.ofNullable(MapUtils.getString(command.getBody(), CommandBodyMapper.ITEM_NAME_PROPERTY));
+	}
+
+	Command translatePatchWiedervorlage(Command command) {
+		return getDoneValue(command).map(isDone -> resolvePatchWiedervorlage(command, isDone)).orElse(command);
+
+	}
+
+	private Optional<Boolean> getDoneValue(Command command) {
+		return Optional.ofNullable(MapUtils.getBoolean(getItemMap(command), Wiedervorlage.DONE_FIELD));
+	}
+
+	@SuppressWarnings("unchecked")
+	private Map<String, Object> getItemMap(Command command) {
+		return MapUtils.getMap(command.getBody(), CommandBodyMapper.ITEM_PROPERTY);
+	}
+
+	private Command resolvePatchWiedervorlage(Command command, Boolean isDone) {
+		return isDone.booleanValue() ? command.toBuilder().order(LegacyOrder.WIEDERVORLAGE_ERLEDIGEN).build()
+				: command.toBuilder().order(LegacyOrder.WIEDERVORLAGE_WIEDEREROEFFNEN).build();
+	}
+}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/bescheid/BescheidHistorieProcessorTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/bescheid/BescheidHistorieProcessorTest.java
index b6bf0944b34d9f7b1f9d93511ae3fe75bc2cd0cb..7867115f449b43e4f76270b7c92a7e12c1ab3b42 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/bescheid/BescheidHistorieProcessorTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/bescheid/BescheidHistorieProcessorTest.java
@@ -65,33 +65,39 @@ class BescheidHistorieProcessorTest {
 	class TestProcess {
 
 		private final Command command = CommandTestFactory.create();
-		private final List<Command> commands = Collections.singletonList(command);
+		private final Stream<Command> commands = Stream.of(command);
+		private final Command relevantCommand = CommandTestFactory.create();
+		private final Command filteredCommand = CommandTestFactory.create();
 
 		@BeforeEach
 		void mock() {
-			doReturn(commands).when(processor).filterByOrder(commands);
-			doReturn(commands).when(processor).filterBescheidRelatedCommands(commands);
+			doReturn(Stream.of(relevantCommand)).when(processor).filterByOrder(any());
+			doReturn(Stream.of(filteredCommand)).when(processor).filterBescheidRelatedCommands(any());
 		}
 
 		@Test
 		void shouldFilterByOrder() {
-			processor.process(commands);
+			process();
 
 			verify(processor).filterByOrder(commands);
 		}
 
 		@Test
 		void shouldFilterBescheidRelatedCommands() {
-			processor.process(commands);
+			process();
 
-			verify(processor).filterBescheidRelatedCommands(commands);
+			verify(processor).filterBescheidRelatedCommands(List.of(relevantCommand));
 		}
 
 		@Test
 		void shouldReturnCommands() {
-			var processedCommands = processor.process(commands);
+			var processedCommands = process();
 
-			assertThat(processedCommands).containsExactly(command);
+			assertThat(processedCommands).containsExactly(filteredCommand);
+		}
+
+		private Stream<Command> process() {
+			return processor.process(commands);
 		}
 	}
 
@@ -104,7 +110,7 @@ class BescheidHistorieProcessorTest {
 		void shouldFilterCommandWithOrder(CommandOrder order) {
 			var command = CommandTestFactory.createBuilder().order(order.name()).build();
 
-			var commands = processor.filterByOrder(Collections.singletonList(command));
+			var commands = processor.filterByOrder(Stream.of(command));
 
 			assertThat(commands).isEmpty();
 		}
@@ -114,7 +120,7 @@ class BescheidHistorieProcessorTest {
 		void shouldKeepCommandWithOrder(CommandOrder order) {
 			var command = CommandTestFactory.createBuilder().order(order.name()).build();
 
-			var commands = processor.filterByOrder(Collections.singletonList(command));
+			var commands = processor.filterByOrder(Stream.of(command));
 
 			assertThat(commands).containsExactly(command);
 		}
@@ -127,7 +133,7 @@ class BescheidHistorieProcessorTest {
 					.body(Collections.singletonMap(VorgangAttachedItem.FIELD_ITEM_NAME, BescheidHistorieProcessor.BESCHEID_ITEM_NAME))
 					.build();
 
-			var commands = processor.filterByOrder(Collections.singletonList(command));
+			var commands = processor.filterByOrder(Stream.of(command));
 
 			assertThat(commands).isEmpty();
 		}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/bescheid/DocumentHistorieProcessorTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/bescheid/DocumentHistorieProcessorTest.java
index 41e1f2a11c72cfa85e948335a6b827b9b4a680d9..5df53b0da134933af263cf52da4ca005edae67e6 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/bescheid/DocumentHistorieProcessorTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/bescheid/DocumentHistorieProcessorTest.java
@@ -27,9 +27,8 @@ import static org.assertj.core.api.Assertions.*;
 import static org.mockito.ArgumentMatchers.*;
 import static org.mockito.Mockito.*;
 
-import java.util.Collections;
-import java.util.List;
 import java.util.Map;
+import java.util.stream.Stream;
 
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.DisplayName;
@@ -55,11 +54,12 @@ class DocumentHistorieProcessorTest {
 	class TestProcess {
 
 		private final Command command = CommandTestFactory.create();
-		private final List<Command> commands = Collections.singletonList(command);
+		private final Stream<Command> commands = Stream.of(command);
+		private final Command filteredCommand = CommandTestFactory.create();
 
 		@BeforeEach
 		void mock() {
-			doReturn(commands).when(processor).filterIrrelevantCommands(any());
+			doReturn(Stream.of(filteredCommand)).when(processor).filterIrrelevantCommands(any());
 		}
 
 		@Test
@@ -73,7 +73,7 @@ class DocumentHistorieProcessorTest {
 		void shouldReturnCommands() {
 			var processedCommands = processor.process(commands);
 
-			assertThat(processedCommands).containsExactly(command);
+			assertThat(processedCommands).containsExactly(filteredCommand);
 		}
 	}
 
@@ -86,7 +86,7 @@ class DocumentHistorieProcessorTest {
 		void shouldFilterCommandWithOrder(CommandOrder order) {
 			var command = CommandTestFactory.createBuilder().order(order.toString()).build();
 
-			var commands = processor.filterIrrelevantCommands(Collections.singletonList(command));
+			var commands = processor.filterIrrelevantCommands(Stream.of(command));
 
 			assertThat(commands).isEmpty();
 		}
@@ -96,7 +96,7 @@ class DocumentHistorieProcessorTest {
 		void shouldKeepCommandWithOrder(CommandOrder order) {
 			var command = CommandTestFactory.createBuilder().order(order.toString()).build();
 
-			var commands = processor.filterIrrelevantCommands(Collections.singletonList(command));
+			var commands = processor.filterIrrelevantCommands(Stream.of(command));
 
 			assertThat(commands).containsExactly(command);
 		}
@@ -108,7 +108,7 @@ class DocumentHistorieProcessorTest {
 					.body(Map.of(VorgangAttachedItem.FIELD_ITEM_NAME, DocumentHistorieProcessor.DOCUMENT_ITEM_NAME))
 					.build();
 
-			var commands = processor.filterIrrelevantCommands(Collections.singletonList(command));
+			var commands = processor.filterIrrelevantCommands(Stream.of(command));
 
 			assertThat(commands).isEmpty();
 		}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/common/attacheditem/VorgangAttachedItemHistorieProcessorTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/common/attacheditem/VorgangAttachedItemHistorieProcessorTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..f53d75a581b511b3cdc0f6775f24077e4bd35a58
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/common/attacheditem/VorgangAttachedItemHistorieProcessorTest.java
@@ -0,0 +1,44 @@
+package de.ozgcloud.alfa.common.attacheditem;
+
+import static org.assertj.core.api.Assertions.*;
+
+import java.util.stream.Stream;
+
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.EnumSource;
+import org.junit.jupiter.params.provider.EnumSource.Mode;
+import org.mockito.Spy;
+
+import de.ozgcloud.alfa.common.command.CommandOrder;
+import de.ozgcloud.alfa.common.command.CommandTestFactory;
+
+class VorgangAttachedItemHistorieProcessorTest {
+
+	@Spy
+	private VorgangAttachedItemHistorieProcessor processor;
+
+	@Nested
+	class TestProcess {
+
+		@ParameterizedTest
+		@EnumSource(names = { "DELETE_ATTACHED_ITEM" }, mode = Mode.EXCLUDE)
+		void shouldKeepCommand(CommandOrder order) {
+			var command = CommandTestFactory.createBuilder().order(order.name()).build();
+
+			var commands = processor.process(Stream.of(command));
+
+			assertThat(commands).containsExactly(command);
+		}
+
+		@ParameterizedTest
+		@EnumSource(names = { "DELETE_ATTACHED_ITEM" }, mode = Mode.INCLUDE)
+		void shouldRemoveCommand(CommandOrder order) {
+			var command = CommandTestFactory.createBuilder().order(order.name()).build();
+
+			var commands = processor.process(Stream.of(command));
+
+			assertThat(commands).isEmpty();
+		}
+	}
+}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/historie/HistorieCommandHandlerTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/historie/HistorieCommandHandlerTest.java
deleted file mode 100644
index 1ef92ad05e6ac8dba3008de06a9ba844004f4c98..0000000000000000000000000000000000000000
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/historie/HistorieCommandHandlerTest.java
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * 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.
- */
-package de.ozgcloud.alfa.historie;
-
-import static org.assertj.core.api.Assertions.*;
-import static org.mockito.ArgumentMatchers.*;
-import static org.mockito.Mockito.*;
-
-import java.util.Collections;
-import java.util.Map;
-
-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.CsvSource;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.Spy;
-
-import de.ozgcloud.alfa.common.attacheditem.VorgangAttachedItem;
-import de.ozgcloud.alfa.common.attacheditem.VorgangAttachedItemService;
-import de.ozgcloud.alfa.common.attacheditem.VorgangAttachedItemTestFactory;
-import de.ozgcloud.alfa.common.command.Command;
-import de.ozgcloud.alfa.common.command.CommandOrder;
-import de.ozgcloud.alfa.common.command.CommandService;
-import de.ozgcloud.alfa.common.command.CommandStatus;
-import de.ozgcloud.alfa.common.command.CommandTestFactory;
-import de.ozgcloud.alfa.common.command.LegacyOrder;
-import de.ozgcloud.alfa.loeschanforderung.DeleteLoeschAnforderung;
-import de.ozgcloud.alfa.postfach.PostfachMail;
-import de.ozgcloud.alfa.wiedervorlage.Wiedervorlage;
-
-class HistorieCommandHandlerTest {
-
-	@Spy
-	@InjectMocks
-	private HistorieCommandHandler handler;
-
-	@Mock
-	private VorgangAttachedItemService vorgangAttachedItemService;
-
-	@Mock
-	private CommandService commandService;
-
-	@DisplayName("Is historie command")
-	@Nested
-	class TestIsHistorieCommand {
-
-		@Test
-		void shouldReturnTrueIfNoItemNameExists() {
-			var result = handler
-					.isHistorieCommand(Command.builder().order(CommandOrder.CREATE_ATTACHED_ITEM.name()).body(Collections.emptyMap()).build());
-
-			assertThat(result).isTrue();
-		}
-
-		@Test
-		void shouldCallIsLoeschAnforderungZuruecknehmenRevoked() {
-			var command = CommandTestFactory.create();
-
-			handler.isHistorieCommand(command);
-
-			verify(handler).isLoeschAnforderungZuruecknehmenRevoked(command);
-		}
-
-		@Test
-		void shouldReturnFalseOnLoeschAnforderungZuruecknehmenRevoked() {
-			doReturn(true).when(handler).isLoeschAnforderungZuruecknehmenRevoked(any());
-
-			var result = handler.isHistorieCommand(CommandTestFactory.create());
-
-			assertThat(result).isFalse();
-		}
-
-		@Test
-		void shouldReturnFalseOnDeleteVorgangAttachedItem() {
-			var result = handler.isHistorieCommand(CommandTestFactory.createBuilder().order(CommandOrder.DELETE_ATTACHED_ITEM.name()).build());
-
-			assertThat(result).isFalse();
-		}
-
-		@Test
-		void shouldCallIsDeleteVorgangAttachedItem() {
-			var command = CommandTestFactory.create();
-
-			handler.isHistorieCommand(command);
-
-			verify(handler).isDeleteVorgangAttachedItem(command);
-		}
-	}
-
-	@DisplayName("postfach nachricht verification")
-	@Nested
-	class TestIsOutgoingPostfachNachrichtenByOzgCloudNachrichtenManager {
-
-		private final Command matchingCommand = CommandTestFactory.createBuilder()
-				.order(CommandOrder.CREATE_ATTACHED_ITEM.name())
-				.body(Map.of("item", Map.of(HistorieCommandHandler.DIRECTION, HistorieCommandHandler.DIRECTION_OUTGOING),
-						HistorieCommandHandler.CLIENT, HistorieCommandHandler.OZGCLOUD_NACHRICHTEN_MANAGER))
-				.build();
-
-		@DisplayName("should return true if the command is CREATED_ATTACHED_ITEM order outgoing by mailserice")
-		@Test
-		void shouldReturnTrue() {
-			var result = handler.isOutgoingPostfachNachrichtByOzgCloudNachrichtenManager(matchingCommand);
-
-			assertThat(result).isTrue();
-		}
-
-		@Test
-		void shouldReturnFalseOnIncoming() {
-			var nonMatchingCommand = matchingCommand.toBuilder()
-					.body(Map.of("item", Map.of(HistorieCommandHandler.DIRECTION, HistorieCommandHandler.DIRECTION_INCOMMING),
-							HistorieCommandHandler.CLIENT, HistorieCommandHandler.OZGCLOUD_NACHRICHTEN_MANAGER))
-					.build();
-
-			var result = handler.isOutgoingPostfachNachrichtByOzgCloudNachrichtenManager(nonMatchingCommand);
-
-			assertThat(result).isFalse();
-		}
-
-		@Test
-		void shouldReturnFalseOnOtherClient() {
-			var nonMatchingCommand = matchingCommand.toBuilder()
-					.body(Map.of("item", Map.of(HistorieCommandHandler.DIRECTION, HistorieCommandHandler.DIRECTION_OUTGOING),
-							HistorieCommandHandler.CLIENT, "Alfa"))
-					.build();
-
-			var result = handler.isOutgoingPostfachNachrichtByOzgCloudNachrichtenManager(nonMatchingCommand);
-
-			assertThat(result).isFalse();
-		}
-	}
-
-	@Nested
-	class TestIsLoscheAnforderungVorgangAttachedItem {
-
-		@Test
-		void shouldReturnFalse() {
-			when(vorgangAttachedItemService.isLoeschAnforderung(VorgangAttachedItemTestFactory.ITEM_NAME)).thenReturn(false);
-
-			var result = handler.isCreateLoeschAnforderungVorgangAttachedItem(Command.builder().order(CommandOrder.CREATE_ATTACHED_ITEM.name())
-					.body(Map.of(
-							VorgangAttachedItem.FIELD_ITEM_NAME,
-							VorgangAttachedItemTestFactory.ITEM_NAME))
-					.build());
-
-			assertThat(result).isFalse();
-		}
-
-		@Test
-		void shouldReturnTrue() {
-			when(vorgangAttachedItemService.isLoeschAnforderung(VorgangAttachedItemTestFactory.ITEM_NAME)).thenReturn(true);
-
-			var result = handler.isCreateLoeschAnforderungVorgangAttachedItem(Command.builder().order(CommandOrder.CREATE_ATTACHED_ITEM.name())
-					.body(Map.of(
-							VorgangAttachedItem.FIELD_ITEM_NAME,
-							VorgangAttachedItemTestFactory.ITEM_NAME))
-					.build());
-
-			assertThat(result).isTrue();
-		}
-	}
-
-	@DisplayName("Is loesch anforderung zuruecknehmen revoked")
-	@Nested
-	class TestIsLoeschAnforderungZuruecknehmenRevoked {
-
-		@DisplayName("on matchin order")
-		@Nested
-		class TestOnMatchingOrder {
-
-			private final Command loeschAnforderungZuruecknehmen = CommandTestFactory.createBuilder()
-					.order(CommandOrder.LOESCH_ANFORDERUNG_ZURUECKNEHMEN.name())
-					.body(Map.of(DeleteLoeschAnforderung.CHANGE_STATUS_COMMAND_ID_FIELD, CommandTestFactory.ID))
-					.build();
-
-			@Test
-			void shouldCallCommandService() {
-				when(commandService.getById(anyString())).thenReturn(CommandTestFactory.create());
-
-				handler.isLoeschAnforderungZuruecknehmenRevoked(loeschAnforderungZuruecknehmen);
-
-				verify(commandService).getById(CommandTestFactory.ID);
-			}
-
-			@Test
-			void shouldReturnTrueOnRevokedStatus() {
-				var revokedCommand = loeschAnforderungZuruecknehmen.toBuilder().status(CommandStatus.REVOKED).build();
-				when(commandService.getById(anyString())).thenReturn(revokedCommand);
-
-				var isRevoked = handler.isLoeschAnforderungZuruecknehmenRevoked(loeschAnforderungZuruecknehmen);
-
-				assertThat(isRevoked).isTrue();
-			}
-
-			@Test
-			void shouldReturnFalseOnOtherStatus() {
-				var revokedCommand = loeschAnforderungZuruecknehmen.toBuilder().status(CommandStatus.FINISHED).build();
-				when(commandService.getById(anyString())).thenReturn(revokedCommand);
-
-				var isRevoked = handler.isLoeschAnforderungZuruecknehmenRevoked(loeschAnforderungZuruecknehmen);
-
-				assertThat(isRevoked).isFalse();
-			}
-		}
-
-		@Test
-		void shouldReturnFalseOnNonMatchingOrder() {
-			var isRevoked = handler.isLoeschAnforderungZuruecknehmenRevoked(CommandTestFactory.create());
-
-			assertThat(isRevoked).isFalse();
-		}
-	}
-
-	@DisplayName("translate order")
-	@Nested
-	class TestTranslateOrders {
-
-		@ParameterizedTest
-		@CsvSource(value = { "CREATE_KOMMENTAR;Kommentar", "CREATE_WIEDERVORLAGE;Wiedervorlage" }, delimiter = ';')
-		void shouldTranslateToCreateOrder(String target, String itemName) {
-			var command = handler.translateOrder(createCommand(itemName, CommandOrder.CREATE_ATTACHED_ITEM));
-
-			assertThat(command.getOrder()).isEqualTo(target);
-		}
-
-		@ParameterizedTest
-		@CsvSource(value = { "EDIT_KOMMENTAR;Kommentar", "EDIT_WIEDERVORLAGE;Wiedervorlage" }, delimiter = ';')
-		void shouldTranslateToEditOrder(String target, String itemName) {
-			var command = handler.translateOrder(createCommand(itemName, CommandOrder.UPDATE_ATTACHED_ITEM));
-
-			assertThat(command.getOrder()).isEqualTo(target);
-		}
-
-		@ParameterizedTest
-		@CsvSource(value = { "WIEDERVORLAGE_ERLEDIGEN;true", "WIEDERVORLAGE_WIEDEREROEFFNEN;false" }, delimiter = ';')
-		void shouldTranslateToWiedervolageErledigenOrWiedervolageWiedereroeffnen(String target, String doneValue) {
-			var command = handler.translateOrder(
-					createCommand(Wiedervorlage.class.getSimpleName(), CommandOrder.PATCH_ATTACHED_ITEM, Boolean.valueOf(doneValue)));
-
-			assertThat(command.getOrder()).isEqualTo(target);
-		}
-
-		@ParameterizedTest
-		@CsvSource(value = { "RECEIVE_POSTFACH_NACHRICHT;IN" }, delimiter = ';')
-		void shouldTranslateToReveivedIncomminNachricht(String target, String direction) {
-			var command = handler.translateOrder(
-					createCommand("OzgCloud_NachrichtenManager", CommandOrder.CREATE_ATTACHED_ITEM, direction));
-
-			assertThat(command.getOrder()).isEqualTo(target);
-		}
-
-		@Test
-		void shouldHandleMissingDone() {
-			var command = handler.translateOrder(createCommand(Wiedervorlage.class.getSimpleName(), CommandOrder.PATCH_ATTACHED_ITEM));
-
-			assertThat(command.getCommandOrder()).isEqualTo(CommandOrder.PATCH_ATTACHED_ITEM);
-		}
-
-		@Test
-		void shouldHandleUnkownOrder() {
-			var command = handler
-					.translateOrder(createCommand(Wiedervorlage.class.getSimpleName(), CommandOrder.VORGANG_ABSCHLIESSEN));
-
-			assertThat(command.getCommandOrder()).isEqualTo(CommandOrder.VORGANG_ABSCHLIESSEN);
-		}
-
-		@Test
-		void shouldHandleMissingItemName() {
-			var command = CommandTestFactory.createBuilder().order(LegacyOrder.EDIT_KOMMENTAR).body(Map.of("item", Map.of("value", "test")))
-					.build();
-
-			var translatedCommand = handler.translateOrder(command);
-
-			assertThat(translatedCommand.getOrder()).isEqualTo(LegacyOrder.EDIT_KOMMENTAR);
-		}
-
-		private Command createCommand(String itemName, CommandOrder order) {
-			return CommandTestFactory.createBuilder().order(order.name())
-					.body(Map.of(VorgangAttachedItem.FIELD_ITEM_NAME, itemName, "item", Map.of("value", "test"))).build();
-		}
-
-		private Command createCommand(String itemName, CommandOrder order, boolean done) {
-			return CommandTestFactory.createBuilder().order(order.name())
-					.body(Map.of(VorgangAttachedItem.FIELD_ITEM_NAME, itemName, "item", Map.of("done", done)))
-					.build();
-		}
-
-		private Command createCommand(String client, CommandOrder order, String direction) {
-			return CommandTestFactory.createBuilder().order(order.name())
-					.body(Map.of(HistorieCommandHandler.CLIENT, client, VorgangAttachedItem.FIELD_ITEM_NAME, PostfachMail.class.getSimpleName(),
-							"item",
-							Map.of(HistorieCommandHandler.DIRECTION, direction)))
-					.build();
-		}
-
-	}
-
-	@DisplayName("SEND_POSTFACH_MAIL")
-	@Nested
-	class TestSendPostfachMail {
-
-		private Command command = CommandTestFactory.createBuilder().order(CommandOrder.SEND_POSTFACH_MAIL.name()).build();
-
-		@Test
-		void shouldHandleUnkownOrder() {
-			var translatedCommand = handler.translateOrder(command);
-
-			assertThat(translatedCommand.getCommandOrder()).isEqualTo(CommandOrder.SEND_POSTFACH_NACHRICHT);
-		}
-	}
-}
\ No newline at end of file
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/historie/HistorieServiceTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/historie/HistorieServiceTest.java
index 6d6a75467c7bc45f9aaf65191a5e0dc9ceacce05..725768dcbcf608b24d78caccb7397a6eb5d4788b 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/historie/HistorieServiceTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/historie/HistorieServiceTest.java
@@ -28,26 +28,19 @@ import static org.mockito.ArgumentMatchers.*;
 import static org.mockito.Mockito.*;
 
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
-import java.util.Map;
-import java.util.UUID;
+import java.util.stream.Stream;
 
 import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.Spy;
 
 import de.ozgcloud.alfa.common.command.Command;
-import de.ozgcloud.alfa.common.command.CommandOrder;
 import de.ozgcloud.alfa.common.command.CommandService;
 import de.ozgcloud.alfa.common.command.CommandTestFactory;
-import de.ozgcloud.alfa.loeschanforderung.DeleteLoeschAnforderung;
 import de.ozgcloud.alfa.vorgang.VorgangHeaderTestFactory;
 
 class HistorieServiceTest {
@@ -57,111 +50,85 @@ class HistorieServiceTest {
 	private HistorieService service;
 	@Mock
 	private CommandService commandService;
-	@Mock
-	private HistorieCommandHandler historieCommandHandler;
 	@Spy
 	private List<HistorieProcessor> processors = new ArrayList<>();
 	@Mock
-	private HistorieProcessor processor;
+	private HistorieProcessor firstProcessor;
+	@Mock
+	private HistorieProcessor secondProcessor;
 
-	@DisplayName("Find finished commands")
 	@Nested
 	class TestFindFinishedCommands {
 
+		private final Stream<Command> commands = Stream.of(CommandTestFactory.create());
+
 		@BeforeEach
-		void mockProcessor() {
-			processors.add(processor);
+		void setUpMock() {
+			when(commandService.findFinishedCommands(any())).thenReturn(commands);
 		}
 
-		@DisplayName("process flow")
-		@Nested
-		class TestProcessFlow {
-
-			private Command responseCommand = CommandTestFactory.create();
+		@Test
+		void shouldCallCommandServiceForFinishedCommands() {
+			findFinishedCommands();
 
-			@Captor
-			private ArgumentCaptor<List<Command>> commandCaptor;
+			verify(commandService).findFinishedCommands(VorgangHeaderTestFactory.ID);
+		}
 
-			@BeforeEach
-			void initMock() {
-				when(commandService.findFinishedCommands(any())).thenReturn(List.of(responseCommand).stream());
-				when(historieCommandHandler.isHistorieCommand(any())).thenReturn(true);
-				when(historieCommandHandler.translateOrder(any())).thenAnswer(i -> i.getArgument(0));
+		@Test
+		void shouldCallProcessCommands() {
+			findFinishedCommands();
 
-			}
+			verify(service).processCommands(commands);
+		}
 
-			@Test
-			void shouldCallService() {
-				service.findFinishedCommands(CommandTestFactory.VORGANG_ID).toList();
+		@Test
+		void shouldReturnProcessedCommands() {
+			var processedCommands = Stream.of(CommandTestFactory.create());
+			doReturn(processedCommands).when(service).processCommands(commands);
 
-				verify(commandService).findFinishedCommands(VorgangHeaderTestFactory.ID);
-			}
+			var finishedCommands = findFinishedCommands();
 
-			@Test
-			void shouldFilterInvalidCommands() {
-				service.findFinishedCommands(CommandTestFactory.VORGANG_ID).toList();
+			assertThat(finishedCommands).isSameAs(processedCommands);
+		}
 
-				verify(historieCommandHandler).isHistorieCommand(responseCommand);
-			}
+		private Stream<Command> findFinishedCommands() {
+			return service.findFinishedCommands(VorgangHeaderTestFactory.ID);
+		}
+	}
 
-			@Test
-			void shouldTranslateCommandOrderByCommandHandler() {
-				service.findFinishedCommands(CommandTestFactory.VORGANG_ID).toList();
+	@Nested
+	class TestProcessCommands {
 
-				verify(historieCommandHandler).translateOrder(responseCommand);
-			}
+		private final Stream<Command> inputCommands = Stream.of(CommandTestFactory.create());
+		private final Stream<Command> processedOnceCommands = Stream.of(CommandTestFactory.create());
+		private final Stream<Command> processedTwiceCommands = Stream.of(CommandTestFactory.create());
 
-			@Test
-			void shouldProcessCommands() {
-				service.findFinishedCommands(CommandTestFactory.VORGANG_ID).toList();
+		@BeforeEach
+		void setProcessorMocks() {
+			processors.addAll(List.of(firstProcessor, secondProcessor));
+			when(firstProcessor.process(any())).thenReturn(processedOnceCommands);
+			when(secondProcessor.process(any())).thenReturn(processedTwiceCommands);
+		}
 
-				verify(processor).process(commandCaptor.capture());
-				assertThat(commandCaptor.getValue()).containsExactly(responseCommand);
-			}
+		@Test
+		void shouldProcessCommands() {
+			service.processCommands(inputCommands);
 
-			@Test
-			void shouldReturnProcessedCommands() {
-				var processedCommands = Collections.singletonList(CommandTestFactory.create());
-				when(processor.process(any())).thenReturn(processedCommands);
+			verify(firstProcessor).process(inputCommands);
+		}
 
-				var commands = service.findFinishedCommands(CommandTestFactory.VORGANG_ID).toList();
+		@Test
+		void shouldDoSubsequentProcessing() {
+			service.processCommands(inputCommands);
 
-				assertThat(commands).isEqualTo(processedCommands);
-			}
+			verify(secondProcessor).process(processedOnceCommands);
 		}
 
-		@DisplayName("Filter deleteLoeschAnforderung body commands")
-		@Nested
-		class TestFilterDeleteLoeschAnforderungBodyCommands {
-
-			private final String deleteAttachedItemCommandId = UUID.randomUUID().toString();
-			private final String changeStatusCommandId = UUID.randomUUID().toString();
-			private final Map<String, Object> bodyMap = Map.of(DeleteLoeschAnforderung.DELETE_ATTACHED_ITEM_COMMAND_ID_FIELD,
-					deleteAttachedItemCommandId,
-					DeleteLoeschAnforderung.CHANGE_STATUS_COMMAND_ID_FIELD, changeStatusCommandId);
-			private final Command deleteLoeschAnforderungCommand = CommandTestFactory.createBuilder()
-					.order(CommandOrder.LOESCH_ANFORDERUNG_ZURUECKNEHMEN.name())
-					.body(bodyMap).build();
-			private final Command deleteAttachedItemCommand = CommandTestFactory.createBuilder().id(deleteAttachedItemCommandId).build();
-			private final Command changeStatusCommandICommand = CommandTestFactory.createBuilder().id(changeStatusCommandId).build();
-
-			private final List<Command> finishedCommands = List.of(deleteLoeschAnforderungCommand, deleteAttachedItemCommand,
-					changeStatusCommandICommand);
-
-			@BeforeEach
-			void mock() {
-				when(historieCommandHandler.isHistorieCommand(any())).thenReturn(true);
-				when(commandService.findFinishedCommands(any())).thenReturn(finishedCommands.stream());
-				when(historieCommandHandler.translateOrder(any())).thenAnswer(i -> i.getArgument(0));
-				when(processor.process(any())).thenAnswer(i -> i.getArgument(0));
-			}
-
-			@Test
-			void shouldFilterCommandsRelatedInBody() {
-				var commands = service.findFinishedCommands(CommandTestFactory.VORGANG_ID).toList();
-
-				assertThat(commands).hasSize(1).containsExactly(deleteLoeschAnforderungCommand);
-			}
+		@Test
+		void shouldReturnCommandsAfterProcessing() {
+			var resultCommands = service.processCommands(inputCommands);
+
+			assertThat(resultCommands).isEqualTo(processedTwiceCommands);
 		}
 	}
 }
\ No newline at end of file
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/kommentar/KommentarHistorieProcessorTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/kommentar/KommentarHistorieProcessorTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..c67a8dfc3b86ab32f37c7d889eafb62cb3787ec0
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/kommentar/KommentarHistorieProcessorTest.java
@@ -0,0 +1,176 @@
+package de.ozgcloud.alfa.kommentar;
+
+import static org.assertj.core.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Stream;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.mockito.Spy;
+
+import com.thedeanda.lorem.LoremIpsum;
+
+import de.ozgcloud.alfa.common.command.Command;
+import de.ozgcloud.alfa.common.command.CommandBodyMapper;
+import de.ozgcloud.alfa.common.command.CommandOrder;
+import de.ozgcloud.alfa.common.command.CommandTestFactory;
+import de.ozgcloud.alfa.common.command.LegacyOrder;
+
+class KommentarHistorieProcessorTest {
+
+	@Spy
+	private KommentarHistorieProcessor processor;
+
+	@Nested
+	class TestProcess {
+
+		private final Command command = CommandTestFactory.create();
+		private final Command translatedOnceCommand = CommandTestFactory.create();
+		private final Command translatedTwiceCommand = CommandTestFactory.create();
+
+		@BeforeEach
+		void mockTranslation() {
+			doReturn(translatedOnceCommand).when(processor).translateCreateKommentar(command);
+			doReturn(translatedTwiceCommand).when(processor).translateEditKommentar(translatedOnceCommand);
+		}
+
+		@Test
+		void shouldCallTranslateCreateKommentar() {
+			process();
+
+			verify(processor).translateCreateKommentar(command);
+		}
+
+		@Test
+		void shouldCallTranslateEditKommentar() {
+			process();
+
+			verify(processor).translateEditKommentar(translatedOnceCommand);
+		}
+
+		@Test
+		void shouldReturnStreamOfTranslatedCommand() {
+			var commands = process();
+
+			assertThat(commands).containsExactly(translatedTwiceCommand);
+		}
+
+		private List<Command> process() {
+			return processor.process(Stream.of(command)).toList();
+		}
+	}
+
+	@Nested
+	class TestTranslateCreateKommentar {
+
+		@Nested
+		class TestOnNotCreateAttachedItem {
+
+			@Test
+			void shouldReturnSameCommand() {
+				var command = CommandTestFactory.create();
+
+				var resultCommand = processor.translateCreateKommentar(command);
+
+				assertThat(resultCommand).isSameAs(command);
+			}
+		}
+
+		@Nested
+		class TestOnCreateAttachedItem {
+
+			private Command.CommandBuilder commandBuilder = CommandTestFactory.createBuilder()
+					.order(CommandOrder.CREATE_ATTACHED_ITEM.name());
+
+			@Nested
+			class TestOnIsCreateKommentar {
+				@Test
+				void shouldTranslateToCreateKommentar() {
+					var commandBody = Map.of(CommandBodyMapper.ITEM_NAME_PROPERTY, Kommentar.class.getSimpleName());
+					var command = commandBuilder.body(commandBody).build();
+					var expectedCommand = CommandTestFactory.createBuilder()
+							.order(LegacyOrder.CREATE_KOMMENTAR)
+							.body(commandBody)
+							.build();
+
+					var resultCommand = processor.translateCreateKommentar(command);
+
+					assertThat(resultCommand).usingRecursiveComparison().isEqualTo(expectedCommand);
+				}
+			}
+
+			@Nested
+			class TestOnIsNotCreateKommentar {
+
+				@Test
+				void shouldReturnSameCommand() {
+					var commandBody = Map.of(CommandBodyMapper.ITEM_NAME_PROPERTY, LoremIpsum.getInstance().getWords(1));
+					var command = commandBuilder.body(commandBody).build();
+
+					var resultCommand = processor.translateCreateKommentar(command);
+
+					assertThat(resultCommand).isSameAs(command);
+				}
+			}
+		}
+	}
+
+	@Nested
+	class TestTranslateEditKommentar {
+
+		@Nested
+		class TestOnNotUpdateAttachedItem {
+
+			@Test
+			void shouldReturnSameCommand() {
+				var command = CommandTestFactory.create();
+
+				var resultCommand = processor.translateEditKommentar(command);
+
+				assertThat(resultCommand).isSameAs(command);
+			}
+		}
+
+		@Nested
+		class TestOnUpdateAttachedItem {
+
+			private Command.CommandBuilder commandBuilder = CommandTestFactory.createBuilder()
+					.order(CommandOrder.UPDATE_ATTACHED_ITEM.name());
+
+			@Nested
+			class TestOnIsEditKommentar {
+				@Test
+				void shouldTranslateToCreateKommentar() {
+					var commandBody = Map.of(CommandBodyMapper.ITEM_NAME_PROPERTY, Kommentar.class.getSimpleName());
+					var command = commandBuilder.body(commandBody).build();
+					var expectedCommand = CommandTestFactory.createBuilder()
+							.order(LegacyOrder.EDIT_KOMMENTAR)
+							.body(commandBody)
+							.build();
+
+					var resultCommand = processor.translateEditKommentar(command);
+
+					assertThat(resultCommand).usingRecursiveComparison().isEqualTo(expectedCommand);
+				}
+			}
+
+			@Nested
+			class TestOnIsNotEditKommentar {
+
+				@Test
+				void shouldReturnSameCommand() {
+					var commandBody = Map.of(CommandBodyMapper.ITEM_NAME_PROPERTY, LoremIpsum.getInstance().getWords(1));
+					var command = commandBuilder.body(commandBody).build();
+
+					var resultCommand = processor.translateEditKommentar(command);
+
+					assertThat(resultCommand).isSameAs(command);
+				}
+			}
+		}
+	}
+}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungHistorieProcessorTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungHistorieProcessorTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..17ec36a7d571aa97572f9093ab8d8c4fdd835dde
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungHistorieProcessorTest.java
@@ -0,0 +1,346 @@
+package de.ozgcloud.alfa.loeschanforderung;
+
+import static org.assertj.core.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.*;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import java.util.stream.Stream;
+
+import org.junit.jupiter.api.BeforeEach;
+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.ValueSource;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Spy;
+import org.mockito.invocation.InvocationOnMock;
+
+import com.thedeanda.lorem.LoremIpsum;
+
+import de.ozgcloud.alfa.common.attacheditem.VorgangAttachedItem;
+import de.ozgcloud.alfa.common.attacheditem.VorgangAttachedItemService;
+import de.ozgcloud.alfa.common.command.Command;
+import de.ozgcloud.alfa.common.command.CommandOrder;
+import de.ozgcloud.alfa.common.command.CommandService;
+import de.ozgcloud.alfa.common.command.CommandStatus;
+import de.ozgcloud.alfa.common.command.CommandTestFactory;
+
+class LoeschAnforderungHistorieProcessorTest {
+
+	@Spy
+	@InjectMocks
+	private LoeschAnforderungHistorieProcessor processor;
+
+	@Mock
+	private CommandService commandService;
+	@Mock
+	private VorgangAttachedItemService vorgangAttachedItemService;
+
+	@Nested
+	class TestProcess {
+
+		private final Command command = CommandTestFactory.create();
+
+		@Test
+		void shouldCallIsNotRevokedLoeschAnforderungZuruecknehmen() {
+			process();
+
+			verify(processor).isNotRevokedLoeschAnforderungZuruecknehmen(command);
+		}
+
+		@Nested
+		class TestOnIsNotRevokedLoeschAnforderungZuruecknehmen {
+
+			@BeforeEach
+			void mock() {
+				doReturn(true).when(processor).isNotRevokedLoeschAnforderungZuruecknehmen(any());
+			}
+
+			@Test
+			void shouldCallIsNotCreateLoeschAnforderungVorgangAttachedItem() {
+				process();
+
+				verify(processor).isNotCreateLoeschAnforderungVorgangAttachedItem(command);
+			}
+
+			@Nested
+			class TestOnIsNotCreateLoeschAnforderungVorgangAttachedItem {
+				@BeforeEach
+				void mock() {
+					doReturn(true).when(processor).isNotCreateLoeschAnforderungVorgangAttachedItem(any());
+				}
+
+				@Test
+				void shouldAddLoeschAnforderungZuruecknehmenRelatedCommandIds() {
+					process();
+
+					verify(processor).addLoeschAnforderungZuruecknehmenRelatedCommandIds(argThat(Collection::isEmpty), eq(command));
+				}
+
+				@Test
+				void shouldRemoveLoeschAnforderungZuruecknehmenRelatedCommands() {
+					doAnswer(this::addCommandIdToSet).when(processor)
+							.addLoeschAnforderungZuruecknehmenRelatedCommandIds(anySet(), any());
+
+					var commands = process();
+
+					assertThat(commands).isEmpty();
+				}
+
+				@SuppressWarnings("unchecked")
+				private Object addCommandIdToSet(InvocationOnMock invokation) {
+					invokation.getArgument(0, Set.class).add(CommandTestFactory.ID);
+					return command;
+				}
+
+				@Test
+				void shouldKeepCommandsWithDifferentId() {
+					doAnswer(this::addDummyIdToSet).when(processor)
+							.addLoeschAnforderungZuruecknehmenRelatedCommandIds(anySet(), any());
+
+					var commands = process();
+
+					assertThat(commands).containsExactly(command);
+				}
+
+				@SuppressWarnings("unchecked")
+				private Object addDummyIdToSet(InvocationOnMock invokation) {
+					invokation.getArgument(0, Set.class).add("dummy");
+					return command;
+				}
+			}
+
+			@Nested
+			class TestOnIsCreateLoeschAnforderungVorgangAttachedItem {
+				@BeforeEach
+				void mock() {
+					doReturn(false).when(processor).isNotCreateLoeschAnforderungVorgangAttachedItem(any());
+				}
+
+				@Test
+				void shouldNotCallAddLoeschAnforderungZuruecknehmenRelatedCommandIds() {
+					process();
+
+					verify(processor, never()).addLoeschAnforderungZuruecknehmenRelatedCommandIds(any(), any());
+				}
+
+				@Test
+				void shouldRemoveCommand() {
+					var commands = process();
+
+					assertThat(commands).isEmpty();
+				}
+			}
+		}
+
+		@Nested
+		class TestOnIsRevokedLoeschAnforderungZuruecknehmen {
+
+			@BeforeEach
+			void mock() {
+				doReturn(false).when(processor).isNotRevokedLoeschAnforderungZuruecknehmen(any());
+			}
+
+			@Test
+			void shouldNotGetLoeschAnforderungZuruecknehmenRelatedCommandIds() {
+				process();
+
+				verify(processor, never()).addLoeschAnforderungZuruecknehmenRelatedCommandIds(anySet(), any());
+			}
+
+			@Test
+			void shouldRemoveRevokedLoeschAnforderungenZuruecknehmen() {
+				var commands = process();
+
+				assertThat(commands).isEmpty();
+			}
+		}
+
+		private Stream<Command> process() {
+			return processor.process(Stream.of(command));
+		}
+
+	}
+
+	@Nested
+	class TestIsNotRevokedLoeschAnforderungZuruecknehmen {
+
+		@Nested
+		class TestOnIsNotLoeschAnforderungZurücknehmen {
+
+			private final Command command = CommandTestFactory.create();
+
+			@Test
+			void shouldReturnTrue() {
+				var result = processor.isNotRevokedLoeschAnforderungZuruecknehmen(command);
+
+				assertThat(result).isTrue();
+			}
+		}
+
+		@Nested
+		class TestOnIsLoeschAnforderungZurücknehmen {
+
+			private final Command command = CommandTestFactory.createBuilder()
+					.order(CommandOrder.LOESCH_ANFORDERUNG_ZURUECKNEHMEN.toString())
+					.build();
+
+			private final String changeStatusCommandId = UUID.randomUUID().toString();
+
+			@BeforeEach
+			void mock() {
+				doReturn(changeStatusCommandId).when(processor).getChangeStatusCommandId(any());
+				when(commandService.getById(any())).thenReturn(CommandTestFactory.create());
+			}
+
+			@Test
+			void shouldGetChangeStatusCommandId() {
+				isNotRevokedLoeschAnforderungZuruecknehmen();
+
+				verify(processor).getChangeStatusCommandId(command);
+			}
+
+			@Test
+			void shouldGetChangeStatusCommand() {
+				isNotRevokedLoeschAnforderungZuruecknehmen();
+
+				verify(commandService).getById(changeStatusCommandId);
+			}
+
+			@Test
+			void shouldReturnTrueIfChangeStatusCommandIsNotRevoked() {
+				var changeStatusCommand = CommandTestFactory.createBuilder().status(CommandStatus.FINISHED).build();
+				when(commandService.getById(any())).thenReturn(changeStatusCommand);
+
+				var result = isNotRevokedLoeschAnforderungZuruecknehmen();
+
+				assertThat(result).isTrue();
+			}
+
+			@Test
+			void shouldReturnFalseIfChangeStatusCommandIsRevoked() {
+				var changeStatusCommand = CommandTestFactory.createBuilder().status(CommandStatus.REVOKED).build();
+				when(commandService.getById(any())).thenReturn(changeStatusCommand);
+
+				var result = isNotRevokedLoeschAnforderungZuruecknehmen();
+
+				assertThat(result).isFalse();
+			}
+
+			private boolean isNotRevokedLoeschAnforderungZuruecknehmen() {
+				return processor.isNotRevokedLoeschAnforderungZuruecknehmen(command);
+			}
+		}
+	}
+
+	@Nested
+	class TestIsNotCreateLoeschAnforderungVorgangAttachedItem {
+
+		@ParameterizedTest
+		@EnumSource(names = { "CREATE_ATTACHED_ITEM" }, mode = EnumSource.Mode.EXCLUDE)
+		void shouldReturnTrueForNotCreateAttachedItem(CommandOrder order) {
+			var command = CommandTestFactory.createBuilder().order(order.name()).build();
+
+			var result = processor.isNotCreateLoeschAnforderungVorgangAttachedItem(command);
+
+			assertThat(result).isTrue();
+		}
+
+		@ParameterizedTest
+		@EnumSource(names = { "CREATE_ATTACHED_ITEM" }, mode = EnumSource.Mode.EXCLUDE)
+		void shouldNotCallVorgangAttachedItemService(CommandOrder order) {
+			var command = CommandTestFactory.createBuilder().order(order.name()).build();
+
+			processor.isNotCreateLoeschAnforderungVorgangAttachedItem(command);
+
+			verify(vorgangAttachedItemService, never()).isLoeschAnforderung(any());
+		}
+
+		@Nested
+		class TestOnCreateAttacheditemOrder {
+
+			private final String itemName = LoremIpsum.getInstance().getWords(1);
+			private final Map<String, ?> commandBody = Map.of(VorgangAttachedItem.FIELD_ITEM_NAME, itemName);
+			private final Command command = CommandTestFactory.createBuilder()
+					.order(CommandOrder.CREATE_ATTACHED_ITEM.name())
+					.body(commandBody)
+					.build();
+
+			@Test
+			void shouldCallVorgangAttachedItemService() {
+				processor.isNotCreateLoeschAnforderungVorgangAttachedItem(command);
+
+				verify(vorgangAttachedItemService).isLoeschAnforderung(itemName);
+			}
+
+			@ParameterizedTest
+			@ValueSource(booleans = { true, false })
+			void shouldReturnNegatedResult(boolean isLoeschAnforderung) {
+				when(vorgangAttachedItemService.isLoeschAnforderung(any())).thenReturn(isLoeschAnforderung);
+
+				var result = processor.isNotCreateLoeschAnforderungVorgangAttachedItem(command);
+
+				assertThat(result).isNotEqualTo(isLoeschAnforderung);
+			}
+		}
+	}
+
+	@Nested
+	class TestGetChangeStatusCommandId {
+
+		@Test
+		void shouldReturnChangeStatusCommandId() {
+			var changeStatusCommandId = UUID.randomUUID().toString();
+			var commandBody = Map.of(DeleteLoeschAnforderung.CHANGE_STATUS_COMMAND_ID_FIELD, changeStatusCommandId);
+			var command = CommandTestFactory.createBuilder().body(commandBody).build();
+
+			var id = processor.getChangeStatusCommandId(command);
+
+			assertThat(id).isEqualTo(changeStatusCommandId);
+		}
+	}
+
+	@Nested
+	class TestAddLoeschAnforderungZuruecknehmenRelatedCommandIds {
+		private final String changeStatusCommandId = UUID.randomUUID().toString();
+		private final String deleteAttachedItemCommandId = UUID.randomUUID().toString();
+		private final Map<String, ?> commandBody = Map.of(
+				DeleteLoeschAnforderung.CHANGE_STATUS_COMMAND_ID_FIELD, changeStatusCommandId,
+				DeleteLoeschAnforderung.DELETE_ATTACHED_ITEM_COMMAND_ID_FIELD, deleteAttachedItemCommandId,
+				LoremIpsum.getInstance().getWords(1), UUID.randomUUID().toString());
+		private final Command command = CommandTestFactory.createBuilder()
+				.order(CommandOrder.LOESCH_ANFORDERUNG_ZURUECKNEHMEN.name())
+				.body(commandBody)
+				.build();
+		private final HashSet<String> idsToRemove = new HashSet<>();
+
+		@Test
+		void shouldReturnSameCommand() {
+			var returnedCommand = processor.addLoeschAnforderungZuruecknehmenRelatedCommandIds(idsToRemove, command);
+
+			assertThat(returnedCommand).isSameAs(command);
+		}
+
+		@Test
+		void shouldNotAddAnyIds() {
+			processor.addLoeschAnforderungZuruecknehmenRelatedCommandIds(idsToRemove, CommandTestFactory.create());
+
+			assertThat(idsToRemove).isEmpty();
+		}
+
+		@Test
+		void shouldAddRelatedCommandIdsOfLoeschAnforderungenZuruecknehmen() {
+			processor.addLoeschAnforderungZuruecknehmenRelatedCommandIds(idsToRemove, command);
+
+			assertThat(idsToRemove).containsExactlyInAnyOrder(changeStatusCommandId, deleteAttachedItemCommandId);
+		}
+	}
+
+}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/postfach/PostfachNachrichtHistorieProcessorTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/postfach/PostfachNachrichtHistorieProcessorTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..300249da5973529dc8243ec16debb14e007a03a4
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/postfach/PostfachNachrichtHistorieProcessorTest.java
@@ -0,0 +1,274 @@
+package de.ozgcloud.alfa.postfach;
+
+import static org.assertj.core.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.*;
+
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Stream;
+
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.mockito.Spy;
+
+import com.thedeanda.lorem.LoremIpsum;
+
+import de.ozgcloud.alfa.common.command.Command;
+import de.ozgcloud.alfa.common.command.CommandOrder;
+import de.ozgcloud.alfa.common.command.CommandTestFactory;
+
+class PostfachNachrichtHistorieProcessorTest {
+
+	@Spy
+	private PostfachNachrichtHistorieProcessor processor;
+
+	@Nested
+	class TestProcess {
+
+		private final Command command = CommandTestFactory.create();
+
+		@Test
+		void shouldCallIsNotOutgoingPostfachNachrichtByNachrichtenManager() {
+			process();
+
+			verify(processor).isNotOutgoingPostfachNachrichtByNachrichtenManager(command);
+		}
+
+		@Test
+		void shouldContainCommandIfIsNotOutgoingPostfachNachrichtByNachrichtenManager() {
+			doReturn(true).when(processor).isNotOutgoingPostfachNachrichtByNachrichtenManager(any());
+			doReturn(command).when(processor).translateSendPostfachMailCommand(command);
+			doReturn(command).when(processor).translateReceivePostfachNachrichtCommand(command);
+
+			var commands = process();
+
+			assertThat(commands).containsExactly(command);
+		}
+
+		@Test
+		void shouldNotContainCommandIfisNotOutgoingPostfachNachrichtByNachrichtenManager() {
+			doReturn(false).when(processor).isNotOutgoingPostfachNachrichtByNachrichtenManager(any());
+
+			var commands = process();
+
+			assertThat(commands).isEmpty();
+		}
+
+		@Test
+		void shouldTranslateSendPostfachMailCommand() {
+			doReturn(true).when(processor).isNotOutgoingPostfachNachrichtByNachrichtenManager(any());
+
+			process();
+
+			verify(processor).translateSendPostfachMailCommand(command);
+		}
+
+		@Test
+		void shouldReturnTranslatedSendPostfachMailCommand() {
+			var translatedCommandOrder = CommandTestFactory.create();
+			doReturn(true).when(processor).isNotOutgoingPostfachNachrichtByNachrichtenManager(any());
+			doReturn(translatedCommandOrder).when(processor).translateSendPostfachMailCommand(command);
+			doAnswer(invocation -> invocation.getArgument(0)).when(processor).translateReceivePostfachNachrichtCommand(any());
+
+			var commands = process();
+
+			assertThat(commands).containsExactly(translatedCommandOrder);
+		}
+
+		@Test
+		void shouldTranslateReceivePostfachNachrichtCommand() {
+			doReturn(true).when(processor).isNotOutgoingPostfachNachrichtByNachrichtenManager(any());
+			doAnswer(invocation -> invocation.getArgument(0)).when(processor).translateSendPostfachMailCommand(any());
+
+			process();
+
+			verify(processor).translateReceivePostfachNachrichtCommand(command);
+		}
+
+		@Test
+		void shouldReturnTranslatedReceivePostfachNachrichtCommand() {
+			var translatedCommandOrder = CommandTestFactory.create();
+			doReturn(true).when(processor).isNotOutgoingPostfachNachrichtByNachrichtenManager(any());
+			doAnswer(invocation -> invocation.getArgument(0)).when(processor).translateSendPostfachMailCommand(any());
+			doReturn(translatedCommandOrder).when(processor).translateReceivePostfachNachrichtCommand(command);
+
+			var commands = process();
+
+			assertThat(commands).containsExactly(translatedCommandOrder);
+		}
+
+		private List<Command> process() {
+			return processor.process(Stream.of(command)).toList();
+		}
+	}
+
+	@Nested
+	class TestIsNotOutgoingPostfachNachrichtenByNachrichtenManager {
+
+		private final Command matchingCommand = CommandTestFactory.createBuilder()
+				.order(CommandOrder.CREATE_ATTACHED_ITEM.name())
+				.body(Map.of("item", Map.of(PostfachNachrichtHistorieProcessor.DIRECTION, PostfachNachrichtHistorieProcessor.DIRECTION_OUTGOING),
+						PostfachNachrichtHistorieProcessor.CLIENT, PostfachNachrichtHistorieProcessor.OZGCLOUD_NACHRICHTEN_MANAGER))
+				.build();
+
+		@Test
+		void shouldReturnFalse() {
+			var result = processor.isNotOutgoingPostfachNachrichtByNachrichtenManager(matchingCommand);
+
+			assertThat(result).isFalse();
+		}
+
+		@Test
+		void shouldReturnTrueOnOtherOrder() {
+			var nonMatchingCommand = matchingCommand.toBuilder().order(LoremIpsum.getInstance().getWords(1)).build();
+
+			var result = processor.isNotOutgoingPostfachNachrichtByNachrichtenManager(nonMatchingCommand);
+
+			assertThat(result).isTrue();
+		}
+
+		@Test
+		void shouldReturnTrueOnIncoming() {
+			var commandBody = Map.of("item",
+					Map.of(PostfachNachrichtHistorieProcessor.DIRECTION, PostfachNachrichtHistorieProcessor.DIRECTION_INCOMMING),
+					PostfachNachrichtHistorieProcessor.CLIENT, PostfachNachrichtHistorieProcessor.OZGCLOUD_NACHRICHTEN_MANAGER);
+			var nonMatchingCommand = matchingCommand.toBuilder()
+					.body(commandBody)
+					.build();
+
+			var result = processor.isNotOutgoingPostfachNachrichtByNachrichtenManager(nonMatchingCommand);
+
+			assertThat(result).isTrue();
+		}
+
+		@Test
+		void shouldReturnTrueOnOtherClient() {
+			var commandBody = Map.of("item",
+					Map.of(PostfachNachrichtHistorieProcessor.DIRECTION, PostfachNachrichtHistorieProcessor.DIRECTION_OUTGOING),
+					PostfachNachrichtHistorieProcessor.CLIENT, LoremIpsum.getInstance().getWords(1));
+			var nonMatchingCommand = matchingCommand.toBuilder()
+					.body(commandBody)
+					.build();
+
+			var result = processor.isNotOutgoingPostfachNachrichtByNachrichtenManager(nonMatchingCommand);
+
+			assertThat(result).isTrue();
+		}
+	}
+
+	@Nested
+	class TestTranslateSendPostfachMailCommand {
+
+		@Nested
+		class TestOnHasSendPostfachMailOrder {
+			@Test
+			void shouldTranslateOrderToSendPostfachNachricht() {
+				var command = CommandTestFactory.createBuilder().order(CommandOrder.SEND_POSTFACH_MAIL.name()).build();
+				var expectedCommand = command.toBuilder().order(CommandOrder.SEND_POSTFACH_NACHRICHT.name()).build();
+
+				var resultCommand = processor.translateSendPostfachMailCommand(command);
+
+				assertThat(resultCommand).usingRecursiveComparison().isEqualTo(expectedCommand);
+			}
+		}
+
+		@Nested
+		class TestOnHasNotSendPostfachMailOrder {
+			@Test
+			void shouldReturnSameCommand() {
+				var command = CommandTestFactory.create();
+
+				var resultCommand = processor.translateSendPostfachMailCommand(command);
+
+				assertThat(resultCommand).isSameAs(command);
+			}
+		}
+	}
+
+	@Nested
+	class TestTranslateReceivePostfachNachrichtCommand {
+
+		private final Command command = CommandTestFactory.create();
+
+		@Test
+		void shouldCallIsIncomingNachrichtbyNachrichtenManager() {
+			processor.translateReceivePostfachNachrichtCommand(command);
+
+			verify(processor).isIncomingNachrichtByNachrichtenManager(command);
+		}
+
+		@Test
+		void shouldTranslateOnIsIncomingNachrichtbyNachrichtenManager() {
+			doReturn(true).when(processor).isIncomingNachrichtByNachrichtenManager(any());
+			var expectedCommand = command.toBuilder().order(CommandOrder.RECEIVE_POSTFACH_NACHRICHT.name()).build();
+
+			var resultCommand = processor.translateReceivePostfachNachrichtCommand(command);
+
+			assertThat(resultCommand).usingRecursiveComparison().isEqualTo(expectedCommand);
+		}
+
+		@Test
+		void shouldNotTranslateOnIsNotIncomingNachrichtbyNachrichtenManager() {
+			doReturn(false).when(processor).isIncomingNachrichtByNachrichtenManager(any());
+
+			var resultCommand = processor.translateReceivePostfachNachrichtCommand(command);
+
+			assertThat(resultCommand).isSameAs(command);
+		}
+	}
+
+	@Nested
+	class TestIsIncomingNachrichtByNachrichtenManager {
+
+		private final Command matchingCommand = CommandTestFactory.createBuilder()
+				.order(CommandOrder.CREATE_ATTACHED_ITEM.name())
+				.body(Map.of("item", Map.of(PostfachNachrichtHistorieProcessor.DIRECTION, PostfachNachrichtHistorieProcessor.DIRECTION_INCOMMING),
+						PostfachNachrichtHistorieProcessor.CLIENT, PostfachNachrichtHistorieProcessor.OZGCLOUD_NACHRICHTEN_MANAGER))
+				.build();
+
+		@Test
+		void shouldReturnTrue() {
+			var result = processor.isIncomingNachrichtByNachrichtenManager(matchingCommand);
+
+			assertThat(result).isTrue();
+		}
+
+		@Test
+		void shouldReturnFalseOnOtherOrder() {
+			var nonMatchingCommand = matchingCommand.toBuilder().order(LoremIpsum.getInstance().getWords(1)).build();
+
+			var result = processor.isIncomingNachrichtByNachrichtenManager(nonMatchingCommand);
+
+			assertThat(result).isFalse();
+		}
+
+		@Test
+		void shouldReturnFalseOnOutgoing() {
+			var commandBody = Map.of("item",
+					Map.of(PostfachNachrichtHistorieProcessor.DIRECTION, PostfachNachrichtHistorieProcessor.DIRECTION_OUTGOING),
+					PostfachNachrichtHistorieProcessor.CLIENT, PostfachNachrichtHistorieProcessor.OZGCLOUD_NACHRICHTEN_MANAGER);
+			var nonMatchingCommand = matchingCommand.toBuilder()
+					.body(commandBody)
+					.build();
+
+			var result = processor.isIncomingNachrichtByNachrichtenManager(nonMatchingCommand);
+
+			assertThat(result).isFalse();
+		}
+
+		@Test
+		void shouldReturnFalseOnOtherClient() {
+			var commandBody = Map.of("item",
+					Map.of(PostfachNachrichtHistorieProcessor.DIRECTION, PostfachNachrichtHistorieProcessor.DIRECTION_INCOMMING),
+					PostfachNachrichtHistorieProcessor.CLIENT, LoremIpsum.getInstance().getWords(1));
+			var nonMatchingCommand = matchingCommand.toBuilder()
+					.body(commandBody)
+					.build();
+
+			var result = processor.isIncomingNachrichtByNachrichtenManager(nonMatchingCommand);
+
+			assertThat(result).isFalse();
+		}
+	}
+}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageHistorieProcessorTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageHistorieProcessorTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..78662dc0cd55e2936abb48ea4bc597b4af52167d
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageHistorieProcessorTest.java
@@ -0,0 +1,261 @@
+package de.ozgcloud.alfa.wiedervorlage;
+
+import static org.assertj.core.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.*;
+
+import java.util.Map;
+import java.util.stream.Stream;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.mockito.Spy;
+import org.mockito.stubbing.Answer;
+
+import com.thedeanda.lorem.LoremIpsum;
+
+import de.ozgcloud.alfa.common.command.Command;
+import de.ozgcloud.alfa.common.command.CommandBodyMapper;
+import de.ozgcloud.alfa.common.command.CommandOrder;
+import de.ozgcloud.alfa.common.command.CommandTestFactory;
+import de.ozgcloud.alfa.common.command.LegacyOrder;
+import io.jsonwebtoken.lang.Collections;
+
+class WiedervorlageHistorieProcessorTest {
+
+	@Spy
+	private WiedervorlageHistorieProcessor processor;
+
+	@Nested
+	class TestProcess {
+
+		private final Command command = CommandTestFactory.create();
+		private final Command translatedCommand = CommandTestFactory.create();
+		private final Answer<Command> doNotTranslate = invocation -> invocation.getArgument(0);
+
+		@BeforeEach
+		void mockDefault() {
+			doAnswer(doNotTranslate).when(processor).translateCreateAttachedItem(any());
+			doAnswer(doNotTranslate).when(processor).translateUpdateAttachedItem(any());
+			doAnswer(doNotTranslate).when(processor).translatePatchAttachedItem(any());
+		}
+
+		@Test
+		void shouldPropagateAllOrders() {
+
+			var commands = processor.process(Stream.of(command));
+
+			assertThat(commands).containsExactly(command);
+		}
+
+		@Test
+		void shouldTranslateCreateAttachedItem() {
+			processor.process(Stream.of(command)).toList();
+
+			verify(processor).translateCreateAttachedItem(command);
+		}
+
+		@Test
+		void shouldReturnTranslatedCreateAttachedItem() {
+			doReturn(translatedCommand).when(processor).translateCreateAttachedItem(any());
+
+			var commands = processor.process(Stream.of(command)).toList();
+
+			assertThat(commands).containsExactly(translatedCommand);
+			reset(processor);
+		}
+
+		@Test
+		void shouldTranslateUpdateAttachedItem() {
+			processor.process(Stream.of(command)).toList();
+
+			verify(processor).translateUpdateAttachedItem(command);
+		}
+
+		@Test
+		void shouldReturnTranslatedUpdateAttachedItem() {
+			doReturn(translatedCommand).when(processor).translateUpdateAttachedItem(any());
+
+			var commands = processor.process(Stream.of(command)).toList();
+
+			assertThat(commands).containsExactly(translatedCommand);
+			reset(processor);
+		}
+
+		@Test
+		void shouldTranslatePatchAttachedItem() {
+			processor.process(Stream.of(command)).toList();
+
+			verify(processor).translatePatchAttachedItem(command);
+		}
+
+		@Test
+		void shouldReturnTranslatedPatchAttachedItem() {
+			doReturn(translatedCommand).when(processor).translatePatchAttachedItem(any());
+
+			var commands = processor.process(Stream.of(command)).toList();
+
+			assertThat(commands).containsExactly(translatedCommand);
+			reset(processor);
+		}
+	}
+
+	@Nested
+	class TestTranslateCreateAttachedItem {
+
+		private final Map<String, ?> commandBody = Map.of(CommandBodyMapper.ITEM_NAME_PROPERTY, Wiedervorlage.class.getSimpleName());
+		private final Command createWiedervorlageCommand = CommandTestFactory.createBuilder()
+				.order(CommandOrder.CREATE_ATTACHED_ITEM.name())
+				.body(commandBody)
+				.build();
+
+		@Test
+		void shouldTranslateOrderToCreateWiedervorlage() {
+			var expectedCommand = createWiedervorlageCommand.toBuilder().order(LegacyOrder.CREATE_WIEDERVORLAGE).build();
+
+			var translatedCommand = processor.translateCreateAttachedItem(createWiedervorlageCommand);
+
+			assertThat(translatedCommand).usingRecursiveComparison().isEqualTo(expectedCommand);
+		}
+
+		@Test
+		void shouldNotTranslateOtherOrderCommands() {
+			var command = createWiedervorlageCommand.toBuilder().order(LoremIpsum.getInstance().getWords(1)).build();
+
+			var translatedCommand = processor.translateCreateAttachedItem(command);
+
+			assertThat(translatedCommand).isSameAs(command);
+		}
+
+		@Test
+		void shouldNotTranslateOtherAttachedItems() {
+			var otherCommandBody = Map.of(CommandBodyMapper.ITEM_NAME_PROPERTY, LoremIpsum.getInstance().getWords(1));
+			var command = createWiedervorlageCommand.toBuilder().body(otherCommandBody).build();
+
+			var translatedCommand = processor.translateCreateAttachedItem(command);
+
+			assertThat(translatedCommand).isSameAs(command);
+		}
+	}
+
+	@Nested
+	class TestTranslateUpdateAttachedItem {
+
+		private final Map<String, ?> commandBody = Map.of(CommandBodyMapper.ITEM_NAME_PROPERTY, Wiedervorlage.class.getSimpleName());
+		private final Command editWiedervorlageCommand = CommandTestFactory.createBuilder()
+				.order(CommandOrder.UPDATE_ATTACHED_ITEM.name())
+				.body(commandBody)
+				.build();
+
+		@Test
+		void shouldTranslateOrderToEditWiedervorlage() {
+			var expectedCommand = editWiedervorlageCommand.toBuilder().order(LegacyOrder.EDIT_WIEDERVORLAGE).build();
+
+			var translatedCommand = processor.translateUpdateAttachedItem(editWiedervorlageCommand);
+
+			assertThat(translatedCommand).usingRecursiveComparison().isEqualTo(expectedCommand);
+		}
+
+		@Test
+		void shouldNotTranslateOtherOrderCommands() {
+			var command = editWiedervorlageCommand.toBuilder().order(LoremIpsum.getInstance().getWords(1)).build();
+
+			var translatedCommand = processor.translateUpdateAttachedItem(command);
+
+			assertThat(translatedCommand).isSameAs(command);
+		}
+
+		@Test
+		void shouldNotTranslateOtherAttachedItems() {
+			var otherCommandBody = Map.of(CommandBodyMapper.ITEM_NAME_PROPERTY, LoremIpsum.getInstance().getWords(1));
+			var command = editWiedervorlageCommand.toBuilder().body(otherCommandBody).build();
+
+			var translatedCommand = processor.translateUpdateAttachedItem(command);
+
+			assertThat(translatedCommand).isSameAs(command);
+		}
+	}
+
+	@Nested
+	class TestTranslatePatchAttachedItem {
+
+		private final Map<String, ?> commandBody = Map.of(CommandBodyMapper.ITEM_NAME_PROPERTY, Wiedervorlage.class.getSimpleName());
+		private final Command patchWiedervorlageCommand = CommandTestFactory.createBuilder()
+				.order(CommandOrder.PATCH_ATTACHED_ITEM.name())
+				.body(commandBody)
+				.build();
+
+		@Test
+		void shouldCallTranslatePatchWiedervorlage() {
+			processor.translatePatchAttachedItem(patchWiedervorlageCommand);
+
+			verify(processor).translatePatchWiedervorlage(patchWiedervorlageCommand);
+		}
+
+		@Test
+		void shouldReturnTranslatedCommand() {
+			var translatedCommand = CommandTestFactory.create();
+			doReturn(translatedCommand).when(processor).translatePatchWiedervorlage(any());
+
+			var resultCommand = processor.translatePatchAttachedItem(patchWiedervorlageCommand);
+
+			assertThat(resultCommand).isSameAs(translatedCommand);
+		}
+
+		@Test
+		void shouldNotTranslateOtherOrderCommands() {
+			var command = patchWiedervorlageCommand.toBuilder().order(LoremIpsum.getInstance().getWords(1)).build();
+
+			var translatedCommand = processor.translatePatchAttachedItem(command);
+
+			assertThat(translatedCommand).isSameAs(command);
+		}
+
+		@Test
+		void shouldNotTranslateOtherAttachedItems() {
+			var otherCommandBody = Map.of(CommandBodyMapper.ITEM_NAME_PROPERTY, LoremIpsum.getInstance().getWords(1));
+			var command = patchWiedervorlageCommand.toBuilder().body(otherCommandBody).build();
+
+			var translatedCommand = processor.translatePatchAttachedItem(command);
+
+			assertThat(translatedCommand).isSameAs(command);
+		}
+	}
+
+	@Nested
+	class TestTranslatePatchWiedervorlage {
+
+		@Test
+		void shouldReturnWiedervorlageErledigenCommand() {
+			var commandBody = Map.of(CommandBodyMapper.ITEM_PROPERTY, Map.of(Wiedervorlage.DONE_FIELD, true));
+			var command = CommandTestFactory.createBuilder().body(commandBody).build();
+			var expectedCommand = command.toBuilder().order(LegacyOrder.WIEDERVORLAGE_ERLEDIGEN);
+
+			var translatedCommand = processor.translatePatchWiedervorlage(command);
+
+			assertThat(translatedCommand).usingRecursiveComparison().isEqualTo(expectedCommand);
+		}
+
+		@Test
+		void shouldReturnWiedervorlageWiedereroeffnenCommand() {
+			var commandBody = Map.of(CommandBodyMapper.ITEM_PROPERTY, Map.of(Wiedervorlage.DONE_FIELD, false));
+			var command = CommandTestFactory.createBuilder().body(commandBody).build();
+			var expectedCommand = command.toBuilder().order(LegacyOrder.WIEDERVORLAGE_WIEDEREROEFFNEN);
+
+			var translatedCommand = processor.translatePatchWiedervorlage(command);
+
+			assertThat(translatedCommand).usingRecursiveComparison().isEqualTo(expectedCommand);
+		}
+
+		@Test
+		void shouldNotTranslateOnMissingBoolean() {
+			var commandBody = Map.of(CommandBodyMapper.ITEM_PROPERTY, Collections.emptyMap());
+			var command = CommandTestFactory.createBuilder().body(commandBody).build();
+
+			var translatedCommand = processor.translatePatchWiedervorlage(command);
+
+			assertThat(translatedCommand).isSameAs(command);
+		}
+	}
+}