diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/RootModelAssembler.java b/alfa-service/src/main/java/de/ozgcloud/alfa/RootModelAssembler.java
index e62dd86b34e92a1292fe3ace76e4d9b2f3bcef20..d6715591975f7fdc22b2aba99bcea9e80e086b80 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/RootModelAssembler.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/RootModelAssembler.java
@@ -25,54 +25,51 @@ package de.ozgcloud.alfa;
 
 import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*;
 
-import java.util.Optional;
+import java.util.List;
+import java.util.stream.Stream;
 
 import org.apache.commons.lang3.StringUtils;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.hateoas.EntityModel;
 import org.springframework.hateoas.Link;
 import org.springframework.hateoas.server.RepresentationModelAssembler;
 import org.springframework.stereotype.Component;
 
-import de.ozgcloud.alfa.common.ModelBuilder;
 import de.ozgcloud.alfa.common.downloadtoken.DownloadTokenController;
 import de.ozgcloud.alfa.common.user.CurrentUserService;
 import de.ozgcloud.alfa.common.user.UserManagerUrlProvider;
 import de.ozgcloud.alfa.common.user.UserRole;
+import lombok.RequiredArgsConstructor;
 
 @Component
+@RequiredArgsConstructor
 public class RootModelAssembler implements RepresentationModelAssembler<Root, EntityModel<Root>> {
 
 	static final String REL_DOWNLOAD_TOKEN = "downloadToken";
 	static final String REL_CURRENT_USER = "currentUser";
 	static final String REL_DOCUMENTATIONS = "documentations";
 
-	@Autowired
-	private RootViewLinkHandler viewLinkHandler;
-	@Autowired
-	private CurrentUserService currentUserService;
-	@Autowired
-	private UserManagerUrlProvider userManagerUrlProvider;
+	private final RootViewLinkHandler viewLinkHandler;
+	private final CurrentUserService currentUserService;
+	private final UserManagerUrlProvider userManagerUrlProvider;
 
 	@Value("${ozgcloud.user-assistance.documentation.url:#{null}}")
 	private String documentationUrl;
 
 	@Override
 	public EntityModel<Root> toModel(Root root) {
-		var modelBuilder = ModelBuilder.fromEntity(root)
-				.ifMatch(this::hasAnyRole).addLinks(
+		var model = EntityModel.of(root)
+				.addAllIf(hasAnyRole(), () -> List.of(
 						linkTo(RootController.class).withSelfRel(),
-						linkTo(DownloadTokenController.class).withRel(REL_DOWNLOAD_TOKEN))
-				.ifMatch(userManagerUrlProvider::isConfiguredForUserProfile)
-				.addLinkIfPresent(this::buildCurrentUserLink)
-				.addLink(buildUserAssistanceDocumentationUrl());
+						linkTo(DownloadTokenController.class).withRel(REL_DOWNLOAD_TOKEN)))
+				.addAllIf(userManagerUrlProvider.isConfiguredForUserProfile(), this::buildCurrentUserLink)
+				.add(buildUserAssistanceDocumentationUrl());
 
 		if (hasAnyRole()) {
-			viewLinkHandler.addViewLinks(modelBuilder, currentUserService.findUserId());
+			viewLinkHandler.addViewLinks(model, currentUserService.findUserId());
 		}
 
-		return modelBuilder.buildModel();
+		return model;
 	}
 
 	boolean hasAnyRole() {
@@ -83,12 +80,12 @@ public class RootModelAssembler implements RepresentationModelAssembler<Root, En
 		return currentUserService.hasRole(UserRole.VERWALTUNG_USER) || currentUserService.hasRole(UserRole.VERWALTUNG_POSTSTELLE);
 	}
 
-	private Optional<Link> buildCurrentUserLink() {
+	private List<Link> buildCurrentUserLink() {
 		return currentUserService.findUserId().map(userId -> Link.of(String.format(userManagerUrlProvider.getUserProfileTemplate(), userId))
-				.withRel(REL_CURRENT_USER));
+				.withRel(REL_CURRENT_USER)).stream().toList();
 	}
 
-	private Optional<Link> buildUserAssistanceDocumentationUrl() {
-		return Optional.ofNullable(documentationUrl).filter(StringUtils::isNotBlank).map(href -> Link.of(href, REL_DOCUMENTATIONS));
+	private List<Link> buildUserAssistanceDocumentationUrl() {
+		return Stream.of(documentationUrl).filter(StringUtils::isNotBlank).map(href -> Link.of(href, REL_DOCUMENTATIONS)).toList();
 	}
 }
\ No newline at end of file
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/RootProperties.java b/alfa-service/src/main/java/de/ozgcloud/alfa/RootProperties.java
index d339fc00329168ff35b4278df716f6e817c4448d..ed16ff445eba3033bfd3b159c690353627723746 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/RootProperties.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/RootProperties.java
@@ -1,3 +1,26 @@
+/*
+ * Copyright (C) 2025 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;
 
 import org.springframework.boot.context.properties.ConfigurationProperties;
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/RootViewLinkHandler.java b/alfa-service/src/main/java/de/ozgcloud/alfa/RootViewLinkHandler.java
index 80f77f5181edd904055c5b2c704d5d44bed5ffa2..a8af53edb791331f6beb006f0b95bd89d8758f8d 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/RootViewLinkHandler.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/RootViewLinkHandler.java
@@ -28,12 +28,11 @@ import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*;
 import java.util.List;
 import java.util.Optional;
 
-import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.hateoas.EntityModel;
 import org.springframework.hateoas.Link;
 import org.springframework.hateoas.server.LinkBuilder;
 import org.springframework.stereotype.Component;
 
-import de.ozgcloud.alfa.common.ModelBuilder;
 import de.ozgcloud.alfa.common.user.CurrentUserService;
 import de.ozgcloud.alfa.common.user.UserId;
 import de.ozgcloud.alfa.common.user.UserRole;
@@ -41,8 +40,10 @@ import de.ozgcloud.alfa.system.SystemStatusService;
 import de.ozgcloud.alfa.vorgang.Vorgang.VorgangStatus;
 import de.ozgcloud.alfa.vorgang.VorgangController;
 import lombok.NonNull;
+import lombok.RequiredArgsConstructor;
 
 @Component
+@RequiredArgsConstructor
 class RootViewLinkHandler {
 
 	static final String VORGAENGE_ALL_REL_TEMPLATE = "vorgaenge_%s_all";
@@ -67,23 +68,21 @@ class RootViewLinkHandler {
 
 	static final int PAGE_SIZE = 100;
 
-	@Autowired
-	private CurrentUserService currentUserService;
-	@Autowired
-	private SystemStatusService systemStatusService;
+	private final CurrentUserService currentUserService;
+	private final SystemStatusService systemStatusService;
 
 	private final List<VorgangStatus> statusList = List.of(VorgangStatus.NEU, VorgangStatus.ANGENOMMEN, VorgangStatus.IN_BEARBEITUNG,
 			VorgangStatus.BESCHIEDEN, VorgangStatus.ABGESCHLOSSEN, VorgangStatus.VERWORFEN, VorgangStatus.ZU_LOESCHEN);
 
-	public void addViewLinks(ModelBuilder<Root> modelBuilder, Optional<UserId> userId) {
-		modelBuilder.addLink(buildGetAllVorgaengeLink());
-		addSearchAllVorgaengeLink(modelBuilder);
+	public void addViewLinks(EntityModel<Root> model, Optional<UserId> userId) {
+		model.add(buildGetAllVorgaengeLink());
+		addSearchAllVorgaengeLink(model);
 
 		if (currentUserService.hasRole(UserRole.VERWALTUNG_POSTSTELLE)) {
-			addViewLinksForVerwaltungPoststelle(modelBuilder, userId);
+			addViewLinksForVerwaltungPoststelle(model, userId);
 		}
 		if (currentUserService.hasRole(UserRole.VERWALTUNG_USER)) {
-			addViewLinksForVerwaltungUser(modelBuilder, userId);
+			addViewLinksForVerwaltungUser(model, userId);
 		}
 	}
 
@@ -91,9 +90,9 @@ class RootViewLinkHandler {
 		return linkTo(methodOn(VorgangController.class).getAll(0, PAGE_SIZE)).withRel(ALL_VORGAENGE_REL);
 	}
 
-	void addSearchAllVorgaengeLink(ModelBuilder<Root> modelBuilder) {
+	void addSearchAllVorgaengeLink(EntityModel<Root> model) {
 		if (systemStatusService.isSearchServerAvailable()) {
-			modelBuilder.addLink(buildGetAllVorgaengeBySearchByLink());
+			model.add(buildGetAllVorgaengeBySearchByLink());
 		}
 	}
 
@@ -101,34 +100,33 @@ class RootViewLinkHandler {
 		return linkTo(methodOn(VorgangController.class).getAllBySearchBy(0, PAGE_SIZE, null)).withRel(SEARCH_ALL_REL);
 	}
 
-	void addViewLinksForVerwaltungPoststelle(ModelBuilder<Root> modelBuilder, Optional<UserId> userId) {
-		userId.map(this::buildMyVorgaengeLink).ifPresent(modelBuilder::addLink);
+	void addViewLinksForVerwaltungPoststelle(EntityModel<Root> model, Optional<UserId> userId) {
+		userId.map(this::buildMyVorgaengeLink).ifPresent(model::add);
 
 		if (systemStatusService.isSearchServerAvailable()) {
-			userId.map(this::buildSearchMyVorgaengeLink).ifPresent(modelBuilder::addLink);
+			userId.map(this::buildSearchMyVorgaengeLink).ifPresent(model::add);
 		}
 	}
 
-	void addViewLinksForVerwaltungUser(ModelBuilder<Root> modelBuilder, Optional<UserId> userId) {
-		addAllVorgangStatusLinks(modelBuilder);
+	void addViewLinksForVerwaltungUser(EntityModel<Root> model, Optional<UserId> userId) {
+		addAllVorgangStatusLinks(model);
 
-		modelBuilder.addLink(buildGetAllUnassignedVorgaengeLink());
-		modelBuilder.addLinks(buildUnassignedVorgaengeStatusLinks());
+		model.add(buildGetAllUnassignedVorgaengeLink());
+		model.add(buildUnassignedVorgaengeStatusLinks());
 
-		userId.map(this::buildMyVorgaengeLink).ifPresent(modelBuilder::addLink);
-		userId.map(this::buildMyVorgaengeStatusLinks).ifPresent(modelBuilder::addLinks);
+		userId.map(this::buildMyVorgaengeLink).ifPresent(model::add);
+		userId.map(this::buildMyVorgaengeStatusLinks).ifPresent(model::add);
 
 		if (systemStatusService.isSearchServerAvailable()) {
-			userId.map(this::buildSearchMyVorgaengeLink).ifPresent(modelBuilder::addLink);
-			modelBuilder.addLink(buildSearchUnassignedVorgaengeLink());
+			userId.map(this::buildSearchMyVorgaengeLink).ifPresent(model::add);
+			model.add(buildSearchUnassignedVorgaengeLink());
 		}
 
-		modelBuilder.addLink(buildGetAllByHasNextWiedervorlageFristLink().withRel(ALL_WIEDERVORLAGEN_REL));
-		modelBuilder
-				.addLink(buildGetAllByAssignedToAndHasNextWiedervorlageFristLink(UserId.empty(), UNASSIGNED_WIEDERVORLAGEN_REL));
-		userId.map(id -> buildGetAllByAssignedToAndHasNextWiedervorlageFristLink(id, MY_WIEDERVORLAGEN_REL)).ifPresent(modelBuilder::addLink);
+		model.add(buildGetAllByHasNextWiedervorlageFristLink().withRel(ALL_WIEDERVORLAGEN_REL));
+		model.add(buildGetAllByAssignedToAndHasNextWiedervorlageFristLink(UserId.empty(), UNASSIGNED_WIEDERVORLAGEN_REL));
+		userId.map(id -> buildGetAllByAssignedToAndHasNextWiedervorlageFristLink(id, MY_WIEDERVORLAGEN_REL)).ifPresent(model::add);
 
-		addGetByUngeleseneNachrichtenLinks(modelBuilder, userId);
+		addGetByUngeleseneNachrichtenLinks(model, userId);
 	}
 
 	Link buildGetAllUnassignedVorgaengeLink() {
@@ -155,12 +153,12 @@ class RootViewLinkHandler {
 		return linkTo(methodOn(VorgangController.class).getAllByAssignedToAndSearchBy(0, PAGE_SIZE, userId, null));
 	}
 
-	void addAllVorgangStatusLinks(ModelBuilder<Root> modelBuilder) {
-		addVorgangStatusLinks(modelBuilder, VORGAENGE_ALL_REL_TEMPLATE);
+	void addAllVorgangStatusLinks(EntityModel<Root> model) {
+		addVorgangStatusLinks(model, VORGAENGE_ALL_REL_TEMPLATE);
 	}
 
-	void addVorgangStatusLinks(ModelBuilder<Root> modelBuilder, String linkRelTemplate) {
-		statusList.forEach(status -> modelBuilder.addLink(buildGetAllVorgaengeByStatus(status, linkRelTemplate)));
+	void addVorgangStatusLinks(EntityModel<Root> model, String linkRelTemplate) {
+		statusList.forEach(status -> model.add(buildGetAllVorgaengeByStatus(status, linkRelTemplate)));
 	}
 
 	Link buildGetAllVorgaengeByStatus(VorgangStatus status, String linkRelTemplate) {
@@ -199,21 +197,21 @@ class RootViewLinkHandler {
 				VorgangController.PARAM_NEXT_WIEDERVORLAGE_FRIST_EXISTS)).withRel(linkRel);
 	}
 
-	void addGetByUngeleseneNachrichtenLinks(ModelBuilder<Root> modelBuilder, Optional<UserId> userId) {
-		modelBuilder.addLink(buildGelAllByUngeleseneNachrichtenLink());
-		modelBuilder.addLink(buildGetAllByAssignedToAndUngeleseneNachrichten(UserId.empty(), UNASSIGNED_UNGELESENE_NACHRICHTEN_REL));
-		userId.map(id -> buildGetAllByAssignedToAndUngeleseneNachrichten(id, MY_UNGELESENE_NACHRICHTEN_REL)).ifPresent(modelBuilder::addLink);
+	void addGetByUngeleseneNachrichtenLinks(EntityModel<Root> model, Optional<UserId> userId) {
+		model.add(buildGelAllByUngeleseneNachrichtenLink());
+		model.add(buildGetAllByAssignedToAndUngeleseneNachrichten(UserId.empty(), UNASSIGNED_UNGELESENE_NACHRICHTEN_REL));
+		userId.map(id -> buildGetAllByAssignedToAndUngeleseneNachrichten(id, MY_UNGELESENE_NACHRICHTEN_REL)).ifPresent(model::add);
 	}
 
 	Link buildGelAllByUngeleseneNachrichtenLink() {
 		return linkTo(methodOn(VorgangController.class)
 				.getAllByUngeleseneNachrichten(0, PAGE_SIZE, VorgangController.PARAM_NACHRICHTEN_UNGELESENE))
-				.withRel(ALL_UNGELESENE_NACHRICHTEN_REL);
+						.withRel(ALL_UNGELESENE_NACHRICHTEN_REL);
 	}
 
 	Link buildGetAllByAssignedToAndUngeleseneNachrichten(@NonNull UserId userId, String linkRel) {
 		return linkTo(methodOn(VorgangController.class)
 				.getAllByAssignedToAndUngeleseneNachrichten(0, PAGE_SIZE, userId, VorgangController.PARAM_NACHRICHTEN_UNGELESENE))
-				.withRel(linkRel);
+						.withRel(linkRel);
 	}
 }
\ No newline at end of file
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/aktenzeichen/AktenzeichenModelProcessor.java b/alfa-service/src/main/java/de/ozgcloud/alfa/aktenzeichen/AktenzeichenModelProcessor.java
index aa7ce0231ef73c01e37dc2886be868cd38962b56..7f767028624c83276e34c42df2226aeb606e6310 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/aktenzeichen/AktenzeichenModelProcessor.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/aktenzeichen/AktenzeichenModelProcessor.java
@@ -33,7 +33,6 @@ import org.springframework.hateoas.LinkRelation;
 import org.springframework.hateoas.server.RepresentationModelProcessor;
 import org.springframework.stereotype.Component;
 
-import de.ozgcloud.alfa.common.ModelBuilder;
 import de.ozgcloud.alfa.common.command.CommandController;
 import de.ozgcloud.alfa.vorgang.Vorgang;
 import de.ozgcloud.alfa.vorgang.VorgangWithEingang;
@@ -43,9 +42,11 @@ public class AktenzeichenModelProcessor implements RepresentationModelProcessor<
 
 	static final LinkRelation REL_SET_AKTENZEICHEN = LinkRelation.of("set_aktenzeichen");
 
-	static final List<Vorgang.VorgangStatus> SET_AKTENZEICHEN_STATUSES = List.of(Vorgang.VorgangStatus.ANGENOMMEN, Vorgang.VorgangStatus.IN_BEARBEITUNG);
+	static final List<Vorgang.VorgangStatus> SET_AKTENZEICHEN_STATUSES = List.of(Vorgang.VorgangStatus.ANGENOMMEN,
+			Vorgang.VorgangStatus.IN_BEARBEITUNG);
 
-	private static final Predicate<VorgangWithEingang> IS_SET_AKTENZEICHEN_ALLOWED = vorgang -> SET_AKTENZEICHEN_STATUSES.contains(vorgang.getStatus());
+	private static final Predicate<VorgangWithEingang> IS_SET_AKTENZEICHEN_ALLOWED = vorgang -> SET_AKTENZEICHEN_STATUSES
+			.contains(vorgang.getStatus());
 
 	@Override
 	public EntityModel<VorgangWithEingang> process(EntityModel<VorgangWithEingang> model) {
@@ -54,11 +55,9 @@ public class AktenzeichenModelProcessor implements RepresentationModelProcessor<
 		if (vorgang == null) {
 			return model;
 		}
+		model.addIf(IS_SET_AKTENZEICHEN_ALLOWED.test(vorgang), () -> linkTo(methodOn(CommandController.CommandByRelationController.class)
+				.createCommand(vorgang.getId(), vorgang.getId(), vorgang.getVersion(), null)).withRel(REL_SET_AKTENZEICHEN));
 
-		return ModelBuilder.fromModel(model)
-				.ifMatch(IS_SET_AKTENZEICHEN_ALLOWED)
-				.addLink(linkTo(methodOn(CommandController.CommandByRelationController.class).createCommand(vorgang.getId(), vorgang.getId(), vorgang.getVersion(),
-						null)).withRel(REL_SET_AKTENZEICHEN))
-				.buildModel();
+		return model;
 	}
 }
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/bescheid/BescheidModelAssembler.java b/alfa-service/src/main/java/de/ozgcloud/alfa/bescheid/BescheidModelAssembler.java
index f02c1ae8594ce65d7791033112b4ed7f2fda297e..723a74e134aa4a3398961b959b234e001db8fad7 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/bescheid/BescheidModelAssembler.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/bescheid/BescheidModelAssembler.java
@@ -26,6 +26,7 @@ package de.ozgcloud.alfa.bescheid;
 import static java.util.Optional.*;
 import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*;
 
+import java.util.List;
 import java.util.Optional;
 import java.util.function.Predicate;
 
@@ -37,7 +38,6 @@ import org.springframework.hateoas.server.mvc.WebMvcLinkBuilder;
 import org.springframework.stereotype.Component;
 
 import de.ozgcloud.alfa.bescheid.BescheidController.BescheidByVorgangController;
-import de.ozgcloud.alfa.common.ModelBuilder;
 import de.ozgcloud.alfa.common.binaryfile.BinaryFileController;
 import de.ozgcloud.alfa.common.command.CommandController;
 import de.ozgcloud.alfa.common.command.CommandController.CommandByRelationController;
@@ -88,22 +88,20 @@ public class BescheidModelAssembler implements RepresentationModelAssembler<Besc
 				methodOn(BescheidCommandController.class).createCommand(vorgangWithEingang.getId(), bescheid.getId(), bescheid.getVersion(),
 						null));
 
-		return ModelBuilder.fromEntity(bescheid)
-				.addLink(selfLink.withSelfRel())
-				.addLink(deleteLink.withRel(REL_DELETE))
-				.addLink(selfLink.withSelfRel())
-				.addLink(uploadBescheidFileLink.withRel(REL_UPLOAD_BESCHEID_FILE))
-				.addLink(uploadAttachmentLink.withRel(REL_UPLOAD_ATTACHMENT))
-				.ifMatch(HAS_ATTACHMENTS)
-				.addLink(attachmentsLink.withRel(REL_ATTACHMENTS))
-				.addLink(createCommandLink.withRel(REL_UPDATE))
-				.ifMatch(() -> canCreateBescheidDocumentAutomatically(vorgangWithEingang))
-				.addLink(createCommandLink.withRel(REL_CREATE_DOCUMENT))
-				.addLink(createCommandLink.withRel(REL_CREATE_DOCUMENT_FROM_FILE))
-				.ifMatch(() -> canSendMessageToAntragsteller(vorgangWithEingang))
-				.addLink(bescheidenUndSendenLink.withRel(REL_BESCHEIDEN_UND_SENDEN))
-				.addLink(createCommandLink.withRel(REL_BESCHEIDEN))
-				.buildModel();
+		return EntityModel.of(bescheid)
+				.add(List.of(selfLink.withSelfRel(),
+						deleteLink.withRel(REL_DELETE),
+						uploadBescheidFileLink.withRel(REL_UPLOAD_BESCHEID_FILE),
+						uploadAttachmentLink.withRel(REL_UPLOAD_ATTACHMENT),
+						createCommandLink.withRel(REL_BESCHEIDEN),
+						createCommandLink.withRel(REL_UPDATE),
+						createCommandLink.withRel(REL_CREATE_DOCUMENT_FROM_FILE)))
+				.addIf(HAS_ATTACHMENTS.test(bescheid),
+						() -> attachmentsLink.withRel(REL_ATTACHMENTS))
+				.addIf(canCreateBescheidDocumentAutomatically(vorgangWithEingang),
+						() -> createCommandLink.withRel(REL_CREATE_DOCUMENT))
+				.addIf(canSendMessageToAntragsteller(vorgangWithEingang),
+						() -> bescheidenUndSendenLink.withRel(REL_BESCHEIDEN_UND_SENDEN));
 	}
 
 	@Override
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/bescheid/BescheidVorgangProcessor.java b/alfa-service/src/main/java/de/ozgcloud/alfa/bescheid/BescheidVorgangProcessor.java
index d9cab224faea3d45e4bf2d63a2e25a6dc33853af..1af6b1ed3fbcb663d89a4f855559c9a1cf6bff97 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/bescheid/BescheidVorgangProcessor.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/bescheid/BescheidVorgangProcessor.java
@@ -26,7 +26,6 @@ package de.ozgcloud.alfa.bescheid;
 import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*;
 
 import java.util.Objects;
-import java.util.function.BooleanSupplier;
 
 import org.springframework.hateoas.EntityModel;
 import org.springframework.hateoas.LinkRelation;
@@ -35,7 +34,6 @@ import org.springframework.hateoas.server.mvc.WebMvcLinkBuilder;
 import org.springframework.stereotype.Component;
 
 import de.ozgcloud.alfa.bescheid.BescheidController.BescheidByVorgangController;
-import de.ozgcloud.alfa.common.ModelBuilder;
 import de.ozgcloud.alfa.common.command.CommandController.CommandByRelationController;
 import de.ozgcloud.alfa.common.user.CurrentUserService;
 import de.ozgcloud.alfa.common.user.UserRole;
@@ -60,14 +58,14 @@ class BescheidVorgangProcessor implements RepresentationModelProcessor<EntityMod
 		if (Objects.isNull(vorgang) || currentUserService.hasRole(UserRole.EINHEITLICHER_ANSPRECHPARTNER)) {
 			return model;
 		}
-		return ModelBuilder.fromModel(model)
-				.ifMatch(isRetrievingDraftAllowed(vorgang))
-				.addLink(getDraftLink(vorgang.getId()).withRel(REL_DRAFT))
-				.ifMatch(isCreatingDraftAllowed(vorgang))
-				.addLink(getCreateBescheidDraftLink(vorgang.getId(), vorgang.getVersion()).withRel(REL_CREATE_DRAFT))
-				.ifMatch(() -> existsBescheid(vorgang.getId()))
-				.addLink(getBescheideLink(vorgang.getId()).withRel(REL_BESCHEIDE))
-				.buildModel();
+		model
+				.addIf(isRetrievingDraftAllowed(vorgang),
+						() -> getDraftLink(vorgang.getId()).withRel(REL_DRAFT))
+				.addIf(isCreatingDraftAllowed(vorgang),
+						() -> getCreateBescheidDraftLink(vorgang.getId(), vorgang.getVersion()).withRel(REL_CREATE_DRAFT))
+				.addIf(existsBescheid(vorgang.getId()),
+						() -> getBescheideLink(vorgang.getId()).withRel(REL_BESCHEIDE));
+		return model;
 	}
 
 	private WebMvcLinkBuilder getDraftLink(String vorgangId) {
@@ -86,12 +84,12 @@ class BescheidVorgangProcessor implements RepresentationModelProcessor<EntityMod
 		return linkTo(methodOn(BescheidByVorgangController.class).getAll(vorgangId));
 	}
 
-	BooleanSupplier isRetrievingDraftAllowed(Vorgang vorgang) {
-		return () -> isVorgangInBearbeitung(vorgang) && draftExists(vorgang);
+	boolean isRetrievingDraftAllowed(Vorgang vorgang) {
+		return isVorgangInBearbeitung(vorgang) && draftExists(vorgang);
 	}
 
-	BooleanSupplier isCreatingDraftAllowed(Vorgang vorgang) {
-		return () -> isVorgangInBearbeitung(vorgang) && !draftExists(vorgang);
+	boolean isCreatingDraftAllowed(Vorgang vorgang) {
+		return isVorgangInBearbeitung(vorgang) && !draftExists(vorgang);
 	}
 
 	boolean isVorgangInBearbeitung(Vorgang vorgang) {
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/bescheid/DocumentModelAssembler.java b/alfa-service/src/main/java/de/ozgcloud/alfa/bescheid/DocumentModelAssembler.java
index cef3f165bce2d94123fdaef19b81ae670e38f30e..5d01a2a663cc36a1c98fec53630792e4348472e2 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/bescheid/DocumentModelAssembler.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/bescheid/DocumentModelAssembler.java
@@ -29,7 +29,6 @@ import org.springframework.hateoas.EntityModel;
 import org.springframework.hateoas.server.RepresentationModelAssembler;
 import org.springframework.stereotype.Component;
 
-import de.ozgcloud.alfa.common.ModelBuilder;
 import lombok.RequiredArgsConstructor;
 
 @Component
@@ -42,8 +41,7 @@ class DocumentModelAssembler implements RepresentationModelAssembler<Document, E
 	public EntityModel<Document> toModel(Document document) {
 		var selfLink = linkTo(methodOn(DocumentController.class).getDocument(document.getId()));
 
-		return ModelBuilder.fromEntity(document)
-				.addLink(selfLink.withSelfRel())
-				.buildModel();
+		return EntityModel.of(document)
+				.add(selfLink.withSelfRel());
 	}
 }
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/CollaborationModelAssembler.java b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/CollaborationModelAssembler.java
index cdcc60be022212764463013dd956efa906508806..703c1e5fabfaed6905cd4e068eba196210e44d27 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/CollaborationModelAssembler.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/CollaborationModelAssembler.java
@@ -35,8 +35,6 @@ import org.springframework.hateoas.server.RepresentationModelAssembler;
 import org.springframework.stereotype.Component;
 
 import de.ozgcloud.alfa.collaboration.CollaborationController.CollaborationByVorgangController;
-import de.ozgcloud.alfa.common.CollectionModelBuilder;
-import de.ozgcloud.alfa.common.ModelBuilder;
 import de.ozgcloud.alfa.common.command.CommandController;
 import de.ozgcloud.alfa.vorgang.VorgangController;
 import de.ozgcloud.alfa.vorgang.VorgangWithEingang;
@@ -53,10 +51,8 @@ class CollaborationModelAssembler implements RepresentationModelAssembler<Collab
 	@Override
 	public EntityModel<Collaboration> toModel(Collaboration collaboration) {
 		var selfLink = linkTo(methodOn(CollaborationController.class).getById(collaboration.getId())).withSelfRel();
-
-		return ModelBuilder.fromEntity(collaboration)
-				.addLink(selfLink)
-				.buildModel();
+		return EntityModel.of(collaboration)
+				.add(selfLink);
 	}
 
 	public CollectionModel<EntityModel<Collaboration>> toCollectionModel(Stream<? extends Collaboration> entities, String vorgangId) {
@@ -65,11 +61,9 @@ class CollaborationModelAssembler implements RepresentationModelAssembler<Collab
 
 		var selfLink = linkTo(methodOn(CollaborationByVorgangController.class).getAllByVorgangId(vorgangId)).withSelfRel();
 
-		return CollectionModelBuilder.fromEntities(entityModels)
-				.addLink(selfLink)
-				.ifMatch(() -> entityModels.isEmpty() && vorgangController.isEditable(vorgang))
-				.addLink(() -> buildCreateCollaborationRequestLink(vorgang))
-				.buildModel();
+		return CollectionModel.of(entityModels)
+				.add(selfLink)
+				.addIf(entityModels.isEmpty() && vorgangController.isEditable(vorgang), () -> buildCreateCollaborationRequestLink(vorgang));
 	}
 
 	Link buildCreateCollaborationRequestLink(VorgangWithEingang vorgang) {
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/CollaborationVorgangProcessor.java b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/CollaborationVorgangProcessor.java
index b1c4dd3da3b2f4846590bd6afb9f94ae0d9e3220..2f75114f05193871bb4c78621f119d912075065f 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/CollaborationVorgangProcessor.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/CollaborationVorgangProcessor.java
@@ -25,6 +25,7 @@ package de.ozgcloud.alfa.collaboration;
 
 import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*;
 
+import java.util.List;
 import java.util.Objects;
 
 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@@ -35,7 +36,6 @@ import org.springframework.hateoas.server.RepresentationModelProcessor;
 import org.springframework.stereotype.Component;
 
 import de.ozgcloud.alfa.collaboration.CollaborationController.CollaborationByVorgangController;
-import de.ozgcloud.alfa.common.ModelBuilder;
 import de.ozgcloud.alfa.common.user.CurrentUserService;
 import de.ozgcloud.alfa.common.user.UserRole;
 import de.ozgcloud.alfa.vorgang.VorgangWithEingang;
@@ -60,12 +60,10 @@ class CollaborationVorgangProcessor implements RepresentationModelProcessor<Enti
 		if (Objects.isNull(vorgang) || !currentUserService.hasRole(UserRole.VERWALTUNG_USER)) {
 			return model;
 		}
-
-		return ModelBuilder.fromModel(model)
-				.ifMatch(() -> !collaborationService.hasCollaboration(vorgang.getId()))
-				.addLinks(buildSearchOrganisationsEinheitLink(), buildSearchFachstelleLink())
-				.addLink(linkTo(methodOn(CollaborationByVorgangController.class).getAllByVorgangId(vorgang.getId())).withRel(REL_COLLABORATIONS))
-				.buildModel();
+		model.addAllIf(!collaborationService.hasCollaboration(vorgang.getId()),
+				() -> List.of(buildSearchOrganisationsEinheitLink(), buildSearchFachstelleLink()))
+				.add(linkTo(methodOn(CollaborationByVorgangController.class).getAllByVorgangId(vorgang.getId())).withRel(REL_COLLABORATIONS));
+		return model;
 	}
 
 	private Link buildSearchOrganisationsEinheitLink() {
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/FachstelleModelAssembler.java b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/FachstelleModelAssembler.java
index 0b3a22989fd57212f3e4b93c3654d199174ed15f..9bc6f742c029bf7908c9559c22bc3ee81dfa0574 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/FachstelleModelAssembler.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/FachstelleModelAssembler.java
@@ -32,17 +32,14 @@ import org.springframework.hateoas.EntityModel;
 import org.springframework.hateoas.server.RepresentationModelAssembler;
 import org.springframework.stereotype.Component;
 
-import de.ozgcloud.alfa.common.ModelBuilder;
-
 @Component
 class FachstelleModelAssembler
 		implements RepresentationModelAssembler<Fachstelle, EntityModel<Fachstelle>> {
 
 	@Override
 	public EntityModel<Fachstelle> toModel(@Nonnull Fachstelle entity) {
-		return ModelBuilder.fromEntity(entity)
-				.addLink(linkTo(FachstelleController.class).slash(entity.getId()).withSelfRel())
-				.buildModel();
+		return EntityModel.of(entity)
+				.add(linkTo(FachstelleController.class).slash(entity.getId()).withSelfRel());
 	}
 
 	@Override
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitHeaderModelAssembler.java b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitHeaderModelAssembler.java
index 35bc52e64167f4ce8de05e37bf30502947c4b43d..a77ae2c76afb27e1fe2356e9e115d0b72813d4eb 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitHeaderModelAssembler.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitHeaderModelAssembler.java
@@ -32,17 +32,14 @@ import org.springframework.hateoas.EntityModel;
 import org.springframework.hateoas.server.RepresentationModelAssembler;
 import org.springframework.stereotype.Component;
 
-import de.ozgcloud.alfa.common.ModelBuilder;
-
 @Component
 class OrganisationsEinheitHeaderModelAssembler
 		implements RepresentationModelAssembler<OrganisationsEinheitHeader, EntityModel<OrganisationsEinheitHeader>> {
 
 	@Override
 	public EntityModel<OrganisationsEinheitHeader> toModel(@Nonnull OrganisationsEinheitHeader entity) {
-		return ModelBuilder.fromEntity(entity)
-				.addLink(linkTo(OrganisationsEinheitController.class).slash(entity.getId()).withSelfRel())
-				.buildModel();
+		return EntityModel.of(entity)
+				.add(linkTo(OrganisationsEinheitController.class).slash(entity.getId()).withSelfRel());
 	}
 
 	@Override
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitModelAssembler.java b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitModelAssembler.java
index ad3ee72f30874e2fee0f3ed5475b64c68b083029..1d699dcc740a6e21cdfd9628f4fccb5a54bf0432 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitModelAssembler.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitModelAssembler.java
@@ -29,15 +29,12 @@ import org.springframework.hateoas.EntityModel;
 import org.springframework.hateoas.server.RepresentationModelAssembler;
 import org.springframework.stereotype.Component;
 
-import de.ozgcloud.alfa.common.ModelBuilder;
-
 @Component
 class OrganisationsEinheitModelAssembler implements RepresentationModelAssembler<OrganisationsEinheit, EntityModel<OrganisationsEinheit>> {
 
 	@Override
 	public EntityModel<OrganisationsEinheit> toModel(OrganisationsEinheit entity) {
-		return ModelBuilder.fromEntity(entity)
-				.addLink(linkTo(OrganisationsEinheitController.class).slash(entity.getId()).withSelfRel())
-				.buildModel();
+		return EntityModel.of(entity)
+				.add(linkTo(OrganisationsEinheitController.class).slash(entity.getId()).withSelfRel());
 	}
 }
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/common/CollectionModelBuilder.java b/alfa-service/src/main/java/de/ozgcloud/alfa/common/CollectionModelBuilder.java
deleted file mode 100644
index 01ceb2d404037d97e024e9ff33baa69b6cc88607..0000000000000000000000000000000000000000
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/common/CollectionModelBuilder.java
+++ /dev/null
@@ -1,94 +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.common;
-
-import java.util.LinkedList;
-import java.util.List;
-import java.util.function.BooleanSupplier;
-import java.util.function.Predicate;
-import java.util.function.Supplier;
-import java.util.stream.Stream;
-
-import org.springframework.hateoas.CollectionModel;
-import org.springframework.hateoas.Link;
-
-import lombok.RequiredArgsConstructor;
-
-public class CollectionModelBuilder<T> {
-
-	private final Iterable<T> entities;
-
-	private final List<Link> links = new LinkedList<>();
-
-	private CollectionModelBuilder(Iterable<T> entities) {
-		this.entities = entities;
-	}
-
-	public static <T> CollectionModelBuilder<T> fromEntities(Iterable<T> entities) {
-		return new CollectionModelBuilder<>(entities);
-	}
-
-	public static <T> CollectionModelBuilder<T> fromEntities(Stream<T> entities) {
-		return new CollectionModelBuilder<>(entities.toList());
-	}
-
-	public CollectionModelBuilder<T> addLink(Link link) {
-		links.add(link);
-		return this;
-	}
-
-	public ConditionalLinkAdder ifMatch(BooleanSupplier guard) {
-		return new ConditionalLinkAdder(guard.getAsBoolean());
-	}
-
-	public ConditionalLinkAdder ifMatch(Predicate<? super Iterable<T>> predicate) {
-		return new ConditionalLinkAdder(predicate.test(entities));
-	}
-
-	public CollectionModel<T> buildModel() {
-		var builtModel = CollectionModel.of(entities);
-		builtModel.add(links);
-		return builtModel;
-	}
-
-	@RequiredArgsConstructor
-	public class ConditionalLinkAdder {
-
-		public final boolean conditionFulfilled;
-
-		public CollectionModelBuilder<T> addLink(Link link) {
-			if (conditionFulfilled) {
-				links.add(link);
-			}
-			return CollectionModelBuilder.this;
-		}
-
-		public CollectionModelBuilder<T> addLink(Supplier<Link> linkSupplier) {
-			if (conditionFulfilled) {
-				links.add(linkSupplier.get());
-			}
-			return CollectionModelBuilder.this;
-		}
-	}
-}
\ No newline at end of file
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/common/LinkedResourceCollectionProcessor.java b/alfa-service/src/main/java/de/ozgcloud/alfa/common/LinkedResourceCollectionProcessor.java
new file mode 100644
index 0000000000000000000000000000000000000000..8a3e623017e86d8fb9995ab58b3f300f2380e454
--- /dev/null
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/common/LinkedResourceCollectionProcessor.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2025 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.common;
+
+import org.springframework.hateoas.CollectionModel;
+import org.springframework.hateoas.EntityModel;
+import org.springframework.hateoas.server.RepresentationModelProcessor;
+import org.springframework.stereotype.Component;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.log4j.Log4j2;
+
+@Log4j2
+@Component
+@RequiredArgsConstructor
+public class LinkedResourceCollectionProcessor<T> implements RepresentationModelProcessor<CollectionModel<EntityModel<T>>> {
+
+	private final LinkedResourceProcessor<T> elementProcessor;
+
+	@Override
+	public CollectionModel<EntityModel<T>> process(CollectionModel<EntityModel<T>> model) {
+		model.getContent().forEach(elementProcessor::process);
+		return model;
+	}
+}
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/common/LinkedResourceProcessor.java b/alfa-service/src/main/java/de/ozgcloud/alfa/common/LinkedResourceProcessor.java
new file mode 100644
index 0000000000000000000000000000000000000000..67cb22c470130c5e04079b40a61182c98aed13a8
--- /dev/null
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/common/LinkedResourceProcessor.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2025 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.common;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.stream.Stream;
+
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.hateoas.EntityModel;
+import org.springframework.hateoas.Link;
+import org.springframework.hateoas.server.RepresentationModelProcessor;
+import org.springframework.hateoas.server.mvc.WebMvcLinkBuilder;
+import org.springframework.stereotype.Component;
+
+import de.ozgcloud.alfa.common.user.UserManagerUrlProvider;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.log4j.Log4j2;
+
+@Log4j2
+@Component
+@RequiredArgsConstructor
+public class LinkedResourceProcessor<T> implements RepresentationModelProcessor<EntityModel<T>> {
+
+	private final UserManagerUrlProvider userManagerUrlProvider;
+
+	@Override
+	public EntityModel<T> process(EntityModel<T> model) {
+		addResourceLinks(model);
+		addUserProfileLinks(model);
+		return model;
+	}
+
+	void addResourceLinks(EntityModel<T> model) {
+		getAnnotatedFields(LinkedResource.class, model.getContent())
+				.filter(field -> shouldAddLink(model, field))
+				.forEach(field -> addLinkForLinkedResourceField(model, field));
+	}
+
+	void addLinkForLinkedResourceField(EntityModel<T> model, Field field) {
+		getEntityFieldValue(model.getContent(), field).map(Object::toString).filter(StringUtils::isNotBlank)
+				.ifPresent(val -> model
+						.add(WebMvcLinkBuilder.linkTo(field.getAnnotation(LinkedResource.class).controllerClass()).slash(val)
+								.withRel(getResourceName(field))));
+	}
+
+	void addUserProfileLinks(EntityModel<T> model) {
+		getAnnotatedFields(LinkedUserProfileResource.class, model.getContent())
+				.filter(field -> shouldAddLink(model, field))
+				.forEach(field -> addLinkForLinkedUserProfileResourceField(model, field));
+	}
+
+	Stream<Field> getAnnotatedFields(Class<? extends Annotation> annotationClass, T content) {
+		if (Objects.isNull(content)) {
+			return Stream.empty();
+		}
+		return Arrays.stream(content.getClass().getDeclaredFields())
+				.filter(field -> field.isAnnotationPresent(annotationClass));
+	}
+
+	boolean shouldAddLink(EntityModel<T> model, Field field) {
+		return !(field.getType().isArray() || Collection.class.isAssignableFrom(field.getType())
+				|| model.hasLink(getResourceName(field)));
+	}
+
+	void addLinkForLinkedUserProfileResourceField(EntityModel<T> model, Field field) {
+		getEntityFieldValue(model.getContent(), field).map(Object::toString).filter(StringUtils::isNotBlank)
+				.ifPresent(value -> addUserProfileLink(model, field, value));
+	}
+
+	private void addUserProfileLink(EntityModel<T> model, Field field, String value) {
+		Optional.ofNullable(userManagerUrlProvider.getUserProfileTemplate()).filter(StringUtils::isNotBlank)
+				.ifPresent(template -> model.add(Link.of(template.formatted(value)).withRel(getResourceName(field))));
+	}
+
+	private Optional<Object> getEntityFieldValue(T content, Field field) {
+		try {
+			field.setAccessible(true);
+			Optional<Object> value = Optional.ofNullable(field.get(content));
+			field.setAccessible(false);
+			return value;
+		} catch (IllegalArgumentException | IllegalAccessException e) {
+			LOG.warn("Cannot access field value of LinkedResource field.", e);
+		}
+		return Optional.empty();
+	}
+
+	private String getResourceName(Field field) {
+		var fieldName = field.getName();
+		if (fieldName.endsWith("Id")) {
+			return fieldName.substring(0, fieldName.indexOf("Id"));
+		}
+		return fieldName;
+	}
+}
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/common/LinkedUserProfileResourceSerializer.java b/alfa-service/src/main/java/de/ozgcloud/alfa/common/LinkedUserProfileResourceSerializer.java
index ed0f0ee2936cd65ee0e34587616ae67c2af65183..eeecf38a5a0a714901c274bcd451c07b8d6ef893 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/common/LinkedUserProfileResourceSerializer.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/common/LinkedUserProfileResourceSerializer.java
@@ -28,7 +28,9 @@ import java.lang.reflect.InvocationTargetException;
 import java.util.Collection;
 
 import org.apache.commons.lang3.reflect.ConstructorUtils;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.hateoas.Link;
+import org.springframework.stereotype.Component;
 
 import com.fasterxml.jackson.core.JsonGenerator;
 import com.fasterxml.jackson.databind.BeanProperty;
@@ -36,37 +38,34 @@ import com.fasterxml.jackson.databind.JsonSerializer;
 import com.fasterxml.jackson.databind.SerializerProvider;
 import com.fasterxml.jackson.databind.ser.ContextualSerializer;
 
+import de.ozgcloud.alfa.common.user.UserManagerProperties;
+import de.ozgcloud.alfa.common.user.UserManagerUrlProvider;
 import de.ozgcloud.common.errorhandling.TechnicalException;
-import lombok.NoArgsConstructor;
+import lombok.RequiredArgsConstructor;
 
-@NoArgsConstructor
+@Component
+@RequiredArgsConstructor(onConstructor_ = { @Autowired })
 public class LinkedUserProfileResourceSerializer extends JsonSerializer<Object> implements ContextualSerializer {
 
+	private final UserManagerUrlProvider userManagerUrlProvider;
 	private LinkedUserProfileResource annotation;
 
-	private LinkedUserProfileResourceSerializer(LinkedUserProfileResource annotation) {
-		this.annotation = annotation;
+	// ObjectMapper uses this, if called outside of Spring, so dependency injection does not work
+	private LinkedUserProfileResourceSerializer() {
+		this(new UserManagerUrlProvider(new UserManagerProperties()));
 	}
 
 	@Override
 	public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) {
-		return new LinkedUserProfileResourceSerializer(property.getAnnotation(LinkedUserProfileResource.class));
+		return LinkedUserProfileResourceSerializer.createForAnnotatedField(userManagerUrlProvider,
+				property.getAnnotation(LinkedUserProfileResource.class));
 	}
 
-	String buildLink(Object id) {
-		if (UserProfileUrlProvider.isConfigured()) {
-			return Link.of(UserProfileUrlProvider.getUrl(getExtractor().extractId(id))).getHref();
-		} else {
-			return id.toString();
-		}
-	}
-
-	IdExtractor<Object> getExtractor() {
-		try {
-			return ConstructorUtils.invokeConstructor(annotation.extractor());
-		} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException e) {
-			throw new TechnicalException("Error instanciating IdExtractor", e);
-		}
+	static LinkedUserProfileResourceSerializer createForAnnotatedField(UserManagerUrlProvider userManagerUrlProvider,
+			LinkedUserProfileResource annotation) {
+		var serializer = new LinkedUserProfileResourceSerializer(userManagerUrlProvider);
+		serializer.annotation = annotation;
+		return serializer;
 	}
 
 	@Override
@@ -80,7 +79,23 @@ public class LinkedUserProfileResourceSerializer extends JsonSerializer<Object>
 		}
 	}
 
-	void writeObject(JsonGenerator gen, Object value) {
+	private String buildLink(Object id) {
+		return userManagerUrlProvider.isConfiguredForUserProfile() ? Link.of(buildUserProfileUri(id.toString())).getHref() : String.valueOf(id);
+	}
+
+	private String buildUserProfileUri(String id) {
+		return String.format(userManagerUrlProvider.getUserProfileTemplate(), getExtractor().extractId(id));
+	}
+
+	private IdExtractor<Object> getExtractor() {
+		try {
+			return ConstructorUtils.invokeConstructor(annotation.extractor());
+		} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException e) {
+			throw new TechnicalException("Error instanciating IdExtractor", e);
+		}
+	}
+
+	private void writeObject(JsonGenerator gen, Object value) {
 		try {
 			gen.writeObject(value);
 		} catch (IOException e) {
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/common/ModelBuilder.java b/alfa-service/src/main/java/de/ozgcloud/alfa/common/ModelBuilder.java
deleted file mode 100644
index 79ec76f5f087866bf96bd896d377b25482b0547c..0000000000000000000000000000000000000000
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/common/ModelBuilder.java
+++ /dev/null
@@ -1,279 +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.common;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Field;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.function.BooleanSupplier;
-import java.util.function.Function;
-import java.util.function.Predicate;
-import java.util.function.Supplier;
-import java.util.function.UnaryOperator;
-import java.util.stream.Collectors;
-
-import org.apache.commons.collections.CollectionUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.reflect.FieldUtils;
-import org.springframework.hateoas.EntityModel;
-import org.springframework.hateoas.Link;
-import org.springframework.hateoas.server.mvc.WebMvcLinkBuilder;
-
-import lombok.RequiredArgsConstructor;
-import lombok.extern.log4j.Log4j2;
-
-@Log4j2
-public class ModelBuilder<T> {
-
-	private static final Map<Class<?>, Map<Object, List<Field>>> ANNOTATED_FIELDS_BY_ANNOTATION = new ConcurrentHashMap<>();
-
-	private final T entity;
-	private final EntityModel<T> model;
-
-	private final List<Link> links = new LinkedList<>();
-	private final List<Function<EntityModel<T>, EntityModel<T>>> mapper = new LinkedList<>();
-
-	private ModelBuilder(T entity) {
-		this.entity = entity;
-		this.model = null;
-	}
-
-	private ModelBuilder(EntityModel<T> model) {
-		this.entity = null;
-		this.model = model;
-	}
-
-	public static <T> ModelBuilder<T> fromEntity(T entity) {
-		return new ModelBuilder<>(entity);
-	}
-
-	public static <T> ModelBuilder<T> fromModel(EntityModel<T> model) {
-		return new ModelBuilder<>(model);
-	}
-
-	public ModelBuilder<T> addLink(Link link) {
-		links.add(link);
-		return this;
-	}
-
-	public ModelBuilder<T> addLink(Optional<Link> link) {
-		link.ifPresent(links::add);
-		return this;
-	}
-
-	public ModelBuilder<T> addLinks(Link... links) {
-		this.links.addAll(Arrays.asList(links));
-		return this;
-	}
-
-	public ModelBuilder<T> addLinks(Collection<Link> links) {
-		this.links.addAll(links);
-		return this;
-	}
-
-	public ConditionalLinkAdder ifMatch(Predicate<T> predicate) {
-		return new ConditionalLinkAdder(predicate.test(Objects.isNull(entity) ? model.getContent() : entity));
-	}
-
-	public ConditionalLinkAdder ifMatch(BooleanSupplier guard) {
-		return new ConditionalLinkAdder(guard.getAsBoolean());
-	}
-
-	public ModelBuilder<T> map(UnaryOperator<EntityModel<T>> mapper) {
-		this.mapper.add(mapper);
-		return this;
-	}
-
-	public EntityModel<T> buildModel() {
-		var filteredLinks = links.stream().filter(Objects::nonNull).collect(Collectors.toSet());
-
-		EntityModel<T> buildedModel = Objects.isNull(model) ? EntityModel.of(entity) : model;
-		buildedModel = buildedModel.add(filteredLinks);
-
-		addLinkByLinkedResourceAnnotationIfMissing(buildedModel);
-		addLinkByLinkedUserProfileResourceAnnotationIfMissing(buildedModel);
-
-		return applyMapper(buildedModel);
-	}
-
-	private EntityModel<T> applyMapper(EntityModel<T> resource) {
-		Iterator<Function<EntityModel<T>, EntityModel<T>>> i = mapper.iterator();
-		EntityModel<T> result = resource;
-		while (i.hasNext()) {
-			result = i.next().apply(result);
-		}
-		return result;
-	}
-
-	private void addLinkByLinkedResourceAnnotationIfMissing(EntityModel<T> resource) {
-		getFields(LinkedResource.class).stream()
-				.filter(field -> shouldAddLink(resource, field))
-				.forEach(field -> handleLinkedResourceField(resource, field));
-	}
-
-	private void handleLinkedResourceField(EntityModel<T> resource, Field field) {
-		getEntityFieldValue(field).map(Object::toString).filter(StringUtils::isNotBlank).ifPresent(val -> resource
-				.add(WebMvcLinkBuilder.linkTo(field.getAnnotation(LinkedResource.class).controllerClass()).slash(val)
-						.withRel(sanitizeName(field.getName()))));
-	}
-
-	private void addLinkByLinkedUserProfileResourceAnnotationIfMissing(EntityModel<T> resource) {
-		getFields(LinkedUserProfileResource.class).stream()
-				.filter(field -> shouldAddLink(resource, field))
-				.forEach(field -> handleLinkedUserProfileResourceField(resource, field));
-	}
-
-	private void handleLinkedUserProfileResourceField(EntityModel<T> resource, Field field) {
-		getEntityFieldValue(field).ifPresent(val -> {
-			if (UserProfileUrlProvider.isConfigured()) {
-				resource.add(Link.of(UserProfileUrlProvider.getUrl(val)).withRel(sanitizeName(field.getName())));
-			}
-		});
-	}
-
-	private boolean shouldAddLink(EntityModel<T> resource, Field field) {
-		return !(field.getType().isArray() || Collection.class.isAssignableFrom(field.getType()) || resource.hasLink(sanitizeName(field.getName())));
-	}
-
-	private List<Field> getFields(Class<? extends Annotation> annotationClass) {
-		var fields = Optional.ofNullable(ANNOTATED_FIELDS_BY_ANNOTATION.get(getEntity().getClass()))
-				.map(fieldsByAnnotation -> fieldsByAnnotation.get(annotationClass))
-				.orElseGet(Collections::emptyList);
-
-		if (CollectionUtils.isEmpty(fields)) {
-			fields = FieldUtils.getFieldsListWithAnnotation(getEntity().getClass(), annotationClass);
-
-			updateFields(annotationClass, fields);
-		}
-		return fields;
-	}
-
-	private void updateFields(Class<? extends Annotation> annotationClass, List<Field> fields) {
-		var annotationMap = Optional.ofNullable(ANNOTATED_FIELDS_BY_ANNOTATION.get(getEntity().getClass())).orElseGet(HashMap::new);
-		annotationMap.put(annotationClass, fields);
-
-		ANNOTATED_FIELDS_BY_ANNOTATION.put(annotationClass, annotationMap);
-	}
-
-	private String sanitizeName(String fieldName) {
-		if (fieldName.endsWith("Id")) {
-			return fieldName.substring(0, fieldName.indexOf("Id"));
-		}
-		return fieldName;
-	}
-
-	private Optional<Object> getEntityFieldValue(Field field) {
-		try {
-			field.setAccessible(true);
-			Optional<Object> value = Optional.ofNullable(field.get(getEntity()));
-			field.setAccessible(false);
-			return value;
-		} catch (IllegalArgumentException | IllegalAccessException e) {
-			LOG.warn("Cannot access field value of LinkedResource field.", e);
-		}
-		return Optional.empty();
-	}
-
-	private T getEntity() {
-		return Optional.ofNullable(entity == null ? model.getContent() : entity)
-				.orElseThrow(() -> new IllegalStateException("Entity must not null for ModelBuilding"));
-	}
-
-	@RequiredArgsConstructor
-	public class ConditionalLinkAdder {
-
-		public final boolean conditionFulfilled;
-
-		public ModelBuilder<T> addLink(Supplier<Link> linkSupplier) {
-			if (conditionFulfilled) {
-				addLink(linkSupplier.get());
-			}
-			return ModelBuilder.this;
-		}
-
-		public ModelBuilder<T> addLinkIfPresent(Supplier<Optional<Link>> linkSupplier) {
-			if (conditionFulfilled) {
-				addLink(linkSupplier.get());
-			}
-			return ModelBuilder.this;
-		}
-
-		public ModelBuilder<T> addLink(Function<T, Link> linkBuilder) {
-			if (conditionFulfilled) {
-				addLink(linkBuilder.apply(getEntity()));
-			}
-			return ModelBuilder.this;
-		}
-
-		public ModelBuilder<T> addLink(Link link) {
-			if (conditionFulfilled) {
-				links.add(link);
-			}
-			return ModelBuilder.this;
-		}
-
-		public ModelBuilder<T> addLink(Optional<Link> link) {
-			if (conditionFulfilled) {
-				link.ifPresent(links::add);
-			}
-			return ModelBuilder.this;
-		}
-
-		public ModelBuilder<T> addLinks(Link... links) {
-			if (conditionFulfilled) {
-				ModelBuilder.this.links.addAll(Arrays.asList(links));
-			}
-			return ModelBuilder.this;
-		}
-
-		@SafeVarargs
-		public final ModelBuilder<T> addLinks(Supplier<Link>... linkSuppliers) {
-			if (conditionFulfilled) {
-				for (int i = 0; i < linkSuppliers.length; i++) {
-					ModelBuilder.this.links.add(linkSuppliers[i].get());
-				}
-			}
-			return ModelBuilder.this;
-		}
-
-		public final ModelBuilder<T> addLinks(Supplier<Collection<Link>> linksSupplier) {
-			if (conditionFulfilled) {
-				linksSupplier.get().forEach(ModelBuilder.this.links::add);
-			}
-
-			return ModelBuilder.this;
-		}
-
-	}
-}
\ No newline at end of file
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/common/UserProfileUrlProvider.java b/alfa-service/src/main/java/de/ozgcloud/alfa/common/UserProfileUrlProvider.java
deleted file mode 100644
index 100dd420eb21777a28dae8e70688493017a73756..0000000000000000000000000000000000000000
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/common/UserProfileUrlProvider.java
+++ /dev/null
@@ -1,74 +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.common;
-
-import java.util.Objects;
-
-import org.springframework.beans.BeansException;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.ApplicationContextAware;
-import org.springframework.stereotype.Component;
-
-import com.google.common.base.Preconditions;
-
-@Component
-public class UserProfileUrlProvider implements ApplicationContextAware {
-	// TODO auf javax.validation umstellen
-	private static final String ERROR_MESSAGE = "Key %s missing, please add it to the application.yml";
-	// TODO applicationContext darf nicht static abgelegt werden - es sollte möglich
-	// sein, dass eine andere Konfiguration in der jvm läuft.
-	private static ApplicationContext applicationContext;
-	static final String URL_ROOT_KEY = "ozgcloud.user-manager.url";
-	static final String USER_PROFILES_TEMPLATE_KEY = "ozgcloud.user-manager.profile-template";
-
-	@Override
-	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
-		UserProfileUrlProvider.setSpringContext(applicationContext);
-	}
-
-	private static void setSpringContext(ApplicationContext context) {
-		applicationContext = context;
-	}
-
-	public static boolean isConfigured() {
-		return Objects.nonNull(applicationContext.getEnvironment().getProperty(URL_ROOT_KEY))
-				&& Objects.nonNull(applicationContext.getEnvironment().getProperty(USER_PROFILES_TEMPLATE_KEY));
-	}
-
-	public static String getUrl(Object val) {
-		// TODO Abhängingkeit zu com.google.common ausbauen
-		Preconditions.checkNotNull(applicationContext, "ApplicationContext not initialized");
-
-		// TODO parameter lieber injezieren und validation verwenden
-		var rootUrl = applicationContext.getEnvironment().getProperty(URL_ROOT_KEY);
-		Preconditions.checkNotNull(rootUrl, ERROR_MESSAGE, URL_ROOT_KEY);
-
-		var template = applicationContext.getEnvironment().getProperty(USER_PROFILES_TEMPLATE_KEY);
-		Preconditions.checkNotNull(template, ERROR_MESSAGE, USER_PROFILES_TEMPLATE_KEY);
-
-		// TODO UriComponent Builder verwenden
-		var profilesUrl = rootUrl + template;
-		return String.format(profilesUrl, val);
-	}
-}
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
index ecbd3482e02823170ba6c0bfcb1b3a737fcabba7..821f844c30998f277f2b17ef1f0b446fafa5289d 100644
--- 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
@@ -1,3 +1,26 @@
+/*
+ * Copyright (C) 2025 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.common.attacheditem;
 
 import java.util.function.Predicate;
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/common/binaryfile/BinaryFileModelAssembler.java b/alfa-service/src/main/java/de/ozgcloud/alfa/common/binaryfile/BinaryFileModelAssembler.java
index 1f9e5345231f8f619b0951c4480d12f9cc5d2b78..bd287a72d97f68f5718fd278c5c9ef044ba4fbe5 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/common/binaryfile/BinaryFileModelAssembler.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/common/binaryfile/BinaryFileModelAssembler.java
@@ -32,7 +32,6 @@ import org.springframework.hateoas.EntityModel;
 import org.springframework.hateoas.server.RepresentationModelAssembler;
 import org.springframework.stereotype.Component;
 
-import de.ozgcloud.alfa.common.ModelBuilder;
 import de.ozgcloud.alfa.common.file.OzgFile;
 
 @Component
@@ -43,10 +42,9 @@ public class BinaryFileModelAssembler implements RepresentationModelAssembler<Oz
 	@Override
 	public EntityModel<OzgFile> toModel(OzgFile file) {
 		var selfLink = linkTo(BinaryFileController.class).slash(file.getId());
-
-		return ModelBuilder.fromEntity(file).addLink(selfLink.withSelfRel())
-				.addLink(linkTo(BinaryFileController.class).slash(file.getId()).withRel(REL_DOWNLOAD))
-				.buildModel();
+		return EntityModel.of(file)
+				.add(selfLink.withSelfRel())
+				.add(linkTo(BinaryFileController.class).slash(file.getId()).withRel(REL_DOWNLOAD));
 	}
 
 	public CollectionModel<EntityModel<OzgFile>> toCollectionModel(Stream<OzgFile> entities) {
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/CommandModelAssembler.java b/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/CommandModelAssembler.java
index 31f4bce83e9fd2493493ccf8629ff74aecd11927..94f0209dfd9324b206466fe52e0ae806d26fbb16 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/CommandModelAssembler.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/CommandModelAssembler.java
@@ -39,7 +39,6 @@ import org.springframework.stereotype.Component;
 import de.ozgcloud.alfa.bescheid.BescheidController;
 import de.ozgcloud.alfa.bescheid.DocumentController;
 import de.ozgcloud.alfa.collaboration.CollaborationController.CollaborationByVorgangController;
-import de.ozgcloud.alfa.common.ModelBuilder;
 import de.ozgcloud.alfa.forwarding.ForwardingController;
 import de.ozgcloud.alfa.kommentar.KommentarController;
 import de.ozgcloud.alfa.postfach.PostfachMailController;
@@ -60,15 +59,12 @@ class CommandModelAssembler implements RepresentationModelAssembler<Command, Ent
 
 	@Override
 	public EntityModel<Command> toModel(Command command) {
-		return ModelBuilder.fromEntity(command)
-				.addLink(linkTo(CommandController.class).slash(command.getId()).withSelfRel())
-				.ifMatch(CommandHelper.IS_DONE.and(HAS_KNOWN_COMMAND_ORDER))
-				.addLink(() -> effectedResourceLinkByOrderType(command))
-				.ifMatch(CommandHelper.IS_PENDING)
-				.addLink(() -> linkTo(CommandController.class).slash(command.getId()).withRel(REL_UPDATE))
-				.ifMatch(IS_NOT_LOESCH_ANFORDERUNG_AND_REVOKEABLE)
-				.addLink(() -> linkTo(methodOn(CommandController.class).revoke(command.getId(), null)).withRel(REL_REVOKE))
-				.buildModel();
+		return EntityModel.of(command)
+				.add(linkTo(CommandController.class).slash(command.getId()).withSelfRel())
+				.addIf(CommandHelper.IS_DONE.and(HAS_KNOWN_COMMAND_ORDER).test(command), () -> effectedResourceLinkByOrderType(command))
+				.addIf(CommandHelper.IS_PENDING.test(command), () -> linkTo(CommandController.class).slash(command.getId()).withRel(REL_UPDATE))
+				.addIf(IS_NOT_LOESCH_ANFORDERUNG_AND_REVOKEABLE.test(command),
+						() -> linkTo(methodOn(CommandController.class).revoke(command.getId(), null)).withRel(REL_REVOKE));
 	}
 
 	Link effectedResourceLinkByOrderType(Command entity) {
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/EmptyCommandBody.java b/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/EmptyCommandBody.java
index 3095c1084dc8e64355c1622e0db528fdac472657..6249105613812c4e525b55539b690a060711febd 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/EmptyCommandBody.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/EmptyCommandBody.java
@@ -1,3 +1,26 @@
+/*
+ * Copyright (C) 2025 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.common.command;
 
 class EmptyCommandBody implements CommandBody {
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/common/user/UserManagerUrlProvider.java b/alfa-service/src/main/java/de/ozgcloud/alfa/common/user/UserManagerUrlProvider.java
index 8777af4d2960ce65c5d956b663ab844da6ae8453..819a7beb378b9f7a615ed86c627d49693250550f 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/common/user/UserManagerUrlProvider.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/common/user/UserManagerUrlProvider.java
@@ -27,21 +27,21 @@ import java.util.Optional;
 import java.util.function.Predicate;
 
 import org.apache.commons.lang3.StringUtils;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.web.util.UriComponentsBuilder;
 
 import de.ozgcloud.alfa.postfach.PostfachMail;
+import lombok.RequiredArgsConstructor;
 
 @Service
+@RequiredArgsConstructor
 public class UserManagerUrlProvider {
 
 	public static final String SYSTEM_USER_IDENTIFIER = "system";
 	public static final Predicate<PostfachMail> SENT_BY_CLIENT_USER = postfachNachricht -> Optional.ofNullable(postfachNachricht.getCreatedBy())
 			.map(createdBy -> !createdBy.toString().startsWith(SYSTEM_USER_IDENTIFIER)).orElse(false);
 
-	@Autowired
-	private UserManagerProperties userManagerProperties;
+	private final UserManagerProperties userManagerProperties;
 
 	/** only for building links */
 	public String getUserProfileTemplate() {
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/export/DmsProperties.java b/alfa-service/src/main/java/de/ozgcloud/alfa/export/DmsProperties.java
index 9ec65379fa46462a9e3c9eab9fd84deeb2ce419a..1cbfa1c9506145b9c7f415970e33b0307f3d65ac 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/export/DmsProperties.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/export/DmsProperties.java
@@ -1,3 +1,26 @@
+/*
+ * Copyright (C) 2025 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.export;
 
 import org.springframework.boot.context.properties.ConfigurationProperties;
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/export/ExportVorgangProcessor.java b/alfa-service/src/main/java/de/ozgcloud/alfa/export/ExportVorgangProcessor.java
index 33e5c38b351cb727281233dd7b9e9a26d88acc55..2cd81ac753bfeabdc41a738f018cef0129536d51 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/export/ExportVorgangProcessor.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/export/ExportVorgangProcessor.java
@@ -33,7 +33,6 @@ import org.springframework.hateoas.LinkRelation;
 import org.springframework.hateoas.server.RepresentationModelProcessor;
 import org.springframework.stereotype.Component;
 
-import de.ozgcloud.alfa.common.ModelBuilder;
 import de.ozgcloud.alfa.common.command.CommandController.CommandByRelationController;
 import de.ozgcloud.alfa.vorgang.Vorgang.VorgangStatus;
 import de.ozgcloud.alfa.vorgang.VorgangController;
@@ -59,14 +58,13 @@ class ExportVorgangProcessor implements RepresentationModelProcessor<EntityModel
 		if (Objects.isNull(vorgang)) {
 			return model;
 		}
-
-		return ModelBuilder.fromModel(model)
-				.ifMatch(IS_VORGANG_ABGESCHLOSSEN.and(vorgangController::isEditable))
-				.addLink(linkTo(methodOn(ExportVorgangController.class).exportVorgang(vorgang.getId())).withRel(REL_EXPORT))
-				.ifMatch(IS_VORGANG_ABGESCHLOSSEN.and(isDmsEnabled()).and(vorgangController::isEditable))
-				.addLink(linkTo(methodOn(CommandByRelationController.class).createCommand(vorgang.getId(), vorgang.getId(), vorgang.getVersion(),
-						null)).withRel(REL_ARCHIVE))
-				.buildModel();
+		model
+				.addIf(IS_VORGANG_ABGESCHLOSSEN.and(vorgangController::isEditable).test(vorgang),
+						() -> linkTo(methodOn(ExportVorgangController.class).exportVorgang(vorgang.getId())).withRel(REL_EXPORT))
+				.addIf(IS_VORGANG_ABGESCHLOSSEN.and(isDmsEnabled()).and(vorgangController::isEditable).test(vorgang),
+						() -> linkTo(methodOn(CommandByRelationController.class).createCommand(vorgang.getId(), vorgang.getId(), vorgang.getVersion(),
+								null)).withRel(REL_ARCHIVE));
+		return model;
 	}
 
 	private Predicate<VorgangWithEingang> isDmsEnabled() {
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/forwarding/ForwardingModelAssembler.java b/alfa-service/src/main/java/de/ozgcloud/alfa/forwarding/ForwardingModelAssembler.java
index fdb6df92dd6fa7fc692974d1e079bb8567a1bb78..b43d53909e3b9bd82ae157fa96e394ea487d2fe5 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/forwarding/ForwardingModelAssembler.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/forwarding/ForwardingModelAssembler.java
@@ -35,7 +35,6 @@ import org.springframework.hateoas.LinkRelation;
 import org.springframework.hateoas.server.RepresentationModelAssembler;
 import org.springframework.stereotype.Component;
 
-import de.ozgcloud.alfa.common.ModelBuilder;
 import de.ozgcloud.alfa.common.command.CommandController.CommandByRelationController;
 import de.ozgcloud.alfa.forwarding.Forwarding.Status;
 
@@ -60,20 +59,13 @@ class ForwardingModelAssembler implements RepresentationModelAssembler<Forwardin
 	@Override
 	public EntityModel<Forwarding> toModel(Forwarding entity) {
 		var selfLink = linkTo(ForwardingController.class).slash(entity.getId());
-
-		return ModelBuilder.fromEntity(entity)
-				.addLink(linkTo(ForwardingController.class).slash(entity.getId()).withSelfRel())
-				.ifMatch(IS_SENT)
-				.addLinks(buildMarkAsSuccessLink(entity))
-				.ifMatch(IS_SENT_OR_SUCCESSFULL)
-				.addLinks(buildMarkAsFailLink(entity))
-				.ifMatch(IS_FAILED)
-				.addLink(selfLink.withRel(REL_FAILED))
-				.ifMatch(IS_SUCCESSFULL)
-				.addLink(selfLink.withRel(REL_SUCCESSFULL))
-				.ifMatch(IS_SEND_ERROR)
-				.addLink(selfLink.withRel(REL_ERROR))
-				.buildModel();
+		return EntityModel.of(entity)
+				.add(linkTo(ForwardingController.class).slash(entity.getId()).withSelfRel())
+				.addIf(IS_SENT.test(entity), () -> buildMarkAsSuccessLink(entity))
+				.addIf(IS_SENT_OR_SUCCESSFULL.test(entity), () -> buildMarkAsFailLink(entity))
+				.addIf(IS_FAILED.test(entity), () -> selfLink.withRel(REL_FAILED))
+				.addIf(IS_SUCCESSFULL.test(entity), () -> selfLink.withRel(REL_SUCCESSFULL))
+				.addIf(IS_SEND_ERROR.test(entity), () -> selfLink.withRel(REL_ERROR));
 	}
 
 	public CollectionModel<EntityModel<Forwarding>> toCollectionModel(Stream<Forwarding> entities) {
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/forwarding/ForwardingVorgangWithEingangProcessor.java b/alfa-service/src/main/java/de/ozgcloud/alfa/forwarding/ForwardingVorgangWithEingangProcessor.java
index 60a3c43ef0338e8e7908cc592ddcb3c2fdb7f257..714dc343d3a87d3ea38fa781a544b79121f254f5 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/forwarding/ForwardingVorgangWithEingangProcessor.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/forwarding/ForwardingVorgangWithEingangProcessor.java
@@ -1,3 +1,26 @@
+/*
+ * Copyright (C) 2025 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.forwarding;
 
 import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*;
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/hint/HintModelAssembler.java b/alfa-service/src/main/java/de/ozgcloud/alfa/hint/HintModelAssembler.java
index f7639f549bba1143a6542cc19d3bcb46d98bb0af..ebb2b04267c66642d21158dae6f542155028a5be 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/hint/HintModelAssembler.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/hint/HintModelAssembler.java
@@ -33,8 +33,6 @@ import org.springframework.hateoas.Link;
 import org.springframework.hateoas.server.RepresentationModelAssembler;
 import org.springframework.stereotype.Component;
 
-import de.ozgcloud.alfa.common.ModelBuilder;
-
 @Component
 class HintModelAssembler implements RepresentationModelAssembler<Hint, EntityModel<Hint>> {
 
@@ -44,7 +42,7 @@ class HintModelAssembler implements RepresentationModelAssembler<Hint, EntityMod
 
 	@Override
 	public EntityModel<Hint> toModel(Hint hint) {
-		return ModelBuilder.fromEntity(hint).addLink(buildSelfLink(hint)).buildModel();
+		return EntityModel.of(hint).add(buildSelfLink(hint));
 	}
 
 	private Link buildSelfLink(Hint hint) {
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/hint/HintRootResourceProcessor.java b/alfa-service/src/main/java/de/ozgcloud/alfa/hint/HintRootResourceProcessor.java
index 651e14ef63583ef1e8b89d61bfa0cb4de7f22ba9..27e8c9a4e214adc4213e329e5b98f76e51e76948 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/hint/HintRootResourceProcessor.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/hint/HintRootResourceProcessor.java
@@ -25,27 +25,24 @@ package de.ozgcloud.alfa.hint;
 
 import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*;
 
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.hateoas.EntityModel;
 import org.springframework.hateoas.server.RepresentationModelProcessor;
 import org.springframework.stereotype.Component;
 
 import de.ozgcloud.alfa.Root;
-import de.ozgcloud.alfa.common.ModelBuilder;
+import lombok.RequiredArgsConstructor;
 
 @Component
+@RequiredArgsConstructor
 class HintRootResourceProcessor implements RepresentationModelProcessor<EntityModel<? extends Root>> {
 
 	static final String HINTS_RELATION = "hints";
 
-	@Autowired
-	private HintService service;
+	private final HintService service;
 
 	@Override
 	public EntityModel<? extends Root> process(EntityModel<? extends Root> model) {
-		return ModelBuilder.fromModel(model)
-				.ifMatch(service::hasHints)
-				.addLink(linkTo(HintController.class).withRel(HINTS_RELATION))
-				.buildModel();
+		model.addIf(service.hasHints(), () -> linkTo(HintController.class).withRel(HINTS_RELATION));
+		return model;
 	}
 }
\ No newline at end of file
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/historie/HistorieModelAssembler.java b/alfa-service/src/main/java/de/ozgcloud/alfa/historie/HistorieModelAssembler.java
index a88d362dfe834e164d5b7f5b33396ced8ed230da..1e6a3205439e9499e0714e6353166fd83273166b 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/historie/HistorieModelAssembler.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/historie/HistorieModelAssembler.java
@@ -35,7 +35,6 @@ import org.springframework.hateoas.Link;
 import org.springframework.hateoas.server.RepresentationModelAssembler;
 import org.springframework.stereotype.Component;
 
-import de.ozgcloud.alfa.common.ModelBuilder;
 import de.ozgcloud.alfa.common.command.Command;
 import de.ozgcloud.alfa.common.user.UserManagerUrlProvider;
 import lombok.RequiredArgsConstructor;
@@ -54,11 +53,11 @@ class HistorieModelAssembler implements RepresentationModelAssembler<Command, En
 	@Override
 	public EntityModel<Command> toModel(Command entity) {
 		var cleanCommand = unsetSystemUser(entity);
-		var modelBuilder = ModelBuilder.fromEntity(cleanCommand).addLink(linkTo(HistorieController.class).slash(cleanCommand.getId()).withSelfRel());
+		var model = EntityModel.of(cleanCommand, linkTo(HistorieController.class).slash(cleanCommand.getId()).withSelfRel());
 
-		addAssignedTo(cleanCommand, modelBuilder);
+		addAssignedTo(cleanCommand, model);
 
-		return modelBuilder.buildModel();
+		return model;
 	}
 
 	Command unsetSystemUser(Command entity) {
@@ -73,13 +72,10 @@ class HistorieModelAssembler implements RepresentationModelAssembler<Command, En
 		return Objects.nonNull(entity.getCreatedBy()) && entity.getCreatedBy().toString().startsWith(SYSTEM_USER_PREFIX);
 	}
 
-	private void addAssignedTo(Command entity, ModelBuilder<Command> modelBuilder) {
+	private void addAssignedTo(Command entity, EntityModel<Command> model) {
 		Optional.ofNullable(entity.getBody()).map(body -> body.get(ASSIGNED_TO_BODY_FIELD))
-				.ifPresent(assignedTo -> {
-					if (userManagerUrlProvider.isConfiguredForUserProfile()) {
-						modelBuilder.addLink(Link.of(String.format(userManagerUrlProvider.getUserProfileTemplate(), assignedTo), REL_ASSIGNED_TO));
-					}
-				});
+				.ifPresent(assignedTo -> model.addIf(userManagerUrlProvider.isConfiguredForUserProfile(),
+						() -> Link.of(String.format(userManagerUrlProvider.getUserProfileTemplate(), assignedTo), REL_ASSIGNED_TO)));
 	}
 
 	public CollectionModel<EntityModel<Command>> toCollectionModel(Stream<Command> entities) {
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
index 06eda922582db8ab01d599e3f99db3aeca1ca2ac..5f41da514d5b179168201ad1ab7df4296fea0f16 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/kommentar/KommentarHistorieProcessor.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/kommentar/KommentarHistorieProcessor.java
@@ -1,3 +1,26 @@
+/*
+ * Copyright (C) 2025 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.kommentar;
 
 import java.util.Optional;
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/kommentar/KommentarModelAssembler.java b/alfa-service/src/main/java/de/ozgcloud/alfa/kommentar/KommentarModelAssembler.java
index ed4c3a53428540126bb1e7440fbba411d9b58753..ba9d6df0ae625464e05c3dd9c4fff57905723df0 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/kommentar/KommentarModelAssembler.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/kommentar/KommentarModelAssembler.java
@@ -28,20 +28,19 @@ import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*;
 import java.util.function.Predicate;
 import java.util.stream.Stream;
 
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.hateoas.CollectionModel;
 import org.springframework.hateoas.EntityModel;
 import org.springframework.hateoas.server.RepresentationModelAssembler;
 import org.springframework.stereotype.Component;
 
-import de.ozgcloud.alfa.common.CollectionModelBuilder;
-import de.ozgcloud.alfa.common.ModelBuilder;
 import de.ozgcloud.alfa.common.binaryfile.BinaryFileController;
 import de.ozgcloud.alfa.kommentar.KommentarCommandController.KommentarCommandByVorgangController;
 import de.ozgcloud.alfa.vorgang.VorgangController;
 import de.ozgcloud.alfa.vorgang.VorgangWithEingang;
+import lombok.RequiredArgsConstructor;
 
 @Component
+@RequiredArgsConstructor
 class KommentarModelAssembler implements RepresentationModelAssembler<Kommentar, EntityModel<Kommentar>> {
 
 	static final String REL_CREATE = "create-kommentar";
@@ -51,8 +50,7 @@ class KommentarModelAssembler implements RepresentationModelAssembler<Kommentar,
 
 	private static final Predicate<Kommentar> HAS_ATTACHMENTS = kommentar -> !kommentar.getAttachments().isEmpty();
 
-	@Autowired
-	private VorgangController vorgangController;
+	private final VorgangController vorgangController;
 
 	@Override
 	public EntityModel<Kommentar> toModel(Kommentar kommentar) {
@@ -65,23 +63,19 @@ class KommentarModelAssembler implements RepresentationModelAssembler<Kommentar,
 		var commandLink = linkTo(methodOn(KommentarCommandController.class).editKommentar(null, kommentar.getId(), kommentar.getVersion()));
 		var attachmentsLink = linkTo(methodOn(KommentarController.class).getAttachments(kommentar.getId()));
 
-		return ModelBuilder.fromEntity(kommentar).addLink(selfLink.withSelfRel())
-				.ifMatch(() -> vorgangController.isEditable(vorgang))
-				.addLink(commandLink.withRel(REL_EDIT))
-				.ifMatch(HAS_ATTACHMENTS)
-				.addLink(attachmentsLink.withRel(REL_ATTACHMENTS))
-				.buildModel();
+		return EntityModel.of(kommentar, selfLink.withSelfRel())
+				.addIf(vorgangController.isEditable(vorgang), () -> commandLink.withRel(REL_EDIT))
+				.addIf(HAS_ATTACHMENTS.test(kommentar), () -> attachmentsLink.withRel(REL_ATTACHMENTS));
 	}
 
 	public CollectionModel<EntityModel<Kommentar>> toCollectionModel(Stream<Kommentar> entities, String vorgangId) {
 		var vorgang = vorgangController.getVorgang(vorgangId);
 
-		return CollectionModelBuilder.fromEntities(entities.map(kommentar -> buildModel(kommentar, vorgang)))
-				.addLink(linkTo(KommentarController.class).withSelfRel())
-				.addLink(linkTo(BinaryFileController.class).slash(vorgangId).slash("kommentarAttachment").slash("file").withRel(REL_UPLOAD_FILE))
-				.ifMatch(() -> vorgangController.isEditable(vorgang))
-				.addLink(linkTo(methodOn(KommentarCommandByVorgangController.class).createKommentar(null, vorgangId))
-						.withRel(REL_CREATE))
-				.buildModel();
+		return CollectionModel.of(entities.map(kommentar -> buildModel(kommentar, vorgang)).toList())
+				.add(linkTo(KommentarController.class).withSelfRel())
+				.add(linkTo(BinaryFileController.class).slash(vorgangId).slash("kommentarAttachment").slash("file").withRel(REL_UPLOAD_FILE))
+				.addIf(vorgangController.isEditable(vorgang),
+						() -> linkTo(methodOn(KommentarCommandByVorgangController.class).createKommentar(null, vorgangId))
+								.withRel(REL_CREATE));
 	}
 }
\ No newline at end of file
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungCommandProcessor.java b/alfa-service/src/main/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungCommandProcessor.java
index a1843587039f98039222b661b48b5b2918dd8c5b..d915e9523520305363c1c246fceb0ad4cc4f0b59 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungCommandProcessor.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungCommandProcessor.java
@@ -26,27 +26,25 @@ package de.ozgcloud.alfa.loeschanforderung;
 import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*;
 
 import java.util.Objects;
-import java.util.Optional;
 import java.util.function.Predicate;
 
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.hateoas.EntityModel;
 import org.springframework.hateoas.Link;
 import org.springframework.hateoas.LinkRelation;
 import org.springframework.hateoas.server.RepresentationModelProcessor;
 import org.springframework.stereotype.Component;
 
-import de.ozgcloud.alfa.common.ModelBuilder;
 import de.ozgcloud.alfa.common.attacheditem.VorgangAttachedItem;
 import de.ozgcloud.alfa.common.command.Command;
 import de.ozgcloud.alfa.common.command.CommandHelper;
 import de.ozgcloud.alfa.common.command.CommandOrder;
+import lombok.RequiredArgsConstructor;
 
 @Component
+@RequiredArgsConstructor
 class LoeschAnforderungCommandProcessor implements RepresentationModelProcessor<EntityModel<Command>> {
 
-	@Autowired
-	private LoeschAnforderungService service;
+	private final LoeschAnforderungService service;
 
 	static final LinkRelation REL_REVOKE = LinkRelation.of("revoke");
 
@@ -62,17 +60,17 @@ class LoeschAnforderungCommandProcessor implements RepresentationModelProcessor<
 		if (Objects.isNull(command)) {
 			return model;
 		}
-		return ModelBuilder.fromModel(model)
-				.ifMatch(IS_LOESCHEN_ANFORDERUNG_ZURUECKNEHMEN_AND_REVOKEABLE)
-				.addLink(() -> linkTo(methodOn(LoeschAnforderungCommandController.class).revoke(command.getRelationId(), command.getId(), null))
-						.withRel(REL_REVOKE))
-				.ifMatch(IS_VORGANG_ZUM_LOESCHEN_MARKIEREN_AND_REVOKEABLE)
-				.addLinkIfPresent(() -> buildLink(command))
-				.buildModel();
+		return model
+				.addIf(IS_LOESCHEN_ANFORDERUNG_ZURUECKNEHMEN_AND_REVOKEABLE.test(command),
+						() -> linkTo(methodOn(LoeschAnforderungCommandController.class).revoke(command.getRelationId(), command.getId(), null))
+								.withRel(REL_REVOKE))
+				.addAllIf(IS_VORGANG_ZUM_LOESCHEN_MARKIEREN_AND_REVOKEABLE.test(command),
+						() -> buildLink(command));
 	}
 
-	Optional<Link> buildLink(Command command) {
-		return service.findLoeschAnforderung(command.getVorgangId()).map(loeschAnforderung -> buildLink(loeschAnforderung, command.getId()));
+	Iterable<Link> buildLink(Command command) {
+		return service.findLoeschAnforderung(command.getVorgangId()).map(loeschAnforderung -> buildLink(loeschAnforderung, command.getId())).stream()
+				.toList();
 	}
 
 	Link buildLink(VorgangAttachedItem loeschAnforderung, String commandId) {
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
index 45ecd8907c4844361a93f6f33b031172d2834e95..0554a87af82a57a9a60ad797d1d230f7b3d1f75c 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungHistorieProcessor.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungHistorieProcessor.java
@@ -1,3 +1,26 @@
+/*
+ * Copyright (C) 2025 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.loeschanforderung;
 
 import java.util.HashSet;
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungModelAssembler.java b/alfa-service/src/main/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungModelAssembler.java
index d2b91d808a956a20483ce342da8763de668f9a97..735ad323fc220c34836bafbc007cc0ec6f94752f 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungModelAssembler.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungModelAssembler.java
@@ -25,32 +25,30 @@ package de.ozgcloud.alfa.loeschanforderung;
 
 import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*;
 
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.hateoas.EntityModel;
 import org.springframework.hateoas.LinkRelation;
 import org.springframework.hateoas.server.RepresentationModelAssembler;
 import org.springframework.stereotype.Component;
 
-import de.ozgcloud.alfa.common.ModelBuilder;
+import lombok.RequiredArgsConstructor;
 
 @Component
+@RequiredArgsConstructor
 class LoeschAnforderungModelAssembler implements RepresentationModelAssembler<LoeschAnforderung, EntityModel<LoeschAnforderung>> {
 
 	static final LinkRelation REL_EXECUTE_LOESCHEN = LinkRelation.of("execute_loeschen");
 	static final LinkRelation REL_LOESCH_ANFORDERUNG_ZURUECKNEHMEN = LinkRelation.of("zuruecknehmen");
 
-	@Autowired
-	private LoeschAnforderungService loeschAnforderungService;
+	private final LoeschAnforderungService loeschAnforderungService;
 
 	@Override
 	public EntityModel<LoeschAnforderung> toModel(LoeschAnforderung loeschAnforderung) {
-		return ModelBuilder.fromEntity(loeschAnforderung)
-				.addLink(linkTo(methodOn(LoeschAnforderungController.class).getLoeschanforderung(loeschAnforderung.getId())).withSelfRel())
-				.ifMatch(loeschAnforderungService::isAllowedToVorgangLoeschen)
-				.addLink(linkTo(methodOn(LoeschAnforderungCommandController.class).createCommand(loeschAnforderung.getId(), null)).withRel(
-						REL_EXECUTE_LOESCHEN))
-				.addLink(linkTo(methodOn(LoeschAnforderungCommandController.class).createCommand(loeschAnforderung.getId(), null)).withRel(
-						REL_LOESCH_ANFORDERUNG_ZURUECKNEHMEN))
-				.buildModel();
+		return EntityModel.of(loeschAnforderung)
+				.add(linkTo(methodOn(LoeschAnforderungController.class).getLoeschanforderung(loeschAnforderung.getId())).withSelfRel())
+				.addIf(loeschAnforderungService.isAllowedToVorgangLoeschen(loeschAnforderung),
+						() -> linkTo(methodOn(LoeschAnforderungCommandController.class).createCommand(loeschAnforderung.getId(), null)).withRel(
+								REL_EXECUTE_LOESCHEN))
+				.add(linkTo(methodOn(LoeschAnforderungCommandController.class).createCommand(loeschAnforderung.getId(), null)).withRel(
+						REL_LOESCH_ANFORDERUNG_ZURUECKNEHMEN));
 	}
 }
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungVorgangProcessor.java b/alfa-service/src/main/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungVorgangProcessor.java
index 5281c140049b6c730996d7243ae76b3e0a3ec408..c37a359c0dbc26358097580328c4b295b1eb64b4 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungVorgangProcessor.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungVorgangProcessor.java
@@ -27,7 +27,6 @@ import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*;
 
 import java.util.List;
 import java.util.Objects;
-import java.util.Optional;
 
 import org.springframework.hateoas.EntityModel;
 import org.springframework.hateoas.Link;
@@ -35,7 +34,6 @@ import org.springframework.hateoas.LinkRelation;
 import org.springframework.hateoas.server.RepresentationModelProcessor;
 import org.springframework.stereotype.Component;
 
-import de.ozgcloud.alfa.common.ModelBuilder;
 import de.ozgcloud.alfa.common.attacheditem.VorgangAttachedItem;
 import de.ozgcloud.alfa.common.user.CurrentUserService;
 import de.ozgcloud.alfa.common.user.UserRole;
@@ -68,12 +66,9 @@ class LoeschAnforderungVorgangProcessor implements RepresentationModelProcessor<
 		}
 
 		var vorgangAttachedItem = service.findLoeschAnforderung(vorgang.getId());
-
-		return ModelBuilder.fromModel(model)
-				.ifMatch(this::isLoeschenAnfordernAllowed)
-				.addLink(buildLoschenAnfordernLink(vorgang))
-				.addLink(buildLoschAnforderungLink(vorgangAttachedItem))
-				.buildModel();
+		return model
+				.addIf(isLoeschenAnfordernAllowed(vorgang), () -> buildLoschenAnfordernLink(vorgang))
+				.addIf(vorgangAttachedItem.isPresent(), () -> buildLoschAnforderungLink(vorgangAttachedItem.get()));
 	}
 
 	boolean isLoeschenAnfordernAllowed(Vorgang vorgang) {
@@ -93,8 +88,7 @@ class LoeschAnforderungVorgangProcessor implements RepresentationModelProcessor<
 				.withRel(REL_LOESCHEN_ANFORDERN);
 	}
 
-	private Optional<Link> buildLoschAnforderungLink(Optional<VorgangAttachedItem> vorgangAttachedItem) {
-		return vorgangAttachedItem.map(item -> linkTo(methodOn(LoeschAnforderungController.class).getLoeschanforderung(item.getId()))
-				.withRel(REL_LOESCH_ANFORDERUNG));
+	private Link buildLoschAnforderungLink(VorgangAttachedItem vorgangAttachedItem) {
+		return linkTo(methodOn(LoeschAnforderungController.class).getLoeschanforderung(vorgangAttachedItem.getId())).withRel(REL_LOESCH_ANFORDERUNG);
 	}
 }
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/PostfachMailModelAssembler.java b/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/PostfachMailModelAssembler.java
index 8de875f0fae7795526b3f0b7ec0dd996a2a38d79..d1f3b17742b04f08c6f30d4dac6ef11159425724 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/PostfachMailModelAssembler.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/PostfachMailModelAssembler.java
@@ -39,7 +39,7 @@ import org.springframework.hateoas.mediatype.hal.HalModelBuilder;
 import org.springframework.hateoas.server.RepresentationModelAssembler;
 import org.springframework.stereotype.Component;
 
-import de.ozgcloud.alfa.common.ModelBuilder;
+import de.ozgcloud.alfa.common.LinkedResourceProcessor;
 import de.ozgcloud.alfa.common.binaryfile.BinaryFileController;
 import de.ozgcloud.alfa.common.user.UserManagerUrlProvider;
 import de.ozgcloud.alfa.postfach.PostfachMail.Direction;
@@ -79,6 +79,7 @@ class PostfachMailModelAssembler implements RepresentationModelAssembler<Postfac
 
 	private final UserManagerUrlProvider userManagerUrlProvider;
 	private final VorgangController vorgangController;
+	private final LinkedResourceProcessor<PostfachMail> linkedResourceProcessor;
 
 	public RepresentationModel<EntityModel<PostfachSettings>> toCollectionModel(Stream<PostfachMail> postfachMails, VorgangWithEingang vorgang,
 			PostfachSettings postfachSettings) {
@@ -96,7 +97,7 @@ class PostfachMailModelAssembler implements RepresentationModelAssembler<Postfac
 		return HalModelBuilder
 				.halModelOf(postfachSettings)
 				.link(linkTo(methodOn(PostfachMailController.class).getAll(vorgang.getId())).withSelfRel())
-				.embed(postfachMails.map(this::toModel))
+				.embed(postfachMails.map(this::toModel).map(linkedResourceProcessor::process))
 				.build();
 	}
 
@@ -124,21 +125,20 @@ class PostfachMailModelAssembler implements RepresentationModelAssembler<Postfac
 	public EntityModel<PostfachMail> toModel(PostfachMail postfachMail) {
 		var selfLink = linkTo(PostfachMailController.class).slash(postfachMail.getId());
 
-		return ModelBuilder.fromEntity(postfachMail).addLink(selfLink.withSelfRel())
-				.ifMatch(IS_UNSEND).addLink(linkTo(PostfachMailCommandController.class, postfachMail.getId()).withRel(REL_SEND))
-				.ifMatch(SENT_FAILED)
-				.addLink(linkTo(methodOn(PostfachMailCommandController.class).createCommand(postfachMail.getId(), null))
-						.withRel(REL_RESEND_POSTFACH_MAIL))
-				.ifMatch(IS_UNSEND)
-				.addLink(linkTo(methodOn(PostfachMailCommandController.class).createCommand(postfachMail.getId(), null))
-						.withRel(REL_EDIT))
-				.ifMatch(HAS_ATTACHMENTS)
-				.addLink(linkTo(methodOn(PostfachMailController.class).findAttachments(PostfachNachrichtId.from(postfachMail.getId())))
-						.withRel(REL_ATTACHMENTS))
-				.ifMatch(() -> userManagerUrlProvider.isConfiguredForUserProfile() && SENT_BY_CLIENT_USER.test(postfachMail))
-				.addLink(() -> Link.of(String.format(userManagerUrlProvider.getUserProfileTemplate(), postfachMail.getCreatedBy()),
-						REL_CREATED_BY))
-				.buildModel();
+		return EntityModel.of(postfachMail)
+				.add(selfLink.withSelfRel())
+				.addIf(IS_UNSEND.test(postfachMail),
+						() -> linkTo(PostfachMailCommandController.class, postfachMail.getId()).withRel(REL_SEND))
+				.addIf(SENT_FAILED.test(postfachMail),
+						() -> linkTo(methodOn(PostfachMailCommandController.class).createCommand(postfachMail.getId(), null))
+								.withRel(REL_RESEND_POSTFACH_MAIL))
+				.addIf(IS_UNSEND.test(postfachMail),
+						() -> linkTo(methodOn(PostfachMailCommandController.class).createCommand(postfachMail.getId(), null)).withRel(REL_EDIT))
+				.addIf(HAS_ATTACHMENTS.test(postfachMail),
+						() -> linkTo(methodOn(PostfachMailController.class).findAttachments(PostfachNachrichtId.from(postfachMail.getId())))
+								.withRel(REL_ATTACHMENTS))
+				.addIf(userManagerUrlProvider.isConfiguredForUserProfile() && SENT_BY_CLIENT_USER.test(postfachMail),
+						() -> Link.of(String.format(userManagerUrlProvider.getUserProfileTemplate(), postfachMail.getCreatedBy()), REL_CREATED_BY));
 	}
 
 }
\ No newline at end of file
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
index 6af60c857ed773039bb1f5c86f2e29850e834a7d..0f090911a13892f46f37e6823b178b409c313d0e 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/PostfachNachrichtHistorieProcessor.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/PostfachNachrichtHistorieProcessor.java
@@ -1,3 +1,26 @@
+/*
+ * Copyright (C) 2025 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.postfach;
 
 import java.util.Map;
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/vorgang/VorgangController.java b/alfa-service/src/main/java/de/ozgcloud/alfa/vorgang/VorgangController.java
index 3b6facda1bdca1ad3dd53fa54f250e4df2cbda93..865d83fb59e4bad69534ca0a5ef52a2e686ef193 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/vorgang/VorgangController.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/vorgang/VorgangController.java
@@ -25,8 +25,9 @@ package de.ozgcloud.alfa.vorgang;
 
 import java.util.Optional;
 
+import jakarta.servlet.http.HttpServletResponse;
+
 import org.apache.commons.lang3.StringUtils;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.hateoas.EntityModel;
 import org.springframework.hateoas.RepresentationModel;
 import org.springframework.http.HttpStatus;
@@ -44,10 +45,11 @@ import de.ozgcloud.alfa.common.clientattribute.ClientAttributeService;
 import de.ozgcloud.alfa.common.user.UserId;
 import de.ozgcloud.alfa.statistic.StatisticController;
 import de.ozgcloud.alfa.vorgang.Vorgang.VorgangStatus;
-import jakarta.servlet.http.HttpServletResponse;
+import lombok.RequiredArgsConstructor;
 
 @RestController
 @RequestMapping(VorgangController.PATH)
+@RequiredArgsConstructor
 public class VorgangController {
 
 	static final String PATH = "/api/vorgangs"; // NOSONAR
@@ -62,16 +64,12 @@ public class VorgangController {
 	public static final String PARAM_NEXT_WIEDERVORLAGE_FRIST_EXISTS = "exists";
 	public static final String PARAM_NACHRICHTEN_UNGELESENE = "ungelesene";
 
-	@Autowired
-	private VorgangService vorgangService;
-	@Autowired
-	private VorgangModelAssembler modelAssembler;
+	private final VorgangService vorgangService;
+	private final VorgangModelAssembler modelAssembler;
 
-	@Autowired
-	private ClientAttributeService clientAttributeService;
+	private final ClientAttributeService clientAttributeService;
 
-	@Autowired
-	private StatisticController statisticController;
+	private final StatisticController statisticController;
 
 	@GetMapping(params = { PARAM_PAGE, PARAM_LIMIT })
 	public RepresentationModel<EntityModel<EnhancedVorgang>> getAll(@RequestParam int page, @RequestParam Integer limit) {
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/vorgang/VorgangModelAssembler.java b/alfa-service/src/main/java/de/ozgcloud/alfa/vorgang/VorgangModelAssembler.java
index 47c76b1574946937db404c0342d93411f029cc6d..205bd81da8557af9393258a1c0c62c560c9d1544 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/vorgang/VorgangModelAssembler.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/vorgang/VorgangModelAssembler.java
@@ -37,7 +37,7 @@ import org.springframework.hateoas.server.RepresentationModelAssembler;
 import org.springframework.stereotype.Component;
 import org.springframework.web.util.UriComponentsBuilder;
 
-import de.ozgcloud.alfa.common.ModelBuilder;
+import de.ozgcloud.alfa.common.LinkedResourceProcessor;
 import de.ozgcloud.alfa.common.command.CommandController.CommandByRelationController;
 import de.ozgcloud.alfa.common.user.CurrentUserService;
 import de.ozgcloud.alfa.common.user.UserId;
@@ -58,6 +58,7 @@ class VorgangModelAssembler implements RepresentationModelAssembler<Vorgang, Ent
 
 	private final CurrentUserService userService;
 	private final VorgangService vorgangService;
+	private final LinkedResourceProcessor<Vorgang> linkedResourceProcessor;
 
 	public RepresentationModel<EntityModel<EnhancedVorgang>> toCollectionModel(Stream<VorgangHeader> entities, VorgaengeHeaderResponse response,
 			FindVorgaengeHeaderRequestCriteria requestCriteria, Statistic statistic) {
@@ -72,7 +73,7 @@ class VorgangModelAssembler implements RepresentationModelAssembler<Vorgang, Ent
 	RepresentationModel<EntityModel<EnhancedVorgang>> initModel(Stream<VorgangHeader> entities, Statistic statistic) {
 		return HalModelBuilder.halModelOf(EnhancedVorgang.builder().statistic(statistic).build())
 				.link(linkTo(VorgangController.class).withSelfRel())
-				.embed(entities.map(this::toModel).toList())
+				.embed(entities.map(this::toModel).map(linkedResourceProcessor::process))
 				.build();
 	}
 
@@ -137,13 +138,11 @@ class VorgangModelAssembler implements RepresentationModelAssembler<Vorgang, Ent
 				vorgang.getVersion(), null)).withRel(REL_VORGANG_ASSIGN);
 		var wiedervorlagenLink = linkTo(methodOn(WiedervorlageController.class).findByVorgang(vorgang.getId())).withRel(REL_WIEDERVORLAGEN);
 
-		return ModelBuilder.fromEntity(vorgang)
-				.addLink(selfLinkBuilder.withSelfRel())
-				.addLink(selfLinkBuilder.withRel(REL_VORGANG_MIT_EINGANG))
-				.ifMatch(() -> isAssigneable(vorgang))
-				.addLink(assignLink)
-				.ifMatch(() -> userService.hasRole(UserRole.VERWALTUNG_USER)).addLink(wiedervorlagenLink)
-				.buildModel();
+		return EntityModel.of(vorgang)
+				.add(selfLinkBuilder.withSelfRel())
+				.add(selfLinkBuilder.withRel(REL_VORGANG_MIT_EINGANG))
+				.addIf(isAssigneable(vorgang), () -> (assignLink))
+				.addIf(userService.hasRole(UserRole.VERWALTUNG_USER), () -> wiedervorlagenLink);
 	}
 
 	boolean isAssigneable(Vorgang vorgang) {
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/vorgang/VorgangWithEingangProcessor.java b/alfa-service/src/main/java/de/ozgcloud/alfa/vorgang/VorgangWithEingangProcessor.java
index a5014ff3e7ac1482d61d7c3b6e3b509f744b7fae..e6b7fc75996dc58968bd33cd7dd2431cbcfca61d 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/vorgang/VorgangWithEingangProcessor.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/vorgang/VorgangWithEingangProcessor.java
@@ -37,7 +37,6 @@ import org.springframework.hateoas.server.RepresentationModelProcessor;
 import org.springframework.stereotype.Component;
 
 import de.ozgcloud.alfa.attachment.AttachmentByVorgangController;
-import de.ozgcloud.alfa.common.ModelBuilder;
 import de.ozgcloud.alfa.common.command.CommandController.CommandByRelationController;
 import de.ozgcloud.alfa.common.user.UserManagerUrlProvider;
 import de.ozgcloud.alfa.historie.HistorieController;
@@ -83,29 +82,24 @@ class VorgangWithEingangProcessor implements RepresentationModelProcessor<Entity
 			return model;
 		}
 
-		return ModelBuilder.fromModel(model)
-				.addLink(linkTo(KommentarByVorgangController.class).slash(vorgang.getId()).slash("kommentars").withRel(REL_KOMMENTARE))
-				.ifMatch(HAS_ATTACHMENTS)
-				.addLinks(linkTo(methodOn(AttachmentByVorgangController.class).getAllByVorgang(vorgang.getId()))
-						.withRel(REL_ATTACHMENTS),
-						linkTo(methodOn(AttachmentByVorgangController.class).download(vorgang.getId()))
-								.withRel(REL_DOWNLOAD_ATTACHMENTS))
-				.ifMatch(HAS_REPRESENTATIONS)
-				.addLink(linkTo(methodOn(RepresentationByVorgangController.class).getAll(vorgang.getId()))
-						.withRel(REL_REPRESENTATIONS))
-				.ifMatch(this::isPostfachConfigured)
-				.addLink(linkTo(methodOn(PostfachMailController.class).getAll(vorgang.getId())).withRel(REL_POSTFACH_MAILS))
-				.addLink(linkTo(methodOn(HistorieController.class).getAll(vorgang.getId())).withRel(REL_HISTORIE))
-				.ifMatch(() -> userManagerUrlProvider.isConfiguredForSearchUserProfile() && hasOrganisationsEinheitId(vorgang))
-				.addLink(this::buildSearchUserProfilesLink)
-				.ifMatch(this::isProcessable)
-				.addLink(
+		return model
+				.add(linkTo(KommentarByVorgangController.class).slash(vorgang.getId()).slash("kommentars").withRel(REL_KOMMENTARE))
+				.addAllIf(HAS_ATTACHMENTS.test(vorgang), () -> List.of(
+						linkTo(methodOn(AttachmentByVorgangController.class).getAllByVorgang(vorgang.getId())).withRel(REL_ATTACHMENTS),
+						linkTo(methodOn(AttachmentByVorgangController.class).download(vorgang.getId())).withRel(REL_DOWNLOAD_ATTACHMENTS)))
+				.addIf(HAS_REPRESENTATIONS.test(vorgang),
+						() -> linkTo(methodOn(RepresentationByVorgangController.class).getAll(vorgang.getId())).withRel(REL_REPRESENTATIONS))
+				.addIf(isPostfachConfigured(),
+						() -> linkTo(methodOn(PostfachMailController.class).getAll(vorgang.getId())).withRel(REL_POSTFACH_MAILS))
+				.add(linkTo(methodOn(HistorieController.class).getAll(vorgang.getId())).withRel(REL_HISTORIE))
+				.addIf(userManagerUrlProvider.isConfiguredForSearchUserProfile() && hasOrganisationsEinheitId(vorgang),
+						() -> buildSearchUserProfilesLink(vorgang))
+				.addIf(isProcessable(vorgang),
 						() -> linkTo(methodOn(CommandByRelationController.class).createCommand(vorgang.getId(), vorgang.getId(), vorgang.getVersion(),
-								null)).withRel(REL_PROCESS_VORGANG))
-				.buildModel();
+								null)).withRel(REL_PROCESS_VORGANG));
 	}
 
-	private boolean isPostfachConfigured(VorgangWithEingang vorgang) {
+	private boolean isPostfachConfigured() {
 		return postfachMailController.isPostfachConfigured();
 	}
 
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/vorgang/command/VorgangWithEingangCommandProcessor.java b/alfa-service/src/main/java/de/ozgcloud/alfa/vorgang/command/VorgangWithEingangCommandProcessor.java
index 2c2453560d8651d92c72673e29d17f6d75ce75c3..34de66b87575d17ed2aa13ce1aa43378f4ef9576 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/vorgang/command/VorgangWithEingangCommandProcessor.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/vorgang/command/VorgangWithEingangCommandProcessor.java
@@ -27,13 +27,11 @@ import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*;
 
 import java.util.Objects;
 
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.hateoas.EntityModel;
 import org.springframework.hateoas.LinkRelation;
 import org.springframework.hateoas.server.RepresentationModelProcessor;
 import org.springframework.stereotype.Component;
 
-import de.ozgcloud.alfa.common.ModelBuilder;
 import de.ozgcloud.alfa.common.command.CommandController;
 import de.ozgcloud.alfa.common.command.CommandController.CommandByRelationController;
 import de.ozgcloud.alfa.common.user.CurrentUserService;
@@ -41,19 +39,18 @@ import de.ozgcloud.alfa.common.user.UserRole;
 import de.ozgcloud.alfa.forwarding.ForwardingController;
 import de.ozgcloud.alfa.vorgang.Vorgang.VorgangStatus;
 import de.ozgcloud.alfa.vorgang.VorgangWithEingang;
+import lombok.RequiredArgsConstructor;
 
 @Component
+@RequiredArgsConstructor
 public class VorgangWithEingangCommandProcessor implements RepresentationModelProcessor<EntityModel<VorgangWithEingang>> {
 
 	static final LinkRelation REL_VORGANG_FORWARD = LinkRelation.of("forward");
 	static final LinkRelation REL_PENDING_COMMANDS = LinkRelation.of("pending-commands");
 
-	@Autowired
-	private CurrentUserService userService;
-	@Autowired
-	private ForwardingController forwardingController;
-	@Autowired
-	private CommandController commandController;
+	private final CurrentUserService userService;
+	private final ForwardingController forwardingController;
+	private final CommandController commandController;
 
 	@Override
 	public EntityModel<VorgangWithEingang> process(EntityModel<VorgangWithEingang> model) {
@@ -61,14 +58,12 @@ public class VorgangWithEingangCommandProcessor implements RepresentationModelPr
 		if (Objects.isNull(vorgang)) {
 			return model;
 		}
-		return ModelBuilder.fromModel(model)
-				.ifMatch(this::isForwardingAllowed)
-				.addLink(linkTo(
+		return model
+				.addIf(isForwardingAllowed(vorgang), () -> linkTo(
 						methodOn(CommandByRelationController.class).createCommand(vorgang.getId(), vorgang.getId(), vorgang.getVersion(),
 								null)).withRel(REL_VORGANG_FORWARD))
-				.ifMatch(this::existsPendingCommands)
-				.addLink(linkTo(methodOn(CommandController.class).getPendingCommands(true, vorgang.getId())).withRel(REL_PENDING_COMMANDS))
-				.buildModel();
+				.addIf(existsPendingCommands(vorgang),
+						() -> linkTo(methodOn(CommandController.class).getPendingCommands(true, vorgang.getId())).withRel(REL_PENDING_COMMANDS));
 	}
 
 	boolean isForwardingAllowed(VorgangWithEingang vorgang) {
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
index 352b53f04707694244b3eef02d1062a70e8ad52c..2953cad663b5c6a5959bd62443dc9676d32833a9 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageHistorieProcessor.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageHistorieProcessor.java
@@ -1,3 +1,26 @@
+/*
+ * Copyright (C) 2025 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.wiedervorlage;
 
 import java.util.Map;
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageModelAssembler.java b/alfa-service/src/main/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageModelAssembler.java
index 2a94ca0fcd0a618ed77ae80988c4b61821489e70..a058e87ad7db22dd950b33f457622948180ca80c 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageModelAssembler.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageModelAssembler.java
@@ -28,21 +28,20 @@ import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*;
 import java.util.function.Predicate;
 import java.util.stream.Stream;
 
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.hateoas.CollectionModel;
 import org.springframework.hateoas.EntityModel;
 import org.springframework.hateoas.server.RepresentationModelAssembler;
 import org.springframework.stereotype.Component;
 
-import de.ozgcloud.alfa.common.CollectionModelBuilder;
-import de.ozgcloud.alfa.common.ModelBuilder;
 import de.ozgcloud.alfa.common.binaryfile.BinaryFileController;
 import de.ozgcloud.alfa.vorgang.VorgangController;
 import de.ozgcloud.alfa.vorgang.VorgangWithEingang;
 import de.ozgcloud.alfa.wiedervorlage.WiedervorlageCommandController.WiedervorlageCommandByVorgangController;
 import de.ozgcloud.alfa.wiedervorlage.WiedervorlageController.AttachmentsByWiedervorlageController;
+import lombok.RequiredArgsConstructor;
 
 @Component
+@RequiredArgsConstructor
 class WiedervorlageModelAssembler implements RepresentationModelAssembler<Wiedervorlage, EntityModel<Wiedervorlage>> {
 
 	static final String REL_EDIT = "edit";
@@ -59,8 +58,7 @@ class WiedervorlageModelAssembler implements RepresentationModelAssembler<Wieder
 	public static final String WIEDERVORLAGE_ATTACHMENT_PATH = "wiedervorlageAttachment";
 	public static final String FILE_PATH = "file";
 
-	@Autowired
-	private VorgangController vorgangController;
+	private final VorgangController vorgangController;
 
 	@Override
 	public EntityModel<Wiedervorlage> toModel(Wiedervorlage wiedervorlage) {
@@ -73,26 +71,24 @@ class WiedervorlageModelAssembler implements RepresentationModelAssembler<Wieder
 		var commandLink = linkTo(
 				methodOn(WiedervorlageCommandController.class).updateWiedervorlage(null, wiedervorlage.getId(), wiedervorlage.getVersion()));
 
-		return ModelBuilder.fromEntity(wiedervorlage).addLink(selfLink.withSelfRel())
-				.ifMatch(() -> vorgangController.isEditable(vorgang))
-				.addLink(commandLink.withRel(REL_EDIT))
-				.ifMatch(ALLOW_ERLEDIGEN).addLink(commandLink.withRel(REL_ERLEDIGEN))
-				.ifMatch(ALLOW_WIEDEREROEFFNEN).addLink(commandLink.withRel(REL_WIEDEREROEFFNEN))
-				.ifMatch(HAS_ATTACHMENTS)
-				.addLink(linkTo(methodOn(AttachmentsByWiedervorlageController.class).getAttachments(wiedervorlage.getId())).withRel(REL_ATTACHMENTS))
-				.buildModel();
+		return EntityModel.of(wiedervorlage)
+				.add(selfLink.withSelfRel())
+				.addIf(vorgangController.isEditable(vorgang), () -> commandLink.withRel(REL_EDIT))
+				.addIf(ALLOW_ERLEDIGEN.test(wiedervorlage), () -> commandLink.withRel(REL_ERLEDIGEN))
+				.addIf(ALLOW_WIEDEREROEFFNEN.test(wiedervorlage), () -> commandLink.withRel(REL_WIEDEREROEFFNEN))
+				.addIf(HAS_ATTACHMENTS.test(wiedervorlage),
+						() -> linkTo(methodOn(AttachmentsByWiedervorlageController.class).getAttachments(wiedervorlage.getId()))
+								.withRel(REL_ATTACHMENTS));
 	}
 
 	public CollectionModel<EntityModel<Wiedervorlage>> toCollectionModel(Stream<Wiedervorlage> entities, String vorgangId) {
 		var vorgang = vorgangController.getVorgang(vorgangId);
-
-		return CollectionModelBuilder.fromEntities(entities.map(wiedervorlage -> buildModel(wiedervorlage, vorgang)))
-				.addLink(linkTo(WiedervorlageController.class).withSelfRel())
-				.ifMatch(wiedervorlagenModel -> vorgangController.isEditable(vorgang))
-				.addLink(linkTo(methodOn(WiedervorlageCommandByVorgangController.class).createWiedervorlage(null, vorgangId))
-						.withRel(REL_CREATE))
-				.addLink(linkTo(BinaryFileController.class).slash(vorgangId).slash(WIEDERVORLAGE_ATTACHMENT_PATH).slash(FILE_PATH)
+		return CollectionModel.of(entities.map(wiedervorlage -> buildModel(wiedervorlage, vorgang)).toList())
+				.add(linkTo(WiedervorlageController.class).withSelfRel())
+				.add(linkTo(BinaryFileController.class).slash(vorgangId).slash(WIEDERVORLAGE_ATTACHMENT_PATH).slash(FILE_PATH)
 						.withRel(REL_UPLOAD_FILE))
-				.buildModel();
+				.addIf(vorgangController.isEditable(vorgang),
+						() -> linkTo(methodOn(WiedervorlageCommandByVorgangController.class).createWiedervorlage(null, vorgangId))
+								.withRel(REL_CREATE));
 	}
 }
\ No newline at end of file
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/RootViewLinkHandlerTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/RootViewLinkHandlerTest.java
index c626a7ad29a639313e4d30a6c07bb59ea223112f..6f0e2b655828b4283ba6947fbc81dedeb0783ffd 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/RootViewLinkHandlerTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/RootViewLinkHandlerTest.java
@@ -39,12 +39,12 @@ import org.junit.jupiter.params.provider.EnumSource.Mode;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.Spy;
+import org.springframework.hateoas.EntityModel;
 import org.springframework.hateoas.Link;
 import org.springframework.hateoas.LinkRelation;
 
 import com.thedeanda.lorem.LoremIpsum;
 
-import de.ozgcloud.alfa.common.ModelBuilder;
 import de.ozgcloud.alfa.common.user.CurrentUserService;
 import de.ozgcloud.alfa.common.user.UserId;
 import de.ozgcloud.alfa.common.user.UserProfileTestFactory;
@@ -66,36 +66,37 @@ class RootViewLinkHandlerTest {
 	@Nested
 	class TestAddViewLinks {
 
-		@Mock
-		private Root rootResource;
+		private Root rootResource = RootTestFactory.create();
 
 		private Optional<UserId> emptyUserId = Optional.empty();
 
 		@Test
 		void shouldAddVorgaengeAllLink() {
-			var modelBuilder = ModelBuilder.fromEntity(rootResource);
-			viewLinkHandler.addViewLinks(modelBuilder, emptyUserId);
+			var model = EntityModel.of(rootResource);
 
-			assertThat(modelBuilder.buildModel().getLink(RootViewLinkHandler.ALL_VORGAENGE_REL))
+			viewLinkHandler.addViewLinks(model, emptyUserId);
+
+			assertThat(model.getLink(RootViewLinkHandler.ALL_VORGAENGE_REL))
 					.get().extracting(Link::getHref).isEqualTo("/api/vorgangs?page=0&limit=100");
 		}
 
 		@Test
 		void shouldCallAddSearchAllVorgaengeLink() {
-			var modelBuilder = ModelBuilder.fromEntity(rootResource);
-			viewLinkHandler.addViewLinks(modelBuilder, emptyUserId);
+			var model = EntityModel.of(rootResource);
+
+			viewLinkHandler.addViewLinks(model, emptyUserId);
 
-			verify(viewLinkHandler).addSearchAllVorgaengeLink(modelBuilder);
+			verify(viewLinkHandler).addSearchAllVorgaengeLink(model);
 		}
 
 		@Test
 		void shouldAddLinksForVerwaltungPoststelle() {
 			when(currentUserService.hasRole(UserRole.VERWALTUNG_POSTSTELLE)).thenReturn(true);
 
-			var modelBuilder = ModelBuilder.fromEntity(rootResource);
-			viewLinkHandler.addViewLinks(modelBuilder, emptyUserId);
+			var model = EntityModel.of(rootResource);
+			viewLinkHandler.addViewLinks(model, emptyUserId);
 
-			verify(viewLinkHandler).addViewLinksForVerwaltungPoststelle(modelBuilder, emptyUserId);
+			verify(viewLinkHandler).addViewLinksForVerwaltungPoststelle(model, emptyUserId);
 		}
 
 		@Test
@@ -103,21 +104,21 @@ class RootViewLinkHandlerTest {
 			when(currentUserService.hasRole(UserRole.VERWALTUNG_POSTSTELLE)).thenReturn(false);
 			when(currentUserService.hasRole(UserRole.VERWALTUNG_USER)).thenReturn(true);
 
-			var modelBuilder = ModelBuilder.fromEntity(rootResource);
-			viewLinkHandler.addViewLinks(modelBuilder, emptyUserId);
+			var model = EntityModel.of(rootResource);
+			viewLinkHandler.addViewLinks(model, emptyUserId);
 
-			verify(viewLinkHandler).addViewLinksForVerwaltungUser(modelBuilder, emptyUserId);
+			verify(viewLinkHandler).addViewLinksForVerwaltungUser(model, emptyUserId);
 		}
 
 		@DisplayName("for " + UserRole.VERWALTUNG_POSTSTELLE)
 		@Nested
 		class TestVerwaltungPoststelle {
 
-			private final ModelBuilder<Root> modelBuilder = ModelBuilder.fromEntity(rootResource);
+			private final EntityModel<Root> model = EntityModel.of(rootResource);
 
 			@Test
 			void shouldCallBuildMyVorgaengeLink() {
-				viewLinkHandler.addViewLinksForVerwaltungPoststelle(modelBuilder, Optional.of(UserProfileTestFactory.ID));
+				viewLinkHandler.addViewLinksForVerwaltungPoststelle(model, Optional.of(UserProfileTestFactory.ID));
 
 				verify(viewLinkHandler).buildMyVorgaengeLink(UserProfileTestFactory.ID);
 			}
@@ -134,7 +135,7 @@ class RootViewLinkHandlerTest {
 					void shouldCallBuildSearchMyVorgaengeLink() {
 						when(systemStatusService.isSearchServerAvailable()).thenReturn(true);
 
-						viewLinkHandler.addViewLinksForVerwaltungPoststelle(modelBuilder, Optional.of(UserProfileTestFactory.ID));
+						viewLinkHandler.addViewLinksForVerwaltungPoststelle(model, Optional.of(UserProfileTestFactory.ID));
 
 						verify(viewLinkHandler).buildSearchMyVorgaengeLink(UserProfileTestFactory.ID);
 					}
@@ -148,7 +149,7 @@ class RootViewLinkHandlerTest {
 					void shouldNotCallBuildSearchMyVorgaengeLink() {
 						when(systemStatusService.isSearchServerAvailable()).thenReturn(false);
 
-						viewLinkHandler.addViewLinksForVerwaltungPoststelle(modelBuilder, Optional.of(UserProfileTestFactory.ID));
+						viewLinkHandler.addViewLinksForVerwaltungPoststelle(model, Optional.of(UserProfileTestFactory.ID));
 
 						verify(viewLinkHandler, never()).buildSearchMyVorgaengeLink(any());
 					}
@@ -160,18 +161,18 @@ class RootViewLinkHandlerTest {
 		@Nested
 		class TestVerwaltungUser {
 
-			private final ModelBuilder<Root> modelBuilder = ModelBuilder.fromEntity(rootResource);
+			private final EntityModel<Root> model = EntityModel.of(rootResource);
 
 			@Test
 			void shouldCallAddUnassignedVorgaengeLink() {
-				viewLinkHandler.addViewLinksForVerwaltungUser(modelBuilder, Optional.of(UserProfileTestFactory.ID));
+				viewLinkHandler.addViewLinksForVerwaltungUser(model, Optional.of(UserProfileTestFactory.ID));
 
 				verify(viewLinkHandler).buildGetAllUnassignedVorgaengeLink();
 			}
 
 			@Test
 			void shouldCallAddMyVorgaengeLink() {
-				viewLinkHandler.addViewLinksForVerwaltungUser(modelBuilder, Optional.of(UserProfileTestFactory.ID));
+				viewLinkHandler.addViewLinksForVerwaltungUser(model, Optional.of(UserProfileTestFactory.ID));
 
 				verify(viewLinkHandler).buildMyVorgaengeLink(UserProfileTestFactory.ID);
 			}
@@ -188,7 +189,7 @@ class RootViewLinkHandlerTest {
 					void shouldCallBuildSearchMyVorgaengeLink() {
 						when(systemStatusService.isSearchServerAvailable()).thenReturn(true);
 
-						viewLinkHandler.addViewLinksForVerwaltungUser(modelBuilder, Optional.of(UserProfileTestFactory.ID));
+						viewLinkHandler.addViewLinksForVerwaltungUser(model, Optional.of(UserProfileTestFactory.ID));
 
 						verify(viewLinkHandler).buildSearchMyVorgaengeLink(UserProfileTestFactory.ID);
 					}
@@ -202,7 +203,7 @@ class RootViewLinkHandlerTest {
 					void shouldNotCallBuildSearchMyVorgaengeLink() {
 						when(systemStatusService.isSearchServerAvailable()).thenReturn(false);
 
-						viewLinkHandler.addViewLinksForVerwaltungUser(modelBuilder, Optional.of(UserProfileTestFactory.ID));
+						viewLinkHandler.addViewLinksForVerwaltungUser(model, Optional.of(UserProfileTestFactory.ID));
 
 						verify(viewLinkHandler, never()).buildSearchMyVorgaengeLink(any());
 					}
@@ -211,21 +212,21 @@ class RootViewLinkHandlerTest {
 
 			@Test
 			void shouldCallAddVorgangStatusLinks() {
-				viewLinkHandler.addViewLinksForVerwaltungUser(modelBuilder, Optional.of(UserProfileTestFactory.ID));
+				viewLinkHandler.addViewLinksForVerwaltungUser(model, Optional.of(UserProfileTestFactory.ID));
 
-				verify(viewLinkHandler).addAllVorgangStatusLinks(modelBuilder);
+				verify(viewLinkHandler).addAllVorgangStatusLinks(model);
 			}
 
 			@Test
 			void shouldCallAddMyVorgaengeStatusLinks() {
-				viewLinkHandler.addViewLinksForVerwaltungUser(modelBuilder, Optional.of(UserProfileTestFactory.ID));
+				viewLinkHandler.addViewLinksForVerwaltungUser(model, Optional.of(UserProfileTestFactory.ID));
 
 				verify(viewLinkHandler).buildMyVorgaengeStatusLinks(UserProfileTestFactory.ID);
 			}
 
 			@Test
 			void shouldCallAddUnassignedVorgaengeStatusLinks() {
-				viewLinkHandler.addViewLinksForVerwaltungUser(modelBuilder, Optional.of(UserProfileTestFactory.ID));
+				viewLinkHandler.addViewLinksForVerwaltungUser(model, Optional.of(UserProfileTestFactory.ID));
 
 				verify(viewLinkHandler).buildUnassignedVorgaengeStatusLinks();
 			}
@@ -242,7 +243,7 @@ class RootViewLinkHandlerTest {
 					void shouldCallBuildSearchUnassignedVorgaengeLink() {
 						when(systemStatusService.isSearchServerAvailable()).thenReturn(true);
 
-						viewLinkHandler.addViewLinksForVerwaltungUser(modelBuilder, Optional.of(UserProfileTestFactory.ID));
+						viewLinkHandler.addViewLinksForVerwaltungUser(model, Optional.of(UserProfileTestFactory.ID));
 
 						verify(viewLinkHandler).buildSearchUnassignedVorgaengeLink();
 					}
@@ -256,7 +257,7 @@ class RootViewLinkHandlerTest {
 					void shouldNotCallBuildSearchUnassignedVorgaengeLink() {
 						when(systemStatusService.isSearchServerAvailable()).thenReturn(false);
 
-						viewLinkHandler.addViewLinksForVerwaltungUser(modelBuilder, Optional.of(UserProfileTestFactory.ID));
+						viewLinkHandler.addViewLinksForVerwaltungUser(model, Optional.of(UserProfileTestFactory.ID));
 
 						verify(viewLinkHandler, never()).buildSearchUnassignedVorgaengeLink();
 					}
@@ -269,10 +270,10 @@ class RootViewLinkHandlerTest {
 
 				@Test
 				void shouldAddAllLink() {
-					var modelBuilder = ModelBuilder.fromEntity(rootResource);
-					viewLinkHandler.addViewLinksForVerwaltungUser(modelBuilder, Optional.of(UserProfileTestFactory.ID));
+					var model = EntityModel.of(rootResource);
+					viewLinkHandler.addViewLinksForVerwaltungUser(model, Optional.of(UserProfileTestFactory.ID));
 
-					assertThat(modelBuilder.buildModel().getLink(RootViewLinkHandler.ALL_WIEDERVORLAGEN_REL))
+					assertThat(model.getLink(RootViewLinkHandler.ALL_WIEDERVORLAGEN_REL))
 							.get().extracting(Link::getHref).isEqualTo("/api/vorgangs?page=0&limit=100&nextFrist=exists");
 				}
 
@@ -282,38 +283,38 @@ class RootViewLinkHandlerTest {
 
 					@Test
 					void shouldAddAssignedLinkIfExists() {
-						var modelBuilder = ModelBuilder.fromEntity(rootResource);
-						viewLinkHandler.addViewLinksForVerwaltungUser(modelBuilder, Optional.of(UserProfileTestFactory.ID));
+						var model = EntityModel.of(rootResource);
+						viewLinkHandler.addViewLinksForVerwaltungUser(model, Optional.of(UserProfileTestFactory.ID));
 
-						assertThat(modelBuilder.buildModel().getLink(RootViewLinkHandler.MY_WIEDERVORLAGEN_REL))
+						assertThat(model.getLink(RootViewLinkHandler.MY_WIEDERVORLAGEN_REL))
 								.get().extracting(Link::getHref)
 								.isEqualTo("/api/vorgangs?page=0&limit=100&assignedTo=" + UserProfileTestFactory.ID + "&nextFrist=exists");
 					}
 
 					@Test
 					void shoulNotAddAssignedLinkIfNotExists() {
-						var modelBuilder = ModelBuilder.fromEntity(rootResource);
-						viewLinkHandler.addViewLinksForVerwaltungUser(modelBuilder, Optional.empty());
+						var model = EntityModel.of(rootResource);
+						viewLinkHandler.addViewLinksForVerwaltungUser(model, Optional.empty());
 
-						assertThat(modelBuilder.buildModel().getLink(RootViewLinkHandler.MY_WIEDERVORLAGEN_REL)).isNotPresent();
+						assertThat(model.getLink(RootViewLinkHandler.MY_WIEDERVORLAGEN_REL)).isNotPresent();
 					}
 				}
 
 				@Test
 				void shouldAddUnassignedLink() {
-					var modelBuilder = ModelBuilder.fromEntity(rootResource);
-					viewLinkHandler.addViewLinksForVerwaltungUser(modelBuilder, Optional.of(UserProfileTestFactory.ID));
+					var model = EntityModel.of(rootResource);
+					viewLinkHandler.addViewLinksForVerwaltungUser(model, Optional.of(UserProfileTestFactory.ID));
 
-					assertThat(modelBuilder.buildModel().getLink(RootViewLinkHandler.UNASSIGNED_WIEDERVORLAGEN_REL))
+					assertThat(model.getLink(RootViewLinkHandler.UNASSIGNED_WIEDERVORLAGEN_REL))
 							.get().extracting(Link::getHref).isEqualTo("/api/vorgangs?page=0&limit=100&assignedTo=&nextFrist=exists");
 				}
 			}
 
 			@Test
 			void shouldAddLinksForUngeleseneNachrichten() {
-				viewLinkHandler.addViewLinksForVerwaltungUser(modelBuilder, Optional.of(UserProfileTestFactory.ID));
+				viewLinkHandler.addViewLinksForVerwaltungUser(model, Optional.of(UserProfileTestFactory.ID));
 
-				verify(viewLinkHandler).addGetByUngeleseneNachrichtenLinks(modelBuilder, Optional.of(UserProfileTestFactory.ID));
+				verify(viewLinkHandler).addGetByUngeleseneNachrichtenLinks(model, Optional.of(UserProfileTestFactory.ID));
 			}
 		}
 
@@ -325,10 +326,10 @@ class RootViewLinkHandlerTest {
 			void shouldBeAddedIfSearchServerIsAvailable() {
 				when(systemStatusService.isSearchServerAvailable()).thenReturn(true);
 
-				var modelBuilder = ModelBuilder.fromEntity(rootResource);
-				viewLinkHandler.addSearchAllVorgaengeLink(modelBuilder);
+				var model = EntityModel.of(rootResource);
+				viewLinkHandler.addSearchAllVorgaengeLink(model);
 
-				assertThat(modelBuilder.buildModel().getLink(RootViewLinkHandler.SEARCH_ALL_REL))
+				assertThat(model.getLink(RootViewLinkHandler.SEARCH_ALL_REL))
 						.get().extracting(Link::getHref).isEqualTo("/api/vorgangs?page=0&limit=100&searchBy={searchBy}");
 			}
 
@@ -336,10 +337,10 @@ class RootViewLinkHandlerTest {
 			void shouldNotBeAddedIfSearchServerIsUnavailable() {
 				when(systemStatusService.isSearchServerAvailable()).thenReturn(false);
 
-				var modelBuilder = spy(ModelBuilder.fromEntity(rootResource));
-				viewLinkHandler.addSearchAllVorgaengeLink(modelBuilder);
+				var model = spy(EntityModel.of(rootResource));
+				viewLinkHandler.addSearchAllVorgaengeLink(model);
 
-				verify(modelBuilder, never()).addLink(any(Link.class));
+				verify(model, never()).add(any(Link.class));
 			}
 		}
 
@@ -404,13 +405,13 @@ class RootViewLinkHandlerTest {
 		@Nested
 		class TestAddAllVorgangStatusLinks {
 
-			private final ModelBuilder<Root> modelBuilder = ModelBuilder.fromEntity(rootResource);
+			private final EntityModel<Root> model = EntityModel.of(rootResource);
 
 			@Test
 			void shouldCallAddVorgangStatusLinks() {
-				viewLinkHandler.addAllVorgangStatusLinks(modelBuilder);
+				viewLinkHandler.addAllVorgangStatusLinks(model);
 
-				verify(viewLinkHandler).addVorgangStatusLinks(modelBuilder, RootViewLinkHandler.VORGAENGE_ALL_REL_TEMPLATE);
+				verify(viewLinkHandler).addVorgangStatusLinks(model, RootViewLinkHandler.VORGAENGE_ALL_REL_TEMPLATE);
 			}
 		}
 
@@ -619,9 +620,8 @@ class RootViewLinkHandlerTest {
 	@Nested
 	class TestAddGetByUngeleseneNachrichtenLinks {
 
-		@Mock
-		private Root rootResource;
-		private final ModelBuilder<Root> modelBuilder = ModelBuilder.fromEntity(rootResource);
+		private Root rootResource = RootTestFactory.create();
+		private final EntityModel<Root> model = EntityModel.of(rootResource);
 		private final Link linkAllUngeleseneNachrichten = Link.of(LoremIpsum.getInstance().getUrl());
 		private final Link linkMyUngeleseneNachrichten = Link.of(LoremIpsum.getInstance().getUrl());
 		private final Link linkUnassignedUngeleseneNachrichten = Link.of(LoremIpsum.getInstance().getUrl());
@@ -635,23 +635,23 @@ class RootViewLinkHandlerTest {
 
 		@Test
 		void shouldBuildLinkForUngeleseneNachrichten() {
-			viewLinkHandler.addGetByUngeleseneNachrichtenLinks(modelBuilder, Optional.of(UserProfileTestFactory.ID));
+			viewLinkHandler.addGetByUngeleseneNachrichtenLinks(model, Optional.of(UserProfileTestFactory.ID));
 
 			verify(viewLinkHandler).buildGelAllByUngeleseneNachrichtenLink();
 		}
 
 		@Test
 		void shouldAddLinkForUngeleseneNachrichten() {
-			var modelBuilder = ModelBuilder.fromEntity(rootResource);
+			var model = EntityModel.of(rootResource);
 
-			viewLinkHandler.addGetByUngeleseneNachrichtenLinks(modelBuilder, Optional.of(UserProfileTestFactory.ID));
+			viewLinkHandler.addGetByUngeleseneNachrichtenLinks(model, Optional.of(UserProfileTestFactory.ID));
 
-			assertThat(modelBuilder.buildModel().getLinks()).contains(linkAllUngeleseneNachrichten);
+			assertThat(model.getLinks()).contains(linkAllUngeleseneNachrichten);
 		}
 
 		@Test
 		void shouldBuildLinkForUnassignedUngeleseneNachrichten() {
-			viewLinkHandler.addGetByUngeleseneNachrichtenLinks(modelBuilder, Optional.empty());
+			viewLinkHandler.addGetByUngeleseneNachrichtenLinks(model, Optional.empty());
 
 			verify(viewLinkHandler).buildGetAllByAssignedToAndUngeleseneNachrichten(UserId.empty(),
 					RootViewLinkHandler.UNASSIGNED_UNGELESENE_NACHRICHTEN_REL);
@@ -659,11 +659,11 @@ class RootViewLinkHandlerTest {
 
 		@Test
 		void shouldAddLinkForUnassignedUngeleseneNachrichten() {
-			var modelBuilder = ModelBuilder.fromEntity(rootResource);
+			var model = EntityModel.of(rootResource);
 
-			viewLinkHandler.addGetByUngeleseneNachrichtenLinks(modelBuilder, Optional.empty());
+			viewLinkHandler.addGetByUngeleseneNachrichtenLinks(model, Optional.empty());
 
-			assertThat(modelBuilder.buildModel().getLinks()).contains(linkUnassignedUngeleseneNachrichten);
+			assertThat(model.getLinks()).contains(linkUnassignedUngeleseneNachrichten);
 		}
 
 		@Nested
@@ -677,7 +677,7 @@ class RootViewLinkHandlerTest {
 
 			@Test
 			void shouldBuildLinkForMyUngeleseneNachrichten() {
-				viewLinkHandler.addGetByUngeleseneNachrichtenLinks(modelBuilder, Optional.of(UserProfileTestFactory.ID));
+				viewLinkHandler.addGetByUngeleseneNachrichtenLinks(model, Optional.of(UserProfileTestFactory.ID));
 
 				verify(viewLinkHandler).buildGetAllByAssignedToAndUngeleseneNachrichten(UserProfileTestFactory.ID,
 						RootViewLinkHandler.MY_UNGELESENE_NACHRICHTEN_REL);
@@ -685,11 +685,11 @@ class RootViewLinkHandlerTest {
 
 			@Test
 			void shouldAddLinkForMyUngeleseneNachrichten() {
-				var modelBuilder = ModelBuilder.fromEntity(rootResource);
+				var model = EntityModel.of(rootResource);
 
-				viewLinkHandler.addGetByUngeleseneNachrichtenLinks(modelBuilder, Optional.of(UserProfileTestFactory.ID));
+				viewLinkHandler.addGetByUngeleseneNachrichtenLinks(model, Optional.of(UserProfileTestFactory.ID));
 
-				assertThat(modelBuilder.buildModel().getLinks()).contains(linkMyUngeleseneNachrichten);
+				assertThat(model.getLinks()).contains(linkMyUngeleseneNachrichten);
 			}
 		}
 
@@ -698,7 +698,7 @@ class RootViewLinkHandlerTest {
 
 			@Test
 			void shouldNotBuildLinkForMyUngeleseneNachrichten() {
-				viewLinkHandler.addGetByUngeleseneNachrichtenLinks(modelBuilder, Optional.empty());
+				viewLinkHandler.addGetByUngeleseneNachrichtenLinks(model, Optional.empty());
 
 				verify(viewLinkHandler, never()).buildGetAllByAssignedToAndUngeleseneNachrichten(UserProfileTestFactory.ID,
 						RootViewLinkHandler.MY_UNGELESENE_NACHRICHTEN_REL);
@@ -706,40 +706,4 @@ class RootViewLinkHandlerTest {
 		}
 
 	}
-
-	//	@DisplayName("Test user assistance documentation link")
-	//	@Nested
-	//	class TestDocumentationLink {
-	//
-	//		private static final String DOCUMENTATION_URL = "http://alfa-docs";
-	//
-	//		@Test
-	//		void shouldNotHaveLinkForUndefinedUrl() {
-	//			var link = viewLinkHandler.toModel(root);
-	//
-	//			assertThat(link.getLink(RootViewLinkHandler.REL_DOCUMENTATIONS)).isEmpty();
-	//		}
-	//
-	//		@Test
-	//		void shouldHaveLinkForDefinedUrl() {
-	//			ReflectionTestUtils.setField(viewLinkHandler, "documentationUrl", DOCUMENTATION_URL);
-	//
-	//			var link = viewLinkHandler.toModel(root);
-	//
-	//			assertThat(link.getLink(RootViewLinkHandler.REL_DOCUMENTATIONS))
-	//					.isPresent()
-	//					.map(Link::getHref)
-	//					.hasValue(DOCUMENTATION_URL);
-	//		}
-	//
-	//		@Test
-	//		void shouldNotHaveLinkForEmptyStringUrl() {
-	//			ReflectionTestUtils.setField(viewLinkHandler, "documentationUrl", "");
-	//
-	//			var link = viewLinkHandler.toModel(root);
-	//
-	//			assertThat(link.getLink(RootViewLinkHandler.REL_DOCUMENTATIONS)).isEmpty();
-	//		}
-	//
-	//	}
 }
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/aktenzeichen/AktenzeichenModelProcessorTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/aktenzeichen/AktenzeichenModelProcessorTest.java
index 98c3b71d19a838674ca853d415457eddd448f783..db2df608d44e0e6fefafdc20604cf2a1e868d084 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/aktenzeichen/AktenzeichenModelProcessorTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/aktenzeichen/AktenzeichenModelProcessorTest.java
@@ -23,7 +23,6 @@
  */
 package de.ozgcloud.alfa.aktenzeichen;
 
-import static de.ozgcloud.alfa.common.UserProfileUrlProviderTestFactory.*;
 import static org.assertj.core.api.Assertions.*;
 import static org.mockito.Mockito.*;
 
@@ -37,7 +36,6 @@ import org.springframework.hateoas.EntityModel;
 import org.springframework.hateoas.Link;
 import org.springframework.hateoas.UriTemplate;
 
-import de.ozgcloud.alfa.common.UserProfileUrlProvider;
 import de.ozgcloud.alfa.common.command.CommandController;
 import de.ozgcloud.alfa.vorgang.Vorgang;
 import de.ozgcloud.alfa.vorgang.VorgangHeaderTestFactory;
@@ -46,8 +44,6 @@ import de.ozgcloud.alfa.vorgang.VorgangWithEingangTestFactory;
 
 class AktenzeichenModelProcessorTest {
 
-	private final UserProfileUrlProvider urlProvider = new UserProfileUrlProvider();
-
 	@InjectMocks
 	private AktenzeichenModelProcessor processor;
 
@@ -65,8 +61,6 @@ class AktenzeichenModelProcessorTest {
 		@ParameterizedTest
 		@EnumSource(names = { "ANGENOMMEN", "IN_BEARBEITUNG" }, mode = EnumSource.Mode.EXCLUDE)
 		void shouldNotCreateSetAktenzeichenLink(Vorgang.VorgangStatus vorgangStatus) {
-			initUserProfileUrlProvider(urlProvider);
-
 			var model = processor.process(buildModelWithVorgangStatus(vorgangStatus));
 
 			assertThat(model.getLink(AktenzeichenModelProcessor.REL_SET_AKTENZEICHEN)).isEmpty();
@@ -75,15 +69,12 @@ class AktenzeichenModelProcessorTest {
 		@ParameterizedTest
 		@EnumSource(names = { "ANGENOMMEN", "IN_BEARBEITUNG" })
 		void shouldCreateSetAktenzeichenLink(Vorgang.VorgangStatus vorgangStatus) {
-			initUserProfileUrlProvider(urlProvider);
-
 			var model = processor.process(buildModelWithVorgangStatus(vorgangStatus));
 
 			assertThat(model.getLink(AktenzeichenModelProcessor.REL_SET_AKTENZEICHEN)).isPresent().get()
 					.extracting(Link::getHref)
 					.isEqualTo(UriTemplate.of(CommandController.CommandByRelationController.COMMAND_BY_RELATION_PATH)
-							.expand(VorgangHeaderTestFactory.ID, VorgangHeaderTestFactory.ID, VorgangHeaderTestFactory.VERSION).toString()
-					);
+							.expand(VorgangHeaderTestFactory.ID, VorgangHeaderTestFactory.ID, VorgangHeaderTestFactory.VERSION).toString());
 		}
 	}
 
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/bescheid/BescheidLinkedResourceTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/bescheid/BescheidLinkedResourceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..f4a7748f7c13b3512cef043e5d724f02c7328148
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/bescheid/BescheidLinkedResourceTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2025 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.bescheid;
+
+import static org.assertj.core.api.Assertions.*;
+
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.NullAndEmptySource;
+import org.mockito.InjectMocks;
+import org.springframework.hateoas.EntityModel;
+import org.springframework.hateoas.Link;
+
+import de.ozgcloud.alfa.common.LinkedResourceProcessor;
+
+class BescheidLinkedResourceTest {
+
+	@InjectMocks
+	private LinkedResourceProcessor<Bescheid> processor;
+
+	@Nested
+	class TestEntityModelProcessing {
+		private static final String REL_BESCHEID_DOCUMENT = "bescheidDocument";
+
+		@Test
+		void shouldHaveBescheidDocumentLink() {
+			var model = processor.process(EntityModel.of(BescheidTestFactory.create()));
+
+			assertThat(model.getLink(REL_BESCHEID_DOCUMENT)).isPresent().get().extracting(Link::getHref)
+					.isEqualTo(String.format("%s/%s", DocumentController.PATH, BescheidTestFactory.BESCHEID_DOCUMENT));
+		}
+
+		@ParameterizedTest
+		@NullAndEmptySource
+		void shouldNotHaveBescheidDocumentLinkIfNoDocumentAvailable(String documentId) {
+			var model = processor.process(EntityModel.of(BescheidTestFactory.createBuilder().bescheidDocument(documentId).build()));
+
+			assertThat(model.getLink(REL_BESCHEID_DOCUMENT)).isEmpty();
+		}
+	}
+}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/bescheid/BescheidModelAssemblerTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/bescheid/BescheidModelAssemblerTest.java
index 8c207f58d05b16356cdafe1a05d45ac113ccf99f..bab353051a9c47d5a8764d05ac103a4047690e55 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/bescheid/BescheidModelAssemblerTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/bescheid/BescheidModelAssemblerTest.java
@@ -46,7 +46,6 @@ import org.springframework.hateoas.Link;
 import org.springframework.web.util.UriTemplate;
 
 import de.ozgcloud.alfa.bescheid.BescheidController.BescheidByVorgangController;
-import de.ozgcloud.alfa.common.ModelBuilder;
 import de.ozgcloud.alfa.common.binaryfile.FileId;
 import de.ozgcloud.alfa.common.command.CommandController;
 import de.ozgcloud.alfa.postfach.PostfachMailController;
@@ -175,22 +174,6 @@ class BescheidModelAssemblerTest {
 					.isEqualTo(createCommandLink());
 		}
 
-		@ParameterizedTest
-		@NullAndEmptySource
-		void shouldNotHaveBescheidDocumentLinkIfNoDocumentAvailable(String documentId) {
-			var model = callToModel(BescheidTestFactory.createBuilder().bescheidDocument(documentId).build());
-
-			assertThat(model.getLink(REL_BESCHEID_DOCUMENT)).isEmpty();
-		}
-
-		@Test
-		void shouldHaveBescheidDocumentLink() {
-			var model = callToModel();
-
-			assertThat(model.getLink(REL_BESCHEID_DOCUMENT)).isPresent().get().extracting(Link::getHref)
-					.isEqualTo(String.format("%s/%s", DocumentController.PATH, BescheidTestFactory.BESCHEID_DOCUMENT));
-		}
-
 		@Test
 		void shouldHaveBescheidenUndSendenLink() {
 			when(postfachMailController.isPostfachConfigured()).thenReturn(true);
@@ -213,7 +196,9 @@ class BescheidModelAssemblerTest {
 
 		@Test
 		void shouldNotHaveBescheidenUndSendenLinkOnVorgangWithoutServiceKonto() {
-			var vorgang = vorgangWithEingang.builder().header(VorgangHeadTestFactory.createBuilder().serviceKonto(null).build()).build();
+			var vorgang = VorgangWithEingangTestFactory.createBuilder()
+					.header(VorgangHeadTestFactory.createBuilder().serviceKonto(null).build())
+					.build();
 			when(vorgangController.getVorgang(VorgangHeaderTestFactory.ID)).thenReturn(vorgang);
 			when(postfachMailController.isPostfachConfigured()).thenReturn(true);
 
@@ -276,7 +261,7 @@ class BescheidModelAssemblerTest {
 
 		@Test
 		void shouldHaveEntityModel() {
-			var entityModel = ModelBuilder.fromEntity(bescheid).buildModel();
+			var entityModel = EntityModel.of(bescheid);
 			doReturn(entityModel).when(assembler).toModel(bescheid);
 
 			var collectionModel = callMethod();
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/bescheid/BescheidVorgangProcessorTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/bescheid/BescheidVorgangProcessorTest.java
index 162e1cd996bd355fee44ec30b80ce5ac11c0395a..5c9580a3509f7a01773a26251c5fb157050839e0 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/bescheid/BescheidVorgangProcessorTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/bescheid/BescheidVorgangProcessorTest.java
@@ -23,13 +23,11 @@
  */
 package de.ozgcloud.alfa.bescheid;
 
-import static de.ozgcloud.alfa.common.UserProfileUrlProviderTestFactory.*;
 import static org.assertj.core.api.Assertions.*;
 import static org.mockito.ArgumentMatchers.*;
 import static org.mockito.Mockito.*;
 
 import java.util.Optional;
-import java.util.function.BooleanSupplier;
 
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.DisplayName;
@@ -44,7 +42,6 @@ import org.springframework.hateoas.EntityModel;
 import org.springframework.hateoas.Link;
 
 import de.ozgcloud.alfa.common.EntityModelTestFactory;
-import de.ozgcloud.alfa.common.UserProfileUrlProvider;
 import de.ozgcloud.alfa.common.user.CurrentUserService;
 import de.ozgcloud.alfa.common.user.UserRole;
 import de.ozgcloud.alfa.vorgang.Vorgang;
@@ -87,7 +84,6 @@ class BescheidVorgangProcessorTest {
 
 		@Test
 		void shouldCallExistsBescheid() {
-			initUserProfileUrlProvider(new UserProfileUrlProvider());
 			doReturn(true).when(processor).existsBescheid(anyString());
 
 			callProcess();
@@ -98,11 +94,6 @@ class BescheidVorgangProcessorTest {
 		@Nested
 		class TestLinks {
 
-			@BeforeEach
-			void init() {
-				initUserProfileUrlProvider(new UserProfileUrlProvider());
-			}
-
 			@Test
 			void shouldNotHaveLinkToDraft() {
 				givenRetrievingDraftIsAllowed(false);
@@ -185,11 +176,11 @@ class BescheidVorgangProcessorTest {
 			}
 
 			private void givenRetrievingDraftIsAllowed(boolean shouldBeAdded) {
-				doReturn((BooleanSupplier) () -> shouldBeAdded).when(processor).isRetrievingDraftAllowed(vorgang);
+				doReturn(shouldBeAdded).when(processor).isRetrievingDraftAllowed(vorgang);
 			}
 
 			private void givenCreatingDraftIsAllowed(boolean shouldBeAdded) {
-				doReturn((BooleanSupplier) () -> shouldBeAdded).when(processor).isCreatingDraftAllowed(vorgang);
+				doReturn(shouldBeAdded).when(processor).isCreatingDraftAllowed(vorgang);
 			}
 		}
 
@@ -230,18 +221,18 @@ class BescheidVorgangProcessorTest {
 			givenVorgangInBearbeitung(true);
 			givenDraftExists(true);
 
-			var booleanSupplier = callMethod();
+			var result = callMethod();
 
-			assertThat(booleanSupplier.getAsBoolean()).isTrue();
+			assertThat(result).isTrue();
 		}
 
 		@Test
 		void shouldReturnFalseIfVorgangNotInBearbeitung() {
 			givenVorgangInBearbeitung(false);
 
-			var booleanSupplier = callMethod();
+			var result = callMethod();
 
-			assertThat(booleanSupplier.getAsBoolean()).isFalse();
+			assertThat(result).isFalse();
 		}
 
 		@Test
@@ -249,12 +240,12 @@ class BescheidVorgangProcessorTest {
 			givenVorgangInBearbeitung(true);
 			givenDraftExists(false);
 
-			var booleanSupplier = callMethod();
+			var result = callMethod();
 
-			assertThat(booleanSupplier.getAsBoolean()).isFalse();
+			assertThat(result).isFalse();
 		}
 
-		private BooleanSupplier callMethod() {
+		private boolean callMethod() {
 			return processor.isRetrievingDraftAllowed(vorgang);
 		}
 	}
@@ -267,18 +258,18 @@ class BescheidVorgangProcessorTest {
 			givenVorgangInBearbeitung(true);
 			givenDraftExists(false);
 
-			var booleanSupplier = callMethod();
+			var result = callMethod();
 
-			assertThat(booleanSupplier.getAsBoolean()).isTrue();
+			assertThat(result).isTrue();
 		}
 
 		@Test
 		void shouldReturnFalseIfVorgangNotInBearbeitung() {
 			givenVorgangInBearbeitung(false);
 
-			var booleanSupplier = callMethod();
+			var result = callMethod();
 
-			assertThat(booleanSupplier.getAsBoolean()).isFalse();
+			assertThat(result).isFalse();
 		}
 
 		@Test
@@ -286,12 +277,12 @@ class BescheidVorgangProcessorTest {
 			givenVorgangInBearbeitung(true);
 			givenDraftExists(true);
 
-			var booleanSupplier = callMethod();
+			var result = callMethod();
 
-			assertThat(booleanSupplier.getAsBoolean()).isFalse();
+			assertThat(result).isFalse();
 		}
 
-		private BooleanSupplier callMethod() {
+		private boolean callMethod() {
 			return processor.isCreatingDraftAllowed(vorgang);
 		}
 	}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/bescheid/DocumentLinkedResourceTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/bescheid/DocumentLinkedResourceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..16e41bbc0fd8d77c972d5e7ecc92b558aa87cfff
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/bescheid/DocumentLinkedResourceTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2025 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.bescheid;
+
+import static org.assertj.core.api.Assertions.*;
+
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.NullAndEmptySource;
+import org.mockito.InjectMocks;
+import org.springframework.hateoas.EntityModel;
+import org.springframework.hateoas.Link;
+
+import de.ozgcloud.alfa.common.LinkedResourceProcessor;
+import de.ozgcloud.alfa.common.binaryfile.FileId;
+
+class DocumentLinkedResourceTest {
+
+	@InjectMocks
+	private LinkedResourceProcessor<Document> processor;
+
+	@Nested
+	class TestEntityModelProcessing {
+		static final String REL_FILE = "file";
+
+		@Test
+		void shouldHaveFileIdLink() {
+			var model = processor.process(EntityModel.of(DocumentTestFactory.create()));
+
+			assertThat(model.getLink(REL_FILE)).isPresent().get().extracting(Link::getHref)
+					.isEqualTo("/api/binaryFiles/" + DocumentTestFactory.FILE_ID);
+		}
+
+		@ParameterizedTest
+		@NullAndEmptySource
+		void shouldNotHaveFileIdLinkIfNoFileAvailable(String fileId) {
+			var model = processor.process(EntityModel.of(DocumentTestFactory.createBuilder().fileId(FileId.from(fileId)).build()));
+
+			assertThat(model.getLink(REL_FILE)).isEmpty();
+		}
+	}
+}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/bescheid/DocumentModelAssemblerTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/bescheid/DocumentModelAssemblerTest.java
index b867db73a6ac2d3c267b6105a450325742e2c470..debf5521d25db90c7bffdf623deb75c9b4a6d5d1 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/bescheid/DocumentModelAssemblerTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/bescheid/DocumentModelAssemblerTest.java
@@ -23,7 +23,6 @@
  */
 package de.ozgcloud.alfa.bescheid;
 
-import static de.ozgcloud.alfa.bescheid.DocumentModelAssembler.*;
 import static org.assertj.core.api.Assertions.*;
 
 import org.junit.jupiter.api.Nested;
@@ -51,14 +50,6 @@ class DocumentModelAssemblerTest {
 					.isEqualTo(DocumentController.PATH + "/" + DocumentTestFactory.ID);
 		}
 
-		@Test
-		void shouldHaveFileIdLink() {
-			var model = callToModel();
-
-			assertThat(model.getLink(REL_FILE)).isPresent().get().extracting(Link::getHref)
-					.isEqualTo("/api/binaryFiles/" + DocumentTestFactory.FILE_ID);
-		}
-
 		private EntityModel<Document> callToModel() {
 			return assembler.toModel(document);
 		}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/CollaborationLinkedResourceTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/CollaborationLinkedResourceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..694b60344b247b688d51c2f38f0d1ff273345753
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/CollaborationLinkedResourceTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2025 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.collaboration;
+
+import static org.assertj.core.api.Assertions.*;
+
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.mockito.InjectMocks;
+import org.springframework.hateoas.EntityModel;
+import org.springframework.hateoas.Link;
+
+import de.ozgcloud.alfa.common.LinkedResourceProcessor;
+
+class CollaborationLinkedResourceTest {
+
+	@InjectMocks
+	private LinkedResourceProcessor<Collaboration> processor;
+
+	@Nested
+	class TestEntityModelProcessing {
+		private static final String REL_ZUSTAENDIGE_STELLE = "zustaendigeStelle";
+
+		@Test
+		void shouldHaveLinkToOrganisationsEinheit() {
+			var entityModel = processor.process(EntityModel.of(OrganisationsEinheitCollaborationTestFactory.create()));
+
+			assertThat(entityModel.getLink(REL_ZUSTAENDIGE_STELLE)).get().extracting(Link::getHref)
+					.isEqualTo(OrganisationsEinheitController.PATH + "/" + OrganisationsEinheitTestFactory.ID);
+		}
+
+		@Test
+		void shouldHaveLinkToFachstelle() {
+			var entityModel = processor.process(EntityModel.of(FachstelleCollaborationTestFactory.create()));
+
+			assertThat(entityModel.getLink(REL_ZUSTAENDIGE_STELLE)).get().extracting(Link::getHref)
+					.isEqualTo(FachstelleController.PATH + "/" + FachstelleTestFactory.ID);
+		}
+
+	}
+}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/CollaborationModelAssemblerTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/CollaborationModelAssemblerTest.java
index 3f4db275292b754887a4287662e537e5fba55284..3818b59854bbd3bbff6cdca7428c54b39177f68c 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/CollaborationModelAssemblerTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/CollaborationModelAssemblerTest.java
@@ -41,7 +41,6 @@ import org.springframework.hateoas.Link;
 import org.springframework.hateoas.UriTemplate;
 
 import de.ozgcloud.alfa.collaboration.CollaborationController.CollaborationByVorgangController;
-import de.ozgcloud.alfa.common.ModelBuilder;
 import de.ozgcloud.alfa.common.command.CommandController.CommandByRelationController;
 import de.ozgcloud.alfa.vorgang.VorgangController;
 import de.ozgcloud.alfa.vorgang.VorgangHeaderTestFactory;
@@ -60,8 +59,6 @@ class CollaborationModelAssemblerTest {
 	@Nested
 	class TestToModel {
 
-		private static final String REL_ZUSTAENDIGE_STELLE = "zustaendigeStelle";
-
 		@Nested
 		class OnOrganisationsEinheitCollaboration {
 
@@ -74,14 +71,6 @@ class CollaborationModelAssemblerTest {
 				assertThat(entityModel.getContent()).isEqualTo(collaboration);
 			}
 
-			@Test
-			void shouldHaveLinkToOrganisationsEinheit() {
-				var entityModel = callAssembler();
-
-				assertThat(entityModel.getLink(REL_ZUSTAENDIGE_STELLE)).get().extracting(Link::getHref)
-						.isEqualTo(OrganisationsEinheitController.PATH + "/" + OrganisationsEinheitTestFactory.ID);
-			}
-
 			private EntityModel<Collaboration> callAssembler() {
 				return assembler.toModel(collaboration);
 			}
@@ -99,14 +88,6 @@ class CollaborationModelAssemblerTest {
 				assertThat(entityModel.getContent()).isEqualTo(collaboration);
 			}
 
-			@Test
-			void shouldHaveLinkToFachstelle() {
-				var entityModel = callAssembler();
-
-				assertThat(entityModel.getLink(REL_ZUSTAENDIGE_STELLE)).get().extracting(Link::getHref)
-						.isEqualTo(FachstelleController.PATH + "/" + FachstelleTestFactory.ID);
-			}
-
 			private EntityModel<Collaboration> callAssembler() {
 				return assembler.toModel(collaboration);
 			}
@@ -143,7 +124,7 @@ class CollaborationModelAssemblerTest {
 
 			@Test
 			void shouldHaveEntityModel() {
-				var entityModel = ModelBuilder.fromEntity(collaboration).buildModel();
+				var entityModel = EntityModel.of(collaboration);
 				doReturn(entityModel).when(assembler).toModel(collaboration);
 
 				var collectionModel = callAssembler();
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/CollaborationVorgangProcessorTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/CollaborationVorgangProcessorTest.java
index 4a64401a176409235eaf75a26a7cc089575f1ddf..97079a883a639e1844028ab2356403866462f7f5 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/CollaborationVorgangProcessorTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/CollaborationVorgangProcessorTest.java
@@ -23,7 +23,6 @@
  */
 package de.ozgcloud.alfa.collaboration;
 
-import static de.ozgcloud.alfa.common.UserProfileUrlProviderTestFactory.*;
 import static org.assertj.core.api.Assertions.*;
 import static org.mockito.Mockito.*;
 
@@ -39,7 +38,6 @@ import org.springframework.web.util.UriComponentsBuilder;
 
 import de.ozgcloud.alfa.collaboration.CollaborationController.CollaborationByVorgangController;
 import de.ozgcloud.alfa.common.EntityModelTestFactory;
-import de.ozgcloud.alfa.common.UserProfileUrlProvider;
 import de.ozgcloud.alfa.common.user.CurrentUserService;
 import de.ozgcloud.alfa.common.user.UserRole;
 import de.ozgcloud.alfa.vorgang.VorgangHeaderTestFactory;
@@ -58,8 +56,6 @@ class CollaborationVorgangProcessorTest {
 	@Mock
 	private CurrentUserService currentUserService;
 
-	private final UserProfileUrlProvider urlProvider = new UserProfileUrlProvider();
-
 	@Nested
 	class TestProcess {
 
@@ -94,11 +90,6 @@ class CollaborationVorgangProcessorTest {
 		@Nested
 		class OnNonNullVorgangAndOnVerwaltungUserRole {
 
-			@BeforeEach
-			void prepareBuilder() {
-				initUserProfileUrlProvider(urlProvider);
-			}
-
 			@BeforeEach
 			void mockUserService() {
 				when(currentUserService.hasRole(UserRole.VERWALTUNG_USER)).thenReturn(true);
@@ -113,10 +104,10 @@ class CollaborationVorgangProcessorTest {
 				}
 
 				@Test
-				void shouldHaveTwoLinks() {
+				void shouldHaveOneLink() {
 					var model = callProcessor();
 
-					assertThat(model.getLinks()).hasSize(2);
+					assertThat(model.getLinks()).hasSize(1);
 				}
 
 				@Test
@@ -145,10 +136,10 @@ class CollaborationVorgangProcessorTest {
 				}
 
 				@Test
-				void shouldHaveFourLinks() {
+				void shouldHaveThreeLinks() {
 					var model = callProcessor();
 
-					assertThat(model.getLinks()).hasSize(4);
+					assertThat(model.getLinks()).hasSize(3);
 				}
 
 				@Test
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/common/CollectionModelBuilderTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/common/CollectionModelBuilderTest.java
deleted file mode 100644
index 53e3d279b9ee0174a865852293ec9eb5a7daf849..0000000000000000000000000000000000000000
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/common/CollectionModelBuilderTest.java
+++ /dev/null
@@ -1,149 +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.common;
-
-import static org.assertj.core.api.Assertions.*;
-import static org.mockito.Mockito.*;
-
-import java.util.List;
-import java.util.function.Supplier;
-import java.util.stream.Stream;
-
-import org.junit.jupiter.api.Nested;
-import org.junit.jupiter.api.Test;
-import org.mockito.Mock;
-import org.springframework.hateoas.Link;
-
-import de.ozgcloud.alfa.vorgang.VorgangHeaderTestFactory;
-import de.ozgcloud.alfa.wiedervorlage.Wiedervorlage;
-import de.ozgcloud.alfa.wiedervorlage.WiedervorlageTestFactory;
-
-class CollectionModelBuilderTest {
-
-	private final String HREF = "http://test";
-	private final String REL = "rel";
-
-	@Nested
-	class TestBuildModel {
-
-		@Test
-		void shouldBuildModel() {
-			var vorgang = VorgangHeaderTestFactory.create();
-
-			var model = CollectionModelBuilder.fromEntities(List.of(vorgang)).buildModel();
-
-			assertThat(model.getContent()).hasSize(1).first().usingRecursiveComparison().isEqualTo(vorgang);
-		}
-	}
-
-	@Nested
-	class TestAddLink {
-
-		@Test
-		void shouldAddLink() {
-			var model = CollectionModelBuilder.fromEntities(List.of()).addLink(Link.of(HREF, REL)).buildModel();
-
-			assertThat(model.getLinks()).hasSize(1).first().extracting(Link::getHref, link -> link.getRel().value()).containsExactly(HREF, REL);
-		}
-	}
-
-	@Nested
-	class TestIfMatch {
-
-		@Nested
-		class TestWithBooleanSupplier {
-
-			@Test
-			void shouldAddLink() {
-				var model = CollectionModelBuilder.fromEntities(List.of()).ifMatch(() -> true).addLink(Link.of(HREF, REL)).buildModel();
-
-				assertThat(model.getLinks()).hasSize(1).first().extracting(Link::getHref, link -> link.getRel().value()).containsExactly(HREF, REL);
-			}
-
-			@Test
-			void shouldNotAddLink() {
-				var model = CollectionModelBuilder.fromEntities(List.of()).ifMatch(() -> false).addLink(Link.of(HREF, REL)).buildModel();
-
-				assertThat(model.getLinks()).isEmpty();
-			}
-		}
-
-		@Nested
-		class TestWithPredicate {
-
-			private final Stream<Wiedervorlage> wiedervorlageStream = Stream.of(WiedervorlageTestFactory.create());
-
-			@Test
-			void shouldAddLink() {
-				var model = CollectionModelBuilder.fromEntities(wiedervorlageStream)
-						.ifMatch(wiedervorlagen -> true)
-						.addLink(Link.of(HREF, REL))
-						.buildModel();
-
-				assertThat(model.getLinks()).hasSize(1).first().extracting(Link::getHref, link -> link.getRel().value()).containsExactly(HREF, REL);
-			}
-
-			@Test
-			void shouldNotAddLink() {
-				var model = CollectionModelBuilder.fromEntities(wiedervorlageStream)
-						.ifMatch(wiedervorlagen -> false)
-						.addLink(Link.of(HREF, REL))
-						.buildModel();
-
-				assertThat(model.getLinks()).isEmpty();
-			}
-		}
-
-		@Nested
-		class TestWithLinkSupplier {
-
-			@Mock
-			private Supplier<Link> linkSupplier;
-
-			@Test
-			void shouldAddLink() {
-				when(linkSupplier.get()).thenReturn(Link.of(HREF, REL));
-
-				var model = CollectionModelBuilder.fromEntities(List.of()).ifMatch(() -> true).addLink(linkSupplier).buildModel();
-
-				assertThat(model.getLinks()).hasSize(1).first().extracting(Link::getHref, link -> link.getRel().value()).containsExactly(HREF, REL);
-			}
-
-			@Test
-			void shouldNotCallLinkSupplier() {
-				CollectionModelBuilder.fromEntities(List.of()).ifMatch(() -> false).addLink(linkSupplier).buildModel();
-
-				verify(linkSupplier, never()).get();
-			}
-
-			@Test
-			void shouldNotAddLink() {
-				var model = CollectionModelBuilder.fromEntities(List.of()).ifMatch(() -> false).addLink(linkSupplier).buildModel();
-
-				assertThat(model.getLinks()).isEmpty();
-			}
-		}
-	}
-
-}
\ No newline at end of file
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/common/LinkedResourceCollectionProcessorITCase.java b/alfa-service/src/test/java/de/ozgcloud/alfa/common/LinkedResourceCollectionProcessorITCase.java
new file mode 100644
index 0000000000000000000000000000000000000000..d3dfb408c2f1363af17defb6548f5d4a940c9ed0
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/common/LinkedResourceCollectionProcessorITCase.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2025 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.common;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.web.servlet.assertj.MockMvcTester;
+import org.springframework.test.web.servlet.assertj.MvcTestResult;
+import org.springframework.web.context.WebApplicationContext;
+
+import de.ozgcloud.common.test.ITCase;
+import lombok.SneakyThrows;
+
+@ITCase
+class LinkedResourceCollectionProcessorITCase {
+
+	@Autowired
+	private WebApplicationContext context;
+	private MockMvcTester mockMvc;
+
+	@BeforeEach
+	void setup() {
+		this.mockMvc = MockMvcTester.from(this.context);
+	}
+
+	@Test
+	@SneakyThrows
+	void shouldHaveAddLinkByLinkedResource() {
+		var result = doRequest();
+
+		result.assertThat().bodyJson().extractingPath("$._embedded.testEntityList[0]._links.linkedResource.href")
+				.isEqualTo("http://localhost" + TestIdController.PATH + "/" + TestEntityTestFactory.LINKED_RESOURCE);
+	}
+
+	@Test
+	@SneakyThrows
+	void shouldHaveUserProfileLink() {
+		var result = doRequest();
+
+		result.assertThat().bodyJson().extractingPath("$._embedded.testEntityList[0]._links.user.href")
+				.isEqualTo("https://localhost/api/userProfiles/" + TestEntityTestFactory.USER);
+	}
+
+	private MvcTestResult doRequest() {
+		return mockMvc.get().uri(TestEntityController.PATH + TestEntityController.GET_ALL).exchange();
+	}
+}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/common/LinkedResourceCollectionProcessorTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/common/LinkedResourceCollectionProcessorTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..d08e2a160edd170b672b79703566a619c35de3a2
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/common/LinkedResourceCollectionProcessorTest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2025 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.common;
+
+import static org.assertj.core.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+import java.util.List;
+
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.springframework.hateoas.CollectionModel;
+import org.springframework.hateoas.EntityModel;
+
+class LinkedResourceCollectionProcessorTest {
+
+	@InjectMocks
+	private LinkedResourceCollectionProcessor<TestEntity> processor;
+	@Mock
+	private LinkedResourceProcessor<TestEntity> elementProcessor;
+
+	@Nested
+	class TestProcess {
+
+		@Test
+		void shouldReturnSameCollectionModel() {
+			var collectionModel = CollectionModel.of(List.of(EntityModel.of(TestEntityTestFactory.create())));
+
+			var result = processor.process(collectionModel);
+
+			assertThat(collectionModel).isSameAs(result);
+		}
+
+		@Test
+		void shouldCallLinkedResourceProcessor() {
+			var entityModel = EntityModel.of(TestEntityTestFactory.create());
+			var collectionModel = CollectionModel.of(List.of(entityModel));
+
+			processor.process(collectionModel);
+
+			verify(elementProcessor).process(entityModel);
+		}
+	}
+}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/common/LinkedResourceProcessorITCase.java b/alfa-service/src/test/java/de/ozgcloud/alfa/common/LinkedResourceProcessorITCase.java
new file mode 100644
index 0000000000000000000000000000000000000000..0f6e259e27a6b4e23e8fd1fc1a77680227439777
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/common/LinkedResourceProcessorITCase.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2025 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.common;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.web.servlet.assertj.MockMvcTester;
+import org.springframework.test.web.servlet.assertj.MvcTestResult;
+import org.springframework.web.context.WebApplicationContext;
+
+import de.ozgcloud.common.test.ITCase;
+import lombok.SneakyThrows;
+
+@ITCase
+class LinkedResourceProcessorITCase {
+
+	@Autowired
+	private WebApplicationContext context;
+	private MockMvcTester mockMvc;
+
+	@BeforeEach
+	void setup() {
+		this.mockMvc = MockMvcTester.from(this.context);
+	}
+
+	@Test
+	@SneakyThrows
+	void shouldHaveAddLinkByLinkedResource() {
+		var result = doRequest();
+
+		result.assertThat().bodyJson().extractingPath("$._links.linkedResource.href")
+				.isEqualTo("http://localhost" + TestIdController.PATH + "/" + TestEntityTestFactory.LINKED_RESOURCE);
+	}
+
+	@Test
+	@SneakyThrows
+	void shouldHaveUserProfileLink() {
+		var result = doRequest();
+
+		result.assertThat().bodyJson().extractingPath("$._links.user.href")
+				.isEqualTo("https://localhost/api/userProfiles/" + TestEntityTestFactory.USER);
+	}
+
+	private MvcTestResult doRequest() {
+		return mockMvc.get().uri(TestEntityController.PATH).exchange();
+	}
+}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/common/LinkedResourceProcessorTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/common/LinkedResourceProcessorTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..b640df8181abcbc8439d5aee450b60cdf9f428a6
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/common/LinkedResourceProcessorTest.java
@@ -0,0 +1,392 @@
+/*
+ * Copyright (C) 2025 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.common;
+
+import static org.assertj.core.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.*;
+
+import java.lang.reflect.Field;
+import java.util.Arrays;
+import java.util.List;
+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.NullAndEmptySource;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Spy;
+import org.springframework.hateoas.EntityModel;
+import org.springframework.hateoas.Link;
+
+import com.thedeanda.lorem.LoremIpsum;
+
+import de.ozgcloud.alfa.common.user.UserId;
+import de.ozgcloud.alfa.common.user.UserManagerUrlProvider;
+import lombok.SneakyThrows;
+
+class LinkedResourceProcessorTest {
+
+	@Spy
+	@InjectMocks
+	private LinkedResourceProcessor<TestEntity> processor;
+
+	@Mock
+	private UserManagerUrlProvider userManagerUrlProvider;
+
+	@Nested
+	class TestProcess {
+
+		private final TestEntity entity = TestEntityTestFactory.create();
+		private final EntityModel<TestEntity> model = EntityModel.of(entity);
+
+		@BeforeEach
+		void mock() {
+			doNothing().when(processor).addResourceLinks(any());
+			doNothing().when(processor).addUserProfileLinks(any());
+		}
+
+		@Test
+		void shouldReturnSameEntityModel() {
+			var result = processor.process(model);
+
+			assertThat(result).isSameAs(model);
+		}
+
+		@Test
+		void shouldCallAddResourceLinks() {
+			processor.process(model);
+
+			verify(processor).addResourceLinks(model);
+		}
+
+		@Test
+		void shouldCallAddUserProfileLinks() {
+			processor.process(model);
+
+			verify(processor).addUserProfileLinks(model);
+		}
+	}
+
+	@Nested
+	class TestAddResourceLinks {
+
+		private final TestEntity entity = TestEntityTestFactory.create();
+		private final EntityModel<TestEntity> model = EntityModel.of(entity);
+
+		@Mock
+		private Field field;
+
+		@BeforeEach
+		void mock() {
+			doReturn(Stream.of(field)).when(processor).getAnnotatedFields(any(), any());
+		}
+
+		@Test
+		void shouldGetAnnotatedFieldsWithLinkedResourceAnnotation() {
+			doReturn(false).when(processor).shouldAddLink(any(), any());
+
+			processor.addResourceLinks(model);
+
+			verify(processor).getAnnotatedFields(LinkedResource.class, entity);
+		}
+
+		@Test
+		void shouldCallShouldAddLink() {
+			doReturn(false).when(processor).shouldAddLink(any(), any());
+
+			processor.addResourceLinks(model);
+
+			verify(processor).shouldAddLink(model, field);
+		}
+
+		@Test
+		void shouldCallAddLinkForLinkedResourceField() {
+			doReturn(true).when(processor).shouldAddLink(any(), any());
+
+			processor.addResourceLinks(model);
+
+			verify(processor).addLinkForLinkedResourceField(model, field);
+		}
+
+		@Test
+		void shouldNotCallAddLinkForLinkedResourceField() {
+			doReturn(false).when(processor).shouldAddLink(any(), any());
+
+			processor.addResourceLinks(model);
+
+			verify(processor, never()).addLinkForLinkedResourceField(any(), any());
+		}
+	}
+
+	@Nested
+	class TestAddUserProfileLinks {
+
+		private final TestEntity entity = TestEntityTestFactory.create();
+		private final EntityModel<TestEntity> model = EntityModel.of(entity);
+
+		@Mock
+		private Field field;
+
+		@BeforeEach
+		void mock() {
+			doReturn(Stream.of(field)).when(processor).getAnnotatedFields(any(), any());
+		}
+
+		@Test
+		void shouldGetAnnotatedFieldsWithLinkedUserProfileResourceAnnotation() {
+			doReturn(false).when(processor).shouldAddLink(any(), any());
+
+			processor.addUserProfileLinks(model);
+
+			verify(processor).getAnnotatedFields(LinkedUserProfileResource.class, entity);
+		}
+
+		@Test
+		void shouldCallShouldAddLink() {
+			doReturn(false).when(processor).shouldAddLink(any(), any());
+
+			processor.addUserProfileLinks(model);
+
+			verify(processor).shouldAddLink(model, field);
+		}
+
+		@Test
+		void shouldCallAddLinkForLinkedUserProfileResourceField() {
+			doReturn(true).when(processor).shouldAddLink(any(), any());
+
+			processor.addUserProfileLinks(model);
+
+			verify(processor).addLinkForLinkedUserProfileResourceField(model, field);
+		}
+
+		@Test
+		void shouldNotCallAddLinkForLinkedUserProfileResourceField() {
+			doReturn(false).when(processor).shouldAddLink(any(), any());
+
+			processor.addUserProfileLinks(model);
+
+			verify(processor, never()).addLinkForLinkedUserProfileResourceField(any(), any());
+		}
+	}
+
+	@Nested
+	class TestGetAnnotatedFields {
+
+		@Test
+		void shouldReturnEmptyStreamIfContentIsNull() {
+			var result = processor.getAnnotatedFields(LinkedResource.class, null);
+
+			assertThat(result).isEmpty();
+		}
+
+		@Test
+		void shouldReturnAllFieldsWithLinkedResourceAnnotation() {
+			var entity = TestEntityTestFactory.create();
+			var expectedFields = List.of(getField("linkedResource"), getField("testId"));
+
+			var result = processor.getAnnotatedFields(LinkedResource.class, entity);
+
+			assertThat(result).containsExactlyInAnyOrderElementsOf(expectedFields);
+		}
+
+		@Test
+		void shouldReturnAllFieldsWithLinkedUserProfileResource() {
+			var entity = TestEntityTestFactory.create();
+			var expectedFields = List.of(getField("user"), getField("differentUserId"));
+
+			var result = processor.getAnnotatedFields(LinkedUserProfileResource.class, entity);
+
+			assertThat(result).containsExactlyInAnyOrderElementsOf(expectedFields);
+		}
+
+		@SneakyThrows
+		private Field getField(String fieldName) {
+			return TestEntity.class.getDeclaredField(fieldName);
+		}
+	}
+
+	@Nested
+	class TestShouldAddLink {
+
+		private final TestEntity entity = TestEntityTestFactory.create();
+		private final EntityModel<TestEntity> model = EntityModel.of(entity);
+
+		@Test
+		void shouldReturnFalseIfFieldIsArray() {
+			var field = getField("arrayField");
+
+			var result = processor.shouldAddLink(model, field);
+
+			assertThat(result).isFalse();
+		}
+
+		@Test
+		void shouldReturnFalseIfFieldIsCollection() {
+			var field = getField("collectionField");
+
+			var result = processor.shouldAddLink(model, field);
+
+			assertThat(result).isFalse();
+		}
+
+		@Test
+		void shouldReturnFalseIfFieldHasLink() {
+			var field = getField("linkedResource");
+			model.add(Link.of(LoremIpsum.getInstance().getUrl()).withRel(TestIdController.LINKED_RESOURCE_REL));
+
+			var result = processor.shouldAddLink(model, field);
+
+			assertThat(result).isFalse();
+		}
+
+		@Test
+		void shouldReturnTrueOtherwise() {
+			var fieldsToBuildLinksFor = Arrays.stream(TestEntity.class.getDeclaredFields())
+					.filter(field -> !(field.getName().equals("collectionField") || field.getName().equals("arrayField")));
+
+			var result = fieldsToBuildLinksFor.map(field -> processor.shouldAddLink(model, field));
+
+			assertThat(result).isNotEmpty().allMatch(value -> value.equals(true));
+		}
+
+		@SneakyThrows
+		private Field getField(String fieldName) {
+			return TestEntity.class.getDeclaredField(fieldName);
+		}
+	}
+
+	@Nested
+	class TestAddLinkForLinkedResourceField {
+
+		@Test
+		void shouldAddLinkOfLinkedResource() {
+			var model = EntityModel.of(TestEntityTestFactory.create());
+			var field = getField("linkedResource");
+
+			processor.addLinkForLinkedResourceField(model, field);
+
+			assertThat(model.getLink(TestIdController.LINKED_RESOURCE_REL).get().getHref())
+					.isEqualTo(TestIdController.PATH + "/" + TestEntityTestFactory.LINKED_RESOURCE);
+		}
+
+		@Test
+		void shouldTrimIdSuffix() {
+			var model = EntityModel.of(TestEntityTestFactory.create());
+			var field = getField("testId");
+
+			processor.addLinkForLinkedResourceField(model, field);
+
+			assertThat(model.getLink(TestIdController.ID_REL).get().getHref())
+					.isEqualTo(TestIdController.PATH + "/" + TestEntityTestFactory.ID);
+		}
+
+		@ParameterizedTest
+		@NullAndEmptySource
+		void shouldNotAddLinkIfFieldValueIsNullOrBlank(String linkedResourceValue) {
+			var model = EntityModel.of(TestEntityTestFactory.createBuilder().linkedResource(linkedResourceValue).build());
+			var field = getField("linkedResource");
+
+			processor.addLinkForLinkedResourceField(model, field);
+
+			assertThat(model.getLink(TestIdController.LINKED_RESOURCE_REL)).isEmpty();
+		}
+
+		@SneakyThrows
+		private Field getField(String fieldName) {
+			return TestEntity.class.getDeclaredField(fieldName);
+		}
+	}
+
+	@Nested
+	class TestAddLinkForLinkedUserProfileResourceField {
+
+		private final String userProfileTemplate = LoremIpsum.getInstance().getUrl() + "/%s";
+
+		@Test
+		void shouldGetUserProfileTemplate() {
+			when(userManagerUrlProvider.getUserProfileTemplate()).thenReturn(userProfileTemplate);
+			var field = getField("user");
+
+			processor.addLinkForLinkedUserProfileResourceField(EntityModel.of(TestEntityTestFactory.create()), field);
+
+			verify(userManagerUrlProvider).getUserProfileTemplate();
+		}
+
+		@Test
+		void shouldAddLinkOfLinkedUserProfileResource() {
+			when(userManagerUrlProvider.getUserProfileTemplate()).thenReturn(userProfileTemplate);
+			var model = EntityModel.of(TestEntityTestFactory.create());
+			var field = getField("user");
+
+			processor.addLinkForLinkedUserProfileResourceField(model, field);
+
+			assertThat(model.getLink(TestIdController.USER_REL).get().getHref())
+					.isEqualTo(userProfileTemplate.formatted(TestEntityTestFactory.USER));
+		}
+
+		@Test
+		void shouldTrimIdSuffix() {
+			when(userManagerUrlProvider.getUserProfileTemplate()).thenReturn(userProfileTemplate);
+			var model = EntityModel.of(TestEntityTestFactory.create());
+			var field = getField("differentUserId");
+
+			processor.addLinkForLinkedUserProfileResourceField(model, field);
+
+			assertThat(model.getLink(TestIdController.DIFFERENT_USER_REL).get().getHref())
+					.isEqualTo(userProfileTemplate.formatted(TestEntityTestFactory.DIFFERENT_USER_ID));
+		}
+
+		@ParameterizedTest
+		@NullAndEmptySource
+		void shouldNotAddLinkIfFieldValueIsNullOrBlank(String userValue) {
+			var model = EntityModel.of(TestEntityTestFactory.createBuilder().user(UserId.from(userValue)).build());
+			var field = getField("user");
+
+			processor.addLinkForLinkedUserProfileResourceField(model, field);
+
+			assertThat(model.getLink(TestIdController.USER_REL)).isEmpty();
+		}
+
+		@ParameterizedTest
+		@NullAndEmptySource
+		void shouldNotAddLinkIfUserManagerUrlIsNullOrBlank(String userManagerUrl) {
+			when(userManagerUrlProvider.getUserProfileTemplate()).thenReturn(userManagerUrl);
+			var model = EntityModel.of(TestEntityTestFactory.create());
+			var field = getField("user");
+
+			processor.addLinkForLinkedUserProfileResourceField(model, field);
+
+			assertThat(model.getLink(TestIdController.USER_REL)).isEmpty();
+		}
+
+		@SneakyThrows
+		private Field getField(String fieldName) {
+			return TestEntity.class.getDeclaredField(fieldName);
+		}
+	}
+}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/common/LinkedUserProfileResourceSerializerITCase.java b/alfa-service/src/test/java/de/ozgcloud/alfa/common/LinkedUserProfileResourceSerializerITCase.java
new file mode 100644
index 0000000000000000000000000000000000000000..ca3058226b1c21a358db5a68e879a7869fb6b339
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/common/LinkedUserProfileResourceSerializerITCase.java
@@ -0,0 +1,68 @@
+/*
+ * 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.common;
+
+import static org.assertj.core.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.bean.override.mockito.MockitoBean;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import de.ozgcloud.alfa.common.user.UserManagerUrlProvider;
+import de.ozgcloud.alfa.common.user.UserProfileTestFactory;
+import de.ozgcloud.common.test.ITCase;
+
+@ITCase
+class LinkedUserProfileResourceSerializerITCase {
+
+	private static final String HTTP_LOCALHOST = "http://localhost/";
+	private static final String API_TEMPLATE = "api/profile/%s";
+	private static final String API_PATH = "api/profile/";
+
+	@MockitoBean
+	private UserManagerUrlProvider userManagerUrlProvider;
+
+	@Autowired
+	private ObjectMapper objectMapper;
+
+	@BeforeEach
+	void init() {
+		when(userManagerUrlProvider.isConfiguredForUserProfile()).thenReturn(true);
+		when(userManagerUrlProvider.getUserProfileTemplate()).thenReturn(HTTP_LOCALHOST + API_TEMPLATE);
+	}
+
+	@Test
+	void shouldSerialize() throws JsonProcessingException {
+		var testObj = new LinkedUserProfileResourceTestObject(UserProfileTestFactory.ID);
+
+		var serialized = objectMapper.writeValueAsString(testObj);
+
+		assertThat(serialized).isEqualTo("{\"id\":\"" + HTTP_LOCALHOST + API_PATH + UserProfileTestFactory.ID.toString() + "\"}");
+	}
+}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/common/LinkedUserProfileResourceSerializerTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/common/LinkedUserProfileResourceSerializerTest.java
index 6a7ebb175d136027b76138fa4d0c6aea6544108c..7c4ad67db9c5d2d9b654f22847e24eeb7d68742c 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/common/LinkedUserProfileResourceSerializerTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/common/LinkedUserProfileResourceSerializerTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch den
+ * Copyright (C) 2025 Das Land Schleswig-Holstein vertreten durch den
  * Ministerpräsidenten des Landes Schleswig-Holstein
  * Staatskanzlei
  * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
@@ -26,46 +26,191 @@ package de.ozgcloud.alfa.common;
 import static org.assertj.core.api.Assertions.*;
 import static org.mockito.Mockito.*;
 
-import org.junit.jupiter.api.DisplayName;
+import java.util.List;
+import java.util.UUID;
+
+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.Captor;
 import org.mockito.Mock;
-import org.springframework.context.ApplicationContext;
-import org.springframework.core.env.Environment;
 
-import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.JsonGenerator;
 import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializerProvider;
 
+import de.ozgcloud.alfa.common.user.UserId;
+import de.ozgcloud.alfa.common.user.UserManagerUrlProvider;
 import de.ozgcloud.alfa.common.user.UserProfileTestFactory;
+import lombok.SneakyThrows;
 
 class LinkedUserProfileResourceSerializerTest {
-	@DisplayName("Test the json serilization of linked user profile resource annotations")
+
+	private static final LinkedUserProfileResource ANNOTATION = getAnnotation();
+
+	@Mock
+	private UserManagerUrlProvider userManagerUrlProvider;
+
+	private LinkedUserProfileResourceSerializer serializer;
+
+	@BeforeEach
+	void init() {
+		serializer = LinkedUserProfileResourceSerializer.createForAnnotatedField(userManagerUrlProvider, ANNOTATION);
+	}
+
 	@Nested
-	class TestSerialization {
-		private static final String HTTP_LOCALHOST = "http://localhost/";
-		private static final String API_TEMPLATE = "api/profile/%s";
-		private static final String API_PATH = "api/profile/";
+	class TestSerialize {
 
-		private UserProfileUrlProvider provider = new UserProfileUrlProvider();
+		private static final UserId USER_ID = UserId.from(UUID.randomUUID());
+		private static final UserId USER_ID_2 = UserId.from(UUID.randomUUID());
 
 		@Mock
-		private ApplicationContext context;
+		private JsonGenerator generator;
 		@Mock
-		private Environment env;
+		private SerializerProvider serializerProvider;
+		@Captor
+		private ArgumentCaptor<Object> writtenObjectCaptor;
+
+		@Nested
+		class OnUrlIsConfigured {
+
+			private static final String HTTP_LOCALHOST = "http://localhost/";
+			private static final String API_TEMPLATE = "api/profile/%s";
+			private static final String API_PATH = "api/profile/";
+
+			@BeforeEach
+			void init() {
+				when(userManagerUrlProvider.isConfiguredForUserProfile()).thenReturn(true);
+				when(userManagerUrlProvider.getUserProfileTemplate()).thenReturn(HTTP_LOCALHOST + API_TEMPLATE);
+			}
+
+			@Nested
+			class OnSingularValue {
+
+				@SneakyThrows
+				@Test
+				void shouldSerializeToUrl() {
+					serializeSingleValue();
+
+					verify(generator).writeObject(writtenObjectCaptor.capture());
+					assertThat(writtenObjectCaptor.getValue()).isEqualTo(expectedUrl(USER_ID));
+				}
+			}
+
+			@Nested
+			class OnCollection {
+
+				@SneakyThrows
+				@Test
+				void shouldWriteStartArray() {
+					serializeCollection();
+
+					verify(generator).writeStartArray();
+				}
+
+				@SneakyThrows
+				@Test
+				void shouldSerializeToUrls() {
+					serializeCollection();
+
+					verify(generator, times(2)).writeObject(writtenObjectCaptor.capture());
+					assertThat(writtenObjectCaptor.getAllValues()).containsExactly(expectedUrl(USER_ID), expectedUrl(USER_ID_2));
+				}
+
+				@SneakyThrows
+				@Test
+				void shouldWriteEndArray() {
+					serializeCollection();
+
+					verify(generator).writeEndArray();
+				}
+			}
 
-		@Test
-		void shouldSerialize() throws JsonProcessingException {
-			when(env.getProperty(UserProfileUrlProvider.URL_ROOT_KEY)).thenReturn(HTTP_LOCALHOST);
-			when(env.getProperty(UserProfileUrlProvider.USER_PROFILES_TEMPLATE_KEY)).thenReturn(API_TEMPLATE);
-			when(context.getEnvironment()).thenReturn(env);
-			provider.setApplicationContext(context);
+			private String expectedUrl(UserId id) {
+				return HTTP_LOCALHOST + API_PATH + id.toString();
+			}
+		}
+
+		@Nested
+		class OnUriIsNotConfigured {
+
+			@BeforeEach
+			void init() {
+				when(userManagerUrlProvider.isConfiguredForUserProfile()).thenReturn(false);
+			}
+
+			@Nested
+			class OnSingularValue {
+
+				@SneakyThrows
+				@Test
+				void shouldSerializeToString() {
+					serializeSingleValue();
+
+					verify(generator).writeObject(writtenObjectCaptor.capture());
+					assertThat(writtenObjectCaptor.getValue()).isEqualTo(USER_ID.toString());
+				}
+			}
+
+			@Nested
+			class OnCollection {
+
+				@SneakyThrows
+				@Test
+				void shouldWriteStartArray() {
+					serializeCollection();
+
+					verify(generator).writeStartArray();
+				}
+
+				@SneakyThrows
+				@Test
+				void shouldSerializeToUrls() {
+					serializeCollection();
 
-			var testObj = new LinkedUserProfileResourceTestObject(UserProfileTestFactory.ID);
+					verify(generator, times(2)).writeObject(writtenObjectCaptor.capture());
+					assertThat(writtenObjectCaptor.getAllValues()).containsExactly(USER_ID.toString(), USER_ID_2.toString());
+				}
 
-			String serialized = new ObjectMapper().writeValueAsString(testObj);
+				@SneakyThrows
+				@Test
+				void shouldWriteEndArray() {
+					serializeCollection();
 
-			assertThat(serialized).isEqualTo("{\"id\":\"" + HTTP_LOCALHOST + API_PATH + UserProfileTestFactory.ID.toString() + "\"}");
+					verify(generator).writeEndArray();
+				}
+			}
 		}
 
+		@Nested
+		class OnCreatedImplicitlyByObjectMapper {
+
+			@SneakyThrows
+			@Test
+			void shouldSerializeToString() {
+				var objectMapper = new ObjectMapper();
+
+				var serialized = objectMapper.writeValueAsString(new LinkedUserProfileResourceTestObject(UserProfileTestFactory.ID));
+
+				assertThat(serialized).isEqualTo("{\"id\":\"" + UserProfileTestFactory.ID.toString() + "\"}");
+			}
+		}
+
+		@SneakyThrows
+		private void serializeSingleValue() {
+			serializer.serialize(USER_ID, generator, serializerProvider);
+		}
+
+		@SneakyThrows
+		private void serializeCollection() {
+			serializer.serialize(List.of(USER_ID, USER_ID_2), generator, serializerProvider);
+		}
+	}
+
+	@SneakyThrows
+	private static LinkedUserProfileResource getAnnotation() {
+		var idField = LinkedUserProfileResourceTestObject.class.getDeclaredField("id");
+		return idField.getDeclaredAnnotation(LinkedUserProfileResource.class);
 	}
 }
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/common/ModelBuilderTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/common/ModelBuilderTest.java
deleted file mode 100644
index 8b32ab174485e75e66ed4d3ad7a84bd2aacd77dc..0000000000000000000000000000000000000000
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/common/ModelBuilderTest.java
+++ /dev/null
@@ -1,166 +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.common;
-
-import static org.assertj.core.api.Assertions.*;
-import static org.mockito.Mockito.*;
-
-import java.util.UUID;
-
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.DisplayName;
-import org.junit.jupiter.api.Nested;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.NullAndEmptySource;
-import org.mockito.Mock;
-import org.springframework.context.ApplicationContext;
-import org.springframework.core.env.Environment;
-import org.springframework.web.bind.annotation.RequestMapping;
-
-import lombok.Builder;
-
-class ModelBuilderTest {
-
-	@DisplayName("Add link by annotation if missing")
-	@Nested
-	class TestAddLinkByAnnotationIfMissing {
-
-		private static final String USER_MANAGER_URL = "http://localhost";
-		private static final String USER_MANAGER_PROFILE_TEMPLATE = "/api/profile/%s";
-
-		private UserProfileUrlProvider provider = new UserProfileUrlProvider();
-
-		@Mock
-		private ApplicationContext context;
-		@Mock
-		private Environment env;
-
-		private TestEntity entity = TestEntityTestFactory.create();
-
-		@BeforeEach
-		void mockEnvironment() {
-			when(env.getProperty(UserProfileUrlProvider.URL_ROOT_KEY)).thenReturn(USER_MANAGER_URL);
-			when(env.getProperty(UserProfileUrlProvider.USER_PROFILES_TEMPLATE_KEY)).thenReturn(USER_MANAGER_PROFILE_TEMPLATE);
-			when(context.getEnvironment()).thenReturn(env);
-
-			provider.setApplicationContext(context);
-		}
-
-		@Test
-		void shouldHaveAddLinkByLinkedResource() {
-			var model = ModelBuilder.fromEntity(entity).buildModel();
-
-			assertThat(model.getLink(TestController.FILE_REL).get().getHref()).isEqualTo(TestController.PATH + "/" + TestEntityTestFactory.FILE);
-		}
-
-		@Test
-		void shouldHaveAddLinkByLinkedUserProfileResource() {
-			var model = ModelBuilder.fromEntity(entity).buildModel();
-
-			assertThat(model.getLink(TestController.USER_REL).get().getHref())
-					.isEqualTo(String.format(USER_MANAGER_URL + USER_MANAGER_PROFILE_TEMPLATE, TestEntityTestFactory.USER));
-		}
-
-		@ParameterizedTest
-		@NullAndEmptySource
-		void shouldNotAddLinkByLinkedRessourceIfFieldValueIsNotSet(String fileId) {
-			var model = ModelBuilder.fromEntity(TestEntityTestFactory.createBuilder().file(fileId).build()).buildModel();
-
-			assertThat(model.getLink(TestController.FILE_REL)).isEmpty();
-		}
-	}
-
-	@DisplayName("if usermanager is not configured")
-	@Nested
-	class TestNotAddLinkByAnnotationIfNotConfigured {
-
-		private UserProfileUrlProvider provider = new UserProfileUrlProvider();
-
-		@Mock
-		private ApplicationContext context;
-		@Mock
-		private Environment env;
-
-		private TestEntity entity = TestEntityTestFactory.create();
-
-		@BeforeEach
-		void mockEnvironment() {
-			when(env.getProperty(UserProfileUrlProvider.URL_ROOT_KEY)).thenReturn(null);
-			when(context.getEnvironment()).thenReturn(env);
-
-			provider.setApplicationContext(context);
-		}
-
-		@Test
-		void shouldHaveAddLinkByLinkedResource() {
-			var model = ModelBuilder.fromEntity(entity).buildModel();
-
-			assertThat(model.getLink(TestController.FILE_REL).get().getHref()).isEqualTo(TestController.PATH + "/" + TestEntityTestFactory.FILE);
-		}
-
-		@Test
-		void shouldNotHaveLinkAddByLinkedUserProfileAnnotation() {
-			var model = ModelBuilder.fromEntity(entity).buildModel();
-
-			assertThat(model.getLink(TestController.USER_REL)).isNotPresent();
-		}
-	}
-}
-
-@Builder
-class TestEntity {
-
-	@LinkedResource(controllerClass = TestController.class)
-	private String file;
-
-	@LinkedUserProfileResource
-	private String user;
-}
-
-@RequestMapping(TestController.PATH)
-class TestController {
-
-	static final String PATH = "/api/test";
-
-	static final String USER_REL = "user";
-	static final String FILE_REL = "file";
-
-}
-
-class TestEntityTestFactory {
-
-	static final String USER = UUID.randomUUID().toString();
-	static final String FILE = UUID.randomUUID().toString();
-
-	public static TestEntity create() {
-		return createBuilder().build();
-	}
-
-	public static TestEntity.TestEntityBuilder createBuilder() {
-		return TestEntity.builder()
-				.file(FILE)
-				.user(USER);
-	}
-}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/common/TestEntity.java b/alfa-service/src/test/java/de/ozgcloud/alfa/common/TestEntity.java
new file mode 100644
index 0000000000000000000000000000000000000000..7e44ba5b2fdddd2579fe0ec6a74f66498668bd7b
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/common/TestEntity.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2025 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.common;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.UUID;
+
+import org.springframework.hateoas.CollectionModel;
+import org.springframework.hateoas.EntityModel;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import de.ozgcloud.alfa.common.user.UserId;
+import lombok.Builder;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+
+@Builder
+@Getter
+@EqualsAndHashCode
+class TestEntity {
+
+	@LinkedResource(controllerClass = TestIdController.class)
+	private String linkedResource;
+	@LinkedResource(controllerClass = TestIdController.class)
+	private String testId;
+
+	private String foo;
+	private Collection<String> collectionField;
+	private String[] arrayField;
+
+	@LinkedUserProfileResource
+	private UserId user;
+
+	@LinkedUserProfileResource
+	private String differentUserId;
+}
+
+@RequestMapping(TestEntityController.PATH)
+@RestController
+class TestEntityController {
+
+	static final String PATH = "/api/entity";
+	static final String GET_ALL = "/all";
+
+	@GetMapping
+	public EntityModel<TestEntity> getTestEntity() {
+		return EntityModel.of(TestEntityTestFactory.create());
+	}
+
+	@GetMapping(GET_ALL)
+	public CollectionModel<EntityModel<TestEntity>> getAll() {
+		return CollectionModel.of(List.of(EntityModel.of(TestEntityTestFactory.create())));
+	}
+}
+
+@RequestMapping(TestIdController.PATH)
+class TestIdController {
+
+	static final String PATH = "/api/test";
+
+	static final String USER_REL = "user";
+	static final String DIFFERENT_USER_REL = "differentUser";
+	static final String ID_REL = "test";
+	static final String LINKED_RESOURCE_REL = "linkedResource";
+
+}
+
+class TestEntityTestFactory {
+
+	static final String USER = UUID.randomUUID().toString();
+	static final String DIFFERENT_USER_ID = UUID.randomUUID().toString();
+	static final String ID = UUID.randomUUID().toString();
+	static final String LINKED_RESOURCE = UUID.randomUUID().toString();
+
+	public static TestEntity create() {
+		return createBuilder().build();
+	}
+
+	public static TestEntity.TestEntityBuilder createBuilder() {
+		return TestEntity.builder()
+				.testId(ID)
+				.linkedResource(LINKED_RESOURCE)
+				.user(UserId.from(USER))
+				.differentUserId(DIFFERENT_USER_ID)
+				.foo("bar");
+	}
+}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/common/UserProfileUrlProviderTestFactory.java b/alfa-service/src/test/java/de/ozgcloud/alfa/common/UserProfileUrlProviderTestFactory.java
deleted file mode 100644
index 9498db2b673db8e3d7e171e35a6c87871913aded..0000000000000000000000000000000000000000
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/common/UserProfileUrlProviderTestFactory.java
+++ /dev/null
@@ -1,45 +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.common;
-
-import static org.mockito.Mockito.*;
-
-import org.springframework.context.ApplicationContext;
-import org.springframework.core.env.Environment;
-
-public class UserProfileUrlProviderTestFactory {
-	public static final String ROOT_URL = "https://localhost";
-	public static final String USER_PROFILES_API_PATH = "/api/userProfiles/";
-	public static final String OZGCLOUD_USER_MANAGER_PROFILE_TEMPLATE = "ozgcloud.user-manager.profile-template";
-	public static final String OZGCLOUD_USER_MANAGER_URL = "ozgcloud.user-manager.url";
-
-	public static void initUserProfileUrlProvider(UserProfileUrlProvider urlProvider) {
-		ApplicationContext context = mock(ApplicationContext.class);
-		Environment environment = mock(Environment.class);
-		when(environment.getProperty(OZGCLOUD_USER_MANAGER_URL)).thenReturn(ROOT_URL);
-		when(environment.getProperty(OZGCLOUD_USER_MANAGER_PROFILE_TEMPLATE)).thenReturn(USER_PROFILES_API_PATH + "%s");
-		when(context.getEnvironment()).thenReturn(environment);
-		urlProvider.setApplicationContext(context);
-	}
-}
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
index f53d75a581b511b3cdc0f6775f24077e4bd35a58..9d6fd0b4c431526efa00e2018cf8e9851ffd6358 100644
--- 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
@@ -1,3 +1,26 @@
+/*
+ * Copyright (C) 2025 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.common.attacheditem;
 
 import static org.assertj.core.api.Assertions.*;
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/common/binaryfile/BinaryFileModelAssemblerTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/common/binaryfile/BinaryFileModelAssemblerTest.java
index 5696644059884d034dde92770ab23f5025a25e8e..edfbc4ca3b81e05badab3893425974cc00a48ad2 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/common/binaryfile/BinaryFileModelAssemblerTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/common/binaryfile/BinaryFileModelAssemblerTest.java
@@ -36,7 +36,7 @@ import de.ozgcloud.alfa.common.file.OzgFileTestFactory;
 
 class BinaryFileModelAssemblerTest {
 
-	@InjectMocks // NOSONAR
+	@InjectMocks
 	private BinaryFileModelAssembler modelAssembler;
 
 	@Nested
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/common/command/CommandLinkedResourceTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/common/command/CommandLinkedResourceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..3c58a4efce2dc8aaddca341f05d5a61d16a52621
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/common/command/CommandLinkedResourceTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2025 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.common.command;
+
+import static org.assertj.core.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.springframework.hateoas.EntityModel;
+import org.springframework.hateoas.Link;
+
+import com.thedeanda.lorem.LoremIpsum;
+
+import de.ozgcloud.alfa.common.LinkedResourceProcessor;
+import de.ozgcloud.alfa.common.user.UserId;
+import de.ozgcloud.alfa.common.user.UserManagerUrlProvider;
+import de.ozgcloud.alfa.common.user.UserProfileTestFactory;
+
+class CommandLinkedResourceTest {
+
+	@InjectMocks
+	private LinkedResourceProcessor<Command> processor;
+	@Mock
+	private UserManagerUrlProvider userManagerUrlProvider;
+
+	@Nested
+	class TestEntityModelProcessing {
+		private static final String CREATED_BY = "createdBy";
+		private static final String ROOT_URL = LoremIpsum.getInstance().getUrl();
+		private static final String USER_PROFILES_API_PATH = "/api/user-profiles/";
+
+		@Test
+		void shouldHaveCreatedByLink() {
+			when(userManagerUrlProvider.getUserProfileTemplate()).thenReturn(ROOT_URL + USER_PROFILES_API_PATH + "%s");
+
+			var model = processor.process(EntityModel.of(CommandTestFactory.create()));
+
+			assertThat(model.getLink(CREATED_BY)).isPresent().get().extracting(Link::getHref)
+					.isEqualTo(ROOT_URL + USER_PROFILES_API_PATH + UserProfileTestFactory.ID);
+		}
+
+		@Test
+		void shouldNotHaveCreatedByLinkForSystemUser() {
+			var systemUser = UserId.from("system-" + LoremIpsum.getInstance().getWords(1));
+			var commandBySystemUser = CommandTestFactory.createBuilder()
+					.createdBy(systemUser)
+					.build();
+
+			var model = processor.process(EntityModel.of(commandBySystemUser));
+
+			assertThat(model.getLink(CREATED_BY)).isNotPresent();
+		}
+
+		@Test
+		void shouldNotHaveCreatedByLinkOnNullValue() {
+			var model = processor.process(EntityModel.of(CommandTestFactory.createBuilder().createdBy(null).build()));
+
+			assertThat(model.getLink(CREATED_BY)).isNotPresent();
+		}
+	}
+}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/common/command/CommandModelAssemblerTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/common/command/CommandModelAssemblerTest.java
index 01567b0ff4b2aadac73038fcec78b3ba327a479c..cdc84e3c2bb10c6620376542e304399ff8ea0cfb 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/common/command/CommandModelAssemblerTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/common/command/CommandModelAssemblerTest.java
@@ -27,9 +27,7 @@ import static de.ozgcloud.alfa.common.command.CommandModelAssembler.*;
 import static de.ozgcloud.alfa.common.command.CommandTestFactory.*;
 import static org.assertj.core.api.Assertions.*;
 import static org.junit.jupiter.api.Assertions.*;
-import static org.mockito.Mockito.*;
 
-import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
@@ -38,13 +36,10 @@ import org.junit.jupiter.params.provider.EnumSource;
 import org.junit.jupiter.params.provider.EnumSource.Mode;
 import org.junit.jupiter.params.provider.ValueSource;
 import org.mockito.InjectMocks;
-import org.springframework.context.ApplicationContext;
-import org.springframework.core.env.Environment;
 import org.springframework.hateoas.EntityModel;
 import org.springframework.hateoas.IanaLinkRelations;
 import org.springframework.hateoas.Link;
 
-import de.ozgcloud.alfa.common.UserProfileUrlProvider;
 import de.ozgcloud.alfa.vorgang.VorgangHeaderTestFactory;
 
 class CommandModelAssemblerTest {
@@ -54,13 +49,6 @@ class CommandModelAssemblerTest {
 	@InjectMocks
 	private CommandModelAssembler modelAssembler;
 
-	@BeforeEach
-	void init() {
-		var applicationContext = mock(ApplicationContext.class);
-		lenient().when(applicationContext.getEnvironment()).thenReturn(mock(Environment.class));
-		new UserProfileUrlProvider().setApplicationContext(applicationContext);
-	}
-
 	@Test
 	void shouldHaveSelfLink() {
 		var model = modelAssembler.toModel(CommandTestFactory.create());
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/export/ExportVorgangProcessorTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/export/ExportVorgangProcessorTest.java
index 756653dc959487e3fcc444bc110304ca08477e4e..d522973a92571d1565835336bd1432f88b0f1176 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/export/ExportVorgangProcessorTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/export/ExportVorgangProcessorTest.java
@@ -23,11 +23,9 @@
  */
 package de.ozgcloud.alfa.export;
 
-import static de.ozgcloud.alfa.common.UserProfileUrlProviderTestFactory.*;
 import static org.assertj.core.api.Assertions.*;
 import static org.mockito.Mockito.*;
 
-import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
@@ -39,7 +37,6 @@ import org.springframework.hateoas.EntityModel;
 import org.springframework.hateoas.Link;
 import org.springframework.hateoas.UriTemplate;
 
-import de.ozgcloud.alfa.common.UserProfileUrlProvider;
 import de.ozgcloud.alfa.common.command.CommandController.CommandByRelationController;
 import de.ozgcloud.alfa.vorgang.Vorgang.VorgangStatus;
 import de.ozgcloud.alfa.vorgang.VorgangController;
@@ -56,16 +53,9 @@ class ExportVorgangProcessorTest {
 	@Mock
 	private VorgangController vorgangController;
 
-	private final UserProfileUrlProvider urlProvider = new UserProfileUrlProvider();
-
 	@Nested
 	class TestProcess {
 
-		@BeforeEach
-		void init() {
-			initUserProfileUrlProvider(urlProvider);
-		}
-
 		@DisplayName("Export link")
 		@Nested
 		class TestExportLink {
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/forwarding/ForwardingVorgangWithEingangProcessorTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/forwarding/ForwardingVorgangWithEingangProcessorTest.java
index 15be150ccf28cc8cf1248f727ade96dcbc29e9e5..e1da1b36f786f0186bbf35ed53b12cbb398b94a8 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/forwarding/ForwardingVorgangWithEingangProcessorTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/forwarding/ForwardingVorgangWithEingangProcessorTest.java
@@ -1,3 +1,26 @@
+/*
+ * Copyright (C) 2025 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.forwarding;
 
 import static org.assertj.core.api.Assertions.*;
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/historie/HistorieModelAssemblerTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/historie/HistorieModelAssemblerTest.java
index 76c9affa1efe0cbe797641e39455b5fed4ee50f6..4274b00e92a0b3f08d6981d6ada6469d1e308940 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/historie/HistorieModelAssemblerTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/historie/HistorieModelAssemblerTest.java
@@ -23,7 +23,6 @@
  */
 package de.ozgcloud.alfa.historie;
 
-import static de.ozgcloud.alfa.common.UserProfileUrlProviderTestFactory.*;
 import static org.assertj.core.api.Assertions.*;
 import static org.mockito.Mockito.*;
 
@@ -37,18 +36,12 @@ import org.mockito.Mock;
 import org.springframework.hateoas.IanaLinkRelations;
 import org.springframework.hateoas.Link;
 
-import com.thedeanda.lorem.LoremIpsum;
-
-import de.ozgcloud.alfa.common.UserProfileUrlProvider;
 import de.ozgcloud.alfa.common.command.CommandTestFactory;
-import de.ozgcloud.alfa.common.user.UserId;
 import de.ozgcloud.alfa.common.user.UserManagerUrlProvider;
 import de.ozgcloud.alfa.common.user.UserProfileTestFactory;
 
 class HistorieModelAssemblerTest {
 
-	private static final String CREATED_BY = "createdBy";
-
 	@InjectMocks
 	private HistorieModelAssembler modelAssembler;
 	@Mock
@@ -56,12 +49,8 @@ class HistorieModelAssemblerTest {
 
 	private static final String COMMAND_SINGLE_PATH = "/api/histories/" + CommandTestFactory.ID;
 
-	private UserProfileUrlProvider urlProvider = new UserProfileUrlProvider();
-
 	@Test
 	void shouldHaveSelfLink() {
-		initUserProfileUrlProvider(urlProvider);
-
 		var model = modelAssembler.toModel(CommandTestFactory.create());
 
 		assertThat(model.getLink(IanaLinkRelations.SELF)).isPresent().get().extracting(Link::getHref).isEqualTo(COMMAND_SINGLE_PATH);
@@ -121,36 +110,4 @@ class HistorieModelAssemblerTest {
 		}
 	}
 
-	@DisplayName("createdBy Link")
-	@Nested
-	class TestCreatedByLink {
-		@Test
-		void shouldExistingAtUser() {
-			initUserProfileUrlProvider(urlProvider);
-
-			var model = modelAssembler.toModel(CommandTestFactory.create());
-
-			assertThat(model.getLink(CREATED_BY)).isPresent().get().extracting(Link::getHref)
-					.isEqualTo(ROOT_URL + USER_PROFILES_API_PATH + UserProfileTestFactory.ID);
-		}
-
-		@Test
-		void shouldNotExistForSystemUser() {
-			var systemUser = UserId.from("system-" + LoremIpsum.getInstance().getWords(1));
-			var commandBySystemUser = CommandTestFactory.createBuilder()
-					.createdBy(systemUser)
-					.build();
-
-			var model = modelAssembler.toModel(commandBySystemUser);
-
-			assertThat(model.getLink(CREATED_BY)).isNotPresent();
-		}
-
-		@Test
-		void shouldNotBePresentOnNullValue() {
-			var model = modelAssembler.toModel(CommandTestFactory.createBuilder().createdBy(null).build());
-
-			assertThat(model.getLink(CREATED_BY)).isNotPresent();
-		}
-	}
 }
\ 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
index c67a8dfc3b86ab32f37c7d889eafb62cb3787ec0..97c538ba2ff118213d446b37d36b59b7111e5bc2 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/kommentar/KommentarHistorieProcessorTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/kommentar/KommentarHistorieProcessorTest.java
@@ -1,3 +1,26 @@
+/*
+ * Copyright (C) 2025 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.kommentar;
 
 import static org.assertj.core.api.Assertions.*;
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/kommentar/KommentarLinkedResourceTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/kommentar/KommentarLinkedResourceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..06b1efabedbcda2fc846928f84e01af00c5a4d50
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/kommentar/KommentarLinkedResourceTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2025 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.kommentar;
+
+import static org.assertj.core.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.springframework.hateoas.EntityModel;
+import org.springframework.hateoas.Link;
+
+import com.thedeanda.lorem.LoremIpsum;
+
+import de.ozgcloud.alfa.common.LinkedResourceProcessor;
+import de.ozgcloud.alfa.common.user.UserManagerUrlProvider;
+
+class KommentarLinkedResourceTest {
+
+	@InjectMocks
+	private LinkedResourceProcessor<Kommentar> processor;
+	@Mock
+	private UserManagerUrlProvider userManagerUrlProvider;
+
+	@Nested
+	class TestEntityModelProcessing {
+		private static final String REL_CREATED_BY = "createdBy";
+		private static final String USER_MANAGER_URL = LoremIpsum.getInstance().getUrl();
+
+		@Test
+		void shouldHaveCreatedByLink() {
+			when(userManagerUrlProvider.getUserProfileTemplate()).thenReturn(USER_MANAGER_URL + "%s");
+
+			var model = processor.process(EntityModel.of(KommentarTestFactory.create()));
+
+			assertThat(model.getLink(REL_CREATED_BY)).isPresent().get().extracting(Link::getHref)
+					.isEqualTo(USER_MANAGER_URL + KommentarTestFactory.CREATED_BY);
+		}
+	}
+}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/kommentar/KommentarModelAssemblerTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/kommentar/KommentarModelAssemblerTest.java
index 882b6eab5e7d2b9a7d5e393b8797bed66eb28c30..7ddb61920d73ac7089862b76a13e45a5d217aac7 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/kommentar/KommentarModelAssemblerTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/kommentar/KommentarModelAssemblerTest.java
@@ -23,7 +23,6 @@
  */
 package de.ozgcloud.alfa.kommentar;
 
-import static de.ozgcloud.alfa.common.UserProfileUrlProviderTestFactory.*;
 import static org.assertj.core.api.Assertions.*;
 import static org.mockito.Mockito.*;
 
@@ -41,8 +40,7 @@ import org.springframework.hateoas.IanaLinkRelations;
 import org.springframework.hateoas.Link;
 import org.springframework.hateoas.server.EntityLinks;
 
-import de.ozgcloud.alfa.common.UserProfileUrlProvider;
-import de.ozgcloud.alfa.common.UserProfileUrlProviderTestFactory;
+import de.ozgcloud.alfa.common.user.UserManagerUrlProvider;
 import de.ozgcloud.alfa.vorgang.VorgangController;
 import de.ozgcloud.alfa.vorgang.VorgangHeaderTestFactory;
 import de.ozgcloud.alfa.vorgang.VorgangWithEingang;
@@ -50,10 +48,7 @@ import de.ozgcloud.alfa.vorgang.VorgangWithEingangTestFactory;
 
 class KommentarModelAssemblerTest {
 
-	private final String PATH = KommentarController.KOMMENTAR_PATH + "/";
-	private static final String REL_CREATED_BY = "createdBy";
-	private static final String USER_MANAGER_URL = UserProfileUrlProviderTestFactory.ROOT_URL
-			+ UserProfileUrlProviderTestFactory.USER_PROFILES_API_PATH;
+	private static final String PATH = KommentarController.KOMMENTAR_PATH + "/";
 
 	@Spy
 	@InjectMocks
@@ -97,6 +92,9 @@ class KommentarModelAssemblerTest {
 
 		private final VorgangWithEingang vorgang = VorgangWithEingangTestFactory.create();
 
+		@Mock
+		private UserManagerUrlProvider userManagerUrlProvider;
+
 		@Test
 		void shouldHaveSelfLink() {
 			var link = buildModel().getLink(IanaLinkRelations.SELF);
@@ -124,17 +122,6 @@ class KommentarModelAssemblerTest {
 			assertThat(model.getLink(KommentarModelAssembler.REL_EDIT)).isEmpty();
 		}
 
-		@Test
-		void shouldHaveCreatedByLink() {
-			UserProfileUrlProvider urlProvider = new UserProfileUrlProvider();
-			initUserProfileUrlProvider(urlProvider);
-
-			var model = buildModel();
-
-			assertThat(model.getLink(REL_CREATED_BY)).isPresent().get().extracting(Link::getHref)
-					.isEqualTo(USER_MANAGER_URL + KommentarTestFactory.CREATED_BY);
-		}
-
 		@Test
 		void shouldHaveAttachmentsLink() {
 			var kommentar = KommentarTestFactory.create();
@@ -160,7 +147,6 @@ class KommentarModelAssemblerTest {
 	@Nested
 	class TestLinksOnCollectionModel {
 
-		private final UserProfileUrlProvider urlProvider = new UserProfileUrlProvider();
 		private final VorgangWithEingang vorgang = VorgangWithEingangTestFactory.create();
 
 		@BeforeEach
@@ -170,7 +156,6 @@ class KommentarModelAssemblerTest {
 
 		@Test
 		void shouldBuildModel() {
-			initUserProfileUrlProvider(urlProvider);
 			var kommentar = KommentarTestFactory.create();
 			var vorgang = VorgangWithEingangTestFactory.create();
 			when(vorgangController.getVorgang(VorgangHeaderTestFactory.ID)).thenReturn(vorgang);
@@ -182,8 +167,6 @@ class KommentarModelAssemblerTest {
 
 		@Test
 		void shouldLoadVorgang() {
-			initUserProfileUrlProvider(urlProvider);
-
 			modelAssembler.toCollectionModel(Collections.singleton(KommentarTestFactory.create()).stream(), VorgangHeaderTestFactory.ID);
 
 			verify(vorgangController).getVorgang(VorgangHeaderTestFactory.ID);
@@ -191,7 +174,6 @@ class KommentarModelAssemblerTest {
 
 		@Test
 		void shouldHaveCreateKommentarLink() {
-			initUserProfileUrlProvider(urlProvider);
 			when(vorgangController.isEditable(vorgang)).thenReturn(true);
 
 			var collectionModel = modelAssembler.toCollectionModel(Collections.singleton(KommentarTestFactory.create()).stream(),
@@ -206,7 +188,6 @@ class KommentarModelAssemblerTest {
 
 		@Test
 		void shouldNotHaveCreateKommentarLink() {
-			initUserProfileUrlProvider(urlProvider);
 			when(vorgangController.isEditable(vorgang)).thenReturn(false);
 
 			var collectionModel = modelAssembler.toCollectionModel(Collections.singleton(KommentarTestFactory.create()).stream(),
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungCommandProcessorTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungCommandProcessorTest.java
index e2024c879ace255ff4e5f74a0c4d2492dac29868..e108bfe27f65b0edda495a0f2496ef4b95a681a4 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungCommandProcessorTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungCommandProcessorTest.java
@@ -29,10 +29,10 @@ import static org.mockito.Mockito.*;
 
 import java.util.Optional;
 
-import org.junit.Test;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.EnumSource;
 import org.junit.jupiter.params.provider.EnumSource.Mode;
@@ -42,8 +42,6 @@ import org.mockito.Spy;
 import org.springframework.hateoas.EntityModel;
 import org.springframework.hateoas.Link;
 
-import de.ozgcloud.alfa.common.UserProfileUrlProvider;
-import de.ozgcloud.alfa.common.UserProfileUrlProviderTestFactory;
 import de.ozgcloud.alfa.common.attacheditem.VorgangAttachedItemTestFactory;
 import de.ozgcloud.alfa.common.command.Command;
 import de.ozgcloud.alfa.common.command.CommandOrder;
@@ -63,11 +61,6 @@ class LoeschAnforderungCommandProcessorTest {
 	@Nested
 	class TestProcess {
 
-		@BeforeEach
-		void mock() {
-			UserProfileUrlProviderTestFactory.initUserProfileUrlProvider(new UserProfileUrlProvider());
-		}
-
 		@DisplayName("on revokeable")
 		@Nested
 		class TestRevokeableCommand {
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungControllerTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungControllerTest.java
index a1d67f14c2f6c985fb1c0613cf00c71c86030202..b1a466fa645437424ae754aa470b0126ea93b4e6 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungControllerTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungControllerTest.java
@@ -23,7 +23,6 @@
  */
 package de.ozgcloud.alfa.loeschanforderung;
 
-import static de.ozgcloud.alfa.common.UserProfileUrlProviderTestFactory.*;
 import static org.mockito.Mockito.*;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@@ -38,7 +37,6 @@ import org.springframework.test.web.servlet.MockMvc;
 import org.springframework.test.web.servlet.ResultActions;
 import org.springframework.test.web.servlet.setup.MockMvcBuilders;
 
-import de.ozgcloud.alfa.common.UserProfileUrlProvider;
 import de.ozgcloud.alfa.common.errorhandling.ExceptionController;
 import de.ozgcloud.alfa.common.errorhandling.ProblemDetailMapper;
 import lombok.SneakyThrows;
@@ -91,8 +89,6 @@ class LoeschAnforderungControllerTest {
 
 		@Test
 		void shouldReturn200() throws Exception {
-			initUserProfileUrlProvider(new UserProfileUrlProvider());
-
 			var response = doRequest();
 
 			response.andExpect(status().isOk());
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
index 17ec36a7d571aa97572f9093ab8d8c4fdd835dde..d2ba1f87f6fd64e20a7ff56e2cf530b53e5cfccf 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungHistorieProcessorTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungHistorieProcessorTest.java
@@ -1,3 +1,26 @@
+/*
+ * Copyright (C) 2025 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.loeschanforderung;
 
 import static org.assertj.core.api.Assertions.*;
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungModelAssemblerTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungModelAssemblerTest.java
index c6bedb3645c210635be3d0da465c48c386b6aa0a..3d45e974f0906f977b4304a9cffcdfcffa8f1522 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungModelAssemblerTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungModelAssemblerTest.java
@@ -23,12 +23,10 @@
  */
 package de.ozgcloud.alfa.loeschanforderung;
 
-import static de.ozgcloud.alfa.common.UserProfileUrlProviderTestFactory.*;
 import static org.assertj.core.api.Assertions.*;
 import static org.mockito.ArgumentMatchers.*;
 import static org.mockito.Mockito.*;
 
-import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
@@ -39,8 +37,6 @@ import org.springframework.hateoas.IanaLinkRelations;
 import org.springframework.hateoas.Link;
 import org.springframework.web.util.UriTemplate;
 
-import de.ozgcloud.alfa.common.UserProfileUrlProvider;
-
 class LoeschAnforderungModelAssemblerTest {
 
 	@InjectMocks
@@ -48,11 +44,6 @@ class LoeschAnforderungModelAssemblerTest {
 	@Mock
 	private LoeschAnforderungService loeschAnforderungService;
 
-	@BeforeEach
-	void init() {
-		initUserProfileUrlProvider(new UserProfileUrlProvider());
-	}
-
 	@Nested
 	@DisplayName("Build resource")
 	class TestToModel {
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungVorgangProcessorTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungVorgangProcessorTest.java
index a8ddd9361ca3b7c887d1ef2047010303d47a9fe1..b332d2f57b0b32d9ae0b599efa8c11a2e0c53a31 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungVorgangProcessorTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungVorgangProcessorTest.java
@@ -23,7 +23,6 @@
  */
 package de.ozgcloud.alfa.loeschanforderung;
 
-import static de.ozgcloud.alfa.common.UserProfileUrlProviderTestFactory.*;
 import static org.assertj.core.api.Assertions.*;
 import static org.mockito.ArgumentMatchers.*;
 import static org.mockito.Mockito.*;
@@ -43,7 +42,6 @@ import org.mockito.Spy;
 import org.springframework.hateoas.EntityModel;
 import org.springframework.hateoas.Link;
 
-import de.ozgcloud.alfa.common.UserProfileUrlProvider;
 import de.ozgcloud.alfa.common.attacheditem.VorgangAttachedItemTestFactory;
 import de.ozgcloud.alfa.common.user.CurrentUserService;
 import de.ozgcloud.alfa.common.user.UserRole;
@@ -76,8 +74,6 @@ class LoeschAnforderungVorgangProcessorTest {
 
 			@BeforeEach
 			void mock() {
-				initUserProfileUrlProvider(new UserProfileUrlProvider());
-
 				when(loeschAnforderungService.findLoeschAnforderung(VorgangHeaderTestFactory.ID)).thenReturn(
 						Optional.of(VorgangAttachedItemTestFactory.create()));
 			}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/postfach/PostfachMailModelAssemblerTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/postfach/PostfachMailModelAssemblerTest.java
index 5c8e2874053681408887e2b97e6157456e3c714c..091797403adabd9734b63866c28185033da4e0b7 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/postfach/PostfachMailModelAssemblerTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/postfach/PostfachMailModelAssemblerTest.java
@@ -48,6 +48,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
 import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
 
+import de.ozgcloud.alfa.common.LinkedResourceProcessor;
 import de.ozgcloud.alfa.common.user.UserId;
 import de.ozgcloud.alfa.common.user.UserManagerUrlProvider;
 import de.ozgcloud.alfa.postfach.PostfachMail.Direction;
@@ -69,6 +70,8 @@ class PostfachMailModelAssemblerTest {
 	private UserManagerUrlProvider userManagerUrlProvider;
 	@Mock
 	private VorgangController vorgangController;
+	@Mock
+	private LinkedResourceProcessor<PostfachMail> linkedResourceProcessor;
 
 	@Nested
 	class TestToModel {
@@ -352,6 +355,14 @@ class PostfachMailModelAssemblerTest {
 		private final Stream<PostfachMail> mails = Stream.of(postfachMail);
 		private final VorgangWithEingang vorgang = VorgangWithEingangTestFactory.create();
 		private final PostfachSettings postfachSettings = PostfachSettingsTestFactory.create();
+		private final EntityModel<PostfachMail> entityModel = EntityModel.of(postfachMail);
+		private final EntityModel<PostfachMail> processedEntityModel = EntityModel.of(postfachMail, Link.of("dummy"));
+
+		@BeforeEach
+		void mock() {
+			doReturn(entityModel).when(modelAssembler).toModel(any());
+			when(linkedResourceProcessor.process(entityModel)).thenReturn(processedEntityModel);
+		}
 
 		@Test
 		void shouldHavePostfachAsContent() {
@@ -376,15 +387,21 @@ class PostfachMailModelAssemblerTest {
 			verify(modelAssembler).toModel(postfachMail);
 		}
 
+		@Test
+		void shouldCallLinkedResourceProcessor() {
+			callModelAssembler();
+
+			verify(linkedResourceProcessor).process(entityModel);
+		}
+
 		@Test
 		@SneakyThrows
 		void shouldContainPostfachMails() {
 			var objectMapper = new ObjectMapper().registerModules(new JavaTimeModule(), new Jdk8Module());
-			doReturn(EntityModel.of(postfachMail)).when(modelAssembler).toModel(postfachMail);
 
 			var model = callModelAssembler();
 
-			assertThat(objectMapper.writeValueAsString(model)).contains(objectMapper.writeValueAsString(EntityModel.of(postfachMail)));
+			assertThat(objectMapper.writeValueAsString(model)).contains(objectMapper.writeValueAsString(processedEntityModel));
 		}
 
 		private RepresentationModel<EntityModel<PostfachSettings>> callModelAssembler() {
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
index 300249da5973529dc8243ec16debb14e007a03a4..668aa45f6d57fc702f00604804205fa03f32d5e5 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/postfach/PostfachNachrichtHistorieProcessorTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/postfach/PostfachNachrichtHistorieProcessorTest.java
@@ -1,3 +1,26 @@
+/*
+ * Copyright (C) 2025 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.postfach;
 
 import static org.assertj.core.api.Assertions.*;
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/GrpcLockTestFactory.java b/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/GrpcLockTestFactory.java
index b8f28d98535105c457b34f1c3d6b8ce4f2e56951..6aaa83ef9249a2faf054637e1c53388d3a079a60 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/GrpcLockTestFactory.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/GrpcLockTestFactory.java
@@ -1,3 +1,26 @@
+/*
+ * Copyright (C) 2025 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.vorgang;
 
 import de.ozgcloud.vorgang.vorgang.GrpcLock;
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/GrpcVorgangHeadTestFactory.java b/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/GrpcVorgangHeadTestFactory.java
index b11ce836e7bf43f9c4ff85bcc3d5d73a9a8886fa..ad8e6e25cda5137ba53df1ad1c3951483057a759 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/GrpcVorgangHeadTestFactory.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/GrpcVorgangHeadTestFactory.java
@@ -1,3 +1,26 @@
+/*
+ * Copyright (C) 2025 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.vorgang;
 
 import de.ozgcloud.vorgang.vorgang.GrpcVorgangHead;
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/VorgangControllerTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/VorgangControllerTest.java
index 77a63407f2c188a1a84653ffe35eb17bf1354cd1..609ea5ccf1b83f33ecb2db97b2f4ff90652d2470 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/VorgangControllerTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/VorgangControllerTest.java
@@ -42,8 +42,6 @@ import org.mockito.Captor;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.Spy;
-import org.springframework.context.ApplicationContext;
-import org.springframework.core.env.Environment;
 import org.springframework.hateoas.EntityModel;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.MediaType;
@@ -52,7 +50,6 @@ import org.springframework.test.web.servlet.assertj.MockMvcTester.MockMvcRequest
 import org.springframework.test.web.servlet.assertj.MvcTestResultAssert;
 import org.springframework.web.util.UriComponentsBuilder;
 
-import de.ozgcloud.alfa.common.UserProfileUrlProvider;
 import de.ozgcloud.alfa.common.clientattribute.ClientAttributeService;
 import de.ozgcloud.alfa.common.user.UserId;
 import de.ozgcloud.alfa.common.user.UserProfileTestFactory;
@@ -814,18 +811,10 @@ class VorgangControllerTest {
 	@Nested
 	class TestVorgangWithEingang {
 
-		private UserProfileUrlProvider urlProvider = new UserProfileUrlProvider();
-
 		@BeforeEach
 		void initTest() {
 			when(vorgangService.findVorgangWithEingang(any())).thenReturn(VorgangWithEingangTestFactory.create());
 			when(modelAssembler.toModel(any())).then(i -> EntityModel.of(i.getArgument(0)));
-
-			ApplicationContext context = mock(ApplicationContext.class);
-			Environment environment = mock(Environment.class);
-			when(environment.getProperty(anyString())).thenReturn("test/");
-			when(context.getEnvironment()).thenReturn(environment);
-			urlProvider.setApplicationContext(context);
 		}
 
 		@Test
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/VorgangModelAssemblerTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/VorgangModelAssemblerTest.java
index 94ae793fbbe99920ac5cb16dc8551675ecd9b93d..7daaae7e4675eaad6587961a5f42994787c3191d 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/VorgangModelAssemblerTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/VorgangModelAssemblerTest.java
@@ -23,8 +23,8 @@
  */
 package de.ozgcloud.alfa.vorgang;
 
-import static de.ozgcloud.alfa.common.UserProfileUrlProviderTestFactory.*;
 import static org.assertj.core.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.*;
 import static org.mockito.Mockito.*;
 
 import java.util.Collections;
@@ -44,11 +44,17 @@ import org.springframework.hateoas.EntityModel;
 import org.springframework.hateoas.IanaLinkRelations;
 import org.springframework.hateoas.Link;
 
-import de.ozgcloud.alfa.common.UserProfileUrlProvider;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+
+import de.ozgcloud.alfa.common.LinkedResourceProcessor;
 import de.ozgcloud.alfa.common.user.CurrentUserService;
 import de.ozgcloud.alfa.common.user.UserProfileTestFactory;
 import de.ozgcloud.alfa.common.user.UserRole;
+import de.ozgcloud.alfa.statistic.Statistic;
 import de.ozgcloud.alfa.statistic.StatisticTestFactory;
+import lombok.SneakyThrows;
 
 class VorgangModelAssemblerTest {
 
@@ -59,8 +65,8 @@ class VorgangModelAssemblerTest {
 	private CurrentUserService userService;
 	@Mock
 	private VorgangService vorgangService;
-
-	private UserProfileUrlProvider urlProvider = new UserProfileUrlProvider();
+	@Mock
+	private LinkedResourceProcessor<Vorgang> linkedResourceProcessor;
 
 	private static final int PAGE_SIZE = 100;
 
@@ -68,11 +74,6 @@ class VorgangModelAssemblerTest {
 	@Nested
 	class TestCollectionModel {
 
-		@BeforeEach
-		void prepareBuilder() {
-			initUserProfileUrlProvider(urlProvider);
-		}
-
 		@DisplayName("init model")
 		@Nested
 		class TestInitModel {
@@ -182,6 +183,54 @@ class VorgangModelAssemblerTest {
 		}
 	}
 
+	@Nested
+	class TestInitModel {
+
+		private static final Link DUMMY_LINK = Link.of("dummy");
+		private final VorgangHeader vorgangHeader = VorgangHeaderTestFactory.create();
+		private final Stream<VorgangHeader> entities = Stream.of(vorgangHeader);
+		private final Statistic statistic = StatisticTestFactory.create();
+		private final EntityModel<Vorgang> entityModel = EntityModel.of(vorgangHeader);
+		private final EntityModel<Vorgang> processedEntityModel = EntityModel.of(vorgangHeader, DUMMY_LINK);
+
+		@BeforeEach
+		void mock() {
+			doReturn(entityModel).when(modelAssembler).toModel(any());
+			when(linkedResourceProcessor.process(any())).thenReturn(processedEntityModel);
+		}
+
+		@Test
+		void shouldHaveSelfLink() {
+			var model = modelAssembler.initModel(entities, statistic);
+
+			assertThat(model.getLink(IanaLinkRelations.SELF_VALUE)).get().extracting(Link::getHref).isEqualTo(VorgangController.PATH);
+		}
+
+		@Test
+		void shouldCallToModel() {
+			modelAssembler.initModel(entities, statistic);
+
+			verify(modelAssembler).toModel(vorgangHeader);
+		}
+
+		@Test
+		void shouldCallLinkedResourceProcessor() {
+			modelAssembler.initModel(entities, statistic);
+
+			verify(linkedResourceProcessor).process(entityModel);
+		}
+
+		@Test
+		@SneakyThrows
+		void shouldContainProcessedEntity() {
+			var mapper = new ObjectMapper().registerModules(new JavaTimeModule(), new Jdk8Module());
+
+			var model = mapper.writeValueAsString(modelAssembler.initModel(entities, statistic));
+
+			assertThat(model).contains(mapper.writeValueAsString(processedEntityModel));
+		}
+	}
+
 	@DisplayName("Build page link")
 	@Nested
 	class TestBuildPageLink {
@@ -317,14 +366,8 @@ class VorgangModelAssemblerTest {
 	@Nested
 	class TestLinksOnModel {
 
-		private final UserProfileUrlProvider urlProvider = new UserProfileUrlProvider();
 		private final VorgangWithEingang vorgang = VorgangWithEingangTestFactory.create();
 
-		@BeforeEach
-		void beforeEach() {
-			initUserProfileUrlProvider(urlProvider);
-		}
-
 		@Test
 		void shouldHaveSelfLink() {
 			var link = toModel().getLink(IanaLinkRelations.SELF_VALUE);
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/VorgangWithEingangProcessorTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/VorgangWithEingangProcessorTest.java
index 987b09227e8f17d3beeb0709b2385e6f7f45f930..865bf45b3683b6d3174b97174bf098622ed17577 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/VorgangWithEingangProcessorTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/VorgangWithEingangProcessorTest.java
@@ -23,7 +23,6 @@
  */
 package de.ozgcloud.alfa.vorgang;
 
-import static de.ozgcloud.alfa.common.UserProfileUrlProviderTestFactory.*;
 import static org.assertj.core.api.Assertions.*;
 import static org.mockito.Mockito.*;
 
@@ -42,7 +41,6 @@ import org.springframework.hateoas.LinkRelation;
 import org.springframework.web.util.UriComponentsBuilder;
 import org.springframework.web.util.UriTemplate;
 
-import de.ozgcloud.alfa.common.UserProfileUrlProvider;
 import de.ozgcloud.alfa.common.command.CommandController.CommandByRelationController;
 import de.ozgcloud.alfa.common.user.UserManagerUrlProvider;
 import de.ozgcloud.alfa.postfach.PostfachMailController;
@@ -60,17 +58,10 @@ class VorgangWithEingangProcessorTest {
 	@Mock
 	private VorgangProcessorProperties vorgangProcessorProperties;
 
-	private final UserProfileUrlProvider urlProvider = new UserProfileUrlProvider();
-
 	@DisplayName("Attachments")
 	@Nested
 	class TestAttachments {
 
-		@BeforeEach
-		void init() {
-			initUserProfileUrlProvider(urlProvider);
-		}
-
 		@DisplayName("link")
 		@Nested
 		class TestLink {
@@ -132,11 +123,6 @@ class VorgangWithEingangProcessorTest {
 	@Nested
 	class TestRepresentationsLink {
 
-		@BeforeEach
-		void init() {
-			initUserProfileUrlProvider(urlProvider);
-		}
-
 		private static final String PATH = "/api/vorgang/" + VorgangHeaderTestFactory.ID + "/representations";
 
 		private final LinkRelation linkRel = VorgangWithEingangProcessor.REL_REPRESENTATIONS;
@@ -214,11 +200,6 @@ class VorgangWithEingangProcessorTest {
 	@Nested
 	class TestSearchUserProfileLink {
 
-		@BeforeEach
-		void init() {
-			initUserProfileUrlProvider(urlProvider);
-		}
-
 		@DisplayName("on configured for search user profile")
 		@Nested
 		class TestIsConfigured {
@@ -287,11 +268,6 @@ class VorgangWithEingangProcessorTest {
 		private final VorgangWithEingang vorgang = VorgangWithEingangTestFactory.create();
 		private final EntityModel<VorgangWithEingang> vorgangEntityModel = EntityModel.of(vorgang);
 
-		@BeforeEach
-		void init() {
-			initUserProfileUrlProvider(urlProvider);
-		}
-
 		@DisplayName("on matching configuration")
 		@Nested
 		class TestOnMatchingConfiguration {
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/command/VorgangWithEingangCommandProcessorTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/command/VorgangWithEingangCommandProcessorTest.java
index 37b3d3ad544fc896f8a915c5f22b02b1278ac966..b99f8ab6a405431ba12b6773f37b916181cc0942 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/command/VorgangWithEingangCommandProcessorTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/command/VorgangWithEingangCommandProcessorTest.java
@@ -23,7 +23,6 @@
  */
 package de.ozgcloud.alfa.vorgang.command;
 
-import static de.ozgcloud.alfa.common.UserProfileUrlProviderTestFactory.*;
 import static org.assertj.core.api.Assertions.*;
 import static org.mockito.ArgumentMatchers.*;
 import static org.mockito.Mockito.*;
@@ -44,7 +43,6 @@ import org.springframework.hateoas.EntityModel;
 import org.springframework.hateoas.Link;
 import org.springframework.hateoas.LinkRelation;
 
-import de.ozgcloud.alfa.common.UserProfileUrlProvider;
 import de.ozgcloud.alfa.common.command.CommandController;
 import de.ozgcloud.alfa.common.user.CurrentUserService;
 import de.ozgcloud.alfa.common.user.UserRole;
@@ -70,12 +68,8 @@ class VorgangWithEingangCommandProcessorTest {
 	private VorgangWithEingang vorgang = VorgangWithEingangTestFactory.create();
 	private EntityModel<VorgangWithEingang> vorgangEntityModel = EntityModel.of(vorgang);
 
-	private UserProfileUrlProvider urlProvider = new UserProfileUrlProvider();
-
 	@Test
 	void shouldReturnEntityModel() {
-		initUserProfileUrlProvider(urlProvider);
-
 		var result = processor.process(vorgangEntityModel);
 
 		assertThat(result).isNotNull();
@@ -155,11 +149,6 @@ class VorgangWithEingangCommandProcessorTest {
 
 		private final LinkRelation linkRel = VorgangWithEingangCommandProcessor.REL_VORGANG_FORWARD;
 
-		@BeforeEach
-		void init() {
-			initUserProfileUrlProvider(urlProvider);
-		}
-
 		@Test
 		void shouldNotBePresent() {
 			doReturn(false).when(processor).isForwardingAllowed(any());
@@ -186,11 +175,6 @@ class VorgangWithEingangCommandProcessorTest {
 	@Nested
 	class TestPendingCommandsLink {
 
-		@BeforeEach
-		void init() {
-			initUserProfileUrlProvider(urlProvider);
-		}
-
 		@Test
 		void shouldExists() {
 			when(commandController.existsPendingCommands(any())).thenReturn(true);
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
index 78662dc0cd55e2936abb48ea4bc597b4af52167d..d5c25ca60d57f95610560c3fcc1431e528449f69 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageHistorieProcessorTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageHistorieProcessorTest.java
@@ -1,3 +1,26 @@
+/*
+ * Copyright (C) 2025 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.wiedervorlage;
 
 import static org.assertj.core.api.Assertions.*;
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageModelAssemblerTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageModelAssemblerTest.java
index 01cbb98f06ab930c917ae0bff08a2afd6d90e7aa..196c4aff1ba6966ee0f190769aca3c9a67d1f694 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageModelAssemblerTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageModelAssemblerTest.java
@@ -24,7 +24,6 @@
 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.Collections;
@@ -36,13 +35,10 @@ import org.junit.jupiter.api.Test;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.Spy;
-import org.springframework.context.ApplicationContext;
-import org.springframework.core.env.Environment;
 import org.springframework.hateoas.EntityModel;
 import org.springframework.hateoas.IanaLinkRelations;
 import org.springframework.hateoas.server.EntityLinks;
 
-import de.ozgcloud.alfa.common.UserProfileUrlProvider;
 import de.ozgcloud.alfa.common.file.OzgFileTestFactory;
 import de.ozgcloud.alfa.vorgang.VorgangController;
 import de.ozgcloud.alfa.vorgang.VorgangHeaderTestFactory;
@@ -51,7 +47,7 @@ import de.ozgcloud.alfa.vorgang.VorgangWithEingangTestFactory;
 
 class WiedervorlageModelAssemblerTest {
 
-	private final String PATH = WiedervorlageController.WIEDERVORLAGE_PATH + "/";
+	private static final String PATH = WiedervorlageController.WIEDERVORLAGE_PATH + "/";
 
 	@Spy
 	@InjectMocks
@@ -62,17 +58,6 @@ class WiedervorlageModelAssemblerTest {
 	@Mock
 	private VorgangController vorgangController;
 
-	private UserProfileUrlProvider urlProvider = new UserProfileUrlProvider();
-
-	@BeforeEach
-	void initTest() {
-		var context = mock(ApplicationContext.class);
-		var environment = mock(Environment.class);
-		when(environment.getProperty(anyString())).thenReturn("test/");
-		when(context.getEnvironment()).thenReturn(environment);
-		urlProvider.setApplicationContext(context);
-	}
-
 	@Nested
 	class TestToModel {