diff --git a/src/main/java/de/ozgcloud/aggregation/AggregationManagerRunner.java b/src/main/java/de/ozgcloud/aggregation/AggregationManagerRunner.java
index 33159fba127c9cd79a03ee26abd0937fa3e1cc0b..3cd83a1ba1130ed10ce21e2466db8abc71e47955 100644
--- a/src/main/java/de/ozgcloud/aggregation/AggregationManagerRunner.java
+++ b/src/main/java/de/ozgcloud/aggregation/AggregationManagerRunner.java
@@ -27,6 +27,7 @@ import java.util.Objects;
 import java.util.UUID;
 
 import org.apache.logging.log4j.ThreadContext;
+import org.springframework.beans.factory.annotation.Lookup;
 import org.springframework.boot.CommandLineRunner;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
 import org.springframework.stereotype.Component;
@@ -35,9 +36,6 @@ import de.ozgcloud.aggregation.transformation.AggregationMapping;
 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.WarehouseRepository;
-import de.ozgcloud.apilib.vorgang.OzgCloudVorgangService;
 import lombok.Getter;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.log4j.Log4j2;
@@ -46,25 +44,20 @@ import lombok.extern.log4j.Log4j2;
 @RequiredArgsConstructor
 @Log4j2
 @ConditionalOnProperty(prefix = "ozgcloud.command.line.runner", value = "enabled", havingValue = "true", matchIfMissing = true)
