diff --git a/pom.xml b/pom.xml
index 11774d31e3a7e94b242b60584d061966167dc89d..ae94f89fffaf1a8fcdb6ad3f7349a46f32923d45 100644
--- a/pom.xml
+++ b/pom.xml
@@ -41,7 +41,7 @@
 	<inceptionYear>2024</inceptionYear>
 
 	<properties>
-		<ozgcloud.api-lib.version>0.17.0</ozgcloud.api-lib.version>
+		<ozgcloud.api-lib.version>0.18.0-SNAPSHOT</ozgcloud.api-lib.version>
 		<jslt.version>0.1.14</jslt.version>
 		<hibernate-validator.version>8.0.2.Final</hibernate-validator.version>
 		<spring-boot.build-image.imageName>docker.ozg-sh.de/aggregation-manager:build-latest</spring-boot.build-image.imageName>
diff --git a/src/main/java/de/ozgcloud/aggregation/AggregationManagerRunner.java b/src/main/java/de/ozgcloud/aggregation/AggregationManagerRunner.java
index c08af99ce4121083c767fdb8ba3adb4d5503c0ef..3629c317ecacf3a46c778bab7472af4c11fea46b 100644
--- a/src/main/java/de/ozgcloud/aggregation/AggregationManagerRunner.java
+++ b/src/main/java/de/ozgcloud/aggregation/AggregationManagerRunner.java
@@ -26,8 +26,12 @@ package de.ozgcloud.aggregation;
 import java.util.List;
 import java.util.Objects;
 import java.util.UUID;
+import java.util.function.Function;
+import java.util.function.IntFunction;
+import java.util.function.IntPredicate;
 import java.util.function.Predicate;
 import java.util.function.UnaryOperator;
+import java.util.stream.IntStream;
 import java.util.stream.Stream;
 
 import org.apache.logging.log4j.CloseableThreadContext;
@@ -39,12 +43,15 @@ import org.springframework.stereotype.Component;
 import de.ozgcloud.aggregation.transformation.Transformation;
 import de.ozgcloud.aggregation.transformation.TransformationException;
 import de.ozgcloud.aggregation.transformation.TransformationService;
+import de.ozgcloud.aggregation.transformation.VorgangMapper;
 import de.ozgcloud.aggregation.warehouse.DocumentEntry;
 import de.ozgcloud.aggregation.warehouse.WarehouseRepository;
 import de.ozgcloud.apilib.vorgang.OzgCloudVorgang;
 import de.ozgcloud.apilib.vorgang.OzgCloudVorgangQuery;
 import de.ozgcloud.apilib.vorgang.OzgCloudVorgangService;
+import de.ozgcloud.apilib.vorgang.OzgCloudVorgangStub;
 import de.ozgcloud.apilib.vorgang.Page;
+import lombok.Getter;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.log4j.Log4j2;
 
@@ -60,14 +67,13 @@ public class AggregationManagerRunner implements CommandLineRunner {
 	private static final Predicate<Batch> HAS_NEXT_BATCH = x -> !x.items.isEmpty();
 
 	private final OzgCloudVorgangService vorgangService;
-
 	private final AggregationManagerConfiguration config;
 
 	private final TransformationProperties transformationProperties;
 
 	private final TransformationService transformationService;
-
 	private final WarehouseRepository repository;
+	private final VorgangMapper vorgangMapper;
 
 	@Override
 	public void run(String... args) throws TransformationException {
@@ -85,34 +91,72 @@ public class AggregationManagerRunner implements CommandLineRunner {
 	void runWithTransformation(Transformation transformation) {
 		try (Execution execution = new Execution(transformation)) {
 			ThreadContext.put(MDC_EXECUTION, execution.id.toString());
-			extractBatchesFromDataSource(execution).map(this::transformBatches).forEach(this::loadBatchesIntoRepository);
+			loadVorgaengeIntoRepository(Stream.concat(
+					extractBatchesOfVorgaengeFromDataSource(execution),
+					extractBatchesOfDeletedVorgaengeFromDataSource(execution)));
 		} finally {
 			ThreadContext.remove(MDC_EXECUTION);
 		}
 	}
 
-	Stream<Batch> extractBatchesFromDataSource(Execution execution) {
+	void loadVorgaengeIntoRepository(Stream<Batch> batches) {
+		batches.map(this::transformBatchToDocumentEntries).forEach(this::loadDocumentEntriesIntoRepository);
+	}
+
+	Stream<Batch> extractBatchesOfVorgaengeFromDataSource(Execution execution) {
+		return extractBatchesFromDataSource(execution, this::getVorgaengeFromDataSource);
+	}
+
+	List<OzgCloudVorgang> getVorgaengeFromDataSource(Page page) {
+		return vorgangService.find(buildFindAllQuery(), page).stream()
+				.map(vorgangStub -> vorgangService.getById(vorgangStub.getId()))
+				.toList();
+	}
+
+	OzgCloudVorgangQuery buildFindAllQuery() {
+		return OzgCloudVorgangQuery.builder().build();
+	}
+
+	Stream<Batch> extractBatchesOfDeletedVorgaengeFromDataSource(Execution execution) {
+		return extractBatchesFromDataSource(execution, getPagedDeletedVorgaenge(vorgangService.findDeleted()));
+	}
+
+	Function<Page, List<OzgCloudVorgang>> getPagedDeletedVorgaenge(Stream<OzgCloudVorgangStub> allDeletedVorgaenge) {
+		var it = allDeletedVorgaenge.iterator();
+		IntPredicate hasNextVorgangStub = ignored -> it.hasNext();
+		IntFunction<OzgCloudVorgangStub> nextVorgangStub = ignored -> it.next();
+		return page -> IntStream.range(page.getOffset(), page.getOffset() + page.getLimit())
+				.takeWhile(hasNextVorgangStub)
+				.mapToObj(nextVorgangStub)
+				.map(vorgangMapper::fromVorgangStub)
+				.toList();
+	}
+
+	Stream<Batch> extractBatchesFromDataSource(Execution execution, Function<Page, List<OzgCloudVorgang>> getFromDataSource) {
 		var fetchSize = config.getFetchingBatchSize();
-		var initialBatch = createBatch(execution, 0, fetchSize);
-		UnaryOperator<Batch> nextBatch = x -> createBatch(execution, x.page.getOffset() + fetchSize, fetchSize);
+		var initialBatch = createBatch(execution, Page.builder().offset(0).limit(fetchSize).build(), getFromDataSource);
+		UnaryOperator<Batch> nextBatch = x -> createBatch(
+				execution,
+				Page.builder().offset(x.page.getOffset() + fetchSize).limit(fetchSize).build(),
+				getFromDataSource);
 		return Stream.iterate(initialBatch, HAS_NEXT_BATCH, nextBatch).filter(x -> !x.items.isEmpty());
 	}
 
-	private Batch createBatch(Execution execution, int offset, int size) {
-		var page = Page.builder().offset(offset).limit(size).build();
-		var matchAll = OzgCloudVorgangQuery.builder().build();
-		var data = vorgangService.find(matchAll, page).stream().map(e -> vorgangService.getById(e.getId()))
-				.toList();
-		return new Batch(execution, UUID.randomUUID(), page, data);
+	private Batch createBatch(Execution execution, Page page, Function<Page, List<OzgCloudVorgang>> getFromDataSource) {
+		return new Batch(execution, createBatchUUID(), page, getFromDataSource.apply(page));
+	}
+
+	UUID createBatchUUID() {
+		return UUID.randomUUID();
 	}
 
-	void loadBatchesIntoRepository(Stream<DocumentEntry> entries) {
+	void loadDocumentEntriesIntoRepository(Stream<DocumentEntry> entries) {
 		final List<DocumentEntry> documents = entries.toList();
 		LOG.atDebug().log("store documents: {}", () -> documents.stream().map(DocumentEntry::getId).toList());
 		repository.saveAll(documents);
 	}
 
-	Stream<DocumentEntry> transformBatches(Batch batch) {
+	Stream<DocumentEntry> transformBatchToDocumentEntries(Batch batch) {
 		return batch.items.stream().map(vorgang -> transformWithinBatch(batch, vorgang)).filter(Objects::nonNull);
 	}
 
@@ -121,7 +165,7 @@ public class AggregationManagerRunner implements CommandLineRunner {
 			return batch.execution.transformation.apply(vorgang);
 		} catch (TransformationException e) {
 			LOG.atError().withThrowable(e).log("failed to transform vorgang [{}] in batch [{}] of execution [{}]",
-					() -> vorgang.getId(), () -> batch.id, () -> batch.execution.id);
+					vorgang::getId, () -> batch.id, () -> batch.execution.id);
 			return null;
 		}
 	}
@@ -129,6 +173,7 @@ public class AggregationManagerRunner implements CommandLineRunner {
 	@RequiredArgsConstructor
 	protected static class Execution implements AutoCloseable {
 		private final UUID id = UUID.randomUUID();
+		@Getter
 		private final Transformation transformation;
 
 		@Override
diff --git a/src/main/java/de/ozgcloud/aggregation/transformation/JSLTransformationService.java b/src/main/java/de/ozgcloud/aggregation/transformation/JSLTransformationService.java
index 8575a6b07fb001f35e6d289633ed9032506c5994..51a81b9f543d4beae28614c8e8f969a61ed26a6f 100644
--- a/src/main/java/de/ozgcloud/aggregation/transformation/JSLTransformationService.java
+++ b/src/main/java/de/ozgcloud/aggregation/transformation/JSLTransformationService.java
@@ -47,12 +47,12 @@ import com.schibsted.spt.data.jslt.impl.PairExpression;
 import de.ozgcloud.aggregation.transformation.AggregationMapping.FieldMapping;
 import lombok.RequiredArgsConstructor;
 
-@Service
-@RequiredArgsConstructor
 /**
  * JSTL implementation of the {@link TransformationService}. This service
  * internally uses JSLT {@link Expression} for {@link Transformation}s
  */
+@Service
+@RequiredArgsConstructor
 public class JSLTransformationService implements TransformationService {
 
 	private static final LetExpression[] EMPTY_TEMPLATES = new LetExpression[] {};
@@ -103,7 +103,7 @@ public class JSLTransformationService implements TransformationService {
 			for (var field : fields) {
 				current = new DotExpression(field, current, null);
 			}
-			return Optional.of(current);
+			return Optional.ofNullable(current);
 		}
 	}
 
diff --git a/src/main/java/de/ozgcloud/aggregation/transformation/Transformation.java b/src/main/java/de/ozgcloud/aggregation/transformation/Transformation.java
index 6420f11e79f95875e349a43930c7e197476b56d2..1616f30665b1b9b223aba9204354e7a7bc9a57eb 100644
--- a/src/main/java/de/ozgcloud/aggregation/transformation/Transformation.java
+++ b/src/main/java/de/ozgcloud/aggregation/transformation/Transformation.java
@@ -41,6 +41,6 @@ public interface Transformation {
 	 * @throws TransformationException when the {@link Transformation} could not be
 	 *                                 applied to the given {@link OzgCloudVorgang}
 	 */
-	public DocumentEntry apply(OzgCloudVorgang vorgang) throws TransformationException;
+	DocumentEntry apply(OzgCloudVorgang vorgang) throws TransformationException;
 
 }
diff --git a/src/main/java/de/ozgcloud/aggregation/transformation/VorgangMapper.java b/src/main/java/de/ozgcloud/aggregation/transformation/VorgangMapper.java
index 606596aa88d2dbf4239272539862b3b4d3bcdb0f..04c6f87748d292fda01b599086eb5b9005c1920e 100644
--- a/src/main/java/de/ozgcloud/aggregation/transformation/VorgangMapper.java
+++ b/src/main/java/de/ozgcloud/aggregation/transformation/VorgangMapper.java
@@ -31,6 +31,7 @@ import de.ozgcloud.aggregation.warehouse.DocumentEntry.DocumentEntryBuilder;
 import de.ozgcloud.apilib.vorgang.OzgCloudVorgang;
 import de.ozgcloud.apilib.vorgang.OzgCloudVorgangId;
 import de.ozgcloud.apilib.vorgang.OzgCloudVorgangStatus;
+import de.ozgcloud.apilib.vorgang.OzgCloudVorgangStub;
 
 @Mapper
 public interface VorgangMapper {
@@ -41,6 +42,9 @@ public interface VorgangMapper {
 	@Mapping(target = "vorgangsname", source = "vorgangName")
 	DocumentEntryBuilder toDocumentEntryBuilder(OzgCloudVorgang vorgang, @MappingTarget DocumentEntryBuilder builder);
 
+	@Mapping(target = "eingangs", ignore = true)
+	OzgCloudVorgang fromVorgangStub(OzgCloudVorgangStub vorgangStub);
+
 	default String idToString(OzgCloudVorgangId id) {
 		return id.toString();
 	}
diff --git a/src/test/java/de/ozgcloud/aggregation/AggregationManagerRunnerITCase.java b/src/test/java/de/ozgcloud/aggregation/AggregationManagerRunnerITCase.java
index c108972abc8bfcb4041a02a9a10a8d3cf0d5ed96..c7ebb19305b6318b97af1787a0acb02456d4c084 100644
--- a/src/test/java/de/ozgcloud/aggregation/AggregationManagerRunnerITCase.java
+++ b/src/test/java/de/ozgcloud/aggregation/AggregationManagerRunnerITCase.java
@@ -27,6 +27,7 @@ import static org.assertj.core.api.Assertions.*;
 import static org.mockito.ArgumentMatchers.*;
 import static org.mockito.Mockito.*;
 
+import java.time.ZoneId;
 import java.time.ZonedDateTime;
 import java.time.temporal.ChronoUnit;
 import java.util.Collections;
@@ -44,6 +45,8 @@ import org.springframework.test.context.TestPropertySource;
 import org.springframework.test.context.bean.override.mockito.MockitoSpyBean;
 
 import de.ozgcloud.aggregation.warehouse.DocumentEntry;
+import de.ozgcloud.aggregation.warehouse.DocumentEntryTestFactory;
+import de.ozgcloud.aggregation.warehouse.ObjectNodeTestFactory;
 import de.ozgcloud.aggregation.warehouse.WarehouseRepository;
 import de.ozgcloud.apilib.vorgang.OzgCloudVorgang;
 import de.ozgcloud.apilib.vorgang.OzgCloudVorgangHeader;
@@ -51,6 +54,7 @@ import de.ozgcloud.apilib.vorgang.OzgCloudVorgangHeaderTestFactory;
 import de.ozgcloud.apilib.vorgang.OzgCloudVorgangId;
 import de.ozgcloud.apilib.vorgang.OzgCloudVorgangService;
 import de.ozgcloud.apilib.vorgang.OzgCloudVorgangStub;
+import de.ozgcloud.apilib.vorgang.OzgCloudVorgangStubTestFactory;
 import de.ozgcloud.apilib.vorgang.OzgCloudVorgangTestFactory;
 import de.ozgcloud.apilib.vorgang.Page;
 import de.ozgcloud.common.test.DataITCase;
@@ -73,8 +77,6 @@ class AggregationManagerRunnerITCase {
 	@Nested
 	class TestRun {
 
-		private static final OzgCloudVorgang VORGANG = TestConfig.VORGANGS.get(0);
-
 		@BeforeEach
 		void setUp() {
 			repository.deleteAll();
@@ -84,43 +86,73 @@ class AggregationManagerRunnerITCase {
 		void shouldProcessAllData() {
 			runner.run();
 
-			assertThat(repository.count()).isEqualTo(TestConfig.NUMBER_OF_VORGAENGE);
+			assertThat(repository.count()).isEqualTo(TestConfig.NUMBER_OF_VORGAENGE + TestConfig.NUMBER_OF_VORGANG_STUBS);
 		}
 
-		@Test
-		void shouldHaveEingangsdatum() {
-			runner.run();
+		@Nested
+		class TestVorgangDocument {
 
-			var document = findVorgangDocument();
-			assertThat(document.getEingangsdatum()).isCloseTo(VORGANG.getHeader().getCreatedAt(), within(1, ChronoUnit.MILLIS));
-		}
+			private static final OzgCloudVorgang VORGANG = TestConfig.VORGANGS.getFirst();
 
-		@Test
-		void shouldHaveVorgangName() {
-			runner.run();
+			@Test
+			void shouldHaveEingangsdatum() {
+				runner.run();
 
-			var document = findVorgangDocument();
-			assertThat(document.getVorgangsname()).isEqualTo(VORGANG.getVorgangName());
-		}
+				var document = findVorgangDocument();
+				assertThat(document.getEingangsdatum()).isCloseTo(VORGANG.getHeader().getCreatedAt(), within(1, ChronoUnit.MILLIS));
+			}
 
-		@Test
-		void shouldHaveStatus() {
-			runner.run();
+			@Test
+			void shouldHaveVorgangName() {
+				runner.run();
 
-			var document = findVorgangDocument();
-			assertThat(document.getStatus()).isEqualTo(VORGANG.getHeader().getStatus().toString());
-		}
+				var document = findVorgangDocument();
+				assertThat(document.getVorgangsname()).isEqualTo(VORGANG.getVorgangName());
+			}
 
-		@Test
-		void shouldNotHaveAnyPayload() {
-			runner.run();
+			@Test
+			void shouldHaveStatus() {
+				runner.run();
+
+				var document = findVorgangDocument();
+				assertThat(document.getStatus()).isEqualTo(VORGANG.getHeader().getStatus().toString());
+			}
+
+			@Test
+			void shouldNotHaveAnyPayload() {
+				runner.run();
 
-			var document = findVorgangDocument();
-			assertThat(document.getPayload()).isEmpty();
+				var document = findVorgangDocument();
+				assertThat(document.getPayload()).isEmpty();
+			}
+
+			private DocumentEntry findVorgangDocument() {
+				return repository.findById(VORGANG.getId().toString()).get();
+			}
 		}
 
-		private DocumentEntry findVorgangDocument() {
-			return repository.findById(VORGANG.getId().toString()).get();
+		@Nested
+		class TestVorgangStubDocument {
+
+			private static final OzgCloudVorgangStub VORGANG_STUB = TestConfig.VORGANG_STUBS.getFirst();
+
+			@Test
+			void shouldHaveValues() {
+				var expected = DocumentEntryTestFactory.createBuilder()
+						.id(VORGANG_STUB.getId().toString())
+						.eingangsdatum(DocumentEntryTestFactory.EINGANGSDATUM.withZoneSameInstant(ZoneId.systemDefault()))
+						.payload(ObjectNodeTestFactory.create().removeAll())
+						.build();
+
+				runner.run();
+
+				assertThat(findVorgangStubDocument()).usingRecursiveComparison().isEqualTo(expected);
+
+			}
+
+			private DocumentEntry findVorgangStubDocument() {
+				return repository.findById(VORGANG_STUB.getId().toString()).get();
+			}
 		}
 	}
 
@@ -130,9 +162,12 @@ class AggregationManagerRunnerITCase {
 		private static final int NUMBER_OF_VORGAENGE = 10;
 		public static final List<OzgCloudVorgang> VORGANGS = createVorgaenge();
 
+		private static final int NUMBER_OF_VORGANG_STUBS = 5;
+		public static final List<OzgCloudVorgangStub> VORGANG_STUBS = createVorgangStubs();
+
 		private static List<OzgCloudVorgang> createVorgaenge() {
 			return IntStream.range(0, NUMBER_OF_VORGAENGE)
-					.mapToObj(i -> createVorgang(i))
+					.mapToObj(TestConfig::createVorgang)
 					.toList();
 		}
 
@@ -147,7 +182,7 @@ class AggregationManagerRunnerITCase {
 
 		private static OzgCloudVorgangHeader createHeader(int i) {
 			return OzgCloudVorgangHeaderTestFactory.createBuilder()
-					.createdAt(ZonedDateTime.now().minus(1, ChronoUnit.DAYS))
+					.createdAt(ZonedDateTime.now().minusDays(1))
 					.aktenzeichen("akt-" + i).build();
 		}
 
@@ -156,6 +191,16 @@ class AggregationManagerRunnerITCase {
 					.vorgangNummer(vorgang.getVorgangNummer()).header(vorgang.getHeader()).build();
 		}
 
+		private static List<OzgCloudVorgangStub> createVorgangStubs() {
+			return IntStream.range(0, NUMBER_OF_VORGANG_STUBS).mapToObj(TestConfig::createVorgangStub).toList();
+		}
+
+		private static OzgCloudVorgangStub createVorgangStub(int i) {
+			return OzgCloudVorgangStubTestFactory.createBuilder()
+					.id(OzgCloudVorgangId.from("stub-id" + i))
+					.build();
+		}
+
 		@Bean
 		@Primary
 		OzgCloudVorgangService vorgangService() {
@@ -176,6 +221,8 @@ class AggregationManagerRunnerITCase {
 					.thenAnswer(i -> VORGANGS.stream().filter(vorgang -> vorgang.getId().equals(i.getArgument(0)))
 							.findFirst().orElse(null));
 
+			when(vorgangService.findDeleted()).thenAnswer(i -> VORGANG_STUBS.stream());
+
 			return vorgangService;
 		}
 
diff --git a/src/test/java/de/ozgcloud/aggregation/AggregationManagerRunnerTest.java b/src/test/java/de/ozgcloud/aggregation/AggregationManagerRunnerTest.java
index 95e5495c5c4aed3efe3bcc4e2c51281e7c1643e5..b9e7f4c3aa06073458d6485d9281d0af9d427ca2 100644
--- a/src/test/java/de/ozgcloud/aggregation/AggregationManagerRunnerTest.java
+++ b/src/test/java/de/ozgcloud/aggregation/AggregationManagerRunnerTest.java
@@ -23,36 +23,63 @@
  */
 package de.ozgcloud.aggregation;
 
+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.UUID;
+import java.util.function.Function;
+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.ArgumentCaptor;
+import org.mockito.ArgumentMatcher;
+import org.mockito.Captor;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.Spy;
 
 import com.thedeanda.lorem.LoremIpsum;
 
+import de.ozgcloud.aggregation.AggregationManagerRunner.Batch;
+import de.ozgcloud.aggregation.AggregationManagerRunner.Execution;
 import de.ozgcloud.aggregation.transformation.AggregationMapping;
 import de.ozgcloud.aggregation.transformation.AggregationMappingTestFactory;
 import de.ozgcloud.aggregation.transformation.Transformation;
 import de.ozgcloud.aggregation.transformation.TransformationService;
+import de.ozgcloud.aggregation.transformation.VorgangMapper;
+import de.ozgcloud.aggregation.warehouse.DocumentEntry;
+import de.ozgcloud.aggregation.warehouse.DocumentEntryTestFactory;
+import de.ozgcloud.aggregation.warehouse.WarehouseRepository;
+import de.ozgcloud.apilib.vorgang.OzgCloudVorgang;
+import de.ozgcloud.apilib.vorgang.OzgCloudVorgangQuery;
+import de.ozgcloud.apilib.vorgang.OzgCloudVorgangService;
+import de.ozgcloud.apilib.vorgang.OzgCloudVorgangStub;
+import de.ozgcloud.apilib.vorgang.OzgCloudVorgangStubTestFactory;
+import de.ozgcloud.apilib.vorgang.OzgCloudVorgangTestFactory;
+import de.ozgcloud.apilib.vorgang.Page;
 
 class AggregationManagerRunnerTest {
 
-	@InjectMocks
-	@Spy
-	private AggregationManagerRunner runner;
-
+	@Mock
+	private OzgCloudVorgangService vorgangService;
+	@Mock
+	private AggregationManagerConfiguration config;
 	@Mock
 	private TransformationProperties transformationProperties;
 	@Mock
 	private TransformationService transformationService;
+	@Mock
+	private WarehouseRepository repository;
+	@Mock
+	private VorgangMapper vorgangMapper;
+	@Spy
+	@InjectMocks
+	private AggregationManagerRunner runner;
 
 	@Nested
 	class TestRun {
@@ -162,4 +189,310 @@ class AggregationManagerRunnerTest {
 			}
 		}
 	}
+
+	@Nested
+	class TestRunWithTransformation {
+
+		@Mock
+		private Transformation transformation;
+		private final ArgumentMatcher<Execution> hasTransformation = execution -> execution.getTransformation().equals(transformation);
+		@Mock
+		private Batch batchOfVorgaenge;
+		@Mock
+		private Batch batchOfDeletedVorgaenge;
+		@Captor
+		private ArgumentCaptor<Stream<Batch>> batchStreamCaptor;
+
+		@BeforeEach
+		void init() {
+			doReturn(Stream.of(batchOfVorgaenge)).when(runner).extractBatchesOfVorgaengeFromDataSource(any());
+			doReturn(Stream.of(batchOfDeletedVorgaenge)).when(runner).extractBatchesOfDeletedVorgaengeFromDataSource(any());
+			doNothing().when(runner).loadVorgaengeIntoRepository(any());
+		}
+
+		@Test
+		void shouldExtractBatchesOfVorgaengeFromDataSource() {
+			runner.runWithTransformation(transformation);
+
+			verify(runner).extractBatchesOfVorgaengeFromDataSource(argThat(hasTransformation));
+		}
+
+		@Test
+		void shouldExtractBatchesOfDeletedVorgaengeFromDataSource() {
+			runner.runWithTransformation(transformation);
+
+			verify(runner).extractBatchesOfDeletedVorgaengeFromDataSource(argThat(hasTransformation));
+		}
+
+		@Test
+		void shouldLoadVorgaengeIntoRepository() {
+			runner.runWithTransformation(transformation);
+
+			verify(runner).loadVorgaengeIntoRepository(batchStreamCaptor.capture());
+			assertThat(batchStreamCaptor.getValue()).containsExactly(batchOfVorgaenge, batchOfDeletedVorgaenge);
+		}
+	}
+
+	@Nested
+	class TestLoadVorgaengeIntoRepository {
+
+		@Mock
+		private Execution execution;
+		@Mock
+		private Batch batch;
+		private final DocumentEntry documentEntry = DocumentEntryTestFactory.create();
+		@Captor
+		private ArgumentCaptor<Stream<DocumentEntry>> documentEntriesCaptor;
+
+		@BeforeEach
+		void init() {
+			doReturn(Stream.of(documentEntry)).when(runner).transformBatchToDocumentEntries(any());
+			doNothing().when(runner).loadDocumentEntriesIntoRepository(any());
+		}
+
+		@Test
+		void shouldTransform() {
+			loadVorgaengeIntoRepository();
+
+			verify(runner).transformBatchToDocumentEntries(batch);
+		}
+
+		@Test
+		void shouldLoadIntoRepository() {
+			loadVorgaengeIntoRepository();
+
+			verify(runner).loadDocumentEntriesIntoRepository(documentEntriesCaptor.capture());
+			assertThat(documentEntriesCaptor.getValue()).containsExactly(documentEntry);
+		}
+
+		private void loadVorgaengeIntoRepository() {
+			runner.loadVorgaengeIntoRepository(Stream.of(batch));
+		}
+	}
+
+	@Nested
+	class TestExtractBatchesOfVorgaengeFromDataSource {
+
+		@Mock
+		private Execution execution;
+		@Captor
+		private ArgumentCaptor<Function<Page, List<OzgCloudVorgang>>> functionToRetrieveDataCaptor;
+		@Mock
+		private Batch batch;
+		@Mock
+		private Page page;
+
+		@BeforeEach
+		void init() {
+			doReturn(Stream.of(batch)).when(runner).extractBatchesFromDataSource(any(), any());
+		}
+
+		@Test
+		void shouldExtract() {
+			runner.extractBatchesOfVorgaengeFromDataSource(execution);
+
+			verify(runner).extractBatchesFromDataSource(eq(execution), any());
+		}
+
+		@Test
+		void shouldExtractWithDataRetrievalFunction() {
+			runner.extractBatchesOfVorgaengeFromDataSource(execution);
+
+			verify(runner).extractBatchesFromDataSource(eq(execution), functionToRetrieveDataCaptor.capture());
+			functionToRetrieveDataCaptor.getValue().apply(page);
+			verify(runner).getVorgaengeFromDataSource(page);
+		}
+
+		@Test
+		void shouldReturnExtractedBatches() {
+			var extracted = runner.extractBatchesOfVorgaengeFromDataSource(execution);
+
+			assertThat(extracted).containsExactly(batch);
+		}
+	}
+
+	@Nested
+	class TestGetVorgaengeFromDataSource {
+
+		private final Page page = Page.builder().offset(10).limit(2).build();
+		private final OzgCloudVorgangQuery query = OzgCloudVorgangQuery.builder().build();
+
+		@BeforeEach
+		void init() {
+			doReturn(query).when(runner).buildFindAllQuery();
+			when(vorgangService.find(any(), any())).thenReturn(List.of(OzgCloudVorgangStubTestFactory.create()));
+			when(vorgangService.getById(any())).thenReturn(OzgCloudVorgangTestFactory.create());
+		}
+
+		@Test
+		void shouldCallVorgangService() {
+			getVorgaengeFromDataSource();
+
+			verify(vorgangService).find(query, page);
+		}
+
+		@Test
+		void shouldGetVorgangDetails() {
+			getVorgaengeFromDataSource();
+
+			verify(vorgangService).getById(OzgCloudVorgangTestFactory.ID);
+		}
+
+		@Test
+		void shouldReturnVorgangDetails() {
+			var vorgaenge = getVorgaengeFromDataSource();
+
+			assertThat(vorgaenge).usingRecursiveFieldByFieldElementComparator().containsExactly(OzgCloudVorgangTestFactory.create());
+		}
+
+		private List<OzgCloudVorgang> getVorgaengeFromDataSource() {
+			return runner.getVorgaengeFromDataSource(page);
+		}
+	}
+
+	@Nested
+	class TestExtractBatchesOfDeletedVorgaengeFromDataSource {
+
+		@Mock
+		private Execution execution;
+		@Mock
+		private Function<Page, List<OzgCloudVorgang>> functionToRetrieveData;
+		private final List<OzgCloudVorgangStub> deletedVorgaenge = List.of(OzgCloudVorgangStubTestFactory.create());
+		@Captor
+		private ArgumentCaptor<Stream<OzgCloudVorgangStub>> deletedVorgaengeCaptor;
+		@Mock
+		private Batch batch;
+
+		@BeforeEach
+		void init() {
+			when(vorgangService.findDeleted()).thenReturn(deletedVorgaenge.stream());
+			doReturn(functionToRetrieveData).when(runner).getPagedDeletedVorgaenge(any());
+			doReturn(Stream.of(batch)).when(runner).extractBatchesFromDataSource(any(), any());
+		}
+
+		@Test
+		void shouldFindDeleted() {
+			runner.extractBatchesOfDeletedVorgaengeFromDataSource(execution);
+
+			verify(vorgangService).findDeleted();
+		}
+
+		@Test
+		void shouldGetPagedDeletedVorgaenge() {
+			runner.extractBatchesOfDeletedVorgaengeFromDataSource(execution);
+
+			verify(runner).getPagedDeletedVorgaenge(deletedVorgaengeCaptor.capture());
+			assertThat(deletedVorgaengeCaptor.getValue()).usingRecursiveFieldByFieldElementComparator().containsExactlyElementsOf(deletedVorgaenge);
+		}
+
+		@Test
+		void shouldExtractWithDataRetrievalFunction() {
+			runner.extractBatchesOfDeletedVorgaengeFromDataSource(execution);
+
+			verify(runner).extractBatchesFromDataSource(execution, functionToRetrieveData);
+		}
+
+		@Test
+		void shouldReturnExtractedBatches() {
+			var extracted = runner.extractBatchesOfDeletedVorgaengeFromDataSource(execution);
+
+			assertThat(extracted).containsExactly(batch);
+		}
+	}
+
+	@Nested
+	class TestGetPagedDeletedVorgaenge {
+
+		private static final int PAGE_SIZE = 2;
+
+		private final Stream<OzgCloudVorgangStub> vorgangStubs = Stream.generate(OzgCloudVorgangStubTestFactory::create).limit(PAGE_SIZE + 1);
+
+		@Test
+		void shouldReturnFirstFullPage() {
+			var pagingFunction = runner.getPagedDeletedVorgaenge(vorgangStubs);
+
+			var vorgaenge = getFirstPage(pagingFunction);
+
+			assertThat(vorgaenge).hasSize(PAGE_SIZE);
+		}
+
+		@Test
+		void shouldReturnSecondPageWithOneElement() {
+			var pagingFunction = runner.getPagedDeletedVorgaenge(vorgangStubs);
+			getFirstPage(pagingFunction);
+
+			var vorgaenge = getSecondPage(pagingFunction);
+
+			assertThat(vorgaenge).hasSize(1);
+		}
+
+		private List<OzgCloudVorgang> getFirstPage(Function<Page, List<OzgCloudVorgang>> pagingFunction) {
+			return pagingFunction.apply(Page.builder().offset(0).limit(PAGE_SIZE).build());
+		}
+
+		private List<OzgCloudVorgang> getSecondPage(Function<Page, List<OzgCloudVorgang>> pagingFunction) {
+			return pagingFunction.apply(Page.builder().offset(PAGE_SIZE).limit(PAGE_SIZE).build());
+		}
+	}
+
+	@Nested
+	class TestExtractBatchesFromDataSource {
+
+		private static final int BATCH_SIZE = 2;
+		private static final List<OzgCloudVorgang> VORGAENGE_1 = List.of(OzgCloudVorgangTestFactory.create(), OzgCloudVorgangTestFactory.create());
+		private static final List<OzgCloudVorgang> VORGAENGE_2 = List.of(OzgCloudVorgangTestFactory.create());
+		private static final UUID BATCH_1_UUID = UUID.randomUUID();
+		private static final UUID BATCH_2_UUID = UUID.randomUUID();
+
+		@Mock
+		private Execution execution;
+		@Mock
+		private Function<Page, List<OzgCloudVorgang>> functionToRetrieveData;
+
+		@BeforeEach
+		void init() {
+			when(config.getFetchingBatchSize()).thenReturn(BATCH_SIZE);
+			when(functionToRetrieveData.apply(any())).thenReturn(VORGAENGE_1, VORGAENGE_2, List.of());
+			when(runner.createBatchUUID()).thenReturn(BATCH_1_UUID, BATCH_2_UUID);
+		}
+
+		@Test
+		void shouldCallFunctionToRetrieveDataForFirstPage() {
+			extractBatchesFromDataSource();
+
+			verify(functionToRetrieveData).apply(argThat(hasExpectedOffsetAndConfiguredLimit(0)));
+		}
+
+		@Test
+		void shouldCallFunctionToRetrieveDataForSecondPage() {
+			extractBatchesFromDataSource().toList();
+
+			verify(functionToRetrieveData).apply(argThat(hasExpectedOffsetAndConfiguredLimit(BATCH_SIZE)));
+		}
+
+		@Test
+		void shouldCallFunctionToRetrieveDataForThirdPage() {
+			extractBatchesFromDataSource().toList();
+
+			verify(functionToRetrieveData).apply(argThat(hasExpectedOffsetAndConfiguredLimit(BATCH_SIZE * 2)));
+		}
+
+		@Test
+		void shouldReturnBatches() {
+			var batches = extractBatchesFromDataSource().toList();
+
+			assertThat(batches).hasSize(2).usingRecursiveFieldByFieldElementComparator().containsExactly(
+					new Batch(execution, BATCH_1_UUID, Page.builder().offset(0).limit(BATCH_SIZE).build(), VORGAENGE_1),
+					new Batch(execution, BATCH_2_UUID, Page.builder().offset(BATCH_SIZE).limit(BATCH_SIZE).build(), VORGAENGE_2)
+			);
+		}
+
+		private ArgumentMatcher<Page> hasExpectedOffsetAndConfiguredLimit(int expectedOffset) {
+			return page -> page.getOffset() == expectedOffset && page.getLimit() == BATCH_SIZE;
+		}
+
+		private Stream<Batch> extractBatchesFromDataSource() {
+			return runner.extractBatchesFromDataSource(execution, functionToRetrieveData);
+		}
+	}
 }
diff --git a/src/test/java/de/ozgcloud/aggregation/transformation/VorgangMapperTest.java b/src/test/java/de/ozgcloud/aggregation/transformation/VorgangMapperTest.java
index cfba8feb1ffb4fc61eb59d4dd3c171a4288e042c..12c67ca70ca6101ec0ea09d3a04aa451e8322ced 100644
--- a/src/test/java/de/ozgcloud/aggregation/transformation/VorgangMapperTest.java
+++ b/src/test/java/de/ozgcloud/aggregation/transformation/VorgangMapperTest.java
@@ -32,6 +32,7 @@ import org.mockito.InjectMocks;
 
 import de.ozgcloud.aggregation.warehouse.DocumentEntry;
 import de.ozgcloud.aggregation.warehouse.DocumentEntryTestFactory;
+import de.ozgcloud.apilib.vorgang.OzgCloudVorgangStubTestFactory;
 import de.ozgcloud.apilib.vorgang.OzgCloudVorgangTestFactory;
 
 public class VorgangMapperTest {
@@ -51,4 +52,19 @@ public class VorgangMapperTest {
 			assertThat(documentEntry).usingRecursiveComparison().isEqualTo(expectedEntry);
 		}
 	}
+
+	@Nested
+	class TestFromVorgangStub {
+
+		@Test
+		void shouldMapAllFieldsButEingangs() {
+			var expected = OzgCloudVorgangTestFactory.createBuilder()
+					.clearEingangs()
+					.build();
+
+			var mapped = mapper.fromVorgangStub(OzgCloudVorgangStubTestFactory.create());
+
+			assertThat(mapped).usingRecursiveComparison().isEqualTo(expected);
+		}
+	}
 }