-public class AggregationManagerRunner implements CommandLineRunner {
+public abstract class AggregationManagerRunner implements CommandLineRunner {
 
 	private static final String MDC_EXECUTION = "execution";
 
-	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 {
 		var identifier = transformationProperties.getIdentifier();
 		var aggregationMappings = transformationProperties.getAggregationMappings();
 		if (Objects.isNull(aggregationMappings) || aggregationMappings.isEmpty()) {
-			runWithTransformation(transformationService.load(identifier, null), null);
+			runWithDefaultTransformation(transformationService.load(identifier, null));
 		} else {
 			aggregationMappings.stream()
 					.forEach(aggregationMapping -> runWithTransformation(transformationService.load(identifier, aggregationMapping),
@@ -72,26 +65,29 @@ public class AggregationManagerRunner implements CommandLineRunner {
 		}
 	}
 
+	void runWithDefaultTransformation(Transformation transformation) {
+		runWithTransformation(transformation, null);
+	}
+
 	void runWithTransformation(Transformation transformation, AggregationMapping aggregationMapping) {
 		try (Execution execution = new Execution(transformation)) {
 			ThreadContext.put(MDC_EXECUTION, execution.id.toString());
-			buildAggregationLoader(transformation, aggregationMapping).load();
+			prepareAggregator(execution, aggregationMapping).aggregate();
 		} finally {
 			ThreadContext.remove(MDC_EXECUTION);
 		}
 	}
 
-	AggregationLoader buildAggregationLoader(Transformation transformation, AggregationMapping aggregationMapping) {
-		var builder = AggregationLoader.builder()
-				.execution(new Execution(transformation))
-				.vorgangService(vorgangService)
-				.repository(repository)
-				.vorgangMapper(vorgangMapper)
-				.batchSize(config.getFetchingBatchSize());
-		return Objects.isNull(aggregationMapping) ? builder.build()
-				: builder.formIdentifier(aggregationMapping.getFormIdentifier()).collectionName(aggregationMapping.getName()).build();
+	Aggregator prepareAggregator(Execution execution, AggregationMapping aggregationMapping) {
+		return createAggregator()
+				.withExecution(execution)
+				.withAggregationMapping(aggregationMapping)
+				.withBatchSize(config.getFetchingBatchSize());
 	}
 
+	@Lookup
+	protected abstract Aggregator createAggregator();
+
 	@Getter
 	@RequiredArgsConstructor
 	protected static class Execution implements AutoCloseable {
diff --git a/src/main/java/de/ozgcloud/aggregation/AggregationLoader.java b/src/main/java/de/ozgcloud/aggregation/Aggregator.java
similarity index 84%
rename from src/main/java/de/ozgcloud/aggregation/AggregationLoader.java
rename to src/main/java/de/ozgcloud/aggregation/Aggregator.java
index 34bc80bc94f5f550c88d0243ee8cfbf68fd46d80..79cf481fe8871d780ceec13bb1b7564037d2fb0c 100644
--- a/src/main/java/de/ozgcloud/aggregation/AggregationLoader.java
+++ b/src/main/java/de/ozgcloud/aggregation/Aggregator.java
@@ -13,8 +13,11 @@ import java.util.stream.IntStream;
 import java.util.stream.Stream;
 
 import org.apache.logging.log4j.CloseableThreadContext;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
 
 import de.ozgcloud.aggregation.AggregationManagerRunner.Execution;
+import de.ozgcloud.aggregation.transformation.AggregationMapping;
 import de.ozgcloud.aggregation.transformation.AggregationMapping.FormIdentifier;
 import de.ozgcloud.aggregation.transformation.TransformationException;
 import de.ozgcloud.aggregation.transformation.VorgangMapper;
@@ -26,27 +29,46 @@ import de.ozgcloud.apilib.vorgang.OzgCloudVorgangQuery.FormIdentification;
 import de.ozgcloud.apilib.vorgang.OzgCloudVorgangService;
 import de.ozgcloud.apilib.vorgang.OzgCloudVorgangStub;
 import de.ozgcloud.apilib.vorgang.Page;
-import lombok.Builder;
+import lombok.RequiredArgsConstructor;
 import lombok.extern.log4j.Log4j2;
 
-@Builder
+@Component
+@Scope("prototype")
+@RequiredArgsConstructor
 @Log4j2
-class AggregationLoader {
+class Aggregator {
 
 	private static final String MDC_VORGANG = "vorgang";
 	private static final Predicate<Batch> HAS_NEXT_BATCH = x -> !x.items.isEmpty();
 
-	private final Execution execution;
-	private final FormIdentifier formIdentifier;
-	@Builder.Default
-	private final String collectionName = DocumentEntry.COLLECTION;
 	private final OzgCloudVorgangService vorgangService;
 	private final WarehouseRepository repository;
 	private final VorgangMapper vorgangMapper;
-	@Builder.Default
-	private final int batchSize = 100;
 
-	public void load() {
+	private Execution execution;
+	private FormIdentifier formIdentifier;
+	private String collectionName = DocumentEntry.COLLECTION;
+	private int batchSize = 100;
+
+	public Aggregator withExecution(Execution execution) {
+		this.execution = execution;
+		return this;
+	}
+
+	public Aggregator withAggregationMapping(AggregationMapping aggregationMapping) {
+		if (Objects.nonNull(aggregationMapping)) {
+			this.formIdentifier = aggregationMapping.getFormIdentifier();
+			this.collectionName = aggregationMapping.getName();
+		}
+		return this;
+	}
+
+	public Aggregator withBatchSize(int batchSize) {
+		this.batchSize = batchSize;
+		return this;
+	}
+
+	public void aggregate() {
 		loadVorgaengeIntoRepository(Stream.concat(extractBatchesOfVorgaengeFromDataSource(), extractBatchesOfDeletedVorgaengeFromDataSource()));
 	}
 
diff --git a/src/main/java/de/ozgcloud/aggregation/warehouse/WarehouseRepository.java b/src/main/java/de/ozgcloud/aggregation/warehouse/WarehouseRepository.java
index d100e47d538c011d225e00b3956330b68ab94d70..c31564a9a30e98564b181b174e3589510be7c12c 100644
--- a/src/main/java/de/ozgcloud/aggregation/warehouse/WarehouseRepository.java
+++ b/src/main/java/de/ozgcloud/aggregation/warehouse/WarehouseRepository.java
@@ -27,6 +27,6 @@ import org.springframework.data.mongodb.repository.MongoRepository;
 import org.springframework.stereotype.Repository;
 
 @Repository
-public interface WarehouseRepository extends CustomWarehouseRepository, MongoRepository<DocumentEntry, String> {
+public interface WarehouseRepository extends MongoRepository<DocumentEntry, String>, CustomWarehouseRepository {
 
 }
diff --git a/src/test/java/de/ozgcloud/aggregation/AggregationManagerRunnerTest.java b/src/test/java/de/ozgcloud/aggregation/AggregationManagerRunnerTest.java
index 5579862b69c7b721a0ef0a878be1456b3ba9383e..ef2a1f26bb2fdfbcdf47a5dcd7d2f6292f63b661 100644
--- a/src/test/java/de/ozgcloud/aggregation/AggregationManagerRunnerTest.java
+++ b/src/test/java/de/ozgcloud/aggregation/AggregationManagerRunnerTest.java
@@ -34,19 +34,19 @@ import org.apache.commons.lang3.RandomUtils;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentMatcher;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.Spy;
-import org.springframework.test.util.ReflectionTestUtils;
 
 import com.thedeanda.lorem.LoremIpsum;
 
+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.WarehouseRepository;
 import de.ozgcloud.apilib.vorgang.OzgCloudVorgangService;
 
@@ -64,9 +64,11 @@ class AggregationManagerRunnerTest {
 	private WarehouseRepository repository;
 	@Mock
 	private VorgangMapper vorgangMapper;
+	@Mock
+	private static Aggregator aggregator;
 	@Spy
 	@InjectMocks
-	private AggregationManagerRunner runner;
+	private AggregationManagerRunnerImpl runner;
 
 	@Nested
 	class TestRun {
@@ -143,10 +145,10 @@ class AggregationManagerRunnerTest {
 			}
 
 			@Test
-			void shouldCallRunWithTransformation() {
+			void shouldCallRunWithDefaultTransformation() {
 				runner.run();
 
-				verify(runner).runWithTransformation(transformation, null);
+				verify(runner).runWithDefaultTransformation(transformation);
 			}
 		}
 
@@ -169,40 +171,55 @@ class AggregationManagerRunnerTest {
 			}
 
 			@Test
-			void shouldCallRunWithTransformation() {
+			void shouldCallRunWithDefaultTransformation() {
 				runner.run();
 
-				verify(runner).runWithTransformation(transformation, null);
+				verify(runner).runWithDefaultTransformation(transformation);
 			}
 		}
 	}
 
+	@Nested
+	class TestRunWithDefaultTransformation {
+
+		@Mock
+		private Transformation transformation;
+
+		@Test
+		void shouldCallRunWithTransformation() {
+			doNothing().when(runner).runWithTransformation(any(), any());
+
+			runner.runWithDefaultTransformation(transformation);
+
+			verify(runner).runWithTransformation(eq(transformation), isNull());
+		}
+	}
+
 	@Nested
 	class TestRunWithTransformation {
 
 		@Mock
 		private Transformation transformation;
 		private final AggregationMapping aggregationMapping = AggregationMappingTestFactory.create();
-		@Mock
-		private AggregationLoader aggregationLoader;
+		private final ArgumentMatcher<Execution> hasTransformation = execution -> execution.getTransformation().equals(transformation);
 
 		@BeforeEach
 		void mock() {
-			when(runner.buildAggregationLoader(transformation, aggregationMapping)).thenReturn(aggregationLoader);
+			doReturn(aggregator).when(runner).prepareAggregator(any(), any());
 		}
 
 		@Test
-		void shouldCallBuildAggregationLoader() {
+		void shouldCallPrepareAggregator() {
 			runWithTransformation();
 
-			verify(runner).buildAggregationLoader(transformation, aggregationMapping);
+			verify(runner).prepareAggregator(argThat(hasTransformation), eq(aggregationMapping));
 		}
 
 		@Test
 		void shouldLoadAggregation() {
 			runWithTransformation();
 
-			verify(aggregationLoader).load();
+			verify(aggregator).aggregate();
 		}
 
 		private void runWithTransformation() {
@@ -211,87 +228,67 @@ class AggregationManagerRunnerTest {
 	}
 
 	@Nested
-	class TestBuildAggregationLoader {
+	class TestPrepareAggregator {
 
 		@Mock
-		private Transformation transformation;
+		private Execution execution;
 		private final AggregationMapping aggregationMapping = AggregationMappingTestFactory.create();
 		private final int batchSize = RandomUtils.insecure().randomInt();
 
 		@BeforeEach
 		void mock() {
 			when(config.getFetchingBatchSize()).thenReturn(batchSize);
+			when(aggregator.withExecution(any())).thenReturn(aggregator);
+			when(aggregator.withAggregationMapping(any())).thenReturn(aggregator);
+			when(aggregator.withBatchSize(anyInt())).thenReturn(aggregator);
 		}
 
 		@Test
 		void shouldGetBatchSize() {
-			runner.buildAggregationLoader(transformation, aggregationMapping);
+			runner.prepareAggregator(execution, aggregationMapping);
 
 			verify(config).getFetchingBatchSize();
 		}
 
 		@Test
-		void shouldReturnAggregationLoaderWithExecution() {
-			var loader = runner.buildAggregationLoader(transformation, aggregationMapping);
-
-			assertThat(ReflectionTestUtils.getField(loader, "execution")).extracting("transformation").isEqualTo(transformation);
-		}
-
-		@Test
-		void shouldReturnAggregationLoaderWithFormIdentifier() {
-			var loader = runner.buildAggregationLoader(transformation, aggregationMapping);
-
-			assertThat(ReflectionTestUtils.getField(loader, "formIdentifier")).isEqualTo(AggregationMappingTestFactory.FORM_IDENTIFIER);
-		}
-
-		@Test
-		void shouldReturnAggregationLoaderWithCollectionName() {
-			var loader = runner.buildAggregationLoader(transformation, aggregationMapping);
-
-			assertThat(ReflectionTestUtils.getField(loader, "collectionName")).isEqualTo(AggregationMappingTestFactory.NAME);
-		}
-
-		@Test
-		void shouldReturnAggregationLoaderWithVorgangService() {
-			var loader = runner.buildAggregationLoader(transformation, aggregationMapping);
+		void shouldSetExecution() {
+			runner.prepareAggregator(execution, aggregationMapping);
 
-			assertThat(ReflectionTestUtils.getField(loader, "vorgangService")).isEqualTo(vorgangService);
+			verify(aggregator).withExecution(execution);
 		}
 
 		@Test
-		void shouldReturnAggregationLoaderWithRepository() {
-			var loader = runner.buildAggregationLoader(transformation, aggregationMapping);
+		void shouldSetAggregationMapping() {
+			runner.prepareAggregator(execution, aggregationMapping);
 
-			assertThat(ReflectionTestUtils.getField(loader, "repository")).isEqualTo(repository);
+			verify(aggregator).withAggregationMapping(aggregationMapping);
 		}
 
 		@Test
-		void shouldReturnAggregationLoaderWithVorgangMapper() {
-			var loader = runner.buildAggregationLoader(transformation, aggregationMapping);
+		void shouldSetBatchSize() {
+			runner.prepareAggregator(execution, aggregationMapping);
 
-			assertThat(ReflectionTestUtils.getField(loader, "vorgangMapper")).isEqualTo(vorgangMapper);
+			verify(aggregator).withBatchSize(batchSize);
 		}
 
 		@Test
-		void shouldReturnAggregationLoaderWithBatchSize() {
-			var loader = runner.buildAggregationLoader(transformation, aggregationMapping);
+		void shouldReturnAggregator() {
+			var result = runner.prepareAggregator(execution, aggregationMapping);
 
-			assertThat(ReflectionTestUtils.getField(loader, "batchSize")).isEqualTo(batchSize);
+			assertThat(result).isEqualTo(aggregator);
 		}
+	}
 
-		@Test
-		void shouldReturnAggregationLoaderWithNullFormIdentifier() {
-			var loader = runner.buildAggregationLoader(transformation, null);
+	static class AggregationManagerRunnerImpl extends AggregationManagerRunner {
 
-			assertThat(ReflectionTestUtils.getField(loader, "formIdentifier")).isNull();
+		public AggregationManagerRunnerImpl(AggregationManagerConfiguration config, TransformationProperties transformationProperties,
+				TransformationService transformationService) {
+			super(config, transformationProperties, transformationService);
 		}
 
-		@Test
-		void shouldReturnAggregationLoaderWithDefaultCollectionName() {
-			var loader = runner.buildAggregationLoader(transformation, null);
-
-			assertThat(ReflectionTestUtils.getField(loader, "collectionName")).isEqualTo(DocumentEntry.COLLECTION);
+		@Override
+		protected Aggregator createAggregator() {
+			return aggregator;
 		}
 	}
-
 }
diff --git a/src/test/java/de/ozgcloud/aggregation/AggregationLoaderTest.java b/src/test/java/de/ozgcloud/aggregation/AggregatorTest.java
similarity index 59%
rename from src/test/java/de/ozgcloud/aggregation/AggregationLoaderTest.java
rename to src/test/java/de/ozgcloud/aggregation/AggregatorTest.java
index 09e196006cdff8ba55b8731917de4f68a03f55b4..2d66f74b8f51b0eb4abbd382b62aa780b98dce54 100644
--- a/src/test/java/de/ozgcloud/aggregation/AggregationLoaderTest.java
+++ b/src/test/java/de/ozgcloud/aggregation/AggregatorTest.java
@@ -10,19 +10,23 @@ import java.util.UUID;
 import java.util.function.Function;
 import java.util.stream.Stream;
 
+import org.apache.commons.lang3.RandomUtils;
 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 org.springframework.test.util.ReflectionTestUtils;
 
-import com.thedeanda.lorem.LoremIpsum;
-
-import de.ozgcloud.aggregation.AggregationLoader.Batch;
 import de.ozgcloud.aggregation.AggregationManagerRunner.Execution;
+import de.ozgcloud.aggregation.Aggregator.Batch;
+import de.ozgcloud.aggregation.transformation.AggregationMapping;
 import de.ozgcloud.aggregation.transformation.AggregationMapping.FormIdentifier;
+import de.ozgcloud.aggregation.transformation.AggregationMappingTestFactory;
 import de.ozgcloud.aggregation.transformation.FormIdentifierTestFactory;
 import de.ozgcloud.aggregation.transformation.Transformation;
 import de.ozgcloud.aggregation.transformation.VorgangMapper;
@@ -37,32 +41,119 @@ import de.ozgcloud.apilib.vorgang.OzgCloudVorgangStubTestFactory;
 import de.ozgcloud.apilib.vorgang.OzgCloudVorgangTestFactory;
 import de.ozgcloud.apilib.vorgang.Page;
 
-class AggregationLoaderTest {
+class AggregatorTest {
 
-	private AggregationLoader aggregationLoader;
+	@InjectMocks
+	@Spy
+	private Aggregator aggregator;
 	@Mock
 	private Transformation transformation;
 	private final Execution execution = new Execution(transformation);
-	private final FormIdentifier formIdentifier = FormIdentifierTestFactory.create();
 	@Mock
 	private WarehouseRepository repository;
 	@Mock
 	private VorgangMapper vorgangMapper;
 	@Mock
 	private OzgCloudVorgangService vorgangService;
-	private AggregationLoader.AggregationLoaderBuilder aggregationLoaderBuilder;
-
-	@BeforeEach
-	void setUp() {
-		aggregationLoaderBuilder = AggregationLoader.builder()
-				.execution(execution)
-				.repository(repository)
-				.vorgangMapper(vorgangMapper)
-				.vorgangService(vorgangService);
+
+	@Nested
+	class TestWithExecution {
+
+		@Test
+		void shouldReturnSelf() {
+			var result = aggregator.withExecution(execution);
+
+			assertThat(result).isSameAs(aggregator);
+		}
+
+		@Test
+		void shouldSetExecution() {
+			var result = aggregator.withExecution(execution);
+
+			assertThat(ReflectionTestUtils.getField(result, "execution")).isEqualTo(execution);
+		}
+	}
+
+	@Nested
+	class TestWithAggregationMapping {
+
+		@Nested
+		class TestOnNonNullAggregationMapping {
+
+			private final AggregationMapping aggregationMapping = AggregationMappingTestFactory.create();
+			private final FormIdentifier formIdentifier = AggregationMappingTestFactory.FORM_IDENTIFIER;
+			private final String collectionName = AggregationMappingTestFactory.NAME;
+
+			@Test
+			void shouldReturnSelf() {
+				var result = aggregator.withAggregationMapping(aggregationMapping);
+
+				assertThat(result).isSameAs(aggregator);
+			}
+
+			@Test
+			void shouldSetFormIdentifier() {
+				var result = aggregator.withAggregationMapping(aggregationMapping);
+
+				assertThat(ReflectionTestUtils.getField(result, "formIdentifier")).isEqualTo(formIdentifier);
+			}
+
+			@Test
+			void shouldSetCollectionName() {
+				var result = aggregator.withAggregationMapping(aggregationMapping);
+
+				assertThat(ReflectionTestUtils.getField(result, "collectionName")).isEqualTo(collectionName);
+			}
+		}
+
+		@Nested
+		class TestOnNullAggregationMapping {
+
+			@Test
+			void shouldReturnSelf() {
+				var result = aggregator.withAggregationMapping(null);
+
+				assertThat(result).isSameAs(aggregator);
+			}
+
+			@Test
+			void shouldNotSetFormIdentifier() {
+				var result = aggregator.withAggregationMapping(null);
+
+				assertThat(ReflectionTestUtils.getField(result, "formIdentifier")).isNull();
+			}
+
+			@Test
+			void shouldNotSetCollectionName() {
+				var result = aggregator.withAggregationMapping(null);
+
+				assertThat(ReflectionTestUtils.getField(result, "collectionName")).isEqualTo(DocumentEntry.COLLECTION);
+			}
+		}
+	}
+
+	@Nested
+	class TestWithBatchSize {
+
+		private final int batchSize = RandomUtils.insecure().randomInt();
+
+		@Test
+		void shouldReturnSelf() {
+			var result = aggregator.withBatchSize(batchSize);
+
+			assertThat(result).isSameAs(aggregator);
+		}
+
+		@Test
+		void shouldSetBatchSize() {
+			var result = aggregator.withBatchSize(batchSize);
+
+			assertThat(ReflectionTestUtils.getField(result, "batchSize")).isEqualTo(batchSize);
+		}
 	}
 
 	@Nested
-	class TestLoad {
+	class TestAggregate {
 		@Mock
 		private Batch batchOfVorgaenge;
 		@Mock
@@ -72,31 +163,30 @@ class AggregationLoaderTest {
 
 		@BeforeEach
 		void setUp() {
-			aggregationLoader = spy(aggregationLoaderBuilder.formIdentifier(formIdentifier).build());
-			doReturn(Stream.of(batchOfVorgaenge)).when(aggregationLoader).extractBatchesOfVorgaengeFromDataSource();
-			doReturn(Stream.of(batchOfDeletedVorgaenge)).when(aggregationLoader).extractBatchesOfDeletedVorgaengeFromDataSource();
-			doNothing().when(aggregationLoader).loadVorgaengeIntoRepository(any());
+			doReturn(Stream.of(batchOfVorgaenge)).when(aggregator).extractBatchesOfVorgaengeFromDataSource();
+			doReturn(Stream.of(batchOfDeletedVorgaenge)).when(aggregator).extractBatchesOfDeletedVorgaengeFromDataSource();
+			doNothing().when(aggregator).loadVorgaengeIntoRepository(any());
 		}
 
 		@Test
 		void shouldExtractBatchesOfVorgaengeFromDataSource() {
-			aggregationLoader.load();
+			aggregator.aggregate();
 
-			verify(aggregationLoader).extractBatchesOfVorgaengeFromDataSource();
+			verify(aggregator).extractBatchesOfVorgaengeFromDataSource();
 		}
 
 		@Test
 		void shouldExtractBatchesOfDeletedVorgaengeFromDataSource() {
-			aggregationLoader.load();
+			aggregator.aggregate();
 
-			verify(aggregationLoader).extractBatchesOfDeletedVorgaengeFromDataSource();
+			verify(aggregator).extractBatchesOfDeletedVorgaengeFromDataSource();
 		}
 
 		@Test
 		void shouldLoadVorgaengeIntoRepository() {
-			aggregationLoader.load();
+			aggregator.aggregate();
 
-			verify(aggregationLoader).loadVorgaengeIntoRepository(batchStreamCaptor.capture());
+			verify(aggregator).loadVorgaengeIntoRepository(batchStreamCaptor.capture());
 			assertThat(batchStreamCaptor.getValue()).containsExactly(batchOfVorgaenge, batchOfDeletedVorgaenge);
 		}
 	}
@@ -112,24 +202,23 @@ class AggregationLoaderTest {
 
 		@BeforeEach
 		void init() {
-			aggregationLoader = spy(aggregationLoaderBuilder.formIdentifier(formIdentifier).build());
-			doReturn(Stream.of(batch)).when(aggregationLoader).extractBatchesFromDataSource(any());
+			doReturn(Stream.of(batch)).when(aggregator).extractBatchesFromDataSource(any());
 		}
 
 		@Test
 		void shouldExtractWithDataRetrievalFunction() {
-			doReturn(Collections.emptyList()).when(aggregationLoader).getVorgaengeFromDataSource(any());
+			doReturn(Collections.emptyList()).when(aggregator).getVorgaengeFromDataSource(any());
 
-			aggregationLoader.extractBatchesOfVorgaengeFromDataSource();
+			aggregator.extractBatchesOfVorgaengeFromDataSource();
 
-			verify(aggregationLoader).extractBatchesFromDataSource(functionToRetrieveDataCaptor.capture());
+			verify(aggregator).extractBatchesFromDataSource(functionToRetrieveDataCaptor.capture());
 			functionToRetrieveDataCaptor.getValue().apply(page);
-			verify(aggregationLoader).getVorgaengeFromDataSource(page);
+			verify(aggregator).getVorgaengeFromDataSource(page);
 		}
 
 		@Test
 		void shouldReturnExtractedBatches() {
-			var extracted = aggregationLoader.extractBatchesOfVorgaengeFromDataSource();
+			var extracted = aggregator.extractBatchesOfVorgaengeFromDataSource();
 
 			assertThat(extracted).containsExactly(batch);
 		}
@@ -139,13 +228,11 @@ class AggregationLoaderTest {
 	class TestGetVorgaengeFromDataSource {
 
 		private final Page page = Page.builder().offset(10).limit(2).build();
-		private final FormIdentifier formIdentifier = FormIdentifierTestFactory.create();
 		private final OzgCloudVorgangQuery query = OzgCloudVorgangQuery.builder().build();
 
 		@BeforeEach
 		void init() {
-			aggregationLoader = spy(aggregationLoaderBuilder.formIdentifier(formIdentifier).build());
-			doReturn(query).when(aggregationLoader).buildFindByFormEngineQuery();
+			doReturn(query).when(aggregator).buildFindByFormEngineQuery();
 			when(vorgangService.find(any(), any())).thenReturn(List.of(OzgCloudVorgangStubTestFactory.create()));
 			when(vorgangService.getById(any())).thenReturn(OzgCloudVorgangTestFactory.create());
 		}
@@ -154,7 +241,7 @@ class AggregationLoaderTest {
 		void shouldCallBuildFindByFormEngineQuery() {
 			getVorgaengeFromDataSource();
 
-			verify(aggregationLoader).buildFindByFormEngineQuery();
+			verify(aggregator).buildFindByFormEngineQuery();
 		}
 
 		@Test
@@ -179,7 +266,7 @@ class AggregationLoaderTest {
 		}
 
 		private List<OzgCloudVorgang> getVorgaengeFromDataSource() {
-			return aggregationLoader.getVorgaengeFromDataSource(page);
+			return aggregator.getVorgaengeFromDataSource(page);
 		}
 	}
 
@@ -189,14 +276,9 @@ class AggregationLoaderTest {
 		@Nested
 		class TestOnFormIdentifierNull {
 
-			@BeforeEach
-			void init() {
-				aggregationLoader = spy(aggregationLoaderBuilder.formIdentifier(null).build());
-			}
-
 			@Test
 			void shouldReturnFindAllQueryOnNullFormIdentifier() {
-				var query = aggregationLoader.buildFindByFormEngineQuery();
+				var query = aggregator.buildFindByFormEngineQuery();
 
 				assertThat(query).usingRecursiveComparison().isEqualTo(OzgCloudVorgangQuery.builder().build());
 			}
@@ -205,21 +287,23 @@ class AggregationLoaderTest {
 		@Nested
 		class TestOnFormIdentifierNotNull {
 
+			private final AggregationMapping aggregationMapping = AggregationMappingTestFactory.create();
+
 			@BeforeEach
 			void init() {
-				aggregationLoader = spy(aggregationLoaderBuilder.formIdentifier(formIdentifier).build());
+				aggregator = aggregator.withAggregationMapping(aggregationMapping);
 			}
 
 			@Test
 			void shouldSetFormIdInQuery() {
-				var query = aggregationLoader.buildFindByFormEngineQuery();
+				var query = aggregator.buildFindByFormEngineQuery();
 
 				assertThat(query.getForm()).get().extracting("formId").isEqualTo(FormIdentifierTestFactory.FORM_ID);
 			}
 
 			@Test
 			void shouldSetFormEngineNameInQuery() {
-				var query = aggregationLoader.buildFindByFormEngineQuery();
+				var query = aggregator.buildFindByFormEngineQuery();
 
 				assertThat(query.getForm()).get().extracting("formEngineName").isEqualTo(FormIdentifierTestFactory.FORM_ENGINE_NAME);
 			}
@@ -244,38 +328,37 @@ class AggregationLoaderTest {
 
 			@BeforeEach
 			void init() {
-				aggregationLoader = spy(aggregationLoaderBuilder.formIdentifier(null).build());
 				when(vorgangService.findDeleted()).thenReturn(deletedVorgaenge.stream());
-				doReturn(functionToRetrieveData).when(aggregationLoader).getPagedDeletedVorgaenge(any());
-				doReturn(Stream.of(batch)).when(aggregationLoader).extractBatchesFromDataSource(any());
+				doReturn(functionToRetrieveData).when(aggregator).getPagedDeletedVorgaenge(any());
+				doReturn(Stream.of(batch)).when(aggregator).extractBatchesFromDataSource(any());
 			}
 
 			@Test
 			void shouldFindDeleted() {
-				aggregationLoader.extractBatchesOfDeletedVorgaengeFromDataSource();
+				aggregator.extractBatchesOfDeletedVorgaengeFromDataSource();
 
 				verify(vorgangService).findDeleted();
 			}
 
 			@Test
 			void shouldGetPagedDeletedVorgaenge() {
-				aggregationLoader.extractBatchesOfDeletedVorgaengeFromDataSource();
+				aggregator.extractBatchesOfDeletedVorgaengeFromDataSource();
 
-				verify(aggregationLoader).getPagedDeletedVorgaenge(deletedVorgaengeCaptor.capture());
+				verify(aggregator).getPagedDeletedVorgaenge(deletedVorgaengeCaptor.capture());
 				assertThat(deletedVorgaengeCaptor.getValue()).usingRecursiveFieldByFieldElementComparator()
 						.containsExactlyElementsOf(deletedVorgaenge);
 			}
 
 			@Test
 			void shouldExtractWithDataRetrievalFunction() {
-				aggregationLoader.extractBatchesOfDeletedVorgaengeFromDataSource();
+				aggregator.extractBatchesOfDeletedVorgaengeFromDataSource();
 
-				verify(aggregationLoader).extractBatchesFromDataSource(functionToRetrieveData);
+				verify(aggregator).extractBatchesFromDataSource(functionToRetrieveData);
 			}
 
 			@Test
 			void shouldReturnExtractedBatches() {
-				var extracted = aggregationLoader.extractBatchesOfDeletedVorgaengeFromDataSource();
+				var extracted = aggregator.extractBatchesOfDeletedVorgaengeFromDataSource();
 
 				assertThat(extracted).containsExactly(batch);
 			}
@@ -284,23 +367,23 @@ class AggregationLoaderTest {
 		@Nested
 		class TestOnFormIdentifierNotNull {
 
+			private final AggregationMapping aggregationMapping = AggregationMappingTestFactory.create();
+
 			@BeforeEach
 			void init() {
-				aggregationLoader = spy(aggregationLoaderBuilder.formIdentifier(formIdentifier).build());
+				aggregator = aggregator.withAggregationMapping(aggregationMapping);
 			}
 
 			@Test
 			void shouldNotFindDeleted() {
-				aggregationLoader.extractBatchesOfDeletedVorgaengeFromDataSource();
+				aggregator.extractBatchesOfDeletedVorgaengeFromDataSource();
 
 				verify(vorgangService, never()).findDeleted();
 			}
 
 			@Test
 			void shouldReturnEmptyStream() {
-				aggregationLoader = spy(aggregationLoaderBuilder.formIdentifier(formIdentifier).build());
-
-				var extracted = aggregationLoader.extractBatchesOfDeletedVorgaengeFromDataSource();
+				var extracted = aggregator.extractBatchesOfDeletedVorgaengeFromDataSource();
 
 				assertThat(extracted).isEmpty();
 			}
@@ -314,14 +397,9 @@ class AggregationLoaderTest {
 
 		private final Stream<OzgCloudVorgangStub> vorgangStubs = Stream.generate(OzgCloudVorgangStubTestFactory::create).limit(PAGE_SIZE + 1);
 
-		@BeforeEach
-		void init() {
-			aggregationLoader = spy(aggregationLoaderBuilder.formIdentifier(null).build());
-		}
-
 		@Test
 		void shouldReturnFirstFullPage() {
-			var pagingFunction = aggregationLoader.getPagedDeletedVorgaenge(vorgangStubs);
+			var pagingFunction = aggregator.getPagedDeletedVorgaenge(vorgangStubs);
 
 			var vorgaenge = getFirstPage(pagingFunction);
 
@@ -330,7 +408,7 @@ class AggregationLoaderTest {
 
 		@Test
 		void shouldReturnSecondPageWithOneElement() {
-			var pagingFunction = aggregationLoader.getPagedDeletedVorgaenge(vorgangStubs);
+			var pagingFunction = aggregator.getPagedDeletedVorgaenge(vorgangStubs);
 			getFirstPage(pagingFunction);
 
 			var vorgaenge = getSecondPage(pagingFunction);
@@ -362,9 +440,9 @@ class AggregationLoaderTest {
 		@SuppressWarnings("unchecked")
 		@BeforeEach
 		void init() {
-			aggregationLoader = spy(aggregationLoaderBuilder.batchSize(BATCH_SIZE).build());
+			aggregator = aggregator.withBatchSize(BATCH_SIZE).withExecution(execution);
 			when(functionToRetrieveData.apply(any())).thenReturn(VORGAENGE_1, VORGAENGE_2, Collections.emptyList());
-			when(aggregationLoader.createBatchUUID()).thenReturn(BATCH_1_UUID, BATCH_2_UUID);
+			when(aggregator.createBatchUUID()).thenReturn(BATCH_1_UUID, BATCH_2_UUID);
 		}
 
 		@Test
@@ -402,7 +480,7 @@ class AggregationLoaderTest {
 		}
 
 		private Stream<Batch> extractBatchesFromDataSource() {
-			return aggregationLoader.extractBatchesFromDataSource(functionToRetrieveData);
+			return aggregator.extractBatchesFromDataSource(functionToRetrieveData);
 		}
 	}
 
@@ -414,41 +492,41 @@ class AggregationLoaderTest {
 		@Mock
 		private Batch batch;
 		private final DocumentEntry documentEntry = DocumentEntryTestFactory.create();
-		private final String collectionName = LoremIpsum.getInstance().getWords(1);
+		private final AggregationMapping aggregationMapping = AggregationMappingTestFactory.create();
 		@Captor
 		private ArgumentCaptor<List<DocumentEntry>> documentEntriesCaptor;
 
 		@BeforeEach
 		void init() {
-			aggregationLoader = spy(aggregationLoaderBuilder.collectionName(collectionName).build());
-			doReturn(List.of(documentEntry)).when(aggregationLoader).transformBatchToDocumentEntries(any());
-			doNothing().when(aggregationLoader).loadDocumentEntriesIntoRepository(any());
+			aggregator = aggregator.withAggregationMapping(aggregationMapping);
+			doReturn(List.of(documentEntry)).when(aggregator).transformBatchToDocumentEntries(any());
+			doNothing().when(aggregator).loadDocumentEntriesIntoRepository(any());
 		}
 
 		@Test
 		void shouldDropCollection() {
 			loadVorgaengeIntoRepository();
 
-			verify(repository).clearCollection(collectionName);
+			verify(repository).clearCollection(AggregationMappingTestFactory.NAME);
 		}
 
 		@Test
 		void shouldTransform() {
 			loadVorgaengeIntoRepository();
 
-			verify(aggregationLoader).transformBatchToDocumentEntries(batch);
+			verify(aggregator).transformBatchToDocumentEntries(batch);
 		}
 
 		@Test
 		void shouldLoadIntoRepository() {
 			loadVorgaengeIntoRepository();
 
-			verify(aggregationLoader).loadDocumentEntriesIntoRepository(documentEntriesCaptor.capture());
+			verify(aggregator).loadDocumentEntriesIntoRepository(documentEntriesCaptor.capture());
 			assertThat(documentEntriesCaptor.getValue()).containsExactly(documentEntry);
 		}
 
 		private void loadVorgaengeIntoRepository() {
-			aggregationLoader.loadVorgaengeIntoRepository(Stream.of(batch));
+			aggregator.loadVorgaengeIntoRepository(Stream.of(batch));
 		}
 	}
 
@@ -456,18 +534,18 @@ class AggregationLoaderTest {
 	class TestLoadDocumentEntriesIntoRepository {
 
 		private final List<DocumentEntry> documentEntries = List.of(DocumentEntryTestFactory.create());
-		private final String collectionName = LoremIpsum.getInstance().getWords(1);
+		private final AggregationMapping aggregationMapping = AggregationMappingTestFactory.create();
 
 		@BeforeEach
 		void init() {
-			aggregationLoader = spy(aggregationLoaderBuilder.collectionName(collectionName).build());
+			aggregator = aggregator.withAggregationMapping(aggregationMapping);
 		}
 
 		@Test
 		void shouldSaveDocumentEntriesInCollection() {
-			aggregationLoader.loadDocumentEntriesIntoRepository(documentEntries);
+			aggregator.loadDocumentEntriesIntoRepository(documentEntries);
 
-			verify(repository).saveAllInCollection(documentEntries, collectionName);
+			verify(repository).saveAllInCollection(documentEntries, AggregationMappingTestFactory.NAME);
 		}
 	}
 }