diff --git a/.vscode/settings.json b/.vscode/settings.json
index 02ffa78fc20462c7539afdc7ef4cc8b7b63bdd1b..9b1e5446992d170181e31942d75d020e12bbe5d3 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,4 +1,5 @@
 {
   "angular.enable-strict-mode-prompt": false,
-  "java.debug.settings.onBuildFailureProceed": true
+  "java.debug.settings.onBuildFailureProceed": true,
+  "java.compile.nullAnalysis.mode": "automatic"
 }
\ No newline at end of file
diff --git a/Jenkinsfile b/Jenkinsfile
index c28bf0d2fa1f10b024edee98db52ddecd73f2b6b..6305e9bab9dcbdf6a30e10c0511a262728f8e7b3 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -85,6 +85,27 @@ pipeline {
 //            }
         }
 
+        stage('Build and push client container') {
+            steps {
+                script {
+                    catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
+                        dir('alfa-client') {
+                            IMAGE_TAG = generateImageTag()
+
+                            sh 'npm run ci-build-alfa-client-container'
+
+                            withCredentials([usernamePassword(credentialsId: 'jenkins-nexus-login', usernameVariable: 'USER', passwordVariable: 'PASSWORD')]) {
+                                sh 'docker login docker.ozg-sh.de -u ${USER} -p ${PASSWORD}'
+
+                                sh "docker tag docker.ozg-sh.de/alfa-client:build-latest docker.ozg-sh.de/alfa-client:${IMAGE_TAG}"
+                                sh "docker push docker.ozg-sh.de/alfa-client:${IMAGE_TAG}"
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
         stage('Set Version') {
           when {
             not {
@@ -227,22 +248,38 @@ pipeline {
             }
         }
 
-        stage ('OWASP Dependency-Check Vulnerabilities') {
+        stage ('Deploy SBOM to DependencyTrack') {
+            steps {
+                configFileProvider([configFile(fileId: 'maven-settings', variable: 'MAVEN_SETTINGS')]) {
+                    withCredentials([string(credentialsId: 'dependency-track-api-key', variable: 'API_KEY')]) {
+
+                        dir('alfa-server') {
+                            
+                            sh 'mvn  --no-transfer-progress -s $MAVEN_SETTINGS io.github.pmckeown:dependency-track-maven-plugin:upload-bom -Ddependency-track.apiKey=$API_KEY -Ddependency-track.projectVersion=' + generateImageTag() + ' -Ddependency-track.dependencyTrackBaseUrl=https://dependency-track.ozg-sh.de'
+                        }
+                    }
+                }
+            }
+        }
+
+        stage ('Trigger Barrierefreiheit Rollout') {
+            when {
+               branch 'barrierefreiheit-dev'
+            }
             steps {
-                    dependencyCheck additionalArguments: '''
-                        -o "./"
-                        -s "./"
-                        -f "ALL"
-                        -d /dependency-check-data
-                        --suppression dependency-check-supressions.xml
-                        --disableKnownExploited
-                        --noupdate
-                        --disableArchive
-                        --prettyPrint''', odcInstallation: 'dependency-check-owasp'
-
-                    dependencyCheckPublisher pattern: 'dependency-check-report.xml'
+                script {
+                    FAILED_STAGE = env.STAGE_NAME
+
+                    cloneGitopsRepo()
+
+                    setNewBarrierefreiheitVersion()
+
+                    pushGitopsRepo()
+
+                }
             }
         }
+
     }
     post {
         failure {
@@ -274,7 +311,10 @@ String generateHelmChartVersion() {
     def chartVersion = "${VERSION}"
 
     if (isMasterBranch()) {
-        chartVersion += "-${env.GIT_COMMIT.take(7)}"
+        chartVersion += getCommitHash()
+    }
+    else if (isBarrierefreiheitBranch()) {
+        chartVersion += "-barrierefreiheit${getCommitHash()}"
     }
     else if (!isReleaseBranch()) {
         chartVersion += "-${env.BRANCH_NAME}"
@@ -295,8 +335,8 @@ Void tagAndPushDockerImage(String newTag){
 String generateImageTag() {
     def imageTag = "${env.BRANCH_NAME}-${VERSION}"
 
-    if (isMasterBranch()) {
-        imageTag += "-${env.GIT_COMMIT.take(7)}"
+    if (isMasterBranch() || isBarrierefreiheitBranch()) {
+        imageTag += getCommitHash()
     }
 
     return imageTag
@@ -365,9 +405,19 @@ Void setNewTestVersion() {
 }
 
 Void setNewGitopsVersion(String environment) {
-    dir("gitops") {
-        def envFile = "${environment}/application/values/alfa-values.yaml"
+    def envFile = "${environment}/application/values/alfa-values.yaml"
+    def commitMessage = "jenkins rollout ${environment} alfa version ${IMAGE_TAG}";
+    setNewGitopsVersion(envFile, commitMessage);
+}
+
+Void setNewBarrierefreiheitVersion() {
+    def envFile = "dev/namespace/namespaces/by-barrierefreiheit-dev.yaml"
+    def commitMessage = "jenkins rollout ${IMAGE_TAG} for Barrierefreiheit Dev"
+    setNewGitopsVersion(envFile, commitMessage);
+}
 
+Void setNewGitopsVersion(String envFile, String commitMessage) {
+    dir("gitops") {
         def envVersions = readYaml file: envFile
 
         envVersions.alfa.image.tag = IMAGE_TAG
@@ -375,15 +425,19 @@ Void setNewGitopsVersion(String environment) {
 
         writeYaml file: envFile, data: envVersions, overwrite: true
 
-        if (hasValuesFileChanged(environment)) {
+        if (hasValuesFileChanged(envFile)) {
             sh "git add ${envFile}"
-            sh "git commit -m 'jenkins rollout ${environment} alfa version ${IMAGE_TAG}'"
+            sh "git commit -m '${commitMessage}'"
         }
     }
 }
 
-Boolean hasValuesFileChanged(String environment) {
-    return sh (script: "git status | grep '${environment}/application/values/alfa-values.yaml'", returnStatus: true) == env.SH_SUCCESS_STATUS_CODE as Integer
+String getCommitHash() {
+    return "-${env.GIT_COMMIT.take(7)}";
+}
+
+Boolean hasValuesFileChanged(String envFile) {
+    return sh (script: "git status | grep '${envFile}'", returnStatus: true) == env.SH_SUCCESS_STATUS_CODE as Integer
 }
 
 Boolean isReleaseBranch() {
@@ -394,6 +448,10 @@ Boolean isMasterBranch() {
     return env.BRANCH_NAME == 'master'
 }
 
+Boolean isBarrierefreiheitBranch() {
+    return env.BRANCH_NAME == 'barrierefreiheit-dev'
+}
+
 Boolean isReleaseVersion(List versions) {
     return matchRegexVersion(versions, RELEASE_REGEX)
 }
diff --git a/alfa-client/apps/admin/src/test/helm/deployment_env_test.yaml b/alfa-client/apps/admin/src/test/helm/deployment_env_test.yaml
index 444d80b661e454360bdad6eaa0ad76bb63ec5935..6172fd2cdf989a7c932e09c1387d7f28e23db17b 100644
--- a/alfa-client/apps/admin/src/test/helm/deployment_env_test.yaml
+++ b/alfa-client/apps/admin/src/test/helm/deployment_env_test.yaml
@@ -22,7 +22,7 @@
 # unter der Lizenz sind dem Lizenztext zu entnehmen.
 #
 
-suite: test deployment container environments 
+suite: test deployment container environments
 templates:
   - templates/deployment.yaml
 set:
@@ -73,3 +73,4 @@ tests:
           content:
             name: my_test_environment_name
             value: "A test value"
+
diff --git a/alfa-client/apps/alfa-e2e/src/components/vorgang/vorgang-subnavigation.ts b/alfa-client/apps/alfa-e2e/src/components/vorgang/vorgang-subnavigation.ts
index 826cb6a09e8321d97578db6ddc61f3706874ba1c..40dc7120e89587eca1214c5b2eb673df1450a220 100644
--- a/alfa-client/apps/alfa-e2e/src/components/vorgang/vorgang-subnavigation.ts
+++ b/alfa-client/apps/alfa-e2e/src/components/vorgang/vorgang-subnavigation.ts
@@ -45,6 +45,10 @@ export class VorgangSubnavigationE2EComponent {
     return cy.getTestElement(this.backIconButton);
   }
 
+  public back(): void {
+    this.getBackButton().click();
+  }
+
   public getAnnehmenIconButton() {
     return cy.getTestElement(this.annehmenIconButton);
   }
diff --git a/alfa-client/apps/alfa-e2e/src/components/vorgang/vorgang-views.e2e.component.ts b/alfa-client/apps/alfa-e2e/src/components/vorgang/vorgang-views.e2e.component.ts
index 446c287de76ee0c62fd746f6df9241c95ed0ce92..719825fd08a222a32c30f8bafd7c70e260d403b7 100644
--- a/alfa-client/apps/alfa-e2e/src/components/vorgang/vorgang-views.e2e.component.ts
+++ b/alfa-client/apps/alfa-e2e/src/components/vorgang/vorgang-views.e2e.component.ts
@@ -18,6 +18,9 @@ export class VorgangViewsE2EComponent {
   private readonly zuLoeschenViewItem: VorgangViewE2EComponent = new VorgangViewE2EComponent(
     'Zu_Loschen',
   );
+  private readonly ungelesenViewItem: VorgangViewE2EComponent = new VorgangViewE2EComponent(
+    'Ungelesen',
+  );
   private readonly wiedervorlagenViewItem: VorgangViewE2EComponent = new VorgangViewE2EComponent(
     'Wiedervorlagen',
   );
@@ -54,6 +57,10 @@ export class VorgangViewsE2EComponent {
     return this.zuLoeschenViewItem;
   }
 
+  public getUngelesen(): VorgangViewE2EComponent {
+    return this.ungelesenViewItem;
+  }
+
   public getWiedervorlagen(): VorgangViewE2EComponent {
     return this.wiedervorlagenViewItem;
   }
diff --git a/alfa-client/apps/alfa-e2e/src/components/vorgang/vorgang-zusammenarbeit.e2e.component.ts b/alfa-client/apps/alfa-e2e/src/components/vorgang/vorgang-zusammenarbeit.e2e.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..9433275b79fafd874af6f7fbef835e5ad2deb76f
--- /dev/null
+++ b/alfa-client/apps/alfa-e2e/src/components/vorgang/vorgang-zusammenarbeit.e2e.component.ts
@@ -0,0 +1,67 @@
+import { enterWith } from '../../support/cypress.util';
+
+export class VorgangZusammenarbeitE2EComponent {
+  private readonly anfrageButton: string = 'anfrage-erstellen-button';
+  private readonly zustaendigeStelleButton: string = 'organisations-einheit-search-button';
+  private readonly titelText: string = 'Titel-text-input';
+  private readonly messageText: string = 'Nachricht-textarea';
+  private readonly sendButton: string = 'collaboration-request-submit-button';
+  private readonly cancelButton: string = 'collaboration-request-cancel-button';
+
+  public getAnfrageButton(): Cypress.Chainable<JQuery<HTMLElement>> {
+    return cy.getTestElement(this.anfrageButton);
+  }
+
+  public createAnfrage(): void {
+    this.getAnfrageButton().click();
+  }
+
+  public getZustaendigeStelleButton(): Cypress.Chainable<JQuery<HTMLElement>> {
+    return cy.getTestElement(this.zustaendigeStelleButton);
+  }
+
+  public searchZustaendigeStelle(): void {
+    this.getZustaendigeStelleButton().click();
+  }
+
+  public getStelleTitel(): Cypress.Chainable<JQuery<HTMLElement>> {
+    return cy.getTestElement(this.titelText);
+  }
+
+  public enterTitel(text: string): void {
+    enterWith(this.getStelleTitel(), text);
+  }
+
+  public getMessageText(): Cypress.Chainable<JQuery<HTMLElement>> {
+    return cy.getTestElement(this.messageText);
+  }
+
+  public enterMessage(text: string): void {
+    enterWith(this.getMessageText(), text);
+  }
+
+  public messageScrollbarIsPresent(): void {
+    this.getMessageText().then(($textarea) => {
+      const scrollHeight = $textarea[0].scrollHeight;
+      const clientHeight = $textarea[0].clientHeight;
+
+      expect(scrollHeight).to.be.greaterThan(clientHeight);
+    });
+  }
+
+  public getSendButton(): Cypress.Chainable<JQuery<HTMLElement>> {
+    return cy.getTestElement(this.sendButton);
+  }
+
+  public sendAnfrage(): void {
+    this.getSendButton().click();
+  }
+
+  public getCancelButton(): Cypress.Chainable<JQuery<HTMLElement>> {
+    return cy.getTestElement(this.cancelButton);
+  }
+
+  public cancelAnfrage(): void {
+    this.getCancelButton().click();
+  }
+}
diff --git a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/postfach-mail/postfach-mail.cy.ts b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/postfach-mail/postfach-mail.cy.ts
index 911f2fd2e419de34cc02083bde0866b2ec5a185e..292ad9ca566f8a29f7be1fcbf104757c712eb5cb 100644
--- a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/postfach-mail/postfach-mail.cy.ts
+++ b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/postfach-mail/postfach-mail.cy.ts
@@ -111,11 +111,12 @@ describe('PostfachMail', () => {
   };
 
   const vorgangWithoutPostfach: VorgangE2E = createVorgangWithoutPostfachId();
+
   function createVorgangWithoutPostfachId(): VorgangE2E {
     return {
       ...buildVorgang(objectIds[2], 'VorgangWithoutPostfachId'),
       eingangs: [...vorgang.eingangs],
-      header: { serviceKonto: null },
+      header: { serviceKonto: null, collaborationLevel: 0 },
     };
   }
 
@@ -523,8 +524,8 @@ describe('PostfachMail', () => {
         exist(postfachMailPage.getSubnavigation().getBackButton());
       });
 
-      it('should show breadcrumb', () => {
-        contains(postfachMailPage.getBreadcrump(), vorgangWithReply.aktenzeichen);
+      it('should show Nachrichten heading', () => {
+        contains(postfachMailPage.getHeading(), postfachMailPage.getHeadingText());
       });
     });
 
diff --git a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/postfach-mail/postfach-mail.filtered-by-organisationseinheit.cy.ts b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/postfach-mail/postfach-mail.filtered-by-organisationseinheit.cy.ts
index 40940b37bbf3e171df48dac38acb764903278f66..3b132859b84722b706bf2b2bf90147331b553595 100644
--- a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/postfach-mail/postfach-mail.filtered-by-organisationseinheit.cy.ts
+++ b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/postfach-mail/postfach-mail.filtered-by-organisationseinheit.cy.ts
@@ -92,7 +92,7 @@ describe('PostfachNachrichten filtered by organisationseinheit', () => {
       visitUrl(authorizedUrl);
       waitForSpinnerToDisappear();
 
-      exist(postfachMailPage.getBreadcrump());
+      exist(postfachMailPage.getHeading());
     });
 
     it('should not open postfachNachrichten page', () => {
@@ -100,7 +100,7 @@ describe('PostfachNachrichten filtered by organisationseinheit', () => {
       visitUrl(forbiddenUrl);
       waitForSpinnerToDisappear();
 
-      notExist(postfachMailPage.getBreadcrump());
+      notExist(postfachMailPage.getHeading());
     });
 
     it('should show snackbar', () => {
@@ -125,7 +125,7 @@ describe('PostfachNachrichten filtered by organisationseinheit', () => {
       visitUrl(authorizedUrl);
       waitForSpinnerToDisappear();
 
-      exist(postfachMailPage.getBreadcrump());
+      exist(postfachMailPage.getHeading());
     });
 
     it('should not open postfachNachrichten page', () => {
@@ -133,7 +133,7 @@ describe('PostfachNachrichten filtered by organisationseinheit', () => {
       visitUrl(forbiddenUrl);
       waitForSpinnerToDisappear();
 
-      notExist(postfachMailPage.getBreadcrump());
+      notExist(postfachMailPage.getHeading());
     });
 
     it('should show snackbar', () => {
diff --git a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/postfach-mail/postfach-nachricht-reply-button.cy.ts b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/postfach-mail/postfach-nachricht-reply-button.cy.ts
index ca29375a29c0d5ce113b82357dca681679efdad5..eca73b26f756e3a3610b82f62299ddbde612e5a3 100644
--- a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/postfach-mail/postfach-nachricht-reply-button.cy.ts
+++ b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/postfach-mail/postfach-nachricht-reply-button.cy.ts
@@ -42,6 +42,7 @@ describe('Postfach Nachricht reply button', () => {
     },
     name: 'BayernID Vorgang',
     header: {
+      collaborationLevel: 0,
       serviceKonto: {
         type: 'BayernId',
         postfachAddress: [
diff --git a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-bescheid/vorgang-bescheid-automatisch-erstellen.cy.ts b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-bescheid/vorgang-bescheid-automatisch-erstellen.cy.ts
index c2a6b888ce2b2bad7055322952440965512d27b5..8f465721f0b67a4a971702d125d5f4bba9df64a9 100644
--- a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-bescheid/vorgang-bescheid-automatisch-erstellen.cy.ts
+++ b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-bescheid/vorgang-bescheid-automatisch-erstellen.cy.ts
@@ -28,7 +28,7 @@ import {
 registerLocaleData(localeDe, 'de', localeDeExtra);
 
 //TODO: Jenkins konfigurieren
-describe.skip('Upload automatic Bescheid', () => {
+describe('Upload automatic Bescheid', () => {
   const mainPage: MainPage = new MainPage();
   const vorgangList: VorgangListE2EComponent = mainPage.getVorgangList();
 
@@ -77,7 +77,7 @@ describe.skip('Upload automatic Bescheid', () => {
     dropCollections();
   });
 
-  describe.skip('Upload automatic Bescheid document', () => {
+  describe('Upload automatic Bescheid document', () => {
     it('should show automatic Bescheid button', () => {
       vorgangList.getListItem(bescheidAutomatik.name).getRoot().click();
       waitForSpinnerToDisappear();
diff --git a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-list-wiedervorlage/vorgang-list-wiedervorlagen.cy.ts b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-list-wiedervorlage/vorgang-list-wiedervorlagen.cy.ts
index d4344f6bafe227730065bc64264bddddc00264d4..3299c6883e8d07f18fca23e37571d1e17b525621 100644
--- a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-list-wiedervorlage/vorgang-list-wiedervorlagen.cy.ts
+++ b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-list-wiedervorlage/vorgang-list-wiedervorlagen.cy.ts
@@ -141,7 +141,7 @@ describe('VorgangList Wiedervorlagen Next Frist', () => {
         vorgangWithWiedervorlageInFuture.name,
       );
 
-      notContainClass(vorgang.getWiedervorlageNextFrist(), 'red');
+      notContainClass(vorgang.getWiedervorlageNextFrist(), 'text-error');
       exist(vorgang.getWiedervorlageNextFrist());
     });
 
@@ -150,7 +150,7 @@ describe('VorgangList Wiedervorlagen Next Frist', () => {
         vorgangWithWiedervorlageInThePast.name,
       );
 
-      containClass(vorgang.getWiedervorlageNextFrist(), 'red');
+      containClass(vorgang.getWiedervorlageNextFrist(), 'text-error');
       exist(vorgang.getWiedervorlageNextFrist());
     });
   });
diff --git a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-list/vorgang-list-ungelesen.cy.ts b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-list/vorgang-list-ungelesen.cy.ts
new file mode 100644
index 0000000000000000000000000000000000000000..323803e5693ea60d476d70aff45717143b624cc4
--- /dev/null
+++ b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-list/vorgang-list-ungelesen.cy.ts
@@ -0,0 +1,127 @@
+import {
+  PostfachMailE2EComponent,
+  PostfachMailListItem,
+} from 'apps/alfa-e2e/src/components/postfach/postfach-mail.e2e.component';
+import { VorgangSubnavigationE2EComponent } from 'apps/alfa-e2e/src/components/vorgang/vorgang-subnavigation';
+import {
+  VorgangViewE2EComponent,
+  VorgangViewsE2EComponent,
+} from 'apps/alfa-e2e/src/components/vorgang/vorgang-views.e2e.component';
+import {
+  PostfachMailItemE2E,
+  VorgangAttachedItemClientE2E,
+  VorgangAttachedItemE2E,
+} from 'apps/alfa-e2e/src/model/vorgang-attached-item';
+import { VorgangPage } from 'apps/alfa-e2e/src/page-objects/vorgang.po';
+import { exist, haveLength } from 'apps/alfa-e2e/src/support/cypress.util';
+import {
+  createPostfachNachrichtAttachedItem,
+  createPostfachNachrichtReplyItem,
+  initVorgangAttachedItem,
+} from 'apps/alfa-e2e/src/support/vorgang-attached-item-util';
+import { VorgangListE2EComponent } from '../../../components/vorgang/vorgang-list.e2e.component';
+import { ClientAttributeNameE2E, ClientAttributesE2E, VorgangE2E } from '../../../model/vorgang';
+import { MainPage, waitForSpinnerToDisappear } from '../../../page-objects/main.po';
+import { dropCollections } from '../../../support/cypress-helper';
+import { initUsermanagerUsers, loginAsSabine } from '../../../support/user-util';
+import {
+  buildVorgang,
+  createHasNewPostfachNachrichtClientAttribute,
+  createHasPostfachNachrichtClientAttribute,
+  initVorgaenge,
+  objectIds,
+} from '../../../support/vorgang-util';
+
+describe('Ungelesene Nachrichten', () => {
+  const mainPage: MainPage = new MainPage();
+  const vorgangList: VorgangListE2EComponent = mainPage.getVorgangList();
+  const vorgangPage: VorgangPage = new VorgangPage();
+  const subnavigation: VorgangSubnavigationE2EComponent = vorgangPage.getSubnavigation();
+  const views: VorgangViewsE2EComponent = mainPage.getViews();
+  const ungelesenView: VorgangViewE2EComponent = views.getUngelesen();
+  const postfachMailContainer: PostfachMailE2EComponent = vorgangPage.getPostfachMailcontainer();
+
+  const clientAttributes: ClientAttributesE2E = {
+    [VorgangAttachedItemClientE2E.OZGCLOUD_NACHRICHTEN_MANAGER]: {
+      [ClientAttributeNameE2E.HAS_NEW_POSTFACH_NACHRICHT]:
+        createHasNewPostfachNachrichtClientAttribute(true),
+      [ClientAttributeNameE2E.HAS_POSTFACH_NACHRICHT]:
+        createHasPostfachNachrichtClientAttribute(true),
+    },
+  };
+
+  const vorgangWithReply1: VorgangE2E = {
+    ...buildVorgang(objectIds[0], 'VorgangWithReply'),
+    clientAttributes,
+  };
+
+  const vorgangWithReply2: VorgangE2E = {
+    ...buildVorgang(objectIds[1], 'VorgangWithReply 2'),
+    clientAttributes,
+  };
+
+  const postfachMailReply1: PostfachMailItemE2E = createPostfachNachrichtReplyItem();
+  const postfachMailReply2: PostfachMailItemE2E = createPostfachNachrichtReplyItem();
+
+  const postfachNachrichtAttachedItem1: VorgangAttachedItemE2E = {
+    ...createPostfachNachrichtAttachedItem(objectIds[0], vorgangWithReply1._id.$oid),
+    item: postfachMailReply1,
+  };
+  const postfachNachrichtAttachedItem2: VorgangAttachedItemE2E = {
+    ...createPostfachNachrichtAttachedItem(objectIds[1], vorgangWithReply2._id.$oid),
+    item: postfachMailReply2,
+  };
+
+  before(() => {
+    initVorgaenge([vorgangWithReply1, vorgangWithReply2]);
+    initVorgangAttachedItem([postfachNachrichtAttachedItem1]);
+    initVorgangAttachedItem([postfachNachrichtAttachedItem2]);
+    initUsermanagerUsers();
+
+    loginAsSabine();
+
+    waitForSpinnerToDisappear();
+    exist(vorgangList.getRoot());
+  });
+
+  after(() => {
+    dropCollections();
+  });
+
+  describe('Show number of unread messages', () => {
+    it('should show 2 unread messages in filter', () => {
+      ungelesenView.getRoot().click();
+      waitForSpinnerToDisappear();
+
+      haveLength(vorgangList.getItems(), 2);
+    });
+
+    it('should show 1 unread message after viewing first message', () => {
+      vorgangList.getListItem(vorgangWithReply1.name).getRoot().click();
+      waitForSpinnerToDisappear();
+
+      const postfachMailItem: PostfachMailListItem = postfachMailContainer.getListItem('Subject');
+      postfachMailItem.getRoot().click();
+      waitForSpinnerToDisappear();
+
+      subnavigation.back();
+      subnavigation.back();
+
+      haveLength(vorgangList.getItems(), 1);
+    });
+
+    it('should show 0 unread messages after viewing second message', () => {
+      vorgangList.getListItem(vorgangWithReply2.name).getRoot().click();
+      waitForSpinnerToDisappear();
+
+      const postfachMailItem: PostfachMailListItem = postfachMailContainer.getListItem('Subject');
+      postfachMailItem.getRoot().click();
+      waitForSpinnerToDisappear();
+
+      subnavigation.back();
+      subnavigation.back();
+
+      haveLength(vorgangList.getItems(), 0);
+    });
+  });
+});
diff --git a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-zusammenarbeit/vorgang-zusammenarbeit-anfragen.cy.ts b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-zusammenarbeit/vorgang-zusammenarbeit-anfragen.cy.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e02c7bed2c4080d6b8fa7d227f826722c67699ce
--- /dev/null
+++ b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-zusammenarbeit/vorgang-zusammenarbeit-anfragen.cy.ts
@@ -0,0 +1,123 @@
+import { registerLocaleData } from '@angular/common';
+import localeDe from '@angular/common/locales/de';
+import localeDeExtra from '@angular/common/locales/extra/de';
+import { VorgangZusammenarbeitE2EComponent } from 'apps/alfa-e2e/src/components/vorgang/vorgang-zusammenarbeit.e2e.component';
+import { VorgangE2E, VorgangStatusE2E } from 'apps/alfa-e2e/src/model/vorgang';
+import 'cypress-real-events/support';
+import { VorgangListE2EComponent } from '../../../components/vorgang/vorgang-list.e2e.component';
+import { MainPage, waitForSpinnerToDisappear } from '../../../page-objects/main.po';
+import { VorgangPage } from '../../../page-objects/vorgang.po';
+import { dropCollections } from '../../../support/cypress-helper';
+import { exist, notExist } from '../../../support/cypress.util';
+import { initUsermanagerUsers, loginAsSabine } from '../../../support/user-util';
+import { buildVorgang, initVorgaenge, objectIds } from '../../../support/vorgang-util';
+
+registerLocaleData(localeDe, 'de', localeDeExtra);
+
+describe('Vorgang Zusammenarbeit anfragen', () => {
+  const mainPage: MainPage = new MainPage();
+  const vorgangList: VorgangListE2EComponent = mainPage.getVorgangList();
+
+  const vorgangPage: VorgangPage = new VorgangPage();
+  const zusammenarbeitContainer: VorgangZusammenarbeitE2EComponent =
+    vorgangPage.getZusammenarbeitContainer();
+
+  const zusammenarbeitVorgang: VorgangE2E = {
+    ...buildVorgang(objectIds[0], 'Zusammenarbeit Vorgang'),
+    status: VorgangStatusE2E.IN_BEARBEITUNG,
+  };
+
+  const titleText: string = 'Dies ist ein Test-Titel !"§$%&';
+  const messageText: string =
+    'Sehr geehrter Tester\n\n Dies ist ein !"§$%& Test\n zum Testen der Nachricht.\n\n\n\nhier sollte eine \nScrollbar\nangezeigt\nwerden!\n\nMfG!';
+
+  before(() => {
+    initVorgaenge([zusammenarbeitVorgang]);
+    initUsermanagerUsers();
+
+    loginAsSabine();
+
+    waitForSpinnerToDisappear();
+    exist(vorgangList.getRoot());
+  });
+
+  after(() => {
+    dropCollections();
+  });
+
+  describe('create new Anfrage', () => {
+    it('should show button for Zusammenarbeit', () => {
+      vorgangList.getListItem(zusammenarbeitVorgang.name).getRoot().click();
+      waitForSpinnerToDisappear();
+
+      exist(zusammenarbeitContainer.getAnfrageButton());
+    });
+
+    it('should show input elements on Anfrage click', () => {
+      zusammenarbeitContainer.createAnfrage();
+
+      exist(zusammenarbeitContainer.getZustaendigeStelleButton());
+      exist(zusammenarbeitContainer.getStelleTitel());
+      exist(zusammenarbeitContainer.getMessageText());
+      exist(zusammenarbeitContainer.getSendButton());
+      exist(zusammenarbeitContainer.getCancelButton());
+    });
+
+    it('should close elements on Cancel click', () => {
+      zusammenarbeitContainer.cancelAnfrage();
+
+      notExist(zusammenarbeitContainer.getZustaendigeStelleButton());
+      notExist(zusammenarbeitContainer.getStelleTitel());
+      notExist(zusammenarbeitContainer.getMessageText());
+      notExist(zusammenarbeitContainer.getSendButton());
+      notExist(zusammenarbeitContainer.getCancelButton());
+      exist(zusammenarbeitContainer.getAnfrageButton());
+    });
+
+    it('should open new search label for Zustaendige Stelle', () => {
+      zusammenarbeitContainer.createAnfrage();
+      //button click
+      //Layer wird angezeigt
+    });
+
+    it('should close layer on Cancel click', () => {
+      //click Abbrechen
+    });
+
+    it('should show no search on entering 1 element', () => {
+      //1 Zeichen in Suche eingeben
+      //keine Vorschau
+    });
+
+    it('should show results on entering 2 elements', () => {
+      //2 Zeichen in Suche eingeben
+      //Vorschau kontrollieren
+    });
+
+    it('should delete search term on clicking X', () => {
+      //X in Suche klicken
+      //Suche ist leer
+      //keine Vorschau
+    });
+
+    it('should copy and paste Zustaendige Stelle after selection', () => {
+      //click Suchergebnis
+      //Adresse und Name wird übernommen
+      //Layer ist geschlossen
+    });
+
+    it('should be able to enter title and message, and show scrollbar on long text', () => {
+      zusammenarbeitContainer.enterTitel(titleText);
+      zusammenarbeitContainer.enterMessage(messageText);
+
+      zusammenarbeitContainer.messageScrollbarIsPresent();
+    });
+
+    it('should show title and message read-only and remove buttons after sending', () => {
+      //Button klicken
+      //Titel und Datum werden angezeigt
+      //Nachricht wird angezeigt
+      //Buttons werden ausgeblendet
+    });
+  });
+});
diff --git a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/wiedervorlage/wiedervorlage.erledigen.cy.ts b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/wiedervorlage/wiedervorlage.erledigen.cy.ts
index 994c49a6065a7b85d0f294803291af520ed6b252..c9ea833a1b6086cabc8286b7821531d0b8aac9bb 100644
--- a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/wiedervorlage/wiedervorlage.erledigen.cy.ts
+++ b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/wiedervorlage/wiedervorlage.erledigen.cy.ts
@@ -33,7 +33,7 @@ import { WiedervorlageInVorgangE2EComponent } from '../../../components/wiedervo
 import { WiedervorlageE2EComponent } from '../../../components/wiedervorlage/wiedervorlage-page.e2e.component';
 import { WiedervorlageSubnavigationE2EComponent } from '../../../components/wiedervorlage/wiedervorlage-subnavigation';
 import { WiedervorlagenInVorgangE2EComponent } from '../../../components/wiedervorlage/wiedervorlagen-in-vorgang.e2e.component';
-import { VorgangE2E } from '../../../model/vorgang';
+import { ClientAttributeNameE2E, VorgangE2E } from '../../../model/vorgang';
 import { WiedervorlageE2E } from '../../../model/wiedervorlage';
 import {
   MainPage,
@@ -51,12 +51,20 @@ import {
   notExist,
 } from '../../../support/cypress.util';
 import { loginAsSabine } from '../../../support/user-util';
-import { createVorgang, initVorgang, objectIds } from '../../../support/vorgang-util';
+import {
+  createAlfaClientAttributes,
+  createNextWiedervorlageFristClientAttribute,
+  createVorgang,
+  initVorgang,
+  objectIds,
+} from '../../../support/vorgang-util';
 import {
   createWiedervorlageAttachedItem,
   createWiedervorlageItem,
 } from '../../../support/wiedervorlage-util';
 
+const wiedervorlageItemFixture: WiedervorlageE2E = require('../../../fixtures/wiedervorlage/wiedervorlage.json');
+
 describe('Wiedervorlage erledigen/wiedereroeffnen', () => {
   const mainPage: MainPage = new MainPage();
 
@@ -76,7 +84,13 @@ describe('Wiedervorlage erledigen/wiedereroeffnen', () => {
   const wiedervorlageContainer: WiedervorlageE2EComponent =
     wiedervorlagePage.getWiedervorlageContainer();
 
-  const vorgang: VorgangE2E = createVorgang();
+  const vorgang: VorgangE2E = {
+    ...createVorgang(),
+    clientAttributes: createAlfaClientAttributes(
+      ClientAttributeNameE2E.NEXT_WIEDERVORLAGE_FRIST,
+      createNextWiedervorlageFristClientAttribute(wiedervorlageItemFixture.frist),
+    ),
+  };
 
   const wiedervorlageZumErledigen: WiedervorlageE2E = {
     ...createWiedervorlageItem('WiedervorlageZumErledigen'),
diff --git a/alfa-client/apps/alfa-e2e/src/fixtures/argocd/by-main-dev.yaml b/alfa-client/apps/alfa-e2e/src/fixtures/argocd/by-main-dev.yaml
index c73587a0b07ff1fb36e484323bd8f5ea31a19300..00e4ac5efb4577ca7cec3289756e6a85b464340d 100644
--- a/alfa-client/apps/alfa-e2e/src/fixtures/argocd/by-main-dev.yaml
+++ b/alfa-client/apps/alfa-e2e/src/fixtures/argocd/by-main-dev.yaml
@@ -9,6 +9,8 @@ project:
 alfa:
   env:
     overrideSpringProfiles: "oc,e2e,dev"
+  customList:
+    ozgcloud_feature_bescheid-wizard: "true"
   ingress:
     use_staging_cert: true
   ozgcloud:
@@ -20,11 +22,12 @@ alfa:
 vorgang_manager:
   env:
     overrideSpringProfiles: "oc,e2e,dev"
-    ozgcloud_bescheid_smart_documents_url: http://smocker:8080/smartdocuments
-    ozgcloud_bescheid_smart_documents_basic_auth_username: MGM
-    ozgcloud_bescheid_smart_documents_basic_auth_password: MGM
-    ozgcloud_bescheid_smart_documents_template_group: OzgCloudTest
-    ozgcloud_bescheid_smart_documents_template: Halteverbot
+    customList:
+      ozgcloud_bescheid_smart_documents_url: http://smocker:8080/smartdocuments
+      ozgcloud_bescheid_smart_documents_basic_auth_username: MGM
+      ozgcloud_bescheid_smart_documents_basic_auth_password: MGM
+      ozgcloud_bescheid_smart_documents_template_group: OzgCloudTest
+      ozgcloud_bescheid_smart_documents_template: Halteverbot
   elasticsearch:
     enabled: true
   replicaCount: 1
diff --git a/alfa-client/apps/alfa-e2e/src/fixtures/user-main/user_zelda.json b/alfa-client/apps/alfa-e2e/src/fixtures/user-main/user_zelda.json
new file mode 100644
index 0000000000000000000000000000000000000000..a283f68b0934c9f7b991b4ca08ba36caefa20853
--- /dev/null
+++ b/alfa-client/apps/alfa-e2e/src/fixtures/user-main/user_zelda.json
@@ -0,0 +1,12 @@
+{
+  "name": "zelda",
+  "password": "Y9nk43yrQ_zzIPpfFU-I",
+  "firstName": "Zelda",
+  "lastName": "Zusammen",
+  "fullName": "Zelda Zusammen",
+  "email": "zelda.z@ozg-sh.de",
+  "initials": "ZZ",
+  "dataTestId": "Zelda_Zusammen",
+  "clientRoles": ["VERWALTUNG_USER"],
+  "groups": ["E2E Tests"]
+}
diff --git a/alfa-client/apps/alfa-e2e/src/fixtures/usermanager/usermanager_user_zelda.json b/alfa-client/apps/alfa-e2e/src/fixtures/usermanager/usermanager_user_zelda.json
new file mode 100644
index 0000000000000000000000000000000000000000..f41f879cb6fdddb220a07c880ebc5fba946a7da0
--- /dev/null
+++ b/alfa-client/apps/alfa-e2e/src/fixtures/usermanager/usermanager_user_zelda.json
@@ -0,0 +1,18 @@
+{
+  "_id": {
+    "$oid": "63284e55c39b316b2ad02e2z"
+  },
+  "createdAt": {
+    "$date": "2024-08-14T13:11:56.489Z"
+  },
+  "deleted": false,
+  "keycloakUserId": "2ccf0c13-da74-4516-ae3d-f46d30e8ec0c",
+  "firstName": "Zelda",
+  "fullName": "Zelda Zusammen",
+  "lastName": "Zusammen",
+  "email": "zelda-z@ozg-sh.de",
+  "lastSyncTimestamp": 1663585874687,
+  "organisationsEinheitIds": ["9797773", "9093371"],
+  "roles": ["VERWALTUNG_USER"],
+  "username": "zelda"
+}
diff --git a/alfa-client/apps/alfa-e2e/src/fixtures/vorgang/vorgang.json b/alfa-client/apps/alfa-e2e/src/fixtures/vorgang/vorgang.json
index 7db3791c3468b1f263a22f255637f3153de69eee..fd4d23ab75d2d554467e4631abb1848acefd52f7 100644
--- a/alfa-client/apps/alfa-e2e/src/fixtures/vorgang/vorgang.json
+++ b/alfa-client/apps/alfa-e2e/src/fixtures/vorgang/vorgang.json
@@ -12,6 +12,7 @@
   "status": "NEU",
   "inCreation": false,
   "header": {
+    "collaborationLevel": 0,
     "serviceKonto": {
       "type": "OSI",
       "postfachAddresses": [
diff --git a/alfa-client/apps/alfa-e2e/src/model/vorgang.ts b/alfa-client/apps/alfa-e2e/src/model/vorgang.ts
index aca577c4cea54f5d30ca05ca61956be6cb82099b..7fdbcfd62b93935aef7f35cb4a4f7fc1858c4422 100644
--- a/alfa-client/apps/alfa-e2e/src/model/vorgang.ts
+++ b/alfa-client/apps/alfa-e2e/src/model/vorgang.ts
@@ -67,6 +67,7 @@ export class VorgangE2E {
 
 export class VorgangHeaderE2E {
   serviceKonto: ServiceKontoE2E;
+  collaborationLevel: number;
 }
 
 export class ServiceKontoE2E {
diff --git a/alfa-client/apps/alfa-e2e/src/page-objects/postfach-mail.component.po.ts b/alfa-client/apps/alfa-e2e/src/page-objects/postfach-mail.component.po.ts
index bdc5117cb20b887bf36518c3d69e953658dab84a..2fc2899824fd391130ecc1088b277d7d48a1d408 100644
--- a/alfa-client/apps/alfa-e2e/src/page-objects/postfach-mail.component.po.ts
+++ b/alfa-client/apps/alfa-e2e/src/page-objects/postfach-mail.component.po.ts
@@ -26,10 +26,11 @@ import { PostfachMailSubnavigation } from '../components/postfach/postfach-mail-
 import { PostfachMailListItem } from '../components/postfach/postfach-mail.e2e.component';
 
 export class PostfachMailPage {
-  private readonly breadcrump: string = 'postfach-breadcrump';
   private readonly root: string = 'postfach-mail-list';
   private readonly downloadButton: string = 'postfach-pdf-export-button';
   private readonly mailText: string = 'postfach-outgoing-nachricht';
+  private readonly heading: string = 'postfach-mail-heading';
+  private readonly headingText: string = 'Nachrichten zum Vorgang';
 
   private readonly subnavigation: PostfachMailSubnavigation = new PostfachMailSubnavigation();
 
@@ -41,8 +42,12 @@ export class PostfachMailPage {
     return this.subnavigation;
   }
 
-  getBreadcrump() {
-    return cy.getTestElement(this.breadcrump);
+  getHeading() {
+    return cy.getTestElement(this.heading);
+  }
+
+  getHeadingText() {
+    return this.headingText;
   }
 
   getListItem(subject: string): PostfachMailListItem {
diff --git a/alfa-client/apps/alfa-e2e/src/page-objects/vorgang.po.ts b/alfa-client/apps/alfa-e2e/src/page-objects/vorgang.po.ts
index 835cc89685361d2d76198e0c331c3a81107fbce8..8b0ef02c9f9fde49c3fa1f498e8db784f02865aa 100644
--- a/alfa-client/apps/alfa-e2e/src/page-objects/vorgang.po.ts
+++ b/alfa-client/apps/alfa-e2e/src/page-objects/vorgang.po.ts
@@ -36,6 +36,7 @@ import { VorgangFormularDatenE2EComponent } from '../components/vorgang/vorgang-
 import { VorgangForwardingE2EComponent } from '../components/vorgang/vorgang-forward.e2e.component';
 import { VorgangMoreMenuE2EComponent } from '../components/vorgang/vorgang-more-menu.e2e.components';
 import { VorgangSubnavigationE2EComponent } from '../components/vorgang/vorgang-subnavigation';
+import { VorgangZusammenarbeitE2EComponent } from '../components/vorgang/vorgang-zusammenarbeit.e2e.component';
 import { WiedervorlagenInVorgangE2EComponent } from '../components/wiedervorlage/wiedervorlagen-in-vorgang.e2e.component';
 
 export class VorgangPage {
@@ -64,6 +65,8 @@ export class VorgangPage {
   private readonly postfachMailContainer: PostfachMailE2EComponent = new PostfachMailE2EComponent();
   private readonly antragstellerContainer: AntragstellerE2EComponent =
     new AntragstellerE2EComponent();
+  private readonly zusammenArbeitContainer: VorgangZusammenarbeitE2EComponent =
+    new VorgangZusammenarbeitE2EComponent();
 
   private readonly fixedDialog: FixedDialogE2EComponent = new FixedDialogE2EComponent();
   private readonly postfachMailFormular: PostfachMailFormularE2EComponent =
@@ -132,6 +135,10 @@ export class VorgangPage {
     return this.antragstellerContainer;
   }
 
+  public getZusammenarbeitContainer(): VorgangZusammenarbeitE2EComponent {
+    return this.zusammenArbeitContainer;
+  }
+
   public getProgressBar() {
     return cy.getTestElement(this.locatorProgressBar);
   }
diff --git a/alfa-client/apps/alfa-e2e/src/support/angular.util.ts b/alfa-client/apps/alfa-e2e/src/support/angular.util.ts
index 4cfea18d440c803df4eb711ab82f0b7a808b9e9f..c2a2187e14ea6dab14577d723fafb49f8f0b85cb 100644
--- a/alfa-client/apps/alfa-e2e/src/support/angular.util.ts
+++ b/alfa-client/apps/alfa-e2e/src/support/angular.util.ts
@@ -39,8 +39,8 @@ enum AngularElementE2E {
 
 export function hasTooltip(element: any, value: string) {
   mouseEnter(element);
-  // element.get('mat-tooltip-component').contains(value);
-  element.get(`div[title="${value}"]`);
+  element.get('mat-tooltip-component').contains(value);
+  // element.get(`div[title="${value}"]`);
 }
 
 export function isChecked(element: any) {
diff --git a/alfa-client/apps/alfa-e2e/src/support/user-util.ts b/alfa-client/apps/alfa-e2e/src/support/user-util.ts
index cf437c63163898a88410f7bbb47143774a312967..a89ac2641cc41863bbce0534b308f3c6cc24ad85 100644
--- a/alfa-client/apps/alfa-e2e/src/support/user-util.ts
+++ b/alfa-client/apps/alfa-e2e/src/support/user-util.ts
@@ -27,11 +27,13 @@ import { initUsermanagerData, login } from './cypress-helper';
 
 const sabineFixture: UserE2E = require('../fixtures/user-main/user_sabine.json');
 const dorotheaFixture: UserE2E = require('../fixtures/user-main/user_dorothea.json');
+const zeldaFixture: UserE2E = require('../fixtures/user-main/user_zelda.json');
 
 const userManagerSabineFixture: UsermanagerUserE2E = require('../fixtures/usermanager/usermanager_user_sabine.json');
 const userManagerPeterFixture: UsermanagerUserE2E = require('../fixtures/usermanager/usermanager_user_peter.json');
 const userManagerEmilFixture: UsermanagerUserE2E = require('../fixtures/usermanager/usermanager_user_emil.json');
 const userManagerDorotheaFixture: UsermanagerUserE2E = require('../fixtures/usermanager/usermanager_user_dorothea.json');
+const userManagerZeldaFixture: UsermanagerUserE2E = require('../fixtures/usermanager/usermanager_user_zelda.json');
 
 export function initUsermanagerUsers() {
   initUsermanagerData([
@@ -39,6 +41,7 @@ export function initUsermanagerUsers() {
     getUserManagerUserPeter(),
     getUserManagerUserEmil(),
     getUserManagerUserDorothea(),
+    //getUserManagerUserZelda(),
   ]);
 }
 
@@ -50,6 +53,10 @@ export function getUserDorothea(): UserE2E {
   return dorotheaFixture;
 }
 
+export function getUserZelda(): UserE2E {
+  return zeldaFixture;
+}
+
 export function getUserManagerUserSabine(): UsermanagerUserE2E {
   return userManagerSabineFixture;
 }
@@ -66,6 +73,10 @@ export function getUserManagerUserDorothea(): UsermanagerUserE2E {
   return userManagerDorotheaFixture;
 }
 
+export function getUserManagerUserZelda(): UsermanagerUserE2E {
+  return userManagerZeldaFixture;
+}
+
 export function getUserSabineId(): string {
   return getUserManagerUserSabine()._id.$oid;
 }
@@ -77,6 +88,7 @@ enum DatabaseUser {
   PETER = 'user-main/user_peter.json',
   RICHARD = 'user-main/user_richard.json',
   SABINE = 'user-main/user_sabine.json',
+  ZELDA = 'user-main/user_zelda.json',
   ZONK = 'user-main/user_zonk.json',
 }
 
@@ -96,6 +108,10 @@ export function loginAsRichard(): void {
   login(DatabaseUser.RICHARD);
 }
 
+export function loginAsZelda(): void {
+  login(DatabaseUser.ZELDA);
+}
+
 export function loginAsSabine(): void {
   login(DatabaseUser.SABINE);
 }
diff --git a/alfa-client/apps/alfa/Caddyfile b/alfa-client/apps/alfa/Caddyfile
new file mode 100644
index 0000000000000000000000000000000000000000..440e32b476cf040c1471b9646a946ee8a2f8757a
--- /dev/null
+++ b/alfa-client/apps/alfa/Caddyfile
@@ -0,0 +1,6 @@
+:8080 {
+    file_server
+    root * /usr/share/caddy
+
+    try_files {path} /index.html
+}
\ No newline at end of file
diff --git a/alfa-client/apps/alfa/Dockerfile b/alfa-client/apps/alfa/Dockerfile
index d69c70876f7ebb414614b0d47d7e5faeb2a44f6d..8ccc0f564746885f35f3286406323cb53fca81b2 100644
--- a/alfa-client/apps/alfa/Dockerfile
+++ b/alfa-client/apps/alfa/Dockerfile
@@ -1,24 +1,20 @@
-# Benutzt das vorher zu bauende Docker image "nx-build-base:x.y.z"
-# Siehe ../Dockerfile.nx-build-base
-FROM docker.ozg-sh.de/nx-build-base:2.0.0 AS builder
+FROM caddy:2.6.4-alpine
 
-ARG NODE_ENV
-ARG CONFIGURATION
+RUN adduser --system --ingroup root caddy
 
-# Turn off Nx Daemon
-ENV CI=true
+WORKDIR /usr/share/caddy
 
-WORKDIR /app/builder
-COPY . .
+COPY apps/alfa/Caddyfile /etc/caddy/Caddyfile
 
-RUN echo "Building configuration: $CONFIGURATION..."
+COPY dist/apps/alfa /usr/share/caddy
 
-RUN npx nx build alfa --outputHashing=all --configuration ${CONFIGURATION:-development} \
-    && ./node_modules/.bin/gzipper compress ./dist --verbose --exclude jpg,jpeg,png,ico,woff,woff2
+RUN chgrp -R 0 /usr/bin/caddy /etc/caddy /config/caddy /usr/share/caddy && \
+    chmod -R g=u /usr/bin/caddy /etc/caddy /config/caddy /usr/share/caddy
 
-FROM nginx:stable-alpine
+USER caddy
 
-WORKDIR /usr/share/nginx/html
+EXPOSE 8080 8081
 
-COPY --from=builder /app/builder/dist/apps/alfa ./
-COPY --from=builder /app/builder/apps/alfa/nginx.conf /etc/nginx/nginx.conf
+ENTRYPOINT ["/usr/bin/caddy"]
+
+CMD ["run", "--config", "/etc/caddy/Caddyfile", "--adapter", "caddyfile"]
\ No newline at end of file
diff --git a/alfa-client/apps/alfa/project.json b/alfa-client/apps/alfa/project.json
index 539fb173beab9fa6efb50227f3efc49c7cc7bf37..932f9ed857394eebe857e588ed2cd2e7abea2ffb 100644
--- a/alfa-client/apps/alfa/project.json
+++ b/alfa-client/apps/alfa/project.json
@@ -122,6 +122,22 @@
       "outputs": [
         "{workspaceRoot}/coverage/apps/alfa"
       ]
+    },
+    "container": {
+      "executor": "@nx-tools/nx-container:build",
+      "options": {
+        "engine": "docker",
+        "push": false,
+        "metadata": {
+          "images": [
+            "docker.ozg-sh.de/alfa-client"
+          ],
+          "load": true,
+          "tags": [
+            "build-latest"
+          ]
+        }
+      }
     }
   }
 }
\ No newline at end of file
diff --git a/alfa-client/apps/alfa/src/app/app.component.html b/alfa-client/apps/alfa/src/app/app.component.html
index c6a6d8832b910a957f0760edc25f00836dc39001..089e9de91f369cb64da483eb2a4316543084ae53 100644
--- a/alfa-client/apps/alfa/src/app/app.component.html
+++ b/alfa-client/apps/alfa/src/app/app.component.html
@@ -28,7 +28,7 @@
     <alfa-header-container [apiRootStateResource]="apiRoot"></alfa-header-container>
 
     <div class="relative ml-4 mt-16 flex flex-grow items-start justify-between">
-      <main class="mat-app-background"><router-outlet></router-outlet></main>
+      <div class="mat-app-background relative grow"><router-outlet></router-outlet></div>
 
       <section class="mat-app-background right-nav">
         <alfa-build-info
diff --git a/alfa-client/apps/alfa/src/app/app.component.scss b/alfa-client/apps/alfa/src/app/app.component.scss
index 5c499a2b70b35c18334696fd0862a60276f9895f..723100bf7df64890adff753bfe4d2edef28ec7e5 100644
--- a/alfa-client/apps/alfa/src/app/app.component.scss
+++ b/alfa-client/apps/alfa/src/app/app.component.scss
@@ -41,13 +41,6 @@
   border-left: 1rem solid $background;
 }
 
-main {
-  position: relative;
-  flex-grow: 1;
-  max-width: calc(100vw - 2.25rem);
-  background-color: #fff;
-}
-
 .right-nav {
   flex-shrink: 0;
   position: sticky;
diff --git a/alfa-client/apps/alfa/src/styles/abstracts/_variables.scss b/alfa-client/apps/alfa/src/styles/abstracts/_variables.scss
index 21fa9559b6dcd7eafb4486651d33fb27b07d89c2..cc31ef7e6b34ed79d269902dd8e6775c3bc68603 100644
--- a/alfa-client/apps/alfa/src/styles/abstracts/_variables.scss
+++ b/alfa-client/apps/alfa/src/styles/abstracts/_variables.scss
@@ -75,6 +75,6 @@ $alfaDarkTheme: mat.define-dark-theme(
   )
 );
 
-$default-font-size: 16px;
+$default-font-size: 1rem;
 
 $iconHeight: 24px;
diff --git a/alfa-client/apps/alfa/src/styles/layout/_main.scss b/alfa-client/apps/alfa/src/styles/layout/_main.scss
index 24416fcac3cc06cd96d4740b7b2d120833cfe3f1..9d074a09ec1c0ebff15cca11c891b4cb1ebb1e5e 100644
--- a/alfa-client/apps/alfa/src/styles/layout/_main.scss
+++ b/alfa-client/apps/alfa/src/styles/layout/_main.scss
@@ -36,7 +36,7 @@
     // TODO Wofür ist der box-shadow?
     // box-shadow: inset 0 -1px 0 0 rgba(0, 0, 0, 0.08), inset 1px 0 0 rgba(0, 0, 0, 0.08), inset -1px 0 0 rgba(0, 0, 0, 0.08);
     position: relative;
-    display: block;
+    display: flex;
     min-height: calc(100vh - $header-height - $navigation-height);
     background-color: #fff;
   }
diff --git a/alfa-client/apps/alfa/src/styles/main.scss b/alfa-client/apps/alfa/src/styles/main.scss
index 996cd1abf1187ae258b8cfaee88756c340dc702d..bded7a1477336c22f6f4358a41da3ffbc82c14ee 100644
--- a/alfa-client/apps/alfa/src/styles/main.scss
+++ b/alfa-client/apps/alfa/src/styles/main.scss
@@ -57,7 +57,6 @@
 @import 'libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-list-container/wiedervorlage-list-in-vorgang-list-container.theme';
 @import 'libs/user-profile/src/lib/user-profile-in-vorgang-container/user-profile-in-vorgang/user-profile-in-vorgang.theme';
 @import 'libs/user-profile/src/lib/user-profile-search-container/user-profile-search-container.theme';
-@import 'libs/vorgang-shared-ui/src/lib/vorgang-nummer/vorgang-nummer.component.theme';
 @import 'libs/ui/src/lib/icon/postfach-icon/postfach-icon.component.theme';
 @import 'libs/ui/src/lib/ui/button-toggle/button-toogle.theme';
 @import 'libs/vorgang/src/lib/vorgang-list-page-container/vorgang-list-page/vorgang-filter-menu-container/vorgang-filter-menu/_vorgang-filter-item.theme.scss';
@@ -83,3 +82,27 @@ body.dark {
   @include mat.all-component-colors($alfaDarkTheme);
   @include custom-components-theme($alfaDarkTheme);
 }
+
+body {
+  --mdc-filled-text-field-label-text-size: 1rem;
+  --mdc-form-field-label-text-size: 12rem;
+}
+
+// Material Datepicker font-sizes
+.mat-datepicker-content {
+  .mat-button, .mat-fab, .mat-icon-button, .mat-mini-fab, .mat-raised-button,th,td {
+       font-size: 1rem
+   }
+ }
+
+.mdc-text-field__input {
+  font-size: 1rem !important;
+}
+
+.mat-calendar-table-header th {
+  font-size: 0.875rem !important;
+}
+
+.mdc-button__label {
+  font-size: 0.875rem !important;
+}
\ No newline at end of file
diff --git a/alfa-client/apps/alfa/src/styles/material/_autocomplete.scss b/alfa-client/apps/alfa/src/styles/material/_autocomplete.scss
index f4c86c65ffaf0fdeff8b1c1ee050f786136acdca..7cdf9cd39e3d7374043becae32bd2aca23dce90f 100644
--- a/alfa-client/apps/alfa/src/styles/material/_autocomplete.scss
+++ b/alfa-client/apps/alfa/src/styles/material/_autocomplete.scss
@@ -46,7 +46,7 @@
 
     .mat-mdc-option {
       border-top: 1px solid rgba(0, 0, 0, 0.08);
-      font-size: 14px;
+      font-size: 0.875rem;
       padding: 0.5rem 1rem;
       margin-bottom: 0 !important;
 
diff --git a/alfa-client/apps/alfa/src/styles/material/_dialog.scss b/alfa-client/apps/alfa/src/styles/material/_dialog.scss
index ac715993faddf5592a3be69d8bf4f0191cda7639..0de26a163ce47c4047a24c95bf8823be55747fe5 100644
--- a/alfa-client/apps/alfa/src/styles/material/_dialog.scss
+++ b/alfa-client/apps/alfa/src/styles/material/_dialog.scss
@@ -5,9 +5,9 @@
   $color-config: mat.get-color-config($theme);
   $primary-palette: map.get($color-config, 'primary');
 
-  h1 {
+  h1.mat-mdc-dialog-title {
     color: mat.get-color-from-palette($primary-palette) !important;
-    font-size: 24px !important;
+    font-size: 1.5rem !important;
     font-weight: normal !important;
   }
 
diff --git a/alfa-client/apps/alfa/src/styles/material/_expansion-panel.scss b/alfa-client/apps/alfa/src/styles/material/_expansion-panel.scss
index e5c83366af924cf6831cde0584e1bbcfc79e1463..6a112124d5c3d02971ca4150048589d2516fa1da 100644
--- a/alfa-client/apps/alfa/src/styles/material/_expansion-panel.scss
+++ b/alfa-client/apps/alfa/src/styles/material/_expansion-panel.scss
@@ -43,7 +43,7 @@
       margin-bottom: 0;
       font-weight: 500;
       margin-left: 16px;
-      font-size: 16px;
+      font-size: 1rem;
     }
 
     .mat-expansion-panel-body {
@@ -57,7 +57,7 @@
 
       h3 {
         color: inherit;
-        font-size: 14px !important;
+        font-size: 0.875rem !important;
         font-weight: 500 !important;
         margin-left: 0;
       }
@@ -93,7 +93,7 @@
   background-color: inherit;
   box-shadow: none;
   border-radius: 0;
-  font-size: 14px;
+  font-size: 0.875rem;
 }
 
 :host-context(.dark) .mat-expansion-panel {
diff --git a/alfa-client/apps/alfa/src/styles/material/_formfield.scss b/alfa-client/apps/alfa/src/styles/material/_formfield.scss
index 2e22e8b8ecf4a04dc2810a38022639466d2f3962..5cd264736c1e1a67ae882b08427d5c3239d0e895 100644
--- a/alfa-client/apps/alfa/src/styles/material/_formfield.scss
+++ b/alfa-client/apps/alfa/src/styles/material/_formfield.scss
@@ -26,11 +26,12 @@ ozgcloud-fixed-dialog {
 
 body.dark {
   mat-form-field {
-    --mdc-theme-error: red;
-    --mdc-filled-text-field-error-focus-label-text-color: red;
-    --mdc-outlined-text-field-error-focus-label-text-color: red;
-    --mdc-filled-text-field-error-label-text-color: red;
-    --mdc-outlined-text-field-error-label-text-color: red;
-    --mdc-filled-text-field-disabled-active-indicator-color: red;
+    --mdc-theme-error: theme('colors.error');
+    --mat-form-field-error-text-color: theme('colors.error');
+    --mdc-filled-text-field-error-focus-label-text-color: theme('colors.error');
+    --mdc-outlined-text-field-error-focus-label-text-color: theme('colors.error');
+    --mdc-filled-text-field-error-label-text-color: theme('colors.error');
+    --mdc-outlined-text-field-error-label-text-color: theme('colors.error');
+    --mdc-filled-text-field-disabled-active-indicator-color: theme('colors.error');
   }
 }
diff --git a/alfa-client/apps/alfa/src/styles/material/_menu.scss b/alfa-client/apps/alfa/src/styles/material/_menu.scss
index 835661a949456ec3e8e6d43eeb8769b7a43b9a81..44aff52c10c60dbf929877ec4ad7ae9e8f68d7a5 100644
--- a/alfa-client/apps/alfa/src/styles/material/_menu.scss
+++ b/alfa-client/apps/alfa/src/styles/material/_menu.scss
@@ -19,5 +19,6 @@ alfa-help-menu {
     height: 40px;
     width: auto;
     padding: 0.5rem;
+    font-size: 0.875rem;
   }
 }
diff --git a/alfa-client/apps/alfa/src/styles/material/_tabs.scss b/alfa-client/apps/alfa/src/styles/material/_tabs.scss
index bee57c8e73b9d5e394d29aa191893e7861a5d667..ea2ff487ba61bf4575526a42460f329721d72a13 100644
--- a/alfa-client/apps/alfa/src/styles/material/_tabs.scss
+++ b/alfa-client/apps/alfa/src/styles/material/_tabs.scss
@@ -35,3 +35,6 @@
     margin-right: 0 !important;
   }
 }
+.mat-mdc-tab .mdc-tab__text-label {
+  font-size: 0.875rem;
+}
\ No newline at end of file
diff --git a/alfa-client/apps/alfa/src/styles/material/_tooltip.scss b/alfa-client/apps/alfa/src/styles/material/_tooltip.scss
index 543eb47ab24a3ce0049bb07400bcf584e2e58af7..44e46b2feb56657f26f6ac3db31b1fcee8a20c32 100644
--- a/alfa-client/apps/alfa/src/styles/material/_tooltip.scss
+++ b/alfa-client/apps/alfa/src/styles/material/_tooltip.scss
@@ -1,5 +1,5 @@
 .mat-tooltip {
-  font-size: 12px !important;
+  font-size: 0.75rem !important;
   padding-top: 2px !important;
   padding-bottom: 2px !important;
   margin-top: 2px !important;
diff --git a/alfa-client/apps/demo/src/app/app.component.html b/alfa-client/apps/demo/src/app/app.component.html
index 81bc4dff284d5e739981af85b8d4e1cc0c4b3844..7dbdd36d8134a9a38fdd859b1371c5a0362820df 100644
--- a/alfa-client/apps/demo/src/app/app.component.html
+++ b/alfa-client/apps/demo/src/app/app.component.html
@@ -14,6 +14,16 @@
       <nav>NAV</nav>
     </div>
     <main class="flex-auto bg-background-50 p-6">
+      <div class="my-5">
+        <ods-instant-search
+          headerText="In der OZG-Cloud"
+          placeholder="zuständige Stelle suchen"
+          [control]="instantSearchFormControl"
+          [searchResults]="getInstantSearchResults()"
+          (searchResultSelected)="selectSearchResult($event)"
+          (searchQueryChanged)="onSearchQueryChanged($event)"
+        ></ods-instant-search>
+      </div>
       <div class="w-96">
         <ods-attachment-wrapper>
           <ods-attachment
@@ -21,6 +31,7 @@
             description="234 kB"
             fileType="pdf"
             isLoading="true"
+            loadingCaption="Mein_Bescheid.pdf wird heruntergeladen..."
           >
           </ods-attachment>
           <ods-attachment caption="Mein_Bescheid.xml" description="234 kB" fileType="xml">
@@ -94,7 +105,7 @@
             value="abgelehnt"
             variant="bescheid_abgelehnt"
           >
-            <ods-close-icon class="fill-abgelehnt" />
+            <ods-close-icon class="fill-abgelehnt" size="large" />
           </ods-radio-button-card>
         </div>
       </form>
@@ -209,14 +220,6 @@
             <p text class="text-center">Bescheiddokument<br />hochladen</p></ods-file-upload-button
           >
         </div>
-
-        <div class="mt-4">
-          <ods-file-upload-button class="w-72" [isLoading]="false" id="upload129">
-            <ods-bescheid-upload-icon />
-            <ods-spinner-icon spinner size="medium" />
-            <div text class="text-center">Anhang hochladen</div></ods-file-upload-button
-          >
-        </div>
         <div class="mt-4">
           <ods-file-upload-button class="w-72" [isLoading]="true" id="upload130">
             <ods-attachment-icon icon />
diff --git a/alfa-client/apps/demo/src/app/app.component.ts b/alfa-client/apps/demo/src/app/app.component.ts
index 5d64b15a623f2330d29201455ec298907bcd94fa..fbd58a87093ed57b19c83b1e1c78151e75ca1b66 100644
--- a/alfa-client/apps/demo/src/app/app.component.ts
+++ b/alfa-client/apps/demo/src/app/app.component.ts
@@ -15,6 +15,8 @@ import {
   ErrorMessageComponent,
   FileIconComponent,
   FileUploadButtonComponent,
+  InstantSearchComponent,
+  OfficeIconComponent,
   RadioButtonCardComponent,
   SaveIconComponent,
   SendIconComponent,
@@ -24,6 +26,12 @@ import {
   TextareaComponent,
 } from '@ods/system';
 
+import { EMPTY_STRING } from '@alfa-client/tech-shared';
+import { Resource } from '@ngxp/rest';
+import {
+  InstantSearchQuery,
+  InstantSearchResult,
+} from 'libs/design-system/src/lib/instant-search/instant-search/instant-search.model';
 import { BescheidDialogExampleComponent } from './components/bescheid-dialog/bescheid-dialog.component';
 import { BescheidPaperComponent } from './components/bescheid-paper/bescheid-paper.component';
 import { BescheidStepperComponent } from './components/bescheid-stepper/bescheid-stepper.component';
@@ -46,6 +54,8 @@ import { CustomStepperComponent } from './components/cdk-demo/custom-stepper.com
     BescheidPaperComponent,
     RadioButtonCardComponent,
     ReactiveFormsModule,
+    InstantSearchComponent,
+    OfficeIconComponent,
     SaveIconComponent,
     SendIconComponent,
     StampIconComponent,
@@ -64,14 +74,45 @@ import { CustomStepperComponent } from './components/cdk-demo/custom-stepper.com
   templateUrl: './app.component.html',
 })
 export class AppComponent {
-  title = 'demo';
-
   darkMode = signal<boolean>(JSON.parse(window.localStorage.getItem('darkMode') ?? 'false'));
 
   @HostBinding('class.dark') get mode() {
     return this.darkMode();
   }
 
+  title = 'demo';
+
+  instantSearchItems: InstantSearchResult<Resource>[] = [
+    {
+      title: 'Landeshauptstadt Kiel - Ordnungsamt, Gewerbe- und Schornsteinfegeraufsicht',
+      description: 'Fabrikstraße  8-10, 24103 Kiel',
+    },
+    {
+      title: 'Amt für Digitalisierung, Breitband und Vermessung Nürnberg Außenstelle Hersbruck',
+      description: 'Rathausmarkt 7, Hersbruck',
+    },
+    {
+      title: 'Amt für Digitalisierung, Breitband und Vermessung Stuttgart',
+      description: 'Rathausmarkt 7, Stuttgart',
+    },
+    {
+      title: 'Amt für Digitalisierung, Breitband und Vermessung Ulm',
+      description: 'Rathausmarkt 7, Ulm',
+    },
+  ];
+  instantSearchFormControl = new FormControl(EMPTY_STRING);
+
+  getInstantSearchResults() {
+    if (this.instantSearchFormControl.value.length < 2) return [];
+    return this.instantSearchItems.filter((item) =>
+      item.title.toLowerCase().includes(this.instantSearchFormControl.value.toLowerCase()),
+    );
+  }
+
+  selectSearchResult(result: InstantSearchResult<Resource>) {
+    console.log(result);
+  }
+
   exampleForm = new FormGroup({
     exampleName: new FormControl('bewilligt'),
   });
@@ -87,4 +128,8 @@ export class AppComponent {
       window.localStorage.setItem('darkMode', JSON.stringify(this.darkMode()));
     });
   }
+
+  public onSearchQueryChanged(searchQuery: InstantSearchQuery) {
+    console.info('Search query: %o', searchQuery);
+  }
 }
diff --git a/alfa-client/libs/admin-settings/src/lib/postfach/postfach-container/postfach-form/postfach-form.component.spec.ts b/alfa-client/libs/admin-settings/src/lib/postfach/postfach-container/postfach-form/postfach-form.component.spec.ts
index f786c3e04a73e2bc719cacf654aaf0c01d77039d..f3e6c68f3f15f51d766224ea4add00605a4e05be 100644
--- a/alfa-client/libs/admin-settings/src/lib/postfach/postfach-container/postfach-form/postfach-form.component.spec.ts
+++ b/alfa-client/libs/admin-settings/src/lib/postfach/postfach-container/postfach-form/postfach-form.component.spec.ts
@@ -175,7 +175,7 @@ describe('PostfachFormComponent', () => {
     function createProblemDetailForAbsenderName(): ProblemDetail {
       return {
         ...createProblemDetail(),
-        'invalid-params': [{ ...createInvalidParam(), name: 'settingBody.absender.name' }],
+        invalidParams: [{ ...createInvalidParam(), name: 'settingBody.absender.name' }],
       };
     }
 
diff --git a/alfa-client/libs/admin-settings/src/lib/shared/text-field/text-field.component.html b/alfa-client/libs/admin-settings/src/lib/shared/text-field/text-field.component.html
index 2baa2a383b01b1e32ac4295240fc0a0890a47f52..303f8720da7e44c2cdcc5618f70a64d366e4c64e 100644
--- a/alfa-client/libs/admin-settings/src/lib/shared/text-field/text-field.component.html
+++ b/alfa-client/libs/admin-settings/src/lib/shared/text-field/text-field.component.html
@@ -13,11 +13,11 @@
     />
   </label>
   <div
-    *ngIf="errorMessages.length > 0"
+    *ngIf="invalidParams.length > 0"
     [attr.data-test-id]="'text-field-errors-' + label | convertForDataTest"
   >
-    <span class="mb-3 italic text-red-500" *ngFor="let errorMessage of errorMessages">{{
-      errorMessage
+    <span class="mb-3 italic text-red-500" *ngFor="let invalidParam of invalidParams">{{
+      getErrorMessage(invalidParam)
     }}</span>
   </div>
 </div>
diff --git a/alfa-client/libs/admin-settings/src/lib/shared/text-field/text-field.component.spec.ts b/alfa-client/libs/admin-settings/src/lib/shared/text-field/text-field.component.spec.ts
index 44f27c6b31b79144a38f750312ba6404f2e00647..9096bedd3ab98897a3adc9474b291c7703144572 100644
--- a/alfa-client/libs/admin-settings/src/lib/shared/text-field/text-field.component.spec.ts
+++ b/alfa-client/libs/admin-settings/src/lib/shared/text-field/text-field.component.spec.ts
@@ -1,37 +1,22 @@
-import { ConvertForDataTestPipe } from '@alfa-client/tech-shared';
-import { getElementFromFixture, notExistsAsHtmlElement } from '@alfa-client/test-utils';
+import { ConvertForDataTestPipe, InvalidParam } from '@alfa-client/tech-shared';
 import { ComponentFixture, TestBed } from '@angular/core/testing';
-import { FormControl, NgControl, ReactiveFormsModule, ValidationErrors } from '@angular/forms';
-import { getDataTestIdOf } from 'libs/tech-shared/test/data-test';
+import { ReactiveFormsModule } from '@angular/forms';
+import { createInvalidParam, createProblemDetail } from 'libs/tech-shared/test/error';
 import { TextFieldComponent } from './text-field.component';
 
+import * as TechValidationUtil from 'libs/tech-shared/src/lib/validation/tech.validation.util';
+
 describe('TextFieldComponent', () => {
   let component: TextFieldComponent;
   let fixture: ComponentFixture<TextFieldComponent>;
 
   const label = 'custom';
-  const spanSelector = getDataTestIdOf('text-field-span-' + label);
-  const inputSelector = getDataTestIdOf('text-field-input-' + label);
-  const errorsSelector = getDataTestIdOf('text-field-errors-' + label);
-
-  const formControl = new FormControl('');
 
   beforeEach(async () => {
     await TestBed.configureTestingModule({
       declarations: [TextFieldComponent, ConvertForDataTestPipe],
       imports: [ReactiveFormsModule],
-    })
-      .overrideComponent(TextFieldComponent, {
-        add: {
-          providers: [
-            {
-              provide: NgControl,
-              useValue: formControl,
-            },
-          ],
-        },
-      })
-      .compileComponents();
+    }).compileComponents();
 
     fixture = TestBed.createComponent(TextFieldComponent);
     component = fixture.componentInstance;
@@ -43,62 +28,39 @@ describe('TextFieldComponent', () => {
     expect(component).toBeTruthy();
   });
 
-  it('should use label', () => {
-    const labelElement = getElementFromFixture(fixture, spanSelector);
-    expect(labelElement.textContent).toBe(label);
-  });
-
-  it('should use form control', () => {
-    const fieldText = 'text';
-    component.writeValue(fieldText);
-
-    fixture.detectChanges();
-
-    const inputElement = getElementFromFixture(fixture, inputSelector);
-    expect(inputElement.value).toBe(fieldText);
-  });
+  describe('getErrorMessage', () => {
+    it('should call getMessageForInvalidParam()', () => {
+      const getMessageForInvalidParam: jest.SpyInstance<string, [string, InvalidParam]> =
+        jest.spyOn(TechValidationUtil, 'getMessageForInvalidParam');
+      const invalidParam: InvalidParam = createInvalidParam();
 
-  describe('invalid indication', () => {
-    it('should show as red if invalid', () => {
-      formControl.setErrors({ someErrorCode: 'Invalid' });
+      component.getErrorMessage(invalidParam);
 
-      fixture.detectChanges();
-
-      const labelElement = getElementFromFixture(fixture, spanSelector);
-      expect([...labelElement.classList]).toEqual(['text-red-500', 'font-bold']);
+      expect(getMessageForInvalidParam).toHaveBeenCalledWith(label, invalidParam);
     });
+  });
 
-    it('should not show as red if valid', () => {
-      formControl.setErrors(null);
+  describe('show error messages', () => {
+    it('should not call getErrorMessage() if no error', () => {
+      component.getErrorMessage = jest.fn();
+      component.fieldControl.setErrors({});
 
       fixture.detectChanges();
 
-      const labelElement = getElementFromFixture(fixture, spanSelector);
-      expect([...labelElement.classList]).toEqual([]);
+      expect(component.getErrorMessage).not.toHaveBeenCalled();
     });
-  });
 
-  describe('error messages', () => {
-    it('should not show empty error message container', () => {
-      fixture.detectChanges();
-
-      notExistsAsHtmlElement(fixture, errorsSelector);
-    });
+    it('should call getErrorMessage() if error', () => {
+      component.getErrorMessage = jest.fn();
 
-    it('should show error messages', () => {
-      const errors: ValidationErrors = {
-        firstMessage: 'first',
-        secondMessage: 'second',
-      };
-      formControl.setErrors(errors);
+      component.fieldControl.setErrors({
+        ...createProblemDetail(),
+        invalidParams: [{ ...createInvalidParam(), name: 'settingBody.absender.name' }],
+      });
 
       fixture.detectChanges();
 
-      const errorsElement: HTMLElement = getElementFromFixture(fixture, errorsSelector);
-      const spansTexts = Array.from(errorsElement.querySelectorAll('span')).map(
-        (span) => span.textContent,
-      );
-      expect(spansTexts).toEqual(Object.values(errors));
+      expect(component.getErrorMessage).toHaveBeenCalled();
     });
   });
 });
diff --git a/alfa-client/libs/admin-settings/src/lib/shared/text-field/text-field.component.ts b/alfa-client/libs/admin-settings/src/lib/shared/text-field/text-field.component.ts
index bca9352718c8cbdb0e8f0434095d574215da1577..00037394425175ac3fcca9fe68b1ba286e3c6315 100644
--- a/alfa-client/libs/admin-settings/src/lib/shared/text-field/text-field.component.ts
+++ b/alfa-client/libs/admin-settings/src/lib/shared/text-field/text-field.component.ts
@@ -1,4 +1,4 @@
-import { isNotNil } from '@alfa-client/tech-shared';
+import { getMessageForInvalidParam, InvalidParam } from '@alfa-client/tech-shared';
 import { Component, Input } from '@angular/core';
 import { FormControlEditorAbstractComponent } from '@ods/component';
 
@@ -10,7 +10,7 @@ export class TextFieldComponent extends FormControlEditorAbstractComponent {
   @Input()
   label: string;
 
-  get errorMessages(): string[] {
-    return isNotNil(this.control?.errors) ? Object.values(this.control.errors) : [];
+  public getErrorMessage(invalidParam: InvalidParam): string {
+    return getMessageForInvalidParam(this.label, invalidParam);
   }
 }
diff --git a/alfa-client/libs/bescheid-shared/src/lib/+state/bescheid.facade.spec.ts b/alfa-client/libs/bescheid-shared/src/lib/+state/bescheid.facade.spec.ts
index 49c3f00e0dec46f8de9e73fc639f637cc2cb73b2..329ddf97fb780671d82c886e829226a28260782d 100644
--- a/alfa-client/libs/bescheid-shared/src/lib/+state/bescheid.facade.spec.ts
+++ b/alfa-client/libs/bescheid-shared/src/lib/+state/bescheid.facade.spec.ts
@@ -4,7 +4,7 @@ import {
   CommandService,
   CreateCommand,
 } from '@alfa-client/command-shared';
-import { EMPTY_STRING, StateResource, createStateResource } from '@alfa-client/tech-shared';
+import { createStateResource, EMPTY_STRING, StateResource } from '@alfa-client/tech-shared';
 import { Mock, mock, useFromMock } from '@alfa-client/test-utils';
 import { VorgangWithEingangLinkRel, VorgangWithEingangResource } from '@alfa-client/vorgang-shared';
 import { Store } from '@ngrx/store';
@@ -43,60 +43,22 @@ describe('BescheidFacade', () => {
     });
   });
 
-  describe('createBescheid', () => {
+  describe('createBescheidDraft', () => {
     const createCommand: CreateCommand = createCreateCommand(CommandOrder.CREATE_BESCHEID);
 
-    describe('with both Links', () => {
-      it('should call command service with CREATE_BESCHEID linkRel', () => {
-        const vorgang: VorgangWithEingangResource = createVorgangWithEingangResource([
-          VorgangWithEingangLinkRel.CREATE_BESCHEID,
-          VorgangWithEingangLinkRel.CREATE_BESCHEID_DRAFT,
-        ]);
-        facade.createBescheid(vorgang, createCommand);
+    it('should create command', () => {
+      const vorgang: VorgangWithEingangResource = createVorgangWithEingangResource([
+        VorgangWithEingangLinkRel.CREATE_BESCHEID_DRAFT,
+      ]);
 
-        expect(commandService.createCommandByProps).toHaveBeenCalledWith({
-          resource: vorgang,
-          linkRel: VorgangWithEingangLinkRel.CREATE_BESCHEID,
-          command: createCommand,
-        });
-      });
-    });
-
-    describe('with CREATE_BESCHEID_DRAFT link', () => {
-      it('should call command service with CREATE_BESCHEID_DRAFT linkRel and empty snackBarMessage', () => {
-        const vorgang: VorgangWithEingangResource = createVorgangWithEingangResource([
-          VorgangWithEingangLinkRel.CREATE_BESCHEID_DRAFT,
-        ]);
-        facade.createBescheid(vorgang, createCommand);
-
-        expect(commandService.createCommandByProps).toHaveBeenCalledWith({
-          resource: vorgang,
-          linkRel: VorgangWithEingangLinkRel.CREATE_BESCHEID_DRAFT,
-          command: createCommand,
-          snackBarMessage: EMPTY_STRING,
-        });
-      });
-    });
-
-    describe('with CREATE_BESCHEID link', () => {
-      it('should call command service with CREATE_BESCHEID_DRAFT linkRel', () => {
-        const vorgang: VorgangWithEingangResource = createVorgangWithEingangResource([
-          VorgangWithEingangLinkRel.CREATE_BESCHEID,
-        ]);
-
-        facade.createBescheid(vorgang, createCommand);
+      facade.createBescheidDraft(vorgang, createCommand);
 
-        expect(commandService.createCommandByProps).toHaveBeenCalledWith({
-          resource: vorgang,
-          linkRel: VorgangWithEingangLinkRel.CREATE_BESCHEID,
-          command: createCommand,
-        });
+      expect(commandService.createCommandByProps).toHaveBeenCalledWith({
+        resource: vorgang,
+        linkRel: VorgangWithEingangLinkRel.CREATE_BESCHEID_DRAFT,
+        command: createCommand,
+        snackBarMessage: EMPTY_STRING,
       });
     });
-    it('should emit error if link is missing()', () => {
-      const vorgang: VorgangWithEingangResource = createVorgangWithEingangResource();
-
-      expect(() => facade.createBescheid(vorgang, createCommand)).toThrowError();
-    });
   });
 });
diff --git a/alfa-client/libs/bescheid-shared/src/lib/+state/bescheid.facade.ts b/alfa-client/libs/bescheid-shared/src/lib/+state/bescheid.facade.ts
index 35933803d5b40bdf4c79f94c3973fa1be790c471..d338a17a00b1bdfd2f6805f333036b90635a623d 100644
--- a/alfa-client/libs/bescheid-shared/src/lib/+state/bescheid.facade.ts
+++ b/alfa-client/libs/bescheid-shared/src/lib/+state/bescheid.facade.ts
@@ -8,7 +8,6 @@ import { EMPTY_STRING, StateResource } from '@alfa-client/tech-shared';
 import { VorgangWithEingangLinkRel, VorgangWithEingangResource } from '@alfa-client/vorgang-shared';
 import { Injectable } from '@angular/core';
 import { Store } from '@ngrx/store';
-import { hasLink } from '@ngxp/rest';
 import { Observable } from 'rxjs';
 
 import * as BescheidSelectors from './bescheid.selectors';
@@ -24,31 +23,6 @@ export class BescheidFacade {
     return this.store.select(BescheidSelectors.bescheidCommand);
   }
 
-  public createBescheid(
-    vorgangWithEingang: VorgangWithEingangResource,
-    command: CreateCommand,
-  ): void {
-    if (hasLink(vorgangWithEingang, VorgangWithEingangLinkRel.CREATE_BESCHEID)) {
-      return this.createBescheidKiel(vorgangWithEingang, command);
-    }
-    if (hasLink(vorgangWithEingang, VorgangWithEingangLinkRel.CREATE_BESCHEID_DRAFT)) {
-      return this.createBescheidDraft(vorgangWithEingang, command);
-    }
-    throw new Error('Missing Link: CREATE_BESCHEID or CREATE_BESCHEID_DRAFT expected');
-  }
-
-  public createBescheidKiel(
-    vorgangWithEingang: VorgangWithEingangResource,
-    command: CreateCommand,
-  ): void {
-    const createCommandProps: CreateCommandProps = {
-      resource: vorgangWithEingang,
-      linkRel: VorgangWithEingangLinkRel.CREATE_BESCHEID,
-      command,
-    };
-    this.commandService.createCommandByProps(createCommandProps);
-  }
-
   public createBescheidDraft(
     vorgangWithEingang: VorgangWithEingangResource,
     command: CreateCommand,
diff --git a/alfa-client/libs/bescheid-shared/src/lib/+state/bescheid.reducer.spec.ts b/alfa-client/libs/bescheid-shared/src/lib/+state/bescheid.reducer.spec.ts
index 67058f2fbdf29b3c9d0fd5623dc297961760b677..e47c8f21156c5727a43406c6cc97551058db83f8 100644
--- a/alfa-client/libs/bescheid-shared/src/lib/+state/bescheid.reducer.spec.ts
+++ b/alfa-client/libs/bescheid-shared/src/lib/+state/bescheid.reducer.spec.ts
@@ -26,7 +26,7 @@ describe('Bescheid Reducer', () => {
         const resource: VorgangWithEingangResource = createVorgangWithEingangResource();
         const action: Action = CommandActions.createCommand({
           resource,
-          linkRel: VorgangWithEingangLinkRel.CREATE_BESCHEID,
+          linkRel: VorgangWithEingangLinkRel.CREATE_BESCHEID_DRAFT,
           command: { ...createCommandResource(), order: CommandOrder.CREATE_BESCHEID },
         });
 
diff --git a/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.spec.ts b/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.spec.ts
index 228b24efb9cd33d7d236fbb0a5b4a4499cee4169..6fba31ec8361dbb715becde41d640de4cc06b93e 100644
--- a/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.spec.ts
+++ b/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.spec.ts
@@ -33,7 +33,7 @@ import { cold } from 'jest-marbles';
 import { CommandLinkRel } from 'libs/command-shared/src/lib/command.linkrel';
 import { createApiError } from 'libs/tech-shared/test/error';
 import { createVorgangWithEingangResource } from 'libs/vorgang-shared/test/vorgang';
-import { Observable, first, of } from 'rxjs';
+import { Observable, of } from 'rxjs';
 import {
   createBinaryFileListResource,
   createBinaryFileResource,
@@ -153,16 +153,16 @@ describe('BescheidService', () => {
     });
 
     it('should call facade', () => {
-      service.createBescheid(vorgangWithEingang).pipe(first()).subscribe();
+      service.createBescheid(vorgangWithEingang).subscribe();
 
-      expect(facade.createBescheid).toHaveBeenCalledWith(vorgangWithEingang, {
+      expect(facade.createBescheidDraft).toHaveBeenCalledWith(vorgangWithEingang, {
         order: CommandOrder.CREATE_BESCHEID,
         body: null,
       });
     });
 
     it('should set resource by uri', () => {
-      service.createBescheid(vorgangWithEingang).pipe(first()).subscribe();
+      service.createBescheid(vorgangWithEingang).subscribe();
 
       expect(service.bescheidResourceService.loadByResourceUri).toHaveBeenCalledWith(
         getUrl(command, CommandLinkRel.EFFECTED_RESOURCE),
@@ -450,7 +450,6 @@ describe('BescheidService', () => {
     it('should set resource by uri', (done) => {
       service
         .updateBescheid(bescheid)
-        .pipe(first())
         .subscribe((commandStateResource: StateResource<CommandResource>) => {
           expect(service.bescheidResourceService.loadByResourceUri).toHaveBeenCalledWith(
             getUrl(commandStateResource.resource, CommandLinkRel.EFFECTED_RESOURCE),
@@ -1134,7 +1133,7 @@ describe('BescheidService', () => {
     });
 
     it('should get resource', () => {
-      service.bescheidVerwerfen().pipe(first()).subscribe();
+      service.bescheidVerwerfen().subscribe();
 
       expect(service.getResource).toHaveBeenCalled();
     });
@@ -1316,19 +1315,19 @@ describe('BescheidService', () => {
     });
 
     it('should get items', () => {
-      service.getLastBescheid().pipe(first()).subscribe();
+      service.getLastBescheid().subscribe();
 
       expect(getItemsSpy).toHaveBeenCalled();
     });
 
     it('should filter by sent status', () => {
-      service.getLastBescheid().pipe(first()).subscribe();
+      service.getLastBescheid().subscribe();
 
       expect(service.filterBySentStatus).toHaveBeenCalledWith(bescheide);
     });
 
     it('should sort by beschieden am', () => {
-      service.getLastBescheid().pipe(first()).subscribe();
+      service.getLastBescheid().subscribe();
 
       expect(sortByGermanDateStrSpy).toHaveBeenCalledWith(bescheide, expect.any(Function));
     });
@@ -1357,13 +1356,13 @@ describe('BescheidService', () => {
     });
 
     it('should get items', () => {
-      service.existBescheid().pipe(first()).subscribe();
+      service.existBescheid().subscribe();
 
       expect(getItemsSpy).toHaveBeenCalled();
     });
 
     it('should filter by sent status', () => {
-      service.existBescheid().pipe(first()).subscribe();
+      service.existBescheid().subscribe();
 
       expect(service.filterBySentStatus).toHaveBeenCalledWith(bescheide);
     });
diff --git a/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.ts b/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.ts
index 76b74767032eac3979371d834d17c59217323600..277891fe474da829e8b3c8adacdcbf233fee73ee 100644
--- a/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.ts
+++ b/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.ts
@@ -13,19 +13,19 @@ import {
   tapOnCommandSuccessfullyDone,
 } from '@alfa-client/command-shared';
 import {
-  EMPTY_ARRAY,
-  HttpError,
-  ResourceListService,
-  StateResource,
   createEmptyStateResource,
   createStateResource,
+  EMPTY_ARRAY,
   filterIsLoadedOrHasError,
   getEmbeddedResources,
   hasStateResourceError,
+  HttpError,
   isLoaded,
   isNotEmpty,
   isNotNil,
+  ResourceListService,
   sortByGermanDateStr,
+  StateResource,
 } from '@alfa-client/tech-shared';
 import {
   VorgangCommandService,
@@ -35,15 +35,15 @@ import {
 } from '@alfa-client/vorgang-shared';
 import { getEmpfaenger } from '@alfa-client/vorgang-shared-ui';
 import { Injectable } from '@angular/core';
-import { ResourceUri, getUrl, hasLink } from '@ngxp/rest';
+import { getUrl, hasLink, ResourceUri } from '@ngxp/rest';
 import {
   BehaviorSubject,
-  Observable,
-  Subscription,
   filter,
   first,
   map,
+  Observable,
   startWith,
+  Subscription,
   switchMap,
   take,
   tap,
@@ -172,7 +172,7 @@ export class BescheidService {
     vorgangWithEingang: VorgangWithEingangResource,
     bescheid?: Bescheid,
   ): Observable<StateResource<CommandResource>> {
-    this.facade.createBescheid(vorgangWithEingang, buildCreateBescheidCommand(bescheid));
+    this.facade.createBescheidDraft(vorgangWithEingang, buildCreateBescheidCommand(bescheid));
     return this.getBescheidCommand().pipe(
       tapOnCommandSuccessfullyDone((commandStateResource: StateResource<CommandResource>) =>
         this.updateBescheidDraft(commandStateResource.resource),
diff --git a/alfa-client/libs/bescheid/src/index.ts b/alfa-client/libs/bescheid/src/index.ts
index 6e1524f86904bd889f89cbdfa55b147a978d67a5..9f2c0268f34d8c2099f74dbb30ffae0bed8a8a21 100644
--- a/alfa-client/libs/bescheid/src/index.ts
+++ b/alfa-client/libs/bescheid/src/index.ts
@@ -1,3 +1,2 @@
 export * from './lib/bescheid.module';
 export * from './lib/beschieden-date-in-vorgang-container/beschieden-date-in-vorgang-container.component';
-export * from './lib/create-bescheid-button-container/create-bescheid-button-container.component';
diff --git a/alfa-client/libs/bescheid/src/lib/bescheid.module.ts b/alfa-client/libs/bescheid/src/lib/bescheid.module.ts
index e6faf4a67f1e937d0aab66ae583415d8a4030bd9..e80dff3c3e0610a0d46b4b5babfa41c1d713d01a 100644
--- a/alfa-client/libs/bescheid/src/lib/bescheid.module.ts
+++ b/alfa-client/libs/bescheid/src/lib/bescheid.module.ts
@@ -12,8 +12,6 @@ import { BescheidListInVorgangComponent } from './bescheid-list-in-vorgang-conta
 import { DocumentInBescheidContainerComponent } from './bescheid-list-in-vorgang-container/bescheid-list-in-vorgang/document-in-bescheid-container/document-in-bescheid-container.component';
 import { BeschiedenDateContainerComponent } from './beschieden-date-in-vorgang-container/beschieden-date-container/beschieden-date-container.component';
 import { BeschiedenDateInVorgangContainerComponent } from './beschieden-date-in-vorgang-container/beschieden-date-in-vorgang-container.component';
-import { CreateBescheidButtonContainerComponent } from './create-bescheid-button-container/create-bescheid-button-container.component';
-import { CreateBescheidButtonComponent } from './create-bescheid-button-container/create-bescheid-button/create-bescheid-button.component';
 
 import {
   BescheidStatusTextComponent,
@@ -36,8 +34,6 @@ import {
     CloseIconComponent,
   ],
   declarations: [
-    CreateBescheidButtonContainerComponent,
-    CreateBescheidButtonComponent,
     BescheidInVorgangContainerComponent,
     BescheidInVorgangComponent,
     BescheidListInVorgangContainerComponent,
@@ -48,7 +44,6 @@ import {
   ],
   exports: [
     BescheidInVorgangContainerComponent,
-    CreateBescheidButtonContainerComponent,
     BescheidListInVorgangContainerComponent,
     BeschiedenDateInVorgangContainerComponent,
   ],
diff --git a/alfa-client/libs/bescheid/src/lib/beschieden-date-in-vorgang-container/beschieden-date-container/beschieden-date-container.component.html b/alfa-client/libs/bescheid/src/lib/beschieden-date-in-vorgang-container/beschieden-date-container/beschieden-date-container.component.html
index 704a6ddd28f903eee9a9fb887c8ac40d4d56683d..61ae1d119505cb9e60d173dce420dd872cfa784e 100644
--- a/alfa-client/libs/bescheid/src/lib/beschieden-date-in-vorgang-container/beschieden-date-container/beschieden-date-container.component.html
+++ b/alfa-client/libs/bescheid/src/lib/beschieden-date-in-vorgang-container/beschieden-date-container/beschieden-date-container.component.html
@@ -9,7 +9,6 @@
     <ods-close-icon
       *ngIf="!bescheid.bewilligt"
       data-test-id="abgelehnt-icon"
-      size="small"
       class="fill-abgelehnt"
     />
 
diff --git a/alfa-client/libs/bescheid/src/lib/create-bescheid-button-container/create-bescheid-button-container.component.html b/alfa-client/libs/bescheid/src/lib/create-bescheid-button-container/create-bescheid-button-container.component.html
deleted file mode 100644
index 1cc547861a553e8955f7f4481a862c2d5daeb535..0000000000000000000000000000000000000000
--- a/alfa-client/libs/bescheid/src/lib/create-bescheid-button-container/create-bescheid-button-container.component.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<alfa-create-bescheid-button
-  data-test-id="create-bescheid-button-component"
-  [createBescheidCommand]="createBescheidInCommand$ | async"
-  (createBescheid)="create()"
->
-</alfa-create-bescheid-button>
diff --git a/alfa-client/libs/bescheid/src/lib/create-bescheid-button-container/create-bescheid-button-container.component.scss b/alfa-client/libs/bescheid/src/lib/create-bescheid-button-container/create-bescheid-button-container.component.scss
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/alfa-client/libs/bescheid/src/lib/create-bescheid-button-container/create-bescheid-button-container.component.spec.ts b/alfa-client/libs/bescheid/src/lib/create-bescheid-button-container/create-bescheid-button-container.component.spec.ts
deleted file mode 100644
index 55dc7e67d6a90ba7555860c8ead94e494bc39316..0000000000000000000000000000000000000000
--- a/alfa-client/libs/bescheid/src/lib/create-bescheid-button-container/create-bescheid-button-container.component.spec.ts
+++ /dev/null
@@ -1,58 +0,0 @@
-import { ComponentFixture, TestBed } from '@angular/core/testing';
-import { Mock, dispatchEventFromFixture, mock } from '@alfa-client/test-utils';
-import { VorgangWithEingangResource } from '@alfa-client/vorgang-shared';
-import { BescheidService } from 'libs/bescheid-shared/src/lib/bescheid.service';
-import { getDataTestIdOf } from 'libs/tech-shared/test/data-test';
-import { createVorgangWithEingangResource } from 'libs/vorgang-shared/test/vorgang';
-import { MockComponent } from 'ng-mocks';
-import { CreateBescheidButtonContainerComponent } from './create-bescheid-button-container.component';
-import { CreateBescheidButtonComponent } from './create-bescheid-button/create-bescheid-button.component';
-
-describe('CreateBescheidButtonContainerComponent', () => {
-  let component: CreateBescheidButtonContainerComponent;
-  let fixture: ComponentFixture<CreateBescheidButtonContainerComponent>;
-
-  const createBescheidComponent: string = getDataTestIdOf('create-bescheid-button-component');
-  const service: Mock<BescheidService> = mock(BescheidService);
-  const vorgangWithEingang: VorgangWithEingangResource = createVorgangWithEingangResource();
-
-  beforeEach(async () => {
-    await TestBed.configureTestingModule({
-      declarations: [
-        CreateBescheidButtonContainerComponent,
-        MockComponent(CreateBescheidButtonComponent),
-      ],
-      providers: [
-        {
-          provide: BescheidService,
-          useValue: service,
-        },
-      ],
-    }).compileComponents();
-
-    fixture = TestBed.createComponent(CreateBescheidButtonContainerComponent);
-    component = fixture.componentInstance;
-    component.vorgangWithEingang = vorgangWithEingang;
-    fixture.detectChanges();
-  });
-
-  it('should create', () => {
-    expect(component).toBeTruthy();
-  });
-
-  describe('ngOnInit', () => {
-    it('should get bescheid command', () => {
-      component.ngOnInit();
-
-      expect(service.getBescheidCommand).toHaveBeenCalled();
-    });
-  });
-
-  describe('create', () => {
-    it('should call service', () => {
-      dispatchEventFromFixture(fixture, createBescheidComponent, 'createBescheid');
-
-      expect(service.createBescheid).toHaveBeenCalledWith(vorgangWithEingang);
-    });
-  });
-});
diff --git a/alfa-client/libs/bescheid/src/lib/create-bescheid-button-container/create-bescheid-button-container.component.ts b/alfa-client/libs/bescheid/src/lib/create-bescheid-button-container/create-bescheid-button-container.component.ts
deleted file mode 100644
index a896daae64dd1c1e9470222356fe83b7c9f41b95..0000000000000000000000000000000000000000
--- a/alfa-client/libs/bescheid/src/lib/create-bescheid-button-container/create-bescheid-button-container.component.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-import { CommandResource } from '@alfa-client/command-shared';
-import { StateResource, createEmptyStateResource } from '@alfa-client/tech-shared';
-import { VorgangWithEingangResource } from '@alfa-client/vorgang-shared';
-import { Component, Input, OnInit } from '@angular/core';
-import { BescheidService } from 'libs/bescheid-shared/src/lib/bescheid.service';
-import { Observable, of } from 'rxjs';
-
-@Component({
-  selector: 'alfa-create-bescheid-button-container',
-  templateUrl: './create-bescheid-button-container.component.html',
-  styleUrls: ['./create-bescheid-button-container.component.scss'],
-})
-export class CreateBescheidButtonContainerComponent implements OnInit {
-  @Input() vorgangWithEingang: VorgangWithEingangResource;
-
-  public createBescheidInCommand$: Observable<StateResource<CommandResource>> = of(
-    createEmptyStateResource<CommandResource>(),
-  );
-
-  constructor(private bescheidService: BescheidService) {}
-
-  ngOnInit(): void {
-    this.createBescheidInCommand$ = this.bescheidService.getBescheidCommand();
-  }
-
-  public create(): void {
-    this.bescheidService.createBescheid(this.vorgangWithEingang);
-  }
-}
diff --git a/alfa-client/libs/bescheid/src/lib/create-bescheid-button-container/create-bescheid-button/create-bescheid-button.component.html b/alfa-client/libs/bescheid/src/lib/create-bescheid-button-container/create-bescheid-button/create-bescheid-button.component.html
deleted file mode 100644
index ac1efb73c28ad0ed875c79f084ebf9a5ee55dec6..0000000000000000000000000000000000000000
--- a/alfa-client/libs/bescheid/src/lib/create-bescheid-button-container/create-bescheid-button/create-bescheid-button.component.html
+++ /dev/null
@@ -1,8 +0,0 @@
-<ozgcloud-icon-button-with-spinner
-  data-test-id="create-bescheid-icon-button"
-  icon="description"
-  toolTip="Bescheid erstellen"
-  [stateResource]="createBescheidCommand"
-  (clickEmitter)="createBescheid.emit()"
->
-</ozgcloud-icon-button-with-spinner>
diff --git a/alfa-client/libs/bescheid/src/lib/create-bescheid-button-container/create-bescheid-button/create-bescheid-button.component.scss b/alfa-client/libs/bescheid/src/lib/create-bescheid-button-container/create-bescheid-button/create-bescheid-button.component.scss
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/alfa-client/libs/bescheid/src/lib/create-bescheid-button-container/create-bescheid-button/create-bescheid-button.component.spec.ts b/alfa-client/libs/bescheid/src/lib/create-bescheid-button-container/create-bescheid-button/create-bescheid-button.component.spec.ts
deleted file mode 100644
index d15b7638e4686c64dd015cae79be7e3cee5915f4..0000000000000000000000000000000000000000
--- a/alfa-client/libs/bescheid/src/lib/create-bescheid-button-container/create-bescheid-button/create-bescheid-button.component.spec.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-import { ComponentFixture, TestBed } from '@angular/core/testing';
-import { dispatchEventFromFixture } from '@alfa-client/test-utils';
-import { IconButtonWithSpinnerComponent } from '@alfa-client/ui';
-import { getDataTestIdOf } from 'libs/tech-shared/test/data-test';
-import { MockComponent } from 'ng-mocks';
-import { CreateBescheidButtonComponent } from './create-bescheid-button.component';
-
-describe('CreateBescheidButtonComponent', () => {
-  let component: CreateBescheidButtonComponent;
-  let fixture: ComponentFixture<CreateBescheidButtonComponent>;
-
-  const createBescheidButton: string = getDataTestIdOf('create-bescheid-icon-button');
-
-  beforeEach(async () => {
-    await TestBed.configureTestingModule({
-      declarations: [CreateBescheidButtonComponent, MockComponent(IconButtonWithSpinnerComponent)],
-    }).compileComponents();
-
-    fixture = TestBed.createComponent(CreateBescheidButtonComponent);
-    component = fixture.componentInstance;
-    fixture.detectChanges();
-  });
-
-  it('should create', () => {
-    expect(component).toBeTruthy();
-  });
-
-  describe('on button click', () => {
-    it('should emit createBescheid', () => {
-      jest.spyOn(component.createBescheid, 'emit');
-
-      dispatchEventFromFixture(fixture, createBescheidButton, 'clickEmitter');
-
-      expect(component.createBescheid.emit).toHaveBeenCalled();
-    });
-  });
-});
diff --git a/alfa-client/libs/bescheid/src/lib/create-bescheid-button-container/create-bescheid-button/create-bescheid-button.component.ts b/alfa-client/libs/bescheid/src/lib/create-bescheid-button-container/create-bescheid-button/create-bescheid-button.component.ts
deleted file mode 100644
index d01c5ecd049877b9fd5a63e4e2ee4cde9cd034b0..0000000000000000000000000000000000000000
--- a/alfa-client/libs/bescheid/src/lib/create-bescheid-button-container/create-bescheid-button/create-bescheid-button.component.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import { Component, EventEmitter, Input, Output } from '@angular/core';
-import { CommandResource } from '@alfa-client/command-shared';
-import { StateResource, createEmptyStateResource } from '@alfa-client/tech-shared';
-
-@Component({
-  selector: 'alfa-create-bescheid-button',
-  templateUrl: './create-bescheid-button.component.html',
-  styleUrls: ['./create-bescheid-button.component.scss'],
-})
-export class CreateBescheidButtonComponent {
-  @Input() createBescheidCommand: StateResource<CommandResource> =
-    createEmptyStateResource<CommandResource>();
-
-  @Output() createBescheid: EventEmitter<void> = new EventEmitter();
-}
diff --git a/alfa-client/libs/binary-file-shared/src/lib/binary-file.service.spec.ts b/alfa-client/libs/binary-file-shared/src/lib/binary-file.service.spec.ts
index 9d69ae78a151079401a9d94caceff99e8c980675..328960de1f9b9a87f8442595ad8b609f339f9da8 100644
--- a/alfa-client/libs/binary-file-shared/src/lib/binary-file.service.spec.ts
+++ b/alfa-client/libs/binary-file-shared/src/lib/binary-file.service.spec.ts
@@ -262,7 +262,7 @@ describe('BinaryFileService', () => {
         service.handleSnackBar(buildUnprocessableEntityErrorResponse(), true);
 
         expect(snackBarService.showError).toHaveBeenCalledWith(
-          VALIDATION_MESSAGES[ValidationMessageCode.VALIDATION_FIELD_FILE_SIZE_EXCEEDED],
+          VALIDATION_MESSAGES[ValidationMessageCode.FIELD_FILE_SIZE_EXCEEDED],
         );
       });
 
@@ -274,7 +274,7 @@ describe('BinaryFileService', () => {
 
       it('should not call snackbarService if not file size exceeded error', () => {
         service.handleSnackBar(
-          buildUnprocessableEntityErrorResponse(ValidationMessageCode.VALIDATION_FIELD_EMPTY),
+          buildUnprocessableEntityErrorResponse(ValidationMessageCode.FIELD_EMPTY),
           true,
         );
 
@@ -283,15 +283,15 @@ describe('BinaryFileService', () => {
     });
 
     function buildUnprocessableEntityErrorResponse(
-      validationMessageCode: ValidationMessageCode = ValidationMessageCode.VALIDATION_FIELD_FILE_SIZE_EXCEEDED,
+      validationMessageCode: ValidationMessageCode = ValidationMessageCode.FIELD_FILE_SIZE_EXCEEDED,
     ): HttpErrorResponse {
       return <HttpErrorResponse>{
         status: 422,
         error: {
-          issues: [
+          invalidParams: [
             {
-              messageCode: validationMessageCode,
-              parameters: [],
+              reason: validationMessageCode,
+              constraintParameters: [],
             },
           ],
         },
diff --git a/alfa-client/libs/binary-file-shared/src/lib/binary-file.service.ts b/alfa-client/libs/binary-file-shared/src/lib/binary-file.service.ts
index bb6592cb76931ff30edca949cc28a864686ecfce..57773cccbfa61d4dab2af4984a88d6d3f9cf7b14 100644
--- a/alfa-client/libs/binary-file-shared/src/lib/binary-file.service.ts
+++ b/alfa-client/libs/binary-file-shared/src/lib/binary-file.service.ts
@@ -29,7 +29,7 @@ import {
   createEmptyStateResource,
   createErrorStateResource,
   createStateResource,
-  getMessageForIssue,
+  getMessageForInvalidParam,
   isNotNil,
   isUnprocessableEntity,
   isValidationFieldFileSizeExceedError,
@@ -90,7 +90,9 @@ export class BinaryFileService {
 
   handleSnackBar(error: HttpErrorResponse, showValidationErrorSnackBar: boolean) {
     if (showValidationErrorSnackBar && isValidationFieldFileSizeExceedError(error.error)) {
-      this.snackbarService.showError(getMessageForIssue(EMPTY_STRING, error.error.issues[0]));
+      this.snackbarService.showError(
+        getMessageForInvalidParam(EMPTY_STRING, error.error.invalidParams[0]),
+      );
     }
   }
 
diff --git a/alfa-client/libs/binary-file/src/lib/binary-file-container/binary-file-container.component.scss b/alfa-client/libs/binary-file/src/lib/binary-file-container/binary-file-container.component.scss
index 7dcaaf304d76dd842af6bcbcc811021fa5c8904f..75e46ace311d763326b4b99335aee48d5ef44996 100644
--- a/alfa-client/libs/binary-file/src/lib/binary-file-container/binary-file-container.component.scss
+++ b/alfa-client/libs/binary-file/src/lib/binary-file-container/binary-file-container.component.scss
@@ -25,5 +25,5 @@
   position: relative;
   max-width: 100%;
   padding: 4px 0;
-  font-size: 14px;
+  font-size: 0.875rem;
 }
diff --git a/alfa-client/libs/binary-file/src/lib/binary-file-container/binary-file/binary-file.component.scss b/alfa-client/libs/binary-file/src/lib/binary-file-container/binary-file/binary-file.component.scss
index fb3024df1b4d16d68a56c7751548f96af38dabbd..17be8d4a626b041450d293d151ef4b4d128e6079 100644
--- a/alfa-client/libs/binary-file/src/lib/binary-file-container/binary-file/binary-file.component.scss
+++ b/alfa-client/libs/binary-file/src/lib/binary-file-container/binary-file/binary-file.component.scss
@@ -89,7 +89,7 @@
 }
 
 .size {
-  font-size: 12px;
+  font-size: 0.75rem;
   flex-shrink: 0;
   margin-right: 4px;
 
diff --git a/alfa-client/libs/binary-file/src/lib/vertical-binary-file-list/vertical-binary-file-list.component.html b/alfa-client/libs/binary-file/src/lib/vertical-binary-file-list/vertical-binary-file-list.component.html
index 187ab55187039b6ca7ea2f9d6b1ab8e0cc456a4a..1dc4313e5e3710b0c1550043dd4c1fa4f6e3d04d 100644
--- a/alfa-client/libs/binary-file/src/lib/vertical-binary-file-list/vertical-binary-file-list.component.html
+++ b/alfa-client/libs/binary-file/src/lib/vertical-binary-file-list/vertical-binary-file-list.component.html
@@ -27,8 +27,12 @@
   *ngIf="binaryFileListStateResource.resource"
   [stateResource]="binaryFileListStateResource"
 >
-  <ods-attachment-wrapper [title]="title" data-test-id="file-list">
-    <ods-attachment-header [title]="title">
+  <ods-attachment-wrapper data-test-id="file-list">
+    <ods-attachment-header
+      [title]="title"
+      *ngIf="title || archiveDownloadUri"
+      data-test-id="file-list-header"
+    >
       <alfa-download-archive-file-button-container
         *ngIf="archiveDownloadUri"
         data-test-class="download-archive-file-button"
diff --git a/alfa-client/libs/binary-file/src/lib/vertical-binary-file-list/vertical-binary-file-list.component.spec.ts b/alfa-client/libs/binary-file/src/lib/vertical-binary-file-list/vertical-binary-file-list.component.spec.ts
index a42980975bd6362343a865a3dae296bbd3191728..f0ec5b2c573b721bfd18afefde63750a310a0310 100644
--- a/alfa-client/libs/binary-file/src/lib/vertical-binary-file-list/vertical-binary-file-list.component.spec.ts
+++ b/alfa-client/libs/binary-file/src/lib/vertical-binary-file-list/vertical-binary-file-list.component.spec.ts
@@ -37,7 +37,7 @@ import {
   createBinaryFileListResource,
   createBinaryFileResource,
 } from 'libs/binary-file-shared/test/binary-file';
-import { getDataTestClassOf } from 'libs/tech-shared/test/data-test';
+import { getDataTestClassOf, getDataTestIdOf } from 'libs/tech-shared/test/data-test';
 import { MockComponent } from 'ng-mocks';
 import { BinaryFile2ContainerComponent } from '../binary-file2-container/binary-file2-container.component';
 import { DownloadArchiveFileButtonContainerComponent } from '../download-archive-file-button-container/download-archive-file-button-container.component';
@@ -48,6 +48,7 @@ describe('VerticalBinaryFileListComponent', () => {
   let fixture: ComponentFixture<VerticalBinaryFileListComponent>;
 
   const downloadArchiveFileButton: string = getDataTestClassOf('download-archive-file-button');
+  const fileListHeader: string = getDataTestIdOf('file-list-header');
 
   const binaryFile: BinaryFileResource = createBinaryFileResource();
 
@@ -109,7 +110,37 @@ describe('VerticalBinaryFileListComponent', () => {
     });
   });
 
+  describe('attachment header', () => {
+    it('should show header if there is title', () => {
+      component.title = 'Title';
+
+      fixture.detectChanges();
+
+      existsAsHtmlElement(fixture, fileListHeader);
+    });
+
+    it('should show header if there is uri', () => {
+      component.archiveDownloadUri = faker.internet.url();
+
+      fixture.detectChanges();
+
+      existsAsHtmlElement(fixture, fileListHeader);
+    });
+
+    it('should not show header if there is no uri or title', () => {
+      component.title = '';
+
+      fixture.detectChanges();
+
+      notExistsAsHtmlElement(fixture, fileListHeader);
+    });
+  });
+
   describe('download archive button', () => {
+    beforeEach(() => {
+      component.title = 'Test title';
+    });
+
     const downloadUri: ResourceUri = faker.internet.url();
 
     it('should be visible if uri exists', () => {
diff --git a/alfa-client/libs/collaboration-shared/.eslintrc.json b/alfa-client/libs/collaboration-shared/.eslintrc.json
new file mode 100644
index 0000000000000000000000000000000000000000..adbe7ae2dfabd4a42804f00846baec80877f4c5c
--- /dev/null
+++ b/alfa-client/libs/collaboration-shared/.eslintrc.json
@@ -0,0 +1,25 @@
+{
+  "extends": ["../../.eslintrc.json"],
+  "ignorePatterns": ["!**/*"],
+  "overrides": [
+    {
+      "files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
+      "rules": {}
+    },
+    {
+      "files": ["*.ts", "*.tsx"],
+      "rules": {}
+    },
+    {
+      "files": ["*.js", "*.jsx"],
+      "rules": {}
+    },
+    {
+      "files": ["*.json"],
+      "parser": "jsonc-eslint-parser",
+      "rules": {
+        "@nx/dependency-checks": "error"
+      }
+    }
+  ]
+}
diff --git a/alfa-client/libs/collaboration-shared/README.md b/alfa-client/libs/collaboration-shared/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..84ff0ba5e53fa8755bbc483ca6989a4dd97ba944
--- /dev/null
+++ b/alfa-client/libs/collaboration-shared/README.md
@@ -0,0 +1,7 @@
+# collaboration-shared
+
+This library was generated with [Nx](https://nx.dev).
+
+## Running unit tests
+
+Run `nx test collaboration-shared` to execute the unit tests.
diff --git a/alfa-client/libs/collaboration-shared/jest.config.ts b/alfa-client/libs/collaboration-shared/jest.config.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b295000beb0ccff8274950b36d2b0c08ef7eb11c
--- /dev/null
+++ b/alfa-client/libs/collaboration-shared/jest.config.ts
@@ -0,0 +1,23 @@
+/* eslint-disable */
+export default {
+  displayName: 'collaboration-shared',
+  preset: '../../jest.preset.js',
+  setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
+  globals: {},
+  coverageDirectory: '../../coverage/libs/collaboration-shared',
+  snapshotSerializers: [
+    'jest-preset-angular/build/serializers/no-ng-attributes',
+    'jest-preset-angular/build/serializers/ng-snapshot',
+    'jest-preset-angular/build/serializers/html-comment',
+  ],
+  transform: {
+    '^.+.(ts|mjs|js|html)$': [
+      'jest-preset-angular',
+      {
+        tsconfig: '<rootDir>/tsconfig.spec.json',
+        stringifyContentPathRegex: '\\.(html|svg)$',
+      },
+    ],
+  },
+  transformIgnorePatterns: ['node_modules/(?!.*.mjs$)'],
+};
diff --git a/alfa-client/libs/collaboration-shared/project.json b/alfa-client/libs/collaboration-shared/project.json
new file mode 100644
index 0000000000000000000000000000000000000000..f262eeba5a931ef0e8f50e915af8be561bbf8cd6
--- /dev/null
+++ b/alfa-client/libs/collaboration-shared/project.json
@@ -0,0 +1,22 @@
+{
+  "name": "collaboration-shared",
+  "$schema": "../../node_modules/nx/schemas/project-schema.json",
+  "projectType": "library",
+  "sourceRoot": "libs/collaboration-shared/src",
+  "prefix": "alfa",
+  "tags": [],
+  "targets": {
+    "test": {
+      "executor": "@nx/jest:jest",
+      "outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
+      "options": {
+        "tsConfig": "libs/collaboration-shared/tsconfig.spec.json",
+        "jestConfig": "libs/collaboration-shared/jest.config.ts"
+      }
+    },
+    "lint": {
+      "executor": "@nx/eslint:lint",
+      "outputs": ["{options.outputFile}"]
+    }
+  }
+}
diff --git a/alfa-client/libs/collaboration-shared/src/index.ts b/alfa-client/libs/collaboration-shared/src/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..cd761bf34a9d3d1e63337bb36e92e56977ef0b1e
--- /dev/null
+++ b/alfa-client/libs/collaboration-shared/src/index.ts
@@ -0,0 +1,6 @@
+export * from './lib/collaboration-shared.module';
+export * from './lib/collaboration.linkrel';
+export * from './lib/collaboration.model';
+export * from './lib/organisations-einheit.linkrel';
+export * from './lib/organisations-einheit.model';
+export * from './lib/organisations-einheit.service';
diff --git a/alfa-client/libs/collaboration-shared/src/lib/collaboration-list-resource.service.ts b/alfa-client/libs/collaboration-shared/src/lib/collaboration-list-resource.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..fa6f47d5d6292485b6d84de0040fc1913c692569
--- /dev/null
+++ b/alfa-client/libs/collaboration-shared/src/lib/collaboration-list-resource.service.ts
@@ -0,0 +1,34 @@
+import {
+  ListResourceServiceConfig,
+  ResourceListService,
+  ResourceRepository,
+} from '@alfa-client/tech-shared';
+import {
+  VorgangResource,
+  VorgangService,
+  VorgangWithEingangLinkRel,
+} from '@alfa-client/vorgang-shared';
+import { CollaborationListLinkRel } from './collaboration.linkrel';
+import { CollaborationListResource, CollaborationResource } from './collaboration.model';
+
+export class CollaborationListResourceService extends ResourceListService<
+  VorgangResource,
+  CollaborationListResource,
+  CollaborationResource
+> {}
+
+export function createCollaborationListResourceService(
+  repository: ResourceRepository,
+  vorgangService: VorgangService,
+) {
+  return new ResourceListService(buildConfig(vorgangService), repository);
+}
+
+function buildConfig(vorgangService: VorgangService): ListResourceServiceConfig<VorgangResource> {
+  return {
+    baseResource: vorgangService.getVorgangWithEingang(),
+    listLinkRel: VorgangWithEingangLinkRel.COLLABORATIONS,
+    listResourceListLinkRel: CollaborationListLinkRel.COLLABORATION_LIST,
+    createLinkRel: CollaborationListLinkRel.CREATE_COLLABORATION_REQUEST,
+  };
+}
diff --git a/alfa-client/libs/collaboration-shared/src/lib/collaboration-shared.module.spec.ts b/alfa-client/libs/collaboration-shared/src/lib/collaboration-shared.module.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..4a3a485289dcdf8dc388b32f75c4415104122f46
--- /dev/null
+++ b/alfa-client/libs/collaboration-shared/src/lib/collaboration-shared.module.spec.ts
@@ -0,0 +1,14 @@
+import { TestBed } from '@angular/core/testing';
+import { CollaborationSharedModule } from './collaboration-shared.module';
+
+describe('CollaborationSharedModule', () => {
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: [CollaborationSharedModule],
+    }).compileComponents();
+  });
+
+  it('should create', () => {
+    expect(CollaborationSharedModule).toBeDefined();
+  });
+});
diff --git a/alfa-client/libs/collaboration-shared/src/lib/collaboration-shared.module.ts b/alfa-client/libs/collaboration-shared/src/lib/collaboration-shared.module.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b4a95fe57bb26a6a1fe9cd8de98e6c2422b0033b
--- /dev/null
+++ b/alfa-client/libs/collaboration-shared/src/lib/collaboration-shared.module.ts
@@ -0,0 +1,33 @@
+import { ResourceRepository } from '@alfa-client/tech-shared';
+import { VorgangService } from '@alfa-client/vorgang-shared';
+import { CommonModule } from '@angular/common';
+import { NgModule } from '@angular/core';
+import {
+  CollaborationListResourceService,
+  createCollaborationListResourceService,
+} from './collaboration-list-resource.service';
+import { CollaborationService } from './collaboration.service';
+import {
+  OrganisationsEinheitResourceSearchService,
+  createOrganisationsEinheitResourceSearchService,
+} from './organisations-einheit-resource-search.service';
+import { OrganisationsEinheitService } from './organisations-einheit.service';
+
+@NgModule({
+  imports: [CommonModule],
+  providers: [
+    CollaborationService,
+    OrganisationsEinheitService,
+    {
+      provide: CollaborationListResourceService,
+      useFactory: createCollaborationListResourceService,
+      deps: [ResourceRepository, VorgangService],
+    },
+    {
+      provide: OrganisationsEinheitResourceSearchService,
+      useFactory: createOrganisationsEinheitResourceSearchService,
+      deps: [ResourceRepository, VorgangService],
+    },
+  ],
+})
+export class CollaborationSharedModule {}
diff --git a/alfa-client/libs/collaboration-shared/src/lib/collaboration.linkrel.ts b/alfa-client/libs/collaboration-shared/src/lib/collaboration.linkrel.ts
new file mode 100644
index 0000000000000000000000000000000000000000..967a0a0a1990749d02d9153c1e2d1a4d88869936
--- /dev/null
+++ b/alfa-client/libs/collaboration-shared/src/lib/collaboration.linkrel.ts
@@ -0,0 +1,4 @@
+export enum CollaborationListLinkRel {
+  COLLABORATION_LIST = 'collaborationList',
+  CREATE_COLLABORATION_REQUEST = 'createCollaborationRequest',
+}
diff --git a/alfa-client/libs/collaboration-shared/src/lib/collaboration.model.ts b/alfa-client/libs/collaboration-shared/src/lib/collaboration.model.ts
new file mode 100644
index 0000000000000000000000000000000000000000..0e5a678748f2ac3076ff3a7cd94f60d5bf69eae0
--- /dev/null
+++ b/alfa-client/libs/collaboration-shared/src/lib/collaboration.model.ts
@@ -0,0 +1,11 @@
+import { ListItemResource, ListResource } from '@alfa-client/tech-shared';
+import { Resource, ResourceUri } from '@ngxp/rest';
+
+export interface Collaboration {
+  titel: string;
+  anfrage: string;
+  zustaendigeStelle: ResourceUri;
+}
+
+export interface CollaborationResource extends Collaboration, Resource, ListItemResource {}
+export interface CollaborationListResource extends ListResource {}
diff --git a/alfa-client/libs/collaboration-shared/src/lib/collaboration.service.spec.ts b/alfa-client/libs/collaboration-shared/src/lib/collaboration.service.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..6bba58e7fc8b68c547729f19c4630e63a4b4b482
--- /dev/null
+++ b/alfa-client/libs/collaboration-shared/src/lib/collaboration.service.spec.ts
@@ -0,0 +1,119 @@
+import { CommandOrder, CommandResource, CommandService } from '@alfa-client/command-shared';
+import { StateResource, createStateResource } from '@alfa-client/tech-shared';
+import { Mock, mock, useFromMock } from '@alfa-client/test-utils';
+import { createCommandResource } from 'libs/command-shared/test/command';
+import { singleColdCompleted } from 'libs/tech-shared/test/marbles';
+import { Observable, of } from 'rxjs';
+import {
+  createCollaboration,
+  createCollaborationListResource,
+} from '../../../collaboration-shared/test/collaboration';
+import { CollaborationListResourceService } from './collaboration-list-resource.service';
+import { CollaborationListLinkRel } from './collaboration.linkrel';
+import { Collaboration, CollaborationListResource } from './collaboration.model';
+import { CollaborationService } from './collaboration.service';
+
+jest.mock('./collaboration-list-resource.service');
+
+describe('CollaborationService', () => {
+  let service: CollaborationService;
+
+  let listService: Mock<CollaborationListResourceService>;
+  let commandService: Mock<CommandService>;
+
+  const collaborationListResource: CollaborationListResource = createCollaborationListResource();
+  const collaborationStateListResource: StateResource<CollaborationListResource> =
+    createStateResource(collaborationListResource);
+
+  beforeEach(() => {
+    listService = mock(CollaborationListResourceService);
+    commandService = mock(CommandService);
+
+    service = new CollaborationService(useFromMock(listService), useFromMock(commandService));
+  });
+
+  describe('get list', () => {
+    beforeEach(() => {
+      listService.getList.mockReturnValue(of(collaborationStateListResource));
+    });
+
+    it('should call service', () => {
+      service.getList();
+
+      expect(listService.getList).toHaveBeenCalled();
+    });
+
+    it('should return value', () => {
+      const list$: Observable<StateResource<CollaborationListResource>> = service.getList();
+
+      expect(list$).toBeObservable(singleColdCompleted(collaborationStateListResource));
+    });
+  });
+
+  describe('is request form visible', () => {
+    it('should return value', (done) => {
+      service.showRequestForm$.next(false);
+
+      service.isRequestFormVisible().subscribe((isVisible: boolean) => {
+        expect(isVisible).toBeTruthy();
+        done();
+      });
+
+      service.showRequestForm();
+    });
+  });
+
+  describe('show anfrage formular', () => {
+    it('should set "showRequestForm" to true', () => {
+      service.showRequestForm$.next(false);
+
+      service.showRequestForm();
+
+      expect(service.showRequestForm$.value).toBeTruthy();
+    });
+  });
+
+  describe('hide anfrage formular', () => {
+    it('should set "showRequestForm" to false', () => {
+      service.showRequestForm$.next(true);
+
+      service.hideRequestForm();
+
+      expect(service.showRequestForm$.value).toBeFalsy();
+    });
+  });
+
+  describe('create', () => {
+    const collaborationListResource: CollaborationListResource = createCollaborationListResource();
+    const commandStateResource: StateResource<CommandResource> =
+      createStateResource(createCommandResource());
+    const collaboration: Collaboration = createCollaboration();
+
+    beforeEach(() => {
+      commandService.createCommandByProps.mockReturnValue(of(commandStateResource));
+    });
+
+    it('should call command service', () => {
+      service.create(collaborationListResource, collaboration);
+
+      expect(commandService.createCommandByProps).toHaveBeenCalledWith({
+        linkRel: CollaborationListLinkRel.CREATE_COLLABORATION_REQUEST,
+        resource: collaborationListResource,
+        command: {
+          order: CommandOrder.CREATE_COLLABORATION_REQUEST,
+          body: collaboration,
+        },
+        snackBarMessage: 'Die Zuarbeit wurde angefragt',
+      });
+    });
+
+    it('should return value', () => {
+      const created$: Observable<StateResource<CommandResource>> = service.create(
+        collaborationListResource,
+        collaboration,
+      );
+
+      expect(created$).toBeObservable(singleColdCompleted(commandStateResource));
+    });
+  });
+});
diff --git a/alfa-client/libs/collaboration-shared/src/lib/collaboration.service.ts b/alfa-client/libs/collaboration-shared/src/lib/collaboration.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..736d0cb47f6cd6ed943688a389a6f8f5e9acb388
--- /dev/null
+++ b/alfa-client/libs/collaboration-shared/src/lib/collaboration.service.ts
@@ -0,0 +1,48 @@
+import { CommandOrder, CommandResource, CommandService } from '@alfa-client/command-shared';
+import { StateResource } from '@alfa-client/tech-shared';
+import { Injectable } from '@angular/core';
+import { BehaviorSubject, Observable } from 'rxjs';
+import { CollaborationListResourceService } from './collaboration-list-resource.service';
+import { CollaborationListLinkRel } from './collaboration.linkrel';
+import { Collaboration, CollaborationListResource } from './collaboration.model';
+
+@Injectable()
+export class CollaborationService {
+  showRequestForm$: BehaviorSubject<boolean> = new BehaviorSubject(false);
+
+  constructor(
+    private listService: CollaborationListResourceService,
+    private commandService: CommandService,
+  ) {}
+
+  public getList(): Observable<StateResource<CollaborationListResource>> {
+    return this.listService.getList();
+  }
+
+  public isRequestFormVisible(): Observable<boolean> {
+    return this.showRequestForm$.asObservable();
+  }
+
+  public showRequestForm(): void {
+    this.showRequestForm$.next(true);
+  }
+
+  public hideRequestForm(): void {
+    this.showRequestForm$.next(false);
+  }
+
+  public create(
+    listResource: CollaborationListResource,
+    collaborationRequest: Collaboration,
+  ): Observable<StateResource<CommandResource>> {
+    return this.commandService.createCommandByProps({
+      linkRel: CollaborationListLinkRel.CREATE_COLLABORATION_REQUEST,
+      resource: listResource,
+      command: {
+        order: CommandOrder.CREATE_COLLABORATION_REQUEST,
+        body: collaborationRequest,
+      },
+      snackBarMessage: 'Die Zuarbeit wurde angefragt',
+    });
+  }
+}
diff --git a/alfa-client/libs/collaboration-shared/src/lib/organisations-einheit-resource-search.service.ts b/alfa-client/libs/collaboration-shared/src/lib/organisations-einheit-resource-search.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..23f726f9ed323a5c596e660190d1168e0aea41e5
--- /dev/null
+++ b/alfa-client/libs/collaboration-shared/src/lib/organisations-einheit-resource-search.service.ts
@@ -0,0 +1,35 @@
+import {
+  ResourceRepository,
+  ResourceSearchService,
+  SearchResourceServiceConfig,
+  mapToResource,
+} from '@alfa-client/tech-shared';
+import {
+  VorgangResource,
+  VorgangService,
+  VorgangWithEingangLinkRel,
+} from '@alfa-client/vorgang-shared';
+import {
+  OrganisationsEinheitListResource,
+  OrganisationsEinheitResource,
+} from './organisations-einheit.model';
+
+export class OrganisationsEinheitResourceSearchService extends ResourceSearchService<
+  VorgangResource,
+  OrganisationsEinheitListResource,
+  OrganisationsEinheitResource
+> {}
+
+export function createOrganisationsEinheitResourceSearchService(
+  repository: ResourceRepository,
+  vorgangService: VorgangService,
+) {
+  return new ResourceSearchService(buildConfig(vorgangService), repository);
+}
+
+function buildConfig(vorgangService: VorgangService): SearchResourceServiceConfig<VorgangResource> {
+  return {
+    baseResource: vorgangService.getVorgangWithEingang().pipe(mapToResource<VorgangResource>()),
+    searchLinkRel: VorgangWithEingangLinkRel.SEARCH_ORGANISATIONS_EINHEIT,
+  };
+}
diff --git a/alfa-client/libs/collaboration-shared/src/lib/organisations-einheit.linkrel.ts b/alfa-client/libs/collaboration-shared/src/lib/organisations-einheit.linkrel.ts
new file mode 100644
index 0000000000000000000000000000000000000000..775f60796051e119cb42f35c368799fe23250981
--- /dev/null
+++ b/alfa-client/libs/collaboration-shared/src/lib/organisations-einheit.linkrel.ts
@@ -0,0 +1,3 @@
+export enum OrganisationsEinheitListLinkRel {
+  ORGANISATIONS_EINHEIT_HEADER_LIST = 'organisationsEinheitHeaderList',
+}
diff --git a/alfa-client/libs/collaboration-shared/src/lib/organisations-einheit.model.ts b/alfa-client/libs/collaboration-shared/src/lib/organisations-einheit.model.ts
new file mode 100644
index 0000000000000000000000000000000000000000..aafc23fbbce95dae57f511413b8e1c0dedd936ad
--- /dev/null
+++ b/alfa-client/libs/collaboration-shared/src/lib/organisations-einheit.model.ts
@@ -0,0 +1,20 @@
+import { ListItemResource, ListResource } from '@alfa-client/tech-shared';
+import { Resource } from '@ngxp/rest';
+
+export interface OrganisationsEinheit {
+  name: string;
+  anschrift: Anschrift;
+}
+
+export interface Anschrift {
+  strasse: string;
+  hausnummer: string;
+  plz: string;
+  ort: string;
+}
+
+export interface OrganisationsEinheitResource
+  extends OrganisationsEinheit,
+    Resource,
+    ListItemResource {}
+export interface OrganisationsEinheitListResource extends ListResource {}
diff --git a/alfa-client/libs/collaboration-shared/src/lib/organisations-einheit.service.spec.ts b/alfa-client/libs/collaboration-shared/src/lib/organisations-einheit.service.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2099588d498d90965f498e9c9c8a1bce56d9bce5
--- /dev/null
+++ b/alfa-client/libs/collaboration-shared/src/lib/organisations-einheit.service.spec.ts
@@ -0,0 +1,102 @@
+import { StateResource, createStateResource } from '@alfa-client/tech-shared';
+import { Mock, mock, useFromMock } from '@alfa-client/test-utils';
+import faker from '@faker-js/faker';
+import { Observable, of } from 'rxjs';
+import { singleColdCompleted } from '../../../tech-shared/test/marbles';
+import {
+  createOrganisationsEinheitListResource,
+  createOrganisationsEinheitResource,
+} from '../../test/organisations-einheit';
+import { OrganisationsEinheitResourceSearchService } from './organisations-einheit-resource-search.service';
+import {
+  OrganisationsEinheitListResource,
+  OrganisationsEinheitResource,
+} from './organisations-einheit.model';
+import { OrganisationsEinheitService } from './organisations-einheit.service';
+
+jest.mock('./organisations-einheit-resource-search.service');
+
+describe('OrganisationsEinheitService', () => {
+  let service: OrganisationsEinheitService;
+
+  let searchService: Mock<OrganisationsEinheitResourceSearchService>;
+
+  const listResource: OrganisationsEinheitListResource = createOrganisationsEinheitListResource();
+  const listStateResource: StateResource<OrganisationsEinheitListResource> =
+    createStateResource(listResource);
+
+  beforeEach(() => {
+    searchService = mock(OrganisationsEinheitResourceSearchService);
+
+    service = new OrganisationsEinheitService(useFromMock(searchService));
+  });
+
+  describe('get search result list', () => {
+    it('should call search service', () => {
+      service.getSearchResultList();
+
+      expect(searchService.getResultList).toHaveBeenCalled();
+    });
+
+    it('should return result', (done) => {
+      searchService.getResultList.mockReturnValue(of(listStateResource));
+
+      service
+        .getSearchResultList()
+        .subscribe((result: StateResource<OrganisationsEinheitListResource>) => {
+          expect(result).toBe(listStateResource);
+          done();
+        });
+    });
+  });
+
+  describe('search', () => {
+    const searchBy: string = faker.random.word();
+
+    it('should call search service with search string', () => {
+      service.search(searchBy);
+
+      expect(searchService.search).toHaveBeenCalledWith(searchBy);
+    });
+  });
+
+  describe('clear search result', () => {
+    it('should call search service', () => {
+      service.clearSearchResult();
+
+      expect(searchService.clearResultList).toHaveBeenCalledWith();
+    });
+  });
+
+  describe('get selected result', () => {
+    const organisationsEinheitResource: OrganisationsEinheitResource =
+      createOrganisationsEinheitResource();
+
+    beforeEach(() => {
+      searchService.getSelectedResult.mockReturnValue(of(organisationsEinheitResource));
+    });
+
+    it('should call service', () => {
+      service.getSelectedResult();
+
+      expect(searchService.getSelectedResult).toHaveBeenCalled();
+    });
+
+    it('should return result', () => {
+      const selectedResult$: Observable<OrganisationsEinheitResource> = service.getSelectedResult();
+
+      expect(selectedResult$).toBeObservable(singleColdCompleted(organisationsEinheitResource));
+    });
+  });
+
+  describe('select search result', () => {
+    const organisationsEinheitResource: OrganisationsEinheitResource =
+      createOrganisationsEinheitResource();
+
+    it('should call service', () => {
+      service.selectSearchResult(organisationsEinheitResource);
+
+      expect(searchService.selectResult).toHaveBeenCalledWith(organisationsEinheitResource);
+    });
+  });
+});
diff --git a/alfa-client/libs/collaboration-shared/src/lib/organisations-einheit.service.ts b/alfa-client/libs/collaboration-shared/src/lib/organisations-einheit.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f4fadaf317dfd2bc7bf9103e8bd4d953613c21aa
--- /dev/null
+++ b/alfa-client/libs/collaboration-shared/src/lib/organisations-einheit.service.ts
@@ -0,0 +1,33 @@
+import { StateResource } from '@alfa-client/tech-shared';
+import { Injectable } from '@angular/core';
+import { Observable } from 'rxjs';
+import { OrganisationsEinheitResourceSearchService } from './organisations-einheit-resource-search.service';
+import {
+  OrganisationsEinheitListResource,
+  OrganisationsEinheitResource,
+} from './organisations-einheit.model';
+
+@Injectable()
+export class OrganisationsEinheitService {
+  constructor(private readonly searchService: OrganisationsEinheitResourceSearchService) {}
+
+  public getSearchResultList(): Observable<StateResource<OrganisationsEinheitListResource>> {
+    return this.searchService.getResultList();
+  }
+
+  public search(searchBy: string): void {
+    this.searchService.search(searchBy);
+  }
+
+  public clearSearchResult(): void {
+    this.searchService.clearResultList();
+  }
+
+  public getSelectedResult(): Observable<OrganisationsEinheitResource> {
+    return this.searchService.getSelectedResult();
+  }
+
+  public selectSearchResult(organisationsEinheitResource: OrganisationsEinheitResource): void {
+    this.searchService.selectResult(organisationsEinheitResource);
+  }
+}
diff --git a/alfa-client/libs/collaboration-shared/src/test-setup.ts b/alfa-client/libs/collaboration-shared/src/test-setup.ts
new file mode 100644
index 0000000000000000000000000000000000000000..6b07c0bac34c40aa6afeef02c18c8db08f79de48
--- /dev/null
+++ b/alfa-client/libs/collaboration-shared/src/test-setup.ts
@@ -0,0 +1,15 @@
+import '@testing-library/jest-dom';
+import 'jest-preset-angular/setup-jest';
+
+import { getTestBed } from '@angular/core/testing';
+import {
+  BrowserDynamicTestingModule,
+  platformBrowserDynamicTesting,
+} from '@angular/platform-browser-dynamic/testing';
+
+getTestBed().resetTestEnvironment();
+getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting(), {
+  teardown: { destroyAfterEach: false },
+  errorOnUnknownProperties: true,
+  errorOnUnknownElements: true,
+});
diff --git a/alfa-client/libs/collaboration-shared/test/collaboration.ts b/alfa-client/libs/collaboration-shared/test/collaboration.ts
new file mode 100644
index 0000000000000000000000000000000000000000..fef47c56b2280e8cc85ae90773b90ba9d910d868
--- /dev/null
+++ b/alfa-client/libs/collaboration-shared/test/collaboration.ts
@@ -0,0 +1,38 @@
+import faker from '@faker-js/faker';
+import { times } from 'lodash-es';
+import { LinkRelationName } from '../../tech-shared/src';
+import { toResource } from '../../tech-shared/test/resource';
+import { CollaborationListLinkRel, OrganisationsEinheitResource } from '../src';
+import {
+  Collaboration,
+  CollaborationListResource,
+  CollaborationResource,
+} from '../src/lib/collaboration.model';
+
+export function createCollaboration(): Collaboration {
+  return {
+    titel: faker.random.words(2),
+    anfrage: faker.random.words(10),
+    zustaendigeStelle: faker.internet.url(),
+  };
+}
+
+export function createCollaborationResource(
+  linkRelations: LinkRelationName[] = [],
+): CollaborationResource {
+  return toResource(createCollaboration(), linkRelations);
+}
+
+export function createCollaborationResources(
+  linkRelations: LinkRelationName[] = [],
+): OrganisationsEinheitResource[] {
+  return times(10, () => toResource(createCollaborationResource(), [...linkRelations]));
+}
+
+export function createCollaborationListResource(
+  linkRelations: LinkRelationName[] = [],
+): CollaborationListResource {
+  return toResource({}, [...linkRelations], {
+    [CollaborationListLinkRel.COLLABORATION_LIST]: createCollaborationResources(),
+  });
+}
diff --git a/alfa-client/libs/collaboration-shared/test/organisations-einheit.ts b/alfa-client/libs/collaboration-shared/test/organisations-einheit.ts
new file mode 100644
index 0000000000000000000000000000000000000000..4c0f749b773824c841749f7cc5f7851bf7a44134
--- /dev/null
+++ b/alfa-client/libs/collaboration-shared/test/organisations-einheit.ts
@@ -0,0 +1,49 @@
+import { times } from 'lodash-es';
+import { toResource } from '../../tech-shared/test/resource';
+import {
+  Anschrift,
+  OrganisationsEinheit,
+  OrganisationsEinheitListLinkRel,
+  OrganisationsEinheitListResource,
+  OrganisationsEinheitResource,
+} from '../src';
+
+import { faker } from '@faker-js/faker';
+
+export function createAnschrift(): Anschrift {
+  return {
+    hausnummer: faker.random.word(),
+    ort: faker.random.word(),
+    plz: faker.random.word(),
+    strasse: faker.random.words(2),
+  };
+}
+
+export function createOrganisationsEinheit(): OrganisationsEinheit {
+  return {
+    name: faker.random.word(),
+    anschrift: createAnschrift(),
+  };
+}
+
+export function createOrganisationsEinheitResource(
+  linkRel: string[] = [],
+): OrganisationsEinheitResource {
+  return toResource(createOrganisationsEinheit(), linkRel);
+}
+
+export function createOrganisationsEinheitResources(
+  linkRelations: string[] = [],
+): OrganisationsEinheitResource[] {
+  return times(10, () => toResource(createOrganisationsEinheitResource(), [...linkRelations]));
+}
+
+export function createOrganisationsEinheitListResource(
+  resources?: OrganisationsEinheitResource[],
+  linkRelations: string[] = [],
+): OrganisationsEinheitListResource {
+  return toResource({}, [...linkRelations], {
+    [OrganisationsEinheitListLinkRel.ORGANISATIONS_EINHEIT_HEADER_LIST]:
+      resources ? resources : createOrganisationsEinheitResources(),
+  });
+}
diff --git a/alfa-client/libs/collaboration-shared/tsconfig.json b/alfa-client/libs/collaboration-shared/tsconfig.json
new file mode 100644
index 0000000000000000000000000000000000000000..7cc6baf2f58ed5ccfba098131996f579979e9f18
--- /dev/null
+++ b/alfa-client/libs/collaboration-shared/tsconfig.json
@@ -0,0 +1,16 @@
+{
+  "extends": "../../tsconfig.base.json",
+  "files": [],
+  "include": [],
+  "references": [
+    {
+      "path": "./tsconfig.lib.json"
+    },
+    {
+      "path": "./tsconfig.spec.json"
+    }
+  ],
+  "compilerOptions": {
+    "target": "es2022"
+  }
+}
diff --git a/alfa-client/libs/collaboration-shared/tsconfig.lib.json b/alfa-client/libs/collaboration-shared/tsconfig.lib.json
new file mode 100644
index 0000000000000000000000000000000000000000..dcc35a71ee8a26bc9394b9cf96b02996be26ec16
--- /dev/null
+++ b/alfa-client/libs/collaboration-shared/tsconfig.lib.json
@@ -0,0 +1,12 @@
+{
+  "extends": "./tsconfig.json",
+  "compilerOptions": {
+    "outDir": "../../dist/out-tsc",
+    "declaration": true,
+    "declarationMap": true,
+    "inlineSources": true,
+    "types": []
+  },
+  "exclude": ["src/test-setup.ts", "src/**/*.spec.ts", "jest.config.ts", "src/**/*.test.ts"],
+  "include": ["src/**/*.ts"]
+}
diff --git a/alfa-client/libs/collaboration-shared/tsconfig.spec.json b/alfa-client/libs/collaboration-shared/tsconfig.spec.json
new file mode 100644
index 0000000000000000000000000000000000000000..c3cb17f784fa2f7b9a4b0e7c9b03663500f4ee3d
--- /dev/null
+++ b/alfa-client/libs/collaboration-shared/tsconfig.spec.json
@@ -0,0 +1,12 @@
+{
+  "extends": "./tsconfig.json",
+  "compilerOptions": {
+    "outDir": "../../dist/out-tsc",
+    "module": "commonjs",
+    "types": ["jest", "node"],
+    "target": "ES2022",
+    "useDefineForClassFields": false
+  },
+  "files": ["src/test-setup.ts"],
+  "include": ["**/*.test.ts", "**/*.spec.ts", "**/*.d.ts", "jest.config.ts"]
+}
diff --git a/alfa-client/libs/collaboration/.eslintrc.json b/alfa-client/libs/collaboration/.eslintrc.json
new file mode 100644
index 0000000000000000000000000000000000000000..243c51741f65cc7afb3a7d85531c24afdcab5e56
--- /dev/null
+++ b/alfa-client/libs/collaboration/.eslintrc.json
@@ -0,0 +1,33 @@
+{
+  "extends": ["../../.eslintrc.json"],
+  "ignorePatterns": ["!**/*"],
+  "overrides": [
+    {
+      "files": ["*.ts"],
+      "extends": ["plugin:@nx/angular", "plugin:@angular-eslint/template/process-inline-templates"],
+      "rules": {
+        "@angular-eslint/directive-selector": [
+          "error",
+          {
+            "type": "attribute",
+            "prefix": "alfa",
+            "style": "camelCase"
+          }
+        ],
+        "@angular-eslint/component-selector": [
+          "error",
+          {
+            "type": "element",
+            "prefix": "alfa",
+            "style": "kebab-case"
+          }
+        ]
+      }
+    },
+    {
+      "files": ["*.html"],
+      "extends": ["plugin:@nx/angular-template"],
+      "rules": {}
+    }
+  ]
+}
diff --git a/alfa-client/libs/collaboration/README.md b/alfa-client/libs/collaboration/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..53577986259ad6d8403d1446c6c1426d24e6d06d
--- /dev/null
+++ b/alfa-client/libs/collaboration/README.md
@@ -0,0 +1,7 @@
+# collaboration
+
+This library was generated with [Nx](https://nx.dev).
+
+## Running unit tests
+
+Run `nx test collaboration` to execute the unit tests.
diff --git a/alfa-client/libs/collaboration/jest.config.ts b/alfa-client/libs/collaboration/jest.config.ts
new file mode 100644
index 0000000000000000000000000000000000000000..fdccd307388de8b7fb2256a71ec07808ec5b05de
--- /dev/null
+++ b/alfa-client/libs/collaboration/jest.config.ts
@@ -0,0 +1,22 @@
+/* eslint-disable */
+export default {
+  displayName: 'collaboration',
+  preset: '../../jest.preset.js',
+  setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
+  coverageDirectory: '../../coverage/libs/collaboration',
+  transform: {
+    '^.+\\.(ts|mjs|js|html)$': [
+      'jest-preset-angular',
+      {
+        tsconfig: '<rootDir>/tsconfig.spec.json',
+        stringifyContentPathRegex: '\\.(html|svg)$',
+      },
+    ],
+  },
+  transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
+  snapshotSerializers: [
+    'jest-preset-angular/build/serializers/no-ng-attributes',
+    'jest-preset-angular/build/serializers/ng-snapshot',
+    'jest-preset-angular/build/serializers/html-comment',
+  ],
+};
diff --git a/alfa-client/libs/collaboration/project.json b/alfa-client/libs/collaboration/project.json
new file mode 100644
index 0000000000000000000000000000000000000000..39d9434a1f4c96550e4d71423eed803a6c397993
--- /dev/null
+++ b/alfa-client/libs/collaboration/project.json
@@ -0,0 +1,21 @@
+{
+  "name": "collaboration",
+  "$schema": "../../node_modules/nx/schemas/project-schema.json",
+  "sourceRoot": "libs/collaboration/src",
+  "prefix": "alfa",
+  "projectType": "library",
+  "tags": [],
+  "targets": {
+    "test": {
+      "executor": "@nx/jest:jest",
+      "outputs": ["{workspaceRoot}/coverage/libs/collaboration"],
+      "options": {
+        "tsConfig": "libs//collaboration/tsconfig.spec.json",
+        "jestConfig": "libs/collaboration/jest.config.ts"
+      }
+    },
+    "lint": {
+      "executor": "@nx/eslint:lint"
+    }
+  }
+}
diff --git a/alfa-client/libs/collaboration/src/index.ts b/alfa-client/libs/collaboration/src/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..fe7fae5e1dd38a384cd93d2ad8425d93ac37ae03
--- /dev/null
+++ b/alfa-client/libs/collaboration/src/index.ts
@@ -0,0 +1,2 @@
+export * from './lib/collaboration-in-vorgang-container/collaboration-in-vorgang-container.component';
+export * from './lib/collaboration.module';
diff --git a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-in-vorgang-container.component.html b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-in-vorgang-container.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..d0d5db82cd5b543c578693ef03c4907a134077f8
--- /dev/null
+++ b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-in-vorgang-container.component.html
@@ -0,0 +1,8 @@
+<alfa-collaboration-in-vorgang
+  data-test-id="collaboration-in-vorgang"
+  [collaborationStateListResource]="collaborationStateListResource$ | async"
+  [isRequestFormVisible]="isRequestFormVisible$ | async"
+  [organisationsEinheit]="selectedOrganisationsEinheit$ | async"
+  (hideRequestForm)="hideRequestForm()"
+  (showRequestForm)="showRequestForm()"
+></alfa-collaboration-in-vorgang>
diff --git a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-in-vorgang-container.component.spec.ts b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-in-vorgang-container.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..85649462f34ddd362382333feed07cf10693ed88
--- /dev/null
+++ b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-in-vorgang-container.component.spec.ts
@@ -0,0 +1,158 @@
+import {
+  CollaborationListResource,
+  OrganisationsEinheitResource,
+} from '@alfa-client/collaboration-shared';
+import { StateResource, createStateResource } from '@alfa-client/tech-shared';
+import { Mock, dispatchEventFromFixture, getMockComponent, mock } from '@alfa-client/test-utils';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { CollaborationService } from 'libs/collaboration-shared/src/lib/collaboration.service';
+import { OrganisationsEinheitResourceSearchService } from 'libs/collaboration-shared/src/lib/organisations-einheit-resource-search.service';
+import { createCollaborationListResource } from 'libs/collaboration-shared/test/collaboration';
+import { createOrganisationsEinheitResource } from 'libs/collaboration-shared/test/organisations-einheit';
+import { getDataTestIdOf } from 'libs/tech-shared/test/data-test';
+import { MockComponent } from 'ng-mocks';
+import { of } from 'rxjs';
+import { CollaborationInVorgangContainerComponent } from './collaboration-in-vorgang-container.component';
+import { CollaborationInVorgangComponent } from './collaboration-in-vorgang/collaboration-in-vorgang.component';
+
+jest.mock('libs/collaboration-shared/src/lib/organisations-einheit-resource-search.service');
+
+describe('CollaborationInVorgangContainerComponent', () => {
+  let component: CollaborationInVorgangContainerComponent;
+  let fixture: ComponentFixture<CollaborationInVorgangContainerComponent>;
+
+  const collaborationInVorgangComp: string = getDataTestIdOf('collaboration-in-vorgang');
+
+  const service: Mock<CollaborationService> = {
+    ...mock(CollaborationService),
+    isRequestFormVisible: jest.fn().mockReturnValue(of(false)),
+  };
+
+  const organisationsEinheitSearchService: Mock<OrganisationsEinheitResourceSearchService> = mock(
+    OrganisationsEinheitResourceSearchService,
+  );
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      declarations: [
+        CollaborationInVorgangContainerComponent,
+        MockComponent(CollaborationInVorgangComponent),
+      ],
+      providers: [
+        {
+          provide: CollaborationService,
+          useValue: service,
+        },
+        {
+          provide: OrganisationsEinheitResourceSearchService,
+          useValue: organisationsEinheitSearchService,
+        },
+      ],
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(CollaborationInVorgangContainerComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+
+  describe('ngOnInit', () => {
+    it('should call service to get collaboration state list resource', () => {
+      component.ngOnInit();
+
+      expect(service.getList).toHaveBeenCalled();
+    });
+
+    it('should call service to get request form visbility', () => {
+      component.ngOnInit();
+
+      expect(service.isRequestFormVisible).toHaveBeenCalled();
+    });
+
+    it('should get selected result', () => {
+      component.ngOnInit();
+
+      expect(organisationsEinheitSearchService.getSelectedResult).toHaveBeenCalled();
+    });
+  });
+
+  describe('collaboration in vorgang component', () => {
+    const collaborationListResource: CollaborationListResource = createCollaborationListResource();
+    const collaborationStateListResource: StateResource<CollaborationListResource> =
+      createStateResource(collaborationListResource);
+
+    describe('should be called with', () => {
+      it('collaboration state list resource', () => {
+        component.collaborationStateListResource$ = of(collaborationStateListResource);
+
+        fixture.detectChanges();
+
+        expect(getCollaborationInVorgangComponent().collaborationStateListResource).toBe(
+          collaborationStateListResource,
+        );
+      });
+
+      it('is request form visible', () => {
+        component.isRequestFormVisible$ = of(true);
+
+        fixture.detectChanges();
+
+        expect(getCollaborationInVorgangComponent().isRequestFormVisible).toBeTruthy();
+      });
+
+      it('organisations einheit', () => {
+        const organisationsEinheitResource: OrganisationsEinheitResource =
+          createOrganisationsEinheitResource();
+        component.selectedOrganisationsEinheit$ = of(organisationsEinheitResource);
+
+        fixture.detectChanges();
+
+        expect(getCollaborationInVorgangComponent().organisationsEinheit).toBe(
+          organisationsEinheitResource,
+        );
+      });
+
+      function getCollaborationInVorgangComponent(): CollaborationInVorgangComponent {
+        return getMockComponent<CollaborationInVorgangComponent>(
+          fixture,
+          CollaborationInVorgangComponent,
+        );
+      }
+    });
+
+    it('should call hideRequestForm on output', () => {
+      component.hideRequestForm = jest.fn();
+
+      dispatchEventFromFixture(fixture, collaborationInVorgangComp, 'hideRequestForm');
+
+      expect(component.hideRequestForm).toHaveBeenCalled();
+    });
+
+    it('should call showRequestForm on output', () => {
+      component.showRequestForm = jest.fn();
+
+      dispatchEventFromFixture(fixture, collaborationInVorgangComp, 'showRequestForm');
+
+      expect(component.showRequestForm).toHaveBeenCalled();
+    });
+  });
+
+  describe('show request form', () => {
+    it('should call service', () => {
+      component.showRequestForm();
+
+      expect(service.showRequestForm).toHaveBeenCalled();
+    });
+  });
+
+  describe('hide request form', () => {
+    it('should call service', () => {
+      component.hideRequestForm();
+
+      expect(service.hideRequestForm).toHaveBeenCalled();
+    });
+  });
+});
diff --git a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-in-vorgang-container.component.ts b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-in-vorgang-container.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..63127377e2c066b9a8eedaa7e2ca7b58c74ba8fa
--- /dev/null
+++ b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-in-vorgang-container.component.ts
@@ -0,0 +1,36 @@
+import { OrganisationsEinheitResource } from '@alfa-client/collaboration-shared';
+import { StateResource } from '@alfa-client/tech-shared';
+import { Component, OnInit } from '@angular/core';
+import { CollaborationListResource } from 'libs/collaboration-shared/src/lib/collaboration.model';
+import { CollaborationService } from 'libs/collaboration-shared/src/lib/collaboration.service';
+import { OrganisationsEinheitResourceSearchService } from 'libs/collaboration-shared/src/lib/organisations-einheit-resource-search.service';
+import { Observable } from 'rxjs';
+
+@Component({
+  selector: 'alfa-collaboration-in-vorgang-container',
+  templateUrl: './collaboration-in-vorgang-container.component.html',
+})
+export class CollaborationInVorgangContainerComponent implements OnInit {
+  public collaborationStateListResource$: Observable<StateResource<CollaborationListResource>>;
+  public isRequestFormVisible$: Observable<boolean>;
+  public selectedOrganisationsEinheit$: Observable<OrganisationsEinheitResource>;
+
+  constructor(
+    private readonly service: CollaborationService,
+    private readonly searchService: OrganisationsEinheitResourceSearchService,
+  ) {}
+
+  ngOnInit(): void {
+    this.collaborationStateListResource$ = this.service.getList();
+    this.isRequestFormVisible$ = this.service.isRequestFormVisible();
+    this.selectedOrganisationsEinheit$ = this.searchService.getSelectedResult();
+  }
+
+  public showRequestForm(): void {
+    this.service.showRequestForm();
+  }
+
+  public hideRequestForm(): void {
+    this.service.hideRequestForm();
+  }
+}
diff --git a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-in-vorgang/collaboration-in-vorgang.component.html b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-in-vorgang/collaboration-in-vorgang.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..298c59138de6107079d0e2c83e2991958d6912ef
--- /dev/null
+++ b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-in-vorgang/collaboration-in-vorgang.component.html
@@ -0,0 +1,31 @@
+<ng-container
+  *ngIf="
+    collaborationStateListResource.resource
+      | hasLink: collaborationListLinkRel.CREATE_COLLABORATION_REQUEST
+  "
+>
+  <ng-template #anfrageErstellenButton>
+    <ods-button
+      variant="outline"
+      text="Anfrage erstellen"
+      dataTestId="anfrage-erstellen-button"
+      (clickEmitter)="showRequestForm.emit()"
+    >
+      <ods-collaboration-icon icon />
+    </ods-button>
+  </ng-template>
+
+  <ng-container *ngIf="isRequestFormVisible; else anfrageErstellenButton">
+    <alfa-collaboration-request-form
+      data-test-id="collaboration-request-form"
+      [collaborationListResource]="collaborationStateListResource.resource"
+      (hide)="hideRequestForm.emit()"
+      (showResult)="setCollaboration($event)"
+    ></alfa-collaboration-request-form>
+  </ng-container>
+</ng-container>
+<ng-container *ngIf="collaboration">
+  <div data-test-id="collaboration-request-result">
+    Result: {{ collaboration | json }} OrganisationsEinheit: {{ organisationsEinheit | json }}
+  </div>
+</ng-container>
diff --git a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-in-vorgang/collaboration-in-vorgang.component.spec.ts b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-in-vorgang/collaboration-in-vorgang.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..71ed93f04ed34882a1a0b8bf62ea74fc11382b13
--- /dev/null
+++ b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-in-vorgang/collaboration-in-vorgang.component.spec.ts
@@ -0,0 +1,186 @@
+import {
+  Collaboration,
+  CollaborationListLinkRel,
+  CollaborationListResource,
+} from '@alfa-client/collaboration-shared';
+import { HasLinkPipe, createStateResource } from '@alfa-client/tech-shared';
+import {
+  EventData,
+  dispatchEventFromFixture,
+  existsAsHtmlElement,
+  getMockComponent,
+  notExistsAsHtmlElement,
+  triggerEvent,
+} from '@alfa-client/test-utils';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ButtonComponent, CollaborationIconComponent } from '@ods/system';
+import {
+  createCollaboration,
+  createCollaborationListResource,
+} from 'libs/collaboration-shared/test/collaboration';
+import { getDataTestIdAttributeOf, getDataTestIdOf } from 'libs/tech-shared/test/data-test';
+import { MockComponent } from 'ng-mocks';
+import { CollaborationRequestFormComponent } from '../collaboration-request-form/collaboration-request-form.component';
+import { CollaborationInVorgangComponent } from './collaboration-in-vorgang.component';
+
+describe('CollaborationInVorgangComponent', () => {
+  let component: CollaborationInVorgangComponent;
+  let fixture: ComponentFixture<CollaborationInVorgangComponent>;
+
+  const anfrageErstellenButton: string = getDataTestIdAttributeOf('anfrage-erstellen-button');
+  const collaborationRequestForm: string = getDataTestIdOf('collaboration-request-form');
+  const collaborationRequestResult: string = getDataTestIdOf('collaboration-request-result');
+
+  const collaborationListResource: CollaborationListResource = createCollaborationListResource();
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      declarations: [
+        CollaborationInVorgangComponent,
+        HasLinkPipe,
+        MockComponent(ButtonComponent),
+        MockComponent(CollaborationRequestFormComponent),
+        MockComponent(CollaborationIconComponent),
+      ],
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(CollaborationInVorgangComponent);
+    component = fixture.componentInstance;
+    component.collaborationStateListResource = createStateResource(collaborationListResource);
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+
+  describe('if create collaboration request link exists', () => {
+    const collaborationListResourceWithLink: CollaborationListResource =
+      createCollaborationListResource([CollaborationListLinkRel.CREATE_COLLABORATION_REQUEST]);
+    beforeEach(() => {
+      component.collaborationStateListResource = createStateResource(
+        collaborationListResourceWithLink,
+      );
+      fixture.detectChanges();
+    });
+
+    describe('anfrage erstellen button', () => {
+      describe('on request form visibility false', () => {
+        beforeEach(() => {
+          component.isRequestFormVisible = false;
+        });
+
+        it('should be shown', () => {
+          fixture.detectChanges();
+
+          existsAsHtmlElement(fixture, anfrageErstellenButton);
+        });
+
+        it('should call service on click', () => {
+          fixture.detectChanges();
+          const showRequestFormSpy: jest.SpyInstance = (component.showRequestForm.emit = jest.fn());
+
+          dispatchEventFromFixture(fixture, anfrageErstellenButton, 'clickEmitter');
+
+          expect(showRequestFormSpy).toHaveBeenCalled();
+        });
+      });
+
+      it('should be hidden if request form visibility is true', () => {
+        component.isRequestFormVisible = true;
+
+        fixture.detectChanges();
+
+        notExistsAsHtmlElement(fixture, anfrageErstellenButton);
+      });
+    });
+
+    describe('zustaendige stelle', () => {
+      describe('on request form visibility true', () => {
+        beforeEach(() => {
+          component.isRequestFormVisible = true;
+        });
+        it('should be shown', () => {
+          fixture.detectChanges();
+
+          existsAsHtmlElement(fixture, collaborationRequestForm);
+        });
+
+        describe('component', () => {
+          it('should call service on hideFormular output', () => {
+            fixture.detectChanges();
+            const hideRequestFormSpy: jest.SpyInstance = (component.hideRequestForm.emit =
+              jest.fn());
+
+            dispatchEventFromFixture(fixture, collaborationRequestForm, 'hide');
+
+            expect(hideRequestFormSpy).toHaveBeenCalled();
+          });
+
+          it('should call set collaboration on showResult output', () => {
+            fixture.detectChanges();
+            component.setCollaboration = jest.fn();
+            const collaboration: Collaboration = createCollaboration();
+
+            const eventData: EventData<CollaborationInVorgangComponent> = {
+              fixture,
+              elementSelector: collaborationRequestForm,
+              name: 'showResult',
+              data: collaboration,
+            };
+            triggerEvent(eventData);
+
+            expect(component.setCollaboration).toHaveBeenCalledWith(collaboration);
+          });
+
+          it('should be called with', () => {
+            fixture.detectChanges();
+
+            const comp: CollaborationRequestFormComponent =
+              getMockComponent<CollaborationRequestFormComponent>(
+                fixture,
+                CollaborationRequestFormComponent,
+              );
+            expect(comp.collaborationListResource).toBe(collaborationListResourceWithLink);
+          });
+        });
+      });
+
+      it('should be hidden if request form visibility is false', () => {
+        component.isRequestFormVisible = false;
+
+        fixture.detectChanges();
+
+        notExistsAsHtmlElement(fixture, collaborationRequestForm);
+      });
+    });
+  });
+
+  describe('on existing collaboration', () => {
+    it('should show result', () => {
+      component.collaboration = createCollaboration();
+
+      fixture.detectChanges();
+
+      existsAsHtmlElement(fixture, collaborationRequestResult);
+    });
+  });
+
+  describe('set collaboration', () => {
+    const collaboration: Collaboration = createCollaboration();
+
+    it('should set attribute', () => {
+      component.setCollaboration(collaboration);
+
+      expect(component.collaboration).toBe(collaboration);
+    });
+
+    it('should call emitter', () => {
+      const hideRequestFormEmitSpy: jest.SpyInstance = (component.hideRequestForm.emit = jest.fn());
+
+      component.setCollaboration(collaboration);
+
+      expect(hideRequestFormEmitSpy).toBeCalled();
+    });
+  });
+});
diff --git a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-in-vorgang/collaboration-in-vorgang.component.ts b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-in-vorgang/collaboration-in-vorgang.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..3216f10156d4e4506b3a028a833700a04b4eb96b
--- /dev/null
+++ b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-in-vorgang/collaboration-in-vorgang.component.ts
@@ -0,0 +1,30 @@
+import {
+  Collaboration,
+  CollaborationListLinkRel,
+  CollaborationListResource,
+  OrganisationsEinheitResource,
+} from '@alfa-client/collaboration-shared';
+import { StateResource } from '@alfa-client/tech-shared';
+import { Component, EventEmitter, Input, Output } from '@angular/core';
+
+@Component({
+  selector: 'alfa-collaboration-in-vorgang',
+  templateUrl: './collaboration-in-vorgang.component.html',
+})
+export class CollaborationInVorgangComponent {
+  @Input() public collaborationStateListResource: StateResource<CollaborationListResource>;
+  @Input() public isRequestFormVisible: boolean;
+  @Input() public organisationsEinheit: OrganisationsEinheitResource;
+
+  @Output() public readonly showRequestForm: EventEmitter<void> = new EventEmitter<void>();
+  @Output() public readonly hideRequestForm: EventEmitter<void> = new EventEmitter<void>();
+
+  public readonly collaborationListLinkRel = CollaborationListLinkRel;
+
+  public collaboration: Collaboration;
+
+  public setCollaboration(collaboration: Collaboration) {
+    this.collaboration = collaboration;
+    this.hideRequestForm.emit();
+  }
+}
diff --git a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/collaboration-request-form.component.html b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/collaboration-request-form.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..bbb5fd59fc99d36e5f449e35d879bdc5b50bde88
--- /dev/null
+++ b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/collaboration-request-form.component.html
@@ -0,0 +1,34 @@
+<alfa-organisations-einheit-container
+  [fieldControl]="formService.form.controls.zustaendigeStelle"
+></alfa-organisations-einheit-container>
+
+<form [formGroup]="formService.form" class="mt-4 flex flex-col gap-2">
+  <ods-text-editor
+    label="Titel"
+    [formControlName]="formServiceClass.FIELD_TITLE"
+    [isRequired]="true"
+  ></ods-text-editor>
+  <ods-textarea-editor
+    label="Nachricht"
+    [formControlName]="formServiceClass.FIELD_NACHRICHT"
+    [isRequired]="true"
+  ></ods-textarea-editor>
+</form>
+
+<div class="mt-4 flex items-center gap-6">
+  <ods-button-with-spinner
+    text="Zuarbeit anfragen"
+    dataTestId="collaboration-request-submit-button"
+    [stateResource]="submitInProgress$ | async"
+    (clickEmitter)="submit()"
+  >
+  </ods-button-with-spinner>
+  <ods-button
+    variant="outline"
+    text="Abbrechen"
+    dataTestId="collaboration-request-cancel-button"
+    (clickEmitter)="hide.emit()"
+  >
+    <ods-close-icon icon class="fill-primary"></ods-close-icon>
+  </ods-button>
+</div>
diff --git a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/collaboration-request-form.component.spec.ts b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/collaboration-request-form.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..0ec28ea4c355c960aeb9be676a5ef47cd6026814
--- /dev/null
+++ b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/collaboration-request-form.component.spec.ts
@@ -0,0 +1,176 @@
+import { CollaborationListResource } from '@alfa-client/collaboration-shared';
+import { CommandLinkRel, CommandResource } from '@alfa-client/command-shared';
+import { StateResource, createStateResource } from '@alfa-client/tech-shared';
+import {
+  dispatchEventFromFixture,
+  getMockComponent,
+  mock,
+  useFromMock,
+} from '@alfa-client/test-utils';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { FormBuilder, ReactiveFormsModule } from '@angular/forms';
+import {
+  ButtonWithSpinnerComponent,
+  TextEditorComponent,
+  TextareaEditorComponent,
+} from '@ods/component';
+import { ButtonComponent, CloseIconComponent } from '@ods/system';
+import { CollaborationService } from 'libs/collaboration-shared/src/lib/collaboration.service';
+import { createCollaborationListResource } from 'libs/collaboration-shared/test/collaboration';
+import { createCommandResource } from 'libs/command-shared/test/command';
+import { getDataTestIdAttributeOf } from 'libs/tech-shared/test/data-test';
+import { singleColdCompleted } from 'libs/tech-shared/test/marbles';
+import { MockComponent } from 'ng-mocks';
+import { of } from 'rxjs';
+import { CollaborationRequestFormComponent } from './collaboration-request-form.component';
+import { CollaborationRequestFormService } from './collaboration.request.formservice';
+import { OrganisationsEinheitContainerComponent } from './organisations-einheit-container/organisations-einheit-container.component';
+
+describe('CollaborationRequestFormComponent', () => {
+  let component: CollaborationRequestFormComponent;
+  let fixture: ComponentFixture<CollaborationRequestFormComponent>;
+
+  const cancelButton: string = getDataTestIdAttributeOf('collaboration-request-cancel-button');
+  const submitButton: string = getDataTestIdAttributeOf('collaboration-request-submit-button');
+
+  let formService: CollaborationRequestFormService;
+
+  const stateCommandResource: StateResource<CommandResource> =
+    createStateResource(createCommandResource());
+
+  beforeEach(async () => {
+    formService = new CollaborationRequestFormService(
+      new FormBuilder(),
+      useFromMock(mock(CollaborationService)),
+    );
+    TestBed.overrideComponent(CollaborationRequestFormComponent, {
+      set: {
+        providers: [
+          {
+            provide: CollaborationRequestFormService,
+            useValue: formService,
+          },
+        ],
+      },
+    });
+    await TestBed.configureTestingModule({
+      imports: [ReactiveFormsModule],
+      declarations: [
+        CollaborationRequestFormComponent,
+        MockComponent(ButtonComponent),
+        MockComponent(ButtonWithSpinnerComponent),
+        MockComponent(CloseIconComponent),
+        MockComponent(TextEditorComponent),
+        MockComponent(TextareaEditorComponent),
+        MockComponent(OrganisationsEinheitContainerComponent),
+      ],
+      providers: [
+        {
+          provide: CollaborationRequestFormService,
+          useValue: formService,
+        },
+      ],
+    }).compileComponents();
+    fixture = TestBed.createComponent(CollaborationRequestFormComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+
+  describe('cancel button', () => {
+    it('should emit hideRequestForm', () => {
+      const emitSpy: jest.SpyInstance = (component.hide.emit = jest.fn());
+
+      dispatchEventFromFixture(fixture, cancelButton, 'clickEmitter');
+
+      expect(emitSpy).toHaveBeenCalled();
+    });
+  });
+
+  describe('submit button', () => {
+    describe('component', () => {
+      it('should be called with state resource', () => {
+        component.submitInProgress$ = of(stateCommandResource);
+
+        fixture.detectChanges();
+
+        const submitButtonComp: ButtonWithSpinnerComponent =
+          getMockComponent<ButtonWithSpinnerComponent>(fixture, ButtonWithSpinnerComponent);
+        expect(submitButtonComp.stateResource).toBe(stateCommandResource);
+      });
+    });
+
+    it('should call submit on output', () => {
+      component.submit = jest.fn();
+
+      dispatchEventFromFixture(fixture, submitButton, 'clickEmitter');
+
+      expect(component.submit).toHaveBeenCalled();
+    });
+  });
+
+  describe('submit', () => {
+    it('should call doSubmit', () => {
+      component.doSubmit = jest.fn();
+
+      component.submit();
+
+      expect(component.doSubmit).toHaveBeenCalled();
+    });
+
+    it('should set submitInProgress', () => {
+      component.doSubmit = jest.fn().mockReturnValue(of(stateCommandResource));
+
+      component.submit();
+
+      expect(component.submitInProgress$).toBeObservable(singleColdCompleted(stateCommandResource));
+    });
+  });
+
+  describe('do submit', () => {
+    beforeEach(() => {
+      formService.submit = jest
+        .fn()
+        .mockReturnValue(
+          of(createStateResource(createCommandResource([CommandLinkRel.EFFECTED_RESOURCE]))),
+        );
+    });
+
+    it('should call formService', () => {
+      formService.submit = jest.fn().mockReturnValue(of(stateCommandResource));
+
+      component.doSubmit().subscribe();
+
+      expect(formService.submit).toHaveBeenCalled();
+    });
+
+    it('should emit show result', () => {
+      const showResultSpy: jest.SpyInstance = (component.showResult.emit = jest.fn());
+
+      component.doSubmit().subscribe();
+
+      expect(showResultSpy).toHaveBeenCalledWith(formService.form.value);
+    });
+
+    it('should return value', () => {
+      formService.submit = jest.fn().mockReturnValue(of(stateCommandResource));
+
+      expect(component.doSubmit()).toBeObservable(singleColdCompleted(stateCommandResource));
+    });
+  });
+
+  describe('set collaboration list resource', () => {
+    it('should call set list resource on formService', () => {
+      formService.setListResource = jest.fn();
+      const collaborationListResource: CollaborationListResource =
+        createCollaborationListResource();
+
+      component.collaborationListResource = collaborationListResource;
+
+      expect(formService.setListResource).toHaveBeenCalledWith(collaborationListResource);
+    });
+  });
+});
diff --git a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/collaboration-request-form.component.ts b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/collaboration-request-form.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ccaf4fd89ec7f6af5d2afe69d3ff397669cd841c
--- /dev/null
+++ b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/collaboration-request-form.component.ts
@@ -0,0 +1,42 @@
+import { Collaboration, CollaborationListResource } from '@alfa-client/collaboration-shared';
+import { CommandResource, tapOnCommandSuccessfullyDone } from '@alfa-client/command-shared';
+import { HttpError, StateResource, createEmptyStateResource } from '@alfa-client/tech-shared';
+import { Component, EventEmitter, Input, Output } from '@angular/core';
+import { Observable, of } from 'rxjs';
+import { CollaborationRequestFormService } from './collaboration.request.formservice';
+
+@Component({
+  selector: 'alfa-collaboration-request-form',
+  templateUrl: './collaboration-request-form.component.html',
+  providers: [CollaborationRequestFormService],
+})
+export class CollaborationRequestFormComponent {
+  @Output() public hide: EventEmitter<void> = new EventEmitter<void>();
+  @Output() public showResult: EventEmitter<Collaboration> = new EventEmitter<Collaboration>();
+
+  @Input() public set collaborationListResource(
+    collaborationListResource: CollaborationListResource,
+  ) {
+    this.formService.setListResource(collaborationListResource);
+  }
+
+  public submitInProgress$: Observable<StateResource<CommandResource | HttpError>> = of(
+    createEmptyStateResource<CommandResource>(),
+  );
+
+  constructor(readonly formService: CollaborationRequestFormService) {}
+
+  public readonly formServiceClass = CollaborationRequestFormService;
+
+  public submit(): void {
+    this.submitInProgress$ = this.doSubmit();
+  }
+
+  doSubmit(): Observable<StateResource<CommandResource>> {
+    return this.formService
+      .submit()
+      .pipe(
+        tapOnCommandSuccessfullyDone(() => this.showResult.emit(this.formService.getFormValue())),
+      );
+  }
+}
diff --git a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/collaboration.request.formservice.spec.ts b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/collaboration.request.formservice.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..a9f135fc6a49e51d32f30ee11708d49189343178
--- /dev/null
+++ b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/collaboration.request.formservice.spec.ts
@@ -0,0 +1,67 @@
+import { CollaborationListResource } from '@alfa-client/collaboration-shared';
+import { CommandResource } from '@alfa-client/command-shared';
+import { HttpError, StateResource, createStateResource } from '@alfa-client/tech-shared';
+import { Mock, mock, useFromMock } from '@alfa-client/test-utils';
+import { UntypedFormBuilder } from '@angular/forms';
+import { CollaborationService } from 'libs/collaboration-shared/src/lib/collaboration.service';
+import { createCollaborationListResource } from 'libs/collaboration-shared/test/collaboration';
+import { createCommandResource } from 'libs/command-shared/test/command';
+import { singleColdCompleted } from 'libs/tech-shared/test/marbles';
+import { Observable, of } from 'rxjs';
+import { CollaborationRequestFormService } from './collaboration.request.formservice';
+
+describe('CollaborationRequestFormService', () => {
+  let formService: CollaborationRequestFormService;
+
+  let service: Mock<CollaborationService>;
+
+  const formBuilder: UntypedFormBuilder = new UntypedFormBuilder();
+
+  const collaborationListResource: CollaborationListResource = createCollaborationListResource();
+
+  beforeEach(() => {
+    service = mock(CollaborationService);
+
+    formService = new CollaborationRequestFormService(formBuilder, useFromMock(service));
+  });
+
+  it('should create', () => {
+    expect(formService).toBeTruthy();
+  });
+
+  describe('do submit', () => {
+    const stateCommandResource: StateResource<CommandResource> =
+      createStateResource(createCommandResource());
+
+    beforeEach(() => {
+      formService.listResource = collaborationListResource;
+      service.create.mockReturnValue(of(stateCommandResource));
+    });
+
+    it('should call service', () => {
+      formService.submit();
+
+      expect(service.create).toHaveBeenCalledWith(
+        collaborationListResource,
+        formService.form.value,
+      );
+    });
+
+    it('should return stateCommandResource', () => {
+      const response$: Observable<StateResource<CommandResource | HttpError>> =
+        formService.submit();
+
+      expect(response$).toBeObservable(singleColdCompleted(stateCommandResource));
+    });
+  });
+
+  describe('set list resource', () => {
+    it('should set given list resource', () => {
+      formService.listResource = undefined;
+
+      formService.setListResource(collaborationListResource);
+
+      expect(formService.listResource).toBe(collaborationListResource);
+    });
+  });
+});
diff --git a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/collaboration.request.formservice.ts b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/collaboration.request.formservice.ts
new file mode 100644
index 0000000000000000000000000000000000000000..eedf11fea57b5413757b863d50fee87000986a58
--- /dev/null
+++ b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/collaboration.request.formservice.ts
@@ -0,0 +1,48 @@
+import { CollaborationListResource } from '@alfa-client/collaboration-shared';
+import { CommandResource } from '@alfa-client/command-shared';
+import { AbstractFormService, StateResource } from '@alfa-client/tech-shared';
+import { Injectable } from '@angular/core';
+import { FormBuilder, FormControl, FormGroup } from '@angular/forms';
+import { ResourceUri } from '@ngxp/rest';
+import { CollaborationService } from 'libs/collaboration-shared/src/lib/collaboration.service';
+import { Observable } from 'rxjs';
+
+@Injectable()
+export class CollaborationRequestFormService extends AbstractFormService<CommandResource> {
+  public static readonly FIELD_ZUSTAENDIGE_STELLE: string = 'zustaendigeStelle';
+  public static readonly FIELD_TITLE: string = 'titel';
+  public static readonly FIELD_NACHRICHT: string = 'anfrage';
+
+  private static readonly PATH_PREFIX: string = 'command.body';
+
+  listResource: CollaborationListResource;
+
+  constructor(
+    formBuilder: FormBuilder,
+    private service: CollaborationService,
+  ) {
+    super(formBuilder);
+  }
+
+  protected initForm(): FormGroup {
+    return this.formBuilder.group({
+      [CollaborationRequestFormService.FIELD_ZUSTAENDIGE_STELLE]: new FormControl<ResourceUri>(
+        null,
+      ),
+      [CollaborationRequestFormService.FIELD_TITLE]: new FormControl<string>(null),
+      [CollaborationRequestFormService.FIELD_NACHRICHT]: new FormControl<string>(null),
+    });
+  }
+
+  protected doSubmit(): Observable<StateResource<CommandResource>> {
+    return this.service.create(this.listResource, this.getFormValue());
+  }
+
+  protected getPathPrefix(): string {
+    return CollaborationRequestFormService.PATH_PREFIX;
+  }
+
+  public setListResource(listResource: CollaborationListResource): void {
+    this.listResource = listResource;
+  }
+}
diff --git a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/organisations-einheit-container/organisations-einheit-container.component.html b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/organisations-einheit-container/organisations-einheit-container.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..76fb67a05d142c765f76eaf2413abc1af5454901
--- /dev/null
+++ b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/organisations-einheit-container/organisations-einheit-container.component.html
@@ -0,0 +1,23 @@
+<ng-container
+  *ngIf="organisationsEinheitResource$ | async as organisationsEinheitResource; else searchButton"
+>
+  <div class="flex items-center gap-3">
+    <ods-office-icon size="large" class="flex-none" />
+    <alfa-organisations-einheit
+      data-test-id="organisations-einheit-in-collaboration"
+      [organisationsEinheitResource]="organisationsEinheitResource"
+    ></alfa-organisations-einheit>
+  </div>
+</ng-container>
+<ng-template #searchButton>
+  <div class="flex items-center gap-3">
+    <ods-button
+      variant="outline"
+      text="Zuständige Stelle auswählen"
+      data-test-id="organisations-einheit-search-button"
+      (clickEmitter)="openSearchDialog()"
+    >
+      <ods-search-icon icon />
+    </ods-button>
+  </div>
+</ng-template>
diff --git a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/organisations-einheit-container/organisations-einheit-container.component.spec.ts b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/organisations-einheit-container/organisations-einheit-container.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..9fe951c4b33dbd191a352467286baaa168922529
--- /dev/null
+++ b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/organisations-einheit-container/organisations-einheit-container.component.spec.ts
@@ -0,0 +1,228 @@
+import {
+  OrganisationsEinheitResource,
+  OrganisationsEinheitService,
+} from '@alfa-client/collaboration-shared';
+import {
+  Mock,
+  dispatchEventFromFixture,
+  existsAsHtmlElement,
+  getMockComponent,
+  mock,
+} from '@alfa-client/test-utils';
+import { OzgcloudDialogService } from '@alfa-client/ui';
+import { DialogConfig } from '@angular/cdk/dialog';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { FormControl } from '@angular/forms';
+import { getUrl } from '@ngxp/rest';
+import { ButtonComponent, OfficeIconComponent } from '@ods/system';
+import { createOrganisationsEinheitResource } from 'libs/collaboration-shared/test/organisations-einheit';
+import { SearchIconComponent } from 'libs/design-system/src/lib/icons/search-icon/search-icon.component';
+import { getDataTestIdOf } from 'libs/tech-shared/test/data-test';
+import { MockComponent } from 'ng-mocks';
+import { of } from 'rxjs';
+import { SearchOrganisationsEinheitContainerComponent } from '../../../search-organisations-einheit-container/search-organisations-einheit-container.component';
+import { OrganisationsEinheitContainerComponent } from './organisations-einheit-container.component';
+import { OrganisationsEinheitComponent } from './organisations-einheit/organisations-einheit.component';
+
+describe('OrganisationsEinheitContainerComponent', () => {
+  let component: OrganisationsEinheitContainerComponent;
+  let fixture: ComponentFixture<OrganisationsEinheitContainerComponent>;
+
+  const searchOrganisationsEinheitButton: string = getDataTestIdOf(
+    'organisations-einheit-search-button',
+  );
+  const organisationsEinheitComp: string = getDataTestIdOf(
+    'organisations-einheit-in-collaboration',
+  );
+
+  const organisationsEinheitResource: OrganisationsEinheitResource =
+    createOrganisationsEinheitResource();
+
+  let dialogService: Mock<OzgcloudDialogService>;
+  let service: Mock<OrganisationsEinheitService>;
+
+  beforeEach(async () => {
+    dialogService = mock(OzgcloudDialogService);
+    service = {
+      ...mock(OrganisationsEinheitService),
+      getSelectedResult: jest.fn().mockReturnValue(of(createOrganisationsEinheitResource())),
+    };
+    TestBed.overrideComponent(OrganisationsEinheitContainerComponent, {
+      set: {
+        providers: [
+          {
+            provide: OrganisationsEinheitService,
+            useValue: service,
+          },
+        ],
+      },
+    });
+    await TestBed.configureTestingModule({
+      declarations: [
+        OrganisationsEinheitContainerComponent,
+        MockComponent(SearchIconComponent),
+        MockComponent(OfficeIconComponent),
+        MockComponent(ButtonComponent),
+        MockComponent(OrganisationsEinheitComponent),
+      ],
+      providers: [
+        {
+          provide: OzgcloudDialogService,
+          useValue: dialogService,
+        },
+        {
+          provide: OrganisationsEinheitService,
+          useValue: service,
+        },
+      ],
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(OrganisationsEinheitContainerComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+
+  describe('ngOnInt', () => {
+    beforeEach(() => {
+      component.getSelectedResult = jest.fn().mockReturnValue(of(organisationsEinheitResource));
+    });
+
+    it('should call getSelectedResult', () => {
+      component.getSelectedResult = jest.fn();
+
+      component.ngOnInit();
+
+      expect(component.getSelectedResult).toHaveBeenCalled();
+    });
+
+    it('should set organisationsEinheitResource', (done) => {
+      component.ngOnInit();
+
+      component.organisationsEinheitResource$.subscribe(
+        (organisationsEinheitResource: OrganisationsEinheitResource) => {
+          expect(organisationsEinheitResource).toBe(organisationsEinheitResource);
+          done();
+        },
+      );
+    });
+  });
+
+  describe('get selected result', () => {
+    const organisationsEinheitResource: OrganisationsEinheitResource =
+      createOrganisationsEinheitResource();
+
+    beforeEach(() => {
+      service.getSelectedResult.mockReturnValue(of(organisationsEinheitResource));
+    });
+
+    it('should call service', () => {
+      component.getSelectedResult().subscribe();
+
+      expect(service.getSelectedResult).toHaveBeenCalled();
+    });
+
+    it('should call handleResult', () => {
+      component.handleResult = jest.fn();
+
+      component.getSelectedResult().subscribe();
+
+      expect(component.handleResult).toHaveBeenCalledWith(organisationsEinheitResource);
+    });
+
+    it('should return value', (done) => {
+      component.handleResult = jest.fn();
+
+      component.getSelectedResult().subscribe((result) => {
+        expect(result).toBe(organisationsEinheitResource);
+        done();
+      });
+    });
+  });
+
+  describe('handle result', () => {
+    beforeEach(() => {
+      component.fieldControl = new FormControl();
+    });
+
+    it('should patch fieldControl with resource uri', () => {
+      const fieldControlPatchSpy: jest.SpyInstance = (component.fieldControl.patchValue =
+        jest.fn());
+
+      component.handleResult(organisationsEinheitResource);
+
+      expect(fieldControlPatchSpy).toHaveBeenCalledWith(getUrl(organisationsEinheitResource));
+    });
+
+    it('should not patch fieldControl if organisationsEinheit resource is null', () => {
+      const fieldControlPatchSpy: jest.SpyInstance = (component.fieldControl.patchValue =
+        jest.fn());
+
+      component.handleResult(null);
+
+      expect(fieldControlPatchSpy).not.toHaveBeenCalled();
+    });
+  });
+
+  describe('search zustaendige stelle button', () => {
+    beforeEach(() => {
+      component.organisationsEinheitResource$ = of(undefined);
+    });
+
+    it('should be visible on missing organisationsEinheit', () => {
+      fixture.detectChanges();
+
+      existsAsHtmlElement(fixture, searchOrganisationsEinheitButton);
+    });
+    it('should call openSearchDialog', () => {
+      component.openSearchDialog = jest.fn();
+
+      fixture.detectChanges();
+      dispatchEventFromFixture(fixture, searchOrganisationsEinheitButton, 'clickEmitter');
+
+      expect(component.openSearchDialog).toHaveBeenCalled();
+    });
+  });
+
+  describe('organisationsEinheit component', () => {
+    beforeEach(() => {
+      component.organisationsEinheitResource$ = of(organisationsEinheitResource);
+    });
+
+    it('should be visible on existing organisationsEinheit', () => {
+      fixture.detectChanges();
+
+      existsAsHtmlElement(fixture, organisationsEinheitComp);
+    });
+
+    it('should be called with resource', () => {
+      fixture.detectChanges();
+
+      const comp: OrganisationsEinheitComponent = getMockComponent<OrganisationsEinheitComponent>(
+        fixture,
+        OrganisationsEinheitComponent,
+      );
+      expect(comp.organisationsEinheitResource).toBe(organisationsEinheitResource);
+    });
+  });
+
+  describe('open search dialog', () => {
+    it('should call dialog service', () => {
+      const DIALOG_CONFIG: DialogConfig = {
+        backdropClass: ['backdrop-blur-1', 'bg-greybackdrop'],
+      };
+
+      component.openSearchDialog();
+
+      expect(dialogService.openInCallingComponentContext).toHaveBeenCalledWith(
+        SearchOrganisationsEinheitContainerComponent,
+        component.viewContainerRef,
+        null,
+        DIALOG_CONFIG,
+      );
+    });
+  });
+});
diff --git a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/organisations-einheit-container/organisations-einheit-container.component.ts b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/organisations-einheit-container/organisations-einheit-container.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2bddc100f8d72ccd8560386dd144574e532a58e6
--- /dev/null
+++ b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/organisations-einheit-container/organisations-einheit-container.component.ts
@@ -0,0 +1,62 @@
+import {
+  OrganisationsEinheitResource,
+  OrganisationsEinheitService,
+} from '@alfa-client/collaboration-shared';
+import { isNotNull } from '@alfa-client/tech-shared';
+import { OzgcloudDialogService } from '@alfa-client/ui';
+import { DialogConfig } from '@angular/cdk/dialog';
+import { Component, Input, OnInit, ViewContainerRef } from '@angular/core';
+import { AbstractControl } from '@angular/forms';
+import { ResourceUri, getUrl } from '@ngxp/rest';
+import { Observable, tap } from 'rxjs';
+import { SearchOrganisationsEinheitContainerComponent } from '../../../search-organisations-einheit-container/search-organisations-einheit-container.component';
+
+const DIALOG_CONFIG: DialogConfig = {
+  backdropClass: ['backdrop-blur-1', 'bg-greybackdrop'],
+};
+
+@Component({
+  selector: 'alfa-organisations-einheit-container',
+  templateUrl: './organisations-einheit-container.component.html',
+  providers: [OrganisationsEinheitService],
+})
+export class OrganisationsEinheitContainerComponent implements OnInit {
+  @Input() public fieldControl: AbstractControl<ResourceUri>;
+
+  public organisationsEinheitResource$: Observable<OrganisationsEinheitResource>;
+
+  constructor(
+    private readonly dialogService: OzgcloudDialogService,
+    readonly viewContainerRef: ViewContainerRef,
+    private readonly service: OrganisationsEinheitService,
+  ) {}
+
+  ngOnInit(): void {
+    this.organisationsEinheitResource$ = this.getSelectedResult();
+  }
+
+  getSelectedResult(): Observable<OrganisationsEinheitResource> {
+    return this.service
+      .getSelectedResult()
+      .pipe(
+        tap((organisationsEinheitResource: OrganisationsEinheitResource) =>
+          this.handleResult(organisationsEinheitResource),
+        ),
+      );
+  }
+
+  handleResult(organisationsEinheitResource: OrganisationsEinheitResource): void {
+    if (isNotNull(organisationsEinheitResource)) {
+      this.fieldControl.patchValue(getUrl(organisationsEinheitResource));
+    }
+  }
+
+  public openSearchDialog(): void {
+    this.dialogService.openInCallingComponentContext<SearchOrganisationsEinheitContainerComponent>(
+      SearchOrganisationsEinheitContainerComponent,
+      this.viewContainerRef,
+      null, //FIXME bitte null nicht als Parameter nehmen
+      DIALOG_CONFIG,
+    );
+  }
+}
diff --git a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/organisations-einheit-container/organisations-einheit/organisations-einheit.component.html b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/organisations-einheit-container/organisations-einheit/organisations-einheit.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..57d9280a6f6c3909e5d5c4494a245a803517d7a3
--- /dev/null
+++ b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/organisations-einheit-container/organisations-einheit/organisations-einheit.component.html
@@ -0,0 +1,2 @@
+<p class="font-bold">{{ name }}</p>
+<p>{{ address }}</p>
diff --git a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/organisations-einheit-container/organisations-einheit/organisations-einheit.component.spec.ts b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/organisations-einheit-container/organisations-einheit/organisations-einheit.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8e6eaa1ea513256ec82992961078976755078248
--- /dev/null
+++ b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/organisations-einheit-container/organisations-einheit/organisations-einheit.component.spec.ts
@@ -0,0 +1,58 @@
+import { OrganisationsEinheitResource } from '@alfa-client/collaboration-shared';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { createOrganisationsEinheitResource } from 'libs/collaboration-shared/test/organisations-einheit';
+import { OrganisationsEinheitComponent } from './organisations-einheit.component';
+
+describe('OrganisationsEinheitComponent', () => {
+  let component: OrganisationsEinheitComponent;
+  let fixture: ComponentFixture<OrganisationsEinheitComponent>;
+
+  const organisationsEinheitResource: OrganisationsEinheitResource =
+    createOrganisationsEinheitResource();
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      declarations: [OrganisationsEinheitComponent],
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(OrganisationsEinheitComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+
+  describe('set organisationsEinheit', () => {
+    it('should call update by organisationsEinheit', () => {
+      component.updateByOrganisationsEinheit = jest.fn();
+
+      component.organisationsEinheitResource = organisationsEinheitResource;
+
+      expect(component.updateByOrganisationsEinheit).toHaveBeenCalledWith(
+        organisationsEinheitResource,
+      );
+    });
+  });
+
+  describe('update by organisationsEinheit', () => {
+    it('should set name', () => {
+      component.name = null;
+
+      component.updateByOrganisationsEinheit(organisationsEinheitResource);
+
+      expect(component.name).toEqual(organisationsEinheitResource.name);
+    });
+
+    it('should set address', () => {
+      component.address = null;
+
+      component.updateByOrganisationsEinheit(organisationsEinheitResource);
+
+      expect(component.address).toEqual(
+        `${organisationsEinheitResource.anschrift.strasse} ${organisationsEinheitResource.anschrift.hausnummer}, ${organisationsEinheitResource.anschrift.plz} ${organisationsEinheitResource.anschrift.ort}`,
+      );
+    });
+  });
+});
diff --git a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/organisations-einheit-container/organisations-einheit/organisations-einheit.component.ts b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/organisations-einheit-container/organisations-einheit/organisations-einheit.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ff94e74f550eee641eaf4645b166838d5048badb
--- /dev/null
+++ b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/organisations-einheit-container/organisations-einheit/organisations-einheit.component.ts
@@ -0,0 +1,26 @@
+import { Anschrift, OrganisationsEinheitResource } from '@alfa-client/collaboration-shared';
+import { Component, Input } from '@angular/core';
+
+@Component({
+  selector: 'alfa-organisations-einheit',
+  templateUrl: './organisations-einheit.component.html',
+})
+export class OrganisationsEinheitComponent {
+  @Input() public set organisationsEinheitResource(
+    organisationsEinheit: OrganisationsEinheitResource,
+  ) {
+    this.updateByOrganisationsEinheit(organisationsEinheit);
+  }
+
+  public name: string;
+  public address: string;
+
+  updateByOrganisationsEinheit(organisationsEinheit: OrganisationsEinheitResource): void {
+    this.name = organisationsEinheit.name;
+    this.address = this.buildAddress(organisationsEinheit.anschrift);
+  }
+
+  private buildAddress(anschrift: Anschrift): string {
+    return `${anschrift.strasse} ${anschrift.hausnummer}, ${anschrift.plz} ${anschrift.ort}`;
+  }
+}
diff --git a/alfa-client/libs/collaboration/src/lib/collaboration.module.spec.ts b/alfa-client/libs/collaboration/src/lib/collaboration.module.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1fa74dca425307c2116f48587c5179882184daa1
--- /dev/null
+++ b/alfa-client/libs/collaboration/src/lib/collaboration.module.spec.ts
@@ -0,0 +1,14 @@
+import { TestBed } from '@angular/core/testing';
+import { CollaborationModule } from './collaboration.module';
+
+describe('CollaborationModule', () => {
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: [CollaborationModule],
+    }).compileComponents();
+  });
+
+  it('should create', () => {
+    expect(CollaborationModule).toBeDefined();
+  });
+});
diff --git a/alfa-client/libs/collaboration/src/lib/collaboration.module.ts b/alfa-client/libs/collaboration/src/lib/collaboration.module.ts
new file mode 100644
index 0000000000000000000000000000000000000000..82a66754b9da100acdf4bf900a6669832f24a4ab
--- /dev/null
+++ b/alfa-client/libs/collaboration/src/lib/collaboration.module.ts
@@ -0,0 +1,57 @@
+import { CollaborationSharedModule } from '@alfa-client/collaboration-shared';
+import { TechSharedModule } from '@alfa-client/tech-shared';
+import { CommonModule } from '@angular/common';
+import { NgModule } from '@angular/core';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import {
+  ButtonWithSpinnerComponent,
+  TextEditorComponent,
+  TextareaEditorComponent,
+} from '@ods/component';
+import {
+  ButtonComponent,
+  CloseIconComponent,
+  CollaborationIconComponent,
+  InstantSearchComponent,
+  OfficeIconComponent,
+  SaveIconComponent,
+  SearchIconComponent,
+} from '@ods/system';
+import { CollaborationInVorgangContainerComponent } from './collaboration-in-vorgang-container/collaboration-in-vorgang-container.component';
+import { CollaborationInVorgangComponent } from './collaboration-in-vorgang-container/collaboration-in-vorgang/collaboration-in-vorgang.component';
+import { CollaborationRequestFormComponent } from './collaboration-in-vorgang-container/collaboration-request-form/collaboration-request-form.component';
+import { OrganisationsEinheitContainerComponent } from './collaboration-in-vorgang-container/collaboration-request-form/organisations-einheit-container/organisations-einheit-container.component';
+import { OrganisationsEinheitComponent } from './collaboration-in-vorgang-container/collaboration-request-form/organisations-einheit-container/organisations-einheit/organisations-einheit.component';
+import { SearchOrganisationsEinheitContainerComponent } from './search-organisations-einheit-container/search-organisations-einheit-container.component';
+import { SearchOrganisationsEinheitFormComponent } from './search-organisations-einheit-container/search-organisations-einheit-form/search-organisations-einheit-form.component';
+
+@NgModule({
+  imports: [
+    CommonModule,
+    ButtonComponent,
+    OfficeIconComponent,
+    SaveIconComponent,
+    CloseIconComponent,
+    SearchIconComponent,
+    CollaborationSharedModule,
+    CollaborationIconComponent,
+    TextEditorComponent,
+    TextareaEditorComponent,
+    FormsModule,
+    ReactiveFormsModule,
+    InstantSearchComponent,
+    TechSharedModule,
+    ButtonWithSpinnerComponent,
+  ],
+  declarations: [
+    CollaborationInVorgangContainerComponent,
+    CollaborationInVorgangComponent,
+    CollaborationRequestFormComponent,
+    SearchOrganisationsEinheitContainerComponent,
+    SearchOrganisationsEinheitFormComponent,
+    OrganisationsEinheitContainerComponent,
+    OrganisationsEinheitComponent,
+  ],
+  exports: [CollaborationInVorgangContainerComponent],
+})
+export class CollaborationModule {}
diff --git a/alfa-client/libs/collaboration/src/lib/search-organisations-einheit-container/search-organisations-einheit-container.component.html b/alfa-client/libs/collaboration/src/lib/search-organisations-einheit-container/search-organisations-einheit-container.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..9af9814d5c4b8c0e740290016e4e3c8bdaecd4db
--- /dev/null
+++ b/alfa-client/libs/collaboration/src/lib/search-organisations-einheit-container/search-organisations-einheit-container.component.html
@@ -0,0 +1,19 @@
+<div class="my-32 flex h-screen flex-col gap-2">
+  <div class="flex gap-48 py-6 lg:gap-96">
+    <h1 class="text-xl font-bold text-primary">Zuständige Stelle auswählen</h1>
+    <ods-button variant="icon" size="fit" (clickEmitter)="closeDialog()">
+      <ods-close-icon class="fill-primary" icon />
+    </ods-button>
+  </div>
+  <alfa-search-organisations-einheit-form
+    *ngIf="organisationsEinheitStateListResource$ | async as organisationsEinheitStateListResource"
+    data-test-id="search-organisations-einheit"
+    [organisationsEinheiten]="
+      organisationsEinheitStateListResource.resource
+        | toEmbeddedResources: organisationsEinheitListLinkRel.ORGANISATIONS_EINHEIT_HEADER_LIST
+    "
+    (search)="search($event)"
+    (selectSearchResult)="selectSearchResult($event)"
+    (clearSearchResult)="clearSearchResult()"
+  ></alfa-search-organisations-einheit-form>
+</div>
diff --git a/alfa-client/libs/collaboration/src/lib/search-organisations-einheit-container/search-organisations-einheit-container.component.spec.ts b/alfa-client/libs/collaboration/src/lib/search-organisations-einheit-container/search-organisations-einheit-container.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2f94294e437896891c8c55521ca86c71a7b255d8
--- /dev/null
+++ b/alfa-client/libs/collaboration/src/lib/search-organisations-einheit-container/search-organisations-einheit-container.component.spec.ts
@@ -0,0 +1,205 @@
+import {
+  OrganisationsEinheitListResource,
+  OrganisationsEinheitResource,
+  OrganisationsEinheitService,
+} from '@alfa-client/collaboration-shared';
+import {
+  StateResource,
+  ToEmbeddedResourcesPipe,
+  createStateResource,
+} from '@alfa-client/tech-shared';
+import {
+  EventData,
+  Mock,
+  dialogRefMock,
+  getMockComponent,
+  mock,
+  triggerEvent,
+} from '@alfa-client/test-utils';
+import { DialogRef } from '@angular/cdk/dialog';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import faker from '@faker-js/faker';
+import { ButtonComponent, CloseIconComponent } from '@ods/system';
+import {
+  createOrganisationsEinheitListResource,
+  createOrganisationsEinheitResource,
+  createOrganisationsEinheitResources,
+} from 'libs/collaboration-shared/test/organisations-einheit';
+import { getDataTestIdOf } from 'libs/tech-shared/test/data-test';
+import { MockComponent } from 'ng-mocks';
+import { of } from 'rxjs';
+import { SearchOrganisationsEinheitContainerComponent } from './search-organisations-einheit-container.component';
+import { SearchOrganisationsEinheitFormComponent } from './search-organisations-einheit-form/search-organisations-einheit-form.component';
+
+describe('SearchOrganisationsEinheitContainerComponent', () => {
+  let component: SearchOrganisationsEinheitContainerComponent;
+  let fixture: ComponentFixture<SearchOrganisationsEinheitContainerComponent>;
+
+  const searchOrganisationsEinheitComp: string = getDataTestIdOf('search-organisations-einheit');
+
+  const service: Mock<OrganisationsEinheitService> = mock(OrganisationsEinheitService);
+
+  const organisationsEinheitResource: OrganisationsEinheitResource =
+    createOrganisationsEinheitResource();
+  const organisationsEinheitResources: OrganisationsEinheitResource[] =
+    createOrganisationsEinheitResources();
+  const organisationsEinheitListResource: OrganisationsEinheitListResource =
+    createOrganisationsEinheitListResource(organisationsEinheitResources);
+  const organisationsEinheitStateListResource: StateResource<OrganisationsEinheitListResource> =
+    createStateResource(organisationsEinheitListResource);
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      declarations: [
+        SearchOrganisationsEinheitContainerComponent,
+        ToEmbeddedResourcesPipe,
+        MockComponent(SearchOrganisationsEinheitFormComponent),
+        MockComponent(ButtonComponent),
+        MockComponent(CloseIconComponent),
+      ],
+      providers: [
+        {
+          provide: OrganisationsEinheitService,
+          useValue: service,
+        },
+        {
+          provide: DialogRef,
+          useValue: dialogRefMock,
+        },
+      ],
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(SearchOrganisationsEinheitContainerComponent);
+    component = fixture.componentInstance;
+    component.organisationsEinheitStateListResource$ = of(organisationsEinheitStateListResource);
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+
+  describe('ngOnInit', () => {
+    it('should call service', () => {
+      component.ngOnInit();
+
+      expect(service.getSearchResultList).toHaveBeenCalled();
+    });
+  });
+
+  describe('search organisationsEinheit component', () => {
+    beforeEach(() => {
+      component.organisationsEinheitStateListResource$ = of(organisationsEinheitStateListResource);
+      fixture.detectChanges();
+    });
+
+    it('should be called with organisationsEinheiten', () => {
+      const comp: SearchOrganisationsEinheitFormComponent =
+        getMockComponent<SearchOrganisationsEinheitFormComponent>(
+          fixture,
+          SearchOrganisationsEinheitFormComponent,
+        );
+
+      expect(comp.organisationsEinheiten).toEqual(organisationsEinheitResources);
+    });
+
+    it('should call search on openSearchDialog output', () => {
+      component.search = jest.fn();
+      const searchBy: string = faker.random.word();
+      const eventData: EventData<SearchOrganisationsEinheitContainerComponent> = {
+        fixture,
+        elementSelector: searchOrganisationsEinheitComp,
+        name: 'search',
+        data: searchBy,
+      };
+
+      triggerEvent(eventData);
+
+      expect(component.search).toHaveBeenCalledWith(searchBy);
+    });
+
+    it('should call selectSearchResult on selectSearchResult output', () => {
+      component.selectSearchResult = jest.fn();
+
+      const eventData: EventData<SearchOrganisationsEinheitContainerComponent> = {
+        fixture,
+        elementSelector: searchOrganisationsEinheitComp,
+        name: 'selectSearchResult',
+        data: organisationsEinheitResource,
+      };
+
+      triggerEvent(eventData);
+
+      expect(component.selectSearchResult).toHaveBeenCalledWith(organisationsEinheitResource);
+    });
+
+    it('should call clearSearchResult', () => {
+      component.clearSearchResult = jest.fn();
+
+      const eventData: EventData<SearchOrganisationsEinheitContainerComponent> = {
+        fixture,
+        elementSelector: searchOrganisationsEinheitComp,
+        name: 'clearSearchResult',
+        data: organisationsEinheitResource,
+      };
+
+      triggerEvent(eventData);
+
+      expect(component.clearSearchResult).toHaveBeenCalled();
+    });
+  });
+
+  describe('search', () => {
+    const searchBy: string = faker.random.word();
+
+    it('should call service', () => {
+      component.search(searchBy);
+
+      expect(service.search).toHaveBeenCalledWith(searchBy);
+    });
+  });
+
+  describe('select search result', () => {
+    it('should set select result', () => {
+      component.selectSearchResult(organisationsEinheitResource);
+
+      expect(service.selectSearchResult).toHaveBeenCalledWith(organisationsEinheitResource);
+    });
+
+    it('should call service', () => {
+      component.selectSearchResult(organisationsEinheitResource);
+
+      expect(service.clearSearchResult).toHaveBeenCalled();
+    });
+
+    it('should close dialog', () => {
+      component.selectSearchResult(organisationsEinheitResource);
+
+      expect(dialogRefMock.close).toHaveBeenCalledWith();
+    });
+  });
+
+  describe('clear search result', () => {
+    it('should call service', () => {
+      component.clearSearchResult();
+
+      expect(service.clearSearchResult).toHaveBeenCalled();
+    });
+  });
+
+  describe('close dialog', () => {
+    it('should clear search result', () => {
+      component.clearSearchResult = jest.fn();
+
+      component.closeDialog();
+
+      expect(component.clearSearchResult).toHaveBeenCalled();
+    });
+
+    it('should close dialog', () => {
+      component.closeDialog();
+
+      expect(dialogRefMock.close).toHaveBeenCalled();
+    });
+  });
+});
diff --git a/alfa-client/libs/collaboration/src/lib/search-organisations-einheit-container/search-organisations-einheit-container.component.ts b/alfa-client/libs/collaboration/src/lib/search-organisations-einheit-container/search-organisations-einheit-container.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..963ef863886ec30268528d90e3d9c5ea09d877d6
--- /dev/null
+++ b/alfa-client/libs/collaboration/src/lib/search-organisations-einheit-container/search-organisations-einheit-container.component.ts
@@ -0,0 +1,52 @@
+import {
+  OrganisationsEinheitListLinkRel,
+  OrganisationsEinheitService,
+} from '@alfa-client/collaboration-shared';
+import { StateResource } from '@alfa-client/tech-shared';
+import { DialogRef } from '@angular/cdk/dialog';
+import { Component, OnInit } from '@angular/core';
+import {
+  OrganisationsEinheitListResource,
+  OrganisationsEinheitResource,
+} from 'libs/collaboration-shared/src/lib/organisations-einheit.model';
+import { Observable } from 'rxjs';
+
+@Component({
+  selector: 'alfa-search-organisations-einheit-container',
+  templateUrl: './search-organisations-einheit-container.component.html',
+})
+export class SearchOrganisationsEinheitContainerComponent implements OnInit {
+  public organisationsEinheitStateListResource$: Observable<
+    StateResource<OrganisationsEinheitListResource>
+  >;
+
+  public readonly organisationsEinheitListLinkRel = OrganisationsEinheitListLinkRel;
+
+  constructor(
+    private readonly service: OrganisationsEinheitService,
+    private readonly dialogRef: DialogRef,
+  ) {}
+
+  ngOnInit(): void {
+    this.organisationsEinheitStateListResource$ = this.service.getSearchResultList();
+  }
+
+  public search(searchBy: string): void {
+    this.service.search(searchBy);
+  }
+
+  public selectSearchResult(organisationsEinheit: OrganisationsEinheitResource): void {
+    this.service.selectSearchResult(organisationsEinheit);
+    this.service.clearSearchResult();
+    this.dialogRef.close();
+  }
+
+  public clearSearchResult(): void {
+    this.service.clearSearchResult();
+  }
+
+  public closeDialog(): void {
+    this.clearSearchResult();
+    this.dialogRef.close();
+  }
+}
diff --git a/alfa-client/libs/collaboration/src/lib/search-organisations-einheit-container/search-organisations-einheit-form/search-organisations-einheit-form.component.html b/alfa-client/libs/collaboration/src/lib/search-organisations-einheit-container/search-organisations-einheit-form/search-organisations-einheit-form.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..7252665d682c7686f3ae4b63e4cce1567edf4f9d
--- /dev/null
+++ b/alfa-client/libs/collaboration/src/lib/search-organisations-einheit-container/search-organisations-einheit-form/search-organisations-einheit-form.component.html
@@ -0,0 +1,12 @@
+<form [formGroup]="formService.form">
+  <ods-instant-search
+    data-test-id="search"
+    placeholder="Name des Amts oder Adresse eingeben"
+    [control]="formService.form.controls.search"
+    [searchResults]="searchResults"
+    (searchResultSelected)="selectSearchResult.emit($event.data)"
+    (searchQueryChanged)="search.emit($event.searchBy)"
+    (searchQueryCleared)="clearSearchResult.emit()"
+    (searchResultClosed)="clearSearchResult.emit()"
+  ></ods-instant-search>
+</form>
diff --git a/alfa-client/libs/collaboration/src/lib/search-organisations-einheit-container/search-organisations-einheit-form/search-organisations-einheit-form.component.spec.ts b/alfa-client/libs/collaboration/src/lib/search-organisations-einheit-container/search-organisations-einheit-form/search-organisations-einheit-form.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e93e7403bfa65080636bf44355f942ab224f063f
--- /dev/null
+++ b/alfa-client/libs/collaboration/src/lib/search-organisations-einheit-container/search-organisations-einheit-form/search-organisations-einheit-form.component.spec.ts
@@ -0,0 +1,183 @@
+import { OrganisationsEinheitResource } from '@alfa-client/collaboration-shared';
+import { EventData, Mock, getMockComponent, mock, triggerEvent } from '@alfa-client/test-utils';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ReactiveFormsModule } from '@angular/forms';
+import faker from '@faker-js/faker';
+import { InstantSearchComponent } from '@ods/system';
+import { createOrganisationsEinheitResource } from 'libs/collaboration-shared/test/organisations-einheit';
+import { InstantSearchResult } from 'libs/design-system/src/lib/instant-search/instant-search/instant-search.model';
+import { createInstantSearchResult } from 'libs/design-system/src/test/search';
+import { getDataTestIdOf } from 'libs/tech-shared/test/data-test';
+import { MockComponent } from 'ng-mocks';
+import { SearchOrganisationsEinheitFormService } from '../search-organisations-einheit.formservice';
+import { SearchOrganisationsEinheitFormComponent } from './search-organisations-einheit-form.component';
+
+describe('SearchOrganisationsEinheitFormComponent', () => {
+  let component: SearchOrganisationsEinheitFormComponent;
+  let fixture: ComponentFixture<SearchOrganisationsEinheitFormComponent>;
+
+  const searchComp: string = getDataTestIdOf('search');
+
+  const formService: Mock<SearchOrganisationsEinheitFormService> = mock(
+    SearchOrganisationsEinheitFormService,
+  );
+
+  const instantSearchResult: InstantSearchResult<OrganisationsEinheitResource> =
+    createInstantSearchResult<OrganisationsEinheitResource>();
+  const organisationsEinheitResource: OrganisationsEinheitResource =
+    createOrganisationsEinheitResource();
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: [ReactiveFormsModule],
+      declarations: [
+        SearchOrganisationsEinheitFormComponent,
+        MockComponent(InstantSearchComponent),
+      ],
+      providers: [
+        {
+          provide: SearchOrganisationsEinheitFormService,
+          useValue: formService,
+        },
+      ],
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(SearchOrganisationsEinheitFormComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+
+  describe('set organisationsEinheiten', () => {
+    it('should map organisationsEinheitResources', () => {
+      component.mapOrganisationsEinheitResources = jest.fn();
+
+      component.organisationsEinheiten = [organisationsEinheitResource];
+
+      expect(component.mapOrganisationsEinheitResources).toHaveBeenCalledWith([
+        organisationsEinheitResource,
+      ]);
+    });
+  });
+
+  describe('map organisationsEinheit Resources', () => {
+    it('should call mapToInstantSearchResult', () => {
+      component.mapToInstantantSearchResult = jest.fn();
+
+      component.mapOrganisationsEinheitResources([organisationsEinheitResource]);
+
+      expect(component.mapToInstantantSearchResult).toHaveBeenCalledWith(
+        organisationsEinheitResource,
+      );
+    });
+
+    it('should set searchResults', () => {
+      component.mapToInstantantSearchResult = jest.fn().mockReturnValue(instantSearchResult);
+
+      component.mapOrganisationsEinheitResources([organisationsEinheitResource]);
+
+      expect(component.searchResults).toEqual([instantSearchResult]);
+    });
+  });
+
+  describe('map to instand search result', () => {
+    it('should map titel', () => {
+      const instantSearchResult: InstantSearchResult<OrganisationsEinheitResource> =
+        component.mapToInstantantSearchResult(organisationsEinheitResource);
+
+      expect(instantSearchResult.title).toBe(organisationsEinheitResource.name);
+    });
+    it('should map description', () => {
+      const instantSearchResult: InstantSearchResult<OrganisationsEinheitResource> =
+        component.mapToInstantantSearchResult(organisationsEinheitResource);
+
+      const expectedDescription: string = `${organisationsEinheitResource.anschrift.strasse} ${organisationsEinheitResource.anschrift.plz} ${organisationsEinheitResource.anschrift.ort}`;
+      expect(instantSearchResult.description).toBe(expectedDescription);
+    });
+
+    it('should map data', () => {
+      const instantSearchResult: InstantSearchResult<OrganisationsEinheitResource> =
+        component.mapToInstantantSearchResult(organisationsEinheitResource);
+
+      expect(instantSearchResult.data).toBe(organisationsEinheitResource);
+    });
+  });
+
+  describe('instant search component', () => {
+    it('should be called with search results', () => {
+      component.searchResults = [instantSearchResult];
+
+      fixture.detectChanges();
+
+      expect(getInstantSearchComponent().searchResults).toEqual([instantSearchResult]);
+    });
+
+    function getInstantSearchComponent(): InstantSearchComponent {
+      return getMockComponent<InstantSearchComponent>(fixture, InstantSearchComponent);
+    }
+
+    it('should emit selected search result on searchResultSelected output', () => {
+      const selectSearchResultSpy: jest.SpyInstance = (component.selectSearchResult.emit =
+        jest.fn());
+      const eventData: EventData<SearchOrganisationsEinheitFormComponent> = {
+        fixture,
+        elementSelector: searchComp,
+        name: 'searchResultSelected',
+        data: { data: organisationsEinheitResource },
+      };
+
+      triggerEvent(eventData);
+
+      expect(selectSearchResultSpy).toHaveBeenCalledWith(organisationsEinheitResource);
+    });
+
+    it('should emit search on searchQueryChanged output', () => {
+      const searchSpy: jest.SpyInstance = (component.search.emit = jest.fn());
+      const searchBy: string = faker.random.word();
+      const eventData: EventData<SearchOrganisationsEinheitFormComponent> = {
+        fixture,
+        elementSelector: searchComp,
+        name: 'searchQueryChanged',
+        data: { searchBy },
+      };
+
+      triggerEvent(eventData);
+
+      expect(searchSpy).toHaveBeenCalledWith(searchBy);
+    });
+
+    describe('should emit clear search result', () => {
+      let clearSearchResultSpy: jest.SpyInstance;
+      let eventData: EventData<SearchOrganisationsEinheitFormComponent>;
+
+      beforeEach(() => {
+        clearSearchResultSpy = component.clearSearchResult.emit = jest.fn();
+        eventData = {
+          fixture,
+          elementSelector: searchComp,
+          name: 'TBD',
+          data: { searchBy: faker.random.word() },
+        };
+      });
+
+      it('on searchResultClosed output', () => {
+        eventData = { ...eventData, name: 'searchResultClosed' };
+
+        triggerEvent(eventData);
+
+        expect(clearSearchResultSpy).toHaveBeenCalledWith();
+      });
+
+      it('on searchQueryCleared output', () => {
+        eventData = { ...eventData, name: 'searchResultClosed' };
+
+        triggerEvent(eventData);
+
+        expect(clearSearchResultSpy).toHaveBeenCalled();
+      });
+    });
+  });
+});
diff --git a/alfa-client/libs/collaboration/src/lib/search-organisations-einheit-container/search-organisations-einheit-form/search-organisations-einheit-form.component.ts b/alfa-client/libs/collaboration/src/lib/search-organisations-einheit-container/search-organisations-einheit-form/search-organisations-einheit-form.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2e49ca660d004820de961dd252ef7ed156040a1a
--- /dev/null
+++ b/alfa-client/libs/collaboration/src/lib/search-organisations-einheit-container/search-organisations-einheit-form/search-organisations-einheit-form.component.ts
@@ -0,0 +1,41 @@
+import { OrganisationsEinheitResource } from '@alfa-client/collaboration-shared';
+import { Component, EventEmitter, Input, Output } from '@angular/core';
+import { InstantSearchResult } from '@ods/system';
+import { SearchOrganisationsEinheitFormService } from '../search-organisations-einheit.formservice';
+
+@Component({
+  selector: 'alfa-search-organisations-einheit-form',
+  templateUrl: './search-organisations-einheit-form.component.html',
+  providers: [SearchOrganisationsEinheitFormService],
+})
+export class SearchOrganisationsEinheitFormComponent {
+  @Input() set organisationsEinheiten(organisationsEinheiten: OrganisationsEinheitResource[]) {
+    this.mapOrganisationsEinheitResources(organisationsEinheiten);
+  }
+
+  @Output() public search: EventEmitter<string> = new EventEmitter();
+  @Output() public selectSearchResult: EventEmitter<OrganisationsEinheitResource> =
+    new EventEmitter();
+  @Output() public clearSearchResult: EventEmitter<string> = new EventEmitter();
+
+  public searchResults: InstantSearchResult<OrganisationsEinheitResource>[];
+
+  constructor(public formService: SearchOrganisationsEinheitFormService) {}
+
+  mapOrganisationsEinheitResources(organisationsEinheiten: OrganisationsEinheitResource[]): void {
+    this.searchResults = organisationsEinheiten.map(
+      (organisationsEinheiten: OrganisationsEinheitResource) =>
+        this.mapToInstantantSearchResult(organisationsEinheiten),
+    );
+  }
+
+  mapToInstantantSearchResult(
+    organisationsEinheit: OrganisationsEinheitResource,
+  ): InstantSearchResult<OrganisationsEinheitResource> {
+    return <any>{
+      title: organisationsEinheit.name,
+      description: `${organisationsEinheit.anschrift.strasse} ${organisationsEinheit.anschrift.plz} ${organisationsEinheit.anschrift.ort}`,
+      data: organisationsEinheit,
+    };
+  }
+}
diff --git a/alfa-client/libs/collaboration/src/lib/search-organisations-einheit-container/search-organisations-einheit.formservice.ts b/alfa-client/libs/collaboration/src/lib/search-organisations-einheit-container/search-organisations-einheit.formservice.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2b63e2097a660615148dce5468d7b017976b64ef
--- /dev/null
+++ b/alfa-client/libs/collaboration/src/lib/search-organisations-einheit-container/search-organisations-einheit.formservice.ts
@@ -0,0 +1,20 @@
+import { Injectable } from '@angular/core';
+import { FormBuilder, FormControl, FormGroup } from '@angular/forms';
+import { ResourceUri } from '@ngxp/rest';
+
+@Injectable()
+export class SearchOrganisationsEinheitFormService {
+  public form: FormGroup;
+
+  public readonly SEARCH_FIELD: string = 'search';
+
+  constructor(private formBuilder: FormBuilder) {
+    this.initForm();
+  }
+
+  private initForm(): void {
+    this.form = this.formBuilder.group({
+      [this.SEARCH_FIELD]: new FormControl<ResourceUri>(null),
+    });
+  }
+}
diff --git a/alfa-client/libs/collaboration/src/test-setup.ts b/alfa-client/libs/collaboration/src/test-setup.ts
new file mode 100644
index 0000000000000000000000000000000000000000..6b07c0bac34c40aa6afeef02c18c8db08f79de48
--- /dev/null
+++ b/alfa-client/libs/collaboration/src/test-setup.ts
@@ -0,0 +1,15 @@
+import '@testing-library/jest-dom';
+import 'jest-preset-angular/setup-jest';
+
+import { getTestBed } from '@angular/core/testing';
+import {
+  BrowserDynamicTestingModule,
+  platformBrowserDynamicTesting,
+} from '@angular/platform-browser-dynamic/testing';
+
+getTestBed().resetTestEnvironment();
+getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting(), {
+  teardown: { destroyAfterEach: false },
+  errorOnUnknownProperties: true,
+  errorOnUnknownElements: true,
+});
diff --git a/alfa-client/libs/collaboration/tsconfig.json b/alfa-client/libs/collaboration/tsconfig.json
new file mode 100644
index 0000000000000000000000000000000000000000..7cc6baf2f58ed5ccfba098131996f579979e9f18
--- /dev/null
+++ b/alfa-client/libs/collaboration/tsconfig.json
@@ -0,0 +1,16 @@
+{
+  "extends": "../../tsconfig.base.json",
+  "files": [],
+  "include": [],
+  "references": [
+    {
+      "path": "./tsconfig.lib.json"
+    },
+    {
+      "path": "./tsconfig.spec.json"
+    }
+  ],
+  "compilerOptions": {
+    "target": "es2022"
+  }
+}
diff --git a/alfa-client/libs/collaboration/tsconfig.lib.json b/alfa-client/libs/collaboration/tsconfig.lib.json
new file mode 100644
index 0000000000000000000000000000000000000000..4cab05d46338c6e9d4dfe6512fd7eb7f60340d3d
--- /dev/null
+++ b/alfa-client/libs/collaboration/tsconfig.lib.json
@@ -0,0 +1,12 @@
+{
+  "extends": "./tsconfig.json",
+  "compilerOptions": {
+    "outDir": "../../dist/out-tsc",
+    "declaration": true,
+    "declarationMap": true,
+    "inlineSources": true,
+    "types": []
+  },
+  "exclude": ["src/**/*.spec.ts", "src/test-setup.ts", "jest.config.ts", "src/**/*.test.ts"],
+  "include": ["src/**/*.ts"]
+}
diff --git a/alfa-client/libs/collaboration/tsconfig.spec.json b/alfa-client/libs/collaboration/tsconfig.spec.json
new file mode 100644
index 0000000000000000000000000000000000000000..7870b7c011681fb77d6114001f44d3eeca69975b
--- /dev/null
+++ b/alfa-client/libs/collaboration/tsconfig.spec.json
@@ -0,0 +1,11 @@
+{
+  "extends": "./tsconfig.json",
+  "compilerOptions": {
+    "outDir": "../../dist/out-tsc",
+    "module": "commonjs",
+    "target": "es2016",
+    "types": ["jest", "node"]
+  },
+  "files": ["src/test-setup.ts"],
+  "include": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts", "src/**/*.d.ts"]
+}
diff --git a/alfa-client/libs/command-shared/src/lib/command.model.ts b/alfa-client/libs/command-shared/src/lib/command.model.ts
index 947b7251c473ceec77e0438c299eca6c799a0752..2803459c58ea9b583b8ffa79355811c592c2747d 100644
--- a/alfa-client/libs/command-shared/src/lib/command.model.ts
+++ b/alfa-client/libs/command-shared/src/lib/command.model.ts
@@ -86,6 +86,7 @@ export enum CommandOrder {
   CREATE_BESCHEID_DOCUMENT_FROM_FILE = 'CREATE_BESCHEID_DOCUMENT_FROM_FILE',
   CREATE_BESCHEID_DOCUMENT = 'CREATE_BESCHEID_DOCUMENT',
   SEND_BESCHEID = 'SEND_BESCHEID',
+  CREATE_COLLABORATION_REQUEST = 'CREATE_COLLABORATION_REQUEST',
 }
 
 export interface CreateCommandProps {
diff --git a/alfa-client/libs/design-component/src/lib/form/formcontrol-editor.abstract.component.ts b/alfa-client/libs/design-component/src/lib/form/formcontrol-editor.abstract.component.ts
index a023a009d1780be33395159d25234da39285f745..cb0f3f5842b32a3ce76321d194097c9a2f64229a 100644
--- a/alfa-client/libs/design-component/src/lib/form/formcontrol-editor.abstract.component.ts
+++ b/alfa-client/libs/design-component/src/lib/form/formcontrol-editor.abstract.component.ts
@@ -21,7 +21,7 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-import { Issue } from '@alfa-client/tech-shared';
+import { InvalidParam } from '@alfa-client/tech-shared';
 import { Component, OnDestroy, OnInit, Optional, Self } from '@angular/core';
 import { ControlValueAccessor, NgControl, UntypedFormControl } from '@angular/forms';
 import { isEmpty } from 'lodash-es';
@@ -89,9 +89,11 @@ export abstract class FormControlEditorAbstractComponent
     }
   }
 
-  get issues(): Issue[] {
+  get invalidParams(): InvalidParam[] {
     return this.fieldControl.errors ?
-        Object.keys(this.fieldControl.errors).map((key) => <Issue>this.fieldControl.errors[key])
+        Object.keys(this.fieldControl.errors).map(
+          (key) => <InvalidParam>this.fieldControl.errors[key],
+        )
       : [];
   }
 }
diff --git a/alfa-client/libs/design-component/src/lib/form/text-editor/text-editor.component.html b/alfa-client/libs/design-component/src/lib/form/text-editor/text-editor.component.html
index 544b9312b03adba3e0e097e8eba8a20751e5b013..9252326a5bdcc9d9c25ec164981bd0e24915bafa 100644
--- a/alfa-client/libs/design-component/src/lib/form/text-editor/text-editor.component.html
+++ b/alfa-client/libs/design-component/src/lib/form/text-editor/text-editor.component.html
@@ -10,7 +10,7 @@
 >
   <ods-validation-error
     error
-    [issues]="issues"
+    [invalidParams]="invalidParams"
     [label]="label"
     [attr.data-test-id]="(label | convertForDataTest) + '-text-editor-error'"
   ></ods-validation-error>
diff --git a/alfa-client/libs/design-component/src/lib/form/text-editor/text-editor.component.ts b/alfa-client/libs/design-component/src/lib/form/text-editor/text-editor.component.ts
index c78a7554800ed6f61eb9d189617811e7f9d0490a..c40849cf31e2279a3727527898213567bab07c4c 100644
--- a/alfa-client/libs/design-component/src/lib/form/text-editor/text-editor.component.ts
+++ b/alfa-client/libs/design-component/src/lib/form/text-editor/text-editor.component.ts
@@ -26,6 +26,6 @@ export class TextEditorComponent extends FormControlEditorAbstractComponent {
   @Input() focus: boolean = false;
 
   get variant(): string {
-    return this.issues.length > 0 ? 'error' : 'default';
+    return this.invalidParams.length > 0 ? 'error' : 'default';
   }
 }
diff --git a/alfa-client/libs/design-component/src/lib/form/textarea-editor/textarea-editor.component.html b/alfa-client/libs/design-component/src/lib/form/textarea-editor/textarea-editor.component.html
index 5f3959bd34260ac44c11db6a108f24583986b9b0..c27f425a3f9ca703f85b9961a8c87175a50a0a9f 100644
--- a/alfa-client/libs/design-component/src/lib/form/textarea-editor/textarea-editor.component.html
+++ b/alfa-client/libs/design-component/src/lib/form/textarea-editor/textarea-editor.component.html
@@ -10,7 +10,7 @@
 >
   <ods-validation-error
     error
-    [issues]="issues"
+    [invalidParams]="invalidParams"
     [label]="label"
     [attr.data-test-id]="(label | convertForDataTest) + '-textarea-editor-error'"
   ></ods-validation-error>
diff --git a/alfa-client/libs/design-component/src/lib/form/textarea-editor/textarea-editor.component.ts b/alfa-client/libs/design-component/src/lib/form/textarea-editor/textarea-editor.component.ts
index f78ee2c938fdb89b91a17060ba862ecadcff04aa..a47b955192b12c4a9ce1379062cd16543e455e2a 100644
--- a/alfa-client/libs/design-component/src/lib/form/textarea-editor/textarea-editor.component.ts
+++ b/alfa-client/libs/design-component/src/lib/form/textarea-editor/textarea-editor.component.ts
@@ -26,6 +26,6 @@ export class TextareaEditorComponent extends FormControlEditorAbstractComponent
   @Input() focus: boolean = false;
 
   get variant(): string {
-    return this.issues.length > 0 ? 'error' : 'default';
+    return this.invalidParams.length > 0 ? 'error' : 'default';
   }
 }
diff --git a/alfa-client/libs/design-component/src/lib/form/validation-error/validation-error.component.html b/alfa-client/libs/design-component/src/lib/form/validation-error/validation-error.component.html
index 703f757c2b17228e8cdfb7d158a7bb7e6a058a93..28ffaaac9b7880787146c5091eceedee3d2a662e 100644
--- a/alfa-client/libs/design-component/src/lib/form/validation-error/validation-error.component.html
+++ b/alfa-client/libs/design-component/src/lib/form/validation-error/validation-error.component.html
@@ -1,3 +1,3 @@
-<ng-container *ngFor="let issue of issues"
-  ><ods-error-message [text]="message(issue)"></ods-error-message
+<ng-container *ngFor="let invalidParam of invalidParams"
+  ><ods-error-message [text]="message(invalidParam)"></ods-error-message
 ></ng-container>
diff --git a/alfa-client/libs/design-component/src/lib/form/validation-error/validation-error.component.spec.ts b/alfa-client/libs/design-component/src/lib/form/validation-error/validation-error.component.spec.ts
index 6abe6133bddfc36ca6ca42e2aa28d049fa96ef4d..845bf47eb456d09d581f97fae71493c8808729ac 100644
--- a/alfa-client/libs/design-component/src/lib/form/validation-error/validation-error.component.spec.ts
+++ b/alfa-client/libs/design-component/src/lib/form/validation-error/validation-error.component.spec.ts
@@ -1,6 +1,7 @@
-import { getMessageForIssue } from '@alfa-client/tech-shared';
+import { getMessageForInvalidParam, InvalidParam } from '@alfa-client/tech-shared';
 import { ComponentFixture, TestBed } from '@angular/core/testing';
-import { createIssue } from 'libs/tech-shared/test/error';
+import { ValidationMessageCode } from 'libs/tech-shared/src/lib/validation/tech.validation.messages';
+import { createInvalidParam } from 'libs/tech-shared/test/error';
 import { ValidationErrorComponent } from './validation-error.component';
 
 describe('ValidationErrorComponent', () => {
@@ -21,32 +22,29 @@ describe('ValidationErrorComponent', () => {
     expect(component).toBeTruthy();
   });
 
-  describe('get message for issue', () => {
+  describe('get message from invalidParam', () => {
     const fieldLabel: string = 'Field Label';
+    const invalidParam: InvalidParam = {
+      ...createInvalidParam(),
+      reason: ValidationMessageCode.FIELD_SIZE,
+    };
 
-    it('should return message', () => {
-      const msg: string = getMessageForIssue(fieldLabel, {
-        ...createIssue(),
-        messageCode: 'validation_field_size',
-      });
+    it('should contain', () => {
+      const msg: string = getMessageForInvalidParam(fieldLabel, invalidParam);
 
       expect(msg).toContain('muss mindestens');
     });
 
     it('should set field label', () => {
-      const msg: string = getMessageForIssue(fieldLabel, {
-        ...createIssue(),
-        messageCode: 'validation_field_size',
-      });
+      const msg: string = getMessageForInvalidParam(fieldLabel, invalidParam);
 
       expect(msg).toContain(fieldLabel);
     });
 
     it('should replace min param', () => {
-      const msg: string = getMessageForIssue(fieldLabel, {
-        ...createIssue(),
-        messageCode: 'validation_field_size',
-        parameters: [{ name: 'min', value: '3' }],
+      const msg: string = getMessageForInvalidParam(fieldLabel, {
+        ...invalidParam,
+        constraintParameters: [{ name: 'min', value: '3' }],
       });
 
       expect(msg).toContain('3');
diff --git a/alfa-client/libs/design-component/src/lib/form/validation-error/validation-error.component.ts b/alfa-client/libs/design-component/src/lib/form/validation-error/validation-error.component.ts
index d47b675b4984616c8ff76acaa04d3c73ebafad42..4d8a67a6e5f9ee9d39a99c9fe5fd97fe6136fe2c 100644
--- a/alfa-client/libs/design-component/src/lib/form/validation-error/validation-error.component.ts
+++ b/alfa-client/libs/design-component/src/lib/form/validation-error/validation-error.component.ts
@@ -1,4 +1,4 @@
-import { Issue, getMessageForIssue } from '@alfa-client/tech-shared';
+import { InvalidParam, getMessageForInvalidParam } from '@alfa-client/tech-shared';
 import { CommonModule } from '@angular/common';
 import { Component, Input } from '@angular/core';
 import { ErrorMessageComponent } from '@ods/system';
@@ -11,9 +11,9 @@ import { ErrorMessageComponent } from '@ods/system';
 })
 export class ValidationErrorComponent {
   @Input() label: string;
-  @Input() issues: Issue[];
+  @Input() invalidParams: InvalidParam[];
 
-  public message(issue: Issue): string {
-    return getMessageForIssue(this.label, issue);
+  public message(invalidParam: InvalidParam): string {
+    return getMessageForInvalidParam(this.label, invalidParam);
   }
 }
diff --git a/alfa-client/libs/design-system/src/index.ts b/alfa-client/libs/design-system/src/index.ts
index 57c220dc85cf06f66d1e23edd66bc7d9bff947ea..16c66be88076bf07e9c5bf7ec2b4052fa5a20d89 100644
--- a/alfa-client/libs/design-system/src/index.ts
+++ b/alfa-client/libs/design-system/src/index.ts
@@ -14,11 +14,18 @@ export * from './lib/icons/attachment-icon/attachment-icon.component';
 export * from './lib/icons/bescheid-generate-icon/bescheid-generate-icon.component';
 export * from './lib/icons/bescheid-upload-icon/bescheid-upload-icon.component';
 export * from './lib/icons/close-icon/close-icon.component';
+export * from './lib/icons/collaboration-icon/collaboration-icon.component';
 export * from './lib/icons/exclamation-icon/exclamation-icon.component';
 export * from './lib/icons/file-icon/file-icon.component';
 export * from './lib/icons/iconVariants';
+export * from './lib/icons/office-icon/office-icon.component';
 export * from './lib/icons/save-icon/save-icon.component';
+export * from './lib/icons/search-icon/search-icon.component';
 export * from './lib/icons/send-icon/send-icon.component';
 export * from './lib/icons/spinner-icon/spinner-icon.component';
 export * from './lib/icons/stamp-icon/stamp-icon.component';
+export * from './lib/instant-search/instant-search/instant-search.component';
+export * from './lib/instant-search/instant-search/instant-search.model';
+export * from './lib/popup/popup-list-item/popup-list-item.component';
+export * from './lib/popup/popup/popup.component';
 export * from './lib/testbtn/testbtn.component';
diff --git a/alfa-client/libs/design-system/src/lib/aria-live-region/aria-live-region.component.spec.ts b/alfa-client/libs/design-system/src/lib/aria-live-region/aria-live-region.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c0848c08f798f58fd91f850597ce0d15f267e065
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/aria-live-region/aria-live-region.component.spec.ts
@@ -0,0 +1,21 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { AriaLiveRegionComponent } from './aria-live-region.component';
+
+describe('AriaLiveRegionComponent', () => {
+  let component: AriaLiveRegionComponent;
+  let fixture: ComponentFixture<AriaLiveRegionComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: [AriaLiveRegionComponent],
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(AriaLiveRegionComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/alfa-client/libs/design-system/src/lib/aria-live-region/aria-live-region.component.ts b/alfa-client/libs/design-system/src/lib/aria-live-region/aria-live-region.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..3cec9afff4c23502077704daea8b04f125158bdd
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/aria-live-region/aria-live-region.component.ts
@@ -0,0 +1,12 @@
+import { CommonModule } from '@angular/common';
+import { Component, Input } from '@angular/core';
+
+@Component({
+  selector: 'ods-aria-live-region',
+  standalone: true,
+  imports: [CommonModule],
+  template: `<span aria-live="polite" class="sr-only" role="status">{{ text }}</span>`,
+})
+export class AriaLiveRegionComponent {
+  @Input() text: string = '';
+}
diff --git a/alfa-client/libs/design-system/src/lib/aria-live-region/aria-live-region.stories.ts b/alfa-client/libs/design-system/src/lib/aria-live-region/aria-live-region.stories.ts
new file mode 100644
index 0000000000000000000000000000000000000000..7af950ebf415e5e2a634be01a2edaa32a9d78a01
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/aria-live-region/aria-live-region.stories.ts
@@ -0,0 +1,25 @@
+import { argsToTemplate, type Meta, type StoryObj } from '@storybook/angular';
+import { AriaLiveRegionComponent } from './aria-live-region.component';
+
+const meta: Meta<AriaLiveRegionComponent> = {
+  title: 'Aria live region',
+  component: AriaLiveRegionComponent,
+  excludeStories: /.*Data$/,
+  tags: ['autodocs'],
+};
+
+export default meta;
+type Story = StoryObj<AriaLiveRegionComponent>;
+
+export const Default: Story = {
+  args: {
+    text: '',
+  },
+  render: (args) => ({
+    props: args,
+    template: `
+      <h2>This component is suitable for screen reader. Fill text field to make screen reader read it aloud.</h2>
+      <ods-aria-live-region ${argsToTemplate(args)} />
+    `,
+  }),
+};
diff --git a/alfa-client/libs/design-system/src/lib/attachment-header/attachment-header.component.spec.ts b/alfa-client/libs/design-system/src/lib/attachment-header/attachment-header.component.spec.ts
index b1484d6418804db087a5418a8eb26a8e41114398..deccecf135ec6549e66369281d7ca0338a76b2e1 100644
--- a/alfa-client/libs/design-system/src/lib/attachment-header/attachment-header.component.spec.ts
+++ b/alfa-client/libs/design-system/src/lib/attachment-header/attachment-header.component.spec.ts
@@ -1,3 +1,4 @@
+import { existsAsHtmlElement, notExistsAsHtmlElement } from '@alfa-client/test-utils';
 import { ComponentFixture, TestBed } from '@angular/core/testing';
 import { AttachmentHeaderComponent } from './attachment-header.component';
 
@@ -18,4 +19,19 @@ describe('AttachmentHeaderComponent', () => {
   it('should create', () => {
     expect(component).toBeTruthy();
   });
+  describe('title', () => {
+    it('should show heading', () => {
+      component.title = 'Test';
+      fixture.detectChanges();
+
+      existsAsHtmlElement(fixture, 'h4');
+    });
+
+    it('should not show heading', () => {
+      component.title = '';
+      fixture.detectChanges();
+
+      notExistsAsHtmlElement(fixture, 'h4');
+    });
+  });
 });
diff --git a/alfa-client/libs/design-system/src/lib/attachment-header/attachment-header.component.ts b/alfa-client/libs/design-system/src/lib/attachment-header/attachment-header.component.ts
index dadeccb218137f87612c2d67a12c7087a6286927..6dd5bdaa1839e7782d20867a60327d9ab32cded6 100644
--- a/alfa-client/libs/design-system/src/lib/attachment-header/attachment-header.component.ts
+++ b/alfa-client/libs/design-system/src/lib/attachment-header/attachment-header.component.ts
@@ -5,8 +5,8 @@ import { Component, Input } from '@angular/core';
   selector: 'ods-attachment-header',
   standalone: true,
   imports: [CommonModule],
-  template: `<div class="flex h-11 items-center justify-between px-3">
-    <h4 class="text-sm font-medium text-text">{{ title }}</h4>
+  template: `<div class="flex h-11 items-center justify-between px-3 empty:hidden">
+    <h4 class="text-sm font-medium text-text" *ngIf="title">{{ title }}</h4>
     <ng-content select="[action-buttons]"></ng-content>
   </div>`,
 })
diff --git a/alfa-client/libs/design-system/src/lib/attachment-wrapper/attachment-wrapper.stories.ts b/alfa-client/libs/design-system/src/lib/attachment-wrapper/attachment-wrapper.stories.ts
index 485acda2600b59166e331fe38bffba7392c1e783..7d8f0fbec59aeb00afc99d2377c1902abd20c73d 100644
--- a/alfa-client/libs/design-system/src/lib/attachment-wrapper/attachment-wrapper.stories.ts
+++ b/alfa-client/libs/design-system/src/lib/attachment-wrapper/attachment-wrapper.stories.ts
@@ -1,7 +1,8 @@
-import { argsToTemplate, moduleMetadata, type Meta, type StoryObj } from '@storybook/angular';
+import { moduleMetadata, type Meta, type StoryObj } from '@storybook/angular';
 
 import { DownloadButtonComponent } from '../../../../design-component/src/lib/download-button/download-button.component';
 
+import { AttachmentHeaderComponent } from '../attachment-header/attachment-header.component';
 import { AttachmentComponent } from '../attachment/attachment.component';
 import { AttachmentWrapperComponent } from './attachment-wrapper.component';
 
@@ -17,7 +18,12 @@ const meta: Meta<AttachmentWrapperComponent> = {
   },
   decorators: [
     moduleMetadata({
-      imports: [AttachmentWrapperComponent, AttachmentComponent, DownloadButtonComponent],
+      imports: [
+        AttachmentWrapperComponent,
+        AttachmentComponent,
+        DownloadButtonComponent,
+        AttachmentHeaderComponent,
+      ],
     }),
   ],
   excludeStories: /.*Data$/,
@@ -28,18 +34,11 @@ export default meta;
 type Story = StoryObj<AttachmentWrapperComponent>;
 
 export const Default: Story = {
-  args: {
-    title: 'Anhänge',
-  },
-  argTypes: {
-    title: {
-      description: 'Title for group of files',
-    },
-  },
-  render: (args) => ({
-    props: args,
-    template: `<ods-attachment-wrapper ${argsToTemplate(args)}>
-        <ods-download-button action-buttons />
+  render: () => ({
+    template: `<ods-attachment-wrapper>
+        <ods-attachment-header title="Anhänge">
+          <ods-download-button action-buttons />
+        </ods-attachment-header>
         <ods-attachment caption="Attachment" description="200 kB" fileType="pdf"></ods-attachment>
         <ods-attachment caption="Second attachment" description="432 kB" fileType="doc"></ods-attachment>
     </ods-attachment-wrapper>`,
diff --git a/alfa-client/libs/design-system/src/lib/bescheid-status-text/bescheid-status-text.component.ts b/alfa-client/libs/design-system/src/lib/bescheid-status-text/bescheid-status-text.component.ts
index 9ed55dd799191cfb77c2462d25a357425f60c2ab..586fcb8a140c698f4e90a5d8b0b53f0e97556ac8 100644
--- a/alfa-client/libs/design-system/src/lib/bescheid-status-text/bescheid-status-text.component.ts
+++ b/alfa-client/libs/design-system/src/lib/bescheid-status-text/bescheid-status-text.component.ts
@@ -13,7 +13,7 @@ import { StampIconComponent } from '../icons/stamp-icon/stamp-icon.component';
       ><ods-stamp-icon size="medium" class="fill-bewilligt" />Bewilligt am {{ dateText }}</span
     >
     <span class="flex items-center gap-2" *ngIf="!bewilligt"
-      ><ods-close-icon size="medium" class="fill-abgelehnt" />Abgelehnt am
+      ><ods-close-icon class="fill-abgelehnt" />Abgelehnt am
       {{ dateText }}
     </span>
     <span
diff --git a/alfa-client/libs/design-system/src/lib/button/button.component.ts b/alfa-client/libs/design-system/src/lib/button/button.component.ts
index 58ba7ec0d96c8c0eb0516c9fbc367b885d686837..277dbfbf830d140408f411526c2e84f33748e379 100644
--- a/alfa-client/libs/design-system/src/lib/button/button.component.ts
+++ b/alfa-client/libs/design-system/src/lib/button/button.component.ts
@@ -6,7 +6,10 @@ import { IconVariants } from '../icons/iconVariants';
 import { SpinnerIconComponent } from '../icons/spinner-icon/spinner-icon.component';
 
 export const buttonVariants = cva(
-  'flex cursor-pointer items-center gap-4 rounded-md font-medium disabled:cursor-wait text-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary',
+  [
+    'flex items-center gap-4 rounded-md disabled:cursor-wait text-sm font-medium box-border',
+    'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-focus',
+  ],
   {
     variants: {
       variant: {
diff --git a/alfa-client/libs/design-system/src/lib/form/radio-button-card/radio-button-card.stories.ts b/alfa-client/libs/design-system/src/lib/form/radio-button-card/radio-button-card.stories.ts
index 96ec7406916b5f4773f6aa448ad12112c913ebfc..dd949aeef16caab452a0ee6c8aee76bb0624cd79 100644
--- a/alfa-client/libs/design-system/src/lib/form/radio-button-card/radio-button-card.stories.ts
+++ b/alfa-client/libs/design-system/src/lib/form/radio-button-card/radio-button-card.stories.ts
@@ -53,7 +53,7 @@ export const Default: Story = {
       value="abgelehnt"
       variant="bescheid_abgelehnt"
     >
-      <ods-close-icon class="fill-abgelehnt" />
+      <ods-close-icon class="fill-abgelehnt" size="large" />
     </ods-radio-button-card>
   </div>`,
   }),
diff --git a/alfa-client/libs/design-system/src/lib/form/text-input/text-input.component.ts b/alfa-client/libs/design-system/src/lib/form/text-input/text-input.component.ts
index e136a50bb991af6df9384d7ceca287879b3cdcc8..a534a5276d34b072c1b8edee6e95e362a5296d77 100644
--- a/alfa-client/libs/design-system/src/lib/form/text-input/text-input.component.ts
+++ b/alfa-client/libs/design-system/src/lib/form/text-input/text-input.component.ts
@@ -1,12 +1,15 @@
-import { convertForDataTest, TechSharedModule } from '@alfa-client/tech-shared';
+import { convertForDataTest, EMPTY_STRING, TechSharedModule } from '@alfa-client/tech-shared';
 import { CommonModule } from '@angular/common';
-import { Component, ElementRef, Input, ViewChild } from '@angular/core';
+import { Component, ElementRef, EventEmitter, Input, Output, ViewChild } from '@angular/core';
 import { FormControl, ReactiveFormsModule } from '@angular/forms';
 import { cva, VariantProps } from 'class-variance-authority';
 import { ErrorMessageComponent } from '../error-message/error-message.component';
 
 const textInputVariants = cva(
-  'block w-full rounded-lg border bg-background-50 px-3 py-2 text-base leading-5 text-text focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2',
+  [
+    'w-full box-border rounded-lg border bg-background-50 px-3 py-2 text-base text-text leading-5',
+    'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2',
+  ],
   {
     variants: {
       variant: {
@@ -28,23 +31,40 @@ type TextInputVariants = VariantProps<typeof textInputVariants>;
   standalone: true,
   imports: [CommonModule, ErrorMessageComponent, ReactiveFormsModule, TechSharedModule],
   template: `
-    <div>
-      <label [for]="id" class="text-md mb-2 block font-medium text-text">
+    <div class="relative">
+      <label *ngIf="showLabel" [for]="id" class="text-md mb-2 block font-medium text-text">
         {{ inputLabel }}<ng-container *ngIf="required"><i aria-hidden="true">*</i></ng-container>
       </label>
       <div class="mt-2">
+        <div
+          *ngIf="withPrefix"
+          class="pointer-events-none absolute bottom-2 left-2 flex size-6 items-center justify-center"
+        >
+          <ng-content select="[prefix]" />
+        </div>
         <input
           type="text"
           [id]="id"
           [formControl]="fieldControl"
-          [ngClass]="textInputVariants({ variant })"
+          [ngClass]="[
+            textInputVariants({ variant }),
+            withPrefix ? 'pl-10' : '',
+            withSuffix ? 'pr-10' : '',
+          ]"
           [placeholder]="placeholder"
           [autocomplete]="autocomplete"
           [attr.aria-required]="required"
           [attr.aria-invalid]="variant === 'error'"
           [attr.data-test-id]="(inputLabel | convertForDataTest) + '-text-input'"
+          (click)="clickEmitter.emit()"
           #inputElement
         />
+        <div
+          *ngIf="withSuffix"
+          class="absolute bottom-2 right-2 flex size-6 items-center justify-center"
+        >
+          <ng-content select="[suffix]" />
+        </div>
       </div>
       <ng-content select="[error]"></ng-content>
     </div>
@@ -60,8 +80,11 @@ export class TextInputComponent {
   @Input() placeholder: string = '';
   @Input() autocomplete: string = 'off';
   @Input() variant: TextInputVariants['variant'];
-  @Input() fieldControl: FormControl;
+  @Input() fieldControl: FormControl = new FormControl(EMPTY_STRING);
   @Input() required: boolean = false;
+  @Input() withPrefix: boolean = false;
+  @Input() withSuffix: boolean = false;
+  @Input() showLabel: boolean = true;
 
   @Input() set focus(value: boolean) {
     if (value && this.inputElement) {
@@ -69,6 +92,8 @@ export class TextInputComponent {
     }
   }
 
+  @Output() clickEmitter: EventEmitter<MouseEvent> = new EventEmitter<MouseEvent>();
+
   inputLabel: string;
   id: string;
   textInputVariants = textInputVariants;
diff --git a/alfa-client/libs/design-system/src/lib/form/textarea/textarea.component.ts b/alfa-client/libs/design-system/src/lib/form/textarea/textarea.component.ts
index 90a4fa85f7dcb0b5a55f6a926a0d08ab63e332a9..2c4340b9f30232e900ef8a4ac8c845adf4765d41 100644
--- a/alfa-client/libs/design-system/src/lib/form/textarea/textarea.component.ts
+++ b/alfa-client/libs/design-system/src/lib/form/textarea/textarea.component.ts
@@ -1,11 +1,14 @@
-import { TechSharedModule, convertForDataTest } from '@alfa-client/tech-shared';
+import { EMPTY_STRING, TechSharedModule, convertForDataTest } from '@alfa-client/tech-shared';
 import { CommonModule } from '@angular/common';
 import { Component, ElementRef, Input, ViewChild } from '@angular/core';
 import { FormControl, ReactiveFormsModule } from '@angular/forms';
 import { VariantProps, cva } from 'class-variance-authority';
 
 const textareaVariants = cva(
-  'block w-full rounded-lg border bg-background-50 px-3 py-2 text-base text-text leading-5 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2',
+  [
+    'w-full box-border rounded-lg border bg-background-50 px-3 py-2 text-base text-text leading-5',
+    'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2',
+  ],
   {
     variants: {
       variant: {
@@ -59,7 +62,7 @@ export class TextareaComponent {
   @Input() rows: number = 3;
   @Input() autocomplete: string = 'off';
   @Input() variant: TextareaVariants['variant'];
-  @Input() fieldControl: FormControl;
+  @Input() fieldControl: FormControl = new FormControl(EMPTY_STRING);
   @Input() required: boolean = false;
 
   @Input() set focus(value: boolean) {
diff --git a/alfa-client/libs/design-system/src/lib/icons/close-icon/close-icon.component.ts b/alfa-client/libs/design-system/src/lib/icons/close-icon/close-icon.component.ts
index 5de688d73e98d67b1296d1519332fd7e3b7c9660..48fe0de3b897881d8bb669774572ea8f68a6895e 100644
--- a/alfa-client/libs/design-system/src/lib/icons/close-icon/close-icon.component.ts
+++ b/alfa-client/libs/design-system/src/lib/icons/close-icon/close-icon.component.ts
@@ -12,16 +12,16 @@ import { IconVariants, iconVariants } from '../iconVariants';
     xmlns="http://www.w3.org/2000/svg"
     [ngClass]="[twMerge(iconVariants({ size }), 'fill-black', class)]"
     aria-hidden="true"
-    viewBox="0 0 14 14"
+    viewBox="0 0 24 24"
     fill="inherit"
   >
     <path
-      d="M14 1.41L12.59 0L7 5.59L1.41 0L0 1.41L5.59 7L0 12.59L1.41 14L7 8.41L12.59 14L14 12.59L8.41 7L14 1.41Z"
+      d="M19 6.41L17.59 5L12 10.59L6.41 5L5 6.41L10.59 12L5 17.59L6.41 19L12 13.41L17.59 19L19 17.59L13.41 12L19 6.41Z"
     />
   </svg>`,
 })
 export class CloseIconComponent {
-  @Input() size: IconVariants['size'] = 'small';
+  @Input() size: IconVariants['size'] = 'medium';
   @Input() class: string = undefined;
 
   iconVariants = iconVariants;
diff --git a/alfa-client/libs/design-system/src/lib/icons/close-icon/close-icon.stories.ts b/alfa-client/libs/design-system/src/lib/icons/close-icon/close-icon.stories.ts
index b8a8eda0b8afab576ba5b7086d226aa2f0adcc96..9cd750050413bd481bcdc246810c8eeb24b53c8c 100644
--- a/alfa-client/libs/design-system/src/lib/icons/close-icon/close-icon.stories.ts
+++ b/alfa-client/libs/design-system/src/lib/icons/close-icon/close-icon.stories.ts
@@ -20,7 +20,7 @@ export const Default: Story = {
       options: ['small', 'medium', 'large', 'extra-large', 'full'],
       description: 'Size of icon. Property "full" means 100%',
       table: {
-        defaultValue: { summary: 'small' },
+        defaultValue: { summary: 'medium' },
       },
     },
   },
diff --git a/alfa-client/libs/design-system/src/lib/icons/collaboration-icon/collaboration-icon.component.spec.ts b/alfa-client/libs/design-system/src/lib/icons/collaboration-icon/collaboration-icon.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c1a2136a653c2b9dfc52bc039fb0aa1d48ce0733
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/icons/collaboration-icon/collaboration-icon.component.spec.ts
@@ -0,0 +1,21 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { CollaborationIconComponent } from './collaboration-icon.component';
+
+describe('CollaborationIconComponent', () => {
+  let component: CollaborationIconComponent;
+  let fixture: ComponentFixture<CollaborationIconComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: [CollaborationIconComponent],
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(CollaborationIconComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/alfa-client/libs/design-system/src/lib/icons/collaboration-icon/collaboration-icon.component.ts b/alfa-client/libs/design-system/src/lib/icons/collaboration-icon/collaboration-icon.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8565574eac373499fcedaea5b514e7f616b344e1
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/icons/collaboration-icon/collaboration-icon.component.ts
@@ -0,0 +1,53 @@
+import { CommonModule } from '@angular/common';
+import { Component, Input } from '@angular/core';
+import { twMerge } from 'tailwind-merge';
+import { IconVariants, iconVariants } from '../iconVariants';
+
+@Component({
+  selector: 'ods-collaboration-icon',
+  standalone: true,
+  imports: [CommonModule],
+  template: `<svg
+    viewBox="0 0 24 24"
+    [ngClass]="[twMerge(iconVariants({ size }), 'stroke-primary', class)]"
+    aria-hidden="true"
+    fill="inherit"
+    xmlns="http://www.w3.org/2000/svg"
+  >
+    <path
+      d="M16 21V19C16 17.9391 15.5786 16.9217 14.8284 16.1716C14.0783 15.4214 13.0609 15 12 15H6C4.93913 15 3.92172 15.4214 3.17157 16.1716C2.42143 16.9217 2 17.9391 2 19V21"
+      stroke-width="2"
+      stroke-linecap="round"
+      stroke-linejoin="round"
+      fill="none"
+    />
+    <path
+      d="M9 11C11.2091 11 13 9.20914 13 7C13 4.79086 11.2091 3 9 3C6.79086 3 5 4.79086 5 7C5 9.20914 6.79086 11 9 11Z"
+      stroke-width="2"
+      stroke-linecap="round"
+      stroke-linejoin="round"
+      fill="none"
+    />
+    <path
+      d="M22 20.9999V18.9999C21.9993 18.1136 21.7044 17.2527 21.1614 16.5522C20.6184 15.8517 19.8581 15.3515 19 15.1299"
+      stroke-width="2"
+      stroke-linecap="round"
+      stroke-linejoin="round"
+      fill="none"
+    />
+    <path
+      d="M16 3.12988C16.8604 3.35018 17.623 3.85058 18.1676 4.55219C18.7122 5.2538 19.0078 6.11671 19.0078 7.00488C19.0078 7.89305 18.7122 8.75596 18.1676 9.45757C17.623 10.1592 16.8604 10.6596 16 10.8799"
+      stroke-width="2"
+      stroke-linecap="round"
+      stroke-linejoin="round"
+      fill="none"
+    />
+  </svg>`,
+})
+export class CollaborationIconComponent {
+  @Input() size: IconVariants['size'] = 'medium';
+  @Input() class: string = undefined;
+
+  iconVariants = iconVariants;
+  twMerge = twMerge;
+}
diff --git a/alfa-client/libs/design-system/src/lib/icons/collaboration-icon/collaboration-icon.stories.ts b/alfa-client/libs/design-system/src/lib/icons/collaboration-icon/collaboration-icon.stories.ts
new file mode 100644
index 0000000000000000000000000000000000000000..dbc1440939f920bb66062062c12ac343a347ddce
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/icons/collaboration-icon/collaboration-icon.stories.ts
@@ -0,0 +1,27 @@
+import type { Meta, StoryObj } from '@storybook/angular';
+
+import { CollaborationIconComponent } from './collaboration-icon.component';
+
+const meta: Meta<CollaborationIconComponent> = {
+  title: 'Icons/Collaboration icon',
+  component: CollaborationIconComponent,
+  excludeStories: /.*Data$/,
+  tags: ['autodocs'],
+};
+
+export default meta;
+type Story = StoryObj<CollaborationIconComponent>;
+
+export const Default: Story = {
+  args: { size: 'medium' },
+  argTypes: {
+    size: {
+      control: 'select',
+      options: ['small', 'medium', 'large', 'extra-large', 'full'],
+      description: 'Size of icon. Property "full" means 100%',
+      table: {
+        defaultValue: { summary: 'medium' },
+      },
+    },
+  },
+};
diff --git a/alfa-client/libs/design-system/src/lib/icons/iconVariants.ts b/alfa-client/libs/design-system/src/lib/icons/iconVariants.ts
index 6ea2dff309ce50e62416e5dd898bcc4771563625..e13cd3b4f155db048c8aab75887fa4f8f13172da 100644
--- a/alfa-client/libs/design-system/src/lib/icons/iconVariants.ts
+++ b/alfa-client/libs/design-system/src/lib/icons/iconVariants.ts
@@ -8,6 +8,7 @@ export const iconVariants = cva('', {
       medium: 'size-6',
       large: 'size-8',
       'extra-large': 'size-10',
+      xxl: 'size-12',
     },
   },
 });
diff --git a/alfa-client/libs/design-system/src/lib/icons/office-icon/office-icon.component.spec.ts b/alfa-client/libs/design-system/src/lib/icons/office-icon/office-icon.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b41f00f7375d9ef6362471bda4734fa271f18ead
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/icons/office-icon/office-icon.component.spec.ts
@@ -0,0 +1,21 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { OfficeIconComponent } from './office-icon.component';
+
+describe('SaveIconComponent', () => {
+  let component: OfficeIconComponent;
+  let fixture: ComponentFixture<OfficeIconComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: [OfficeIconComponent],
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(OfficeIconComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/alfa-client/libs/design-system/src/lib/icons/office-icon/office-icon.component.ts b/alfa-client/libs/design-system/src/lib/icons/office-icon/office-icon.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..25bdbb57d5011b3135a55be56cae8121c1611485
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/icons/office-icon/office-icon.component.ts
@@ -0,0 +1,28 @@
+import { NgClass } from '@angular/common';
+import { Component, Input } from '@angular/core';
+import { twMerge } from 'tailwind-merge';
+
+import { IconVariants, iconVariants } from '../iconVariants';
+
+@Component({
+  selector: 'ods-office-icon',
+  standalone: true,
+  imports: [NgClass],
+  template: `<svg
+    [ngClass]="twMerge(iconVariants({ size }), 'fill-black', class)"
+    viewBox="0 0 24 24"
+    fill="none"
+    xmlns="http://www.w3.org/2000/svg"
+  >
+    <path
+      d="M2 21V4.75L7 1L12 4.75V7H22V21H2ZM4 19H6V17H4V19ZM4 15H6V13H4V15ZM4 11H6V9H4V11ZM4 7H6V5H4V7ZM8 7H10V5H8V7ZM8 19H20V9H8V19ZM14 13V11H18V13H14ZM14 17V15H18V17H14ZM10 13V11H12V13H10ZM10 17V15H12V17H10Z"
+    />
+  </svg>`,
+})
+export class OfficeIconComponent {
+  @Input() size: IconVariants['size'] = 'medium';
+  @Input() class: string = undefined;
+
+  iconVariants = iconVariants;
+  twMerge = twMerge;
+}
diff --git a/alfa-client/libs/design-system/src/lib/icons/office-icon/office-icon.stories.ts b/alfa-client/libs/design-system/src/lib/icons/office-icon/office-icon.stories.ts
new file mode 100644
index 0000000000000000000000000000000000000000..46b9e413bf6ac9da265c12d440201cf12017da9e
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/icons/office-icon/office-icon.stories.ts
@@ -0,0 +1,27 @@
+import type { Meta, StoryObj } from '@storybook/angular';
+
+import { OfficeIconComponent } from './office-icon.component';
+
+const meta: Meta<OfficeIconComponent> = {
+  title: 'Icons/Office icon',
+  component: OfficeIconComponent,
+  excludeStories: /.*Data$/,
+  tags: ['autodocs'],
+};
+
+export default meta;
+type Story = StoryObj<OfficeIconComponent>;
+
+export const Default: Story = {
+  args: { size: 'large' },
+  argTypes: {
+    size: {
+      control: 'select',
+      options: ['small', 'medium', 'large', 'extra-large', 'full'],
+      description: 'Size of icon. Property "full" means 100%',
+      table: {
+        defaultValue: { summary: 'medium' },
+      },
+    },
+  },
+};
diff --git a/alfa-client/libs/design-system/src/lib/icons/search-icon/search-icon.component.spec.ts b/alfa-client/libs/design-system/src/lib/icons/search-icon/search-icon.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5981e81db28b29d1dfe651b306e3f3f938ec0bfb
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/icons/search-icon/search-icon.component.spec.ts
@@ -0,0 +1,21 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { SearchIconComponent } from './search-icon.component';
+
+describe('SearchIconComponent', () => {
+  let component: SearchIconComponent;
+  let fixture: ComponentFixture<SearchIconComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: [SearchIconComponent],
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(SearchIconComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/alfa-client/libs/design-system/src/lib/icons/search-icon/search-icon.component.ts b/alfa-client/libs/design-system/src/lib/icons/search-icon/search-icon.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..641713c3842c42cadb4d4075051fc51141d5f2e3
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/icons/search-icon/search-icon.component.ts
@@ -0,0 +1,28 @@
+import { NgClass } from '@angular/common';
+import { Component, Input } from '@angular/core';
+import { twMerge } from 'tailwind-merge';
+
+import { IconVariants, iconVariants } from '../iconVariants';
+
+@Component({
+  selector: 'ods-search-icon',
+  standalone: true,
+  imports: [NgClass],
+  template: `<svg
+    [ngClass]="twMerge(iconVariants({ size }), 'fill-primary', class)"
+    viewBox="0 0 24 24"
+    fill="none"
+    xmlns="http://www.w3.org/2000/svg"
+  >
+    <path
+      d="M15.5 14H14.71L14.43 13.73C15.41 12.59 16 11.11 16 9.5C16 5.91 13.09 3 9.5 3C5.91 3 3 5.91 3 9.5C3 13.09 5.91 16 9.5 16C11.11 16 12.59 15.41 13.73 14.43L14 14.71V15.5L19 20.49L20.49 19L15.5 14ZM9.5 14C7.01 14 5 11.99 5 9.5C5 7.01 7.01 5 9.5 5C11.99 5 14 7.01 14 9.5C14 11.99 11.99 14 9.5 14Z"
+    />
+  </svg>`,
+})
+export class SearchIconComponent {
+  @Input() size: IconVariants['size'] = 'medium';
+  @Input() class: string = '';
+
+  iconVariants = iconVariants;
+  twMerge = twMerge;
+}
diff --git a/alfa-client/libs/design-system/src/lib/icons/search-icon/search-icon.stories.ts b/alfa-client/libs/design-system/src/lib/icons/search-icon/search-icon.stories.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1952260187ba8fc7f462803ad2e2674f6d071856
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/icons/search-icon/search-icon.stories.ts
@@ -0,0 +1,27 @@
+import type { Meta, StoryObj } from '@storybook/angular';
+
+import { SearchIconComponent } from './search-icon.component';
+
+const meta: Meta<SearchIconComponent> = {
+  title: 'Icons/Search icon',
+  component: SearchIconComponent,
+  excludeStories: /.*Data$/,
+  tags: ['autodocs'],
+};
+
+export default meta;
+type Story = StoryObj<SearchIconComponent>;
+
+export const Default: Story = {
+  args: { size: 'large' },
+  argTypes: {
+    size: {
+      control: 'select',
+      options: ['small', 'medium', 'large', 'extra-large', 'full'],
+      description: 'Size of icon. Property "full" means 100%',
+      table: {
+        defaultValue: { summary: 'medium' },
+      },
+    },
+  },
+};
diff --git a/alfa-client/libs/design-system/src/lib/icons/user-icon/user-icon.component.spec.ts b/alfa-client/libs/design-system/src/lib/icons/user-icon/user-icon.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..6e80ce433f6db593962497c6e2c92386745a5045
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/icons/user-icon/user-icon.component.spec.ts
@@ -0,0 +1,21 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { UserIconComponent } from './user-icon.component';
+
+describe('UserIconComponent', () => {
+  let component: UserIconComponent;
+  let fixture: ComponentFixture<UserIconComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: [UserIconComponent],
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(UserIconComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/alfa-client/libs/design-system/src/lib/icons/user-icon/user-icon.component.ts b/alfa-client/libs/design-system/src/lib/icons/user-icon/user-icon.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..90c01e353f6029d459584e6fcdafa425c6e6d9be
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/icons/user-icon/user-icon.component.ts
@@ -0,0 +1,31 @@
+import { CommonModule } from '@angular/common';
+import { Component, Input } from '@angular/core';
+import { twMerge } from 'tailwind-merge';
+import { ExclamationIconComponent } from '../exclamation-icon/exclamation-icon.component';
+import { IconVariants, iconVariants } from '../iconVariants';
+
+@Component({
+  selector: 'ods-user-icon',
+  standalone: true,
+  imports: [CommonModule, ExclamationIconComponent],
+  template: `
+    <svg
+      viewBox="0 0 47 47"
+      fill="none"
+      xmlns="http://www.w3.org/2000/svg"
+      [ngClass]="[twMerge(iconVariants({ size }), 'fill-ozggray-300', class)]"
+    >
+      <path
+        d="M23.5 3.91663C12.69 3.91663 3.91669 12.69 3.91669 23.5C3.91669 34.31 12.69 43.0833 23.5 43.0833C34.31 43.0833 43.0834 34.31 43.0834 23.5C43.0834 12.69 34.31 3.91663 23.5 3.91663ZM23.5 9.79163C26.7509 9.79163 29.375 12.4158 29.375 15.6666C29.375 18.9175 26.7509 21.5416 23.5 21.5416C20.2492 21.5416 17.625 18.9175 17.625 15.6666C17.625 12.4158 20.2492 9.79163 23.5 9.79163ZM23.5 37.6C18.6042 37.6 14.2763 35.0933 11.75 31.2941C11.8088 27.397 19.5834 25.2625 23.5 25.2625C27.3971 25.2625 35.1913 27.397 35.25 31.2941C32.7238 35.0933 28.3959 37.6 23.5 37.6Z"
+      />
+    </svg>
+  `,
+})
+export class UserIconComponent {
+  @Input() variant: 'user' | 'initials' = 'user';
+  @Input() size: IconVariants['size'] = 'xxl';
+  @Input() class: string = undefined;
+
+  iconVariants = iconVariants;
+  twMerge = twMerge;
+}
diff --git a/alfa-client/libs/design-system/src/lib/icons/user-icon/user-icon.stories.ts b/alfa-client/libs/design-system/src/lib/icons/user-icon/user-icon.stories.ts
new file mode 100644
index 0000000000000000000000000000000000000000..cf801c263a4b51d9dc560f937de4047b07da27a2
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/icons/user-icon/user-icon.stories.ts
@@ -0,0 +1,27 @@
+import type { Meta, StoryObj } from '@storybook/angular';
+
+import { UserIconComponent } from './user-icon.component';
+
+const meta: Meta<UserIconComponent> = {
+  title: 'Icons/User icon',
+  component: UserIconComponent,
+  excludeStories: /.*Data$/,
+  tags: ['autodocs'],
+};
+
+export default meta;
+type Story = StoryObj<UserIconComponent>;
+
+export const Default: Story = {
+  args: { size: 'xxl' },
+  argTypes: {
+    size: {
+      control: 'select',
+      options: ['small', 'medium', 'large', 'extra-large', 'xxl', 'full'],
+      description: 'Size of icon. Property "full" means 100%',
+      table: {
+        defaultValue: { summary: 'xxl' },
+      },
+    },
+  },
+};
diff --git a/alfa-client/libs/design-system/src/lib/instant-search/instant-search/instant-search.component.spec.ts b/alfa-client/libs/design-system/src/lib/instant-search/instant-search/instant-search.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..72cc13e7708a00114b96193a07e83a855f0c628c
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/instant-search/instant-search/instant-search.component.spec.ts
@@ -0,0 +1,618 @@
+import { Mock, mock, useFromMock } from '@alfa-client/test-utils';
+import { EventEmitter } from '@angular/core';
+import {
+  ComponentFixture,
+  TestBed,
+  discardPeriodicTasks,
+  fakeAsync,
+  tick,
+} from '@angular/core/testing';
+import { Resource } from '@ngxp/rest';
+import { Subscription } from 'rxjs';
+import { InstantSearchComponent } from './instant-search.component';
+import { InstantSearchQuery, InstantSearchResult } from './instant-search.model';
+
+describe('InstantSearchComponent', () => {
+  let component: InstantSearchComponent;
+  let fixture: ComponentFixture<InstantSearchComponent>;
+
+  const searchResults: InstantSearchResult<Resource>[] = [
+    { title: 'test', description: 'test' },
+    { title: 'caption', description: 'desc' },
+  ];
+  const searchBy: string = 'query';
+
+  let searchQueryChanged: Mock<EventEmitter<any>>;
+  let searchResultSelected: Mock<EventEmitter<any>>;
+
+  beforeEach(async () => {
+    searchQueryChanged = <any>mock(EventEmitter);
+    searchResultSelected = <any>mock(EventEmitter);
+
+    await TestBed.configureTestingModule({
+      imports: [InstantSearchComponent],
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(InstantSearchComponent);
+    component = fixture.componentInstance;
+    component.searchQueryChanged = useFromMock(searchQueryChanged);
+    component.searchResultSelected = useFromMock(searchResultSelected);
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+
+  describe('ngOnInit', () => {
+    it('should handle value changes', () => {
+      component.handleValueChanges = jest.fn();
+
+      component.ngOnInit();
+
+      expect(component.handleValueChanges).toHaveBeenCalled();
+    });
+  });
+
+  describe('handleValueChanges', () => {
+    beforeEach(() => {
+      component.showResults = jest.fn();
+    });
+
+    it('should subscribe to value changes', () => {
+      component.control.valueChanges.subscribe = jest.fn();
+
+      component.handleValueChanges();
+
+      expect(component.control.valueChanges.subscribe).toHaveBeenCalled();
+    });
+
+    it('should emit query', fakeAsync(() => {
+      component.handleValueChanges();
+
+      component.control.setValue(searchBy);
+
+      tick(InstantSearchComponent.DEBOUNCE_TIME_IN_MILLIS);
+      component.control.valueChanges.subscribe();
+
+      expect(searchQueryChanged.emit).toHaveBeenCalledWith({ searchBy } as InstantSearchQuery);
+    }));
+
+    it('should not emit query', fakeAsync(() => {
+      component.handleValueChanges();
+
+      const searchBy: string = 'q';
+      component.control.setValue(searchBy);
+
+      tick(InstantSearchComponent.DEBOUNCE_TIME_IN_MILLIS);
+      component.control.valueChanges.subscribe();
+
+      expect(searchQueryChanged.emit).not.toHaveBeenCalled();
+    }));
+
+    describe('result are already visible', () => {
+      beforeEach(() => {
+        component.areResultsVisible = true;
+      });
+
+      it('should not show results', fakeAsync(() => {
+        component.handleValueChanges();
+
+        component.control.setValue(searchBy);
+        tick(InstantSearchComponent.DEBOUNCE_TIME_IN_MILLIS);
+
+        component.control.valueChanges.subscribe();
+        expect(component.showResults).not.toHaveBeenCalled();
+
+        discardPeriodicTasks();
+      }));
+    });
+
+    describe('results are not visible', () => {
+      beforeEach(() => {
+        component.areResultsVisible = false;
+      });
+
+      it('should show results', fakeAsync(() => {
+        component.handleValueChanges();
+
+        component.control.setValue(searchBy);
+        tick(InstantSearchComponent.DEBOUNCE_TIME_IN_MILLIS);
+
+        component.control.valueChanges.subscribe();
+        expect(component.showResults).toHaveBeenCalled();
+
+        discardPeriodicTasks();
+      }));
+
+      it('should not show results if debounce time not reached', fakeAsync(() => {
+        component.handleValueChanges();
+
+        component.control.setValue(searchBy);
+        tick(InstantSearchComponent.DEBOUNCE_TIME_IN_MILLIS - 1);
+
+        component.control.valueChanges.subscribe();
+        expect(component.showResults).not.toHaveBeenCalled();
+
+        discardPeriodicTasks();
+      }));
+
+      it('should not show results if not enough characters entered', fakeAsync(() => {
+        component.handleValueChanges();
+
+        component.control.setValue('q');
+        tick(InstantSearchComponent.DEBOUNCE_TIME_IN_MILLIS);
+
+        component.control.valueChanges.subscribe();
+        expect(component.showResults).not.toHaveBeenCalled();
+
+        discardPeriodicTasks();
+      }));
+    });
+  });
+
+  describe('ngOnDestroy', () => {
+    it('should subscribe to value changes', () => {
+      component.formControlSubscription = new Subscription();
+      component.formControlSubscription.unsubscribe = jest.fn();
+
+      component.ngOnDestroy();
+
+      expect(component.formControlSubscription.unsubscribe).toHaveBeenCalled();
+    });
+  });
+
+  describe('set searchResults', () => {
+    describe('on different results', () => {
+      it('should call setSearchResults', () => {
+        component.setSearchResults = jest.fn();
+
+        component.searchResults = searchResults;
+
+        expect(component.setSearchResults).toHaveBeenCalled();
+      });
+    });
+
+    describe('on same results', () => {
+      it('should not call setSearchResults', () => {
+        component.setSearchResults = jest.fn();
+
+        component.searchResults = [];
+
+        expect(component.setSearchResults).not.toHaveBeenCalled();
+      });
+    });
+
+    describe('on null or undefined', () => {
+      it.each([null, undefined])(
+        'should not call setSearchResults for %s',
+        (searchResults: InstantSearchResult<Resource>[]) => {
+          component.setSearchResults = jest.fn();
+
+          component.searchResults = searchResults;
+
+          expect(component.setSearchResults).not.toHaveBeenCalled();
+        },
+      );
+    });
+  });
+
+  describe('setSearchResults', () => {
+    it('should set results', () => {
+      component.setSearchResults(searchResults);
+
+      expect(component.results).toEqual(searchResults);
+    });
+
+    it('should call buildAriaLiveText with search results length', () => {
+      component.buildAriaLiveText = jest.fn();
+
+      component.setSearchResults(searchResults);
+
+      expect(component.buildAriaLiveText).toHaveBeenCalledWith(searchResults.length);
+    });
+  });
+
+  describe('setFocusOnResultItem', () => {
+    beforeEach(() => {
+      component.resultsRef.get = jest.fn().mockReturnValue({ setFocus: jest.fn() });
+    });
+
+    it('should call get for resultsRef with index', () => {
+      component.setFocusOnResultItem(1);
+
+      expect(component.resultsRef.get).toHaveBeenCalledWith(1);
+    });
+
+    it('should call setFocus', () => {
+      component.setFocusOnResultItem(1);
+
+      expect(component.resultsRef.get(1).setFocus).toHaveBeenCalled();
+    });
+  });
+
+  describe('handleArrowNavigation', () => {
+    const event: KeyboardEvent = new KeyboardEvent('arrow');
+
+    beforeEach(() => {
+      component.getResultIndexForKey = jest.fn();
+      component.setFocusOnResultItem = jest.fn();
+    });
+
+    it('should call prevent default', () => {
+      event.preventDefault = jest.fn();
+
+      component.handleArrowNavigation(event);
+
+      expect(event.preventDefault).toHaveBeenCalled();
+    });
+
+    it('should call getResultIndexForKey', () => {
+      component.handleArrowNavigation(event);
+
+      expect(component.getResultIndexForKey).toHaveBeenCalledWith(event.key);
+    });
+
+    it('should call setFocusOnResultItem', () => {
+      component.getResultIndexForKey = jest.fn().mockReturnValue(0);
+
+      component.handleArrowNavigation(event);
+
+      expect(component.setFocusOnResultItem).toHaveBeenCalledWith(0);
+    });
+  });
+
+  describe('handleEscape', () => {
+    const event: KeyboardEvent = new KeyboardEvent('esc');
+
+    it('should call prevent default', () => {
+      event.preventDefault = jest.fn();
+
+      component.handleEscape(event);
+
+      expect(event.preventDefault).toHaveBeenCalled();
+    });
+
+    it('should call hideResults', () => {
+      component.hideResults = jest.fn();
+
+      component.handleEscape(event);
+
+      expect(component.hideResults).toHaveBeenCalled();
+    });
+  });
+
+  describe('getNextResultIndex', () => {
+    it('should return 0 if index is undefined', () => {
+      const result: number = component.getNextResultIndex(undefined, 2);
+
+      expect(result).toBe(0);
+    });
+
+    it('should return 0 if current index is last', () => {
+      const result: number = component.getNextResultIndex(1, 2);
+
+      expect(result).toBe(0);
+    });
+
+    it('should return next search result index', () => {
+      const result: number = component.getNextResultIndex(0, 2);
+
+      expect(result).toBe(1);
+    });
+  });
+
+  describe('getPreviousResultIndex', () => {
+    it('should return last index if current index is undefined', () => {
+      const result: number = component.getPreviousResultIndex(undefined, 2);
+
+      expect(result).toBe(1);
+    });
+
+    it('should return last index if current index is first', () => {
+      const result: number = component.getPreviousResultIndex(0, 2);
+
+      expect(result).toBe(1);
+    });
+
+    it('should return previous search result index', () => {
+      const result: number = component.getPreviousResultIndex(1, 2);
+
+      expect(result).toBe(0);
+    });
+  });
+
+  describe('getResultIndexForKey', () => {
+    it('should call getNextResultIndex if ArrowDown', () => {
+      component.getNextResultIndex = jest.fn();
+
+      component.getResultIndexForKey('ArrowDown');
+
+      expect(component.getNextResultIndex).toHaveBeenCalled();
+    });
+
+    it('should call getPreviousResultIndex if ArrowUp', () => {
+      component.getPreviousResultIndex = jest.fn();
+
+      component.getResultIndexForKey('ArrowUp');
+
+      expect(component.getPreviousResultIndex).toHaveBeenCalled();
+    });
+  });
+
+  describe('getLastItemIndex', () => {
+    it('should return 0', () => {
+      const result: number = component.getLastItemIndex(0);
+
+      expect(result).toBe(0);
+    });
+
+    it('should return decrement of array length', () => {
+      const result: number = component.getLastItemIndex(5);
+
+      expect(result).toBe(4);
+    });
+  });
+
+  describe('buildAriaLiveText', () => {
+    beforeEach(() => {
+      component.control.setValue('test');
+    });
+
+    it('should return text for one result', () => {
+      const result: string = component.buildAriaLiveText(1);
+
+      expect(result).toBe(
+        'Ein Suchergebnis für Eingabe test. Nutze Pfeiltaste nach unten, um das zu erreichen.',
+      );
+    });
+
+    it('should return text for many results', () => {
+      const result: string = component.buildAriaLiveText(4);
+
+      expect(result).toBe(
+        '4 Suchergebnisse für Eingabe test. Nutze Pfeiltaste nach unten, um diese zu erreichen.',
+      );
+    });
+
+    it('should return text for no results', () => {
+      const result: string = component.buildAriaLiveText(0);
+
+      expect(result).toBe('Keine Ergebnisse');
+    });
+  });
+
+  describe('showResults', () => {
+    it('should set isShowResults to true', () => {
+      component.showResults();
+
+      expect(component.areResultsVisible).toBe(true);
+    });
+  });
+
+  describe('hideResults', () => {
+    it('should set isShowResults to false', () => {
+      component.hideResults();
+
+      expect(component.areResultsVisible).toBe(false);
+    });
+
+    it('should emit searchResultClosed event', () => {
+      component.searchResultClosed.emit = jest.fn();
+
+      component.hideResults();
+
+      expect(component.searchResultClosed.emit).toHaveBeenCalled();
+    });
+  });
+
+  describe('onKeydownHandler', () => {
+    const keyboardEvent: KeyboardEvent = new KeyboardEvent('a');
+
+    beforeEach(() => {
+      component.isSearchResultsEmpty = jest.fn();
+      component.isArrowNavigationKey = jest.fn();
+      component.isEscapeKey = jest.fn();
+      component.handleArrowNavigation = jest.fn();
+      component.handleEscape = jest.fn();
+    });
+
+    it('should check for empty result', () => {
+      component.onKeydownHandler(keyboardEvent);
+
+      expect(component.isSearchResultsEmpty).toHaveBeenCalled();
+    });
+
+    describe('search result is empty', () => {
+      beforeEach(() => {
+        component.isSearchResultsEmpty = jest.fn().mockReturnValue(true);
+      });
+
+      it('should ignore key navigation', () => {
+        component.onKeydownHandler(keyboardEvent);
+
+        expect(component.isArrowNavigationKey).not.toHaveBeenCalled();
+      });
+
+      it('should ignore escape key handling', () => {
+        component.onKeydownHandler(keyboardEvent);
+
+        expect(component.isEscapeKey).not.toHaveBeenCalled();
+      });
+    });
+
+    describe('search result is not empty', () => {
+      beforeEach(() => {
+        component.isSearchResultsEmpty = jest.fn().mockReturnValue(false);
+      });
+
+      it('should check if arrow navigation', () => {
+        component.onKeydownHandler(keyboardEvent);
+
+        expect(component.isArrowNavigationKey).toHaveBeenCalled();
+      });
+
+      it('should handle arrow navigation', () => {
+        component.isArrowNavigationKey = jest.fn().mockReturnValue(true);
+
+        component.onKeydownHandler(keyboardEvent);
+
+        expect(component.handleArrowNavigation).toHaveBeenCalled();
+      });
+
+      it('should not handle arrow navigation', () => {
+        component.isArrowNavigationKey = jest.fn().mockReturnValue(false);
+
+        component.onKeydownHandler(keyboardEvent);
+
+        expect(component.handleArrowNavigation).not.toHaveBeenCalled();
+      });
+
+      describe('is not arrow navigation', () => {
+        beforeEach(() => {
+          component.isArrowNavigationKey = jest.fn().mockReturnValue(false);
+        });
+
+        it('should check for escape key', () => {
+          component.onKeydownHandler(keyboardEvent);
+
+          expect(component.isEscapeKey).toHaveBeenCalled();
+        });
+
+        it('should handle escape key', () => {
+          component.isEscapeKey = jest.fn().mockReturnValue(true);
+
+          component.onKeydownHandler(keyboardEvent);
+
+          expect(component.handleEscape).toHaveBeenCalled();
+        });
+
+        it('should not handle escape key', () => {
+          component.isEscapeKey = jest.fn().mockReturnValue(false);
+
+          component.onKeydownHandler(keyboardEvent);
+
+          expect(component.handleEscape).not.toHaveBeenCalled();
+        });
+      });
+    });
+  });
+
+  describe('isSearchResultsEmpty', () => {
+    it('should return true', () => {
+      component.results = [];
+
+      const result: boolean = component.isSearchResultsEmpty();
+
+      expect(result).toBe(true);
+    });
+
+    it('should return false', () => {
+      component.results = searchResults;
+
+      const result: boolean = component.isSearchResultsEmpty();
+
+      expect(result).toBe(false);
+    });
+  });
+
+  describe('isArrowNavigationKey', () => {
+    it.each(['ArrowUp', 'ArrowDown'])('should return true for key %s', (key: string) => {
+      const keyboardEvent: KeyboardEvent = { ...new KeyboardEvent('key'), key };
+
+      const result: boolean = component.isArrowNavigationKey(keyboardEvent);
+
+      expect(result).toBeTruthy();
+    });
+
+    it('should return false', () => {
+      const result: boolean = component.isArrowNavigationKey(new KeyboardEvent('not arrow'));
+
+      expect(result).toBe(false);
+    });
+  });
+
+  describe('isEscapeKey', () => {
+    it('should return true', () => {
+      const escapeKeyEvent = { ...new KeyboardEvent('esc'), key: 'Escape' };
+
+      const result: boolean = component.isEscapeKey(escapeKeyEvent);
+
+      expect(result).toBe(true);
+    });
+
+    it('should return false', () => {
+      const result: boolean = component.isEscapeKey(new KeyboardEvent('not escape'));
+
+      expect(result).toBe(false);
+    });
+  });
+
+  describe('isLastItemOrOutOfArray', () => {
+    it.each([3, 5])('should return true for %s', (index: number) => {
+      const result: boolean = component.isLastItemOrOutOfArray(index, 4);
+
+      expect(result).toBe(true);
+    });
+
+    it('should return false', () => {
+      const result: boolean = component.isLastItemOrOutOfArray(1, 3);
+
+      expect(result).toBe(false);
+    });
+  });
+
+  describe('isFirstItemOrOutOfArray', () => {
+    it.each([0, -1])('should return true for %s', (index: number) => {
+      const result: boolean = component.isFirstItemOrOutOfArray(index);
+
+      expect(result).toBe(true);
+    });
+
+    it('should return false', () => {
+      const result: boolean = component.isFirstItemOrOutOfArray(1);
+
+      expect(result).toBe(false);
+    });
+  });
+
+  describe('onItemClicked', () => {
+    beforeEach(() => {
+      component.hideResults = jest.fn();
+    });
+
+    it('should emit searchResultSelected', () => {
+      component.onItemClicked(searchResults[0], 0);
+
+      expect(searchResultSelected.emit).toHaveBeenCalledWith(searchResults[0]);
+    });
+
+    it('should hide results', () => {
+      component.onItemClicked(searchResults[0], 0);
+
+      expect(component.hideResults).toHaveBeenCalled();
+    });
+  });
+
+  describe('onClickHandler', () => {
+    const e: MouseEvent = { ...new MouseEvent('test') };
+
+    beforeEach(() => {
+      component.hideResults = jest.fn();
+    });
+
+    it('should call hideResults if instant search does not contain event target', () => {
+      component.onClickHandler(e);
+
+      expect(component.hideResults).toHaveBeenCalled();
+    });
+
+    it('should not call hideResults if instant search contains event target', () => {
+      component.ref.nativeElement.contains = jest.fn().mockReturnValue(true);
+
+      component.onClickHandler(e);
+
+      expect(component.hideResults).not.toHaveBeenCalled();
+    });
+  });
+});
diff --git a/alfa-client/libs/design-system/src/lib/instant-search/instant-search/instant-search.component.ts b/alfa-client/libs/design-system/src/lib/instant-search/instant-search/instant-search.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ab653fe9d22fae4f7f7faf447d5b7a5685e85342
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/instant-search/instant-search/instant-search.component.ts
@@ -0,0 +1,232 @@
+import { EMPTY_STRING, isNotNil } from '@alfa-client/tech-shared';
+import { CommonModule } from '@angular/common';
+import {
+  Component,
+  ElementRef,
+  EventEmitter,
+  HostListener,
+  Input,
+  OnDestroy,
+  OnInit,
+  Output,
+  QueryList,
+  ViewChildren,
+} from '@angular/core';
+import { FormControl } from '@angular/forms';
+import { Resource } from '@ngxp/rest';
+import { isEqual, isUndefined } from 'lodash-es';
+import { Subscription, debounceTime, distinctUntilChanged, filter } from 'rxjs';
+import { AriaLiveRegionComponent } from '../../aria-live-region/aria-live-region.component';
+import { SearchFieldComponent } from '../search-field/search-field.component';
+import { SearchResultHeaderComponent } from '../search-result-header/search-result-header.component';
+import { SearchResultItemComponent } from '../search-result-item/search-result-item.component';
+import { SearchResultLayerComponent } from '../search-result-layer/search-result-layer.component';
+import { InstantSearchQuery, InstantSearchResult } from './instant-search.model';
+
+@Component({
+  selector: 'ods-instant-search',
+  standalone: true,
+  imports: [
+    CommonModule,
+    SearchFieldComponent,
+    SearchResultHeaderComponent,
+    SearchResultItemComponent,
+    SearchResultLayerComponent,
+    AriaLiveRegionComponent,
+  ],
+  template: ` <div class="relative">
+    <ods-search-field
+      [placeholder]="placeholder"
+      [attr.aria-expanded]="results.length"
+      [control]="control"
+      aria-controls="results"
+      (inputClicked)="showResults()"
+      (searchQueryCleared)="searchQueryCleared.emit()"
+      #searchField
+    />
+    <ods-aria-live-region [text]="ariaLiveText" />
+    <ods-search-result-layer
+      *ngIf="results.length && areResultsVisible"
+      class="absolute z-50 mt-3 w-full"
+      id="results"
+    >
+      <ods-search-result-header
+        *ngIf="headerText"
+        [text]="headerText"
+        [count]="results.length"
+        header
+      />
+      <ods-search-result-item
+        *ngFor="let result of results; let i = index"
+        [title]="result.title"
+        [description]="result.description"
+        (itemClicked)="onItemClicked(result, i)"
+        #results
+      ></ods-search-result-item>
+    </ods-search-result-layer>
+  </div>`,
+})
+export class InstantSearchComponent implements OnInit, OnDestroy {
+  static readonly DEBOUNCE_TIME_IN_MILLIS: number = 300;
+
+  @Input() placeholder: string = EMPTY_STRING;
+  @Input() headerText: string = EMPTY_STRING;
+  @Input() control: FormControl<string> = new FormControl(EMPTY_STRING);
+
+  @Input() set searchResults(searchResults: InstantSearchResult<Resource>[]) {
+    if (!isEqual(searchResults, this.results) && isNotNil(searchResults)) {
+      this.setSearchResults(searchResults);
+    }
+  }
+
+  @Output() searchResultSelected: EventEmitter<InstantSearchResult<Resource>> = new EventEmitter<
+    InstantSearchResult<Resource>
+  >();
+  @Output() searchResultClosed: EventEmitter<MouseEvent> = new EventEmitter<MouseEvent>();
+  @Output() searchQueryChanged: EventEmitter<InstantSearchQuery> =
+    new EventEmitter<InstantSearchQuery>();
+  @Output() searchQueryCleared: EventEmitter<MouseEvent> = new EventEmitter<MouseEvent>();
+
+  readonly FIRST_ITEM_INDEX: number = 0;
+  readonly PREVIEW_SEARCH_STRING_MIN_LENGTH: number = 2;
+  results: InstantSearchResult<Resource>[] = [];
+  ariaLiveText: string = '';
+  areResultsVisible: boolean = true;
+  private focusedResult: number | undefined = undefined;
+  formControlSubscription: Subscription;
+
+  constructor(public ref: ElementRef) {}
+
+  @ViewChildren('results') resultsRef: QueryList<SearchResultItemComponent>;
+
+  ngOnInit(): void {
+    this.handleValueChanges();
+  }
+
+  handleValueChanges() {
+    this.formControlSubscription = this.control.valueChanges
+      .pipe(
+        debounceTime(InstantSearchComponent.DEBOUNCE_TIME_IN_MILLIS),
+        filter((value: string) => value.length >= this.PREVIEW_SEARCH_STRING_MIN_LENGTH),
+        distinctUntilChanged(),
+      )
+      .subscribe((searchBy: string) => {
+        this.searchQueryChanged.emit({ searchBy });
+        if (!this.areResultsVisible) {
+          this.showResults();
+        }
+      });
+  }
+
+  ngOnDestroy(): void {
+    if (isNotNil(this.formControlSubscription)) this.formControlSubscription.unsubscribe();
+  }
+
+  @HostListener('document:keydown', ['$event'])
+  onKeydownHandler(e: KeyboardEvent): void {
+    if (this.isSearchResultsEmpty()) return;
+    if (this.isArrowNavigationKey(e)) this.handleArrowNavigation(e);
+    if (this.isEscapeKey(e)) this.handleEscape(e);
+  }
+
+  @HostListener('document:click', ['$event'])
+  onClickHandler(e: MouseEvent): void {
+    if (!this.ref.nativeElement.contains(e.target)) {
+      this.hideResults();
+    }
+  }
+
+  handleArrowNavigation(e: KeyboardEvent): void {
+    e.preventDefault();
+    const newIndex = this.getResultIndexForKey(e.key);
+    this.focusedResult = newIndex;
+    this.setFocusOnResultItem(newIndex);
+  }
+
+  handleEscape(e: KeyboardEvent): void {
+    e.preventDefault();
+    this.hideResults();
+  }
+
+  setFocusOnResultItem(index: number): void {
+    this.resultsRef.get(index).setFocus();
+  }
+
+  setSearchResults(searchResults: InstantSearchResult<Resource>[]): void {
+    this.results = searchResults;
+    this.ariaLiveText = this.buildAriaLiveText(searchResults.length);
+  }
+
+  getNextResultIndex(index: number | undefined, resultLength: number): number {
+    if (isUndefined(index)) return this.FIRST_ITEM_INDEX;
+    if (this.isLastItemOrOutOfArray(index, resultLength)) return this.FIRST_ITEM_INDEX;
+    return index + 1;
+  }
+
+  getPreviousResultIndex(index: number | undefined, resultLength: number): number {
+    if (isUndefined(index)) return this.getLastItemIndex(resultLength);
+    if (this.isFirstItemOrOutOfArray(index)) return this.getLastItemIndex(resultLength);
+    return index - 1;
+  }
+
+  getLastItemIndex(arrayLength: number): number {
+    if (arrayLength < 1) return this.FIRST_ITEM_INDEX;
+    return arrayLength - 1;
+  }
+
+  getResultIndexForKey(key: string): number {
+    switch (key) {
+      case 'ArrowDown':
+        return this.getNextResultIndex(this.focusedResult, this.results.length);
+      case 'ArrowUp':
+        return this.getPreviousResultIndex(this.focusedResult, this.results.length);
+      default:
+        console.error('Key %s not allowed', key);
+    }
+  }
+
+  buildAriaLiveText(resultsLength: number): string {
+    if (resultsLength === 1)
+      return `Ein Suchergebnis für Eingabe ${this.control.value}. Nutze Pfeiltaste nach unten, um das zu erreichen.`;
+    if (resultsLength > 1)
+      return `${resultsLength} Suchergebnisse für Eingabe ${this.control.value}. Nutze Pfeiltaste nach unten, um diese zu erreichen.`;
+    return 'Keine Ergebnisse';
+  }
+
+  showResults(): void {
+    this.areResultsVisible = true;
+    this.focusedResult = undefined;
+  }
+
+  hideResults(): void {
+    this.areResultsVisible = false;
+    this.focusedResult = undefined;
+    this.searchResultClosed.emit();
+  }
+
+  isLastItemOrOutOfArray(index: number, arrayLength: number): boolean {
+    return index >= arrayLength - 1;
+  }
+
+  isFirstItemOrOutOfArray(index: number): boolean {
+    return index <= this.FIRST_ITEM_INDEX;
+  }
+
+  isSearchResultsEmpty(): boolean {
+    return this.results.length === 0;
+  }
+
+  isArrowNavigationKey(e: KeyboardEvent): boolean {
+    return e.key === 'ArrowDown' || e.key === 'ArrowUp';
+  }
+
+  isEscapeKey(e: KeyboardEvent): boolean {
+    return e.key === 'Escape';
+  }
+
+  onItemClicked(searchResult: InstantSearchResult<Resource>, index: number) {
+    this.searchResultSelected.emit(searchResult);
+    this.focusedResult = index;
+    this.hideResults();
+  }
+}
diff --git a/alfa-client/libs/design-system/src/lib/instant-search/instant-search/instant-search.model.ts b/alfa-client/libs/design-system/src/lib/instant-search/instant-search/instant-search.model.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ecf661f429fddde80b83340063ad95f54daba6b0
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/instant-search/instant-search/instant-search.model.ts
@@ -0,0 +1,11 @@
+import { Resource } from '@ngxp/rest';
+
+export interface InstantSearchResult<T extends Resource> {
+  title: string;
+  description: string;
+  data?: T;
+}
+
+export interface InstantSearchQuery {
+  searchBy: string;
+}
diff --git a/alfa-client/libs/design-system/src/lib/instant-search/instant-search/instant-search.stories.ts b/alfa-client/libs/design-system/src/lib/instant-search/instant-search/instant-search.stories.ts
new file mode 100644
index 0000000000000000000000000000000000000000..522bc7f81a9e3f677d55c9ac8066632c02f15247
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/instant-search/instant-search/instant-search.stories.ts
@@ -0,0 +1,38 @@
+import { type Meta, type StoryObj } from '@storybook/angular';
+import { InstantSearchComponent } from './instant-search.component';
+
+const meta: Meta<InstantSearchComponent> = {
+  title: 'Instant search/Instant search',
+  component: InstantSearchComponent,
+  excludeStories: /.*Data$/,
+  tags: ['autodocs'],
+};
+
+export default meta;
+type Story = StoryObj<InstantSearchComponent>;
+
+export const Default: Story = {
+  args: {
+    label: '',
+    placeholder: 'zuständige Stelle suchen',
+    headerText: 'In der OZG-Cloud',
+  },
+};
+
+export const SearchResults: Story = {
+  args: {
+    label: '',
+    placeholder: 'zuständige Stelle suchen',
+    headerText: 'In der OZG-Cloud',
+    searchResults: [
+      {
+        title: 'Landeshauptstadt Kiel - Ordnungsamt, Gewerbe- und Schornsteinfegeraufsicht',
+        description: 'Fabrikstraße  8-10, 24103 Kiel',
+      },
+      {
+        title: 'Amt für Digitalisierung, Breitband und Vermessung Nürnberg Außenstelle Hersbruck',
+        description: 'Rathausmarkt 7, Hersbruck',
+      },
+    ],
+  },
+};
diff --git a/alfa-client/libs/design-system/src/lib/instant-search/search-field/search-field.component.spec.ts b/alfa-client/libs/design-system/src/lib/instant-search/search-field/search-field.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..81b3e439ee8eba573c9f17bf31a7a707d02dc911
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/instant-search/search-field/search-field.component.spec.ts
@@ -0,0 +1,55 @@
+import { EMPTY_STRING } from '@alfa-client/tech-shared';
+import { getElementFromFixtureByType, mock } from '@alfa-client/test-utils';
+import { EventEmitter } from '@angular/core';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { FormControl } from '@angular/forms';
+import { TextInputComponent } from '../../form/text-input/text-input.component';
+import { SearchFieldComponent } from './search-field.component';
+
+describe('SearchFieldComponent', () => {
+  let component: SearchFieldComponent;
+  let fixture: ComponentFixture<SearchFieldComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: [SearchFieldComponent],
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(SearchFieldComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+
+  describe('inputClicked', () => {
+    it('should emit event', () => {
+      component.inputClicked = <any>mock(EventEmitter);
+      const input = getElementFromFixtureByType(fixture, TextInputComponent);
+
+      input.inputElement.nativeElement.click();
+
+      expect(component.inputClicked.emit).toHaveBeenCalled();
+    });
+  });
+
+  describe('clearValue', () => {
+    it('should set empty value', () => {
+      component.control = new FormControl('test');
+
+      component.clearInput();
+
+      expect(component.control.value).toBe(EMPTY_STRING);
+    });
+
+    it('should emit searchQueryCleared event', () => {
+      component.searchQueryCleared.emit = jest.fn();
+
+      component.clearInput();
+
+      expect(component.searchQueryCleared.emit).toHaveBeenCalled();
+    });
+  });
+});
diff --git a/alfa-client/libs/design-system/src/lib/instant-search/search-field/search-field.component.ts b/alfa-client/libs/design-system/src/lib/instant-search/search-field/search-field.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..787d40064fb28440d7f0b75efe9b94786dc317ad
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/instant-search/search-field/search-field.component.ts
@@ -0,0 +1,46 @@
+import { CommonModule } from '@angular/common';
+import { Component, EventEmitter, Input, Output } from '@angular/core';
+import { FormControl } from '@angular/forms';
+import { EMPTY_STRING } from '../../../../../tech-shared/src';
+import { TextInputComponent } from '../../form/text-input/text-input.component';
+import { CloseIconComponent } from '../../icons/close-icon/close-icon.component';
+import { SearchIconComponent } from '../../icons/search-icon/search-icon.component';
+
+@Component({
+  selector: 'ods-search-field',
+  standalone: true,
+  imports: [CommonModule, TextInputComponent, SearchIconComponent, CloseIconComponent],
+  template: `<ods-text-input
+    label="instant search"
+    [fieldControl]="control"
+    [placeholder]="placeholder"
+    [withPrefix]="true"
+    [withSuffix]="true"
+    [showLabel]="false"
+    (clickEmitter)="inputClicked.emit()"
+    role="combobox"
+  >
+    <ods-search-icon prefix aria-hidden="true" aria-label="Suchfeld" />
+    <button
+      suffix
+      *ngIf="control.value"
+      (click)="clearInput()"
+      aria-label="Eingabe löschen"
+      data-test-id="clear-instant-search"
+    >
+      <ods-close-icon class="fill-primary hover:fill-primary-hover" />
+    </button>
+  </ods-text-input>`,
+})
+export class SearchFieldComponent {
+  @Input() placeholder: string = EMPTY_STRING;
+  @Input() control: FormControl<string> = new FormControl(EMPTY_STRING);
+
+  @Output() inputClicked: EventEmitter<MouseEvent> = new EventEmitter<MouseEvent>();
+  @Output() searchQueryCleared: EventEmitter<MouseEvent> = new EventEmitter<MouseEvent>();
+
+  clearInput(): void {
+    this.control.setValue(EMPTY_STRING);
+    this.searchQueryCleared.emit();
+  }
+}
diff --git a/alfa-client/libs/design-system/src/lib/instant-search/search-field/search-field.stories.ts b/alfa-client/libs/design-system/src/lib/instant-search/search-field/search-field.stories.ts
new file mode 100644
index 0000000000000000000000000000000000000000..fec43fa8f65cd51c47e4639fd002a34e33c8b119
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/instant-search/search-field/search-field.stories.ts
@@ -0,0 +1,19 @@
+import { type Meta, type StoryObj } from '@storybook/angular';
+import { SearchFieldComponent } from './search-field.component';
+
+const meta: Meta<SearchFieldComponent> = {
+  title: 'Instant search/Search field',
+  component: SearchFieldComponent,
+  excludeStories: /.*Data$/,
+  tags: ['autodocs'],
+};
+
+export default meta;
+type Story = StoryObj<SearchFieldComponent>;
+
+export const Default: Story = {
+  args: {
+    label: '',
+    placeholder: 'search something...',
+  },
+};
diff --git a/alfa-client/libs/design-system/src/lib/instant-search/search-result-header/search-result-header.component.spec.ts b/alfa-client/libs/design-system/src/lib/instant-search/search-result-header/search-result-header.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..7c00b9a408879b4ce0c96c2a374edce5df6739c2
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/instant-search/search-result-header/search-result-header.component.spec.ts
@@ -0,0 +1,21 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { SearchResultHeaderComponent } from './search-result-header.component';
+
+describe('SearchResultHeaderComponent', () => {
+  let component: SearchResultHeaderComponent;
+  let fixture: ComponentFixture<SearchResultHeaderComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: [SearchResultHeaderComponent],
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(SearchResultHeaderComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/alfa-client/libs/design-system/src/lib/instant-search/search-result-header/search-result-header.component.ts b/alfa-client/libs/design-system/src/lib/instant-search/search-result-header/search-result-header.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..4ba8d7894dbddd157532a1418f175e28fa25c3b0
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/instant-search/search-result-header/search-result-header.component.ts
@@ -0,0 +1,17 @@
+import { CommonModule } from '@angular/common';
+import { Component, Input } from '@angular/core';
+
+@Component({
+  selector: 'ods-search-result-header',
+  standalone: true,
+  imports: [CommonModule],
+  template: `
+    <h3 class="mx-6 my-3 w-fit border-b-2 border-primary py-1 text-sm font-semibold text-text">
+      {{ text }} ({{ count }})
+    </h3>
+  `,
+})
+export class SearchResultHeaderComponent {
+  @Input({ required: true }) text!: string;
+  @Input() count: number = 0;
+}
diff --git a/alfa-client/libs/design-system/src/lib/instant-search/search-result-item/search-result-item.component.spec.ts b/alfa-client/libs/design-system/src/lib/instant-search/search-result-item/search-result-item.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..089692b213692a024ccf7d6dc07071bd9c25d812
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/instant-search/search-result-item/search-result-item.component.spec.ts
@@ -0,0 +1,46 @@
+import { getElementFromFixture, mock } from '@alfa-client/test-utils';
+import { EventEmitter } from '@angular/core';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { getDataTestIdOf } from 'libs/tech-shared/test/data-test';
+import { SearchResultItemComponent } from './search-result-item.component';
+
+describe('SearchResultItemComponent', () => {
+  let component: SearchResultItemComponent;
+  let fixture: ComponentFixture<SearchResultItemComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: [SearchResultItemComponent],
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(SearchResultItemComponent);
+    component = fixture.componentInstance;
+    component.title = 'Test';
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+
+  describe('itemClicked', () => {
+    it('should emit event', () => {
+      component.itemClicked = <any>mock(EventEmitter);
+      const button = getElementFromFixture(fixture, getDataTestIdOf('item-button'));
+
+      button.click();
+
+      expect(component.itemClicked.emit).toHaveBeenCalled();
+    });
+  });
+
+  describe('setFocus', () => {
+    it('should focus native element', () => {
+      component.buttonRef.nativeElement.focus = jest.fn();
+
+      component.setFocus();
+
+      expect(component.buttonRef.nativeElement.focus).toHaveBeenCalled();
+    });
+  });
+});
diff --git a/alfa-client/libs/design-system/src/lib/instant-search/search-result-item/search-result-item.component.ts b/alfa-client/libs/design-system/src/lib/instant-search/search-result-item/search-result-item.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ec65fb9ec1774751a28416ba22ae62a27895ad7c
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/instant-search/search-result-item/search-result-item.component.ts
@@ -0,0 +1,38 @@
+import { CommonModule } from '@angular/common';
+import { Component, ElementRef, EventEmitter, Input, Output, ViewChild } from '@angular/core';
+
+@Component({
+  selector: 'ods-search-result-item',
+  standalone: true,
+  imports: [CommonModule],
+  template: `<button
+    *ngIf="title"
+    [ngClass]="[
+      'flex w-full justify-between border-2 border-transparent px-6 py-3',
+      'hover:border-focus focus:border-focus focus:outline-none',
+    ]"
+    role="listitem"
+    tabindex="-1"
+    (click)="itemClicked.emit()"
+    data-test-id="item-button"
+    #button
+  >
+    <div class="flex flex-col items-start justify-between text-start text-text">
+      <p class="text-base font-medium">{{ title }}</p>
+      <p class="text-sm">{{ description }}</p>
+    </div>
+    <ng-content select="[action-button]" />
+  </button>`,
+})
+export class SearchResultItemComponent {
+  @Input({ required: true }) title!: string;
+  @Input() description: string = '';
+
+  @Output() public itemClicked: EventEmitter<MouseEvent> = new EventEmitter<MouseEvent>();
+
+  @ViewChild('button') buttonRef: ElementRef;
+
+  public setFocus() {
+    this.buttonRef.nativeElement.focus();
+  }
+}
diff --git a/alfa-client/libs/design-system/src/lib/instant-search/search-result-layer/search-result-layer.component.spec.ts b/alfa-client/libs/design-system/src/lib/instant-search/search-result-layer/search-result-layer.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d2c91333316ff8253ec828a228ce83b84514113c
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/instant-search/search-result-layer/search-result-layer.component.spec.ts
@@ -0,0 +1,21 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { SearchResultLayerComponent } from './search-result-layer.component';
+
+describe('SearchResultLayerComponent', () => {
+  let component: SearchResultLayerComponent;
+  let fixture: ComponentFixture<SearchResultLayerComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: [SearchResultLayerComponent],
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(SearchResultLayerComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/alfa-client/libs/design-system/src/lib/instant-search/search-result-layer/search-result-layer.component.ts b/alfa-client/libs/design-system/src/lib/instant-search/search-result-layer/search-result-layer.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..971e06b585e2292b36be429b6972ba91090ccaa0
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/instant-search/search-result-layer/search-result-layer.component.ts
@@ -0,0 +1,15 @@
+import { CommonModule } from '@angular/common';
+import { Component } from '@angular/core';
+
+@Component({
+  selector: 'ods-search-result-layer',
+  standalone: true,
+  imports: [CommonModule],
+  template: `<div class="rounded-lg border border-primary-600/50 bg-background-50 shadow-lg">
+    <ng-content select="[header]" />
+    <ul role="list">
+      <ng-content />
+    </ul>
+  </div>`,
+})
+export class SearchResultLayerComponent {}
diff --git a/alfa-client/libs/design-system/src/lib/instant-search/search-result-layer/search-result-layer.stories.ts b/alfa-client/libs/design-system/src/lib/instant-search/search-result-layer/search-result-layer.stories.ts
new file mode 100644
index 0000000000000000000000000000000000000000..02aa94c67050ca8ec652784afb653f56d596454b
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/instant-search/search-result-layer/search-result-layer.stories.ts
@@ -0,0 +1,30 @@
+import { moduleMetadata, type Meta, type StoryObj } from '@storybook/angular';
+import { SearchResultHeaderComponent } from '../search-result-header/search-result-header.component';
+import { SearchResultItemComponent } from '../search-result-item/search-result-item.component';
+import { SearchResultLayerComponent } from './search-result-layer.component';
+
+const meta: Meta<SearchResultLayerComponent> = {
+  title: 'Instant search/Search result layer',
+  component: SearchResultLayerComponent,
+  excludeStories: /.*Data$/,
+  tags: ['autodocs'],
+  decorators: [
+    moduleMetadata({
+      imports: [SearchResultItemComponent, SearchResultHeaderComponent],
+    }),
+  ],
+};
+
+export default meta;
+type Story = StoryObj<SearchResultLayerComponent>;
+
+export const Default: Story = {
+  args: {},
+  render: () => ({
+    template: `<ods-search-result-layer>
+      <ods-search-result-header text="In der OZG-Cloud" [count]="2" header />
+      <ods-search-result-item text="Amt Rantznau - Ordnungsamt" subText="Rathausmarkt 7, Kronshagen" />
+      <ods-search-result-item text="Amt Burg-St. Michaelisdonn - Der Amtsvorsteher" subText="Holzmarkt 7, 25712 Rantznau" />
+    </ods-search-result-layer>`,
+  }),
+};
diff --git a/alfa-client/libs/design-system/src/lib/popup/popup-list-item/popup-list-item.component.spec.ts b/alfa-client/libs/design-system/src/lib/popup/popup-list-item/popup-list-item.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..3d624f9674b26a1f03a2e024f0139f9eb8230746
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/popup/popup-list-item/popup-list-item.component.spec.ts
@@ -0,0 +1,32 @@
+import { dispatchEventFromFixture } from '@alfa-client/test-utils';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { PopupListItemComponent } from './popup-list-item.component';
+
+describe('PopupListItemComponent', () => {
+  let component: PopupListItemComponent;
+  let fixture: ComponentFixture<PopupListItemComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: [PopupListItemComponent],
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(PopupListItemComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+
+  describe('itemClicked emitter', () => {
+    it('should emit itemClicked', () => {
+      component.itemClicked.emit = jest.fn();
+
+      dispatchEventFromFixture(fixture, 'button', 'click');
+
+      expect(component.itemClicked.emit).toHaveBeenCalled();
+    });
+  });
+});
diff --git a/alfa-client/libs/design-system/src/lib/popup/popup-list-item/popup-list-item.component.ts b/alfa-client/libs/design-system/src/lib/popup/popup-list-item/popup-list-item.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..3bc88c4c30db6091ccf72a4e3658972fe4f117b6
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/popup/popup-list-item/popup-list-item.component.ts
@@ -0,0 +1,21 @@
+import { CommonModule } from '@angular/common';
+import { Component, EventEmitter, Input, Output } from '@angular/core';
+
+@Component({
+  selector: 'ods-popup-list-item',
+  standalone: true,
+  imports: [CommonModule],
+  template: `<button
+    class="flex min-h-12 w-full items-center gap-4 border-2 border-transparent bg-whitetext px-4 py-3 text-start outline-none hover:border-primary focus-visible:border-focus"
+    role="listitem"
+    (click)="itemClicked.emit()"
+  >
+    <ng-content select="[icon]" />
+    <p class="text-text">{{ caption }}</p>
+  </button>`,
+})
+export class PopupListItemComponent {
+  @Input({ required: true }) caption!: string;
+
+  @Output() itemClicked: EventEmitter<MouseEvent> = new EventEmitter();
+}
diff --git a/alfa-client/libs/design-system/src/lib/popup/popup-list-item/popup-list-item.stories.ts b/alfa-client/libs/design-system/src/lib/popup/popup-list-item/popup-list-item.stories.ts
new file mode 100644
index 0000000000000000000000000000000000000000..a28201314e94cc47b348fd9082f158ec06326174
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/popup/popup-list-item/popup-list-item.stories.ts
@@ -0,0 +1,24 @@
+import { moduleMetadata, type Meta, type StoryObj } from '@storybook/angular';
+
+import { PopupListItemComponent } from './popup-list-item.component';
+
+const meta: Meta<PopupListItemComponent> = {
+  title: 'Popup/Popup list item',
+  component: PopupListItemComponent,
+  decorators: [
+    moduleMetadata({
+      imports: [PopupListItemComponent],
+    }),
+  ],
+  excludeStories: /.*Data$/,
+  tags: ['autodocs'],
+};
+
+export default meta;
+type Story = StoryObj<PopupListItemComponent>;
+
+export const Default: Story = {
+  args: {
+    caption: 'List item',
+  },
+};
diff --git a/alfa-client/libs/design-system/src/lib/popup/popup/popup.component.spec.ts b/alfa-client/libs/design-system/src/lib/popup/popup/popup.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8d03abd239d9a8054e0efed06259e41bffb8d516
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/popup/popup/popup.component.spec.ts
@@ -0,0 +1,212 @@
+import { getElementFromFixture } from '@alfa-client/test-utils';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { getDataTestIdOf } from 'libs/tech-shared/test/data-test';
+import { PopupComponent } from './popup.component';
+
+describe('PopupComponent', () => {
+  let component: PopupComponent;
+  let fixture: ComponentFixture<PopupComponent>;
+  const popupButton: string = getDataTestIdOf('popup-button');
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: [PopupComponent],
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(PopupComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+
+  describe('togglePopup', () => {
+    it('should change false to true', () => {
+      component.isPopupOpen = false;
+
+      component.togglePopup();
+
+      expect(component.isPopupOpen).toBe(true);
+    });
+
+    it('should change true to false', () => {
+      component.isPopupOpen = true;
+
+      component.togglePopup();
+
+      expect(component.isPopupOpen).toBe(false);
+    });
+  });
+
+  describe('aria-expanded', () => {
+    it('should be true if popup is open', () => {
+      component.isPopupOpen = true;
+      fixture.detectChanges();
+
+      const buttonElement: HTMLElement = getElementFromFixture(fixture, popupButton);
+
+      expect(buttonElement.getAttribute('aria-expanded')).toBe('true');
+    });
+
+    it('should be false if popup is closed', () => {
+      component.isPopupOpen = false;
+      fixture.detectChanges();
+
+      const buttonElement: HTMLElement = getElementFromFixture(fixture, popupButton);
+
+      expect(buttonElement.getAttribute('aria-expanded')).toBe('false');
+    });
+  });
+
+  describe('isEscapeKey', () => {
+    it('should return true', () => {
+      const escapeKeyEvent: KeyboardEvent = {
+        ...new KeyboardEvent('esc'),
+        key: 'Escape',
+      };
+
+      const result: boolean = component.isEscapeKey(escapeKeyEvent);
+
+      expect(result).toBe(true);
+    });
+
+    it('should return false', () => {
+      const keyEvent: KeyboardEvent = new KeyboardEvent('whatever');
+
+      const result: boolean = component.isEscapeKey(keyEvent);
+
+      expect(result).toBe(false);
+    });
+  });
+
+  describe('closePopupAndFocusButton', () => {
+    beforeEach(() => {
+      component.isPopupOpen = true;
+      jest.spyOn(component.buttonRef.nativeElement, 'focus');
+    });
+    it('should close popup', () => {
+      component.closePopupAndFocusButton();
+
+      expect(component.isPopupOpen).toBe(false);
+    });
+
+    it('should focus button', () => {
+      component.closePopupAndFocusButton();
+
+      expect(component.buttonRef.nativeElement.focus).toHaveBeenCalled();
+    });
+  });
+
+  describe('isPopupClosed', () => {
+    it('should return true', () => {
+      component.isPopupOpen = false;
+
+      const result: boolean = component.isPopupClosed();
+
+      expect(result).toBe(true);
+    });
+
+    it('should return false', () => {
+      component.isPopupOpen = true;
+
+      const result: boolean = component.isPopupClosed();
+
+      expect(result).toBe(false);
+    });
+  });
+
+  describe('onKeydownHandler', () => {
+    const e: KeyboardEvent = new KeyboardEvent('test');
+
+    beforeEach(() => {
+      component.closePopupAndFocusButton = jest.fn();
+      component.isEscapeKey = jest.fn();
+    });
+
+    describe('popup is closed', () => {
+      beforeEach(() => {
+        component.isPopupClosed = jest.fn().mockReturnValue(true);
+      });
+
+      it('should not check for escape key', () => {
+        component.onKeydownHandler(e);
+
+        expect(component.isEscapeKey).not.toHaveBeenCalled();
+      });
+    });
+
+    describe('popup is open', () => {
+      beforeEach(() => {
+        component.isPopupClosed = jest.fn().mockReturnValue(false);
+      });
+
+      it('should check for escape key', () => {
+        component.onKeydownHandler(e);
+
+        expect(component.isEscapeKey).toHaveBeenCalled();
+      });
+
+      it('should handle escape key', () => {
+        component.isEscapeKey = jest.fn().mockReturnValue(true);
+
+        component.onKeydownHandler(e);
+
+        expect(component.closePopupAndFocusButton).toHaveBeenCalled();
+      });
+
+      it('should not handle escape key', () => {
+        component.onKeydownHandler(e);
+
+        expect(component.closePopupAndFocusButton).not.toHaveBeenCalled();
+      });
+    });
+  });
+  describe('onClickHandler', () => {
+    const e: MouseEvent = new MouseEvent('test');
+
+    beforeEach(() => {
+      component.closePopupAndFocusButton = jest.fn();
+      component.buttonRef.nativeElement.contains = jest.fn();
+    });
+
+    describe('popup is closed', () => {
+      beforeEach(() => {
+        component.isPopupClosed = jest.fn().mockReturnValue(true);
+      });
+
+      it('should not check for button containing event target', () => {
+        component.onClickHandler(e);
+
+        expect(component.buttonRef.nativeElement.contains).not.toHaveBeenCalled();
+      });
+    });
+
+    describe('popup is open', () => {
+      beforeEach(() => {
+        component.isPopupClosed = jest.fn().mockReturnValue(false);
+      });
+
+      it('should check for button containing event target', () => {
+        component.onClickHandler(e);
+
+        expect(component.buttonRef.nativeElement.contains).toHaveBeenCalled();
+      });
+
+      it('should handle click', () => {
+        component.onClickHandler(e);
+
+        expect(component.closePopupAndFocusButton).toHaveBeenCalled();
+      });
+
+      it('should not handle click', () => {
+        component.buttonRef.nativeElement.contains = jest.fn().mockReturnValue(true);
+
+        component.onClickHandler(e);
+
+        expect(component.closePopupAndFocusButton).not.toHaveBeenCalled();
+      });
+    });
+  });
+});
diff --git a/alfa-client/libs/design-system/src/lib/popup/popup/popup.component.ts b/alfa-client/libs/design-system/src/lib/popup/popup/popup.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..a4901d657b0d4d7246dcff422553a17fa60a31df
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/popup/popup/popup.component.ts
@@ -0,0 +1,76 @@
+import { CdkTrapFocus } from '@angular/cdk/a11y';
+import { CommonModule } from '@angular/common';
+import { Component, ElementRef, HostListener, Input, ViewChild } from '@angular/core';
+import { twMerge } from 'tailwind-merge';
+
+@Component({
+  selector: 'ods-popup',
+  standalone: true,
+  imports: [CommonModule, CdkTrapFocus],
+  template: `<div class="relative w-fit">
+    <button
+      class="w-fit outline-2 outline-offset-2 outline-focus"
+      [ngClass]="[twMerge('w-fit outline-2 outline-offset-2 outline-focus', buttonClass)]"
+      (click)="togglePopup()"
+      [attr.aria-expanded]="isPopupOpen"
+      aria-haspopup="true"
+      [attr.aria-label]="label"
+      data-test-id="popup-button"
+      #button
+    >
+      <ng-content select="[button]" />
+    </button>
+    <ul
+      *ngIf="isPopupOpen"
+      class="max-h-120 animate-fadeIn absolute min-w-44 max-w-80 overflow-y-auto rounded shadow-lg shadow-grayborder focus:outline-none"
+      [ngClass]="alignTo === 'left' ? 'right-0' : 'left-0'"
+      role="dialog"
+      aria-modal="true"
+      cdkTrapFocus
+      [cdkTrapFocusAutoCapture]="true"
+    >
+      <ng-content />
+    </ul>
+  </div>`,
+})
+export class PopupComponent {
+  @Input() alignTo: 'left' | 'right' = 'left';
+  @Input() label: string = '';
+  @Input() buttonClass: string = '';
+
+  isPopupOpen: boolean = false;
+  twMerge = twMerge;
+
+  @ViewChild('button') buttonRef: ElementRef<HTMLButtonElement>;
+
+  @HostListener('document:keydown', ['$event'])
+  onKeydownHandler(e: KeyboardEvent): void {
+    if (this.isPopupClosed()) return;
+    if (this.isEscapeKey(e)) this.closePopupAndFocusButton();
+  }
+
+  @HostListener('document:click', ['$event'])
+  onClickHandler(e: MouseEvent): void {
+    if (this.isPopupClosed()) return;
+    if (!this.buttonRef.nativeElement.contains(e.target as HTMLElement)) {
+      this.closePopupAndFocusButton();
+    }
+  }
+
+  togglePopup(): void {
+    this.isPopupOpen = !this.isPopupOpen;
+  }
+
+  closePopupAndFocusButton(): void {
+    this.isPopupOpen = false;
+    this.buttonRef.nativeElement.focus();
+  }
+
+  isEscapeKey(e: KeyboardEvent): boolean {
+    return e.key === 'Escape';
+  }
+
+  isPopupClosed(): boolean {
+    return !this.isPopupOpen;
+  }
+}
diff --git a/alfa-client/libs/design-system/src/lib/popup/popup/popup.stories.ts b/alfa-client/libs/design-system/src/lib/popup/popup/popup.stories.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ecde2c16145d2e95ddcd3327d51e003d27f721f6
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/popup/popup/popup.stories.ts
@@ -0,0 +1,78 @@
+import {
+  argsToTemplate,
+  componentWrapperDecorator,
+  moduleMetadata,
+  type Meta,
+  type StoryObj,
+} from '@storybook/angular';
+
+import { SaveIconComponent } from '../../icons/save-icon/save-icon.component';
+import { UserIconComponent } from '../../icons/user-icon/user-icon.component';
+import { PopupListItemComponent } from '../popup-list-item/popup-list-item.component';
+import { PopupComponent } from './popup.component';
+
+const meta: Meta<PopupComponent> = {
+  title: 'Popup/Popup',
+  component: PopupComponent,
+  decorators: [
+    moduleMetadata({
+      imports: [PopupComponent, PopupListItemComponent, SaveIconComponent, UserIconComponent],
+    }),
+    componentWrapperDecorator((story) => `<div class="flex justify-center mb-32">${story}</div>`),
+  ],
+  excludeStories: /.*Data$/,
+  tags: ['autodocs'],
+};
+
+export default meta;
+type Story = StoryObj<PopupComponent>;
+
+export const Default: Story = {
+  args: { alignTo: 'left', label: '', buttonClass: '' },
+  argTypes: {
+    alignTo: {
+      control: 'select',
+      options: ['left', 'right'],
+      table: {
+        defaultValue: { summary: 'left' },
+      },
+    },
+    buttonClass: { description: 'Tailwind class for button' },
+    label: { description: 'Aria-label for button' },
+  },
+  render: (args) => ({
+    props: args,
+    template: `<ods-popup ${argsToTemplate(args)}>
+        <ods-user-icon button />
+        <ods-popup-list-item caption="Lorem" />
+        <ods-popup-list-item caption="Ipsum" />
+        <ods-popup-list-item caption="Dolor" />
+      </ods-popup>`,
+  }),
+};
+
+export const LongText: Story = {
+  render: (args) => ({
+    props: args,
+    template: `<ods-popup ${argsToTemplate(args)}>
+        <p button>Trigger popup</p>
+        <ods-popup-list-item caption="Lorem" />
+        <ods-popup-list-item caption="Lorem ipsum dolor sit amet" />
+      </ods-popup>`,
+  }),
+};
+
+export const ItemsWithIcons: Story = {
+  render: (args) => ({
+    props: args,
+    template: `<ods-popup ${argsToTemplate(args)}>
+        <p button>Trigger popup</p>
+        <ods-popup-list-item caption="Lorem">
+          <ods-save-icon icon size="small" />
+        </ods-popup-list-item>
+        <ods-popup-list-item caption="Lorem ipsum dolor sit amet">
+          <ods-save-icon icon size="small" />
+        </ods-popup-list-item>
+      </ods-popup>`,
+  }),
+};
diff --git a/alfa-client/libs/design-system/src/lib/tailwind-preset/root.css b/alfa-client/libs/design-system/src/lib/tailwind-preset/root.css
index 7e997ffe4f9bfb19811dc99c99a708dd8d92e741..10ac4b918b2c3e41d10f5a1a0e41036a3cfdfc03 100644
--- a/alfa-client/libs/design-system/src/lib/tailwind-preset/root.css
+++ b/alfa-client/libs/design-system/src/lib/tailwind-preset/root.css
@@ -68,3 +68,7 @@
 .bescheid-dialog-backdrop {
   @apply bg-gray-500 bg-opacity-30 transition-opacity;
 }
+
+.blur-dialog-backdrop {
+  @apply bg-gray-400 bg-opacity-75 backdrop-blur-sm transition-opacity dark:bg-gray-500 dark:bg-opacity-75;
+}
diff --git a/alfa-client/libs/design-system/src/lib/tailwind-preset/tailwind.config.js b/alfa-client/libs/design-system/src/lib/tailwind-preset/tailwind.config.js
index 1c7b298d5afa17aae60ab57b36b9152cec514121..b17ef3c855216e3e735314a6e0b17984d4b3068f 100644
--- a/alfa-client/libs/design-system/src/lib/tailwind-preset/tailwind.config.js
+++ b/alfa-client/libs/design-system/src/lib/tailwind-preset/tailwind.config.js
@@ -13,7 +13,11 @@ module.exports = {
   darkMode: 'class',
   theme: {
     extend: {
-      animation: { dash: 'dash 1.5s ease-in-out infinite', 'spin-slow': 'spin 2s linear infinite' },
+      animation: {
+        dash: 'dash 1.5s ease-in-out infinite',
+        'spin-slow': 'spin 2s linear infinite',
+        fadeIn: 'fade-in 0.2s ease-in-out 1',
+      },
       keyframes: {
         dash: {
           from: {
@@ -29,10 +33,21 @@ module.exports = {
             'stroke-dashoffset': '-49',
           },
         },
+        'fade-in': {
+          '0%': {
+            opacity: 0,
+          },
+          '100%': {
+            opacity: 1,
+          },
+        },
       },
       borderWidth: {
         3: '3px',
       },
+      maxHeight: {
+        120: '480px',
+      },
       colors: {
         ozgblue: {
           50: 'hsl(200, 100%, 96%)',
@@ -100,6 +115,12 @@ module.exports = {
         error: 'hsl(var(--color-error))',
         focus: 'hsl(var(--color-focus))',
       },
+      backgroundColor: {
+        greybackdrop: 'rgb(229, 229, 229, 0.95)',
+      },
+      backdropBlur: {
+        1: '1px',
+      },
     },
   },
   plugins: [],
diff --git a/alfa-client/libs/design-system/src/test/search.ts b/alfa-client/libs/design-system/src/test/search.ts
new file mode 100644
index 0000000000000000000000000000000000000000..93b65de204918bfae7d639ba89d32f30e9c385f3
--- /dev/null
+++ b/alfa-client/libs/design-system/src/test/search.ts
@@ -0,0 +1,7 @@
+import { faker } from '@faker-js/faker';
+import { Resource } from '@ngxp/rest';
+import { InstantSearchResult } from '../lib/instant-search/instant-search/instant-search.model';
+
+export function createInstantSearchResult<T extends Resource>(data?: T): InstantSearchResult<T> {
+  return { title: faker.random.word(), description: faker.random.words(3), data };
+}
diff --git a/alfa-client/libs/historie/src/lib/historie-container/historie-list/historie-item-header/historie-item-header.component.scss b/alfa-client/libs/historie/src/lib/historie-container/historie-list/historie-item-header/historie-item-header.component.scss
index 9eea5298d9ed6bb65a9907b621cd78aad006e467..98885dff4e1dd8036f867f865eb57eb5c0fb4fa6 100644
--- a/alfa-client/libs/historie/src/lib/historie-container/historie-list/historie-item-header/historie-item-header.component.scss
+++ b/alfa-client/libs/historie/src/lib/historie-container/historie-list/historie-item-header/historie-item-header.component.scss
@@ -26,7 +26,7 @@
   white-space: nowrap;
   align-items: center;
   min-height: 44px;
-  font-size: 14px;
+  font-size: 0.875rem;
   width: 100%;
 }
 
diff --git a/alfa-client/libs/historie/src/lib/historie-container/historie-list/historie-item-vorgang-created/historie-item-vorgang-created.component.scss b/alfa-client/libs/historie/src/lib/historie-container/historie-list/historie-item-vorgang-created/historie-item-vorgang-created.component.scss
index f4e6e49e807966d56e3f9beae6b8a010ba4ed9a7..349c181b396d022cfc4fb9687f4baa47ea8a246b 100644
--- a/alfa-client/libs/historie/src/lib/historie-container/historie-list/historie-item-vorgang-created/historie-item-vorgang-created.component.scss
+++ b/alfa-client/libs/historie/src/lib/historie-container/historie-list/historie-item-vorgang-created/historie-item-vorgang-created.component.scss
@@ -29,7 +29,7 @@
   display: block;
   margin-top: 0.5rem;
   min-height: 44px;
-  font-size: 14px;
+  font-size: 0.875rem;
 }
 
 p {
diff --git a/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang/kommentar-list-item-in-vorgang/kommentar-list-item-in-vorgang.component.html b/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang/kommentar-list-item-in-vorgang/kommentar-list-item-in-vorgang.component.html
index 9a94d2795a84d8bad27b23be6e11bde8eec441c3..5564806d9103ba21af82622fda3aae70e8880595 100644
--- a/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang/kommentar-list-item-in-vorgang/kommentar-list-item-in-vorgang.component.html
+++ b/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang/kommentar-list-item-in-vorgang/kommentar-list-item-in-vorgang.component.html
@@ -24,7 +24,7 @@
 
 -->
 
-<div *ngIf="!editMode" class="plain-text">
+<div *ngIf="!editMode" class="plain-text text-sm">
   <button
     [attr.data-test-id]="'kommentar-item-' + (kommentar.text | convertForDataTest)"
     (click)="edit()"
@@ -36,7 +36,7 @@
         [kommentar]="kommentar"
         data-test-class="kommentar-created-by"
       ></alfa-user-profile-in-kommentar-container>
-      <span data-test-id="kommentar-created-at" class="date">{{
+      <span data-test-id="kommentar-created-at" class="date text-sm">{{
         kommentar.createdAt | formatDateWithTimePipe: false
       }}</span>
     </div>
diff --git a/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang/kommentar-list-item-in-vorgang/kommentar-list-item-in-vorgang.component.scss b/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang/kommentar-list-item-in-vorgang/kommentar-list-item-in-vorgang.component.scss
index bf52bd6b8383f611228097a4f129859c93fbdf78..9c44c9feeccad1edba5bb907ce9624b8d4c05b96 100644
--- a/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang/kommentar-list-item-in-vorgang/kommentar-list-item-in-vorgang.component.scss
+++ b/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang/kommentar-list-item-in-vorgang/kommentar-list-item-in-vorgang.component.scss
@@ -54,7 +54,6 @@ button {
 
   .date {
     flex-shrink: 0;
-    font-size: 13px;
   }
 }
 
diff --git a/alfa-client/libs/navigation/src/lib/build-info/build-info.component.html b/alfa-client/libs/navigation/src/lib/build-info/build-info.component.html
index 3befc6c17ff6c1c67843bb0969acfb0ed2ce4ef3..41cce668006927fdd81db4f1c49e8eaca49358cd 100644
--- a/alfa-client/libs/navigation/src/lib/build-info/build-info.component.html
+++ b/alfa-client/libs/navigation/src/lib/build-info/build-info.component.html
@@ -30,6 +30,6 @@
     <span data-test-id="build-time">{{ buildTime }}</span>
   </ng-container>
 </p>
-<p *ngIf="isNotProduction" data-test-id="not-production-text" class="test-environment">
+<p *ngIf="isNotProduction" data-test-id="not-production-text" class="test-environment text-error">
   Achtung Testumgebung
 </p>
diff --git a/alfa-client/libs/navigation/src/lib/build-info/build-info.component.scss b/alfa-client/libs/navigation/src/lib/build-info/build-info.component.scss
index ec3f82e9c13c393371836db8fecfca6ecc6467d5..73f433970c0765f31b0f88b78a30fad26513afdb 100644
--- a/alfa-client/libs/navigation/src/lib/build-info/build-info.component.scss
+++ b/alfa-client/libs/navigation/src/lib/build-info/build-info.component.scss
@@ -46,7 +46,7 @@ p {
   white-space: nowrap;
   font-style: normal;
   font-weight: 400;
-  font-size: 11px;
+  font-size: 0.6875rem;
   color: #999;
 
   &.version {
@@ -61,5 +61,4 @@ p {
   margin-right: $navigation-height + $header-height;
   letter-spacing: 0.42em;
   text-transform: uppercase;
-  color: #ff0000;
 }
diff --git a/alfa-client/libs/navigation/src/lib/header-container/header/header.component.html b/alfa-client/libs/navigation/src/lib/header-container/header/header.component.html
index 3ef7590196924bd350d246c4b084c71a1cc7cdd3..100cd3141dbcb8562608433313d8cdf30c0af56b 100644
--- a/alfa-client/libs/navigation/src/lib/header-container/header/header.component.html
+++ b/alfa-client/libs/navigation/src/lib/header-container/header/header.component.html
@@ -30,7 +30,7 @@
   <div class="middle">
     <alfa-vorgang-search-container></alfa-vorgang-search-container>
   </div>
-  <div class="right">
+  <div class="flex items-center text-ozggray-800 dark:text-ozggray-300">
     <alfa-help-menu
       [apiRootStateResource]="apiRootStateResource"
       data-test-id="help-menu"
diff --git a/alfa-client/libs/navigation/src/lib/header-container/header/header.component.scss b/alfa-client/libs/navigation/src/lib/header-container/header/header.component.scss
index 167169bea4acdf42c9032a84041bf48006b45809..4e6bde87b4b462a01803569bc823015ce6b9f535 100644
--- a/alfa-client/libs/navigation/src/lib/header-container/header/header.component.scss
+++ b/alfa-client/libs/navigation/src/lib/header-container/header/header.component.scss
@@ -53,9 +53,3 @@ header {
     min-width: 240px;
   }
 }
-
-.right {
-  color: $grey;
-  display: flex;
-  align-items: center;
-}
diff --git a/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-mail-form.component.scss b/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-mail-form.component.scss
index 5b22d572e2a37eb567ba59013f2fc06473826ff6..30d9608bbff2af095d57a37beb36da3bf8b91f7d 100644
--- a/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-mail-form.component.scss
+++ b/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-mail-form.component.scss
@@ -49,8 +49,7 @@
   margin-bottom: 4px;
 
   .label {
-    font-size: 10.5px;
-    opacity: 0.6;
+    font-size: 0.75rem;
   }
 
   .value {
diff --git a/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail/outgoing-mail/outgoing-mail-error-container/outgoing-mail-error/outgoing-mail-error.component.html b/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail/outgoing-mail/outgoing-mail-error-container/outgoing-mail-error/outgoing-mail-error.component.html
index ba6a2c55856a17a9780c64cbb785fd4ea54f96b8..ba91c347f14db1b8a045f6f1c19ee795f3618cb7 100644
--- a/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail/outgoing-mail/outgoing-mail-error-container/outgoing-mail-error/outgoing-mail-error.component.html
+++ b/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail/outgoing-mail/outgoing-mail-error-container/outgoing-mail-error/outgoing-mail-error.component.html
@@ -29,7 +29,7 @@
   class="mail-send-error"
 >
   <span data-test-id="mail-send-error-text">{{ message }}</span>
-  <mat-icon data-test-id="mail-send-error-icon" class="mail-send-error__icon mat-icon-error"
+  <mat-icon data-test-id="mail-send-error-icon" class="mail-send-error__icon text-error"
     >error_outline_white</mat-icon
   >
 </div>
diff --git a/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail/outgoing-mail/outgoing-mail-error-container/outgoing-mail-error/outgoing-mail-error.component.scss b/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail/outgoing-mail/outgoing-mail-error-container/outgoing-mail-error/outgoing-mail-error.component.scss
index d62fb722598b2db40eaa946e2e79722616ecaf0d..aadb9a11f319d4c53e79987a439f2647db86c7f8 100644
--- a/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail/outgoing-mail/outgoing-mail-error-container/outgoing-mail-error/outgoing-mail-error.component.scss
+++ b/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail/outgoing-mail/outgoing-mail-error-container/outgoing-mail-error/outgoing-mail-error.component.scss
@@ -25,10 +25,6 @@
 @use '@angular/material' as mat;
 @import 'variables';
 
-.mat-icon-error {
-  color: mat.get-color-from-palette($warnPalette);
-}
-
 .mail-send-error {
   display: flex;
   align-items: center;
diff --git a/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail/postfach-mail-date/postfach-mail-date.component.scss b/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail/postfach-mail-date/postfach-mail-date.component.scss
index 68891d3304c26291de9f600fa56848c0313f3974..3bfec3b5734dae42f7ecef3a563d6b859bf8111b 100644
--- a/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail/postfach-mail-date/postfach-mail-date.component.scss
+++ b/alfa-client/libs/postfach/src/lib/postfach-mail-list-container/postfach-mail-list/postfach-mail/postfach-mail-date/postfach-mail-date.component.scss
@@ -22,6 +22,6 @@
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
 .date {
-  font-size: 13px;
+  font-size: 0.875rem;
   white-space: nowrap;
 }
diff --git a/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page/postfach-page-mail-list/postfach-page-mail-list.component.html b/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page/postfach-page-mail-list/postfach-page-mail-list.component.html
index 3aac0b25924886e054d181ae7558219d0545e68d..42008dc0e49821e2041d2b5cf06a456f2026b8e4 100644
--- a/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page/postfach-page-mail-list/postfach-page-mail-list.component.html
+++ b/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page/postfach-page-mail-list/postfach-page-mail-list.component.html
@@ -30,7 +30,7 @@
         | toEmbeddedResources: postfachMailListLinkRel.POSTFACH_MAIL_LIST
     "
     [attr.data-test-id]="(postfachMail.subject | convertForDataTest) + '-item'"
-    class="postfach postfach-links-disabled"
+    class="postfach postfach-links-disabled w-full lg:w-1/2"
     [postfachMail]="postfachMail"
   >
   </alfa-postfach-mail>
diff --git a/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page/postfach-page-mail-list/postfach-page-mail-list.component.scss b/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page/postfach-page-mail-list/postfach-page-mail-list.component.scss
index 7aa658e02c12f707953b25897c98bbec80c6d55a..5d7c585646f315886cd9f453d97c87449abcb8b1 100644
--- a/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page/postfach-page-mail-list/postfach-page-mail-list.component.scss
+++ b/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page/postfach-page-mail-list/postfach-page-mail-list.component.scss
@@ -24,7 +24,6 @@
 .postfach {
   display: flex;
   flex-direction: column;
-  width: 100%;
   border-bottom: 1px solid rgb(0 0 0 / 8%);
   padding: 16px 24px 16px 28px;
   margin: 0;
@@ -33,7 +32,7 @@
     .subject {
       display: flex;
       align-items: center;
-      font-size: 16px;
+      font-size: 1rem;
       font-weight: 400;
       margin: 2px 0;
       position: relative;
@@ -53,7 +52,7 @@
     }
 
     .created-at {
-      font-size: 13px;
+      font-size: 0.875rem;
       position: absolute;
       right: 0;
       top: 0;
diff --git a/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page/postfach-page.component.html b/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page/postfach-page.component.html
index 8c220b59d27e750b5a1256abdfd85aaae346a9d6..0ffd6b1df26988e4f6fe93c69f4af1e52f9fc8a3 100644
--- a/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page/postfach-page.component.html
+++ b/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page/postfach-page.component.html
@@ -27,8 +27,10 @@
   <ozgcloud-back-button linkTo="../" label="zurück zur Detailseite"></ozgcloud-back-button>
 </ozgcloud-subnavigation>
 
-<div class="l-scroll-area--full">
-  <alfa-vorgang-in-postfach-breadcrumb-container></alfa-vorgang-in-postfach-breadcrumb-container>
+<div class="l-scroll-area--full flex flex-col">
+  <h1 data-test-id="postfach-mail-heading" class="pl-7 pt-4 text-lg font-medium">
+    Nachrichten zum Vorgang
+  </h1>
   <alfa-postfach-page-mail-list
     [postfachMailListStateResource]="postfachMailListStateResource"
     data-test-id="postfach-mail-list"
diff --git a/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page/postfach-page.component.spec.ts b/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page/postfach-page.component.spec.ts
index 3fa88754e5c94f6717ac4fea2a8d901c3022b6f4..034ad05b31e47a42fd9322fed0202822a746f9e7 100644
--- a/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page/postfach-page.component.spec.ts
+++ b/alfa-client/libs/postfach/src/lib/postfach-page-container/postfach-page/postfach-page.component.spec.ts
@@ -21,10 +21,9 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
+import { BackButtonComponent, SubnavigationComponent } from '@alfa-client/ui';
 import { ComponentFixture, TestBed } from '@angular/core/testing';
 import { MatIcon } from '@angular/material/icon';
-import { BackButtonComponent, SubnavigationComponent } from '@alfa-client/ui';
-import { VorgangInPostfachBreadcrumbContainerComponent } from '@alfa-client/vorgang-shared-ui';
 import { MockComponent } from 'ng-mocks';
 import { PostfachPageMailListComponent } from './postfach-page-mail-list/postfach-page-mail-list.component';
 import { PostfachPageComponent } from './postfach-page.component';
@@ -41,7 +40,6 @@ describe('PostfachPageComponent', () => {
         MockComponent(BackButtonComponent),
         MockComponent(SubnavigationComponent),
         MockComponent(PostfachPageMailListComponent),
-        MockComponent(VorgangInPostfachBreadcrumbContainerComponent),
       ],
     }).compileComponents();
   });
diff --git a/alfa-client/libs/tech-shared/src/index.ts b/alfa-client/libs/tech-shared/src/index.ts
index 64e34b9ffcb66244bb7687070f685ed6090b4950..970130b8c3cc71fccd268eb842d34a249f578750 100644
--- a/alfa-client/libs/tech-shared/src/index.ts
+++ b/alfa-client/libs/tech-shared/src/index.ts
@@ -33,6 +33,7 @@ export * from './lib/message-code';
 export * from './lib/ngrx/actions';
 export * from './lib/pipe/convert-api-error-to-error-messages.pipe';
 export * from './lib/pipe/convert-for-data-test.pipe';
+export * from './lib/pipe/convert-problem-detail-to-error-messages.pipe';
 export * from './lib/pipe/convert-to-boolean.pipe';
 export * from './lib/pipe/enum-to-label.pipe';
 export * from './lib/pipe/file-size.pipe';
@@ -48,6 +49,7 @@ export * from './lib/pipe/to-traffic-light-tooltip.pipe';
 export * from './lib/pipe/to-traffic-light.pipe';
 export * from './lib/resource/api-resource.service';
 export * from './lib/resource/list-resource.service';
+export * from './lib/resource/resource-search.service';
 export * from './lib/resource/resource.model';
 export * from './lib/resource/resource.repository';
 export * from './lib/resource/resource.rxjs.operator';
diff --git a/alfa-client/libs/tech-shared/src/lib/pipe/convert-for-data-test.pipe.ts b/alfa-client/libs/tech-shared/src/lib/pipe/convert-for-data-test.pipe.ts
index e056b77eb22f32ed6c2b9c9765c5101252acef18..cd455ac7098fe6f33d9883b87963e56900d2caec 100644
--- a/alfa-client/libs/tech-shared/src/lib/pipe/convert-for-data-test.pipe.ts
+++ b/alfa-client/libs/tech-shared/src/lib/pipe/convert-for-data-test.pipe.ts
@@ -27,7 +27,7 @@ import { convertForDataTest } from '../tech.util';
 
 @Pipe({ name: 'convertForDataTest' })
 export class ConvertForDataTestPipe implements PipeTransform {
-  transform(value: string) {
+  transform(value: string): string {
     return isNil(value) ? null : convertForDataTest(value);
   }
 }
diff --git a/alfa-client/libs/tech-shared/src/lib/pipe/convert-problem-detail-to-error-messages.pipe.spec.ts b/alfa-client/libs/tech-shared/src/lib/pipe/convert-problem-detail-to-error-messages.pipe.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ffef78f2195217763693fbd09abf727915afac23
--- /dev/null
+++ b/alfa-client/libs/tech-shared/src/lib/pipe/convert-problem-detail-to-error-messages.pipe.spec.ts
@@ -0,0 +1,42 @@
+import { createInvalidParam, createProblemDetail } from '../../../test/error';
+import { InvalidParam, ProblemDetail } from '../tech.model';
+import { ValidationMessageCode } from '../validation/tech.validation.messages';
+import * as TechValidationUtil from '../validation/tech.validation.util';
+import { ConvertProblemDetailToErrorMessagesPipe } from './convert-problem-detail-to-error-messages.pipe';
+
+describe('convertProblemDetailToErrorMessages', () => {
+  const pipe = new ConvertProblemDetailToErrorMessagesPipe();
+
+  it('create an instance', () => {
+    expect(pipe).toBeTruthy();
+  });
+
+  describe('transform', () => {
+    const getMessageForInvalidParam = jest.spyOn(TechValidationUtil, 'getMessageForInvalidParam');
+
+    it('should not call getMessageForInvalidParam', () => {
+      pipe.transform(null);
+
+      expect(getMessageForInvalidParam).not.toHaveBeenCalled();
+    });
+
+    it('should call getMessageForInvalidParam', () => {
+      pipe.transform(createProblemDetail());
+
+      expect(getMessageForInvalidParam).toHaveBeenCalled();
+    });
+
+    it('should return array of error messages', () => {
+      const expectedErrorMessage = 'Bitte  ausfüllen';
+      const invalidParam: InvalidParam = {
+        ...createInvalidParam(),
+        reason: ValidationMessageCode.FIELD_EMPTY,
+      };
+      const problemDetail: ProblemDetail = createProblemDetail([invalidParam]);
+
+      const errorMessages: string[] = pipe.transform(problemDetail);
+
+      expect(errorMessages).toEqual([expectedErrorMessage]);
+    });
+  });
+});
diff --git a/alfa-client/libs/tech-shared/src/lib/pipe/convert-problem-detail-to-error-messages.pipe.ts b/alfa-client/libs/tech-shared/src/lib/pipe/convert-problem-detail-to-error-messages.pipe.ts
new file mode 100644
index 0000000000000000000000000000000000000000..437483a923c7f85353b96a745a2c24e1cc88e0fb
--- /dev/null
+++ b/alfa-client/libs/tech-shared/src/lib/pipe/convert-problem-detail-to-error-messages.pipe.ts
@@ -0,0 +1,17 @@
+import { Pipe, PipeTransform } from '@angular/core';
+import { isNil } from 'lodash-es';
+import { InvalidParam, ProblemDetail } from '../tech.model';
+import { EMPTY_STRING } from '../tech.util';
+import { getMessageForInvalidParam } from '../validation/tech.validation.util';
+
+@Pipe({ name: 'convertProblemDetailToErrorMessages' })
+export class ConvertProblemDetailToErrorMessagesPipe implements PipeTransform {
+  transform(value: ProblemDetail) {
+    if (isNil(value)) {
+      return [];
+    }
+    return value.invalidParams.map((invalidParam: InvalidParam) =>
+      getMessageForInvalidParam(EMPTY_STRING, invalidParam),
+    );
+  }
+}
diff --git a/alfa-client/libs/tech-shared/src/lib/pipe/file-size-plain.pipe.ts b/alfa-client/libs/tech-shared/src/lib/pipe/file-size-plain.pipe.ts
index 275302f1ae582e7b6060a4ecb23266cb2eea729e..43492c8fac7194f393a0fed2f69635372804d255 100644
--- a/alfa-client/libs/tech-shared/src/lib/pipe/file-size-plain.pipe.ts
+++ b/alfa-client/libs/tech-shared/src/lib/pipe/file-size-plain.pipe.ts
@@ -6,13 +6,13 @@ export class FileSizePlainPipe implements PipeTransform {
   readonly MB = Math.pow(this.kB, 2);
   readonly GB = Math.pow(this.kB, 3);
 
-  transform(size: number) {
+  transform(size: number): string {
     if (size >= this.GB) return this.formatFileSize(size / this.GB, 'GB');
     if (size >= this.MB) return this.formatFileSize(size / this.MB, 'MB');
     return this.formatFileSize(size / this.kB, 'kB');
   }
 
-  private formatFileSize(number: number, unit: string) {
+  private formatFileSize(number: number, unit: string): string {
     return `${number.toFixed(2).replace('.', ',')} ${unit}`;
   }
 }
diff --git a/alfa-client/libs/tech-shared/src/lib/pipe/file-size.pipe.ts b/alfa-client/libs/tech-shared/src/lib/pipe/file-size.pipe.ts
index a8ca257d0b3687a5684b809694a56c421ae43ffd..31fb3d58dd0a46c21578be37e853e3b09997825e 100644
--- a/alfa-client/libs/tech-shared/src/lib/pipe/file-size.pipe.ts
+++ b/alfa-client/libs/tech-shared/src/lib/pipe/file-size.pipe.ts
@@ -29,13 +29,13 @@ export class FileSizePipe implements PipeTransform {
   readonly MB = Math.pow(this.kB, 2);
   readonly GB = Math.pow(this.kB, 3);
 
-  transform(size: number) {
+  transform(size: number): string {
     if (size >= this.GB) return this.formatFileSize(size / this.GB, 'GB');
     if (size >= this.MB) return this.formatFileSize(size / this.MB, 'MB');
     return this.formatFileSize(size / this.kB, 'kB');
   }
 
-  private formatFileSize(number: number, unit: string) {
+  private formatFileSize(number: number, unit: string): string {
     return `${number.toFixed(2).replace('.', ',')}<span class="unit">${unit}</span>`;
   }
 }
diff --git a/alfa-client/libs/tech-shared/src/lib/pipe/get-url.pipe.spec.ts b/alfa-client/libs/tech-shared/src/lib/pipe/get-url.pipe.spec.ts
index d28782d0fef619b1cb5297d23e938957686b0b02..7387cf4d9b4d7279a9b8bddecedc0b48a670f6b7 100644
--- a/alfa-client/libs/tech-shared/src/lib/pipe/get-url.pipe.spec.ts
+++ b/alfa-client/libs/tech-shared/src/lib/pipe/get-url.pipe.spec.ts
@@ -1,5 +1,5 @@
 import faker from '@faker-js/faker';
-import { Resource } from '@ngxp/rest';
+import { Resource, ResourceUri } from '@ngxp/rest';
 import { GetUrlPipe } from './get-url.pipe';
 
 describe('GetUrlPipe', () => {
@@ -15,7 +15,7 @@ describe('GetUrlPipe', () => {
   const pipe: GetUrlPipe = new GetUrlPipe();
 
   it('should return resource url', () => {
-    const result: string = pipe.transform(resource, selfLink);
+    const result: ResourceUri = pipe.transform(resource, selfLink);
 
     expect(result).toBe(url);
   });
diff --git a/alfa-client/libs/tech-shared/src/lib/pipe/get-url.pipe.ts b/alfa-client/libs/tech-shared/src/lib/pipe/get-url.pipe.ts
index 0c130a8548597cfbcac2bf8d911b5bd1ee6ab175..32a4ee089847b5cd38365b6cd52683ba06b81203 100644
--- a/alfa-client/libs/tech-shared/src/lib/pipe/get-url.pipe.ts
+++ b/alfa-client/libs/tech-shared/src/lib/pipe/get-url.pipe.ts
@@ -1,9 +1,9 @@
 import { Pipe, PipeTransform } from '@angular/core';
-import { Resource, getUrl } from '@ngxp/rest';
+import { Resource, ResourceUri, getUrl } from '@ngxp/rest';
 
 @Pipe({ name: 'getUrl' })
 export class GetUrlPipe implements PipeTransform {
-  transform(resource: Resource, link: string) {
+  transform(resource: Resource, link: string): ResourceUri {
     return getUrl(resource, link);
   }
 }
diff --git a/alfa-client/libs/tech-shared/src/lib/pipe/has-link.pipe.ts b/alfa-client/libs/tech-shared/src/lib/pipe/has-link.pipe.ts
index 70ac58beccf1b77fe59f7c50bd0b0fa2a0f6f254..311e6b39d2816155469a906027f76784881a5155 100644
--- a/alfa-client/libs/tech-shared/src/lib/pipe/has-link.pipe.ts
+++ b/alfa-client/libs/tech-shared/src/lib/pipe/has-link.pipe.ts
@@ -22,11 +22,11 @@
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
 import { Pipe, PipeTransform } from '@angular/core';
-import { hasLink, Resource } from '@ngxp/rest';
+import { Resource, hasLink } from '@ngxp/rest';
 
 @Pipe({ name: 'hasLink' })
 export class HasLinkPipe implements PipeTransform {
-  transform(resource: Resource, link: string) {
+  transform(resource: Resource, link: string): boolean {
     return hasLink(resource, link);
   }
 }
diff --git a/alfa-client/libs/tech-shared/src/lib/pipe/not-has-link.pipe.ts b/alfa-client/libs/tech-shared/src/lib/pipe/not-has-link.pipe.ts
index 8f8f786c562cf744e412b91f62a66827897535c7..e7bb7f28d2e877e4918e6119103238b839c05e56 100644
--- a/alfa-client/libs/tech-shared/src/lib/pipe/not-has-link.pipe.ts
+++ b/alfa-client/libs/tech-shared/src/lib/pipe/not-has-link.pipe.ts
@@ -22,11 +22,11 @@
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
 import { Pipe, PipeTransform } from '@angular/core';
-import { hasLink, Resource } from '@ngxp/rest';
+import { Resource, hasLink } from '@ngxp/rest';
 
 @Pipe({ name: 'notHasLink' })
 export class NotHasLinkPipe implements PipeTransform {
-  transform(resource: Resource, link: string) {
+  transform(resource: Resource, link: string): boolean {
     return !hasLink(resource, link);
   }
 }
diff --git a/alfa-client/libs/tech-shared/src/lib/pipe/to-embedded-resource.pipe.spec.ts b/alfa-client/libs/tech-shared/src/lib/pipe/to-embedded-resource.pipe.spec.ts
index 309a04197539defcfa29b8320840d4f84aab7721..a4873730938d80aa0efe333f7177aca4e2e4ff28 100644
--- a/alfa-client/libs/tech-shared/src/lib/pipe/to-embedded-resource.pipe.spec.ts
+++ b/alfa-client/libs/tech-shared/src/lib/pipe/to-embedded-resource.pipe.spec.ts
@@ -24,34 +24,36 @@
 import { getEmbeddedResource } from '@ngxp/rest';
 import { DummyListLinkRel } from 'libs/tech-shared/test/dummy';
 import { createDummyListResource } from 'libs/tech-shared/test/resource';
+import { ListResource } from '../resource/resource.util';
+import { EMPTY_ARRAY } from '../tech.util';
 import { ToEmbeddedResourcesPipe } from './to-embedded-resource.pipe';
 
 describe('ToEmbeddedResourcesPipe', () => {
-  const pipe = new ToEmbeddedResourcesPipe();
+  const pipe: ToEmbeddedResourcesPipe = new ToEmbeddedResourcesPipe();
 
   it('create an instance', () => {
     expect(pipe).toBeTruthy();
   });
 
   describe('transform listResource to resources by link', () => {
-    const listResource = createDummyListResource([DummyListLinkRel.LIST]);
+    const listResource: ListResource = createDummyListResource([DummyListLinkRel.LIST]);
 
     it('should return embedded resources', () => {
-      const result = pipe.transform(listResource, DummyListLinkRel.LIST);
+      const result: unknown[] = pipe.transform(listResource, DummyListLinkRel.LIST);
 
       expect(result).toBe(getEmbeddedResource(listResource, DummyListLinkRel.LIST));
     });
 
-    it('should return null by empty listResource', () => {
-      const result = pipe.transform(null, DummyListLinkRel.LIST);
+    it('should return an empty array on null as listResource', () => {
+      const result: unknown[] = pipe.transform(null, DummyListLinkRel.LIST);
 
-      expect(result).toBe(null);
+      expect(result).toBe(EMPTY_ARRAY);
     });
 
-    it('should return null by empty linkel', () => {
-      const result = pipe.transform(listResource, null);
+    it('should return empty array on null as linkel', () => {
+      const result: unknown[] = pipe.transform(listResource, null);
 
-      expect(result).toBe(null);
+      expect(result).toBe(EMPTY_ARRAY);
     });
   });
 });
diff --git a/alfa-client/libs/tech-shared/src/lib/pipe/to-embedded-resource.pipe.ts b/alfa-client/libs/tech-shared/src/lib/pipe/to-embedded-resource.pipe.ts
index 53aec73b8461648669ba4f95b7d4aa1ecb3c5021..77e51945183b3b392c2b3d49647af0bf4a0e02ea 100644
--- a/alfa-client/libs/tech-shared/src/lib/pipe/to-embedded-resource.pipe.ts
+++ b/alfa-client/libs/tech-shared/src/lib/pipe/to-embedded-resource.pipe.ts
@@ -22,13 +22,16 @@
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
 import { Pipe, PipeTransform } from '@angular/core';
-import { getEmbeddedResource } from '@ngxp/rest';
+import { Resource, getEmbeddedResource } from '@ngxp/rest';
 import { isNil } from 'lodash-es';
+import { LinkRelationName } from '../resource/resource.model';
+import { ListResource } from '../resource/resource.util';
+import { EMPTY_ARRAY } from '../tech.util';
 
 @Pipe({ name: 'toEmbeddedResources' })
 export class ToEmbeddedResourcesPipe implements PipeTransform {
-  transform(listResource: any, linkRel: any) {
-    if (isNil(listResource) || isNil(linkRel)) return null;
+  transform(listResource: ListResource, linkRel: LinkRelationName): Resource[] {
+    if (isNil(listResource) || isNil(linkRel)) return EMPTY_ARRAY;
     return getEmbeddedResource(listResource, linkRel);
   }
 }
diff --git a/alfa-client/libs/tech-shared/src/lib/pipe/to-resource-uri.pipe.spec.ts b/alfa-client/libs/tech-shared/src/lib/pipe/to-resource-uri.pipe.spec.ts
index 6f709453705f390368bf511ccef753555b246769..389a82c47e1526c02c5464eb41cddc507d86c49e 100644
--- a/alfa-client/libs/tech-shared/src/lib/pipe/to-resource-uri.pipe.spec.ts
+++ b/alfa-client/libs/tech-shared/src/lib/pipe/to-resource-uri.pipe.spec.ts
@@ -21,7 +21,7 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-import { getUrl, Resource } from '@ngxp/rest';
+import { getUrl, Resource, ResourceUri } from '@ngxp/rest';
 import { createDummyResource } from 'libs/tech-shared/test/resource';
 import { decodeUrlFromEmbedding } from '../tech.util';
 import { ToResourceUriPipe } from './to-resource-uri.pipe';
@@ -38,14 +38,14 @@ describe('ToResourceUriPipe', () => {
     const dummyResource: Resource = createDummyResource();
 
     it('output as expected', () => {
-      const pipeResult: string = pipe.transform(dummyResource);
+      const pipeResult: ResourceUri = pipe.transform(dummyResource);
 
       const result: string = decodeUrlFromEmbedding(pipeResult);
 
       expect(result).toBe(getUrl(dummyResource));
     });
     it('replace "/" with "_" if necessary', () => {
-      const pipeResult: string = pipe.transform({
+      const pipeResult: ResourceUri = pipe.transform({
         _links: { self: { href: base64ResultWithSlash } },
       });
 
@@ -60,7 +60,7 @@ describe('ToResourceUriPipe', () => {
     const dummyResourceWithLink: Resource = createDummyResource([linkRel]);
 
     it('output as expected', () => {
-      const pipeResult: string = pipe.transform(dummyResourceWithLink, linkRel);
+      const pipeResult: ResourceUri = pipe.transform(dummyResourceWithLink, linkRel);
 
       const result: string = decodeUrlFromEmbedding(pipeResult);
 
diff --git a/alfa-client/libs/tech-shared/src/lib/pipe/to-resource-uri.pipe.ts b/alfa-client/libs/tech-shared/src/lib/pipe/to-resource-uri.pipe.ts
index 4c1d7971cd774eb1b53fc0b6bda21744f1a5235b..30d6f4c7e466d6f7e43075af5bc7f74a534c6557 100644
--- a/alfa-client/libs/tech-shared/src/lib/pipe/to-resource-uri.pipe.ts
+++ b/alfa-client/libs/tech-shared/src/lib/pipe/to-resource-uri.pipe.ts
@@ -22,13 +22,13 @@
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
 import { Pipe, PipeTransform } from '@angular/core';
-import { Resource } from '@ngxp/rest';
+import { Resource, ResourceUri } from '@ngxp/rest';
 import { isNil } from 'lodash-es';
 import { toResourceUri } from '../resource/resource.util';
 
 @Pipe({ name: 'toResourceUri' })
 export class ToResourceUriPipe implements PipeTransform {
-  transform(resource: Resource, linkRel?: string): string {
+  transform(resource: Resource, linkRel?: string): ResourceUri {
     if (isNil(resource)) {
       return null;
     }
diff --git a/alfa-client/libs/tech-shared/src/lib/resource/resource-search.service.spec.ts b/alfa-client/libs/tech-shared/src/lib/resource/resource-search.service.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..acbd45df651fd4343be7601e8a9886850f133f0e
--- /dev/null
+++ b/alfa-client/libs/tech-shared/src/lib/resource/resource-search.service.spec.ts
@@ -0,0 +1,194 @@
+import { Mock, mock, useFromMock } from '@alfa-client/test-utils';
+import { fakeAsync, tick } from '@angular/core/testing';
+import faker from '@faker-js/faker';
+import { Resource } from '@ngxp/rest';
+import { DummyLinkRel } from 'libs/tech-shared/test/dummy';
+import { createDummyListResource, createDummyResource } from 'libs/tech-shared/test/resource';
+import { BehaviorSubject, Observable, of } from 'rxjs';
+import { singleColdCompleted } from '../../../test/marbles';
+import { EMPTY_STRING } from '../tech.util';
+import { ResourceSearchService } from './resource-search.service';
+import { LinkRelationName, ListItemResource, SearchResourceServiceConfig } from './resource.model';
+import { ResourceRepository } from './resource.repository';
+import {
+  ListResource,
+  StateResource,
+  createEmptyStateResource,
+  createStateResource,
+} from './resource.util';
+
+describe('ResourceSearchService', () => {
+  let service: ResourceSearchService<Resource, ListResource, ListItemResource>;
+  let config: SearchResourceServiceConfig<Resource>;
+  let repository: Mock<ResourceRepository>;
+
+  const baseResource: Resource = createDummyResource();
+  const baseResourceSubj: BehaviorSubject<Resource> = new BehaviorSubject<Resource>(baseResource);
+  const searchLinkRel: LinkRelationName = DummyLinkRel.DUMMY;
+
+  const listResource: ListResource = createDummyListResource();
+  const stateListResource: StateResource<ListResource> = createStateResource(listResource);
+
+  const searchBy: string = faker.random.words(2);
+
+  beforeEach(() => {
+    config = {
+      baseResource: baseResourceSubj,
+      searchLinkRel,
+    };
+    repository = mock(ResourceRepository);
+
+    service = new ResourceSearchService(config, useFromMock(repository));
+  });
+
+  it('should be created', () => {
+    expect(service).toBeTruthy();
+  });
+
+  describe('get result list', () => {
+    beforeEach(() => {
+      service.handleChanges = jest.fn();
+
+      service.listResource.next(stateListResource);
+      service.searchBy.next(searchBy);
+    });
+
+    it('should call handleChanges', fakeAsync(() => {
+      service.getResultList().subscribe();
+      tick();
+
+      expect(service.handleChanges).toHaveBeenCalledWith(stateListResource, searchBy, baseResource);
+    }));
+
+    it('should return value', (done) => {
+      service.getResultList().subscribe((resultList) => {
+        expect(resultList).toBe(stateListResource);
+        done();
+      });
+    });
+  });
+
+  describe('handle changes', () => {
+    it('should call doSearch on loading flag', () => {
+      service.doSearch = jest.fn();
+
+      service.handleChanges({ ...stateListResource, loading: true }, searchBy, baseResource);
+
+      expect(service.doSearch).toHaveBeenCalledWith(searchBy, baseResource);
+    });
+
+    it('should NOT call doSearch on loading flag false', () => {
+      service.doSearch = jest.fn();
+
+      service.handleChanges({ ...stateListResource, loading: false }, searchBy, baseResource);
+
+      expect(service.doSearch).not.toHaveBeenCalled();
+    });
+  });
+
+  describe('do search', () => {
+    beforeEach(() => {
+      service.dispatchSearch = jest.fn();
+    });
+    describe('on existing searchBy', () => {
+      it('should call dispatchSearch', () => {
+        service.doSearch(searchBy, baseResource);
+
+        expect(service.dispatchSearch).toHaveBeenCalledWith(baseResource, searchLinkRel, searchBy);
+      });
+
+      it('should NOT clear list resource', () => {
+        service.listResource.next(stateListResource);
+
+        service.doSearch(searchBy, baseResource);
+
+        expect(service.listResource.value).toBe(stateListResource);
+      });
+    });
+
+    describe('on empty searchBy', () => {
+      it('should clear list resource', () => {
+        service.listResource.next(stateListResource);
+
+        service.doSearch(EMPTY_STRING, baseResource);
+
+        expect(service.listResource.value).toEqual(createEmptyStateResource());
+      });
+
+      it('should NOT call dispatchSearch', () => {
+        service.doSearch(EMPTY_STRING, baseResource);
+
+        expect(service.dispatchSearch).not.toHaveBeenCalled();
+      });
+    });
+  });
+
+  describe('dispatch search', () => {
+    beforeEach(() => {
+      repository.search.mockReturnValue(of(listResource));
+    });
+
+    it('should call respository', () => {
+      service.dispatchSearch(baseResource, searchLinkRel, searchBy);
+
+      expect(repository.search).toHaveBeenCalledWith(baseResource, searchLinkRel, searchBy);
+    });
+
+    it('should update list resource', () => {
+      service.listResource.next(createEmptyStateResource());
+
+      service.dispatchSearch(baseResource, searchLinkRel, searchBy);
+
+      expect(service.listResource.value).toEqual(createStateResource(listResource));
+    });
+  });
+
+  describe('clear search list', () => {
+    it('should call dispatchClearSearch listResource by given result', () => {
+      service.listResource.next(stateListResource);
+
+      service.clearResultList();
+
+      expect(service.listResource.value).toEqual(createEmptyStateResource());
+    });
+  });
+
+  describe('saerch', () => {
+    it('should set searchBy', () => {
+      service.search(searchBy);
+
+      expect(service.searchBy.value).toEqual(searchBy);
+    });
+
+    it('should set list resource loading', () => {
+      service.listResource.next(stateListResource);
+
+      service.search(searchBy);
+
+      expect(service.listResource.value).toEqual({ ...stateListResource, loading: true });
+    });
+  });
+
+  describe('get selected', () => {
+    const dummyResource: Resource = createDummyResource();
+
+    it('should return selected resource', () => {
+      service.getSelectedResult = jest.fn().mockReturnValue(of(dummyResource));
+      const selectedResult$: Observable<Resource> = service.getSelectedResult();
+
+      expect(selectedResult$).toBeObservable(singleColdCompleted(dummyResource));
+    });
+  });
+
+  describe('select result', () => {
+    const dummyResource: Resource = createDummyResource();
+
+    it('should update selected resource', () => {
+      service.selectedResource.next(null);
+
+      service.selectResult(dummyResource);
+
+      expect(service.selectedResource.value).toEqual(dummyResource);
+    });
+  });
+});
diff --git a/alfa-client/libs/tech-shared/src/lib/resource/resource-search.service.ts b/alfa-client/libs/tech-shared/src/lib/resource/resource-search.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d23b4be986f9a8fb880e582c5925f525459bf3dc
--- /dev/null
+++ b/alfa-client/libs/tech-shared/src/lib/resource/resource-search.service.ts
@@ -0,0 +1,101 @@
+import { Resource } from '@ngxp/rest';
+import { isEmpty } from 'lodash-es';
+import { BehaviorSubject, Observable, first, map, tap, withLatestFrom } from 'rxjs';
+import { EMPTY_STRING, isNotEmpty } from '../tech.util';
+import { LinkRelationName, ListItemResource, SearchResourceServiceConfig } from './resource.model';
+import { ResourceRepository } from './resource.repository';
+import {
+  ListResource,
+  StateResource,
+  createEmptyStateResource,
+  createStateResource,
+} from './resource.util';
+
+/**
+ * B = Type of baseresource
+ * T = Type of listresource
+ * I = Type of items in listresource
+ */
+export class ResourceSearchService<
+  B extends Resource,
+  T extends ListResource,
+  I extends ListItemResource,
+> {
+  readonly listResource: BehaviorSubject<StateResource<T>> = new BehaviorSubject(
+    createEmptyStateResource(),
+  );
+  readonly searchBy: BehaviorSubject<string> = new BehaviorSubject<string>(EMPTY_STRING);
+  readonly selectedResource: BehaviorSubject<I> = new BehaviorSubject<I>(null);
+
+  constructor(
+    private config: SearchResourceServiceConfig<B>,
+    private repository: ResourceRepository,
+  ) {}
+
+  public getResultList(): Observable<StateResource<T>> {
+    return this.selectListResource().pipe(
+      withLatestFrom(this.selectSearchBy(), this.config.baseResource),
+      tap(([listResource, searchBy, baseResource]) => {
+        this.handleChanges(listResource, searchBy, baseResource);
+      }),
+      map(([listResource]) => listResource),
+    );
+  }
+
+  private selectListResource(): Observable<StateResource<T>> {
+    return this.listResource.asObservable();
+  }
+
+  private selectSearchBy(): Observable<string> {
+    return this.searchBy.asObservable();
+  }
+
+  handleChanges(listResource: StateResource<T>, searchBy: string, baseResource: B): void {
+    if (listResource.loading) this.doSearch(searchBy, baseResource);
+  }
+
+  doSearch(searchBy: string, baseResource: B): void {
+    if (isNotEmpty(searchBy)) {
+      this.dispatchSearch(baseResource, this.config.searchLinkRel, searchBy);
+    }
+    if (isEmpty(searchBy)) {
+      this.dispatchClearSearchList();
+    }
+  }
+
+  dispatchSearch(baseResource: B, linkRel: LinkRelationName, searchBy: string): void {
+    this.repository
+      .search<T>(baseResource, linkRel, searchBy)
+      .pipe(first())
+      .subscribe((result: T) => this.dispatchSearchSuccess(result));
+  }
+
+  private dispatchSearchSuccess(result: T): void {
+    this.listResource.next(createStateResource(result));
+  }
+
+  public clearResultList(): void {
+    this.dispatchClearSearchList();
+  }
+
+  private dispatchClearSearchList(): void {
+    this.listResource.next(createEmptyStateResource());
+  }
+
+  public search(searchBy: string): void {
+    this.dispatchInitSearch(searchBy);
+  }
+
+  private dispatchInitSearch(searchBy: string): void {
+    this.searchBy.next(searchBy);
+    this.listResource.next({ ...this.listResource.value, loading: true });
+  }
+
+  public getSelectedResult(): Observable<I> {
+    return this.selectedResource.asObservable();
+  }
+
+  public selectResult(selected: I): void {
+    this.selectedResource.next(selected);
+  }
+}
diff --git a/alfa-client/libs/tech-shared/src/lib/resource/resource.model.ts b/alfa-client/libs/tech-shared/src/lib/resource/resource.model.ts
index 5fa5264f32b11a057af8755641f61d02b001fc46..bbc1b169e432eadfe036aea7e0446a2ba1840910 100644
--- a/alfa-client/libs/tech-shared/src/lib/resource/resource.model.ts
+++ b/alfa-client/libs/tech-shared/src/lib/resource/resource.model.ts
@@ -30,3 +30,8 @@ export interface ResourceServiceConfig<B> {
   delete?: { linkRel: LinkRelationName; order?: string };
   edit?: { linkRel: LinkRelationName; order?: string };
 }
+
+export interface SearchResourceServiceConfig<B> {
+  baseResource: Observable<B>;
+  searchLinkRel: LinkRelationName;
+}
diff --git a/alfa-client/libs/tech-shared/src/lib/resource/resource.repository.spec.ts b/alfa-client/libs/tech-shared/src/lib/resource/resource.repository.spec.ts
index d9b2b8cd5662996a5c8eb0129e54779ee289a105..2c8c97bfd4304f4bad5545a11cbe97dcb8a7258f 100644
--- a/alfa-client/libs/tech-shared/src/lib/resource/resource.repository.spec.ts
+++ b/alfa-client/libs/tech-shared/src/lib/resource/resource.repository.spec.ts
@@ -203,4 +203,62 @@ describe('ResourceRepository', () => {
       expect(result).toBeObservable(singleHot(deletedResource));
     });
   });
+
+  describe('search', () => {
+    const linkRel: string = DummyLinkRel.DUMMY;
+    const dummyResource: Resource = createDummyResource([linkRel]);
+    const searchBy: string = faker.random.word();
+
+    const searchUrl: string = faker.internet.url();
+
+    const dummyListResource: ListResource = createDummyListResource();
+
+    it('should call buildSearchUri', () => {
+      repository.buildSearchUri = jest.fn();
+
+      repository.search(dummyResource, linkRel, searchBy);
+
+      expect(repository.buildSearchUri).toHaveBeenCalledWith(
+        new URL(getUrl(dummyResource, linkRel)),
+        searchBy,
+      );
+    });
+
+    it('should call resourceFactory', () => {
+      repository.buildSearchUri = jest.fn().mockReturnValue(searchUrl);
+
+      repository.search(dummyResource, linkRel, searchBy);
+
+      expect(resourceFactory.fromId).toHaveBeenCalledWith(searchUrl);
+    });
+
+    it('should call resourceWrapper', () => {
+      repository.buildSearchUri = jest.fn().mockReturnValue(searchUrl);
+
+      repository.search(dummyResource, linkRel, searchBy);
+
+      expect(resourceWrapper.get).toHaveBeenCalled();
+    });
+
+    it('should return result', () => {
+      repository.buildSearchUri = jest.fn().mockReturnValue(searchUrl);
+      resourceWrapper.get.mockReturnValue(singleCold(dummyListResource));
+
+      const result: Observable<Resource> = repository.search(dummyResource, linkRel, searchBy);
+
+      expect(result).not.toBeNull();
+      expect(result).toBeObservable(singleHot(dummyListResource));
+    });
+
+    describe('build search uri', () => {
+      const url: URL = new URL('http://test/searchit?searchBy={searchBy}');
+      const searchBy: string = faker.random.word();
+
+      it('should return uri contains searchBy param', () => {
+        const searchUri: ResourceUri = repository.buildSearchUri(url, searchBy);
+
+        expect(searchUri).toEqual(`http://test/searchit?searchBy=${searchBy}`);
+      });
+    });
+  });
 });
diff --git a/alfa-client/libs/tech-shared/src/lib/resource/resource.repository.ts b/alfa-client/libs/tech-shared/src/lib/resource/resource.repository.ts
index 386819910fd1aa3b9fd58349e7a9034f72530982..b0fcb3995f0961983b8caef53160762ad3fc4416 100644
--- a/alfa-client/libs/tech-shared/src/lib/resource/resource.repository.ts
+++ b/alfa-client/libs/tech-shared/src/lib/resource/resource.repository.ts
@@ -6,6 +6,8 @@ import { ListResource } from './resource.util';
 
 @Injectable({ providedIn: 'root' })
 export class ResourceRepository {
+  static SEARCH_PARAM: string = 'searchBy';
+
   constructor(private resourceFactory: ResourceFactory) {}
 
   public getListResource(resource: Resource, linkRel: string): Observable<ListResource> {
@@ -39,4 +41,15 @@ export class ResourceRepository {
   public delete(resource: Resource, linkRel: LinkRelationName): Observable<Resource> {
     return this.resourceFactory.from(resource).delete(linkRel);
   }
+
+  public search<T>(resource: Resource, linkRel: LinkRelationName, searchBy: string): Observable<T> {
+    return this.resourceFactory
+      .fromId(this.buildSearchUri(new URL(getUrl(resource, linkRel)), searchBy))
+      .get();
+  }
+
+  buildSearchUri(url: URL, searchBy: string): ResourceUri {
+    url.searchParams.set(ResourceRepository.SEARCH_PARAM, searchBy);
+    return url.href;
+  }
 }
diff --git a/alfa-client/libs/tech-shared/src/lib/service/formservice.abstract.spec.ts b/alfa-client/libs/tech-shared/src/lib/service/formservice.abstract.spec.ts
index 1472e6fe3c880b33faeaf14e875f6973dde18a73..ee4a624cb890cbf0da636f80ae01f1aeb7fdc616 100644
--- a/alfa-client/libs/tech-shared/src/lib/service/formservice.abstract.spec.ts
+++ b/alfa-client/libs/tech-shared/src/lib/service/formservice.abstract.spec.ts
@@ -25,12 +25,12 @@ import { CommandResource } from '@alfa-client/command-shared';
 import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup } from '@angular/forms';
 import { Resource } from '@ngxp/rest';
 import { cold } from 'jest-marbles';
-import { createApiError, createInvalidParam, createIssue, createProblemDetail } from 'libs/tech-shared/test/error';
+import { createInvalidParam, createProblemDetail } from 'libs/tech-shared/test/error';
 import { Observable, of } from 'rxjs';
 import { AbstractFormService } from './formservice.abstract';
 
 import { createEmptyStateResource, createErrorStateResource, createStateResource, StateResource } from '../resource/resource.util';
-import { ApiError, HttpError, InvalidParam, Issue, ProblemDetail } from '../tech.model';
+import { HttpError, InvalidParam, ProblemDetail } from '../tech.model';
 
 import { createCommandResource } from '../../../../command-shared/test/command';
 import * as ValidationUtil from '../validation/tech.validation.util';
@@ -47,16 +47,16 @@ describe('AbstractFormService', () => {
   });
 
   describe('submit', () => {
-    describe('with api error', () => {
-      const stateResourceWithError: StateResource<ApiError> =
-        createErrorStateResource(createApiError());
+    describe('with ProblemDetail', () => {
+      const stateResourceWithError: StateResource<ProblemDetail> =
+        createErrorStateResource(createProblemDetail());
 
       beforeEach(() => {
         TestFormService.SUBMIT_OBSERVABLE = () => of(stateResourceWithError);
         formService.handleResponse = jest.fn((stateResource) => stateResource);
       });
 
-      it('should call handle response for api error', (done) => {
+      it('should call handle response for ProblemDetail', (done) => {
         formService.submit().subscribe(() => {
           expect(formService.handleResponse).toHaveBeenCalledWith(stateResourceWithError);
           done();
@@ -97,8 +97,8 @@ describe('AbstractFormService', () => {
   });
 
   describe('handleResponse', () => {
-    const apiError: ApiError = createApiError();
-    const stateResource: StateResource<CommandResource> = createErrorStateResource(apiError);
+    const problemDetail: ProblemDetail = createProblemDetail();
+    const stateResource: StateResource<CommandResource> = createErrorStateResource(problemDetail);
 
     beforeEach(() => {
       formService.handleError = jest.fn();
@@ -107,7 +107,7 @@ describe('AbstractFormService', () => {
     it('should handleError on validation error', () => {
       formService.handleResponse({ ...stateResource, loading: false });
 
-      expect(formService.handleError).toHaveBeenCalledWith(apiError);
+      expect(formService.handleError).toHaveBeenCalledWith(problemDetail);
     });
 
     it('should return stateresource while loading', () => {
@@ -129,34 +129,6 @@ describe('AbstractFormService', () => {
 
       expect(formService.setErrorByProblemDetail).toHaveBeenCalledWith(problemDetail);
     });
-
-    it('should set api error', () => {
-      formService.setErrorByApiError = jest.fn();
-      const apiError: ApiError = createApiError();
-
-      formService.handleError(apiError);
-
-      expect(formService.setErrorByApiError).toHaveBeenCalledWith(apiError);
-    });
-  });
-
-  describe('set error by api error', () => {
-    const issue: Issue = createIssue();
-    const apiError: ApiError = createApiError([issue]);
-
-    it('should call setIssueValidationError', () => {
-      const setInvalidParamValidationErrorSpy: jest.SpyInstance<void> = jest
-        .spyOn(ValidationUtil, 'setIssueValidationError')
-        .mockImplementation();
-
-      formService.setErrorByApiError(apiError);
-
-      expect(setInvalidParamValidationErrorSpy).toHaveBeenCalledWith(
-        formService.form,
-        issue,
-        TestFormService.PATH_PREFIX,
-      );
-    });
   });
 
   describe('set error by problem detail', () => {
diff --git a/alfa-client/libs/tech-shared/src/lib/service/formservice.abstract.ts b/alfa-client/libs/tech-shared/src/lib/service/formservice.abstract.ts
index ab647437a8483fb73bccc4fa0e4d083ef8c48cde..956266f7c268dc575e7e29307b0530a31555f43f 100644
--- a/alfa-client/libs/tech-shared/src/lib/service/formservice.abstract.ts
+++ b/alfa-client/libs/tech-shared/src/lib/service/formservice.abstract.ts
@@ -28,16 +28,16 @@ import { isNil } from 'lodash-es';
 import { identity, Observable, OperatorFunction } from 'rxjs';
 import { map } from 'rxjs/operators';
 import { hasStateResourceError, StateResource } from '../resource/resource.util';
-import { ApiError, HttpError, InvalidParam, Issue, ProblemDetail } from '../tech.model';
+import { HttpError, InvalidParam, ProblemDetail } from '../tech.model';
 import { isNotUndefined } from '../tech.util';
-import { setInvalidParamValidationError, setIssueValidationError } from '../validation/tech.validation.util';
+import { setInvalidParamValidationError } from '../validation/tech.validation.util';
 
-export abstract class AbstractFormService {
+export abstract class AbstractFormService<T extends Resource = Resource> {
   form: UntypedFormGroup;
   pathPrefix: string;
   source: any;
 
-  private readonly PROBLEM_DETAIL_INVALID_PARAMS_KEY: string = 'invalid-params';
+  private readonly PROBLEM_DETAIL_INVALID_PARAMS_KEY: string = 'invalidParams';
 
   constructor(public formBuilder: UntypedFormBuilder) {
     this.form = this.initForm();
@@ -46,17 +46,17 @@ export abstract class AbstractFormService {
   protected abstract initForm(): UntypedFormGroup;
 
   public submit(
-    afterSubmit: OperatorFunction<StateResource<Resource>, StateResource<Resource>> = identity,
-  ): Observable<StateResource<Resource | HttpError>> {
+    afterSubmit: OperatorFunction<StateResource<T>, StateResource<T>> = identity,
+  ): Observable<StateResource<T | HttpError>> {
     return this.doSubmit().pipe(
       afterSubmit,
       map((result) => this.handleResponse(result)),
     );
   }
 
-  protected abstract doSubmit(): Observable<StateResource<Resource | HttpError>>;
+  protected abstract doSubmit(): Observable<StateResource<T | HttpError>>;
 
-  handleResponse(result: StateResource<Resource | HttpError>): StateResource<Resource | HttpError> {
+  handleResponse(result: StateResource<T | HttpError>): StateResource<T | HttpError> {
     if (result.loading) return result;
     if (hasStateResourceError(result)) {
       this.handleError(result.error);
@@ -65,28 +65,15 @@ export abstract class AbstractFormService {
   }
 
   handleError(error: HttpError): void {
-    if (this.isApiError(error)) {
-      this.setErrorByApiError(<ApiError>error);
-    }
-    if (this.isProblemDetail(error)) {
+    if (this.hasError(error)) {
       this.setErrorByProblemDetail(<ProblemDetail>error);
     }
   }
 
-  private isApiError(error: HttpError): boolean {
-    return isNotUndefined((<ApiError>error).issues);
-  }
-
-  private isProblemDetail(error: HttpError): boolean {
+  private hasError(error: HttpError): boolean {
     return isNotUndefined((<ProblemDetail>error)[this.PROBLEM_DETAIL_INVALID_PARAMS_KEY]);
   }
 
-  setErrorByApiError(apiError: ApiError): void {
-    apiError.issues.forEach((issue: Issue) =>
-      setIssueValidationError(this.form, issue, this.getPathPrefix()),
-    );
-  }
-
   setErrorByProblemDetail(error: ProblemDetail): void {
     error[this.PROBLEM_DETAIL_INVALID_PARAMS_KEY].forEach((invalidParam: InvalidParam) => {
       setInvalidParamValidationError(this.form, invalidParam, this.getPathPrefix());
diff --git a/alfa-client/libs/tech-shared/src/lib/tech-shared.module.ts b/alfa-client/libs/tech-shared/src/lib/tech-shared.module.ts
index 331031b298487fcfa77df7c10041a33cfedec7bb..a91930ffa732c82e0be57db7f18516b24eb393c9 100644
--- a/alfa-client/libs/tech-shared/src/lib/tech-shared.module.ts
+++ b/alfa-client/libs/tech-shared/src/lib/tech-shared.module.ts
@@ -29,6 +29,7 @@ import { HttpXsrfInterceptor } from './interceptor/http-xsrf.interceptor';
 import { XhrInterceptor } from './interceptor/xhr.interceptor';
 import { ConvertApiErrorToErrorMessagesPipe } from './pipe/convert-api-error-to-error-messages.pipe';
 import { ConvertForDataTestPipe } from './pipe/convert-for-data-test.pipe';
+import { ConvertProblemDetailToErrorMessagesPipe } from './pipe/convert-problem-detail-to-error-messages.pipe';
 import { ConvertToBooleanPipe } from './pipe/convert-to-boolean.pipe';
 import { EnumToLabelPipe } from './pipe/enum-to-label.pipe';
 import { FileSizePlainPipe } from './pipe/file-size-plain.pipe';
@@ -69,6 +70,7 @@ import { ToTrafficLightPipe } from './pipe/to-traffic-light.pipe';
     GetUrlPipe,
     ConvertToBooleanPipe,
     ConvertApiErrorToErrorMessagesPipe,
+    ConvertProblemDetailToErrorMessagesPipe,
   ],
   exports: [
     FormatToPrettyDatePipe,
@@ -90,6 +92,7 @@ import { ToTrafficLightPipe } from './pipe/to-traffic-light.pipe';
     GetUrlPipe,
     ConvertToBooleanPipe,
     ConvertApiErrorToErrorMessagesPipe,
+    ConvertProblemDetailToErrorMessagesPipe,
   ],
   providers: [
     {
diff --git a/alfa-client/libs/tech-shared/src/lib/tech.model.ts b/alfa-client/libs/tech-shared/src/lib/tech.model.ts
index c85852676e5184152aa17856cca07bd33b3a3223..869313d09ddd0b5c7703f80ea79f23bf72403e07 100644
--- a/alfa-client/libs/tech-shared/src/lib/tech.model.ts
+++ b/alfa-client/libs/tech-shared/src/lib/tech.model.ts
@@ -47,12 +47,19 @@ export interface ProblemDetail {
   status: HttpStatusCode;
   detail: string;
   instance: string;
-  'invalid-params': InvalidParam[];
+  invalidParams: InvalidParam[];
 }
 
 export interface InvalidParam {
+  constraintParameters: ConstraintParameter[];
   name: string;
   reason: ValidationMessageCode;
+  value: string;
+}
+
+export interface ConstraintParameter {
+  name: string;
+  value: string;
 }
 
 export declare type HttpError = ProblemDetail | ApiError;
diff --git a/alfa-client/libs/tech-shared/src/lib/validation/tech.validation.messages.ts b/alfa-client/libs/tech-shared/src/lib/validation/tech.validation.messages.ts
index 6c71c22768bb5ae231daf6b3522002a9110bda00..82da103d936c9c009cdfb20a9b1e652cf5b41648 100644
--- a/alfa-client/libs/tech-shared/src/lib/validation/tech.validation.messages.ts
+++ b/alfa-client/libs/tech-shared/src/lib/validation/tech.validation.messages.ts
@@ -22,23 +22,31 @@
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
 export enum ValidationMessageCode {
-  VALIDATION_FIELD_FILE_SIZE_EXCEEDED = 'validation_field_file_size_exceeded',
-  VALIDATION_FIELD_EMPTY = 'validation_field_empty',
-  VALIDATION_FIELD_FILE_CONTENT_TYPE_INVALID = 'validation_field_file_content_type_invalid',
+  FIELD_FILE_SIZE_EXCEEDED = 'validation_field_file_size_exceeded',
+  FIELD_EMPTY = 'validation_field_empty',
+  FIELD_SIZE = 'validation_field_size',
+  FIELD_FILE_CONTENT_TYPE_INVALID = 'validation_field_file_content_type_invalid',
+  FIELD_MIN_SIZE = 'validation_field_min_size',
+  FIELD_MAX_SIZE = 'validation_field_max_size',
+  FIELD_DATE_PAST = 'validation_field_date_past',
+  FIELD_INVALID = 'validation_field_invalid',
+  FIELD_DATE_FORMAT_INVALID = 'validation_field_date_format_invalid',
+  FIELD_ASSIGN_BEARBEITER_NOT_EXIST = 'fe_only_validation_bearbeiter_not_exist',
 }
 
 export const VALIDATION_MESSAGES: { [code: string]: string } = {
-  [ValidationMessageCode.VALIDATION_FIELD_EMPTY]: 'Bitte {field} ausfüllen',
-  validation_field_max_size: '{field} darf höchstens {max} Zeichen enthalten',
-  validation_field_min_size: '{field} muss aus mindestens {min} Zeichen bestehen',
-  validation_field_size: '{field} muss mindestens {min} und darf höchstens {max} Zeichen enthalten',
-  validation_field_date_past: 'Das Datum für {field} muss in der Zukunft liegen',
-  validation_field_invalid: 'Bitte {field} korrekt ausfüllen',
-  [ValidationMessageCode.VALIDATION_FIELD_FILE_SIZE_EXCEEDED]:
+  [ValidationMessageCode.FIELD_EMPTY]: 'Bitte {field} ausfüllen',
+  [ValidationMessageCode.FIELD_MAX_SIZE]: '{field} darf höchstens {max} Zeichen enthalten',
+  [ValidationMessageCode.FIELD_MIN_SIZE]: '{field} muss aus mindestens {min} Zeichen bestehen',
+  [ValidationMessageCode.FIELD_SIZE]:
+    '{field} muss mindestens {min} und darf höchstens {max} Zeichen enthalten',
+  [ValidationMessageCode.FIELD_DATE_PAST]: 'Das Datum für {field} muss in der Zukunft liegen',
+  [ValidationMessageCode.FIELD_INVALID]: 'Bitte {field} korrekt ausfüllen',
+  [ValidationMessageCode.FIELD_FILE_SIZE_EXCEEDED]:
     'Anhänge größer {max}{unit} können nicht hinzugefügt werden.',
 
   fe_only_validation_bearbeiter_not_exist: 'Der Bearbeiter existiert nicht',
-  validation_field_date_format_invalid: 'Geben Sie ein gültiges Datum ein',
-  [ValidationMessageCode.VALIDATION_FIELD_FILE_CONTENT_TYPE_INVALID]:
+  [ValidationMessageCode.FIELD_DATE_FORMAT_INVALID]: 'Geben Sie ein gültiges Datum ein',
+  [ValidationMessageCode.FIELD_FILE_CONTENT_TYPE_INVALID]:
     'Erlaubte Dateiendungen: pdf, jpg, png, jpeg',
 };
diff --git a/alfa-client/libs/tech-shared/src/lib/validation/tech.validation.util.spec.ts b/alfa-client/libs/tech-shared/src/lib/validation/tech.validation.util.spec.ts
index 9e0902270b2423a9510872b1a5f15828549eb8d6..bb2e5b51d1be004bced187df35871e16a00d738a 100644
--- a/alfa-client/libs/tech-shared/src/lib/validation/tech.validation.util.spec.ts
+++ b/alfa-client/libs/tech-shared/src/lib/validation/tech.validation.util.spec.ts
@@ -21,23 +21,12 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-import {
-  AbstractControl,
-  FormControl,
-  FormGroup,
-  UntypedFormControl,
-  UntypedFormGroup,
-} from '@angular/forms';
-import { createInvalidParam, createIssue } from '../../../test/error';
+import { AbstractControl, FormControl, FormGroup, UntypedFormControl, UntypedFormGroup } from '@angular/forms';
+import { faker } from '@faker-js/faker';
+import { createInvalidParam, createIssue, createProblemDetail } from '../../../test/error';
 import { InvalidParam, Issue } from '../tech.model';
-import {
-  getControlForInvalidParam,
-  getControlForIssue,
-  getMessageForInvalidParam,
-  getMessageForIssue,
-  setInvalidParamValidationError,
-  setIssueValidationError,
-} from './tech.validation.util';
+import { VALIDATION_MESSAGES, ValidationMessageCode } from './tech.validation.messages';
+import { getControlForInvalidParam, getControlForIssue, getFieldPath, getMessageForInvalidParam, getMessageForIssue, getMessageReason, setInvalidParamValidationError, setIssueValidationError } from './tech.validation.util';
 
 describe('ValidationUtils', () => {
   const baseField1Control: FormControl = new UntypedFormControl();
@@ -55,7 +44,7 @@ describe('ValidationUtils', () => {
   describe('set issue validation error', () => {
     describe('get control for issue', () => {
       it('should return base field control', () => {
-        const issue: Issue = { ...createIssue(), field: 'baseField1' };
+        const issue: Issue = { ...createIssue(), field: 'class.resource.baseField1' };
 
         const control: AbstractControl = getControlForIssue(form, issue);
 
@@ -63,24 +52,24 @@ describe('ValidationUtils', () => {
       });
 
       it('should return sub group field', () => {
-        const issue: Issue = { ...createIssue(), field: 'subGroup.subGroupField1' };
+        const issue: Issue = { ...createIssue(), field: 'class.resource.subGroup.subGroupField1' };
 
-        const control: AbstractControl = getControlForIssue(form, issue);
+        const control: AbstractControl = getControlForIssue(form, issue, 'resource');
 
         expect(control).toBe(subGroupFieldControl);
       });
 
       it('should ignore path prefix', () => {
-        const issue: Issue = { ...createIssue(), field: 'pathprefix.resource.baseField1' };
+        const issue: Issue = { ...createIssue(), field: 'class.resource.baseField1' };
 
-        const control: AbstractControl = getControlForIssue(form, issue, 'pathprefix.resource');
+        const control: AbstractControl = getControlForIssue(form, issue, 'resource');
 
         expect(control).toBe(baseField1Control);
       });
     });
 
     describe('in base field', () => {
-      const issue: Issue = { ...createIssue(), field: 'baseField1' };
+      const issue: Issue = { ...createIssue(), field: 'class.resource.baseField1' };
 
       it('should set error in control', () => {
         setIssueValidationError(form, issue);
@@ -108,10 +97,10 @@ describe('ValidationUtils', () => {
     });
 
     describe('in subGroup Field', () => {
-      const issue: Issue = { ...createIssue(), field: 'subGroup.subGroupField1' };
+      const issue: Issue = { ...createIssue(), field: 'class.resource.subGroup.subGroupField1' };
 
       it('should set error in control', () => {
-        setIssueValidationError(form, issue);
+        setIssueValidationError(form, issue, 'resource');
 
         expect(subGroupFieldControl.errors).not.toBeNull();
       });
@@ -150,102 +139,200 @@ describe('ValidationUtils', () => {
     });
   });
 
-  describe('invalid param', () => {
-    const formPrefixes: string[] = ['', 'some-prefix'];
-    const fieldNames: string[] = ['baseField1', 'baseField2', 'subGroup.subGroupField1'];
-    const prefixNameCombinations: string[][] = formPrefixes.flatMap((prefix) =>
-      fieldNames.map((name) => [prefix, name]),
-    );
-    const unknownName = 'unknown-field';
-
-    describe.each(prefixNameCombinations)(
-      'with prefix "%s" and fieldName "%s"',
-      (prefix, fieldName) => {
-        let invalidParam: InvalidParam;
-
-        beforeEach(() => {
-          form.reset();
-          invalidParam = {
-            ...createInvalidParam(),
-            name: prefix.length ? `${prefix}.${fieldName}` : fieldName,
-          };
-        });
-
-        describe('get message for invalid param', () => {
-          it('should return', () => {
-            const msg: string = getMessageForInvalidParam(invalidParam, prefix);
-
-            expect(msg).toEqual(`Bitte ${fieldName} ausfüllen`);
-          });
-        });
-
-        describe('get control for invalid param', () => {
-          it('should find', () => {
-            const control: AbstractControl = getControlForInvalidParam(form, invalidParam, prefix);
-
-            expect(control).toBeTruthy();
-          });
-        });
-
-        describe('set invalid param validation error', () => {
-          it('should assign invalidParam to form control error without prefix', () => {
-            const message: string = getMessageForInvalidParam(invalidParam, prefix);
-
-            setInvalidParamValidationError(form, invalidParam, prefix);
-
-            const errorMessage: string = form.getError(invalidParam.reason, fieldName);
-            expect(errorMessage).toBe(message);
-          });
-
-          it('should mark form as touched', () => {
-            setInvalidParamValidationError(form, invalidParam, prefix);
-
-            expect(form.touched).toBeTruthy();
-          });
-        });
-      },
-    );
-
-    describe.each([
-      ['', '', 'unknown-field'],
-      ['valid-prefix', 'valid-prefix', 'unknown-field'],
-      ['valid-prefix', 'valid-prefix', 'subGroup.unknown-field'],
-      ['unknown-prefix', 'valid-prefix', 'unknown-field'],
-      ['unknown-prefix', 'valid-prefix', 'baseField1'],
-    ])(
-      'with pathPrefix "%s", paramPrefix "%s", and field-name "%s"',
-      (pathPrefix, paramPrefix, fieldName) => {
-        let invalidParam: InvalidParam;
-
-        beforeEach(() => {
-          form.reset();
-          invalidParam = createInvalidParam();
-          invalidParam.name = paramPrefix.length > 0 ? `${paramPrefix}.${fieldName}` : fieldName;
-        });
-
-        it('should not find form control', () => {
-          const control: AbstractControl = getControlForInvalidParam(
-            form,
-            invalidParam,
-            pathPrefix,
-          );
-
-          expect(control).toBeFalsy();
-        });
-
-        it('should not assign to field control error', () => {
-          setInvalidParamValidationError(form, invalidParam, pathPrefix);
-
-          const errorMessage = form.getError(invalidParam.reason, unknownName);
-          expect(errorMessage).toBeFalsy();
-        });
-
-        it('should not mark as touched', () => {
-          setInvalidParamValidationError(form, invalidParam, pathPrefix);
-
-          expect(form.touched).toBeFalsy();
-        });
-      },
-    );
+  describe('set invalidParam validation error', () => {
+    describe('get control for invalidParam', () => {
+      it('should return base field control', () => {
+        const invalidParam: InvalidParam = {
+          ...createInvalidParam(),
+          name: 'class.resource.baseField1',
+        };
+
+        const control: AbstractControl = getControlForInvalidParam(form, invalidParam);
+
+        expect(control).toBe(baseField1Control);
+      });
+
+      it('should return sub group field', () => {
+        const invalidParam: InvalidParam = {
+          ...createInvalidParam(),
+          name: 'class.resource.subGroup.subGroupField1',
+        };
+
+        const control: AbstractControl = getControlForInvalidParam(form, invalidParam, 'resource');
+
+        expect(control).toBe(subGroupFieldControl);
+      });
+
+      it('should ignore path prefix', () => {
+        const invalidParam: InvalidParam = {
+          ...createInvalidParam(),
+          name: 'class.resource.baseField1',
+        };
+
+        const control: AbstractControl = getControlForInvalidParam(form, invalidParam, 'resource');
+
+        expect(control).toBe(baseField1Control);
+      });
+    });
+
+    describe('in base field', () => {
+      const invalidParam: InvalidParam = {
+        ...createInvalidParam(),
+        name: 'class.resource.baseField1',
+      };
+
+      it('should set error in control', () => {
+        setInvalidParamValidationError(form, invalidParam);
+
+        expect(baseField1Control.errors).not.toBeNull();
+      });
+
+      it('should set message code in control', () => {
+        setInvalidParamValidationError(form, invalidParam);
+
+        expect(baseField1Control.hasError(invalidParam.reason)).toBe(true);
+      });
+
+      it('should set control touched', () => {
+        setInvalidParamValidationError(form, invalidParam);
+
+        expect(baseField1Control.touched).toBe(true);
+      });
+
+      it('should not set error in other control', () => {
+        setInvalidParamValidationError(form, invalidParam);
+
+        expect(baseField2Control.errors).toBeNull();
+      });
+    });
+
+    describe('in subGroup Field', () => {
+      const invalidParam: InvalidParam = {
+        ...createInvalidParam(),
+        name: 'class.resource.subGroup.subGroupField1',
+      };
+
+      it('should set error in control', () => {
+        setInvalidParamValidationError(form, invalidParam, 'resource');
+
+        expect(subGroupFieldControl.errors).not.toBeNull();
+      });
+    });
+  });
+
+  describe('getFieldPath', () => {
+    const resource: string = 'resource';
+    const backendClassName: string = 'class';
+
+    it('should return field path', () => {
+      const fieldPath: string = 'field1';
+      const fullPath: string = `${backendClassName}.${resource}.${fieldPath}`;
+
+      const result: string = getFieldPath(fullPath, resource);
+
+      expect(result).toBe(fieldPath);
+    });
+
+    it('should get all parts after the prefix', () => {
+      const fieldPath: string = 'group.field1';
+      const fullPath: string = `${backendClassName}.${resource}.${fieldPath}`;
+
+      const result: string = getFieldPath(fullPath, resource);
+
+      expect(result).toBe(fieldPath);
+    });
+
+    it('should return field from full path when resource is undefined', () => {
+      const fieldPath: string = 'field1';
+      const fullPath: string = `${backendClassName}.${resource}.${fieldPath}`;
+
+      const result: string = getFieldPath(fullPath, undefined);
+
+      expect(result).toBe(fieldPath);
+    });
+
+    it('should return field from field when resource is undefined', () => {
+      const fieldPath: string = 'field1';
+
+      const result: string = getFieldPath(fieldPath, undefined);
+
+      expect(result).toBe(fieldPath);
+    });
+  });
+
+  describe('getMessageReason', () => {
+    it('should return reason', () => {
+      const problemDetail = createProblemDetail();
+
+      const reason: ValidationMessageCode = getMessageReason(problemDetail);
+
+      expect(reason).toEqual(problemDetail.invalidParams[0].reason);
+    });
+
+    it('should return null', () => {
+      const problemDetail = createProblemDetail([{ ...createInvalidParam(), reason: null }]);
+
+      const reason: ValidationMessageCode = getMessageReason(problemDetail);
+
+      expect(reason).toBeNull();
+    });
+  });
+
+  describe('getMessageForInvalidParam', () => {
+    const label: string = faker.random.word();
+
+    it('should return undefined reason', () => {
+      const invalidParam: InvalidParam = createInvalidParam();
+
+      const message: string = getMessageForInvalidParam(label, {
+        ...invalidParam,
+        reason: undefined,
+      });
+
+      expect(message).toBeUndefined();
+    });
+
+    it('should return message', () => {
+      const invalidParam: InvalidParam = createInvalidParam();
+
+      const message: string = getMessageForInvalidParam(label, {
+        ...invalidParam,
+        reason: ValidationMessageCode.FIELD_DATE_FORMAT_INVALID,
+      });
+      expect(message).toEqual(VALIDATION_MESSAGES[ValidationMessageCode.FIELD_DATE_FORMAT_INVALID]);
+    });
+
+    it('should return message with field placeholder', () => {
+      const invalidParam: InvalidParam = createInvalidParam();
+
+      const message: string = getMessageForInvalidParam(label, {
+        ...invalidParam,
+        reason: ValidationMessageCode.FIELD_INVALID,
+      });
+      expect(message).toEqual(
+        VALIDATION_MESSAGES[ValidationMessageCode.FIELD_INVALID].replace('{field}', label),
+      );
+    });
+
+    it('should return message with placeholders', () => {
+      const invalidParam: InvalidParam = createInvalidParam();
+      const min: string = '1';
+      const max: string = '5';
+
+      const message: string = getMessageForInvalidParam(label, {
+        ...invalidParam,
+        reason: ValidationMessageCode.FIELD_SIZE,
+        constraintParameters: [
+          { name: 'min', value: min },
+          { name: 'max', value: max },
+        ],
+      });
+      expect(message).toEqual(
+        VALIDATION_MESSAGES[ValidationMessageCode.FIELD_SIZE]
+          .replace('{field}', label)
+          .replace('{min}', min)
+          .replace('{max}', max),
+      );
+    });
   });
 });
diff --git a/alfa-client/libs/tech-shared/src/lib/validation/tech.validation.util.ts b/alfa-client/libs/tech-shared/src/lib/validation/tech.validation.util.ts
index 4a34005de2f231027678dc6ce606a8cc2e3e1bed..d562a4543baec28671348cd0ef81402c055b154d 100644
--- a/alfa-client/libs/tech-shared/src/lib/validation/tech.validation.util.ts
+++ b/alfa-client/libs/tech-shared/src/lib/validation/tech.validation.util.ts
@@ -22,9 +22,9 @@
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
 import { AbstractControl, UntypedFormGroup } from '@angular/forms';
-import { isNil } from 'lodash-es';
-import { ApiError, InvalidParam, Issue, IssueParam } from '../tech.model';
-import { isNotNil, replacePlaceholder } from '../tech.util';
+import { isEmpty, isNil } from 'lodash-es';
+import { ApiError, InvalidParam, Issue, IssueParam, ProblemDetail } from '../tech.model';
+import { replacePlaceholder } from '../tech.util';
 import { VALIDATION_MESSAGES, ValidationMessageCode } from './tech.validation.messages';
 
 export function isValidationError(issue: Issue): boolean {
@@ -47,7 +47,7 @@ export function getControlForIssue(
   issue: Issue,
   pathPrefix?: string,
 ): AbstractControl {
-  const fieldPath: string = getFieldPathWithoutPrefix(issue.field, pathPrefix);
+  const fieldPath: string = getFieldPath(issue.field, pathPrefix);
 
   let curControl: AbstractControl = form;
   fieldPath
@@ -72,8 +72,12 @@ export function getMessageForIssue(label: string, issue: Issue): string {
   return msg;
 }
 
-export function isValidationFieldFileSizeExceedError(error: any) {
-  return getMessageCode(error) === ValidationMessageCode.VALIDATION_FIELD_FILE_SIZE_EXCEEDED;
+export function isValidationFieldFileSizeExceedError(error: ProblemDetail): boolean {
+  return getMessageReason(error) === ValidationMessageCode.FIELD_FILE_SIZE_EXCEEDED;
+}
+
+export function getMessageReason(problemDetail: ProblemDetail): ValidationMessageCode | null {
+  return problemDetail.invalidParams[0].reason ?? null;
 }
 
 export function getMessageCode(apiError: ApiError): string {
@@ -86,12 +90,9 @@ export function setInvalidParamValidationError(
   pathPrefix?: string,
 ): void {
   const control: AbstractControl = getControlForInvalidParam(form, invalidParam, pathPrefix);
-  if (isNotNil(control)) {
-    control.setErrors({
-      [invalidParam.reason]: getMessageForInvalidParam(invalidParam, pathPrefix),
-    });
-    control.markAsTouched();
-  }
+
+  control.setErrors({ [invalidParam.reason]: invalidParam });
+  control.markAsTouched();
 }
 
 export function getControlForInvalidParam(
@@ -99,17 +100,29 @@ export function getControlForInvalidParam(
   invalidParam: InvalidParam,
   pathPrefix?: string,
 ): AbstractControl {
-  return form.get(getFieldPathWithoutPrefix(invalidParam.name, pathPrefix));
+  return form.get(getFieldPath(invalidParam.name, pathPrefix));
 }
 
-export function getMessageForInvalidParam(item: InvalidParam, pathPrefix: string): string {
-  return replacePlaceholder(
-    VALIDATION_MESSAGES[item.reason],
-    'field',
-    getFieldPathWithoutPrefix(item.name, pathPrefix),
+export function getMessageForInvalidParam(label: string, invalidParam: InvalidParam): string {
+  let msg: string = VALIDATION_MESSAGES[invalidParam.reason];
+
+  if (isNil(msg)) {
+    console.warn('No message for code ' + invalidParam.reason + ' found.');
+    return invalidParam.reason;
+  }
+
+  msg = replacePlaceholder(msg, 'field', label);
+  invalidParam.constraintParameters.forEach(
+    (param: IssueParam) => (msg = replacePlaceholder(msg, param.name, param.value)),
   );
+  return msg;
 }
 
-function getFieldPathWithoutPrefix(name: string, pathPrefix?: string): string {
-  return pathPrefix ? name.substring(pathPrefix.length + 1) : name;
+export function getFieldPath(name: string, pathPrefix: string): string {
+  if (isEmpty(pathPrefix)) {
+    return name.split('.').pop();
+  }
+
+  const indexOfField = name.lastIndexOf(pathPrefix) + pathPrefix.length + 1;
+  return name.slice(indexOfField);
 }
diff --git a/alfa-client/libs/tech-shared/test/data-test.ts b/alfa-client/libs/tech-shared/test/data-test.ts
index d0c53e43d65c6547e211bce4ac0ef9bfb887b9b4..4b4b9cc2b8a1661880fbe10002e8d1b3a0a02c7a 100644
--- a/alfa-client/libs/tech-shared/test/data-test.ts
+++ b/alfa-client/libs/tech-shared/test/data-test.ts
@@ -28,3 +28,7 @@ export function getDataTestClassOf(value: string): string {
 export function getDataTestIdOf(value: string): string {
   return `[data-test-id="${value}"]`;
 }
+
+export function getDataTestIdAttributeOf(value: string): string {
+  return `[dataTestId="${value}"]`;
+}
diff --git a/alfa-client/libs/tech-shared/test/error.ts b/alfa-client/libs/tech-shared/test/error.ts
index 9803a5a5ad90888ceb7125bc535f5c379548d126..3f80af06d43d07792780eaf023c378bcfd697345 100644
--- a/alfa-client/libs/tech-shared/test/error.ts
+++ b/alfa-client/libs/tech-shared/test/error.ts
@@ -23,7 +23,14 @@
  */
 import { HttpErrorResponse, HttpStatusCode } from '@angular/common/http';
 import { faker } from '@faker-js/faker';
-import { ApiError, InvalidParam, Issue, IssueParam, ProblemDetail } from '../src/lib/tech.model';
+import {
+  ApiError,
+  ConstraintParameter,
+  InvalidParam,
+  Issue,
+  IssueParam,
+  ProblemDetail,
+} from '../src/lib/tech.model';
 import { ValidationMessageCode } from '../src/lib/validation/tech.validation.messages';
 
 export function createIssueParam(): IssueParam {
@@ -63,10 +70,22 @@ export function createProblemDetail(
     type: faker.random.word(),
     instance: faker.internet.url(),
     detail: faker.random.word(),
-    'invalid-params': invalidParams,
+    invalidParams: invalidParams,
   };
 }
 
 export function createInvalidParam(): InvalidParam {
-  return { name: faker.random.word(), reason: ValidationMessageCode.VALIDATION_FIELD_EMPTY };
+  return {
+    name: faker.random.word(),
+    reason: ValidationMessageCode.FIELD_EMPTY,
+    value: faker.random.words(10),
+    constraintParameters: [createInvalidParamConstraintParameter()],
+  };
+}
+
+export function createInvalidParamConstraintParameter(): ConstraintParameter {
+  return {
+    name: faker.random.word(),
+    value: faker.random.word(),
+  };
 }
diff --git a/alfa-client/libs/test-utils/src/index.ts b/alfa-client/libs/test-utils/src/index.ts
index 2496647d81ac7e86f904aef5e70b2031539d4541..9500ab27220d6d74064d30a8d163c00f020ce2f7 100644
--- a/alfa-client/libs/test-utils/src/index.ts
+++ b/alfa-client/libs/test-utils/src/index.ts
@@ -21,7 +21,9 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
+export * from './lib/dialog';
 export * from './lib/helper';
 export * from './lib/jest.helper';
 export * from './lib/mocking';
+export * from './lib/model';
 export * from './lib/test-utils.module';
diff --git a/alfa-client/libs/test-utils/src/lib/dialog.ts b/alfa-client/libs/test-utils/src/lib/dialog.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d9a32f03a17d554f48e5263d1df4c4b7bb552b9b
--- /dev/null
+++ b/alfa-client/libs/test-utils/src/lib/dialog.ts
@@ -0,0 +1 @@
+export const dialogRefMock = { close: jest.fn() };
diff --git a/alfa-client/libs/test-utils/src/lib/helper.ts b/alfa-client/libs/test-utils/src/lib/helper.ts
index ed3e6fa137f9399a1ce428b627c13b47a70947f9..b95ce2e05c2a1912d502259ff1172ae34b16959b 100644
--- a/alfa-client/libs/test-utils/src/lib/helper.ts
+++ b/alfa-client/libs/test-utils/src/lib/helper.ts
@@ -24,6 +24,7 @@
 import { DebugElement, Type } from '@angular/core';
 import { ComponentFixture } from '@angular/core/testing';
 import { By } from '@angular/platform-browser';
+import { EventData } from './model';
 
 export function getElementFromFixtureByType<T>(
   fixture: ComponentFixture<any>,
@@ -47,8 +48,8 @@ export function getElementsFromFixture(fixture: ComponentFixture<any>, htmlEleme
   return fixture.nativeElement.querySelectorAll(htmlElement);
 }
 
-export function dispatchEventFromFixture(
-  fixture: ComponentFixture<any>,
+export function dispatchEventFromFixture<T>(
+  fixture: ComponentFixture<T>,
   elementSelector: string,
   event: string,
 ): void {
@@ -56,6 +57,14 @@ export function dispatchEventFromFixture(
   element.nativeElement.dispatchEvent(new Event(event));
 }
 
+export function triggerEvent<T>(eventData: EventData<T>) {
+  const element: DebugElement = getDebugElementFromFixtureByCss(
+    eventData.fixture,
+    eventData.elementSelector,
+  );
+  element.triggerEventHandler(eventData.name, eventData.data);
+}
+
 export function getDebugElementFromFixtureByCss(
   fixture: ComponentFixture<any>,
   query: string,
diff --git a/alfa-client/libs/test-utils/src/lib/model.ts b/alfa-client/libs/test-utils/src/lib/model.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e48d4ed88c7c2447665811a86fc712dc2a4904da
--- /dev/null
+++ b/alfa-client/libs/test-utils/src/lib/model.ts
@@ -0,0 +1,8 @@
+import { ComponentFixture } from '@angular/core/testing';
+
+export interface EventData<T> {
+  fixture: ComponentFixture<T>;
+  elementSelector: string;
+  name: string;
+  data?: unknown;
+}
diff --git a/alfa-client/libs/ui/src/lib/assets/update.svg b/alfa-client/libs/ui/src/lib/assets/update.svg
index 1eb6a0751c7673b2de4a52c06aba58f191f32570..64c8cf90dc1a17b7183fd9dc03a66effd3273449 100644
--- a/alfa-client/libs/ui/src/lib/assets/update.svg
+++ b/alfa-client/libs/ui/src/lib/assets/update.svg
@@ -1 +1,4 @@
-<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368"><path d="M480-120q-75 0-140.5-28.5t-114-77q-48.5-48.5-77-114T120-480q0-75 28.5-140.5t77-114q48.5-48.5 114-77T480-840q82 0 155.5 35T760-706v-94h80v240H600v-80h110q-41-56-101-88t-129-32q-117 0-198.5 81.5T200-480q0 117 81.5 198.5T480-200q105 0 183.5-68T756-440h82q-15 137-117.5 228.5T480-120Zm112-192L440-464v-216h80v184l128 128-56 56Z"/></svg>
\ No newline at end of file
+<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="inherit">
+  <path
+    d="M480-120q-75 0-140.5-28.5t-114-77q-48.5-48.5-77-114T120-480q0-75 28.5-140.5t77-114q48.5-48.5 114-77T480-840q82 0 155.5 35T760-706v-94h80v240H600v-80h110q-41-56-101-88t-129-32q-117 0-198.5 81.5T200-480q0 117 81.5 198.5T480-200q105 0 183.5-68T756-440h82q-15 137-117.5 228.5T480-120Zm112-192L440-464v-216h80v184l128 128-56 56Z" />
+</svg>
\ No newline at end of file
diff --git a/alfa-client/libs/ui/src/lib/ui/download-button/download-button.component.html b/alfa-client/libs/ui/src/lib/ui/download-button/download-button.component.html
index 2d3bb50998667c75d6e563071d9de2a9ab088eb6..7d38323f46aa6ab9afabe4ab3226220cf2730d89 100644
--- a/alfa-client/libs/ui/src/lib/ui/download-button/download-button.component.html
+++ b/alfa-client/libs/ui/src/lib/ui/download-button/download-button.component.html
@@ -8,5 +8,5 @@
   [color]="'primary'"
 >
   <mat-icon>save_alt</mat-icon>
-  <span>{{ text }}</span>
+  <span class="text-sm">{{ text }}</span>
 </a>
diff --git a/alfa-client/libs/ui/src/lib/ui/editor/autocomplete-editor/autocomplete-editor.component.html b/alfa-client/libs/ui/src/lib/ui/editor/autocomplete-editor/autocomplete-editor.component.html
index 6f484f807eca85ab9ccc7bc42c43c12c9bdc850f..8a0fb969d94a66f00007edfff7f6f84f55edd969 100644
--- a/alfa-client/libs/ui/src/lib/ui/editor/autocomplete-editor/autocomplete-editor.component.html
+++ b/alfa-client/libs/ui/src/lib/ui/editor/autocomplete-editor/autocomplete-editor.component.html
@@ -54,7 +54,7 @@
   <mat-error>
     <ozgcloud-validation-error
       [attr.data-test-id]="(label | convertForDataTest) + '-autocomplete-error'"
-      [issues]="issues"
+      [invalidParams]="invalidParams"
       [label]="label"
     >
     </ozgcloud-validation-error>
diff --git a/alfa-client/libs/ui/src/lib/ui/editor/date-editor/date-editor.component.html b/alfa-client/libs/ui/src/lib/ui/editor/date-editor/date-editor.component.html
index 589e1679db0ad9e505aa9b98a1c981b366e5abfb..07ec3ad16554c885825d55b1f14139a7e05a246f 100644
--- a/alfa-client/libs/ui/src/lib/ui/editor/date-editor/date-editor.component.html
+++ b/alfa-client/libs/ui/src/lib/ui/editor/date-editor/date-editor.component.html
@@ -43,7 +43,7 @@
   <mat-error>
     <ozgcloud-validation-error
       [attr.data-test-id]="(label | convertForDataTest) + '-date-error'"
-      [issues]="issues"
+      [invalidParams]="invalidParams"
       [label]="label"
     ></ozgcloud-validation-error>
   </mat-error>
diff --git a/alfa-client/libs/ui/src/lib/ui/editor/file-upload-editor/file-upload-editor.component.html b/alfa-client/libs/ui/src/lib/ui/editor/file-upload-editor/file-upload-editor.component.html
index a6f83cf4e2fa94e8a84d5ee0aebbfd9fa1efd8d1..94acabf0cf558593f633a252fb6bdb35f07f5fd0 100644
--- a/alfa-client/libs/ui/src/lib/ui/editor/file-upload-editor/file-upload-editor.component.html
+++ b/alfa-client/libs/ui/src/lib/ui/editor/file-upload-editor/file-upload-editor.component.html
@@ -48,7 +48,7 @@
 <mat-error>
   <ozgcloud-validation-error
     [attr.data-test-id]="(label | convertForDataTest) + '-file-upload-error'"
-    [issues]="issues"
+    [invalidParams]="invalidParams"
     [label]="label"
   >
   </ozgcloud-validation-error>
diff --git a/alfa-client/libs/ui/src/lib/ui/editor/text-editor/text-editor.component.html b/alfa-client/libs/ui/src/lib/ui/editor/text-editor/text-editor.component.html
index bcf6e536c27a4a13aab0a99e43c2c155920bc241..8a8e01260fd7b5cb4af14320ea4af0d264b9a980 100644
--- a/alfa-client/libs/ui/src/lib/ui/editor/text-editor/text-editor.component.html
+++ b/alfa-client/libs/ui/src/lib/ui/editor/text-editor/text-editor.component.html
@@ -58,7 +58,7 @@
   <mat-error>
     <ozgcloud-validation-error
       [attr.data-test-id]="(getPlaceholderLabel() | convertForDataTest) + '-text-error'"
-      [issues]="issues"
+      [invalidParams]="invalidParams"
       [label]="getPlaceholderLabel()"
     ></ozgcloud-validation-error>
   </mat-error>
diff --git a/alfa-client/libs/ui/src/lib/ui/editor/textarea-editor/textarea-editor.component.html b/alfa-client/libs/ui/src/lib/ui/editor/textarea-editor/textarea-editor.component.html
index cf3135707e7a986230e2dc9957326bb1766a6a88..14034ce169db28951cd062e19343976a81ca8d7b 100644
--- a/alfa-client/libs/ui/src/lib/ui/editor/textarea-editor/textarea-editor.component.html
+++ b/alfa-client/libs/ui/src/lib/ui/editor/textarea-editor/textarea-editor.component.html
@@ -39,8 +39,8 @@
 
   <mat-error>
     <ozgcloud-validation-error
-      [issues]="issues"
       [label]="label"
+      [invalidParams]="invalidParams"
       [attr.data-test-id]="(label | convertForDataTest) + '-textarea-error'"
     >
     </ozgcloud-validation-error>
diff --git a/alfa-client/libs/ui/src/lib/ui/expansion-panel/_expansion-panel.theme.scss b/alfa-client/libs/ui/src/lib/ui/expansion-panel/_expansion-panel.theme.scss
index 6847720e6a809da6652b2ae2a87c87f9ccf04a48..ba505ad18cce11ca6b59ad4fecbf9e0f17b8be62 100644
--- a/alfa-client/libs/ui/src/lib/ui/expansion-panel/_expansion-panel.theme.scss
+++ b/alfa-client/libs/ui/src/lib/ui/expansion-panel/_expansion-panel.theme.scss
@@ -43,7 +43,7 @@ ozgcloud-expansion-panel {
     margin-bottom: 0;
     font-weight: 500;
     margin-left: 8px;
-    font-size: 16px;
+    font-size: 1rem;
   }
 
   .mat-expansion-panel-body {
diff --git a/alfa-client/libs/ui/src/lib/ui/fixed-dialog/_fixed-dialog.theme.scss b/alfa-client/libs/ui/src/lib/ui/fixed-dialog/_fixed-dialog.theme.scss
index f71cbc89bc0ca6eccd4030537e653e21b0ef83b2..5e3662430bdfb5e5f7106997756cd7645620ed10 100644
--- a/alfa-client/libs/ui/src/lib/ui/fixed-dialog/_fixed-dialog.theme.scss
+++ b/alfa-client/libs/ui/src/lib/ui/fixed-dialog/_fixed-dialog.theme.scss
@@ -33,7 +33,7 @@
       margin: 0;
       padding: 0 4px 0 16px;
       color: #fff;
-      font-size: 16px;
+      font-size: 1rem;
       font-weight: normal;
       justify-content: space-between;
       align-items: center;
@@ -52,7 +52,7 @@
       padding: 0;
     }
     .mat-mdc-form-field-error {
-      font-size: 12px;
+      font-size: 0.75rem;
     }
     .mdc-dialog__content {
       line-height: 20px;
diff --git a/alfa-client/libs/ui/src/lib/ui/http-error-dialog/connection-timeout-retry-dialog/connection-timeout-retry-dialog.component.scss b/alfa-client/libs/ui/src/lib/ui/http-error-dialog/connection-timeout-retry-dialog/connection-timeout-retry-dialog.component.scss
index 6d01e5239cf92f45f39c7c0f6344a683f858e0bf..547ff80f6141d27b901ff4f2e28a6b5ac3049b03 100644
--- a/alfa-client/libs/ui/src/lib/ui/http-error-dialog/connection-timeout-retry-dialog/connection-timeout-retry-dialog.component.scss
+++ b/alfa-client/libs/ui/src/lib/ui/http-error-dialog/connection-timeout-retry-dialog/connection-timeout-retry-dialog.component.scss
@@ -23,13 +23,13 @@
  */
 h1 {
   font-weight: normal;
-  font-size: 24px;
+  font-size: 1.5rem;
   display: flex;
   align-items: center;
 
   .mat-icon {
     margin-right: 8px;
-    font-size: 30px;
+    font-size: 1.875rem;
     width: 30px;
     height: 30px;
   }
diff --git a/alfa-client/libs/ui/src/lib/ui/http-error-dialog/connection-timeout-retry-fail-dialog/connection-timeout-retry-fail-dialog.component.scss b/alfa-client/libs/ui/src/lib/ui/http-error-dialog/connection-timeout-retry-fail-dialog/connection-timeout-retry-fail-dialog.component.scss
index 48d8d08527c969b705c347d217d527c30aa6cd39..c3fa5daffcee059afdc534b5fdf6fb369c99b9f0 100644
--- a/alfa-client/libs/ui/src/lib/ui/http-error-dialog/connection-timeout-retry-fail-dialog/connection-timeout-retry-fail-dialog.component.scss
+++ b/alfa-client/libs/ui/src/lib/ui/http-error-dialog/connection-timeout-retry-fail-dialog/connection-timeout-retry-fail-dialog.component.scss
@@ -23,13 +23,13 @@
  */
 h2 {
   font-weight: normal;
-  font-size: 24px;
+  font-size: 1.5rem;
   display: flex;
   align-items: center;
 
   .mat-icon {
     margin-right: 8px;
-    font-size: 30px;
+    font-size: 1.875rem;
     width: 30px;
     height: 30px;
   }
diff --git a/alfa-client/libs/ui/src/lib/ui/mattooltip/mattooltip.default.ts b/alfa-client/libs/ui/src/lib/ui/mattooltip/mattooltip.default.ts
index ba74384d51851cefb3f9e85aa82f0d695f8f02bb..3c11d7da1b6616bf23f2d13790a38510cbf0e536 100644
--- a/alfa-client/libs/ui/src/lib/ui/mattooltip/mattooltip.default.ts
+++ b/alfa-client/libs/ui/src/lib/ui/mattooltip/mattooltip.default.ts
@@ -4,4 +4,6 @@ export const matTooltipDefaultOptions: MatTooltipDefaultOptions = {
   showDelay: 1500,
   hideDelay: 0,
   touchendHideDelay: 1500,
+  positionAtOrigin: true,
+  disableTooltipInteractivity: true,
 };
diff --git a/alfa-client/libs/ui/src/lib/ui/menu-item/menu-item.component.html b/alfa-client/libs/ui/src/lib/ui/menu-item/menu-item.component.html
index 2a127b78127ac601a4ba02e88f6b428795d26970..43c0239c59f88b1bc4f8d9c49e428ba5a97a2c5f 100644
--- a/alfa-client/libs/ui/src/lib/ui/menu-item/menu-item.component.html
+++ b/alfa-client/libs/ui/src/lib/ui/menu-item/menu-item.component.html
@@ -6,7 +6,7 @@
 </ng-template>
 
 <div>
-  <div class="headline">{{ headline }}</div>
-  <div class="text">{{ text }}</div>
+  <div class="text-base font-medium">{{ headline }}</div>
+  <div class="mb-3 text-sm font-normal">{{ text }}</div>
   <ng-content></ng-content>
 </div>
diff --git a/alfa-client/libs/ui/src/lib/ui/menu-item/menu-item.component.scss b/alfa-client/libs/ui/src/lib/ui/menu-item/menu-item.component.scss
index 41f783ee481e672a91b6b728e277ef0ccbf7f868..369725c1daec6c0954ab191e89b33aac2cf12aac 100644
--- a/alfa-client/libs/ui/src/lib/ui/menu-item/menu-item.component.scss
+++ b/alfa-client/libs/ui/src/lib/ui/menu-item/menu-item.component.scss
@@ -15,17 +15,6 @@ ozgcloud-svgicon-big {
   margin-right: 1rem;
 }
 
-.headline {
-  font-weight: 500;
-  font-size: 16px;
-}
-
-.text {
-  font-weight: 400;
-  font-size: 14px;
-  margin-bottom: 10px;
-}
-
 :host-context(.dark) {
   color: #fff;
   background-color: #393939;
diff --git a/alfa-client/libs/ui/src/lib/ui/notification/internal-server-error-dialog/internal-server-error-dialog.component.scss b/alfa-client/libs/ui/src/lib/ui/notification/internal-server-error-dialog/internal-server-error-dialog.component.scss
index cc051218ffa5dbef0d2c3ad72469e6e01b8baeb9..6f31abcc6bb5a5554ca7f88a30b784eb2f48f450 100644
--- a/alfa-client/libs/ui/src/lib/ui/notification/internal-server-error-dialog/internal-server-error-dialog.component.scss
+++ b/alfa-client/libs/ui/src/lib/ui/notification/internal-server-error-dialog/internal-server-error-dialog.component.scss
@@ -27,7 +27,7 @@ h1 {
 
   .mat-icon {
     margin-right: 8px;
-    font-size: 30px;
+    font-size: 1.875rem;
     width: 30px;
     height: 30px;
   }
diff --git a/alfa-client/libs/ui/src/lib/ui/open-url-button/open-url-button.component.html b/alfa-client/libs/ui/src/lib/ui/open-url-button/open-url-button.component.html
index d5da9183f237f187be716d871c9181e5691438d5..f9b4506ca32ddc37a7ae623293999da1391d81ba 100644
--- a/alfa-client/libs/ui/src/lib/ui/open-url-button/open-url-button.component.html
+++ b/alfa-client/libs/ui/src/lib/ui/open-url-button/open-url-button.component.html
@@ -10,5 +10,5 @@
   class="button"
 >
   <mat-icon>open_in_new</mat-icon>
-  <span>{{ text }}</span>
+  <span class="text-sm">{{ text }}</span>
 </a>
diff --git a/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/shared/ozgcloud-button-content/ozgcloud-button-content.component.html b/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/shared/ozgcloud-button-content/ozgcloud-button-content.component.html
index 43d399abb04e8fc3417be4b88a13c6d5d2d5b810..30f7ac2c092a194e06bafd2e9cafa606a858a8ee 100644
--- a/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/shared/ozgcloud-button-content/ozgcloud-button-content.component.html
+++ b/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/shared/ozgcloud-button-content/ozgcloud-button-content.component.html
@@ -16,7 +16,7 @@
 >
 </mat-icon>
 
-<span *ngIf="text" data-test-class="button-with-spinner-text">{{ text }}</span>
+<span *ngIf="text" class="text-sm" data-test-class="button-with-spinner-text">{{ text }}</span>
 
 <ozgcloud-spinner [diameter]="22" padding="0" [stateResource]="stateResource" [show]="showSpinner">
 </ozgcloud-spinner>
diff --git a/alfa-client/libs/ui/src/lib/ui/ozgcloud-dialog/ozgcloud-dialog.service.spec.ts b/alfa-client/libs/ui/src/lib/ui/ozgcloud-dialog/ozgcloud-dialog.service.spec.ts
index 90ba85e40ec86b4c785793fecc5e5e6b0d4e850e..8fac9311bbcd78efbdd449922e9901f6cd97aa45 100644
--- a/alfa-client/libs/ui/src/lib/ui/ozgcloud-dialog/ozgcloud-dialog.service.spec.ts
+++ b/alfa-client/libs/ui/src/lib/ui/ozgcloud-dialog/ozgcloud-dialog.service.spec.ts
@@ -10,12 +10,20 @@ describe('OzgcloudDialogService', () => {
 
   const component = <any>{ name: 'Component' };
   const dialogData = { id: 'ZumBeispiel' };
+  const dialogConfig: DialogConfig = {
+    hasBackdrop: true,
+    disableClose: true,
+  };
   const dialogConfigWithData: DialogConfig = { data: dialogData };
   const viewContainerRef = <any>{};
   const dialogConfigWithDataAndViewContainerRef: DialogConfig = {
     data: dialogData,
     viewContainerRef,
   };
+  const dialogConfigWithOwnConfigAndViewContainerRef: DialogConfig = {
+    ...dialogConfig,
+    viewContainerRef,
+  };
   const dialogConfigWithOutDataAndWithViewContainerRef: DialogConfig = {
     viewContainerRef,
   };
@@ -59,7 +67,16 @@ describe('OzgcloudDialogService', () => {
       expect(dialog.open).toHaveBeenCalledWith(component, dialogConfigWithDataAndViewContainerRef);
     });
 
-    it('should open dialog wihtout data', () => {
+    it('should open dialog with custom config', () => {
+      service.openInCallingComponentContext(component, viewContainerRef, null, dialogConfig);
+
+      expect(dialog.open).toHaveBeenCalledWith(
+        component,
+        dialogConfigWithOwnConfigAndViewContainerRef,
+      );
+    });
+
+    it('should open dialog without data and custom config', () => {
       service.openInCallingComponentContext(component, viewContainerRef);
 
       expect(dialog.open).toHaveBeenCalledWith(
diff --git a/alfa-client/libs/ui/src/lib/ui/ozgcloud-dialog/ozgcloud-dialog.service.ts b/alfa-client/libs/ui/src/lib/ui/ozgcloud-dialog/ozgcloud-dialog.service.ts
index 27769a03b7ebd03c1db3a8ad50ee02d5b5ce9a69..3c9383b4a60f1293b42ee00b3acc3fa90a54abaf 100644
--- a/alfa-client/libs/ui/src/lib/ui/ozgcloud-dialog/ozgcloud-dialog.service.ts
+++ b/alfa-client/libs/ui/src/lib/ui/ozgcloud-dialog/ozgcloud-dialog.service.ts
@@ -30,8 +30,12 @@ export class OzgcloudDialogService {
     component: ComponentType<T>,
     viewContainerRef: ViewContainerRef,
     data?: D,
+    dialogConfig?: DialogConfig,
   ): DialogRef<T> {
-    return this.openDialog(component, this.buildDialogConfigWithData(data, { viewContainerRef }));
+    return this.openDialog(
+      component,
+      this.buildDialogConfigWithData(data, { viewContainerRef, ...dialogConfig }),
+    );
   }
 
   private buildDialogConfigWithData<D>(data: D, dialogConfig?: DialogConfig): DialogConfig | null {
diff --git a/alfa-client/libs/ui/src/lib/ui/slide-toggle/slide-toggle.component.html b/alfa-client/libs/ui/src/lib/ui/slide-toggle/slide-toggle.component.html
index a76b8bea8332621394acda1e83b7aebfbd987394..5812a93c4d9789a4127f65101278302a13ce02e5 100644
--- a/alfa-client/libs/ui/src/lib/ui/slide-toggle/slide-toggle.component.html
+++ b/alfa-client/libs/ui/src/lib/ui/slide-toggle/slide-toggle.component.html
@@ -29,5 +29,5 @@
   [matTooltip]="toolTip"
   [checked]="checked"
   (change)="valueChanged.emit($event.checked)"
-  >{{ label }}
+  ><span class="text-sm">{{ label }}</span>
 </mat-slide-toggle>
diff --git a/alfa-client/libs/ui/src/lib/ui/validation-error/validation-error.component.html b/alfa-client/libs/ui/src/lib/ui/validation-error/validation-error.component.html
index 13f1ef45c46566b76aad56247845108a014310e6..2c47c8ccdafa3929335cd41715394e7c2e11357d 100644
--- a/alfa-client/libs/ui/src/lib/ui/validation-error/validation-error.component.html
+++ b/alfa-client/libs/ui/src/lib/ui/validation-error/validation-error.component.html
@@ -23,4 +23,4 @@
     unter der Lizenz sind dem Lizenztext zu entnehmen.
 
 -->
-<span *ngFor="let issue of issues">{{ message(issue) }}</span>
+<span *ngFor="let invalidParam of invalidParams">{{ message(invalidParam) }}</span>
diff --git a/alfa-client/libs/ui/src/lib/ui/validation-error/validation-error.component.spec.ts b/alfa-client/libs/ui/src/lib/ui/validation-error/validation-error.component.spec.ts
index 299af463232908e4f3edec96f97f7fd912379b0e..e486895e359ed8cbb702456e19b5f88530683e48 100644
--- a/alfa-client/libs/ui/src/lib/ui/validation-error/validation-error.component.spec.ts
+++ b/alfa-client/libs/ui/src/lib/ui/validation-error/validation-error.component.spec.ts
@@ -21,8 +21,10 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
+import { InvalidParam, getMessageForInvalidParam } from '@alfa-client/tech-shared';
 import { ComponentFixture, TestBed } from '@angular/core/testing';
-import { createIssue } from 'libs/tech-shared/test/error';
+import { ValidationMessageCode } from 'libs/tech-shared/src/lib/validation/tech.validation.messages';
+import { createInvalidParam } from 'libs/tech-shared/test/error';
 import { ValidationErrorComponent } from './validation-error.component';
 
 describe('ValidationErrorComponent', () => {
@@ -45,9 +47,32 @@ describe('ValidationErrorComponent', () => {
     expect(component).toBeTruthy();
   });
 
-  it('should get message', () => {
-    var msg = component.message({ ...createIssue(), messageCode: 'validation_field_size' });
+  describe('get message from invalidParam', () => {
+    const fieldLabel: string = 'Field Label';
+    const invalidParam: InvalidParam = {
+      ...createInvalidParam(),
+      reason: ValidationMessageCode.FIELD_SIZE,
+    };
 
-    expect(msg).not.toHaveLength(0);
+    it('should contain ', () => {
+      const msg: string = getMessageForInvalidParam(fieldLabel, invalidParam);
+
+      expect(msg).toContain('muss mindestens');
+    });
+
+    it('should set field label', () => {
+      const msg: string = getMessageForInvalidParam(fieldLabel, invalidParam);
+
+      expect(msg).toContain(fieldLabel);
+    });
+
+    it('should replace min param', () => {
+      const msg: string = getMessageForInvalidParam(fieldLabel, {
+        ...invalidParam,
+        constraintParameters: [{ name: 'min', value: '3' }],
+      });
+
+      expect(msg).toContain('3');
+    });
   });
 });
diff --git a/alfa-client/libs/ui/src/lib/ui/validation-error/validation-error.component.ts b/alfa-client/libs/ui/src/lib/ui/validation-error/validation-error.component.ts
index 0432ac003dae9960503559194148fb5d79f52c45..1c5e6df544c2a3d480dd40d6915b72ef166c7273 100644
--- a/alfa-client/libs/ui/src/lib/ui/validation-error/validation-error.component.ts
+++ b/alfa-client/libs/ui/src/lib/ui/validation-error/validation-error.component.ts
@@ -21,8 +21,8 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
+import { InvalidParam, getMessageForInvalidParam } from '@alfa-client/tech-shared';
 import { Component, Input } from '@angular/core';
-import { getMessageForIssue, Issue } from '@alfa-client/tech-shared';
 
 @Component({
   selector: 'ozgcloud-validation-error',
@@ -31,9 +31,9 @@ import { getMessageForIssue, Issue } from '@alfa-client/tech-shared';
 })
 export class ValidationErrorComponent {
   @Input() label: string;
-  @Input() issues: Issue[];
+  @Input() invalidParams: InvalidParam[];
 
-  public message(issue: Issue): string {
-    return getMessageForIssue(this.label, issue);
+  public message(invalidParam: InvalidParam): string {
+    return getMessageForInvalidParam(this.label, invalidParam);
   }
 }
diff --git a/alfa-client/libs/user-assistance/src/lib/help-menu/help-menu.component.html b/alfa-client/libs/user-assistance/src/lib/help-menu/help-menu.component.html
index 2b0db504b3f464f1624afcbceb95df15cfb6e3e0..8c00cbfc6abd899bf3da59fc774efc61a8c19755 100644
--- a/alfa-client/libs/user-assistance/src/lib/help-menu/help-menu.component.html
+++ b/alfa-client/libs/user-assistance/src/lib/help-menu/help-menu.component.html
@@ -5,9 +5,9 @@
   [matMenuTriggerFor]="helpMenu.matMenu"
   data-test-id="help-menu-button"
 >
-  <div class="help-menu">
-    <ozgcloud-icon icon="help_outline"></ozgcloud-icon>
-    <div class="text">Hilfe</div>
+  <div class="flex items-center text-ozggray-800 dark:text-ozggray-300">
+    <ozgcloud-icon class="mr-1" icon="help_outline"></ozgcloud-icon>
+    <div>Hilfe</div>
   </div>
 </button>
 <ozgcloud-menu #helpMenu>
diff --git a/alfa-client/libs/user-assistance/src/lib/help-menu/help-menu.component.scss b/alfa-client/libs/user-assistance/src/lib/help-menu/help-menu.component.scss
deleted file mode 100644
index 99cbeef04c23dba9c76fa256dbdb4764f5a1e2b4..0000000000000000000000000000000000000000
--- a/alfa-client/libs/user-assistance/src/lib/help-menu/help-menu.component.scss
+++ /dev/null
@@ -1,11 +0,0 @@
-@import 'variables';
-
-.help-menu {
-  display: flex;
-  align-items: center;
-  color: $grey;
-}
-
-ozgcloud-icon {
-  margin-right: 4px;
-}
diff --git a/alfa-client/libs/user-assistance/src/lib/help-menu/help-menu.component.ts b/alfa-client/libs/user-assistance/src/lib/help-menu/help-menu.component.ts
index 602c0ee4effc7366a69024c531427d7ff5410ae9..5c7c59840a98bac1696c1a1b3a5b5de3c9b14618 100644
--- a/alfa-client/libs/user-assistance/src/lib/help-menu/help-menu.component.ts
+++ b/alfa-client/libs/user-assistance/src/lib/help-menu/help-menu.component.ts
@@ -1,12 +1,11 @@
-import { Component, Input } from '@angular/core';
 import { ApiRootLinkRel, ApiRootResource } from '@alfa-client/api-root-shared';
 import { StateResource } from '@alfa-client/tech-shared';
+import { Component, Input } from '@angular/core';
 import { hasLink } from '@ngxp/rest';
 
 @Component({
   selector: 'alfa-help-menu',
   templateUrl: './help-menu.component.html',
-  styleUrls: ['./help-menu.component.scss'],
 })
 export class HelpMenuComponent {
   @Input() apiRootStateResource: StateResource<ApiRootResource>;
diff --git a/alfa-client/libs/user-profile/src/lib/user-profile-in-header-container/user-profile-in-header/user-profile-in-header.component.html b/alfa-client/libs/user-profile/src/lib/user-profile-in-header-container/user-profile-in-header/user-profile-in-header.component.html
index 3fb9f5af72a952068f8d799e64ab20156999d96f..6a738849018cd80575928861fbe1a876b1c8dde3 100644
--- a/alfa-client/libs/user-profile/src/lib/user-profile-in-header-container/user-profile-in-header/user-profile-in-header.component.html
+++ b/alfa-client/libs/user-profile/src/lib/user-profile-in-header-container/user-profile-in-header/user-profile-in-header.component.html
@@ -38,6 +38,6 @@
 <ozgcloud-menu #accountMenu data-test-id="account-menu">
   <button mat-menu-item (click)="logoutEmitter.emit()" data-test-id="logout-button">
     <mat-icon>logout</mat-icon>
-    <span>Abmelden</span>
+    <span class="text-base">Abmelden</span>
   </button>
 </ozgcloud-menu>
diff --git a/alfa-client/libs/user-profile/src/lib/user-profile-search-container/user-profile-search/user-profile.search.formservice.ts b/alfa-client/libs/user-profile/src/lib/user-profile-search-container/user-profile-search/user-profile.search.formservice.ts
index 4ec86ff50492e343fb1fe25fe2936d8cab1e8e9a..7293348a84e515fc1ae97109279f3ea8e49375d4 100644
--- a/alfa-client/libs/user-profile/src/lib/user-profile-search-container/user-profile-search/user-profile.search.formservice.ts
+++ b/alfa-client/libs/user-profile/src/lib/user-profile-search-container/user-profile-search/user-profile.search.formservice.ts
@@ -21,12 +21,13 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
+import { AbstractFormService, ProblemDetail, StateResource } from '@alfa-client/tech-shared';
+import { UserProfileListResource, UserProfileService } from '@alfa-client/user-profile-shared';
 import { Injectable, OnDestroy } from '@angular/core';
 import { UntypedFormBuilder, UntypedFormControl, UntypedFormGroup } from '@angular/forms';
-import { AbstractFormService, StateResource } from '@alfa-client/tech-shared';
-import { UserProfileListResource, UserProfileService } from '@alfa-client/user-profile-shared';
 import { isNil } from 'lodash-es';
 import { Observable, Subscription } from 'rxjs';
+import { ValidationMessageCode } from '../../../../../tech-shared/src/lib/validation/tech.validation.messages';
 
 @Injectable()
 export class UserProfileSearchFormService extends AbstractFormService implements OnDestroy {
@@ -62,11 +63,11 @@ export class UserProfileSearchFormService extends AbstractFormService implements
   }
 
   public setEmptyUserProfileError(): void {
-    this.setErrorByApiError(emptyUserProfileError);
+    this.setErrorByProblemDetail(emptyUserProfileError);
   }
 
   public setNoUserProfileFoundError(): void {
-    this.setErrorByApiError(noUserProfileFoundError);
+    this.setErrorByProblemDetail(noUserProfileFoundError);
   }
 
   ngOnDestroy(): void {
@@ -74,23 +75,34 @@ export class UserProfileSearchFormService extends AbstractFormService implements
   }
 }
 
-const noUserProfileFoundError = {
-  issues: [
+const noUserProfileFoundError: ProblemDetail = {
+  type: null,
+  title: null,
+  status: null,
+  detail: null,
+  instance: null,
+  invalidParams: [
     {
-      field: 'only.fe.searchBy',
-      message: 'fe_only_validation_bearbeiter_not_exist',
-      messageCode: 'fe_only_validation_bearbeiter_not_exist',
-      parameters: [],
+      name: 'only.fe.searchBy',
+      reason: ValidationMessageCode.FIELD_ASSIGN_BEARBEITER_NOT_EXIST,
+      constraintParameters: [],
+      value: null,
     },
   ],
 };
-const emptyUserProfileError = {
-  issues: [
+
+const emptyUserProfileError: ProblemDetail = {
+  type: null,
+  title: null,
+  status: null,
+  detail: null,
+  instance: null,
+  invalidParams: [
     {
-      field: 'only.fe.searchBy',
-      message: 'validation_field_empty',
-      messageCode: 'validation_field_empty',
-      parameters: [],
+      name: 'only.fe.searchBy',
+      reason: ValidationMessageCode.FIELD_EMPTY,
+      constraintParameters: [],
+      value: null,
     },
   ],
 };
diff --git a/alfa-client/libs/vorgang-detail/src/lib/aktenzeichen-edit-dialog/aktenzeichen-edit-dialog.component.scss b/alfa-client/libs/vorgang-detail/src/lib/aktenzeichen-edit-dialog/aktenzeichen-edit-dialog.component.scss
index b61ea6c2be7bb5ea25305e910e0a68287228372b..7f465ba13ac6b4c51d5570ab26e7b4e77e93a158 100644
--- a/alfa-client/libs/vorgang-detail/src/lib/aktenzeichen-edit-dialog/aktenzeichen-edit-dialog.component.scss
+++ b/alfa-client/libs/vorgang-detail/src/lib/aktenzeichen-edit-dialog/aktenzeichen-edit-dialog.component.scss
@@ -50,7 +50,7 @@
 .hinweis {
   grid-area: hinweis;
   padding-left: 16px;
-  font-size: 14px;
+  font-size: 0.875rem;
 }
 
 ozgcloud-stroked-button-with-spinner {
diff --git a/alfa-client/libs/vorgang-detail/src/lib/aktenzeichen-editable/aktenzeichen-editable.component.html b/alfa-client/libs/vorgang-detail/src/lib/aktenzeichen-editable/aktenzeichen-editable.component.html
index 12e280dd9853ea90cd3db02843929d801bf39301..3f94a6da451f1731445c8b37487d6dfc03eb0fe6 100644
--- a/alfa-client/libs/vorgang-detail/src/lib/aktenzeichen-editable/aktenzeichen-editable.component.html
+++ b/alfa-client/libs/vorgang-detail/src/lib/aktenzeichen-editable/aktenzeichen-editable.component.html
@@ -23,14 +23,14 @@
     unter der Lizenz sind dem Lizenztext zu entnehmen.
 
 -->
-<div class="horizontal">
-  <div alfa-aktenzeichen class="ellipsis" [vorgang]="vorgang"></div>
-  <ng-container *ngIf="vorgang | hasLink: linkRel.SET_AKTENZEICHEN">
+<div class="flex flex-shrink" alfa-aktenzeichen [vorgang]="vorgang"></div>
+<ng-container *ngIf="vorgang | hasLink: linkRel.SET_AKTENZEICHEN">
+  <div class="relative w-12">
     <ozgcloud-icon-button-primary
       svgIcon="edit"
       tooltip="Aktenzeichen bearbeiten"
       data-test-id="aktenzeichen-editieren"
       (clickEmitter)="onEdit()"
     ></ozgcloud-icon-button-primary>
-  </ng-container>
-</div>
+  </div>
+</ng-container>
diff --git a/alfa-client/libs/vorgang-detail/src/lib/aktenzeichen-editable/aktenzeichen-editable.component.scss b/alfa-client/libs/vorgang-detail/src/lib/aktenzeichen-editable/aktenzeichen-editable.component.scss
index be66b5c81cdb771090d274585ae82dfe028a4b6d..dbb9218a330a285d37db355ff911cac5a991f9a9 100644
--- a/alfa-client/libs/vorgang-detail/src/lib/aktenzeichen-editable/aktenzeichen-editable.component.scss
+++ b/alfa-client/libs/vorgang-detail/src/lib/aktenzeichen-editable/aktenzeichen-editable.component.scss
@@ -22,21 +22,8 @@
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
 
-.horizontal {
-  display: flex;
-  align-items: center;
-  font-size: 16px;
-  font-weight: 300;
-}
-
-.ellipsis {
-  text-overflow: ellipsis;
-  white-space: nowrap;
-  overflow: hidden;
-}
-
 // Workaround Material's fixed 48px height
 :host ::ng-deep ozgcloud-icon-button-primary button {
   position: absolute;
-  top: -24px;
+  top: -14px;
 }
diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-action-buttons/vorgang-detail-action-buttons.component.html b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-action-buttons/vorgang-detail-action-buttons.component.html
index 85de971a72be9d72870985a6c9c32c35939b0079..2c9d56aca5b60504793eed40f24a3066de934e84 100644
--- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-action-buttons/vorgang-detail-action-buttons.component.html
+++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-action-buttons/vorgang-detail-action-buttons.component.html
@@ -82,9 +82,3 @@
   [showAsIconButton]="showAsIconButton"
   [vorgang]="vorgangWithEingang"
 ></alfa-postfach-mail-button-container>
-
-<alfa-create-bescheid-button-container
-  *ngIf="vorgangWithEingang | hasLink: vorgangWithEingangLinkRel.CREATE_BESCHEID"
-  [vorgangWithEingang]="vorgangWithEingang"
-  data-test-id="create-bescheid-button-container"
-></alfa-create-bescheid-button-container>
diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-action-buttons/vorgang-detail-action-buttons.component.spec.ts b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-action-buttons/vorgang-detail-action-buttons.component.spec.ts
index d62f61ebe56e9a706ee873724f56e4524b8c7d91..3d3eab79b4d777303aa0d2be366e76e21dcb3f23 100644
--- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-action-buttons/vorgang-detail-action-buttons.component.spec.ts
+++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-action-buttons/vorgang-detail-action-buttons.component.spec.ts
@@ -21,13 +21,7 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-import { ComponentFixture, TestBed } from '@angular/core/testing';
-import { CreateBescheidButtonContainerComponent } from '@alfa-client/bescheid';
-import {
-  EndgueltigLoeschenButtonContainerComponent,
-  LoeschAnforderungZuruecknehmenButtonContainerComponent,
-  LoeschenAnfordernButtonContainerComponent,
-} from '@alfa-client/loesch-anforderung';
+import { EndgueltigLoeschenButtonContainerComponent, LoeschAnforderungZuruecknehmenButtonContainerComponent, LoeschenAnfordernButtonContainerComponent } from '@alfa-client/loesch-anforderung';
 import { PostfachMailButtonContainerComponent } from '@alfa-client/postfach';
 import { HasLinkPipe } from '@alfa-client/tech-shared';
 import { existsAsHtmlElement, notExistsAsHtmlElement } from '@alfa-client/test-utils';
@@ -35,6 +29,7 @@ import { IconButtonWithSpinnerComponent } from '@alfa-client/ui';
 import { AssignUserProfileButtonContainerComponent } from '@alfa-client/user-profile';
 import { VorgangWithEingangLinkRel } from '@alfa-client/vorgang-shared';
 import { CreateWiedervorlageButtonContainerComponent } from '@alfa-client/wiedervorlage';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
 import { getDataTestIdOf } from 'libs/tech-shared/test/data-test';
 import { createVorgangWithEingangResource } from 'libs/vorgang-shared/test/vorgang';
 import { MockComponent } from 'ng-mocks';
@@ -77,7 +72,6 @@ describe('VorgangDetailActionButtonsComponent', () => {
         MockComponent(LoeschenAnfordernButtonContainerComponent),
         MockComponent(EndgueltigLoeschenButtonContainerComponent),
         MockComponent(LoeschAnforderungZuruecknehmenButtonContainerComponent),
-        MockComponent(CreateBescheidButtonContainerComponent),
       ],
     });
   });
diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-antragsteller/vorgang-detail-antragsteller.component.html b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-antragsteller/vorgang-detail-antragsteller.component.html
index d0a6bdc22500a72a94d95c18d503d083c005f7a9..11c9b0139c83dc5fbef7f1235df0c3a3559e19cb 100644
--- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-antragsteller/vorgang-detail-antragsteller.component.html
+++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-antragsteller/vorgang-detail-antragsteller.component.html
@@ -23,13 +23,13 @@
     unter der Lizenz sind dem Lizenztext zu entnehmen.
 
 -->
-<h3 class="font-medium leading-6 mb-2">Antragsteller</h3>
-<ul 
-  *ngIf="antragstellerExists; else noAntragsteller" 
-  data-test-id="antragsteller-list" 
-  class="text-sm leading-6 my-1"
+<h3 class="mb-2 font-medium leading-6">Antragsteller</h3>
+<ul
+  *ngIf="antragstellerExists; else noAntragsteller"
+  data-test-id="antragsteller-list"
+  class="my-1 text-sm leading-6"
 >
-  <div class="font-medium mb-2">
+  <div class="mb-2 font-medium">
     <h4 *ngIf="!isFirma && name" data-test-id="antragsteller-name" class="my-1">
       {{ name }}
     </h4>
@@ -40,12 +40,9 @@
   <li
     *ngIf="antragstellerStrasseHausnummer || antragstellerPlzOrt"
     data-test-id="antragsteller-adresse"
-    class="flex gap-2 my-2"
+    class="my-2 flex gap-2"
   >
-    <mat-icon
-      class="material-icons-outlined"
-      aria-label="Adresse"
-      aria-hidden="false"
+    <mat-icon class="material-icons-outlined" aria-label="Adresse" aria-hidden="false"
       >location_on</mat-icon
     >
     <div class="flex flex-col">
@@ -58,34 +55,26 @@
     </div>
   </li>
   <div *ngIf="isFirma && name" class="mb-1">
-    <h4 class="my-1 font-medium">
-      Ansprechpartner
-    </h4>
+    <h4 class="my-1 font-medium">Ansprechpartner</h4>
     <p class="my-1" data-test-id="antragsteller-ansprechpartner-name">{{ name }}</p>
   </div>
-  <li *ngIf="antragstellerData.email" [title]="email" class="flex gap-2 my-2">
-    <mat-icon
-      class="material-icons-outlined"
-      aria-label="E-Mail-Adresse"
-      aria-hidden="false"
+  <li *ngIf="antragstellerData.email" [title]="antragstellerData.email" class="my-2 flex gap-2">
+    <mat-icon class="material-icons-outlined" aria-label="E-Mail-Adresse" aria-hidden="false"
       >email</mat-icon
     >
     <p data-test-id="antragsteller-email">
       {{ antragstellerData.email }}
     </p>
   </li>
-  <li *ngIf="antragstellerData.telefon" class="flex gap-2 my-2">
-    <mat-icon
-      class="material-icons-outlined"
-      aria-label="Telefonnummer"
-      aria-hidden="false"
+  <li *ngIf="antragstellerData.telefon" class="my-2 flex gap-2">
+    <mat-icon class="material-icons-outlined" aria-label="Telefonnummer" aria-hidden="false"
       >call_black</mat-icon
     >
     <p data-test-id="antragsteller-telefon">
       {{ antragstellerData.telefon }}
     </p>
   </li>
-  <li *ngIf="geburt" class="flex gap-2 my-2">
+  <li *ngIf="geburt" class="my-2 flex gap-2">
     <mat-icon
       class="material-icons-outlined"
       aria-label="Geburtsdatum und Geburtsort"
diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-area.component.html b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-area.component.html
index ab08e19db0339b7d1aa5352adca61c0778cb7f95..2d16e8047196cf952d24fea9f905b058d7a3e9d9 100644
--- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-area.component.html
+++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-area.component.html
@@ -26,62 +26,82 @@
 <ozgcloud-spinner [stateResource]="vorgangStateResource" class="header-spinner"></ozgcloud-spinner>
 
 <ng-container *ngIf="vorgangStateResource.resource as vorgangResource">
-  <div class="container">
-    <alfa-vorgang-detail-header
-      [vorgangWithEingang]="vorgangResource"
-      class="mat-typography"
-      data-test-id="vorgang-detail-header"
-    ></alfa-vorgang-detail-header>
-
-    <div class="section one-column">
-      <alfa-vorgang-detail-formular-daten
+  <div
+    class="flex min-h-full grow flex-col divide-y divide-gray-200 border-l border-r border-gray-200 dark:divide-background-100 dark:border-transparent lg:flex-row lg:divide-x lg:divide-y-0"
+  >
+    <div class="w-full grow">
+      <alfa-vorgang-detail-header
         [vorgangWithEingang]="vorgangResource"
-      ></alfa-vorgang-detail-formular-daten>
+        data-test-id="vorgang-detail-header"
+      ></alfa-vorgang-detail-header>
 
-      <div *ngIf="vorgangResource | hasLink: vorgangWithEingangLinkRel.BESCHEIDE">
-        <ozgcloud-expansion-panel headline="Bescheid" data-test-id="bescheid-expansion-panel">
-          <alfa-bescheid-list-in-vorgang-container data-test-id="bescheid-container-in-vorgang">
-          </alfa-bescheid-list-in-vorgang-container>
-        </ozgcloud-expansion-panel>
-      </div>
+      <div class="section one-column">
+        <alfa-vorgang-detail-formular-daten
+          [vorgangWithEingang]="vorgangResource"
+        ></alfa-vorgang-detail-formular-daten>
 
-      <alfa-vorgang-detail-formular-buttons
-        [vorgangWithEingang]="vorgangResource"
-      ></alfa-vorgang-detail-formular-buttons>
-    </div>
+        <div *ngIf="vorgangResource | hasLink: vorgangWithEingangLinkRel.BESCHEIDE">
+          <ozgcloud-expansion-panel headline="Bescheid" data-test-id="bescheid-expansion-panel">
+            <alfa-bescheid-list-in-vorgang-container data-test-id="bescheid-container-in-vorgang">
+            </alfa-bescheid-list-in-vorgang-container>
+          </ozgcloud-expansion-panel>
+        </div>
 
-    <div class="two-column">
-      <div class="section" *ngIf="vorgangResource | hasLink: vorgangWithEingangLinkRel.FORWARDING">
-        <alfa-vorgang-forwarding-container
-          [vorgang]="vorgangResource"
-          data-test-id="forwarding-container-in-vorgang"
-        ></alfa-vorgang-forwarding-container>
+        <alfa-vorgang-detail-formular-buttons
+          [vorgangWithEingang]="vorgangResource"
+        ></alfa-vorgang-detail-formular-buttons>
       </div>
 
-      <div class="section" *ngIf="vorgangResource | hasLink: vorgangHeaderLinkRel.WIEDERVORLAGEN">
-        <alfa-wiedervorlage-list-in-vorgang-container
-          [vorgangStateResource]="vorgangStateResource"
-          data-test-id="wiedervorlagen-container-in-vorgang"
-        ></alfa-wiedervorlage-list-in-vorgang-container>
+      <div
+        class="section one-column"
+        *ngIf="vorgangResource | hasLink: vorgangWithEingangLinkRel.COLLABORATIONS"
+      >
+        <ozgcloud-expansion-panel
+          headline="Zusammenarbeit"
+          data-test-id="collaboration-expansion-panel"
+        >
+          <alfa-collaboration-in-vorgang-container
+            data-test-id="collaboration-in-voragng-container"
+          ></alfa-collaboration-in-vorgang-container>
+        </ozgcloud-expansion-panel>
       </div>
 
-      <div class="section" *ngIf="vorgangResource | hasLink: vorgangHeaderLinkRel.KOMMENTARE">
-        <alfa-kommentar-list-in-vorgang-container
-          [vorgangStateResource]="vorgangStateResource"
-          data-test-id="kommentar-container-in-vorgang"
-        ></alfa-kommentar-list-in-vorgang-container>
+      <div class="two-column">
+        <div
+          class="section"
+          *ngIf="vorgangResource | hasLink: vorgangWithEingangLinkRel.FORWARDING"
+        >
+          <alfa-vorgang-forwarding-container
+            [vorgang]="vorgangResource"
+            data-test-id="forwarding-container-in-vorgang"
+          ></alfa-vorgang-forwarding-container>
+        </div>
+
+        <div class="section" *ngIf="vorgangResource | hasLink: vorgangHeaderLinkRel.WIEDERVORLAGEN">
+          <alfa-wiedervorlage-list-in-vorgang-container
+            [vorgangStateResource]="vorgangStateResource"
+            data-test-id="wiedervorlagen-container-in-vorgang"
+          ></alfa-wiedervorlage-list-in-vorgang-container>
+        </div>
+
+        <div class="section" *ngIf="vorgangResource | hasLink: vorgangHeaderLinkRel.KOMMENTARE">
+          <alfa-kommentar-list-in-vorgang-container
+            [vorgangStateResource]="vorgangStateResource"
+            data-test-id="kommentar-container-in-vorgang"
+          ></alfa-kommentar-list-in-vorgang-container>
+        </div>
       </div>
     </div>
-  </div>
-  <div class="right">
-    <alfa-vorgang-detail-antragsteller
-      [antragsteller]="vorgangResource.eingang.antragsteller"
-      data-test-id="vorgang-detail-antragsteller"
-    ></alfa-vorgang-detail-antragsteller>
-    <alfa-postfach-mail-list-container
-      *ngIf="vorgangResource | hasLink: vorgangHeaderLinkRel.POSTFACH_MAILS"
-      [vorgangStateResource]="vorgangStateResource"
-      data-test-id="postfach-nachrichten-container-in-vorgang"
-    ></alfa-postfach-mail-list-container>
+    <div class="flex w-[calc(100vw-2.5rem)] flex-col px-6 py-4 lg:w-80 lg:px-3 lg:py-4">
+      <alfa-vorgang-detail-antragsteller
+        [antragsteller]="vorgangResource.eingang.antragsteller"
+        data-test-id="vorgang-detail-antragsteller"
+      ></alfa-vorgang-detail-antragsteller>
+      <alfa-postfach-mail-list-container
+        *ngIf="vorgangResource | hasLink: vorgangHeaderLinkRel.POSTFACH_MAILS"
+        [vorgangStateResource]="vorgangStateResource"
+        data-test-id="postfach-nachrichten-container-in-vorgang"
+      ></alfa-postfach-mail-list-container>
+    </div>
   </div>
 </ng-container>
diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-area.component.scss b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-area.component.scss
index b27537ba49e70f26ea5350c7ca2b70cd2163f2f6..c3a493baffe343fe0fddd809db8c86361a29229c 100644
--- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-area.component.scss
+++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-area.component.scss
@@ -25,27 +25,6 @@
 @import 'include-media/dist/include-media';
 @import 'variables';
 
-:host {
-  position: relative;
-  display: flex;
-  background-color: inherit;
-  width: 100%;
-}
-
-.container {
-  width: calc(100% - 300px);
-  border-left: 1px solid rgba(0, 0, 0, 0.08);
-  border-right: 1px solid rgba(0, 0, 0, 0.08);
-  min-height: calc(100vh - $header-height - $navigation-height);
-}
-
-.right {
-  right: 21px;
-  width: 300px;
-  padding: 12px 16px;
-  display: flex;
-  flex-direction: column;
-}
 
 .header-spinner {
   position: absolute;
diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-area.component.spec.ts b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-area.component.spec.ts
index 34870cb494be2e9160e6101076214483ad95ff0b..7786b45a3e33dc073681a9cb53887a78d3a9587e 100644
--- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-area.component.spec.ts
+++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-area.component.spec.ts
@@ -21,6 +21,7 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
+import { CollaborationInVorgangContainerComponent } from '@alfa-client/collaboration';
 import { VorgangForwardingContainerComponent } from '@alfa-client/forwarding';
 import { KommentarListInVorgangContainerComponent } from '@alfa-client/kommentar';
 import { PostfachMailListContainerComponent } from '@alfa-client/postfach';
@@ -30,6 +31,7 @@ import {
   createEmptyStateResource,
   createStateResource,
 } from '@alfa-client/tech-shared';
+import { existsAsHtmlElement, notExistsAsHtmlElement } from '@alfa-client/test-utils';
 import {
   ExpansionPanelComponent,
   OzgcloudStrokedButtonWithSpinnerComponent,
@@ -57,6 +59,7 @@ describe('VorgangDetailAreaComponent', () => {
   let component: VorgangDetailAreaComponent;
   let fixture: ComponentFixture<VorgangDetailAreaComponent>;
 
+  const collaborationContainer: string = getDataTestIdOf('collaboration-in-voragng-container');
   const wiedervorlagenContainer: string = getDataTestIdOf('wiedervorlagen-container-in-vorgang');
   const kommentarContainer: string = getDataTestIdOf('kommentar-container-in-vorgang');
   const postfachNachrichtenContainer: string = getDataTestIdOf(
@@ -86,6 +89,7 @@ describe('VorgangDetailAreaComponent', () => {
         MockComponent(VorgangForwardingContainerComponent),
         MockComponent(BescheidListInVorgangContainerComponent),
         MockComponent(ExpansionPanelComponent),
+        MockComponent(CollaborationInVorgangContainerComponent),
       ],
     }).compileComponents();
   });
@@ -101,6 +105,26 @@ describe('VorgangDetailAreaComponent', () => {
     expect(component).toBeTruthy();
   });
 
+  describe('Collaboration', () => {
+    it('should be visibile if link is present', () => {
+      component.vorgangStateResource = createStateResource(
+        createVorgangWithEingangResource([VorgangWithEingangLinkRel.COLLABORATIONS]),
+      );
+
+      fixture.detectChanges();
+
+      existsAsHtmlElement(fixture, collaborationContainer);
+    });
+
+    it('should be hidden if link is missing', () => {
+      component.vorgangStateResource = createStateResource(vorgang);
+
+      fixture.detectChanges();
+
+      notExistsAsHtmlElement(fixture, collaborationContainer);
+    });
+  });
+
   describe('wiedervorlagen', () => {
     it('should be visible', () => {
       component.vorgangStateResource = createStateResource(
diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-area.component.ts b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-area.component.ts
index 09cee300973dd96c97e72416ae51f1c5659b914f..f6a3f401d927e1350cb0903df7cc30ef6a5fa84e 100644
--- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-area.component.ts
+++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-area.component.ts
@@ -33,6 +33,7 @@ import { Component, Input } from '@angular/core';
   selector: 'alfa-vorgang-detail-area',
   templateUrl: './vorgang-detail-area.component.html',
   styleUrls: ['./vorgang-detail-area.component.scss'],
+  styles: [':host {@apply relative w-full}'],
 })
 export class VorgangDetailAreaComponent {
   @Input() vorgangStateResource: StateResource<VorgangWithEingangResource>;
diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-formular-daten/vorgang-detail-antrag-data/vorgang-detail-eingang-header/vorgang-detail-eingang-header.component.html b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-formular-daten/vorgang-detail-antrag-data/vorgang-detail-eingang-header/vorgang-detail-eingang-header.component.html
index f380c834f477c400ea3f433c010d5042d310dfe8..f98881642b25040932ffba2562c09236cac0d56b 100644
--- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-formular-daten/vorgang-detail-antrag-data/vorgang-detail-eingang-header/vorgang-detail-eingang-header.component.html
+++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-formular-daten/vorgang-detail-antrag-data/vorgang-detail-eingang-header/vorgang-detail-eingang-header.component.html
@@ -23,7 +23,7 @@
     unter der Lizenz sind dem Lizenztext zu entnehmen.
 
 -->
-<table aria-label="Eingangsdaten">
+<table aria-label="Eingangsdaten" class="text-sm">
   <tr>
     <th scope="col">Formularfeld</th>
     <th scope="col">Formulareingabe</th>
diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-formular-daten/vorgang-detail-form-data-table/vorgang-detail-form-data-table.component.html b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-formular-daten/vorgang-detail-form-data-table/vorgang-detail-form-data-table.component.html
index 0fe8366d794c27918ea8b9379d8f62177093f1fd..d1278b5dd728a544987d02dad56a18edb886505a 100644
--- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-formular-daten/vorgang-detail-form-data-table/vorgang-detail-form-data-table.component.html
+++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-formular-daten/vorgang-detail-form-data-table/vorgang-detail-form-data-table.component.html
@@ -23,7 +23,7 @@
     unter der Lizenz sind dem Lizenztext zu entnehmen.
 
 -->
-<table aria-label="Formulardaten" *ngIf="isObject(formData) && !isArray(formData)">
+<table class="text-sm" aria-label="Formulardaten" *ngIf="isObject(formData) && !isArray(formData)">
   <tr>
     <th scope="col">Formularfeld</th>
     <th scope="col">Formulareingabe</th>
@@ -43,7 +43,7 @@
   </tr>
 </table>
 
-<table aria-label="Formulardaten" *ngIf="isArray(formData)">
+<table class="text-sm" aria-label="Formulardaten" *ngIf="isArray(formData)">
   <tr>
     <th scope="col">Formulareingabe</th>
   </tr>
diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-formular-daten/vorgang-detail-formular-daten.component.scss b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-formular-daten/vorgang-detail-formular-daten.component.scss
index 0398e355577626ab5eb2c15f4a48ef0779fcc557..20502e39cc84dcfed0c934c467c3cb7cd7dec769 100644
--- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-formular-daten/vorgang-detail-formular-daten.component.scss
+++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-formular-daten/vorgang-detail-formular-daten.component.scss
@@ -24,3 +24,7 @@
 mat-tab-group {
   padding-right: 1rem;
 }
+
+::ng-deep .mat-tab-header {
+  overflow-x: scroll !important;
+}
diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-header/vorgang-detail-header.component.html b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-header/vorgang-detail-header.component.html
index 976a5a346670cbc0d0b44b77143781bd2b5a2472..53bde5e294bc362da2e488e9be63a802e33b57ab 100644
--- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-header/vorgang-detail-header.component.html
+++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-header/vorgang-detail-header.component.html
@@ -23,39 +23,50 @@
     unter der Lizenz sind dem Lizenztext zu entnehmen.
 
 -->
-<alfa-vorgang-status-dot [status]="vorgang.status" class="status-dot"></alfa-vorgang-status-dot>
 
-<div class="flex flex-row items-center gap-7">
-  <alfa-vorgang-status-text
-    [status]="vorgang.status"
-    data-test-id="status-text"
-    class="status-text"
-  ></alfa-vorgang-status-text>
-  <alfa-beschieden-date-in-vorgang-container></alfa-beschieden-date-in-vorgang-container>
+<div class="flex flex-row">
+  <div class="flex w-12 flex-shrink-0 flex-grow-0 items-center">
+    <alfa-vorgang-status-dot [status]="vorgang.status" class="status-dot"></alfa-vorgang-status-dot>
+  </div>
+  <div class="flex flex-shrink flex-grow flex-wrap gap-x-3 gap-y-1">
+    <div class="flex flex-grow gap-7">
+      <alfa-vorgang-status-text
+        [status]="vorgang.status"
+        data-test-id="status-text"
+        class="status-text"
+      ></alfa-vorgang-status-text>
+      <alfa-beschieden-date-in-vorgang-container></alfa-beschieden-date-in-vorgang-container>
+    </div>
+    <div class="initial-date text-sm" data-test-id="created-at">
+      {{ vorgang.createdAt | date: 'EEEE, d. LLLL y, H:mm' }}
+    </div>
+  </div>
 </div>
 
-<div class="initial-date" data-test-id="created-at">
-  {{ vorgang.createdAt | date: 'EEEE, d. LLLL y, H:mm' }}
+<div class="ml-12 flex flex-row gap-6">
+  <div class="flex flex-grow flex-col gap-x-3 gap-y-1">
+    <h2 data-test-id="name" class="mb-1.5 mt-4 break-all text-base font-medium">
+      {{ vorgang.name }}
+    </h2>
+    <alfa-vorgang-nummer class="vorgang-nummer" [vorgang]="vorgang"></alfa-vorgang-nummer>
+    <div class="flex flex-1 flex-row gap-1">
+      <div class="flex flex-shrink-0" [class.text-gray-400]="!hasAktenzeichen">
+        <mat-icon svgIcon="az" style="width: 1.5rem; height: 1.5rem"></mat-icon>
+      </div>
+      <alfa-aktenzeichen-editable
+        data-test-id="alfa-aktenzeichen-editable-button"
+        class="flex flex-grow"
+        [class.text-gray-400]="!hasAktenzeichen"
+        [vorgang]="vorgang"
+      ></alfa-aktenzeichen-editable>
+    </div>
+  </div>
+  <div class="mt-4 w-10 flex-shrink-0 flex-grow-0">
+    <alfa-user-profile-in-vorgang-container
+      *ngIf="vorgang | hasLink: linkRel.ASSIGN"
+      data-test-id="vorgang-header-user-icon"
+      [vorgang]="vorgang"
+      class="user"
+    ></alfa-user-profile-in-vorgang-container>
+  </div>
 </div>
-
-<alfa-vorgang-nummer class="vorgang-nummer big" [vorgang]="vorgang"></alfa-vorgang-nummer>
-
-<div class="aktenzeichen" [class.aktenzeichen--active]="hasAktenzeichen">
-  <mat-icon svgIcon="az"></mat-icon>
-  <alfa-aktenzeichen-editable
-    class="aktenzeichen-editable"
-    [vorgang]="vorgang"
-  ></alfa-aktenzeichen-editable>
-</div>
-
-<div data-test-id="name" class="name">
-  {{ vorgang.name }}
-</div>
-
-<alfa-user-profile-in-vorgang-container
-  *ngIf="vorgang | hasLink: linkRel.ASSIGN"
-  data-test-id="vorgang-header-user-icon"
-  [vorgang]="vorgang"
-  class="user"
->
-</alfa-user-profile-in-vorgang-container>
diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-header/vorgang-detail-header.component.scss b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-header/vorgang-detail-header.component.scss
index 62adcc21dd7dcfdda38c96f774b16d8af49b5c39..90cd66da90d80e78e540c55a81c54c45b18ba321 100644
--- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-header/vorgang-detail-header.component.scss
+++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-header/vorgang-detail-header.component.scss
@@ -21,92 +21,6 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-@import 'breakpoints';
-@import 'include-media/dist/include-media';
-@import 'variables';
-
 :host {
-  display: grid;
-  row-gap: 10px;
-  align-items: center;
-  grid-template-columns: 48px 1fr 8%;
-  grid-template-areas:
-    'status-dot status-text initial-date'
-    '. name user'
-    '. vorgang-nummer user'
-    '. aktenzeichen aktenzeichen';
-
-  padding: 1rem 1.5rem;
-}
-
-.name {
-  line-height: 1.4;
-  margin: 8px 0 4px 0;
-  font-size: 16px;
-  font-weight: 500;
-}
-
-.ellipsis {
-  text-overflow: ellipsis;
-  white-space: nowrap;
-  overflow: hidden;
-}
-
-mat-icon {
-  margin: 0 0.5rem 0 -0rem;
-  height: 1.875rem;
-  min-height: 1.875rem;
-  width: 1.875rem;
-  min-width: 1.875rem;
-}
-
-.status-dot {
-  grid-area: status-dot;
-}
-
-.status-text {
-  grid-area: status-text;
-}
-
-.initial-date {
-  grid-area: initial-date;
-  justify-self: end;
-  white-space: nowrap;
-}
-
-.aktenzeichen {
-  grid-area: aktenzeichen;
-  margin-left: -2px;
-  display: flex;
-  align-items: center;
-  color: #c2c2c2;
-
-  &--active {
-    color: unset;
-  }
-
-  .aktenzeichen-editable {
-    width: calc(100% - 82px);
-  }
-}
-
-.vorgang-nummer {
-  grid-area: vorgang-nummer;
-  margin-left: -2px;
-}
-
-.name {
-  grid-area: name;
-  align-self: start;
-}
-
-.user {
-  grid-area: user;
-  align-self: start;
-  justify-self: end;
-}
-
-.status {
-  display: flex;
-  flex-direction: column;
-}
+  @apply flex flex-col px-6 py-4;
+}
\ No newline at end of file
diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-header/vorgang-detail-header.component.spec.ts b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-header/vorgang-detail-header.component.spec.ts
index 85e1fd655bb0390a80cd39b79e3acae785ca68d6..292996ceb1f44de52245d522725c0243cc9c9b55 100644
--- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-header/vorgang-detail-header.component.spec.ts
+++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-header/vorgang-detail-header.component.spec.ts
@@ -23,13 +23,9 @@
  */
 import { BeschiedenDateInVorgangContainerComponent } from '@alfa-client/bescheid';
 import { EMPTY_STRING, EnumToLabelPipe, HasLinkPipe } from '@alfa-client/tech-shared';
-import { getDebugElementFromFixtureByCss } from '@alfa-client/test-utils';
+import { getDebugElementFromFixtureByCss, getElementFromFixture } from '@alfa-client/test-utils';
 import { VorgangHeaderLinkRel } from '@alfa-client/vorgang-shared';
-import {
-  VorgangNummerComponent,
-  VorgangStatusDotComponent,
-  VorgangStatusTextComponent,
-} from '@alfa-client/vorgang-shared-ui';
+import { VorgangNummerComponent, VorgangStatusDotComponent, VorgangStatusTextComponent } from '@alfa-client/vorgang-shared-ui';
 import { DebugElement } from '@angular/core';
 import { ComponentFixture, TestBed } from '@angular/core/testing';
 import { MatIcon } from '@angular/material/icon';
@@ -46,6 +42,9 @@ describe('VorgangDetailHeaderComponent', () => {
   let fixture: ComponentFixture<VorgangDetailHeaderComponent>;
 
   const user: string = getDataTestIdOf('vorgang-header-user-icon');
+  const aktenzeichenEditableComponentDataTestId: string = getDataTestIdOf(
+    'alfa-aktenzeichen-editable-button',
+  );
 
   beforeEach(async () => {
     await TestBed.configureTestingModule({
@@ -111,16 +110,16 @@ describe('VorgangDetailHeaderComponent', () => {
       expect(component.hasAktenzeichen).toBeFalsy();
     });
 
-    it('should set class aktenzeichen--active for aktenzeichen', () => {
+    it('should NOT set class text-gray-400 for aktenzeichen', () => {
       fixture.detectChanges();
 
-      const element = getDebugElementFromFixtureByCss(fixture, 'div.aktenzeichen--active');
+      const element = getDebugElementFromFixtureByCss(fixture, 'div.text-gray-400');
 
-      expect(element).toBeInstanceOf(DebugElement);
+      expect(element).not.toBeInstanceOf(DebugElement);
     });
 
     it.each([null, EMPTY_STRING])(
-      'should NOT set class aktenzeichen--active for aktenzeichen %s',
+      'should set class text-gray-400 for aktenzeichen %s',
       (aktenzeichen: string) => {
         const vorgangWithEingang = createVorgangWithEingangResource();
         vorgangWithEingang.aktenzeichen = aktenzeichen;
@@ -128,10 +127,33 @@ describe('VorgangDetailHeaderComponent', () => {
 
         fixture.detectChanges();
 
-        const element = getDebugElementFromFixtureByCss(fixture, 'div.aktenzeichen--active');
+        const element = getDebugElementFromFixtureByCss(fixture, 'div.text-gray-400');
 
-        expect(element).not.toBeInstanceOf(DebugElement);
+        expect(element).toBeInstanceOf(DebugElement);
       },
     );
+
+    it.each([null, EMPTY_STRING])(
+      'should set class text-gray-400 for alfa-aktenzeichen-editable %s',
+      (aktenzeichen: string) => {
+        const vorgangWithEingang = createVorgangWithEingangResource();
+        vorgangWithEingang.aktenzeichen = aktenzeichen;
+        component.vorgangWithEingang = vorgangWithEingang;
+
+        fixture.detectChanges();
+
+        const element = getElementFromFixture(fixture, aktenzeichenEditableComponentDataTestId);
+
+        expect(element).toHaveClass('text-gray-400');
+      },
+    );
+
+    it('should NOT set class text-gray-400 for alfa-aktenzeichen-editable', () => {
+      fixture.detectChanges();
+
+      const element = getElementFromFixture(fixture, aktenzeichenEditableComponentDataTestId);
+
+      expect(element).not.toHaveClass('text-gray-400');
+    });
   });
 });
diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-header/vorgang-detail-header.component.ts b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-header/vorgang-detail-header.component.ts
index e0a5d6854b61a58401ea6c9830a9b76ea8a95cbf..4748530c41f1b37ca65281ccaaba44b08c47eebe 100644
--- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-header/vorgang-detail-header.component.ts
+++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-header/vorgang-detail-header.component.ts
@@ -21,15 +21,15 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-import { Component, Input } from '@angular/core';
-import { VorgangWithEingangLinkRel, VorgangWithEingangResource } from '@alfa-client/vorgang-shared';
 import { isNotEmpty } from '@alfa-client/tech-shared';
+import { VorgangWithEingangLinkRel, VorgangWithEingangResource } from '@alfa-client/vorgang-shared';
+import { Component, Input } from '@angular/core';
 import { createVorgangWithEingangResource } from '../../../../../../vorgang-shared/test/vorgang';
 
 @Component({
   selector: 'alfa-vorgang-detail-header',
   templateUrl: './vorgang-detail-header.component.html',
-  styleUrls: ['./vorgang-detail-header.component.scss'],
+  styles: [':host {@apply flex flex-col px-6 py-4}'],
 })
 export class VorgangDetailHeaderComponent {
   readonly linkRel = VorgangWithEingangLinkRel;
diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-attachments/vorgang-detail-bescheiden-result-attachments.component.html b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-attachments/vorgang-detail-bescheiden-result-attachments.component.html
index ff4e542e0d9181e9ee7bc98b468e62b2a1d23482..78e9fba0ee241ee0b39e7a9e4d771e48cb1b84fd 100644
--- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-attachments/vorgang-detail-bescheiden-result-attachments.component.html
+++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-attachments/vorgang-detail-bescheiden-result-attachments.component.html
@@ -22,7 +22,7 @@
       *ngIf="uploadFileInProgress.loading || uploadFileInProgress.error"
       [loadingCaption]="uploadFileInProgress.fileName"
       errorCaption="Fehler beim Hochladen"
-      [errorMessages]="uploadFileInProgress.error | convertApiErrorToErrorMessages"
+      [errorMessages]="uploadFileInProgress.error | convertProblemDetailToErrorMessages"
       description="Anhang wird hochgeladen"
       [isLoading]="uploadFileInProgress.loading"
     ></ods-attachment>
diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-attachments/vorgang-detail-bescheiden-result-attachments.component.spec.ts b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-attachments/vorgang-detail-bescheiden-result-attachments.component.spec.ts
index 63758c537759f45fbe750b6c286b6b2e5778864d..caed9958a4f9dc70ae170976ae44c01c77e8e235 100644
--- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-attachments/vorgang-detail-bescheiden-result-attachments.component.spec.ts
+++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-attachments/vorgang-detail-bescheiden-result-attachments.component.spec.ts
@@ -2,7 +2,6 @@ import { BescheidService } from '@alfa-client/bescheid-shared';
 import { BinaryFile2ContainerComponent } from '@alfa-client/binary-file';
 import { BinaryFileResource } from '@alfa-client/binary-file-shared';
 import {
-  ConvertApiErrorToErrorMessagesPipe,
   convertForDataTest,
   ConvertForDataTestPipe,
   createErrorStateResource,
@@ -15,6 +14,7 @@ import { OzgcloudSvgIconComponent, SpinnerComponent } from '@alfa-client/ui';
 import { ComponentFixture, TestBed } from '@angular/core/testing';
 import { MatIcon } from '@angular/material/icon';
 import { AttachmentComponent, AttachmentWrapperComponent, SpinnerIconComponent } from '@ods/system';
+import { ConvertProblemDetailToErrorMessagesPipe } from 'libs/tech-shared/src/lib/pipe/convert-problem-detail-to-error-messages.pipe';
 import { MockComponent, MockPipe } from 'ng-mocks';
 import { BehaviorSubject, EMPTY, Observable, of, Subscription } from 'rxjs';
 import { createUploadFileInProgress } from '../../../../../../../bescheid-shared/src/test/bescheid';
@@ -51,7 +51,7 @@ describe('VorgangDetailBescheidenResultAttachmentsComponent', () => {
         ConvertForDataTestPipe,
         MatIcon,
         MockPipe(FileSizePipe),
-        MockPipe(ConvertApiErrorToErrorMessagesPipe),
+        MockPipe(ConvertProblemDetailToErrorMessagesPipe),
         MockComponent(OzgcloudSvgIconComponent),
         MockComponent(SpinnerComponent),
         MockComponent(AttachmentWrapperComponent),
diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-dokument/vorgang-detail-bescheiden-result-dokument.component.html b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-dokument/vorgang-detail-bescheiden-result-dokument.component.html
index bb762af88d7b449d222804be6eccd2be60690f5e..d94edab530d6fb8fcdce754bee1d5083f0e7e6b7 100644
--- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-dokument/vorgang-detail-bescheiden-result-dokument.component.html
+++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-dokument/vorgang-detail-bescheiden-result-dokument.component.html
@@ -27,7 +27,7 @@
       'upload-bescheid-document-error-' + !!uploadBescheidDocumentInProgress.error
     "
     [isLoading]="uploadBescheidDocumentInProgress.loading"
-    [errorMessages]="uploadBescheidDocumentInProgress.error | convertApiErrorToErrorMessages"
+    [errorMessages]="uploadBescheidDocumentInProgress.error | convertProblemDetailToErrorMessages"
     description="Bescheiddokument wird hochgeladen"
   ></ods-attachment>
   <ods-attachment
diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-dokument/vorgang-detail-bescheiden-result-dokument.component.spec.ts b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-dokument/vorgang-detail-bescheiden-result-dokument.component.spec.ts
index c61b90e368bb525ef644dfd2e95d156c06338d22..7dceb5ce5ba5e75c88ddb80fdd529a89b3e5ed41 100644
--- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-dokument/vorgang-detail-bescheiden-result-dokument.component.spec.ts
+++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-dokument/vorgang-detail-bescheiden-result-dokument.component.spec.ts
@@ -2,7 +2,6 @@ import { BescheidLinkRel, BescheidResource, BescheidService } from '@alfa-client
 import { BinaryFile2ContainerComponent } from '@alfa-client/binary-file';
 import { CommandResource } from '@alfa-client/command-shared';
 import {
-  ConvertApiErrorToErrorMessagesPipe,
   StateResource,
   createEmptyStateResource,
   createStateResource,
@@ -13,6 +12,7 @@ import { getUrl } from '@ngxp/rest';
 import { AttachmentComponent, AttachmentWrapperComponent } from '@ods/system';
 import { createBescheidResource } from 'libs/bescheid-shared/src/test/bescheid';
 import { createBinaryFileResource } from 'libs/binary-file-shared/test/binary-file';
+import { ConvertProblemDetailToErrorMessagesPipe } from 'libs/tech-shared/src/lib/pipe/convert-problem-detail-to-error-messages.pipe';
 import { getDataTestIdOf } from 'libs/tech-shared/test/data-test';
 import { createApiError } from 'libs/tech-shared/test/error';
 import { MockComponent, MockPipe } from 'ng-mocks';
@@ -48,7 +48,7 @@ describe('VorgangDetailBescheidenResultDokumentComponent', () => {
         MockComponent(BinaryFile2ContainerComponent),
         MockComponent(AttachmentComponent),
         MockComponent(AttachmentWrapperComponent),
-        MockPipe(ConvertApiErrorToErrorMessagesPipe),
+        MockPipe(ConvertProblemDetailToErrorMessagesPipe),
       ],
       providers: [
         {
diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result.component.spec.ts b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result.component.spec.ts
index 22332fc5187c9ce1bc318ceb77b4b7ad0e30e833..b97073aba59db97bc5c523bfb34b83155061bf7a 100644
--- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result.component.spec.ts
+++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result.component.spec.ts
@@ -413,7 +413,7 @@ describe('VorgangDetailBescheidenResultComponent', () => {
     });
 
     it('should call formservice submit', () => {
-      component.doUpdateAndSend(bescheidDraft, jest.fn()).pipe(first()).subscribe();
+      component.doUpdateAndSend(bescheidDraft, jest.fn()).subscribe();
 
       expect(formService.submit).toHaveBeenCalled();
     });
@@ -607,7 +607,7 @@ describe('VorgangDetailBescheidenResultComponent', () => {
 
   describe('get active step', () => {
     it('should call formService', () => {
-      component.getActiveStep().pipe(first()).subscribe();
+      component.getActiveStep().subscribe();
 
       expect(formService.getActiveStep).toHaveBeenCalled();
     });
@@ -617,7 +617,7 @@ describe('VorgangDetailBescheidenResultComponent', () => {
       (step: number) => {
         formService.getActiveStep.mockReturnValue(of(step));
 
-        component.getActiveStep().pipe(first()).subscribe();
+        component.getActiveStep().subscribe();
 
         expect(bescheidService.clearAttachmentUpload).toHaveBeenCalled();
       },
@@ -633,7 +633,7 @@ describe('VorgangDetailBescheidenResultComponent', () => {
         (step: number) => {
           formService.getActiveStep.mockReturnValue(of(step));
 
-          component.getActiveStep().pipe(first()).subscribe();
+          component.getActiveStep().subscribe();
 
           expect(component.resetSend).toHaveBeenCalled();
         },
@@ -642,7 +642,7 @@ describe('VorgangDetailBescheidenResultComponent', () => {
       it('should not be called on last step', () => {
         formService.getActiveStep.mockReturnValue(of(3));
 
-        component.getActiveStep().pipe(first()).subscribe();
+        component.getActiveStep().subscribe();
 
         expect(component.resetSend).not.toHaveBeenCalled();
       });
@@ -656,7 +656,6 @@ describe('VorgangDetailBescheidenResultComponent', () => {
       component.resetSend();
 
       component.saveAndSendInProgress$
-        .pipe(first())
         .subscribe((saveAndSendInProgress: StateResource<CommandResource>) => {
           expect(saveAndSendInProgress).toEqual(createEmptyStateResource());
           done();
diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-steps/vorgang-detail-bescheiden-steps-content/vorgang-detail-bescheiden-antrag-bescheiden/vorgang-detail-bescheiden-antrag-bescheiden.component.html b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-steps/vorgang-detail-bescheiden-steps-content/vorgang-detail-bescheiden-antrag-bescheiden/vorgang-detail-bescheiden-antrag-bescheiden.component.html
index ad1704f9c19a82c2a3fe30cb866eb98730f4ff69..22c3e14619ff5c4636838a058b8e614684b64a83 100644
--- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-steps/vorgang-detail-bescheiden-steps-content/vorgang-detail-bescheiden-antrag-bescheiden/vorgang-detail-bescheiden-antrag-bescheiden.component.html
+++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-steps/vorgang-detail-bescheiden-steps-content/vorgang-detail-bescheiden-antrag-bescheiden/vorgang-detail-bescheiden-antrag-bescheiden.component.html
@@ -14,7 +14,7 @@
       value="false"
       data-test-id="button-abgelehnt"
       variant="bescheid_abgelehnt"
-      ><ods-close-icon size="medium" class="fill-abgelehnt"></ods-close-icon>
+      ><ods-close-icon size="large" class="fill-abgelehnt"></ods-close-icon>
     </ods-radio-button-card>
   </div>
   <div class="flex w-full">
diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-page.component.html b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-page.component.html
index b985566e1869ee4b1de3b2588dd7188845a72768..db812801dad788276e27e6c98981813d383bfc0d 100644
--- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-page.component.html
+++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-page.component.html
@@ -23,7 +23,8 @@
     unter der Lizenz sind dem Lizenztext zu entnehmen.
 
 -->
-<ng-container *ngIf="vorgangStateResource$ | async as vorgangStateResource">
+<main *ngIf="vorgangStateResource$ | async as vorgangStateResource">
+  <h1 class="sr-only">Details zum Vorgang</h1>
   <ozgcloud-subnavigation class="mat-typography mat-app-background" data-test-id="subnavigation">
     <alfa-vorgang-detail-back-button-container></alfa-vorgang-detail-back-button-container>
     <ng-container *ngIf="vorgangStateResource.resource">
@@ -38,14 +39,16 @@
     </ng-container>
   </ozgcloud-subnavigation>
 
-  <div class="l-scroll-area--full">
+  <div
+    class="l-scroll-area--full flex border-l border-r border-grayborder/30 dark:border-transparent"
+  >
     <alfa-vorgang-detail-area
       *ngIf="vorgangStateResource"
       [vorgangStateResource]="vorgangStateResource"
       data-test-id="detail-area"
     ></alfa-vorgang-detail-area>
   </div>
-</ng-container>
+</main>
 
 <ozgcloud-progress-bar
   [stateResource]="revokeCommandStateResource$ | async"
diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail.module.ts b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail.module.ts
index 5a6d84231e9b41aa3bc51655315edd6ff5e4e531..4ab436286109e6af58e8fa0d851edf0d074ee1f7 100644
--- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail.module.ts
+++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail.module.ts
@@ -23,6 +23,7 @@
  */
 import { BescheidModule } from '@alfa-client/bescheid';
 import { BinaryFileModule } from '@alfa-client/binary-file';
+import { CollaborationModule } from '@alfa-client/collaboration';
 import { ForwardingModule } from '@alfa-client/forwarding';
 import { HistorieModule } from '@alfa-client/historie';
 import { KommentarModule } from '@alfa-client/kommentar';
@@ -161,6 +162,7 @@ const routes: Routes = [
     TextareaEditorComponent,
     BescheidStatusTextComponent,
     ErrorMessageComponent,
+    CollaborationModule,
   ],
   declarations: [
     VorgangDetailPageComponent,
diff --git a/alfa-client/libs/vorgang-shared-ui/src/index.ts b/alfa-client/libs/vorgang-shared-ui/src/index.ts
index 8184426d005669520ee4aecfb7c9089f7500fbda..af3be465ac6cfdacf0f35612a2ed3b20d453b6ab 100644
--- a/alfa-client/libs/vorgang-shared-ui/src/index.ts
+++ b/alfa-client/libs/vorgang-shared-ui/src/index.ts
@@ -22,7 +22,6 @@
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
 export * from './lib/aktenzeichen/aktenzeichen.component';
-export * from './lib/vorgang-in-postfach-breadcrumb-container/vorgang-in-postfach-breadcrumb-container.component';
 export * from './lib/vorgang-nummer/vorgang-nummer.component';
 export * from './lib/vorgang-search-container/vorgang-search-container.component';
 export * from './lib/vorgang-shared-ui.module';
diff --git a/alfa-client/libs/vorgang-shared-ui/src/lib/aktenzeichen/aktenzeichen.component.html b/alfa-client/libs/vorgang-shared-ui/src/lib/aktenzeichen/aktenzeichen.component.html
index 5721feaf55413b70b412e07ccafb3856599e39a4..de19cd3d1c9c817c155c02dbce1f0a4caef91339 100644
--- a/alfa-client/libs/vorgang-shared-ui/src/lib/aktenzeichen/aktenzeichen.component.html
+++ b/alfa-client/libs/vorgang-shared-ui/src/lib/aktenzeichen/aktenzeichen.component.html
@@ -23,6 +23,10 @@
     unter der Lizenz sind dem Lizenztext zu entnehmen.
 
 -->
-<span [matTooltip]="aktenzeichen" data-test-id="aktenzeichen" class="truncate">{{
-  aktenzeichen
-}}</span>
+<div
+  class="line-clamp-1 flex-shrink overflow-hidden break-all text-base font-normal lg:line-clamp-none lg:flex"
+  data-test-id="aktenzeichen"
+  [matTooltip]="aktenzeichen"
+>
+  {{ aktenzeichen }}
+</div>
diff --git a/alfa-client/libs/vorgang-shared-ui/src/lib/aktenzeichen/aktenzeichen.component.spec.ts b/alfa-client/libs/vorgang-shared-ui/src/lib/aktenzeichen/aktenzeichen.component.spec.ts
index 44c38ecb399f0407d118f8ceda4b8ae6089d9e46..05840895fe5579580d83309bb74166ec39bb0cde 100644
--- a/alfa-client/libs/vorgang-shared-ui/src/lib/aktenzeichen/aktenzeichen.component.spec.ts
+++ b/alfa-client/libs/vorgang-shared-ui/src/lib/aktenzeichen/aktenzeichen.component.spec.ts
@@ -61,7 +61,7 @@ describe('AktenzeichenComponent', () => {
       fixture.detectChanges();
       const aktenzeichenMessage: HTMLElement = fixture.nativeElement.querySelector(aktenzeichen);
 
-      expect(aktenzeichenMessage.innerHTML).toBe(VORGANG_KEIN_AKTENZEICHEN_ZUGEWIESEN);
+      expect(aktenzeichenMessage.innerHTML.trim()).toBe(VORGANG_KEIN_AKTENZEICHEN_ZUGEWIESEN);
     });
 
     it('should show aktenzeichen', () => {
@@ -70,7 +70,7 @@ describe('AktenzeichenComponent', () => {
       fixture.detectChanges();
       const aktenzeichenMessage: HTMLElement = fixture.nativeElement.querySelector(aktenzeichen);
 
-      expect(aktenzeichenMessage.textContent).toBe(vorgang.aktenzeichen);
+      expect(aktenzeichenMessage.textContent.trim()).toBe(vorgang.aktenzeichen);
     });
   });
 });
diff --git a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-in-postfach-breadcrumb-container/vorgang-in-postfach-breadcrumb-container.component.html b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-in-postfach-breadcrumb-container/vorgang-in-postfach-breadcrumb-container.component.html
deleted file mode 100644
index c8de63c7fdfba1ac8c851fe64f6c50b40100ec20..0000000000000000000000000000000000000000
--- a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-in-postfach-breadcrumb-container/vorgang-in-postfach-breadcrumb-container.component.html
+++ /dev/null
@@ -1,29 +0,0 @@
-<!--
-
-    Copyright (C) 2022 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.
-
--->
-<alfa-vorgang-in-postfach-breadcrumb
-  [vorgangStateResource]="vorgangStateResource$ | async"
-  data-test-id="postfach-breadcrump"
-></alfa-vorgang-in-postfach-breadcrumb>
diff --git a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-in-postfach-breadcrumb-container/vorgang-in-postfach-breadcrumb-container.component.scss b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-in-postfach-breadcrumb-container/vorgang-in-postfach-breadcrumb-container.component.scss
deleted file mode 100644
index 9a08a5aabce6cc4cdbb268c4190a8d67f82f19e5..0000000000000000000000000000000000000000
--- a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-in-postfach-breadcrumb-container/vorgang-in-postfach-breadcrumb-container.component.scss
+++ /dev/null
@@ -1,23 +0,0 @@
-/**
- * Copyright (C) 2022 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.
- */
diff --git a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-in-postfach-breadcrumb-container/vorgang-in-postfach-breadcrumb-container.component.spec.ts b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-in-postfach-breadcrumb-container/vorgang-in-postfach-breadcrumb-container.component.spec.ts
deleted file mode 100644
index 369a11caaf327063d67485a3b978ab158b167ffa..0000000000000000000000000000000000000000
--- a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-in-postfach-breadcrumb-container/vorgang-in-postfach-breadcrumb-container.component.spec.ts
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2022 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.
- */
-import { ComponentFixture, TestBed } from '@angular/core/testing';
-import { Mock, mock } from '@alfa-client/test-utils';
-import { VorgangService } from '@alfa-client/vorgang-shared';
-import { MockComponent } from 'ng-mocks';
-import { VorgangInPostfachBreadcrumbContainerComponent } from './vorgang-in-postfach-breadcrumb-container.component';
-import { VorgangInPostfachBreadcrumbComponent } from './vorgang-in-postfach-breadcrumb/vorgang-in-postfach-breadcrumb.component';
-
-describe('VorgangInPostfachBreadcrumbContainerComponent', () => {
-  let component: VorgangInPostfachBreadcrumbContainerComponent;
-  let fixture: ComponentFixture<VorgangInPostfachBreadcrumbContainerComponent>;
-
-  const vorgangService: Mock<VorgangService> = mock(VorgangService);
-
-  beforeEach(async () => {
-    await TestBed.configureTestingModule({
-      declarations: [
-        VorgangInPostfachBreadcrumbContainerComponent,
-        MockComponent(VorgangInPostfachBreadcrumbComponent),
-      ],
-      providers: [
-        {
-          provide: VorgangService,
-          useValue: vorgangService,
-        },
-      ],
-    }).compileComponents();
-  });
-
-  beforeEach(() => {
-    fixture = TestBed.createComponent(VorgangInPostfachBreadcrumbContainerComponent);
-    component = fixture.componentInstance;
-    fixture.detectChanges();
-  });
-
-  it('should create', () => {
-    expect(component).toBeTruthy();
-  });
-
-  describe('ngOnInit', () => {
-    it('should call vorgang service', () => {
-      component.ngOnInit();
-
-      expect(vorgangService.getVorgangWithEingang).toHaveBeenCalled();
-    });
-  });
-});
diff --git a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-in-postfach-breadcrumb-container/vorgang-in-postfach-breadcrumb-container.component.ts b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-in-postfach-breadcrumb-container/vorgang-in-postfach-breadcrumb-container.component.ts
deleted file mode 100644
index bde0eba9d92b2abdac24b3d3270d9d49e89475e2..0000000000000000000000000000000000000000
--- a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-in-postfach-breadcrumb-container/vorgang-in-postfach-breadcrumb-container.component.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2022 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.
- */
-import { Component, OnInit } from '@angular/core';
-import { StateResource } from '@alfa-client/tech-shared';
-import { VorgangService, VorgangWithEingangResource } from '@alfa-client/vorgang-shared';
-import { Observable } from 'rxjs';
-
-@Component({
-  selector: 'alfa-vorgang-in-postfach-breadcrumb-container',
-  templateUrl: './vorgang-in-postfach-breadcrumb-container.component.html',
-  styleUrls: ['./vorgang-in-postfach-breadcrumb-container.component.scss'],
-})
-export class VorgangInPostfachBreadcrumbContainerComponent implements OnInit {
-  vorgangStateResource$: Observable<StateResource<VorgangWithEingangResource>>;
-
-  constructor(private vorgangService: VorgangService) {}
-
-  ngOnInit(): void {
-    this.vorgangStateResource$ = this.vorgangService.getVorgangWithEingang();
-  }
-}
diff --git a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-in-postfach-breadcrumb-container/vorgang-in-postfach-breadcrumb/vorgang-in-postfach-breadcrumb.component.html b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-in-postfach-breadcrumb-container/vorgang-in-postfach-breadcrumb/vorgang-in-postfach-breadcrumb.component.html
deleted file mode 100644
index b51eccd1277977c1a109c3a87718fd11a4091901..0000000000000000000000000000000000000000
--- a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-in-postfach-breadcrumb-container/vorgang-in-postfach-breadcrumb/vorgang-in-postfach-breadcrumb.component.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!--
-
-    Copyright (C) 2022 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.
-
--->
-<span *ngIf="vorgangStateResource.resource as vorgang">
-  <a routerLink="/vorgang/{{ vorgang | toResourceUri }}" alfa-aktenzeichen [vorgang]="vorgang"></a>
-  <span>/</span>
-  <span>Nachrichten</span>
-</span>
diff --git a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-in-postfach-breadcrumb-container/vorgang-in-postfach-breadcrumb/vorgang-in-postfach-breadcrumb.component.scss b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-in-postfach-breadcrumb-container/vorgang-in-postfach-breadcrumb/vorgang-in-postfach-breadcrumb.component.scss
deleted file mode 100644
index 4df2ebcfa6f39b46618043b2ddb18650cea2f619..0000000000000000000000000000000000000000
--- a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-in-postfach-breadcrumb-container/vorgang-in-postfach-breadcrumb/vorgang-in-postfach-breadcrumb.component.scss
+++ /dev/null
@@ -1,46 +0,0 @@
-/**
- * Copyright (C) 2022 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.
- */
-@import 'variables';
-
-:host {
-  display: block;
-  font-size: 18px;
-  padding: 16px 24px 4px 26px;
-
-  ::ng-deep span {
-    margin: 0 4px;
-  }
-
-  a {
-    text-decoration: none;
-    outline: 0;
-    margin: -3px;
-    padding: 3px;
-
-    &:focus {
-      border-radius: 12px;
-      background-color: rgba(#777, 0.16);
-    }
-  }
-}
diff --git a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-in-postfach-breadcrumb-container/vorgang-in-postfach-breadcrumb/vorgang-in-postfach-breadcrumb.component.spec.ts b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-in-postfach-breadcrumb-container/vorgang-in-postfach-breadcrumb/vorgang-in-postfach-breadcrumb.component.spec.ts
deleted file mode 100644
index f5bdd3e8a9e65ad7adcd8f08453e914f3b06a6de..0000000000000000000000000000000000000000
--- a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-in-postfach-breadcrumb-container/vorgang-in-postfach-breadcrumb/vorgang-in-postfach-breadcrumb.component.spec.ts
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2022 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.
- */
-import { ComponentFixture, TestBed } from '@angular/core/testing';
-import { RouterTestingModule } from '@angular/router/testing';
-import { createStateResource, ToResourceUriPipe } from '@alfa-client/tech-shared';
-import { createVorgangWithEingangResource } from 'libs/vorgang-shared/test/vorgang';
-import { MockComponent } from 'ng-mocks';
-import { AktenzeichenComponent } from '../../aktenzeichen/aktenzeichen.component';
-import { VorgangInPostfachBreadcrumbComponent } from './vorgang-in-postfach-breadcrumb.component';
-
-describe('VorgangInPostfachBreadcrumbComponent', () => {
-  let component: VorgangInPostfachBreadcrumbComponent;
-  let fixture: ComponentFixture<VorgangInPostfachBreadcrumbComponent>;
-
-  beforeEach(async () => {
-    await TestBed.configureTestingModule({
-      declarations: [
-        VorgangInPostfachBreadcrumbComponent,
-        ToResourceUriPipe,
-        MockComponent(AktenzeichenComponent),
-      ],
-      imports: [RouterTestingModule],
-    }).compileComponents();
-  });
-
-  beforeEach(() => {
-    fixture = TestBed.createComponent(VorgangInPostfachBreadcrumbComponent);
-    component = fixture.componentInstance;
-    component.vorgangStateResource = createStateResource(createVorgangWithEingangResource());
-    fixture.detectChanges();
-  });
-
-  it('should create', () => {
-    expect(component).toBeTruthy();
-  });
-});
diff --git a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-nummer/_vorgang-nummer.component.theme.scss b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-nummer/_vorgang-nummer.component.theme.scss
deleted file mode 100644
index 00e4305df64ad8278be645380fe84dc15f92cd4b..0000000000000000000000000000000000000000
--- a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-nummer/_vorgang-nummer.component.theme.scss
+++ /dev/null
@@ -1,58 +0,0 @@
-/**
- * Copyright (C) 2022 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.
- */
-alfa-vorgang-nummer {
-  div {
-    display: flex;
-    align-items: center;
-    margin: 0;
-  }
-
-  mat-icon {
-    margin-right: 0.25rem;
-    height: 1.5rem;
-    min-height: 1.5rem;
-    width: 1.5rem;
-    min-width: 1.5rem;
-  }
-
-  span {
-    text-overflow: ellipsis;
-    white-space: nowrap;
-    overflow: hidden;
-  }
-
-  &.big {
-    div {
-      font-size: 16px;
-      font-weight: 300;
-    }
-    mat-icon {
-      margin-right: 0.5rem;
-      height: 1.875rem;
-      min-height: 1.875rem;
-      width: 1.875rem;
-      min-width: 1.875rem;
-    }
-  }
-}
diff --git a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-nummer/vorgang-nummer.component.html b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-nummer/vorgang-nummer.component.html
index 79e54f9224cda253b209638ff7a340ee55b2c555..66d983892157124277169515a44384b7fb2e789a 100644
--- a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-nummer/vorgang-nummer.component.html
+++ b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-nummer/vorgang-nummer.component.html
@@ -23,7 +23,14 @@
     unter der Lizenz sind dem Lizenztext zu entnehmen.
 
 -->
-<div>
-  <mat-icon svgIcon="nr"></mat-icon>
-  <span [matTooltip]="vorgang.nummer" data-test-id="vorgang-nummer">{{ vorgang.nummer }}</span>
+
+<div class="flex flex-shrink-0">
+  <mat-icon svgIcon="nr" style="width: 1.5rem; height: 1.5rem"></mat-icon>
+</div>
+<div
+  class="line-clamp-1 flex-shrink overflow-hidden break-all text-base font-normal lg:line-clamp-none lg:flex"
+  data-test-id="vorgang-nummer"
+  [matTooltip]="vorgang.nummer"
+>
+  {{ vorgang.nummer }}
 </div>
diff --git a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-nummer/vorgang-nummer.component.spec.ts b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-nummer/vorgang-nummer.component.spec.ts
index 17e53a890b1310c8661ea9cd8494b3fed95b4977..a622e364e43db4f9fb65e938f384f6a55234d952 100644
--- a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-nummer/vorgang-nummer.component.spec.ts
+++ b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-nummer/vorgang-nummer.component.spec.ts
@@ -61,7 +61,7 @@ describe('VorgangNummerComponent', () => {
     it('should show vorgang.nummer', () => {
       const text: HTMLElement = getElementFromFixture(fixture, vorgangnummer);
 
-      expect(text.textContent).toBe(vorgang.nummer);
+      expect(text.textContent.trim()).toBe(vorgang.nummer);
     });
   });
 });
diff --git a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-nummer/vorgang-nummer.component.ts b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-nummer/vorgang-nummer.component.ts
index 610e020a9d73ba64a29ef19537ecba26a6c0e3dc..3acb48b3de595cafc0f0ff76fc579f951d51f560 100644
--- a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-nummer/vorgang-nummer.component.ts
+++ b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-nummer/vorgang-nummer.component.ts
@@ -21,12 +21,13 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-import { Component, Input } from '@angular/core';
 import { Vorgang } from '@alfa-client/vorgang-shared';
+import { Component, Input } from '@angular/core';
 
 @Component({
   selector: 'alfa-vorgang-nummer',
   templateUrl: './vorgang-nummer.component.html',
+  styles: [':host {@apply flex flex-1 flex-row gap-1}'],
 })
 export class VorgangNummerComponent {
   @Input() vorgang: Vorgang;
diff --git a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.component.scss b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.component.scss
index 006026859a6c1c9552ccbb9928f909d9d447078d..37365d6a66d8d35bd8ebb1864f069fc74fad0e03 100644
--- a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.component.scss
+++ b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.component.scss
@@ -31,7 +31,7 @@ input {
   border: 0;
   background-color: transparent;
   outline: 0;
-  font-size: 18px !important;
+  font-size: 1.125rem !important;
   color: inherit;
   min-width: 0; // Firefox workaround for close icon
   width: calc(100% - 40px);
diff --git a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-shared-ui.module.ts b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-shared-ui.module.ts
index 542c39b469e4eff2171701519b31a5950e68ed18..21b8ef623c86deb6ed8b8e8c7430bff6bd20971b 100644
--- a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-shared-ui.module.ts
+++ b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-shared-ui.module.ts
@@ -21,15 +21,13 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-import { CommonModule } from '@angular/common';
-import { NgModule } from '@angular/core';
-import { RouterModule } from '@angular/router';
 import { TechSharedModule } from '@alfa-client/tech-shared';
 import { UiModule } from '@alfa-client/ui';
 import { VorgangSharedModule } from '@alfa-client/vorgang-shared';
+import { CommonModule } from '@angular/common';
+import { NgModule } from '@angular/core';
+import { RouterModule } from '@angular/router';
 import { AktenzeichenComponent } from './aktenzeichen/aktenzeichen.component';
-import { VorgangInPostfachBreadcrumbContainerComponent } from './vorgang-in-postfach-breadcrumb-container/vorgang-in-postfach-breadcrumb-container.component';
-import { VorgangInPostfachBreadcrumbComponent } from './vorgang-in-postfach-breadcrumb-container/vorgang-in-postfach-breadcrumb/vorgang-in-postfach-breadcrumb.component';
 import { VorgangNummerComponent } from './vorgang-nummer/vorgang-nummer.component';
 import { VorgangSearchContainerComponent } from './vorgang-search-container/vorgang-search-container.component';
 import { VorgangSearchAutocompleteOptionsContentComponent } from './vorgang-search-container/vorgang-search/vorgang-search-autocomplete-options-content/vorgang-search-autocomplete-options-content.component';
@@ -46,8 +44,6 @@ import { WiedervorlageIconComponent } from './wiedervorlage-icon/wiedervorlage-i
     VorgangSearchComponent,
     AktenzeichenComponent,
     VorgangStatusDotComponent,
-    VorgangInPostfachBreadcrumbContainerComponent,
-    VorgangInPostfachBreadcrumbComponent,
     VorgangSearchAutocompleteOptionsContentComponent,
     VorgangSearchClearButtonComponent,
     VorgangNummerComponent,
@@ -58,7 +54,6 @@ import { WiedervorlageIconComponent } from './wiedervorlage-icon/wiedervorlage-i
     VorgangSearchContainerComponent,
     AktenzeichenComponent,
     VorgangStatusDotComponent,
-    VorgangInPostfachBreadcrumbContainerComponent,
     VorgangSearchAutocompleteOptionsContentComponent,
     VorgangNummerComponent,
     VorgangStatusTextComponent,
diff --git a/alfa-client/libs/vorgang-shared-ui/src/lib/wiedervorlage-icon/wiedervorlage-icon.component.html b/alfa-client/libs/vorgang-shared-ui/src/lib/wiedervorlage-icon/wiedervorlage-icon.component.html
index 9bf2265a277651fe8d40eff1a80ad736136077ea..929a086df43bd18a6e9a4b0097d02c877d3d51e1 100644
--- a/alfa-client/libs/vorgang-shared-ui/src/lib/wiedervorlage-icon/wiedervorlage-icon.component.html
+++ b/alfa-client/libs/vorgang-shared-ui/src/lib/wiedervorlage-icon/wiedervorlage-icon.component.html
@@ -1,4 +1,7 @@
-<div [class.red]="isOverdue" data-test-class="wiedervorlage-icon">
+<div
+  [ngClass]="{ 'text-error': isOverdue, 'text-text': !isOverdue }"
+  data-test-class="wiedervorlage-icon"
+>
   <ng-container *ngIf="isOverdue; else defaultFrist">
     <ozgcloud-svgicon
       svgIcon="resubmission_expired"
diff --git a/alfa-client/libs/vorgang-shared-ui/src/lib/wiedervorlage-icon/wiedervorlage-icon.component.scss b/alfa-client/libs/vorgang-shared-ui/src/lib/wiedervorlage-icon/wiedervorlage-icon.component.scss
index 9315d4d7758a4c1fcfe23122a58d1d7059d8b257..5d71aeb617f12da1e3cf893fb102314114d1e7df 100644
--- a/alfa-client/libs/vorgang-shared-ui/src/lib/wiedervorlage-icon/wiedervorlage-icon.component.scss
+++ b/alfa-client/libs/vorgang-shared-ui/src/lib/wiedervorlage-icon/wiedervorlage-icon.component.scss
@@ -6,11 +6,3 @@
   margin-right: 6px;
   height: $iconHeight;
 }
-
-.red {
-  color: mat.get-color-from-palette($warnPalette, darker);
-}
-
-body.dark :host .red {
-  color: red;
-}
diff --git a/alfa-client/libs/vorgang-shared/src/lib/vorgang.linkrel.ts b/alfa-client/libs/vorgang-shared/src/lib/vorgang.linkrel.ts
index 57cfeeab38cb013afb230703102924d436b2acd0..a06768b2ed6d34e4c9a6e3fd4f7352a6de6edc89 100644
--- a/alfa-client/libs/vorgang-shared/src/lib/vorgang.linkrel.ts
+++ b/alfa-client/libs/vorgang-shared/src/lib/vorgang.linkrel.ts
@@ -56,7 +56,6 @@ export enum VorgangWithEingangLinkRel {
   HISTORIE = 'historie',
   SEARCH_USER_PROFILES = 'search-user-profiles',
   EXPORT = 'export',
-  CREATE_BESCHEID = 'createBescheid',
   CREATE_BESCHEID_DRAFT = 'createBescheidDraft',
   PROCESS_VORGANG = 'processVorgang',
 
@@ -65,6 +64,10 @@ export enum VorgangWithEingangLinkRel {
   BESCHEIDE = 'bescheide',
   UEBERSPRINGEN_UND_ABSCHLIESSEN = 'ueberspringen_und_abschliessen',
   DOWNLOAD_ATTACHMENTS = 'downloadAttachments',
+
+  SEARCH_ORGANISATIONS_EINHEIT = 'searchOrganisationsEinheit',
+
+  COLLABORATIONS = 'collaborations',
 }
 
 export enum LoeschAnforderungLinkRel {
diff --git a/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list-container.component.html b/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list-container.component.html
index cf927e2bacf4d6005e3200b3bbcd87a79736ba74..21f6df0c5a7913b49e25ca281f68add1f7fd2f77 100644
--- a/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list-container.component.html
+++ b/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list-container.component.html
@@ -27,11 +27,11 @@
   class="list"
   *ngIf="{
     vorgaenge: vorgaenge$ | async,
-    vorgangListPageResource: vorgangListPageResource$ | async
+    vorgangListPageResource: vorgangListPageResource$ | async,
   } as vorgangListData"
 >
   <alfa-vorgang-list
-    class="l-scroll-area--full"
+    class="l-scroll-area--full flex-col"
     [vorgangListPageResource]="vorgangListData.vorgangListPageResource"
     [vorgaenge]="vorgangListData.vorgaenge"
     [searchString]="searchString$ | async"
diff --git a/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/empty-list/empty-list.component.html b/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/empty-list/empty-list.component.html
index 73e479922ecc7ce9a6a1512263e624b4325ad828..9e299474628d6d580806b68d4cc97510749f7c12 100644
--- a/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/empty-list/empty-list.component.html
+++ b/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/empty-list/empty-list.component.html
@@ -24,10 +24,12 @@
 
 -->
 <div role="status" aria-live="assertive" *ngIf="searchString; else emptyDatabase">
-  <h3 data-test-id="empty-list-text">Es wurden keine Treffer für „{{ searchString }}“ gefunden</h3>
+  <h3 class="mb-1 text-lg" data-test-id="empty-list-text">
+    Es wurden keine Treffer für „{{ searchString }}“ gefunden
+  </h3>
   <p>Versuchen Sie es mit einem anderen Suchbegriff oder prüfen Sie die Schreibweise.</p>
 </div>
 
 <ng-template #emptyDatabase>
-  <h3 data-test-id="empty-database-text">Es sind keine Vorgänge vorhanden</h3>
+  <h3 class="mb-1 text-lg" data-test-id="empty-database-text">Es sind keine Vorgänge vorhanden</h3>
 </ng-template>
diff --git a/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/empty-list/empty-list.component.scss b/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/empty-list/empty-list.component.scss
index 536fd860a7e00090aac1b7868250154e178dbbea..f5257d8da6cdb6bf4d867ef90955dee710f72b40 100644
--- a/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/empty-list/empty-list.component.scss
+++ b/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/empty-list/empty-list.component.scss
@@ -25,8 +25,3 @@
   display: block;
   padding: 24px 32px;
 }
-
-h3 {
-  font-size: 18px;
-  margin-bottom: 4px;
-}
diff --git a/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-list-item.component.html b/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-list-item.component.html
index 4ae91cb40e746eef978cc1682f431ec3ab17e9f1..228c9808d45c6f5b81e47b178e21cfe28e4fe01c 100644
--- a/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-list-item.component.html
+++ b/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-list-item.component.html
@@ -28,9 +28,9 @@
   [attr.aria-label]="ariaLabel"
   routerLink="/vorgang/{{ vorgang | toResourceUri: vorgangLinkRel.VORGANG_WITH_EINGANG }}"
   [attr.data-test-id]="'vorgang-list-item-' + vorgang.name | convertForDataTest"
-  class="flex flex-row gap-4 border-b-2 border-slate-100 p-4 hover:shadow-[inset_1px_-1px_0_0_rgba(0,0,0,0.16)]"
+  class="flex flex-row gap-4 border-b-2 border-gray-200 p-4 hover:shadow-[inset_1px_-1px_0_0_rgba(0,0,0,0.16)] dark:border-b dark:border-gray-300 dark:hover:shadow-[inset_1px_-1px_0_0_rgba(255,255,255,0.60)]"
 >
-  <div class="flex w-36 flex-none flex-col">
+  <div class="flex w-32 flex-none flex-col">
     <div class="flex items-center gap-3">
       <alfa-vorgang-status-dot
         [status]="vorgang.status"
@@ -51,14 +51,20 @@
       ></alfa-vorgang-bescheid-status>
     </div>
   </div>
-  <div class="flex min-w-0 flex-1 flex-col gap-2">
-    <div data-test-id="name" class="text-base font-medium">{{ vorgang.name }}</div>
-    <div>
+  <div class="flex flex-1 flex-col gap-1">
+    <div data-test-id="name" class="break-all text-base font-medium">
+      {{ vorgang.name }}
+    </div>
+    <div class="mt-1">
       <alfa-vorgang-nummer class="vorgang-nummer" [vorgang]="vorgang"></alfa-vorgang-nummer>
     </div>
-    <div class="flex min-w-0 grow flex-row gap-1">
-      <mat-icon class="flex flex-none" svgIcon="az"></mat-icon>
-      <div alfa-aktenzeichen class="flex-initial truncate" [vorgang]="vorgang"></div>
+    <div>
+      <div class="flex flex-row gap-1">
+        <div class="flex flex-shrink-0">
+          <mat-icon svgIcon="az" style="width: 1.5rem; height: 1.5rem"></mat-icon>
+        </div>
+        <div alfa-aktenzeichen [vorgang]="vorgang"></div>
+      </div>
     </div>
   </div>
   <div class="flex w-36 flex-none flex-col gap-2">
@@ -83,7 +89,6 @@
       </ozgcloud-postfach-icon>
     </div>
   </div>
-  <div class="w-28 flex-none"></div>
   <div class="w-10 flex-none">
     <alfa-user-profile-in-vorgang-list-item-container
       *ngIf="vorgang | hasLink: vorgangLinkRel.ASSIGN"
diff --git a/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-list-item.component.spec.ts b/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-list-item.component.spec.ts
index 4a06bce8341af9c60b88bb268fa5c6e437466e40..13b574ef5c2fcdc6d993803208437cb01bb5ce3c 100644
--- a/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-list-item.component.spec.ts
+++ b/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-list-item.component.spec.ts
@@ -21,23 +21,12 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-import {
-  convertForDataTest,
-  ConvertForDataTestPipe,
-  EnumToLabelPipe,
-  HasLinkPipe,
-  ToResourceUriPipe,
-} from '@alfa-client/tech-shared';
+import { convertForDataTest, ConvertForDataTestPipe, EnumToLabelPipe, HasLinkPipe, ToResourceUriPipe } from '@alfa-client/tech-shared';
 import { getElementFromFixture } from '@alfa-client/test-utils';
 import { PostfachIconComponent } from '@alfa-client/ui';
 import { UserProfileInVorgangListItemContainerComponent } from '@alfa-client/user-profile';
 import { VorgangHeaderLinkRel } from '@alfa-client/vorgang-shared';
-import {
-  AktenzeichenComponent,
-  VorgangNummerComponent,
-  VorgangStatusDotComponent,
-  VorgangStatusTextComponent,
-} from '@alfa-client/vorgang-shared-ui';
+import { AktenzeichenComponent, VorgangNummerComponent, VorgangStatusDotComponent, VorgangStatusTextComponent } from '@alfa-client/vorgang-shared-ui';
 import { WiedervorlageListInVorgangListContainerComponent } from '@alfa-client/wiedervorlage';
 import { registerLocaleData } from '@angular/common';
 import localeDe from '@angular/common/locales/de';
@@ -55,7 +44,7 @@ import { MockComponent, MockModule } from 'ng-mocks';
 import { VorgangBescheidStatusComponent } from './vorgang-bescheid-status/vorgang-bescheid-status.component';
 import { VorgangCreatedAtComponent } from './vorgang-created-at/vorgang-created-at.component';
 import { VorgangListItemComponent } from './vorgang-list-item.component';
-import { VorgangNextFristButton } from './vorgang-next-frist-button/vorgang-next-frist-button.component';
+import { VorgangNextFristButtonComponent } from './vorgang-next-frist-button/vorgang-next-frist-button.component';
 
 registerLocaleData(localeDe, 'de', localeDeExtra);
 
@@ -83,7 +72,7 @@ describe('VorgangListItemComponent', () => {
         MockComponent(VorgangStatusDotComponent),
         MockComponent(VorgangStatusTextComponent),
         MockComponent(WiedervorlageListInVorgangListContainerComponent),
-        MockComponent(VorgangNextFristButton),
+        MockComponent(VorgangNextFristButtonComponent),
         MockComponent(UserProfileInVorgangListItemContainerComponent),
         MockComponent(VorgangCreatedAtComponent),
         MockComponent(VorgangBescheidStatusComponent),
diff --git a/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-next-frist-button/vorgang-next-frist-button.component.html b/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-next-frist-button/vorgang-next-frist-button.component.html
index 37b136c5f1d31d7d6f21f87df330bec6cce80a9c..206b3aa1c4c6986f0b4f18fdcb876810bf81d610 100644
--- a/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-next-frist-button/vorgang-next-frist-button.component.html
+++ b/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-next-frist-button/vorgang-next-frist-button.component.html
@@ -31,7 +31,11 @@
   (mouseleave)="showWiedervorlagen = false"
   (focusout)="showWiedervorlagen = false"
 >
-  <div class="date" [class.red]="isOverdue" data-test-class="wiedervorlage-next-frist">
+  <div
+    class="date"
+    [ngClass]="{ 'text-error': isOverdue, 'text-text': !isOverdue }"
+    data-test-class="wiedervorlage-next-frist"
+  >
     <alfa-wiedervorlage-icon [isOverdue]="isOverdue"></alfa-wiedervorlage-icon>
     <span>{{ vorgang.nextFrist | formatToPrettyDate }}</span>
   </div>
diff --git a/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-next-frist-button/vorgang-next-frist-button.component.scss b/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-next-frist-button/vorgang-next-frist-button.component.scss
index aa806fcb134fd31ffe3294c79892fccf159157fa..458f0a6eb3a1c8807675fab809d27e13ca79503b 100644
--- a/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-next-frist-button/vorgang-next-frist-button.component.scss
+++ b/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-next-frist-button/vorgang-next-frist-button.component.scss
@@ -29,7 +29,6 @@
   background-color: inherit;
   border: 0;
   padding: 0;
-  color: inherit;
   position: relative;
 }
 
@@ -38,11 +37,3 @@
   align-items: center;
   white-space: nowrap;
 }
-
-.red {
-  color: mat.get-color-from-palette($warnPalette, darker);
-}
-
-body.dark :host .red {
-  color: red;
-}
diff --git a/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-next-frist-button/vorgang-next-frist-button.component.spec.ts b/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-next-frist-button/vorgang-next-frist-button.component.spec.ts
index fdb11dc41d8f88b720e77c67589bbbce34e1e0f6..78c2a7a5031a73a342aac9438339a7a19b38c420 100644
--- a/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-next-frist-button/vorgang-next-frist-button.component.spec.ts
+++ b/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-next-frist-button/vorgang-next-frist-button.component.spec.ts
@@ -21,31 +21,31 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
+import { FormatToPrettyDatePipe, HasLinkPipe } from '@alfa-client/tech-shared';
+import { VorgangHeaderLinkRel } from '@alfa-client/vorgang-shared';
 import { registerLocaleData } from '@angular/common';
 import localeDe from '@angular/common/locales/de';
 import localeDeExtra from '@angular/common/locales/extra/de';
 import { ComponentFixture, TestBed } from '@angular/core/testing';
 import { MatIcon } from '@angular/material/icon';
-import { FormatToPrettyDatePipe, HasLinkPipe } from '@alfa-client/tech-shared';
-import { VorgangHeaderLinkRel } from '@alfa-client/vorgang-shared';
 import { WiedervorlageIconComponent } from 'libs/vorgang-shared-ui/src/lib/wiedervorlage-icon/wiedervorlage-icon.component';
 import { createVorgangResource } from 'libs/vorgang-shared/test/vorgang';
 import { WiedervorlageListInVorgangListContainerComponent } from 'libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-list-container/wiedervorlage-list-in-vorgang-list-container.component';
 import { MockComponent } from 'ng-mocks';
-import { VorgangNextFristButton } from './vorgang-next-frist-button.component';
+import { VorgangNextFristButtonComponent } from './vorgang-next-frist-button.component';
 
 import * as dateUtil from '../../../../../../../tech-shared/src/lib/date.util';
 
 registerLocaleData(localeDe, 'de', localeDeExtra);
 
-describe('VorgangNextFristButton', () => {
-  let component: VorgangNextFristButton;
-  let fixture: ComponentFixture<VorgangNextFristButton>;
+describe('VorgangNextFristButtonComponent', () => {
+  let component: VorgangNextFristButtonComponent;
+  let fixture: ComponentFixture<VorgangNextFristButtonComponent>;
 
   beforeEach(async () => {
     await TestBed.configureTestingModule({
       declarations: [
-        VorgangNextFristButton,
+        VorgangNextFristButtonComponent,
         FormatToPrettyDatePipe,
         HasLinkPipe,
         MatIcon,
@@ -56,7 +56,7 @@ describe('VorgangNextFristButton', () => {
   });
 
   beforeEach(() => {
-    fixture = TestBed.createComponent(VorgangNextFristButton);
+    fixture = TestBed.createComponent(VorgangNextFristButtonComponent);
     component = fixture.componentInstance;
     component.vorgang = createVorgangResource([VorgangHeaderLinkRel.VORGANG_WITH_EINGANG]);
     fixture.detectChanges();
diff --git a/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-next-frist-button/vorgang-next-frist-button.component.ts b/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-next-frist-button/vorgang-next-frist-button.component.ts
index f552a5b278d5b8f2b42e1e04a35eac0a18bbe27c..c85a4ce054c39c3587012bdb9183faa0f3628a8e 100644
--- a/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-next-frist-button/vorgang-next-frist-button.component.ts
+++ b/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-next-frist-button/vorgang-next-frist-button.component.ts
@@ -21,23 +21,21 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-import { Component, Input, OnInit } from '@angular/core';
 import { isISODateInPast } from '@alfa-client/tech-shared';
-import { VorgangHeaderLinkRel, VorgangResource } from '@alfa-client/vorgang-shared';
+import { VorgangResource } from '@alfa-client/vorgang-shared';
+import { Component, Input, OnInit } from '@angular/core';
 
 @Component({
   selector: 'alfa-vorgang-next-frist-button',
   templateUrl: './vorgang-next-frist-button.component.html',
   styleUrls: ['./vorgang-next-frist-button.component.scss'],
 })
-export class VorgangNextFristButton implements OnInit {
+export class VorgangNextFristButtonComponent implements OnInit {
   @Input() vorgang: VorgangResource;
 
   public showWiedervorlagen: boolean = false;
   public isOverdue: boolean;
 
-  readonly vorgangLinkRel = VorgangHeaderLinkRel;
-
   ngOnInit() {
     this.isOverdue = isISODateInPast(this.vorgang.nextFrist as unknown as string);
   }
diff --git a/alfa-client/libs/vorgang/src/lib/vorgang-list-page-container/vorgang-list-page/vorgang-filter-menu-container/vorgang-filter-menu/_vorgang-filter-item.theme.scss b/alfa-client/libs/vorgang/src/lib/vorgang-list-page-container/vorgang-list-page/vorgang-filter-menu-container/vorgang-filter-menu/_vorgang-filter-item.theme.scss
index b30526d2948a0fcf1e0ddfa018ae3e1f7469eae7..63637945bf7b4a4a09251c073daeba6ae7ba00bd 100644
--- a/alfa-client/libs/vorgang/src/lib/vorgang-list-page-container/vorgang-list-page/vorgang-filter-menu-container/vorgang-filter-menu/_vorgang-filter-item.theme.scss
+++ b/alfa-client/libs/vorgang/src/lib/vorgang-list-page-container/vorgang-list-page/vorgang-filter-menu-container/vorgang-filter-menu/_vorgang-filter-item.theme.scss
@@ -30,7 +30,7 @@ alfa-vorgang-filter-menu {
     justify-content: space-between;
     gap: 0.5rem;
     height: 2rem;
-    font-size: 14px;
+    font-size: 0.875rem;
 
     mat-icon {
       display: none;
diff --git a/alfa-client/libs/vorgang/src/lib/vorgang-list-page-container/vorgang-list-page/vorgang-list-page.component.html b/alfa-client/libs/vorgang/src/lib/vorgang-list-page-container/vorgang-list-page/vorgang-list-page.component.html
index 43ee22e674f7a4c0b4e62185d5c0ca2cba652d82..c947a1e4cb95a6d6817a0e3573f93a94d523943b 100644
--- a/alfa-client/libs/vorgang/src/lib/vorgang-list-page-container/vorgang-list-page/vorgang-list-page.component.html
+++ b/alfa-client/libs/vorgang/src/lib/vorgang-list-page-container/vorgang-list-page/vorgang-list-page.component.html
@@ -23,9 +23,10 @@
     unter der Lizenz sind dem Lizenztext zu entnehmen.
 
 -->
+<h1 class="sr-only">Vorgangsliste</h1>
 <alfa-vorgang-filter-menu-container class="mat-app-background"></alfa-vorgang-filter-menu-container>
 
-<div class="content">
+<div class="flex flex-row">
   <alfa-vorgang-views-menu-container
     *ngIf="apiRootStateResource.resource"
     [apiRootResource]="apiRootStateResource.resource"
@@ -38,20 +39,21 @@
       else showNoRoleMessage
     "
     data-test-id="vorgaenge-list"
-    class="flex flex-1 flex-col overflow-hidden"
+    class="flex flex-1 flex-col overflow-hidden border border-gray-200 dark:border-black"
   >
     <router-outlet></router-outlet>
   </main>
 
   <ng-template #showNoRoleMessage>
-    <div class="l-scroll-area--full no-role-message" data-test-id="user-no-role-message">
-      <h2>Es sind keine Vorgänge in Alfa verfügbar.</h2>
-      <p>Prüfen Sie, ob folgendes zutrifft:</p>
-      <ul>
-        <li>Es wurden keine Rollen zugewiesen.</li>
-      </ul>
-
-      <p>Bitte bei der verantwortlichen Person des User-Managements bzw. des Keycloaks melden.</p>
+    <div class="flex-1 border border-gray-200 px-7 py-6" data-test-id="user-no-role-message">
+      <div>
+        <h2>Es sind keine Vorgänge in Alfa verfügbar.</h2>
+        <p>Prüfen Sie, ob folgendes zutrifft:</p>
+        <ul>
+          <li>Es wurden keine Rollen zugewiesen.</li>
+        </ul>
+        <p>Bitte bei der verantwortlichen Person des User-Managements bzw. des Keycloaks melden.</p>
+      </div>
     </div>
   </ng-template>
 </div>
diff --git a/alfa-client/libs/vorgang/src/lib/vorgang-list-page-container/vorgang-list-page/vorgang-list-page.component.scss b/alfa-client/libs/vorgang/src/lib/vorgang-list-page-container/vorgang-list-page/vorgang-list-page.component.scss
index 07a6f9291052df7ec173c86ffd766c1b85df934d..0ed70776b23972cc2f11d42feee865af9cc28525 100644
--- a/alfa-client/libs/vorgang/src/lib/vorgang-list-page-container/vorgang-list-page/vorgang-list-page.component.scss
+++ b/alfa-client/libs/vorgang/src/lib/vorgang-list-page-container/vorgang-list-page/vorgang-list-page.component.scss
@@ -33,16 +33,6 @@ h1 {
   display: flex;
   flex-direction: row;
   background-color: $background;
-
-  main,
-  .no-role-message {
-    flex: 1 1 100%;
-    border: 1px solid $greyLight;
-  }
-
-  .no-role-message {
-    padding: 1.5rem 2rem;
-  }
 }
 
 :host-context(.dark) {
diff --git a/alfa-client/libs/vorgang/src/lib/vorgang-list-page-container/vorgang-list-page/vorgang-views-menu/vorgang-search-view-item-container/vorgang-search-view-item/vorgang-search-view-item.component.html b/alfa-client/libs/vorgang/src/lib/vorgang-list-page-container/vorgang-list-page/vorgang-views-menu/vorgang-search-view-item-container/vorgang-search-view-item/vorgang-search-view-item.component.html
index 9f578e5efcee92394cc676b46eb6cd5e0ee27cca..2952d25ef91664647393b0bbc585841e47c2c4c3 100644
--- a/alfa-client/libs/vorgang/src/lib/vorgang-list-page-container/vorgang-list-page/vorgang-views-menu/vorgang-search-view-item-container/vorgang-search-view-item/vorgang-search-view-item.component.html
+++ b/alfa-client/libs/vorgang/src/lib/vorgang-list-page-container/vorgang-list-page/vorgang-views-menu/vorgang-search-view-item-container/vorgang-search-view-item/vorgang-search-view-item.component.html
@@ -4,5 +4,5 @@
   data-test-id="views-menu-item-Suche"
 >
   <ozgcloud-icon icon="search"></ozgcloud-icon>
-  Suche
+  <span class="text-sm">Suche</span>
 </ozgcloud-routing-button>
diff --git a/alfa-client/libs/vorgang/src/lib/vorgang-list-page-container/vorgang-list-page/vorgang-views-menu/vorgang-view-item-container/vorgang-view-item/vorgang-view-item.component.html b/alfa-client/libs/vorgang/src/lib/vorgang-list-page-container/vorgang-list-page/vorgang-views-menu/vorgang-view-item-container/vorgang-view-item/vorgang-view-item.component.html
index 85a09071dd9f3890a988ce787c06accb65d54a16..5983cd2ccd84b22bf04bae1536d6dcb362409ba5 100644
--- a/alfa-client/libs/vorgang/src/lib/vorgang-list-page-container/vorgang-list-page/vorgang-views-menu/vorgang-view-item-container/vorgang-view-item/vorgang-view-item.component.html
+++ b/alfa-client/libs/vorgang/src/lib/vorgang-list-page-container/vorgang-list-page/vorgang-views-menu/vorgang-view-item-container/vorgang-view-item/vorgang-view-item.component.html
@@ -4,10 +4,11 @@
   [attr.data-test-id]="'views-menu-item-' + (label | convertForDataTest)"
 >
   <ng-content></ng-content>
-  <div class="label">{{ label }}</div>
+  <div class="label text-sm">{{ label }}</div>
   <div
     *ngIf="count != null"
     [attr.data-test-id]="'views-menu-item-count-' + (label | convertForDataTest)"
+    class="text-sm"
   >
     {{ count }}
   </div>
diff --git a/alfa-client/libs/vorgang/src/lib/vorgang-list-page-container/vorgang-list-page/vorgang-views-menu/vorgang-views-menu.component.html b/alfa-client/libs/vorgang/src/lib/vorgang-list-page-container/vorgang-list-page/vorgang-views-menu/vorgang-views-menu.component.html
index 6c874f1b35f4c2e6ea7955504a4dc69a5937fa6b..1e827d60d406dbba0cb91511e6258e5e43924386 100644
--- a/alfa-client/libs/vorgang/src/lib/vorgang-list-page-container/vorgang-list-page/vorgang-views-menu/vorgang-views-menu.component.html
+++ b/alfa-client/libs/vorgang/src/lib/vorgang-list-page-container/vorgang-list-page/vorgang-views-menu/vorgang-views-menu.component.html
@@ -24,7 +24,7 @@
 
 -->
 <ng-container *ngIf="vorgangStatisticStateResource?.resource as statistic">
-  <div class="views">
+  <nav class="views" aria-label="Statusansichten">
     <alfa-vorgang-view-item-container
       *ngIf="
         apiRootResource
@@ -190,5 +190,5 @@
       class="top-border"
     >
     </alfa-vorgang-search-view-item-container>
-  </div>
+  </nav>
 </ng-container>
diff --git a/alfa-client/libs/vorgang/src/lib/vorgang-list-search-container/vorgang-list-search/vorgang-list-search.component.scss b/alfa-client/libs/vorgang/src/lib/vorgang-list-search-container/vorgang-list-search/vorgang-list-search.component.scss
index df5f0bc9484e063d9de082c2293e383a0827f3e2..464e85fde3aa33bf73740006a64cdb20d69453a3 100644
--- a/alfa-client/libs/vorgang/src/lib/vorgang-list-search-container/vorgang-list-search/vorgang-list-search.component.scss
+++ b/alfa-client/libs/vorgang/src/lib/vorgang-list-search-container/vorgang-list-search/vorgang-list-search.component.scss
@@ -7,6 +7,6 @@ div {
 }
 
 h3 {
-  font-size: 18px;
+  font-size: 1.125rem;
   margin-bottom: 4px;
 }
diff --git a/alfa-client/libs/vorgang/src/lib/vorgang.module.ts b/alfa-client/libs/vorgang/src/lib/vorgang.module.ts
index 073eeb74eb9eb31e3b8c5bee5448438d2e810ffd..0fea0e60e669a1a394c27127d2573e64a21f8f3c 100644
--- a/alfa-client/libs/vorgang/src/lib/vorgang.module.ts
+++ b/alfa-client/libs/vorgang/src/lib/vorgang.module.ts
@@ -39,7 +39,7 @@ import { EmptyListComponent } from './vorgang-list-container/vorgang-list/empty-
 import { VorgangBescheidStatusComponent } from './vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-bescheid-status/vorgang-bescheid-status.component';
 import { VorgangCreatedAtComponent } from './vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-created-at/vorgang-created-at.component';
 import { VorgangListItemComponent } from './vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-list-item.component';
-import { VorgangNextFristButton } from './vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-next-frist-button/vorgang-next-frist-button.component';
+import { VorgangNextFristButtonComponent } from './vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-next-frist-button/vorgang-next-frist-button.component';
 import { VorgangListComponent } from './vorgang-list-container/vorgang-list/vorgang-list.component';
 import { VorgangListPageContainerComponent } from './vorgang-list-page-container/vorgang-list-page-container.component';
 import { VorgangFilterMenuContainerComponent } from './vorgang-list-page-container/vorgang-list-page/vorgang-filter-menu-container/vorgang-filter-menu-container.component';
@@ -184,7 +184,7 @@ const routes: Routes = [
     VorgangListContainerComponent,
     VorgangListPageComponent,
     EmptyListComponent,
-    VorgangNextFristButton,
+    VorgangNextFristButtonComponent,
     VorgangListPageContainerComponent,
     VorgangFilterMenuContainerComponent,
     VorgangFilterMenuComponent,
diff --git a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-container/wiedervorlage-list-in-vorgang/wiedervorlage-in-vorgang/wiedervorlage-in-vorgang.component.html b/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-container/wiedervorlage-list-in-vorgang/wiedervorlage-in-vorgang/wiedervorlage-in-vorgang.component.html
index 8f22382ce7fa032dcc18833d833fbac8d705de24..63809ff94287361c07b4b4bbb35f83c19a87f663 100644
--- a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-container/wiedervorlage-list-in-vorgang/wiedervorlage-in-vorgang/wiedervorlage-in-vorgang.component.html
+++ b/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-container/wiedervorlage-list-in-vorgang/wiedervorlage-in-vorgang/wiedervorlage-in-vorgang.component.html
@@ -23,7 +23,10 @@
     unter der Lizenz sind dem Lizenztext zu entnehmen.
 
 -->
-<div [attr.data-test-id]="wiedervorlageResource.betreff | convertForDataTest" class="container">
+<div
+  [attr.data-test-id]="wiedervorlageResource.betreff | convertForDataTest"
+  class="container text-sm"
+>
   <div class="row">
     <alfa-wiedervorlage-status
       data-test-class="status"
diff --git a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-page-container/wiedervorlage-page/wiedervorlage-breadcrumb-container/wiedervorlage-breadcrumb/wiedervorlage-breadcrumb.component.html b/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-page-container/wiedervorlage-page/wiedervorlage-breadcrumb-container/wiedervorlage-breadcrumb/wiedervorlage-breadcrumb.component.html
index c9ba19672327f65810cbf341f1509d9d35efb768..bd029889ffc001a81cfc4018f1c9303de2a51348 100644
--- a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-page-container/wiedervorlage-page/wiedervorlage-breadcrumb-container/wiedervorlage-breadcrumb/wiedervorlage-breadcrumb.component.html
+++ b/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-page-container/wiedervorlage-page/wiedervorlage-breadcrumb-container/wiedervorlage-breadcrumb/wiedervorlage-breadcrumb.component.html
@@ -23,8 +23,4 @@
     unter der Lizenz sind dem Lizenztext zu entnehmen.
 
 -->
-<span alfa-aktenzeichen [vorgang]="vorgang"></span>
-<span>/</span>
-<span>Wiedervorlagen</span>
-<span>/</span>
-<span>{{ betreff }}</span>
+<h2 class="mb-2 mt-1 text-base font-medium">{{ betreff }}</h2>
diff --git a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-page-container/wiedervorlage-page/wiedervorlage-breadcrumb-container/wiedervorlage-breadcrumb/wiedervorlage-breadcrumb.component.ts b/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-page-container/wiedervorlage-page/wiedervorlage-breadcrumb-container/wiedervorlage-breadcrumb/wiedervorlage-breadcrumb.component.ts
index d4f5108551db4bc9e246f30efb74d8ff36137003..7de3be70b8613d9de494fb7b5ef8b7e70c5a0813 100644
--- a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-page-container/wiedervorlage-page/wiedervorlage-breadcrumb-container/wiedervorlage-breadcrumb/wiedervorlage-breadcrumb.component.ts
+++ b/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-page-container/wiedervorlage-page/wiedervorlage-breadcrumb-container/wiedervorlage-breadcrumb/wiedervorlage-breadcrumb.component.ts
@@ -21,14 +21,13 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
 import { VorgangResource } from '@alfa-client/vorgang-shared';
 import { WiedervorlageMessages, WiedervorlageResource } from '@alfa-client/wiedervorlage-shared';
+import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
 
 @Component({
   selector: 'alfa-wiedervorlage-breadcrumb',
   templateUrl: './wiedervorlage-breadcrumb.component.html',
-  styleUrls: ['./wiedervorlage-breadcrumb.component.scss'],
 })
 export class WiedervorlageBreadcrumbComponent implements OnChanges {
   @Input() vorgang: VorgangResource;
diff --git a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-page-container/wiedervorlage-page/wiedervorlage-page.component.html b/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-page-container/wiedervorlage-page/wiedervorlage-page.component.html
index 612c4524067db2d4d7d4d0f312029a33e79603ed..bfca634528875b5bc619c54bf6cf960a268a38d8 100644
--- a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-page-container/wiedervorlage-page/wiedervorlage-page.component.html
+++ b/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-page-container/wiedervorlage-page/wiedervorlage-page.component.html
@@ -33,7 +33,8 @@
   </ozgcloud-subnavigation>
 
   <div class="l-scroll-area--full">
-    <div class="wrapper">
+    <div class="wrapper grow">
+      <h1 class="text-lg font-medium">Wiedervorlage</h1>
       <alfa-wiedervorlage-breadcrumb-container
         [wiedervorlage]="wiedervorlageStateResource.resource"
       ></alfa-wiedervorlage-breadcrumb-container>
diff --git a/alfa-client/package-lock.json b/alfa-client/package-lock.json
index a7e9f6cfe77a4da3de7f151bdcbd299486c59c20..6f74aee054bb6dd8cf0188cb27a4e8c4ce1b78b5 100644
--- a/alfa-client/package-lock.json
+++ b/alfa-client/package-lock.json
@@ -1,12 +1,12 @@
 {
   "name": "alfa",
-  "version": "0.7.0-SNAPSHOT",
+  "version": "0.8.0-SNAPSHOT",
   "lockfileVersion": 3,
   "requires": true,
   "packages": {
     "": {
       "name": "alfa",
-      "version": "0.7.0-SNAPSHOT",
+      "version": "0.8.0-SNAPSHOT",
       "license": "MIT",
       "dependencies": {
         "@angular/animations": "17.3.10",
@@ -202,13 +202,13 @@
       }
     },
     "node_modules/@angular-devkit/architect": {
-      "version": "0.1800.3",
-      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@angular-devkit/architect/-/architect-0.1800.3.tgz",
-      "integrity": "sha512-ZoQuvCN/Ft4XJ+/XouYFKGoyEYTfZ8I5yI1M4t19lkRb3MwpQribWcZu4PP+SNnS6/9qnW7guxiQGS+CVlqnDg==",
+      "version": "0.1801.4",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@angular-devkit/architect/-/architect-0.1801.4.tgz",
+      "integrity": "sha512-Ch1ZwRh1N/vcCKHm4ErLcgZly3tlwdLUDGBaAIlhE3YFGq543Swv6a5IcDw0veD6iGFceJAmbrp+z5hmzI8p5A==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "@angular-devkit/core": "18.0.3",
+        "@angular-devkit/core": "18.1.4",
         "rxjs": "7.8.1"
       },
       "engines": {
@@ -218,15 +218,15 @@
       }
     },
     "node_modules/@angular-devkit/architect/node_modules/@angular-devkit/core": {
-      "version": "18.0.3",
-      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@angular-devkit/core/-/core-18.0.3.tgz",
-      "integrity": "sha512-nTs1KbNSVCVooPdDaeTh1YbggNVaqexbQjXNIvJJzRB8qPkWNPxm0pQeFjU7kWUBg2+aBXN4/CNwU1YHwxfiSQ==",
+      "version": "18.1.4",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@angular-devkit/core/-/core-18.1.4.tgz",
+      "integrity": "sha512-lKBsvbqW2QFL8terzNuSDSmKBo8//QNRO4qU5mVJ1fFf4xBJanXKoiAMuADhx+/owVIptnYT59IZ8jUAna+Srg==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "ajv": "8.13.0",
+        "ajv": "8.16.0",
         "ajv-formats": "3.0.1",
-        "jsonc-parser": "3.2.1",
+        "jsonc-parser": "3.3.1",
         "picomatch": "4.0.2",
         "rxjs": "7.8.1",
         "source-map": "0.7.4"
@@ -246,9 +246,9 @@
       }
     },
     "node_modules/@angular-devkit/architect/node_modules/ajv": {
-      "version": "8.13.0",
-      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/ajv/-/ajv-8.13.0.tgz",
-      "integrity": "sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==",
+      "version": "8.16.0",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/ajv/-/ajv-8.16.0.tgz",
+      "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==",
       "dev": true,
       "peer": true,
       "dependencies": {
@@ -280,6 +280,13 @@
         }
       }
     },
+    "node_modules/@angular-devkit/architect/node_modules/jsonc-parser": {
+      "version": "3.3.1",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/jsonc-parser/-/jsonc-parser-3.3.1.tgz",
+      "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==",
+      "dev": true,
+      "peer": true
+    },
     "node_modules/@angular-devkit/architect/node_modules/picomatch": {
       "version": "4.0.2",
       "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/picomatch/-/picomatch-4.0.2.tgz",
@@ -6276,30 +6283,30 @@
       }
     },
     "node_modules/@floating-ui/core": {
-      "version": "1.6.2",
-      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@floating-ui/core/-/core-1.6.2.tgz",
-      "integrity": "sha512-+2XpQV9LLZeanU4ZevzRnGFg2neDeKHgFLjP6YLW+tly0IvrhqT4u8enLGjLH3qeh85g19xY5rsAusfwTdn5lg==",
+      "version": "1.6.7",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@floating-ui/core/-/core-1.6.7.tgz",
+      "integrity": "sha512-yDzVT/Lm101nQ5TCVeK65LtdN7Tj4Qpr9RTXJ2vPFLqtLxwOrpoxAHAJI8J3yYWUc40J0BDBheaitK5SJmno2g==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "@floating-ui/utils": "^0.2.0"
+        "@floating-ui/utils": "^0.2.7"
       }
     },
     "node_modules/@floating-ui/dom": {
-      "version": "1.6.5",
-      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@floating-ui/dom/-/dom-1.6.5.tgz",
-      "integrity": "sha512-Nsdud2X65Dz+1RHjAIP0t8z5e2ff/IRbei6BqFrl1urT8sDVzM1HMQ+R0XcU5ceRfyO3I6ayeqIfh+6Wb8LGTw==",
+      "version": "1.6.10",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@floating-ui/dom/-/dom-1.6.10.tgz",
+      "integrity": "sha512-fskgCFv8J8OamCmyun8MfjB1Olfn+uZKjOKZ0vhYF3gRmEUXcGOjxWL8bBr7i4kIuPZ2KD2S3EUIOxnjC8kl2A==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "@floating-ui/core": "^1.0.0",
-        "@floating-ui/utils": "^0.2.0"
+        "@floating-ui/core": "^1.6.0",
+        "@floating-ui/utils": "^0.2.7"
       }
     },
     "node_modules/@floating-ui/react-dom": {
-      "version": "2.1.0",
-      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@floating-ui/react-dom/-/react-dom-2.1.0.tgz",
-      "integrity": "sha512-lNzj5EQmEKn5FFKc04+zasr09h/uX8RtJRNj5gUXsSQIXHVWTVh+hVAg1vOMCexkX8EgvemMvIFpQfkosnVNyA==",
+      "version": "2.1.1",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@floating-ui/react-dom/-/react-dom-2.1.1.tgz",
+      "integrity": "sha512-4h84MJt3CHrtG18mGsXuLCHMrug49d7DFkU0RMIyshRveBeyV2hmV/pDaF2Uxtu8kgq5r46llp5E5FQiR0K2Yg==",
       "dev": true,
       "peer": true,
       "dependencies": {
@@ -6311,9 +6318,9 @@
       }
     },
     "node_modules/@floating-ui/utils": {
-      "version": "0.2.2",
-      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@floating-ui/utils/-/utils-0.2.2.tgz",
-      "integrity": "sha512-J4yDIIthosAsRZ5CPYP/jQvUAQtlZTTD/4suA08/FEnlxqW3sKS9iAhgsa9VYLZ6vDHn/ixJgIqRQPotoBjxIw==",
+      "version": "0.2.7",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@floating-ui/utils/-/utils-0.2.7.tgz",
+      "integrity": "sha512-X8R8Oj771YRl/w+c1HqAC1szL8zWQRwFvgDwT129k9ACdBoud/+/rX9V0qiMl6LWUdP9voC2nDVZYPMQQsb6eA==",
       "dev": true,
       "peer": true
     },
@@ -8465,13 +8472,13 @@
       }
     },
     "node_modules/@nrwl/devkit": {
-      "version": "19.2.3",
-      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@nrwl/devkit/-/devkit-19.2.3.tgz",
-      "integrity": "sha512-OL6sc70gR/USasvbYzyYY44Hd5ZCde2UfiA5h8VeAYAJbq+JmtscpvjcnZ7OIsXyYEOxe1rypULElqu/8qpKzQ==",
+      "version": "19.5.7",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@nrwl/devkit/-/devkit-19.5.7.tgz",
+      "integrity": "sha512-sTEwqsAT6bMturU14o/0O6v509OkwGOglxpbiL/zIYO/fDkMoNgnhlHBIT87i4YVuofMz2Z+hTfjDskzDPRSYw==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "@nx/devkit": "19.2.3"
+        "@nx/devkit": "19.5.7"
       }
     },
     "node_modules/@nrwl/eslint-plugin-nx": {
@@ -8985,13 +8992,13 @@
       }
     },
     "node_modules/@nx/devkit": {
-      "version": "19.2.3",
-      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@nx/devkit/-/devkit-19.2.3.tgz",
-      "integrity": "sha512-if1WwRVexrQBBADObEcxVIivq4QRZWY/nYRhCQy/qfFI6Cu2jBSI6ZQ1uy7to2L2sQPLgn8v2beQZiAeZdIktg==",
+      "version": "19.5.7",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@nx/devkit/-/devkit-19.5.7.tgz",
+      "integrity": "sha512-mUtZQcdqbF0Q9HfyG14jmpPCtZ1GnVaLNIADZv5SLpFyfh4ZjaBw6wdjPj7Sp3imLoyqMrcd9nCRNO2hlem8bw==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "@nrwl/devkit": "19.2.3",
+        "@nrwl/devkit": "19.5.7",
         "ejs": "^3.1.7",
         "enquirer": "~2.3.6",
         "ignore": "^5.0.4",
@@ -11055,28 +11062,61 @@
       }
     },
     "node_modules/@radix-ui/react-roving-focus": {
-      "version": "1.0.4",
-      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@radix-ui/react-roving-focus/-/react-roving-focus-1.0.4.tgz",
-      "integrity": "sha512-2mUg5Mgcu001VkGy+FfzZyzbmuUWzgWkj3rvv4yu+mLw03+mTzbxZHvfcGyFp2b8EkQeMkpRQ5FiA2Vr2O6TeQ==",
+      "version": "1.1.0",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.0.tgz",
+      "integrity": "sha512-EA6AMGeq9AEeQDeSH0aZgG198qkfHSbvWTf1HvoDmOB5bBG/qTxjYMWUKMnYiV6J/iP/J8MEFSuB2zRU2n7ODA==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "@babel/runtime": "^7.13.10",
-        "@radix-ui/primitive": "1.0.1",
-        "@radix-ui/react-collection": "1.0.3",
-        "@radix-ui/react-compose-refs": "1.0.1",
-        "@radix-ui/react-context": "1.0.1",
-        "@radix-ui/react-direction": "1.0.1",
-        "@radix-ui/react-id": "1.0.1",
-        "@radix-ui/react-primitive": "1.0.3",
-        "@radix-ui/react-use-callback-ref": "1.0.1",
-        "@radix-ui/react-use-controllable-state": "1.0.1"
+        "@radix-ui/primitive": "1.1.0",
+        "@radix-ui/react-collection": "1.1.0",
+        "@radix-ui/react-compose-refs": "1.1.0",
+        "@radix-ui/react-context": "1.1.0",
+        "@radix-ui/react-direction": "1.1.0",
+        "@radix-ui/react-id": "1.1.0",
+        "@radix-ui/react-primitive": "2.0.0",
+        "@radix-ui/react-use-callback-ref": "1.1.0",
+        "@radix-ui/react-use-controllable-state": "1.1.0"
       },
       "peerDependencies": {
         "@types/react": "*",
         "@types/react-dom": "*",
-        "react": "^16.8 || ^17.0 || ^18.0",
-        "react-dom": "^16.8 || ^17.0 || ^18.0"
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "@types/react-dom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/primitive": {
+      "version": "1.1.0",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@radix-ui/primitive/-/primitive-1.1.0.tgz",
+      "integrity": "sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-collection": {
+      "version": "1.1.0",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@radix-ui/react-collection/-/react-collection-1.1.0.tgz",
+      "integrity": "sha512-GZsZslMJEyo1VKm5L1ZJY8tGDxZNPAoUeQUIbKeJfoi7Q4kmig5AsgLMYYuyYbfjd8fBmFORAIwYAkXMnXZgZw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@radix-ui/react-compose-refs": "1.1.0",
+        "@radix-ui/react-context": "1.1.0",
+        "@radix-ui/react-primitive": "2.0.0",
+        "@radix-ui/react-slot": "1.1.0"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "@types/react-dom": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
       },
       "peerDependenciesMeta": {
         "@types/react": {
@@ -11087,6 +11127,167 @@
         }
       }
     },
+    "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-compose-refs": {
+      "version": "1.1.0",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz",
+      "integrity": "sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==",
+      "dev": true,
+      "peer": true,
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-context": {
+      "version": "1.1.0",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@radix-ui/react-context/-/react-context-1.1.0.tgz",
+      "integrity": "sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==",
+      "dev": true,
+      "peer": true,
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-direction": {
+      "version": "1.1.0",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@radix-ui/react-direction/-/react-direction-1.1.0.tgz",
+      "integrity": "sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg==",
+      "dev": true,
+      "peer": true,
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-id": {
+      "version": "1.1.0",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@radix-ui/react-id/-/react-id-1.1.0.tgz",
+      "integrity": "sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@radix-ui/react-use-layout-effect": "1.1.0"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-primitive": {
+      "version": "2.0.0",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@radix-ui/react-primitive/-/react-primitive-2.0.0.tgz",
+      "integrity": "sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@radix-ui/react-slot": "1.1.0"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "@types/react-dom": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "@types/react-dom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-slot": {
+      "version": "1.1.0",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@radix-ui/react-slot/-/react-slot-1.1.0.tgz",
+      "integrity": "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@radix-ui/react-compose-refs": "1.1.0"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-use-callback-ref": {
+      "version": "1.1.0",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz",
+      "integrity": "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==",
+      "dev": true,
+      "peer": true,
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-use-controllable-state": {
+      "version": "1.1.0",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.1.0.tgz",
+      "integrity": "sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@radix-ui/react-use-callback-ref": "1.1.0"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-use-layout-effect": {
+      "version": "1.1.0",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.0.tgz",
+      "integrity": "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==",
+      "dev": true,
+      "peer": true,
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
     "node_modules/@radix-ui/react-select": {
       "version": "1.2.2",
       "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@radix-ui/react-select/-/react-select-1.2.2.tgz",
@@ -11133,20 +11334,59 @@
       }
     },
     "node_modules/@radix-ui/react-separator": {
-      "version": "1.0.3",
-      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@radix-ui/react-separator/-/react-separator-1.0.3.tgz",
-      "integrity": "sha512-itYmTy/kokS21aiV5+Z56MZB54KrhPgn6eHDKkFeOLR34HMN2s8PaN47qZZAGnvupcjxHaFZnW4pQEh0BvvVuw==",
+      "version": "1.1.0",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@radix-ui/react-separator/-/react-separator-1.1.0.tgz",
+      "integrity": "sha512-3uBAs+egzvJBDZAzvb/n4NxxOYpnspmWxO2u5NbZ8Y6FM/NdrGSF9bop3Cf6F6C71z1rTSn8KV0Fo2ZVd79lGA==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "@babel/runtime": "^7.13.10",
-        "@radix-ui/react-primitive": "1.0.3"
+        "@radix-ui/react-primitive": "2.0.0"
       },
       "peerDependencies": {
         "@types/react": "*",
         "@types/react-dom": "*",
-        "react": "^16.8 || ^17.0 || ^18.0",
-        "react-dom": "^16.8 || ^17.0 || ^18.0"
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "@types/react-dom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-separator/node_modules/@radix-ui/react-compose-refs": {
+      "version": "1.1.0",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz",
+      "integrity": "sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==",
+      "dev": true,
+      "peer": true,
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-separator/node_modules/@radix-ui/react-primitive": {
+      "version": "2.0.0",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@radix-ui/react-primitive/-/react-primitive-2.0.0.tgz",
+      "integrity": "sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@radix-ui/react-slot": "1.1.0"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "@types/react-dom": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
       },
       "peerDependenciesMeta": {
         "@types/react": {
@@ -11157,6 +11397,25 @@
         }
       }
     },
+    "node_modules/@radix-ui/react-separator/node_modules/@radix-ui/react-slot": {
+      "version": "1.1.0",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@radix-ui/react-slot/-/react-slot-1.1.0.tgz",
+      "integrity": "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@radix-ui/react-compose-refs": "1.1.0"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
     "node_modules/@radix-ui/react-slot": {
       "version": "1.0.2",
       "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@radix-ui/react-slot/-/react-slot-1.0.2.tgz",
@@ -11177,22 +11436,21 @@
       }
     },
     "node_modules/@radix-ui/react-toggle": {
-      "version": "1.0.3",
-      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@radix-ui/react-toggle/-/react-toggle-1.0.3.tgz",
-      "integrity": "sha512-Pkqg3+Bc98ftZGsl60CLANXQBBQ4W3mTFS9EJvNxKMZ7magklKV69/id1mlAlOFDDfHvlCms0fx8fA4CMKDJHg==",
+      "version": "1.1.0",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@radix-ui/react-toggle/-/react-toggle-1.1.0.tgz",
+      "integrity": "sha512-gwoxaKZ0oJ4vIgzsfESBuSgJNdc0rv12VhHgcqN0TEJmmZixXG/2XpsLK8kzNWYcnaoRIEEQc0bEi3dIvdUpjw==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "@babel/runtime": "^7.13.10",
-        "@radix-ui/primitive": "1.0.1",
-        "@radix-ui/react-primitive": "1.0.3",
-        "@radix-ui/react-use-controllable-state": "1.0.1"
+        "@radix-ui/primitive": "1.1.0",
+        "@radix-ui/react-primitive": "2.0.0",
+        "@radix-ui/react-use-controllable-state": "1.1.0"
       },
       "peerDependencies": {
         "@types/react": "*",
         "@types/react-dom": "*",
-        "react": "^16.8 || ^17.0 || ^18.0",
-        "react-dom": "^16.8 || ^17.0 || ^18.0"
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
       },
       "peerDependenciesMeta": {
         "@types/react": {
@@ -11204,26 +11462,25 @@
       }
     },
     "node_modules/@radix-ui/react-toggle-group": {
-      "version": "1.0.4",
-      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@radix-ui/react-toggle-group/-/react-toggle-group-1.0.4.tgz",
-      "integrity": "sha512-Uaj/M/cMyiyT9Bx6fOZO0SAG4Cls0GptBWiBmBxofmDbNVnYYoyRWj/2M/6VCi/7qcXFWnHhRUfdfZFvvkuu8A==",
+      "version": "1.1.0",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@radix-ui/react-toggle-group/-/react-toggle-group-1.1.0.tgz",
+      "integrity": "sha512-PpTJV68dZU2oqqgq75Uzto5o/XfOVgkrJ9rulVmfTKxWp3HfUjHE6CP/WLRR4AzPX9HWxw7vFow2me85Yu+Naw==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "@babel/runtime": "^7.13.10",
-        "@radix-ui/primitive": "1.0.1",
-        "@radix-ui/react-context": "1.0.1",
-        "@radix-ui/react-direction": "1.0.1",
-        "@radix-ui/react-primitive": "1.0.3",
-        "@radix-ui/react-roving-focus": "1.0.4",
-        "@radix-ui/react-toggle": "1.0.3",
-        "@radix-ui/react-use-controllable-state": "1.0.1"
+        "@radix-ui/primitive": "1.1.0",
+        "@radix-ui/react-context": "1.1.0",
+        "@radix-ui/react-direction": "1.1.0",
+        "@radix-ui/react-primitive": "2.0.0",
+        "@radix-ui/react-roving-focus": "1.1.0",
+        "@radix-ui/react-toggle": "1.1.0",
+        "@radix-ui/react-use-controllable-state": "1.1.0"
       },
       "peerDependencies": {
         "@types/react": "*",
         "@types/react-dom": "*",
-        "react": "^16.8 || ^17.0 || ^18.0",
-        "react-dom": "^16.8 || ^17.0 || ^18.0"
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
       },
       "peerDependenciesMeta": {
         "@types/react": {
@@ -11234,27 +11491,260 @@
         }
       }
     },
+    "node_modules/@radix-ui/react-toggle-group/node_modules/@radix-ui/primitive": {
+      "version": "1.1.0",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@radix-ui/primitive/-/primitive-1.1.0.tgz",
+      "integrity": "sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/@radix-ui/react-toggle-group/node_modules/@radix-ui/react-compose-refs": {
+      "version": "1.1.0",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz",
+      "integrity": "sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==",
+      "dev": true,
+      "peer": true,
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-toggle-group/node_modules/@radix-ui/react-context": {
+      "version": "1.1.0",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@radix-ui/react-context/-/react-context-1.1.0.tgz",
+      "integrity": "sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==",
+      "dev": true,
+      "peer": true,
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-toggle-group/node_modules/@radix-ui/react-direction": {
+      "version": "1.1.0",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@radix-ui/react-direction/-/react-direction-1.1.0.tgz",
+      "integrity": "sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg==",
+      "dev": true,
+      "peer": true,
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-toggle-group/node_modules/@radix-ui/react-primitive": {
+      "version": "2.0.0",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@radix-ui/react-primitive/-/react-primitive-2.0.0.tgz",
+      "integrity": "sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@radix-ui/react-slot": "1.1.0"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "@types/react-dom": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "@types/react-dom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-toggle-group/node_modules/@radix-ui/react-slot": {
+      "version": "1.1.0",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@radix-ui/react-slot/-/react-slot-1.1.0.tgz",
+      "integrity": "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@radix-ui/react-compose-refs": "1.1.0"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-toggle-group/node_modules/@radix-ui/react-use-callback-ref": {
+      "version": "1.1.0",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz",
+      "integrity": "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==",
+      "dev": true,
+      "peer": true,
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-toggle-group/node_modules/@radix-ui/react-use-controllable-state": {
+      "version": "1.1.0",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.1.0.tgz",
+      "integrity": "sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@radix-ui/react-use-callback-ref": "1.1.0"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-toggle/node_modules/@radix-ui/primitive": {
+      "version": "1.1.0",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@radix-ui/primitive/-/primitive-1.1.0.tgz",
+      "integrity": "sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/@radix-ui/react-toggle/node_modules/@radix-ui/react-compose-refs": {
+      "version": "1.1.0",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz",
+      "integrity": "sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==",
+      "dev": true,
+      "peer": true,
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-toggle/node_modules/@radix-ui/react-primitive": {
+      "version": "2.0.0",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@radix-ui/react-primitive/-/react-primitive-2.0.0.tgz",
+      "integrity": "sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@radix-ui/react-slot": "1.1.0"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "@types/react-dom": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "@types/react-dom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-toggle/node_modules/@radix-ui/react-slot": {
+      "version": "1.1.0",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@radix-ui/react-slot/-/react-slot-1.1.0.tgz",
+      "integrity": "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@radix-ui/react-compose-refs": "1.1.0"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-toggle/node_modules/@radix-ui/react-use-callback-ref": {
+      "version": "1.1.0",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz",
+      "integrity": "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==",
+      "dev": true,
+      "peer": true,
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-toggle/node_modules/@radix-ui/react-use-controllable-state": {
+      "version": "1.1.0",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.1.0.tgz",
+      "integrity": "sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@radix-ui/react-use-callback-ref": "1.1.0"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
     "node_modules/@radix-ui/react-toolbar": {
-      "version": "1.0.4",
-      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@radix-ui/react-toolbar/-/react-toolbar-1.0.4.tgz",
-      "integrity": "sha512-tBgmM/O7a07xbaEkYJWYTXkIdU/1pW4/KZORR43toC/4XWyBCURK0ei9kMUdp+gTPPKBgYLxXmRSH1EVcIDp8Q==",
+      "version": "1.1.0",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@radix-ui/react-toolbar/-/react-toolbar-1.1.0.tgz",
+      "integrity": "sha512-ZUKknxhMTL/4hPh+4DuaTot9aO7UD6Kupj4gqXCsBTayX1pD1L+0C2/2VZKXb4tIifQklZ3pf2hG9T+ns+FclQ==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "@babel/runtime": "^7.13.10",
-        "@radix-ui/primitive": "1.0.1",
-        "@radix-ui/react-context": "1.0.1",
-        "@radix-ui/react-direction": "1.0.1",
-        "@radix-ui/react-primitive": "1.0.3",
-        "@radix-ui/react-roving-focus": "1.0.4",
-        "@radix-ui/react-separator": "1.0.3",
-        "@radix-ui/react-toggle-group": "1.0.4"
+        "@radix-ui/primitive": "1.1.0",
+        "@radix-ui/react-context": "1.1.0",
+        "@radix-ui/react-direction": "1.1.0",
+        "@radix-ui/react-primitive": "2.0.0",
+        "@radix-ui/react-roving-focus": "1.1.0",
+        "@radix-ui/react-separator": "1.1.0",
+        "@radix-ui/react-toggle-group": "1.1.0"
       },
       "peerDependencies": {
         "@types/react": "*",
         "@types/react-dom": "*",
-        "react": "^16.8 || ^17.0 || ^18.0",
-        "react-dom": "^16.8 || ^17.0 || ^18.0"
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
       },
       "peerDependenciesMeta": {
         "@types/react": {
@@ -11265,6 +11755,104 @@
         }
       }
     },
+    "node_modules/@radix-ui/react-toolbar/node_modules/@radix-ui/primitive": {
+      "version": "1.1.0",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@radix-ui/primitive/-/primitive-1.1.0.tgz",
+      "integrity": "sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==",
+      "dev": true,
+      "peer": true
+    },
+    "node_modules/@radix-ui/react-toolbar/node_modules/@radix-ui/react-compose-refs": {
+      "version": "1.1.0",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz",
+      "integrity": "sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==",
+      "dev": true,
+      "peer": true,
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-toolbar/node_modules/@radix-ui/react-context": {
+      "version": "1.1.0",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@radix-ui/react-context/-/react-context-1.1.0.tgz",
+      "integrity": "sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==",
+      "dev": true,
+      "peer": true,
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-toolbar/node_modules/@radix-ui/react-direction": {
+      "version": "1.1.0",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@radix-ui/react-direction/-/react-direction-1.1.0.tgz",
+      "integrity": "sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg==",
+      "dev": true,
+      "peer": true,
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-toolbar/node_modules/@radix-ui/react-primitive": {
+      "version": "2.0.0",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@radix-ui/react-primitive/-/react-primitive-2.0.0.tgz",
+      "integrity": "sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@radix-ui/react-slot": "1.1.0"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "@types/react-dom": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "@types/react-dom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-toolbar/node_modules/@radix-ui/react-slot": {
+      "version": "1.1.0",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@radix-ui/react-slot/-/react-slot-1.1.0.tgz",
+      "integrity": "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@radix-ui/react-compose-refs": "1.1.0"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
     "node_modules/@radix-ui/react-use-callback-ref": {
       "version": "1.0.1",
       "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.1.tgz",
@@ -13612,19 +14200,19 @@
       }
     },
     "node_modules/@storybook/components": {
-      "version": "7.6.19",
-      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@storybook/components/-/components-7.6.19.tgz",
-      "integrity": "sha512-8Zw/RQ4crzKkUR7ojxvRIj8vktKiBBO8Nq93qv4JfDqDWrcR7cro0hOlZgmZmrzbFunBBt6WlsNNO6nVP7R4Xw==",
+      "version": "7.6.20",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@storybook/components/-/components-7.6.20.tgz",
+      "integrity": "sha512-0d8u4m558R+W5V+rseF/+e9JnMciADLXTpsILrG+TBhwECk0MctIWW18bkqkujdCm8kDZr5U2iM/5kS1Noy7Ug==",
       "dev": true,
       "peer": true,
       "dependencies": {
         "@radix-ui/react-select": "^1.2.2",
         "@radix-ui/react-toolbar": "^1.0.4",
-        "@storybook/client-logger": "7.6.19",
+        "@storybook/client-logger": "7.6.20",
         "@storybook/csf": "^0.1.2",
         "@storybook/global": "^5.0.0",
-        "@storybook/theming": "7.6.19",
-        "@storybook/types": "7.6.19",
+        "@storybook/theming": "7.6.20",
+        "@storybook/types": "7.6.20",
         "memoizerific": "^1.11.3",
         "use-resize-observer": "^9.1.0",
         "util-deprecate": "^1.0.2"
@@ -13639,14 +14227,14 @@
       }
     },
     "node_modules/@storybook/components/node_modules/@storybook/channels": {
-      "version": "7.6.19",
-      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@storybook/channels/-/channels-7.6.19.tgz",
-      "integrity": "sha512-2JGh+i95GwjtjqWqhtEh15jM5ifwbRGmXeFqkY7dpdHH50EEWafYHr2mg3opK3heVDwg0rJ/VBptkmshloXuvA==",
+      "version": "7.6.20",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@storybook/channels/-/channels-7.6.20.tgz",
+      "integrity": "sha512-4hkgPSH6bJclB2OvLnkZOGZW1WptJs09mhQ6j6qLjgBZzL/ZdD6priWSd7iXrmPiN5TzUobkG4P4Dp7FjkiO7A==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "@storybook/client-logger": "7.6.19",
-        "@storybook/core-events": "7.6.19",
+        "@storybook/client-logger": "7.6.20",
+        "@storybook/core-events": "7.6.20",
         "@storybook/global": "^5.0.0",
         "qs": "^6.10.0",
         "telejson": "^7.2.0",
@@ -13658,9 +14246,9 @@
       }
     },
     "node_modules/@storybook/components/node_modules/@storybook/client-logger": {
-      "version": "7.6.19",
-      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@storybook/client-logger/-/client-logger-7.6.19.tgz",
-      "integrity": "sha512-oGzOxbmLmciSIfd5gsxDzPmX8DttWhoYdPKxjMuCuWLTO2TWpkCWp1FTUMWO72mm/6V/FswT/aqpJJBBvdZ3RQ==",
+      "version": "7.6.20",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@storybook/client-logger/-/client-logger-7.6.20.tgz",
+      "integrity": "sha512-NwG0VIJQCmKrSaN5GBDFyQgTAHLNishUPLW1NrzqTDNAhfZUoef64rPQlinbopa0H4OXmlB+QxbQIb3ubeXmSQ==",
       "dev": true,
       "peer": true,
       "dependencies": {
@@ -13672,13 +14260,13 @@
       }
     },
     "node_modules/@storybook/components/node_modules/@storybook/types": {
-      "version": "7.6.19",
-      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@storybook/types/-/types-7.6.19.tgz",
-      "integrity": "sha512-DeGYrRPRMGTVfT7o2rEZtRzyLT2yKTI2exgpnxbwPWEFAduZCSfzBrcBXZ/nb5B0pjA9tUNWls1YzGkJGlkhpg==",
+      "version": "7.6.20",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@storybook/types/-/types-7.6.20.tgz",
+      "integrity": "sha512-GncdY3x0LpbhmUAAJwXYtJDUQEwfF175gsjH0/fxPkxPoV7Sef9TM41jQLJW/5+6TnZoCZP/+aJZTJtq3ni23Q==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "@storybook/channels": "7.6.19",
+        "@storybook/channels": "7.6.20",
         "@types/babel__core": "^7.0.0",
         "@types/express": "^4.7.0",
         "file-system-cache": "2.3.0"
@@ -13853,9 +14441,9 @@
       }
     },
     "node_modules/@storybook/core-events": {
-      "version": "7.6.19",
-      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@storybook/core-events/-/core-events-7.6.19.tgz",
-      "integrity": "sha512-K/W6Uvum0ocZSgjbi8hiotpe+wDEHDZlvN+KlPqdh9ae9xDK8aBNBq9IelCoqM+uKO1Zj+dDfSQds7CD781DJg==",
+      "version": "7.6.20",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@storybook/core-events/-/core-events-7.6.20.tgz",
+      "integrity": "sha512-tlVDuVbDiNkvPDFAu+0ou3xBBYbx9zUURQz4G9fAq0ScgBOs/bpzcRrFb4mLpemUViBAd47tfZKdH4MAX45KVQ==",
       "dev": true,
       "peer": true,
       "dependencies": {
@@ -14383,14 +14971,14 @@
       }
     },
     "node_modules/@storybook/theming": {
-      "version": "7.6.19",
-      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@storybook/theming/-/theming-7.6.19.tgz",
-      "integrity": "sha512-sAho13MmtA80ctOaLn8lpkQBsPyiqSdLcOPH5BWFhatQzzBQCpTAKQk+q/xGju8bNiPZ+yQBaBzbN8SfX8ceCg==",
+      "version": "7.6.20",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@storybook/theming/-/theming-7.6.20.tgz",
+      "integrity": "sha512-iT1pXHkSkd35JsCte6Qbanmprx5flkqtSHC6Gi6Umqoxlg9IjiLPmpHbaIXzoC06DSW93hPj5Zbi1lPlTvRC7Q==",
       "dev": true,
       "peer": true,
       "dependencies": {
         "@emotion/use-insertion-effect-with-fallbacks": "^1.0.0",
-        "@storybook/client-logger": "7.6.19",
+        "@storybook/client-logger": "7.6.20",
         "@storybook/global": "^5.0.0",
         "memoizerific": "^1.11.3"
       },
@@ -14404,9 +14992,9 @@
       }
     },
     "node_modules/@storybook/theming/node_modules/@storybook/client-logger": {
-      "version": "7.6.19",
-      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@storybook/client-logger/-/client-logger-7.6.19.tgz",
-      "integrity": "sha512-oGzOxbmLmciSIfd5gsxDzPmX8DttWhoYdPKxjMuCuWLTO2TWpkCWp1FTUMWO72mm/6V/FswT/aqpJJBBvdZ3RQ==",
+      "version": "7.6.20",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@storybook/client-logger/-/client-logger-7.6.20.tgz",
+      "integrity": "sha512-NwG0VIJQCmKrSaN5GBDFyQgTAHLNishUPLW1NrzqTDNAhfZUoef64rPQlinbopa0H4OXmlB+QxbQIb3ubeXmSQ==",
       "dev": true,
       "peer": true,
       "dependencies": {
@@ -14675,6 +15263,16 @@
       "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==",
       "devOptional": true
     },
+    "node_modules/@swc/helpers": {
+      "version": "0.5.12",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@swc/helpers/-/helpers-0.5.12.tgz",
+      "integrity": "sha512-KMZNXiGibsW9kvZAO1Pam2JPTDBm+KSHMMHWdsyI/1DbIZjT2A6Gy3hblVXUMEDvUAKq+e0vL0X0o54owWji7g==",
+      "optional": true,
+      "peer": true,
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
     "node_modules/@swc/types": {
       "version": "0.1.8",
       "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/@swc/types/-/types-0.1.8.tgz",
@@ -19867,9 +20465,9 @@
       "dev": true
     },
     "node_modules/debug": {
-      "version": "4.3.4",
-      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/debug/-/debug-4.3.4.tgz",
-      "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+      "version": "4.3.6",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/debug/-/debug-4.3.6.tgz",
+      "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==",
       "dependencies": {
         "ms": "2.1.2"
       },
@@ -27768,32 +28366,32 @@
       }
     },
     "node_modules/mocha": {
-      "version": "10.4.0",
-      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/mocha/-/mocha-10.4.0.tgz",
-      "integrity": "sha512-eqhGB8JKapEYcC4ytX/xrzKforgEc3j1pGlAXVy3eRwrtAy5/nIfT1SvgGzfN0XZZxeLq0aQWkOUAmqIJiv+bA==",
+      "version": "10.7.0",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/mocha/-/mocha-10.7.0.tgz",
+      "integrity": "sha512-v8/rBWr2VO5YkspYINnvu81inSz2y3ODJrhO175/Exzor1RcEZZkizgE2A+w/CAXXoESS8Kys5E62dOHGHzULA==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "ansi-colors": "4.1.1",
-        "browser-stdout": "1.3.1",
-        "chokidar": "3.5.3",
-        "debug": "4.3.4",
-        "diff": "5.0.0",
-        "escape-string-regexp": "4.0.0",
-        "find-up": "5.0.0",
-        "glob": "8.1.0",
-        "he": "1.2.0",
-        "js-yaml": "4.1.0",
-        "log-symbols": "4.1.0",
-        "minimatch": "5.0.1",
-        "ms": "2.1.3",
-        "serialize-javascript": "6.0.0",
-        "strip-json-comments": "3.1.1",
-        "supports-color": "8.1.1",
-        "workerpool": "6.2.1",
-        "yargs": "16.2.0",
-        "yargs-parser": "20.2.4",
-        "yargs-unparser": "2.0.0"
+        "ansi-colors": "^4.1.3",
+        "browser-stdout": "^1.3.1",
+        "chokidar": "^3.5.3",
+        "debug": "^4.3.5",
+        "diff": "^5.2.0",
+        "escape-string-regexp": "^4.0.0",
+        "find-up": "^5.0.0",
+        "glob": "^8.1.0",
+        "he": "^1.2.0",
+        "js-yaml": "^4.1.0",
+        "log-symbols": "^4.1.0",
+        "minimatch": "^5.1.6",
+        "ms": "^2.1.3",
+        "serialize-javascript": "^6.0.2",
+        "strip-json-comments": "^3.1.1",
+        "supports-color": "^8.1.1",
+        "workerpool": "^6.5.1",
+        "yargs": "^16.2.0",
+        "yargs-parser": "^20.2.9",
+        "yargs-unparser": "^2.0.0"
       },
       "bin": {
         "_mocha": "bin/_mocha",
@@ -27803,16 +28401,6 @@
         "node": ">= 14.0.0"
       }
     },
-    "node_modules/mocha/node_modules/ansi-colors": {
-      "version": "4.1.1",
-      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/ansi-colors/-/ansi-colors-4.1.1.tgz",
-      "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==",
-      "dev": true,
-      "peer": true,
-      "engines": {
-        "node": ">=6"
-      }
-    },
     "node_modules/mocha/node_modules/ansi-regex": {
       "version": "5.0.1",
       "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/ansi-regex/-/ansi-regex-5.0.1.tgz",
@@ -27839,34 +28427,6 @@
         "url": "https://github.com/chalk/ansi-styles?sponsor=1"
       }
     },
-    "node_modules/mocha/node_modules/chokidar": {
-      "version": "3.5.3",
-      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/chokidar/-/chokidar-3.5.3.tgz",
-      "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
-      "dev": true,
-      "funding": [
-        {
-          "type": "individual",
-          "url": "https://paulmillr.com/funding/"
-        }
-      ],
-      "peer": true,
-      "dependencies": {
-        "anymatch": "~3.1.2",
-        "braces": "~3.0.2",
-        "glob-parent": "~5.1.2",
-        "is-binary-path": "~2.1.0",
-        "is-glob": "~4.0.1",
-        "normalize-path": "~3.0.0",
-        "readdirp": "~3.6.0"
-      },
-      "engines": {
-        "node": ">= 8.10.0"
-      },
-      "optionalDependencies": {
-        "fsevents": "~2.3.2"
-      }
-    },
     "node_modules/mocha/node_modules/cliui": {
       "version": "7.0.4",
       "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/cliui/-/cliui-7.0.4.tgz",
@@ -27879,16 +28439,6 @@
         "wrap-ansi": "^7.0.0"
       }
     },
-    "node_modules/mocha/node_modules/diff": {
-      "version": "5.0.0",
-      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/diff/-/diff-5.0.0.tgz",
-      "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==",
-      "dev": true,
-      "peer": true,
-      "engines": {
-        "node": ">=0.3.1"
-      }
-    },
     "node_modules/mocha/node_modules/escape-string-regexp": {
       "version": "4.0.0",
       "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
@@ -27934,9 +28484,9 @@
       }
     },
     "node_modules/mocha/node_modules/minimatch": {
-      "version": "5.0.1",
-      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/minimatch/-/minimatch-5.0.1.tgz",
-      "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==",
+      "version": "5.1.6",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/minimatch/-/minimatch-5.1.6.tgz",
+      "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
       "dev": true,
       "peer": true,
       "dependencies": {
@@ -27953,16 +28503,6 @@
       "dev": true,
       "peer": true
     },
-    "node_modules/mocha/node_modules/serialize-javascript": {
-      "version": "6.0.0",
-      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/serialize-javascript/-/serialize-javascript-6.0.0.tgz",
-      "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==",
-      "dev": true,
-      "peer": true,
-      "dependencies": {
-        "randombytes": "^2.1.0"
-      }
-    },
     "node_modules/mocha/node_modules/strip-ansi": {
       "version": "6.0.1",
       "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/strip-ansi/-/strip-ansi-6.0.1.tgz",
@@ -28030,9 +28570,9 @@
       }
     },
     "node_modules/mocha/node_modules/yargs-parser": {
-      "version": "20.2.4",
-      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/yargs-parser/-/yargs-parser-20.2.4.tgz",
-      "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==",
+      "version": "20.2.9",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/yargs-parser/-/yargs-parser-20.2.9.tgz",
+      "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
       "dev": true,
       "peer": true,
       "engines": {
@@ -37868,9 +38408,9 @@
       }
     },
     "node_modules/workerpool": {
-      "version": "6.2.1",
-      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/workerpool/-/workerpool-6.2.1.tgz",
-      "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==",
+      "version": "6.5.1",
+      "resolved": "http://nexus.ozg-sh.de/repository/npm-proxy/workerpool/-/workerpool-6.5.1.tgz",
+      "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==",
       "dev": true,
       "peer": true
     },
diff --git a/alfa-client/package.json b/alfa-client/package.json
index 8dc2364f58bb67444d25979f3fd75136efdac63e..a02724a20ba7b3e3d31967f73f9e0ec13ad8fce5 100644
--- a/alfa-client/package.json
+++ b/alfa-client/package.json
@@ -1,6 +1,6 @@
 {
   "name": "alfa",
-  "version": "0.7.0-SNAPSHOT",
+  "version": "0.8.0-SNAPSHOT",
   "license": "MIT",
   "scripts": {
     "start": "nx run alfa:serve --port 4300 --disable-host-check",
@@ -10,9 +10,10 @@
     "start-for-screenreader": "nx run alfa:serve --host 192.168.178.20 --port 4300 --disable-host-check --verbose",
     "start:devbe": "nx run alfa:serve --port 4300 --disable-host-check --proxy-config proxy.dev.conf.json --verbose",
     "build": "nx run alfa:build",
+    "ci-build-alfa-client-container": "nx container alfa",
     "test": "nx affected --target=test --parallel 8 -- --runInBand",
     "test:cov": "jest --coverage",
-    "test:lib": "nx test ${npm_config_lib} --watchAll",
+    "test:lib": "nx test ${npm_config_lib}",
     "test:debug:lib": "nx test ${npm_config_lib} --detectOpenHandles --watchAll",
     "ci-build": "nx run alfa:build --outputHashing=all",
     "ci-build-admin": "nx container admin && cp -r dist/ apps/admin/",
diff --git a/alfa-client/pom.xml b/alfa-client/pom.xml
index 31c038a64e63e52771d87ecb1085e907e9af2cb8..b36055f368b4404644459bb3f3816469ba738293 100644
--- a/alfa-client/pom.xml
+++ b/alfa-client/pom.xml
@@ -29,7 +29,7 @@
 	<parent>
 		<groupId>de.ozgcloud.alfa</groupId>
 		<artifactId>alfa</artifactId>
-		<version>2.11.0-SNAPSHOT</version>
+		<version>2.12.0-SNAPSHOT</version>
 	</parent>
 
     <modelVersion>4.0.0</modelVersion>
diff --git a/alfa-client/tsconfig.base.json b/alfa-client/tsconfig.base.json
index b8645da774def8753885d8a14cfd87a1e8f887eb..15284c9f0e8bc51994ae4e9b965a16c8b17d0bb6 100644
--- a/alfa-client/tsconfig.base.json
+++ b/alfa-client/tsconfig.base.json
@@ -23,6 +23,8 @@
       "@alfa-client/bescheid-shared": ["libs/bescheid-shared/src/index.ts"],
       "@alfa-client/binary-file": ["libs/binary-file/src/index.ts"],
       "@alfa-client/binary-file-shared": ["libs/binary-file-shared/src/index.ts"],
+      "@alfa-client/collaboration": ["libs/collaboration/src/index.ts"],
+      "@alfa-client/collaboration-shared": ["libs/collaboration-shared/src/index.ts"],
       "@alfa-client/command-shared": ["libs/command-shared/src/index.ts"],
       "@alfa-client/environment-shared": ["libs/environment-shared/src/index.ts"],
       "@alfa-client/forwarding": ["libs/forwarding/src/index.ts"],
@@ -55,7 +57,8 @@
       "@alfa-client/wiedervorlage-shared": ["libs/wiedervorlage-shared/src/index.ts"],
       "@ods/component": ["libs/design-component/src/index.ts"],
       "@ods/system": ["libs/design-system/src/index.ts"],
-      "authentication": ["libs/authentication/src/index.ts"]
+      "authentication": ["libs/authentication/src/index.ts"],
+      "test": ["libs/test/src/index.ts"]
     }
   },
   "exclude": ["node_modules", "tmp"]
diff --git a/alfa-server/pom.xml b/alfa-server/pom.xml
index 5124be2c496ebd8623a1445b16fdcb0a2074c4f0..e157390eee8d5e6722072745abd75cb760f831ec 100644
--- a/alfa-server/pom.xml
+++ b/alfa-server/pom.xml
@@ -5,7 +5,7 @@
 	<parent>
 		<groupId>de.ozgcloud.alfa</groupId>
 		<artifactId>alfa</artifactId>
-		<version>2.11.0-SNAPSHOT</version>
+		<version>2.12.0-SNAPSHOT</version>
 	</parent>
 
 	<artifactId>alfa-server</artifactId>
diff --git a/alfa-server/src/main/resources/application-dev.yml b/alfa-server/src/main/resources/application-dev.yml
index 52ca56a22d8fa5ded4dcecfae01b3e22553c2da1..6f11904235f17602539afaca47cd695e69deee8b 100644
--- a/alfa-server/src/main/resources/application-dev.yml
+++ b/alfa-server/src/main/resources/application-dev.yml
@@ -10,6 +10,7 @@ server:
 ozgcloud:
   feature:
     reply-always-allowed: true
+    collaboration-enabled: true
   production: false
   stage:
     production: false
diff --git a/alfa-server/src/main/resources/application-e2e.yml b/alfa-server/src/main/resources/application-e2e.yml
index 7aa16cc6e02921c1fa3157a05b185fcbf08c623d..69d9b46a198e57b5d03f01cc78f2d83e209f9335 100644
--- a/alfa-server/src/main/resources/application-e2e.yml
+++ b/alfa-server/src/main/resources/application-e2e.yml
@@ -8,8 +8,8 @@ keycloak:
 
 ozgcloud:
   feature:
-    createBescheid: true
     reply-always-allowed: true
+    collaboration-enabled: true
   forwarding:
     lninfo:
       url: classpath:files/LandesnetzInfo.html
diff --git a/alfa-server/src/main/resources/application-local.yml b/alfa-server/src/main/resources/application-local.yml
index b113a7052d27746ebf67fdd3600b381e7e658dd5..74743fd293aab8aeda88d286548ff33e73ea55d7 100644
--- a/alfa-server/src/main/resources/application-local.yml
+++ b/alfa-server/src/main/resources/application-local.yml
@@ -18,6 +18,7 @@ grpc:
 ozgcloud:
   feature:
     reply-always-allowed: true
+    collaboration-enabled: true
   production: false
   user-assistance:
     documentation:
diff --git a/alfa-server/src/main/resources/application.yml b/alfa-server/src/main/resources/application.yml
index ac930de36a83c9b7d962e72dca5ef29eae2fdd57..0f0c8e24b2ea7023c57f11e22b8f3d7c997864e3 100644
--- a/alfa-server/src/main/resources/application.yml
+++ b/alfa-server/src/main/resources/application.yml
@@ -61,6 +61,9 @@ grpc:
     user-manager:
       address: static://127.0.0.1:9000
       negotiationType: TLS
+    zufi-manager:
+      address: static://127.0.0.1:9190
+      negotiationType: TLS
 
 ozgcloud:
   auth:
diff --git a/alfa-service/pom.xml b/alfa-service/pom.xml
index f2e9a4141f8dc1c75e3769a1671b1ca511714d8c..9f540119c2fdada17280122da064557d1fc1078a 100644
--- a/alfa-service/pom.xml
+++ b/alfa-service/pom.xml
@@ -24,14 +24,16 @@
     unter der Lizenz sind dem Lizenztext zu entnehmen.
 
 -->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 
 	<modelVersion>4.0.0</modelVersion>
 
 	<parent>
 		<groupId>de.ozgcloud.alfa</groupId>
 		<artifactId>alfa</artifactId>
-		<version>2.11.0-SNAPSHOT</version>
+		<version>2.12.0-SNAPSHOT</version>
 	</parent>
 
 	<artifactId>alfa-service</artifactId>
@@ -127,6 +129,10 @@
 			<groupId>de.ozgcloud.user</groupId>
 			<artifactId>user-manager-interface</artifactId>
 		</dependency>
+		<dependency>
+			<groupId>de.ozgcloud.zufi</groupId>
+			<artifactId>zufi-manager-interface</artifactId>
+		</dependency>
 
 		<!-- tools -->
 		<dependency>
@@ -229,4 +235,4 @@
 		</plugins>
 	</build>
 
-</project>
+</project>
\ No newline at end of file
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/Anschrift.java b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/Anschrift.java
new file mode 100644
index 0000000000000000000000000000000000000000..e39bea0b531da3fa6d82b4a122f226135714d96f
--- /dev/null
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/Anschrift.java
@@ -0,0 +1,15 @@
+package de.ozgcloud.alfa.collaboration;
+
+import lombok.Builder;
+import lombok.Getter;
+
+@Builder
+@Getter
+class Anschrift {
+
+	private String strasse;
+	private String hausnummer;
+	private String plz;
+	private String ort;
+
+}
\ No newline at end of file
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/Collaboration.java b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/Collaboration.java
new file mode 100644
index 0000000000000000000000000000000000000000..a6e8f794e96951c0eb215b97dc73b49205ce0234
--- /dev/null
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/Collaboration.java
@@ -0,0 +1,24 @@
+package de.ozgcloud.alfa.collaboration;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+
+import de.ozgcloud.alfa.common.LinkedResource;
+import de.ozgcloud.alfa.common.command.CommandBody;
+import lombok.Builder;
+import lombok.Getter;
+
+@Getter
+@Builder
+public class Collaboration implements CommandBody {
+
+	@JsonIgnore
+	private String vorgangId;
+	@JsonIgnore
+	private String collaborationVorgangId;
+
+	private String titel;
+	private String anfrage;
+
+	@LinkedResource(controllerClass = OrganisationsEinheitController.class)
+	private String zustaendigeStelle;
+}
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/CollaborationController.java b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/CollaborationController.java
new file mode 100644
index 0000000000000000000000000000000000000000..63a1fa8edc08547408395b4b70739cd766ef27fe
--- /dev/null
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/CollaborationController.java
@@ -0,0 +1,26 @@
+package de.ozgcloud.alfa.collaboration;
+
+import org.springframework.hateoas.CollectionModel;
+import org.springframework.hateoas.EntityModel;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import lombok.RequiredArgsConstructor;
+
+@RestController
+@RequestMapping(CollaborationController.PATH)
+@RequiredArgsConstructor
+public class CollaborationController {
+
+	private final CollaborationModelAssembler assembler;
+	private final CollaborationService service;
+
+	static final String PATH = "/api/vorgangs"; // NOSONAR
+
+	@GetMapping("/{vorgangId}/collaborations")
+	public CollectionModel<EntityModel<Collaboration>> getAllByVorgangId(@PathVariable String vorgangId) {
+		return assembler.toCollectionModel(service.getCollaborations(vorgangId), vorgangId);
+	}
+}
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
new file mode 100644
index 0000000000000000000000000000000000000000..0323c66fe4fa72971c00afc34815b8d92a064670
--- /dev/null
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/CollaborationModelAssembler.java
@@ -0,0 +1,48 @@
+package de.ozgcloud.alfa.collaboration;
+
+import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*;
+
+import java.util.stream.Stream;
+
+import org.springframework.hateoas.CollectionModel;
+import org.springframework.hateoas.EntityModel;
+import org.springframework.hateoas.Link;
+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;
+import de.ozgcloud.alfa.vorgang.VorgangController;
+import lombok.RequiredArgsConstructor;
+
+@Component
+@RequiredArgsConstructor
+class CollaborationModelAssembler implements RepresentationModelAssembler<Collaboration, EntityModel<Collaboration>> {
+
+	static final LinkRelation REL_CREATE_COLLABORATION_REQUEST = LinkRelation.of("createCollaborationRequest");
+
+	private final VorgangController vorgangController;
+
+	@Override
+	public EntityModel<Collaboration> toModel(Collaboration collaboration) {
+		return ModelBuilder.fromEntity(collaboration)
+				// TODO: Wenn Schnittstelle zum laden der Collaboration existiert, muss self
+				// link ergänzt werden
+				.buildModel();
+	}
+
+	public CollectionModel<EntityModel<Collaboration>> toCollectionModel(Stream<? extends Collaboration> entities, String vorgangId) {
+		var collectionModel = CollectionModel.of(entities.map(this::toModel).toList())
+				.add(linkTo(methodOn(CollaborationController.class).getAllByVorgangId(vorgangId)).withSelfRel());
+		return collectionModel
+				.addIf(collectionModel.getContent().isEmpty(), () -> buildCreateCollaborationRequestLink(vorgangId));
+	}
+
+	Link buildCreateCollaborationRequestLink(String vorgangId) {
+		var vorgang = vorgangController.getVorgang(vorgangId);
+		return linkTo(methodOn(CommandController.CommandByRelationController.class).createCommand(vorgang.getId(), vorgang.getId(),
+				vorgang.getVersion(), null)).withRel(REL_CREATE_COLLABORATION_REQUEST);
+	}
+
+}
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/CollaborationRemoteService.java b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/CollaborationRemoteService.java
new file mode 100644
index 0000000000000000000000000000000000000000..a81de9638ea305b333fbebb229520bb0d42ad33c
--- /dev/null
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/CollaborationRemoteService.java
@@ -0,0 +1,14 @@
+package de.ozgcloud.alfa.collaboration;
+
+import java.util.stream.Stream;
+
+import org.springframework.stereotype.Service;
+
+@Service
+public class CollaborationRemoteService {
+
+	public Stream<Collaboration> getCollaborations(String vorgangId) {
+		// TODO: Replace Dummy Data with real grpc call
+		return Stream.empty();
+	}
+}
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/CollaborationService.java b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/CollaborationService.java
new file mode 100644
index 0000000000000000000000000000000000000000..8b4406b926453d570d635b13a556ef6e9050b65b
--- /dev/null
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/CollaborationService.java
@@ -0,0 +1,23 @@
+package de.ozgcloud.alfa.collaboration;
+
+import java.util.stream.Stream;
+
+import org.springframework.stereotype.Service;
+
+import lombok.RequiredArgsConstructor;
+
+@Service
+@RequiredArgsConstructor
+class CollaborationService {
+
+	private final CollaborationRemoteService remoteService;
+
+	public Stream<Collaboration> getCollaborations(String vorgangId) {
+		return remoteService.getCollaborations(vorgangId);
+	}
+
+	public boolean hasCollaboration(String vorgangId) {
+		return remoteService.getCollaborations(vorgangId).findAny().isPresent();
+	}
+
+}
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
new file mode 100644
index 0000000000000000000000000000000000000000..c8c7378a3ea53c202a34f4cf8582a30e71b8da09
--- /dev/null
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/CollaborationVorgangProcessor.java
@@ -0,0 +1,44 @@
+package de.ozgcloud.alfa.collaboration;
+
+import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*;
+
+import java.util.Objects;
+
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+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.user.CurrentUserService;
+import de.ozgcloud.alfa.common.user.UserRole;
+import de.ozgcloud.alfa.vorgang.VorgangWithEingang;
+import lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+@Component
+@ConditionalOnProperty("ozgcloud.feature.collaboration-enabled")
+class CollaborationVorgangProcessor implements RepresentationModelProcessor<EntityModel<VorgangWithEingang>> {
+
+	static final LinkRelation REL_COLLABORATIONS = LinkRelation.of("collaborations");
+	static final LinkRelation REL_SEARCH_ORGANISATIONS_EINHEIT = LinkRelation.of("searchOrganisationsEinheit");
+
+	private final CurrentUserService currentUserService;
+	private final CollaborationService collaborationService;
+
+	@Override
+	public EntityModel<VorgangWithEingang> process(EntityModel<VorgangWithEingang> model) {
+		var vorgang = model.getContent();
+
+		if (Objects.isNull(vorgang) || !currentUserService.hasRole(UserRole.VERWALTUNG_USER)) {
+			return model;
+		}
+
+		return ModelBuilder.fromModel(model)
+				.ifMatch(() -> !collaborationService.hasCollaboration(vorgang.getId()))
+				.addLink(linkTo(methodOn(OrganisationsEinheitController.class).search(null)).withRel(REL_SEARCH_ORGANISATIONS_EINHEIT))
+				.addLink(linkTo(methodOn(CollaborationController.class).getAllByVorgangId(vorgang.getId())).withRel(REL_COLLABORATIONS))
+				.buildModel();
+	}
+}
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheit.java b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheit.java
new file mode 100644
index 0000000000000000000000000000000000000000..33bbb03f0d3e3ccfb854740dd9d97e9316d0a691
--- /dev/null
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheit.java
@@ -0,0 +1,14 @@
+package de.ozgcloud.alfa.collaboration;
+
+import lombok.Builder;
+import lombok.Getter;
+import lombok.extern.jackson.Jacksonized;
+
+@Builder
+@Getter
+@Jacksonized
+class OrganisationsEinheit {
+
+	private String id;
+	private XzufiId xzufiId;
+}
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitController.java b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitController.java
new file mode 100644
index 0000000000000000000000000000000000000000..e60539a72396755760875f86af415b3cc547dd9d
--- /dev/null
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitController.java
@@ -0,0 +1,37 @@
+package de.ozgcloud.alfa.collaboration;
+
+import java.util.Optional;
+
+import org.springframework.hateoas.CollectionModel;
+import org.springframework.hateoas.EntityModel;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import lombok.RequiredArgsConstructor;
+
+@RestController
+@RequestMapping(OrganisationsEinheitController.PATH)
+@RequiredArgsConstructor
+class OrganisationsEinheitController {
+
+	static final String PATH = "/api/organisationseinheits"; // NOSONAR
+	static final String SEARCH_BY_PARAM = "searchBy";
+
+	private final OrganisationsEinheitService service;
+	private final OrganisationsEinheitModelAssembler assembler;
+	private final OrganisationsEinheitHeaderModelAssembler headerModelAssembler;
+
+	@GetMapping("/{organisationsEinheitId}")
+	public ResponseEntity<EntityModel<OrganisationsEinheit>> getById(@PathVariable String organisationsEinheitId) {
+		return ResponseEntity.of(Optional.of(service.getById(organisationsEinheitId)).map(assembler::toModel));
+	}
+
+	@GetMapping(params = { SEARCH_BY_PARAM })
+	public CollectionModel<EntityModel<OrganisationsEinheitHeader>> search(@RequestParam String searchBy) {
+		return headerModelAssembler.toCollectionModel(service.searchOrganisationsEinheiten(searchBy).toList());
+	}
+}
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitHeader.java b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitHeader.java
new file mode 100644
index 0000000000000000000000000000000000000000..ebe24c6a9a962df8c6438ee52da962871f630254
--- /dev/null
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitHeader.java
@@ -0,0 +1,17 @@
+package de.ozgcloud.alfa.collaboration;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+
+import lombok.Builder;
+import lombok.Getter;
+
+@Builder
+@Getter
+class OrganisationsEinheitHeader {
+
+	@JsonIgnore
+	private String id;
+	private String name;
+	private Anschrift anschrift;
+
+}
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitHeaderMapper.java b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitHeaderMapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..0fa1bb19f6546781d3cc0b3ea4a9b111c09f7be2
--- /dev/null
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitHeaderMapper.java
@@ -0,0 +1,11 @@
+package de.ozgcloud.alfa.collaboration;
+
+import org.mapstruct.Mapper;
+
+import de.ozgcloud.zufi.grpc.organisationseinheit.GrpcOrganisationsEinheit;
+
+@Mapper
+interface OrganisationsEinheitHeaderMapper {
+
+	OrganisationsEinheitHeader fromGrpc(GrpcOrganisationsEinheit organisationsEinheit);
+}
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
new file mode 100644
index 0000000000000000000000000000000000000000..8cbea84ba7535ce790c4dc8d80333f9d47737319
--- /dev/null
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitHeaderModelAssembler.java
@@ -0,0 +1,30 @@
+package de.ozgcloud.alfa.collaboration;
+
+import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*;
+
+import jakarta.annotation.Nonnull;
+
+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.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();
+	}
+
+	@Override
+	public CollectionModel<EntityModel<OrganisationsEinheitHeader>> toCollectionModel(Iterable<? extends OrganisationsEinheitHeader> entities) {
+		return RepresentationModelAssembler.super.toCollectionModel(entities)
+				.add(linkTo(OrganisationsEinheitController.class).withSelfRel());
+	}
+}
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitMapper.java b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitMapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..20c30041b9642e66551eaecc771091bec74d7920
--- /dev/null
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitMapper.java
@@ -0,0 +1,11 @@
+package de.ozgcloud.alfa.collaboration;
+
+import org.mapstruct.Mapper;
+
+import de.ozgcloud.zufi.grpc.organisationseinheit.GrpcOrganisationsEinheit;
+
+@Mapper
+interface OrganisationsEinheitMapper {
+
+	OrganisationsEinheit fromGrpc(GrpcOrganisationsEinheit organisationsEinheit);
+}
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
new file mode 100644
index 0000000000000000000000000000000000000000..60f582dfdb3477e72aecd9ad3bf3062d37838fdc
--- /dev/null
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitModelAssembler.java
@@ -0,0 +1,20 @@
+package de.ozgcloud.alfa.collaboration;
+
+import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*;
+
+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();
+	}
+}
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitRemoteService.java b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitRemoteService.java
new file mode 100644
index 0000000000000000000000000000000000000000..aeea7b92941b95fab767bb1641920739e78b8092
--- /dev/null
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitRemoteService.java
@@ -0,0 +1,48 @@
+package de.ozgcloud.alfa.collaboration;
+
+import java.util.stream.Stream;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import de.ozgcloud.alfa.common.GrpcUtil;
+import de.ozgcloud.zufi.grpc.organisationseinheit.GrpcOrganisationsEinheitGetRequest;
+import de.ozgcloud.zufi.grpc.organisationseinheit.GrpcOrganisationsEinheitGetResponse;
+import de.ozgcloud.zufi.grpc.organisationseinheit.GrpcOrganisationsEinheitSearchRequest;
+import de.ozgcloud.zufi.grpc.organisationseinheit.OrganisationsEinheitServiceGrpc.OrganisationsEinheitServiceBlockingStub;
+import net.devh.boot.grpc.client.inject.GrpcClient;
+
+@Service
+class OrganisationsEinheitRemoteService {
+
+	@GrpcClient(GrpcUtil.ZUFI_MANAGER_GRPC_CLIENT)
+	private OrganisationsEinheitServiceBlockingStub serviceStub;
+
+	@Autowired
+	private OrganisationsEinheitHeaderMapper organisationsEinheitHeaderMapper;
+	@Autowired
+	private OrganisationsEinheitMapper organisationsEinheitMapper;
+
+	public Stream<OrganisationsEinheitHeader> search(String searchBy) {
+		var response = serviceStub.search(buildSearchRequest(searchBy));
+		return response.getOrganisationsEinheitenList().stream().map(organisationsEinheitHeaderMapper::fromGrpc);
+	}
+
+	private GrpcOrganisationsEinheitSearchRequest buildSearchRequest(String searchBy) {
+		return GrpcOrganisationsEinheitSearchRequest.newBuilder().setSearchBy(searchBy).build();
+	}
+
+	public OrganisationsEinheit getById(String id) {
+		var request = buildGetByIdRequest(id);
+		var response = serviceStub.getById(request);
+		return getOrganisationsEinheitFromGetByIdResponse(response);
+	}
+
+	GrpcOrganisationsEinheitGetRequest buildGetByIdRequest(String organisationsEinheitId) {
+		return GrpcOrganisationsEinheitGetRequest.newBuilder().setId(organisationsEinheitId).build();
+	}
+
+	OrganisationsEinheit getOrganisationsEinheitFromGetByIdResponse(GrpcOrganisationsEinheitGetResponse response) {
+		return organisationsEinheitMapper.fromGrpc(response.getOrganisationsEinheit());
+	}
+}
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitService.java b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitService.java
new file mode 100644
index 0000000000000000000000000000000000000000..58afb0f569cf5353de916024011e9670f3a9c537
--- /dev/null
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitService.java
@@ -0,0 +1,23 @@
+package de.ozgcloud.alfa.collaboration;
+
+import java.util.stream.Stream;
+
+import org.springframework.stereotype.Service;
+
+import lombok.RequiredArgsConstructor;
+
+@Service
+@RequiredArgsConstructor
+class OrganisationsEinheitService {
+
+	private final OrganisationsEinheitRemoteService remoteService;
+
+	public OrganisationsEinheit getById(String id) {
+		return remoteService.getById(id);
+	}
+
+	public Stream<OrganisationsEinheitHeader> searchOrganisationsEinheiten(String searchBy) {
+		return remoteService.search(searchBy);
+	}
+
+}
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/XzufiId.java b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/XzufiId.java
new file mode 100644
index 0000000000000000000000000000000000000000..49e1f5f3ecafe67ad7ca22daf104406e5a8f39a2
--- /dev/null
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/XzufiId.java
@@ -0,0 +1,11 @@
+package de.ozgcloud.alfa.collaboration;
+
+import lombok.Builder;
+import lombok.Getter;
+
+@Builder
+@Getter
+public class XzufiId {
+	private String id;
+	private String schemeAgencyId;
+}
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/common/FeatureToggleProperties.java b/alfa-service/src/main/java/de/ozgcloud/alfa/common/FeatureToggleProperties.java
index b06e637da196c9b9d5dfb11a5d51a72fb505da7d..5b60fc67206213d2be23bda2aebddfb539873da5 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/common/FeatureToggleProperties.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/common/FeatureToggleProperties.java
@@ -13,12 +13,12 @@ import lombok.Setter;
 public class FeatureToggleProperties {
 
 	/**
-	 * Enable/Disable bescheid creation feature.
+	 * Enable mail reply option regardless of other configuration.
 	 */
-	private boolean createBescheid = false;
+	private boolean replyAlwaysAllowed = false;
 
 	/**
-	 * Enable mail reply option regardless of other configuration.
+	 * Enable collaboration-feature in Vorgang
 	 */
-	private boolean replyAlwaysAllowed = false;
+	private boolean collaborationEnabled = false;
 }
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/common/GrpcUtil.java b/alfa-service/src/main/java/de/ozgcloud/alfa/common/GrpcUtil.java
index d11d5297b8373ad3d84900333a7f996c7e2db650..fc033f658d18ce1a5726b631e32ab7b591c5817f 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/common/GrpcUtil.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/common/GrpcUtil.java
@@ -38,6 +38,8 @@ public class GrpcUtil {
 
 	public static final String VORGANG_MANAGER_GRPC_CLIENT = "vorgang-manager";
 
+	public static final String ZUFI_MANAGER_GRPC_CLIENT = "zufi-manager";
+
 	public static final String SERVICE_KEY = "GRPC_SERVICE";
 
 	public static Key<String> keyOfString(String key) {
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/CommandBody.java b/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/CommandBody.java
index 8bdf5bbab7eee1d9c6040bdc844cc568546e88bd..42f3ec714dd2a8c466b34cf2670977e2eba6d45a 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/CommandBody.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/CommandBody.java
@@ -29,6 +29,7 @@ import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
 import de.ozgcloud.alfa.aktenzeichen.AktenzeichenCommandBody;
 import de.ozgcloud.alfa.bescheid.Bescheid;
 import de.ozgcloud.alfa.bescheid.BescheidDocumentFromFileBody;
+import de.ozgcloud.alfa.collaboration.Collaboration;
 import de.ozgcloud.alfa.kommentar.Kommentar;
 import de.ozgcloud.alfa.loeschanforderung.DeleteLoeschAnforderung;
 import de.ozgcloud.alfa.loeschanforderung.LoeschAnforderung;
@@ -54,7 +55,8 @@ import de.ozgcloud.alfa.wiedervorlage.Wiedervorlage;
 		@Type(value = Bescheid.class, name = "UPDATE_BESCHEID"),
 		@Type(value = ProcessVorgangBody.class, name = "PROCESS_VORGANG"),
 		@Type(value = AktenzeichenCommandBody.class, name = "SET_AKTENZEICHEN"),
-		@Type(value = BescheidDocumentFromFileBody.class, name = "CREATE_BESCHEID_DOCUMENT_FROM_FILE")
+		@Type(value = BescheidDocumentFromFileBody.class, name = "CREATE_BESCHEID_DOCUMENT_FROM_FILE"),
+		@Type(value = Collaboration.class, name = "CREATE_COLLABORATION_REQUEST")
 })
 public interface CommandBody {
 }
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 843c170180851a807ec32a4cdc2cc2c019095d3e..d8825572907482b5b7acaae723eea79c2cde445b 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
@@ -38,6 +38,7 @@ import org.springframework.stereotype.Component;
 
 import de.ozgcloud.alfa.bescheid.BescheidController;
 import de.ozgcloud.alfa.bescheid.DocumentController;
+import de.ozgcloud.alfa.collaboration.CollaborationController;
 import de.ozgcloud.alfa.common.ModelBuilder;
 import de.ozgcloud.alfa.kommentar.KommentarController;
 import de.ozgcloud.alfa.postfach.PostfachMailController;
@@ -82,6 +83,7 @@ class CommandModelAssembler implements RepresentationModelAssembler<Command, Ent
 			case WIEDERVORLAGE -> linkTo(WiedervorlageController.class).slash(entity.getRelationId());
 			case BESCHEID -> linkTo(methodOn(BescheidController.class).getDraft(entity.getVorgangId()));
 			case DOCUMENT -> linkTo(DocumentController.class).slash(entity.getCreatedResource());
+			case COLLABORATION -> linkTo(methodOn(CollaborationController.class).getAllByVorgangId(entity.getVorgangId()));
 			case NONE -> throw new IllegalArgumentException("Unknown CommandOrder: " + entity.getOrder());
 		};
 
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/CommandOrder.java b/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/CommandOrder.java
index 2ecc444afffdd33e851266564ec0356fd19ff164..f2a74744787b4e860b4b0ce2234a62719625dffc 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/CommandOrder.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/CommandOrder.java
@@ -73,10 +73,12 @@ public enum CommandOrder {
 
 	PROCESS_VORGANG(false, Type.VORGANG),
 
+	CREATE_COLLABORATION_REQUEST(false, Type.COLLABORATION),
+
 	UNBEKANNT(false, Type.NONE);
 
 	enum Type {
-		VORGANG, VORGANG_LIST, WIEDERVORLAGE, KOMMENTAR, FORWARDING, POSTFACH, BESCHEID, DOCUMENT, NONE
+		VORGANG, VORGANG_LIST, WIEDERVORLAGE, KOMMENTAR, FORWARDING, POSTFACH, BESCHEID, DOCUMENT, COLLABORATION, NONE
 	}
 
 	private final boolean revokeable;
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/CommandService.java b/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/CommandService.java
index 777ad9b7689d27e87f460276f96ffbd46d99ffe3..dc573993c67ac660e97502ae4087e66d43ed3928 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/CommandService.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/CommandService.java
@@ -29,21 +29,21 @@ import java.util.stream.Stream;
 import jakarta.validation.Valid;
 
 import org.apache.commons.collections.MapUtils;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
 
 import de.ozgcloud.alfa.loeschanforderung.DeleteLoeschAnforderung;
 import lombok.NonNull;
+import lombok.RequiredArgsConstructor;
 
+@RequiredArgsConstructor
 @Validated
 @Service
 public class CommandService {
 
 	static final long NO_RELATION_VERSION = -1;
 
-	@Autowired
-	private CommandRemoteService remoteService;
+	private final CommandRemoteService remoteService;
 
 	/**
 	 * @deprecated use {@link #createCommand(CreateCommand)} instead
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/common/errorhandling/ExceptionController.java b/alfa-service/src/main/java/de/ozgcloud/alfa/common/errorhandling/ExceptionController.java
index 5e4f5be4e7d0a8077ab670e49769d3655c8abd47..facaacd37af7212818e9e220331f7c6a24c4c4a4 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/common/errorhandling/ExceptionController.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/common/errorhandling/ExceptionController.java
@@ -23,49 +23,38 @@
  */
 package de.ozgcloud.alfa.common.errorhandling;
 
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map.Entry;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.Set;
 import java.util.UUID;
-import java.util.stream.Stream;
 
-import jakarta.validation.ConstraintViolation;
 import jakarta.validation.ConstraintViolationException;
-import jakarta.validation.Path;
-import jakarta.validation.metadata.ConstraintDescriptor;
 
-import org.hibernate.validator.engine.HibernateConstraintViolation;
 import org.springframework.core.annotation.Order;
 import org.springframework.http.HttpStatus;
+import org.springframework.http.ProblemDetail;
 import org.springframework.security.access.AccessDeniedException;
-import org.springframework.web.bind.annotation.ControllerAdvice;
 import org.springframework.web.bind.annotation.ExceptionHandler;
-import org.springframework.web.bind.annotation.ResponseBody;
 import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
 
-import de.ozgcloud.alfa.common.binaryfile.DynamicViolationParameter;
 import de.ozgcloud.common.errorhandling.ExceptionUtil;
 import de.ozgcloud.common.errorhandling.TechnicalException;
+import lombok.RequiredArgsConstructor;
 import lombok.extern.log4j.Log4j2;
 
-@ControllerAdvice
+@RestControllerAdvice
+@RequiredArgsConstructor
 @Log4j2
 @Order(98)
-public class ExceptionController {
-
-	private static final Set<String> IGNORABLE_CONSTRAINT_VIOLATION_ATTRIBUTES = new HashSet<>(Arrays.asList("groups", "payload", "message"));
+public class ExceptionController extends ResponseEntityExceptionHandler {
 
 	static final String RUNTIME_MESSAGE_CODE = "generale.server_error";
 	static final String RESOURCE_NOT_FOUNT_MESSAGE_CODE = "resource.not_found";
 	static final String ACCESS_DENIED_MESSAGE_CODE = "generale.access_denied";
 
+	private final ProblemDetailMapper problemDetailMapper;
+
 	@ExceptionHandler(FunctionalException.class)
 	@ResponseStatus(HttpStatus.BAD_REQUEST)
-	@ResponseBody
 	public ApiError handleFunctionalException(FunctionalException e) {
 		LOG.error("BadRequest", e);
 		return ApiError.builder().issue(buildIssueForFunctionalException(e)).build();
@@ -77,7 +66,6 @@ public class ExceptionController {
 
 	@ExceptionHandler(AccessDeniedException.class)
 	@ResponseStatus(HttpStatus.FORBIDDEN)
-	@ResponseBody
 	public ApiError handleAccessDeniedException(AccessDeniedException e) {
 		var exceptionId = createExceptionId();
 		var messageWithExceptionId = ExceptionUtil.formatMessageWithExceptionId(e.getMessage(), exceptionId);
@@ -92,7 +80,6 @@ public class ExceptionController {
 
 	@ExceptionHandler(ResourceNotFoundException.class)
 	@ResponseStatus(HttpStatus.NOT_FOUND)
-	@ResponseBody
 	public ApiError handleResourceNotFoundException(ResourceNotFoundException e) {
 		LOG.warn("Resource not found: {}", e.getMessage());
 		return ApiError.builder().issue(buildIssueForResourceNotFoundException(e)).build();
@@ -103,66 +90,14 @@ public class ExceptionController {
 	}
 
 	@ExceptionHandler(ConstraintViolationException.class)
-	@ResponseStatus(HttpStatus.UNPROCESSABLE_ENTITY)
-	@ResponseBody
-	public ApiError handleConstraintViolationException(ConstraintViolationException e) {
-		var exceptionId = createExceptionId();
-		var messageWithExceptionId = ExceptionUtil.formatMessageWithExceptionId(e.getMessage(), exceptionId);
-		LOG.warn("Validation Exception: {}", messageWithExceptionId);
-		return ApiError.builder().issues(buildIssues(e, exceptionId)).build();
-	}
-
-	private List<Issue> buildIssues(ConstraintViolationException e, String exceptionId) {
-		return e.getConstraintViolations().stream()
-				.map(violation -> buildIssue(violation, exceptionId))
-				.toList();
-	}
-
-	private Issue buildIssue(ConstraintViolation<?> violation, String exceptionId) {
-		return Issue.builder()//
-				.field(buildFieldPath(violation.getPropertyPath()))//
-				.messageCode(violation.getMessageTemplate().replace("{", "").replace("}", ""))//
-				.message(violation.getMessage())//
-				.parameters(buildParameters(violation).toList())
-				.exceptionId(exceptionId)
-				.build();
-	}
-
-	private String buildFieldPath(Path propertyPath) {
-		return propertyPath.toString().substring(propertyPath.toString().indexOf('.') + 1);
-	}
-
-	Stream<IssueParam> buildParameters(ConstraintViolation<?> violation) {
-		var dynamicPayload = getDynamicPayload(violation);
-		return Optional.ofNullable(violation.getConstraintDescriptor())
-				.map(ConstraintDescriptor::getAttributes)
-				.map(descr -> descr.entrySet().stream()
-						.filter(entry -> !IGNORABLE_CONSTRAINT_VIOLATION_ATTRIBUTES.contains(entry.getKey()))
-						.map(entryMap -> buildIssueParam(entryMap, dynamicPayload)))
-				.orElse(Stream.empty());
-	}
-
-	private IssueParam buildIssueParam(Entry<String, Object> entry, Optional<DynamicViolationParameter> dynamicValues) {
-		return IssueParam.builder().name(entry.getKey()).value(getValue(entry, dynamicValues)).build();
-	}
-
-	private String getValue(Entry<String, Object> entry, Optional<DynamicViolationParameter> dynamicValues) {
-		return dynamicValues
-				.map(DynamicViolationParameter::getMap)
-				.map(map -> map.get(entry.getKey()))
-				.filter(Objects::nonNull)
-				.map(String::valueOf)
-				.orElse(String.valueOf(entry.getValue()));
-	}
+	public ProblemDetail handleConstraintViolationException(ConstraintViolationException e) {
+		LOG.warn("Validation Exception: {}", problemDetailMapper.buildMessageWithExceptionId(e));
 
-	private Optional<DynamicViolationParameter> getDynamicPayload(ConstraintViolation<?> violation) {
-		HibernateConstraintViolation<?> hibernateViolation = violation.unwrap(HibernateConstraintViolation.class);
-		return Optional.ofNullable(hibernateViolation.getDynamicPayload(DynamicViolationParameter.class));
+		return problemDetailMapper.fromConstraintViolationException(e);
 	}
 
 	@ExceptionHandler(TechnicalException.class)
 	@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
-	@ResponseBody
 	public ApiError handleTechnicalException(TechnicalException e) {
 		LOG.error("TechnicalException on Request", e);
 		return buildRuntimeApiError(e.getMessage(), e.getExceptionId());
@@ -170,7 +105,6 @@ public class ExceptionController {
 
 	@ExceptionHandler(RuntimeException.class)
 	@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
-	@ResponseBody
 	public ApiError handleRuntimeException(RuntimeException e) {
 		var exceptionId = createExceptionId();
 		var messageWithExceptionId = ExceptionUtil.formatMessageWithExceptionId(e.getMessage(), exceptionId);
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/common/errorhandling/ProblemDetailMapper.java b/alfa-service/src/main/java/de/ozgcloud/alfa/common/errorhandling/ProblemDetailMapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..c4a358f396674e8bcd4f8f4fb36eb677eec7b74b
--- /dev/null
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/common/errorhandling/ProblemDetailMapper.java
@@ -0,0 +1,90 @@
+package de.ozgcloud.alfa.common.errorhandling;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.UUID;
+import java.util.stream.Stream;
+
+import jakarta.validation.ConstraintViolation;
+import jakarta.validation.ConstraintViolationException;
+import jakarta.validation.metadata.ConstraintDescriptor;
+
+import org.hibernate.validator.engine.HibernateConstraintViolation;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ProblemDetail;
+import org.springframework.stereotype.Component;
+
+import de.ozgcloud.alfa.common.binaryfile.DynamicViolationParameter;
+import de.ozgcloud.common.errorhandling.ExceptionUtil;
+
+@Component
+public class ProblemDetailMapper {
+
+	static final String INVALID_PARAMS_KEY_CONSTRAINT_PARAMETERS = "constraintParameters";
+	static final String INVALID_PARAMS_KEY_REASON = "reason";
+	static final String INVALID_PARAMS_KEY_VALUE = "value";
+	static final String INVALID_PARAMS_KEY_NAME = "name";
+	static final String INVALID_PARAMS = "invalidParams";
+	static final String PROVIDED_VALUE_WAS_NULL = "Provided value was null!";
+	private static final Set<String> IGNORABLE_CONSTRAINT_VIOLATION_ATTRIBUTES = Set.of("groups", "payload", "message");
+
+	public ProblemDetail fromConstraintViolationException(ConstraintViolationException e) {
+		var problemDetail = ProblemDetail.forStatusAndDetail(HttpStatus.UNPROCESSABLE_ENTITY, buildMessageWithExceptionId(e));
+		problemDetail.setProperty(INVALID_PARAMS, buildInvalidParams(e.getConstraintViolations()).toList());
+		return problemDetail;
+	}
+
+	public String buildMessageWithExceptionId(ConstraintViolationException e) {
+		var exceptionId = createExceptionId();
+		return ExceptionUtil.formatMessageWithExceptionId(e.getLocalizedMessage(),
+				exceptionId);
+	}
+
+	String createExceptionId() {
+		return UUID.randomUUID().toString();
+	}
+
+	Stream<Map<String, Object>> buildInvalidParams(Set<ConstraintViolation<?>> violations) {
+		return Objects.requireNonNullElse(violations, Collections.<ConstraintViolation<?>>emptySet()).stream().map(this::buildDetailedViolation);
+	}
+
+	Map<String, Object> buildDetailedViolation(ConstraintViolation<?> violation) {
+		return Map.of(
+				INVALID_PARAMS_KEY_NAME, violation.getPropertyPath().toString(),
+				INVALID_PARAMS_KEY_VALUE, Objects.requireNonNullElse(violation.getInvalidValue(), PROVIDED_VALUE_WAS_NULL).toString(),
+				INVALID_PARAMS_KEY_REASON, violation.getMessage(),
+				INVALID_PARAMS_KEY_CONSTRAINT_PARAMETERS, buildParameters(violation).toList());
+	}
+
+	Stream<IssueParam> buildParameters(ConstraintViolation<?> violation) {
+		var dynamicPayload = getDynamicPayload(violation);
+		return Optional.ofNullable(violation.getConstraintDescriptor())
+				.map(ConstraintDescriptor::getAttributes)
+				.map(descr -> descr.entrySet().stream()
+						.filter(entry -> !IGNORABLE_CONSTRAINT_VIOLATION_ATTRIBUTES.contains(entry.getKey()))
+						.map(entryMap -> buildIssueParam(entryMap, dynamicPayload)))
+				.orElse(Stream.empty());
+	}
+
+	private IssueParam buildIssueParam(Entry<String, Object> entry, Optional<DynamicViolationParameter> dynamicValues) {
+		return IssueParam.builder().name(entry.getKey()).value(getValue(entry, dynamicValues)).build();
+	}
+
+	private String getValue(Entry<String, Object> entry, Optional<DynamicViolationParameter> dynamicValues) {
+		return dynamicValues
+				.map(DynamicViolationParameter::getMap)
+				.map(map -> map.get(entry.getKey()))
+				.filter(Objects::nonNull)
+				.map(String::valueOf)
+				.orElse(String.valueOf(entry.getValue()));
+	}
+
+	private Optional<DynamicViolationParameter> getDynamicPayload(ConstraintViolation<?> violation) {
+		HibernateConstraintViolation<?> hibernateViolation = violation.unwrap(HibernateConstraintViolation.class);
+		return Optional.ofNullable(hibernateViolation.getDynamicPayload(DynamicViolationParameter.class));
+	}
+}
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/common/user/CurrentUserService.java b/alfa-service/src/main/java/de/ozgcloud/alfa/common/user/CurrentUserService.java
index f4a517c4052a3658f8ecfc3d81e5ac5a6593c849..a62746f45d4920e8e787e2beca665ecf137d8a99 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/common/user/CurrentUserService.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/common/user/CurrentUserService.java
@@ -29,7 +29,6 @@ import java.util.List;
 import java.util.Objects;
 import java.util.Optional;
 
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
 import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.oauth2.jwt.Jwt;
@@ -37,7 +36,9 @@ import org.springframework.stereotype.Service;
 
 import de.ozgcloud.alfa.common.binaryfile.AlfaUserWithFileId;
 import de.ozgcloud.common.errorhandling.TechnicalException;
+import lombok.RequiredArgsConstructor;
 
+@RequiredArgsConstructor
 @Service
 public class CurrentUserService {
 
@@ -51,10 +52,9 @@ public class CurrentUserService {
 	static final String KEYCLOAK_USER_GIVEN_NAME = "given_name";
 	static final String KEYCLOAK_USER_FAMILY_NAME = "family_name";
 
-	@Autowired
-	private UserService userService;
-	@Autowired
-	private RoleHierarchy roleHierarchy;
+	private final UserService userService;
+
+	private final RoleHierarchy roleHierarchy;
 
 	public boolean hasRole(String role) {
 		return CurrentUserHelper.hasRole(role) || hasRoleReachable(role);
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 94edbda19108796dfe1b0518e3cea960fa3aa1d5..6b111ac3c55ed436df4b141e6115ba419d599905 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
@@ -23,7 +23,6 @@
  */
 package de.ozgcloud.alfa.vorgang;
 
-import static java.util.Optional.*;
 import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*;
 
 import java.util.List;
@@ -39,7 +38,6 @@ import org.springframework.stereotype.Component;
 
 import de.ozgcloud.alfa.attachment.AttachmentController;
 import de.ozgcloud.alfa.attachment.AttachmentController.AttachmentsByVorgangController;
-import de.ozgcloud.alfa.common.FeatureToggleProperties;
 import de.ozgcloud.alfa.common.ModelBuilder;
 import de.ozgcloud.alfa.common.command.CommandController.CommandByRelationController;
 import de.ozgcloud.alfa.common.user.CurrentUserService;
@@ -64,7 +62,6 @@ class VorgangWithEingangProcessor implements RepresentationModelProcessor<Entity
 	static final LinkRelation REL_POSTFACH_MAILS = LinkRelation.of("postfachMails");
 	static final LinkRelation REL_VORGANG_FORWARDING = LinkRelation.of("forwarding");
 	static final LinkRelation REL_HISTORIE = LinkRelation.of("historie");
-	static final LinkRelation REL_BESCHEID = LinkRelation.of("createBescheid");
 	static final LinkRelation REL_PROCESS_VORGANG = LinkRelation.of("processVorgang");
 
 	static final String REL_SEARCH_USER = "search-user-profiles";
@@ -75,8 +72,6 @@ class VorgangWithEingangProcessor implements RepresentationModelProcessor<Entity
 	private final CurrentUserService userService;
 	private final UserManagerUrlProvider userManagerUrlProvider;
 
-	private final FeatureToggleProperties featureToggleProperties;
-	private final VorgangProperties vorgangProperties;
 	private final VorgangProcessorProperties vorgangProcessorProperties;
 
 	private static final Predicate<VorgangWithEingang> HAS_ATTACHMENTS = vorgangWithEingang -> vorgangWithEingang.getEingang()
@@ -111,9 +106,6 @@ class VorgangWithEingangProcessor implements RepresentationModelProcessor<Entity
 				.addLink(linkTo(methodOn(HistorieController.class).getAll(vorgang.getId())).withRel(REL_HISTORIE))
 				.ifMatch(() -> userManagerUrlProvider.isConfiguredForSearchUserProfile() && hasOrganisationsEinheitId(vorgang))
 				.addLink(this::buildSearchUserProfilesLink)
-				.ifMatch(this::isCreateBescheidEnabled)
-				.addLink(linkTo(methodOn(CommandByRelationController.class).createCommand(vorgang.getId(), vorgang.getId(), vorgang.getVersion(),
-						null)).withRel(REL_BESCHEID))
 				.ifMatch(this::isProcessable)
 				.addLink(
 						() -> linkTo(methodOn(CommandByRelationController.class).createCommand(vorgang.getId(), vorgang.getId(), vorgang.getVersion(),
@@ -144,21 +136,6 @@ class VorgangWithEingangProcessor implements RepresentationModelProcessor<Entity
 		return vorgang.getEingang().getZustaendigeStelle().getOrganisationseinheitenId();
 	}
 
-	boolean isCreateBescheidEnabled(VorgangWithEingang vorgang) {
-		return featureToggleProperties.isCreateBescheid() && hasVorgangCreateBescheidEnabled(vorgang);
-	}
-
-	boolean hasVorgangCreateBescheidEnabled(VorgangWithEingang vorgang) {
-		return ofNullable(vorgang.getEingang())
-				.map(Eingang::getHeader)
-				.map(this::isCreateBescheidEnabled)
-				.orElse(false);
-	}
-
-	private boolean isCreateBescheidEnabled(EingangHeader eingangHeader) {
-		return vorgangProperties.getBescheid().stream().anyMatch(prop -> isFormIdAndFormEngineNameMatching(eingangHeader, prop));
-	}
-
 	private boolean isProcessable(VorgangWithEingang vorgang) {
 		return isAnyFormIdAndFormEngineNameMatching(vorgang.getEingang().getHeader(), vorgangProcessorProperties.getProcessor());
 	}
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageCommandController.java b/alfa-service/src/main/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageCommandController.java
index d621a01dd99a332de8fe0dd6b2b754ccdc9a351a..7f068905ec5b2f0c464fe677dc4cfa10634847c2 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageCommandController.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageCommandController.java
@@ -54,26 +54,28 @@ public class WiedervorlageCommandController {
 		var wiedervorlage = service.getById(wiedervorlageId);
 		var createdCommand = createCommand(wiedervorlage, command);
 
-		service.updateNextFrist(wiedervorlage.getVorgangId());
-
 		return ResponseEntity.created(linkTo(CommandController.class).slash(createdCommand.getId()).toUri()).build();
 	}
 
 	Command createCommand(Wiedervorlage wiedervorlage, CreateCommand command) {
 		switch (command.getOrder()) {
-			case LegacyOrder.WIEDERVORLAGE_ERLEDIGEN: {
-				return service.erledigen(wiedervorlage);
-			}
-			case LegacyOrder.WIEDERVORLAGE_WIEDEREROEFFNEN: {
-				return service.wiedereroeffnen(wiedervorlage);
-			}
-			case LegacyOrder.EDIT_WIEDERVORLAGE: {
-				return service.editWiedervorlage(updateWiedervorlageByCommand(wiedervorlage, (Wiedervorlage) command.getBody()),
-						wiedervorlage.getId(),
-						wiedervorlage.getVersion());
-			}
-			default:
-				throw new TechnicalException("Unsupported order " + command.getOrder());
+		case LegacyOrder.WIEDERVORLAGE_ERLEDIGEN: {
+			var changed = wiedervorlage.toBuilder().done(true).build();
+			service.updateNextFrist(wiedervorlage.getVorgangId(), changed);
+			return service.erledigen(changed);
+		}
+		case LegacyOrder.WIEDERVORLAGE_WIEDEREROEFFNEN: {
+			var changed = wiedervorlage.toBuilder().done(false).build();
+			service.updateNextFrist(wiedervorlage.getVorgangId(), changed);
+			return service.wiedereroeffnen(changed);
+		}
+		case LegacyOrder.EDIT_WIEDERVORLAGE: {
+			var changed = updateWiedervorlageByCommand(wiedervorlage, (Wiedervorlage) command.getBody());
+			service.updateNextFrist(wiedervorlage.getVorgangId(), changed);
+			return service.editWiedervorlage(changed, wiedervorlage.getId(), wiedervorlage.getVersion());
+		}
+		default:
+			throw new TechnicalException("Unsupported order " + command.getOrder());
 		}
 	}
 
@@ -96,9 +98,10 @@ public class WiedervorlageCommandController {
 
 		@PostMapping
 		public ResponseEntity<Void> createWiedervorlage(@RequestBody CreateCommand command, @PathVariable String vorgangId) {
-			var createdCommand = service.createWiedervorlage((Wiedervorlage) command.getBody(), vorgangId);
+			var wiedervorlage = (Wiedervorlage) command.getBody();
+			var createdCommand = service.createWiedervorlage(wiedervorlage, vorgangId);
 
-			service.updateNextFrist(vorgangId);
+			service.updateNextFrist(vorgangId, wiedervorlage);
 
 			return ResponseEntity.created(linkTo(CommandController.class).slash(createdCommand.getId()).toUri()).build();
 		}
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageService.java b/alfa-service/src/main/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageService.java
index 660aeefbe8e6a5d1425fd04d4d3b9cedee1a6e8a..c61984151d2b6dd72de917a16391c28aedad325c 100644
--- a/alfa-service/src/main/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageService.java
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageService.java
@@ -33,7 +33,6 @@ import java.util.stream.Stream;
 
 import jakarta.validation.Valid;
 
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
@@ -41,19 +40,18 @@ import org.springframework.validation.annotation.Validated;
 import de.ozgcloud.alfa.common.attacheditem.VorgangAttachedItemService;
 import de.ozgcloud.alfa.common.command.Command;
 import de.ozgcloud.alfa.common.user.CurrentUserService;
+import lombok.RequiredArgsConstructor;
 
+@RequiredArgsConstructor
 @Validated
 @Service
 class WiedervorlageService {
 
 	private static final Predicate<Wiedervorlage> IS_NOT_DONE = wiedervorlage -> !wiedervorlage.isDone();
 
-	@Autowired
-	private WiedervorlageRemoteService remoteService;
-	@Autowired
-	private VorgangAttachedItemService vorgangAttachedItemService;
-	@Autowired
-	private CurrentUserService currentUserService;
+	private final WiedervorlageRemoteService remoteService;
+	private final VorgangAttachedItemService vorgangAttachedItemService;
+	private final CurrentUserService currentUserService;
 
 	public Command createWiedervorlage(@Valid Wiedervorlage wiedervorlage, String vorgangId) {
 		return vorgangAttachedItemService.createNewWiedervorlage(addCreated(wiedervorlage), vorgangId);
@@ -75,10 +73,13 @@ class WiedervorlageService {
 	}
 
 	@Async
-	public void updateNextFrist(String vorgangId) {
-		var allWiedervorlagen = findByVorgangId(vorgangId);
+	public void updateNextFrist(String vorgangId, Wiedervorlage changedOrNewWiedervorlage) {
+		var persistedWiedervorlagen = findByVorgangId(vorgangId);
+		var persistedWiedervorlagenExcludingChanged = persistedWiedervorlagen.filter(
+				wiedervorlage -> !wiedervorlage.getId().equals(changedOrNewWiedervorlage.getId()));
 
-		remoteService.updateNextFrist(vorgangId, calculateNextFrist(allWiedervorlagen));
+		var wiedervorlagen = Stream.concat(persistedWiedervorlagenExcludingChanged, Stream.of(changedOrNewWiedervorlage));
+		remoteService.updateNextFrist(vorgangId, calculateNextFrist(wiedervorlagen));
 	}
 
 	Optional<LocalDate> calculateNextFrist(Stream<Wiedervorlage> wiedervorlagen) {
@@ -94,11 +95,11 @@ class WiedervorlageService {
 		return remoteService.findByVorgangId(vorgangId);
 	}
 
-	Command erledigen(Wiedervorlage wiedervorlage) {
+	public Command erledigen(Wiedervorlage wiedervorlage) {
 		return vorgangAttachedItemService.setWiedervorlageDone(wiedervorlage, true);
 	}
 
-	Command wiedereroeffnen(Wiedervorlage wiedervorlage) {
+	public Command wiedereroeffnen(Wiedervorlage wiedervorlage) {
 		return vorgangAttachedItemService.setWiedervorlageDone(wiedervorlage, false);
 	}
 
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/bescheid/BescheidCommandITCase.java b/alfa-service/src/test/java/de/ozgcloud/alfa/bescheid/BescheidCommandITCase.java
index d4c71d099ea22b5a27736889e0fb0aebff784a44..b85d323ef153890af71025bd9b886ab230a6a67f 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/bescheid/BescheidCommandITCase.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/bescheid/BescheidCommandITCase.java
@@ -52,9 +52,9 @@ public class BescheidCommandITCase {
 			String content = createInvalidRequestContent(BescheidTestFactory.createBuilder().beschiedenAm(null).build());
 
 			doRequest(content).andExpect(status().isUnprocessableEntity())
-					.andExpect(jsonPath("$.issues.length()").value(1))
-					.andExpect(jsonPath("$.issues.[0].field").value("command.body.beschiedenAm"))
-					.andExpect(jsonPath("$.issues.[0].messageCode").value(ValidationMessageCodes.FIELD_DATE_FORMAT_INVALID));
+					.andExpect(jsonPath("$.invalidParams.length()").value(1))
+					.andExpect(jsonPath("$.invalidParams[0].name").value("createCommand.command.body.beschiedenAm"))
+					.andExpect(jsonPath("$.invalidParams[0].reason").value(ValidationMessageCodes.FIELD_DATE_FORMAT_INVALID));
 		}
 
 		@ParameterizedTest
@@ -82,9 +82,9 @@ public class BescheidCommandITCase {
 			return mockMvc.perform(
 					post(CommandByRelationController.COMMAND_BY_RELATION_PATH, VorgangHeaderTestFactory.ID, VorgangHeaderTestFactory.ID,
 							VorgangHeaderTestFactory.VERSION)
-							.with(csrf())
-							.contentType(MediaType.APPLICATION_JSON)
-							.content(content));
+									.with(csrf())
+									.contentType(MediaType.APPLICATION_JSON)
+									.content(content));
 		}
 	}
 }
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 159f038b04b56863c3532950ec5ebef062bf48f4..540170e893ab437f58b3609e4b1ab16c3971e4cd 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
@@ -249,7 +249,7 @@ class BescheidModelAssemblerTest {
 
 			callMethod();
 
-			verify(assembler).toCollectionModel(List.of(bescheid));
+			verify(assembler).toModel(bescheid);
 		}
 
 		@Test
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 fc714d41d1e45acb791372084e94c4c0b0bddab8..1b897c7d005dadfed9e1a76145eb873061b31e1b 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
@@ -20,6 +20,7 @@ import org.mockito.Spy;
 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;
@@ -27,7 +28,6 @@ import de.ozgcloud.alfa.vorgang.Vorgang;
 import de.ozgcloud.alfa.vorgang.VorgangHeaderTestFactory;
 import de.ozgcloud.alfa.vorgang.VorgangWithEingang;
 import de.ozgcloud.alfa.vorgang.VorgangWithEingangTestFactory;
-import lombok.NoArgsConstructor;
 
 class BescheidVorgangProcessorTest {
 
@@ -47,11 +47,9 @@ class BescheidVorgangProcessorTest {
 
 		@Test
 		void shouldReturnTheSameModelOnNullVorgang() {
-			var inputModel = new NullableEntityModel();
+			var processedModel = processor.process(EntityModelTestFactory.NULLABLE);
 
-			var processedModel = processor.process(inputModel);
-
-			assertThat(processedModel).isEqualTo(inputModel);
+			assertThat(processedModel).isEqualTo(EntityModelTestFactory.NULLABLE);
 		}
 
 		@Test
@@ -175,11 +173,6 @@ class BescheidVorgangProcessorTest {
 		private EntityModel<VorgangWithEingang> callProcess() {
 			return processor.process(EntityModel.of(vorgang));
 		}
-
-		@NoArgsConstructor
-		private static class NullableEntityModel extends EntityModel<VorgangWithEingang> {
-
-		}
 	}
 
 	@DisplayName("Exists bescheid")
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/AnschriftTestFactory.java b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/AnschriftTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..6036b9c1544846dd762deffc756f5ef6ac94b456
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/AnschriftTestFactory.java
@@ -0,0 +1,24 @@
+package de.ozgcloud.alfa.collaboration;
+
+import com.thedeanda.lorem.LoremIpsum;
+
+import de.ozgcloud.alfa.collaboration.Anschrift.AnschriftBuilder;
+
+public class AnschriftTestFactory {
+	public static final String PLZ = LoremIpsum.getInstance().getZipCode();
+	public static final String ORT = LoremIpsum.getInstance().getCity();
+	public static final String STRASSE = LoremIpsum.getInstance().getWords(2);
+	public static final String HAUSNUMMER = String.valueOf((int) (Math.random() * 1000));
+
+	public static Anschrift create() {
+		return createBuilder().build();
+	}
+
+	public static AnschriftBuilder createBuilder() {
+		return Anschrift.builder()
+				.strasse(STRASSE)
+				.ort(ORT)
+				.hausnummer(HAUSNUMMER)
+				.plz(PLZ);
+	}
+}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/CollaborationControllerTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/CollaborationControllerTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..87122cbb75c58ec12784d345654fd573f534ed70
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/CollaborationControllerTest.java
@@ -0,0 +1,148 @@
+package de.ozgcloud.alfa.collaboration;
+
+import static org.mockito.Mockito.*;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
+
+import java.util.Collections;
+import java.util.stream.Stream;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.springframework.hateoas.CollectionModel;
+import org.springframework.hateoas.EntityModel;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.ResultActions;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.util.UriComponentsBuilder;
+
+import lombok.SneakyThrows;
+
+class CollaborationControllerTest {
+
+	@InjectMocks
+	private CollaborationController controller;
+
+	@Mock
+	private CollaborationService service;
+
+	@Mock
+	private CollaborationModelAssembler assembler;
+
+	private MockMvc mockMvc;
+
+	@BeforeEach
+	void initTest() {
+		mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
+	}
+
+	@Nested
+	class TestGetAllByVorgangId {
+
+		private final Collaboration collaboration = CollaborationTestFactory.create();
+
+		@SneakyThrows
+		@Test
+		void shouldCallCollaborationService() {
+			performRequest();
+
+			verify(service).getCollaborations(CollaborationTestFactory.VORGANG_ID);
+		}
+
+		@Nested
+		class TestOnExistingCollaboration {
+
+			private final Stream<Collaboration> collaborations = Stream.of(collaboration);
+
+			@BeforeEach
+			void mock() {
+				when(service.getCollaborations(CollaborationTestFactory.VORGANG_ID)).thenReturn(collaborations);
+			}
+
+			@Test
+			void shouldCallAssembler() {
+				performRequest();
+
+				verify(assembler).toCollectionModel(collaborations, CollaborationTestFactory.VORGANG_ID);
+			}
+
+			@SneakyThrows
+			@Test
+			void shouldReturnStatusOk() {
+				when(assembler.toCollectionModel(collaborations, CollaborationTestFactory.VORGANG_ID))
+						.thenReturn(CollectionModel.of(Collections.singletonList(EntityModel.of(collaboration))));
+
+				var response = performRequest();
+
+				response.andExpect(status().isOk());
+			}
+
+			@Nested
+			class TestResponseBody {
+
+				@BeforeEach
+				void mockAssembler() {
+					when(assembler.toCollectionModel(collaborations, CollaborationTestFactory.VORGANG_ID))
+							.thenReturn(CollectionModel.of(Collections.singletonList(EntityModel.of(collaboration))));
+				}
+
+				@SneakyThrows
+				@Test
+				void shouldNotHaveVorgangId() {
+					var response = performRequest();
+
+					response.andExpect(jsonPath("$.vorgangId").doesNotExist());
+				}
+
+				@SneakyThrows
+				@Test
+				void shouldNotHaveCollaborationVorgangId() {
+					var response = performRequest();
+
+					response.andExpect(jsonPath("$.collaborationVorgangId").doesNotExist());
+				}
+
+				@SneakyThrows
+				@Test
+				void shouldHaveTitel() {
+					var response = performRequest();
+
+					response.andExpect(jsonPath("$.content[0].titel").value(CollaborationTestFactory.TITEL));
+				}
+
+				@SneakyThrows
+				@Test
+				void shouldHaveAnfrage() {
+					var response = performRequest();
+
+					System.out.println(response.andReturn().getResponse().getContentAsString());
+
+					response.andExpect(jsonPath("$.content[0].anfrage").value(CollaborationTestFactory.ANFRAGE));
+				}
+
+				@SneakyThrows
+				@Test
+				void shouldHaveZustaendigeStelle() {
+					var expectedLink = UriComponentsBuilder
+							.fromUriString("http://localhost")
+							.path(OrganisationsEinheitController.PATH)
+							.pathSegment(CollaborationTestFactory.ZUSTAENDIGE_STELLE)
+							.build();
+
+					var response = performRequest();
+
+					response.andExpect(jsonPath("$.content[0].zustaendigeStelle")
+							.value(expectedLink.toString()));
+				}
+			}
+		}
+
+		@SneakyThrows
+		private ResultActions performRequest() {
+			return mockMvc.perform(get(CollaborationController.PATH + "/" + CollaborationTestFactory.VORGANG_ID + "/collaborations"));
+		}
+	}
+}
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
new file mode 100644
index 0000000000000000000000000000000000000000..42ccdb43a2d39ed2bf5f6f71874eec71e57d36ed
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/CollaborationModelAssemblerTest.java
@@ -0,0 +1,183 @@
+package de.ozgcloud.alfa.collaboration;
+
+import static org.assertj.core.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+import java.util.stream.Stream;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Spy;
+import org.springframework.hateoas.CollectionModel;
+import org.springframework.hateoas.EntityModel;
+import org.springframework.hateoas.IanaLinkRelations;
+import org.springframework.hateoas.Link;
+import org.springframework.hateoas.UriTemplate;
+
+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;
+import de.ozgcloud.alfa.vorgang.VorgangWithEingang;
+import de.ozgcloud.alfa.vorgang.VorgangWithEingangTestFactory;
+
+class CollaborationModelAssemblerTest {
+
+	@Spy
+	@InjectMocks
+	private CollaborationModelAssembler assembler;
+
+	@Mock
+	private VorgangController vorgangController;
+
+	@Nested
+	class TestToModel {
+
+		private static final String REL_ZUSTAENDIGE_STELLE = "zustaendigeStelle";
+		private final Collaboration collaboration = CollaborationTestFactory.create();
+
+		@Test
+		void shouldHaveContent() {
+			var entityModel = callAssembler();
+
+			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);
+		}
+	}
+
+	@Nested
+	class TestToCollectionModel {
+		private final Collaboration collaboration = CollaborationTestFactory.create();
+
+		@Nested
+		class OnNonEmptyCollaborationList {
+
+			@Test
+			void shouldCallToModel() {
+				callAssembler();
+
+				verify(assembler).toModel(collaboration);
+			}
+
+			@Test
+			void shouldHaveEntityModel() {
+				var entityModel = ModelBuilder.fromEntity(collaboration).buildModel();
+				doReturn(entityModel).when(assembler).toModel(collaboration);
+
+				var collectionModel = callAssembler();
+
+				assertThat(collectionModel.getContent()).containsExactly(entityModel);
+			}
+
+			@Test
+			void shouldHaveSelfLink() {
+				var collectionModel = callAssembler();
+
+				assertThat(collectionModel.getLink(IanaLinkRelations.SELF_VALUE)).get().extracting(Link::getHref)
+						.isEqualTo(CollaborationController.PATH + "/" + VorgangHeaderTestFactory.ID + "/collaborations");
+			}
+
+			@Test
+			void shouldNotHaveCreateCollaborationRequestLink() {
+				var collectionModel = callAssembler();
+
+				assertThat(collectionModel.getLink(CollaborationModelAssembler.REL_CREATE_COLLABORATION_REQUEST)).isEmpty();
+			}
+
+			private CollectionModel<EntityModel<Collaboration>> callAssembler() {
+				return assembler.toCollectionModel(Stream.of(collaboration), VorgangHeaderTestFactory.ID);
+			}
+		}
+
+		@Nested
+		class OnEmptyCollaborationList {
+
+			@Mock
+			private Link createCollaborationRequestLink;
+
+			@BeforeEach
+			void mock() {
+				doReturn(createCollaborationRequestLink).when(assembler).buildCreateCollaborationRequestLink(VorgangHeaderTestFactory.ID);
+			}
+
+			@Test
+			void shouldHaveEmptyContent() {
+				var collectionModel = callAssembler();
+
+				assertThat(collectionModel.getContent()).isEmpty();
+			}
+
+			@Test
+			void shouldHaveSelfLink() {
+				var collectionModel = callAssembler();
+
+				assertThat(collectionModel.getLink(IanaLinkRelations.SELF_VALUE)).get().extracting(Link::getHref)
+						.isEqualTo(CollaborationController.PATH + "/" + VorgangHeaderTestFactory.ID + "/collaborations");
+			}
+
+			@Test
+			void shouldHaveCreateCollaborationRequestLink() {
+				var collectionModel = callAssembler();
+
+				assertThat(collectionModel.getLinks()).contains(createCollaborationRequestLink);
+			}
+
+			private CollectionModel<EntityModel<Collaboration>> callAssembler() {
+				return assembler.toCollectionModel(Stream.empty(), VorgangHeaderTestFactory.ID);
+			}
+		}
+	}
+
+	@Nested
+	class TestBuildCreateCollaborationRequestLink {
+
+		private final VorgangWithEingang vorgang = VorgangWithEingangTestFactory.create();
+
+		@BeforeEach
+		void mockVorgangController() {
+			when(vorgangController.getVorgang(VorgangHeaderTestFactory.ID)).thenReturn(vorgang);
+		}
+
+		@Test
+		void shouldCallVorgangController() {
+			callAssembler();
+
+			verify(vorgangController).getVorgang(VorgangHeaderTestFactory.ID);
+		}
+
+		@Test
+		void shouldHaveHrefToCreateCommand() {
+			var expectedHref = UriTemplate.of(CommandByRelationController.COMMAND_BY_RELATION_PATH)
+					.expand(VorgangHeaderTestFactory.ID, VorgangHeaderTestFactory.ID, VorgangHeaderTestFactory.VERSION).toString();
+
+			var link = callAssembler();
+
+			assertThat(link).extracting(Link::getHref).isEqualTo(expectedHref);
+		}
+
+		@Test
+		void shouldHaveCreateCollaborationRequestRelation() {
+			var link = callAssembler();
+
+			assertThat(link).extracting(Link::getRel).isEqualTo(CollaborationModelAssembler.REL_CREATE_COLLABORATION_REQUEST);
+		}
+
+		private Link callAssembler() {
+			return assembler.buildCreateCollaborationRequestLink(VorgangHeaderTestFactory.ID);
+		}
+	}
+}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/CollaborationServiceTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/CollaborationServiceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..2659c7fce3f402080694a5b38cdd0fe11f3507f1
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/CollaborationServiceTest.java
@@ -0,0 +1,84 @@
+package de.ozgcloud.alfa.collaboration;
+
+import static org.assertj.core.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+import java.util.UUID;
+import java.util.stream.Stream;
+
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+
+class CollaborationServiceTest {
+
+	@InjectMocks
+	private CollaborationService service;
+
+	@Mock
+	private CollaborationRemoteService remoteService;
+
+	@Nested
+	class TestGetCollaborations {
+
+		private final String id = UUID.randomUUID().toString();
+
+		@Test
+		void shouldCallRemoteService() {
+			callService();
+
+			verify(remoteService).getCollaborations(id);
+		}
+
+		@Test
+		void shouldReturnCollaboration() {
+			var collaboration = CollaborationTestFactory.create();
+			when(remoteService.getCollaborations(id)).thenReturn(Stream.of(collaboration));
+
+			var returnedCollaboration = callService();
+
+			assertThat(returnedCollaboration).contains(collaboration);
+		}
+
+		private Stream<Collaboration> callService() {
+			return service.getCollaborations(id);
+		}
+	}
+
+	@Nested
+	class TestHasCollaboration {
+
+		private final String id = UUID.randomUUID().toString();
+
+		@Test
+		void shouldCallRemoteService() {
+			callService();
+
+			verify(remoteService).getCollaborations(id);
+		}
+
+		@Test
+		void shouldReturnTrue() {
+			var collaboration = CollaborationTestFactory.create();
+			when(remoteService.getCollaborations(id)).thenReturn(Stream.of(collaboration));
+
+			var hasCollaboration = callService();
+
+			assertThat(hasCollaboration).isTrue();
+		}
+
+		@Test
+		void shouldReturnFalse() {
+			when(remoteService.getCollaborations(id)).thenReturn(Stream.empty());
+
+			var hasCollaboration = callService();
+
+			assertThat(hasCollaboration).isFalse();
+		}
+
+		private boolean callService() {
+			return service.hasCollaboration(id);
+		}
+	}
+}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/CollaborationTestFactory.java b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/CollaborationTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..133acf57bb11cd6d048f2c578405f4ceadd4ae4b
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/CollaborationTestFactory.java
@@ -0,0 +1,30 @@
+package de.ozgcloud.alfa.collaboration;
+
+import java.util.UUID;
+
+import com.thedeanda.lorem.LoremIpsum;
+
+import de.ozgcloud.alfa.collaboration.Collaboration.CollaborationBuilder;
+
+public class CollaborationTestFactory {
+
+	public static final String VORGANG_ID = UUID.randomUUID().toString();
+	public static final String COLLABORATION_VORGANG_ID = UUID.randomUUID().toString();
+	public static final String TITEL = LoremIpsum.getInstance().getWords(7);
+	public static final String ANFRAGE = LoremIpsum.getInstance().getParagraphs(2, 5);
+	public static final String ZUSTAENDIGE_STELLE = OrganisationsEinheitTestFactory.ID;
+
+	public static Collaboration create() {
+		return createBuilder()
+				.build();
+	}
+
+	private static CollaborationBuilder createBuilder() {
+		return Collaboration.builder()
+				.vorgangId(VORGANG_ID)
+				.collaborationVorgangId(COLLABORATION_VORGANG_ID)
+				.titel(TITEL)
+				.anfrage(ANFRAGE)
+				.zustaendigeStelle(ZUSTAENDIGE_STELLE);
+	}
+}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/CollaborationVorgangProcessorITCase.java b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/CollaborationVorgangProcessorITCase.java
new file mode 100644
index 0000000000000000000000000000000000000000..fe189548817a2ec6f40b4eb9536d0e2f8cef3cdb
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/CollaborationVorgangProcessorITCase.java
@@ -0,0 +1,32 @@
+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.springframework.beans.factory.NoSuchBeanDefinitionException;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.ApplicationContext;
+
+class CollaborationVorgangProcessorITCase {
+
+	@SpringBootTest(properties = {"ozgcloud.feature.collaboration-enabled=true"})
+	@Nested
+	class OnFeatureEnabled {
+
+		@Test
+		void shouldExistInApplicationContext(ApplicationContext context) {
+			assertThat(context.getBean(CollaborationVorgangProcessor.class)).isNotNull();
+		}
+	}
+
+	@SpringBootTest
+	@Nested
+	class OnFeatureDisabled {
+
+		@Test
+		void shouldNotExistInApplicationContext(ApplicationContext context) {
+			assertThatThrownBy(() -> context.getBean(CollaborationVorgangProcessor.class)).isInstanceOf(NoSuchBeanDefinitionException.class);
+		}
+	}
+}
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
new file mode 100644
index 0000000000000000000000000000000000000000..8e28fca8d28c0752644af390b656228fef93ea26
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/CollaborationVorgangProcessorTest.java
@@ -0,0 +1,163 @@
+package de.ozgcloud.alfa.collaboration;
+
+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.Nested;
+import org.junit.jupiter.api.Test;
+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.web.util.UriComponentsBuilder;
+
+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;
+import de.ozgcloud.alfa.vorgang.VorgangWithEingang;
+import de.ozgcloud.alfa.vorgang.VorgangWithEingangTestFactory;
+
+class CollaborationVorgangProcessorTest {
+
+	@Spy
+	@InjectMocks
+	private CollaborationVorgangProcessor processor;
+
+	@Mock
+	private CollaborationService collaborationService;
+
+	@Mock
+	private CurrentUserService currentUserService;
+
+	private final UserProfileUrlProvider urlProvider = new UserProfileUrlProvider();
+
+	@Nested
+	class TestProcess {
+
+		@Nested
+		class OnNullVorgang {
+
+			@Test
+			void shouldNotAddLinksIfVorgangIsNull() {
+				var model = processor.process(EntityModelTestFactory.NULLABLE);
+
+				assertThat(model.hasLinks()).isFalse();
+			}
+		}
+
+		@Nested
+		class OnNotVerwaltungUserRole {
+
+			@BeforeEach
+			void mockUserService() {
+				when(currentUserService.hasRole(UserRole.VERWALTUNG_USER)).thenReturn(false);
+			}
+
+			@Test
+			void shouldNotAddLinks() {
+				var model = processor.process(EntityModel.of(VorgangWithEingangTestFactory.create()));
+
+				assertThat(model.hasLinks()).isFalse();
+			}
+
+		}
+
+		@Nested
+		class OnNonNullVorgangAndOnVerwaltungUserRole {
+
+			@BeforeEach
+			void prepareBuilder() {
+				initUserProfileUrlProvider(urlProvider);
+			}
+
+			@BeforeEach
+			void mockUserService() {
+				when(currentUserService.hasRole(UserRole.VERWALTUNG_USER)).thenReturn(true);
+			}
+
+			@Nested
+			class OnCollaborationPresent {
+
+				@BeforeEach
+				void setUpMock() {
+					when(collaborationService.hasCollaboration(VorgangHeaderTestFactory.ID)).thenReturn(true);
+				}
+
+				@Test
+				void shouldHaveTwoLinks() {
+					var model = callProcessor();
+
+					assertThat(model.getLinks()).hasSize(2);
+				}
+
+				@Test
+				void shouldNotAddSearchOrganisationsEinheitLink() {
+					var model = callProcessor();
+
+					assertThat(model.getLink(CollaborationVorgangProcessor.REL_SEARCH_ORGANISATIONS_EINHEIT)).isEmpty();
+				}
+
+				@Test
+				void shouldAddCollaborationsLink() {
+					var model = callProcessor();
+
+					assertThat(model.getLink(CollaborationVorgangProcessor.REL_COLLABORATIONS)).get()
+							.extracting(Link::getHref)
+							.isEqualTo(CollaborationController.PATH + "/" + VorgangHeaderTestFactory.ID + "/collaborations");
+				}
+			}
+
+			@Nested
+			class OnCollaborationsNotPresent {
+
+				@BeforeEach
+				void setUpMock() {
+					when(collaborationService.hasCollaboration(VorgangHeaderTestFactory.ID)).thenReturn(false);
+				}
+
+				@Test
+				void shouldHaveThreeLinks() {
+					var model = callProcessor();
+
+					assertThat(model.getLinks()).hasSize(3);
+
+				}
+
+				@Test
+				void shouldAddSearchOrganisationsEinheitLink() {
+					var expectedHref = UriComponentsBuilder.fromUriString(OrganisationsEinheitController.PATH)
+							.queryParam(OrganisationsEinheitController.SEARCH_BY_PARAM, "{" + OrganisationsEinheitController.SEARCH_BY_PARAM + "}")
+							.build().toString();
+
+					var model = callProcessor();
+
+					assertThat(model.getLink(CollaborationVorgangProcessor.REL_SEARCH_ORGANISATIONS_EINHEIT)).get()
+							.extracting(Link::getHref)
+							.isEqualTo(expectedHref);
+				}
+
+				@Test
+				void shouldAddCollaborationsLink() {
+					var expectedHref = UriComponentsBuilder.fromUriString(CollaborationController.PATH)
+							.pathSegment(VorgangHeaderTestFactory.ID, "collaborations")
+							.build().toString();
+
+					var model = callProcessor();
+
+					assertThat(model.getLink(CollaborationVorgangProcessor.REL_COLLABORATIONS)).get()
+							.extracting(Link::getHref)
+							.isEqualTo(expectedHref);
+				}
+			}
+
+			private EntityModel<VorgangWithEingang> callProcessor() {
+				return processor.process(EntityModel.of(VorgangWithEingangTestFactory.create()));
+			}
+		}
+	}
+}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/GrpcAnschriftTestFactory.java b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/GrpcAnschriftTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..8f06c7fdd95ab06bae9054f94a72a1cd45f6a47b
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/GrpcAnschriftTestFactory.java
@@ -0,0 +1,24 @@
+package de.ozgcloud.alfa.collaboration;
+
+import de.ozgcloud.zufi.grpc.organisationseinheit.GrpcAnschrift;
+import de.ozgcloud.zufi.grpc.organisationseinheit.GrpcAnschrift.Builder;
+
+public class GrpcAnschriftTestFactory {
+	public static final String STRASSE = AnschriftTestFactory.STRASSE;
+	public static final String HAUSNUMMER = AnschriftTestFactory.HAUSNUMMER;
+	public static final String PLZ = AnschriftTestFactory.PLZ;
+	public static final String ORT = AnschriftTestFactory.ORT;
+
+	public static GrpcAnschrift create() {
+		return createBuilder().build();
+	}
+
+	public static Builder createBuilder() {
+		return GrpcAnschrift.newBuilder()
+				.setStrasse(STRASSE)
+				.setHausnummer(HAUSNUMMER)
+				.setPlz(PLZ)
+				.setOrt(ORT);
+	}
+
+}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/GrpcOrganisationsEinheitGetRequestTestFactory.java b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/GrpcOrganisationsEinheitGetRequestTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..518acd646c25f50be9cdffffb43e412b8ccc4bea
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/GrpcOrganisationsEinheitGetRequestTestFactory.java
@@ -0,0 +1,19 @@
+package de.ozgcloud.alfa.collaboration;
+
+import java.util.UUID;
+
+import de.ozgcloud.zufi.grpc.organisationseinheit.GrpcOrganisationsEinheitGetRequest;
+
+class GrpcOrganisationsEinheitGetRequestTestFactory {
+
+	public static final String ID = UUID.randomUUID().toString();
+
+	public static GrpcOrganisationsEinheitGetRequest create() {
+		return createBuilder().build();
+	}
+
+	public static GrpcOrganisationsEinheitGetRequest.Builder createBuilder() {
+		return GrpcOrganisationsEinheitGetRequest.newBuilder().setId(ID);
+	}
+
+}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/GrpcOrganisationsEinheitGetResponseTestFactory.java b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/GrpcOrganisationsEinheitGetResponseTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..a1c5a313d04f5d631b84b13579b84cbbdd71fedd
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/GrpcOrganisationsEinheitGetResponseTestFactory.java
@@ -0,0 +1,18 @@
+package de.ozgcloud.alfa.collaboration;
+
+import de.ozgcloud.zufi.grpc.organisationseinheit.GrpcOrganisationsEinheit;
+import de.ozgcloud.zufi.grpc.organisationseinheit.GrpcOrganisationsEinheitGetResponse;
+
+class GrpcOrganisationsEinheitGetResponseTestFactory {
+
+	public static final GrpcOrganisationsEinheit GRPC_ORGANISATIONS_EINHEIT = GrpcOrganisationsEinheitTestFactory.create();
+
+	public static GrpcOrganisationsEinheitGetResponse create() {
+		return createBuilder().build();
+	}
+
+	public static GrpcOrganisationsEinheitGetResponse.Builder createBuilder() {
+		return GrpcOrganisationsEinheitGetResponse.newBuilder().setOrganisationsEinheit(GRPC_ORGANISATIONS_EINHEIT);
+	}
+
+}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/GrpcOrganisationsEinheitSearchResponseTestFactory.java b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/GrpcOrganisationsEinheitSearchResponseTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..34d6204cb5a1ea202f1fa9b7565f40d27b12ab12
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/GrpcOrganisationsEinheitSearchResponseTestFactory.java
@@ -0,0 +1,20 @@
+package de.ozgcloud.alfa.collaboration;
+
+import de.ozgcloud.zufi.grpc.organisationseinheit.GrpcOrganisationsEinheit;
+import de.ozgcloud.zufi.grpc.organisationseinheit.GrpcOrganisationsEinheitSearchResponse;
+import de.ozgcloud.zufi.grpc.organisationseinheit.GrpcOrganisationsEinheitSearchResponse.Builder;
+
+public class GrpcOrganisationsEinheitSearchResponseTestFactory {
+
+	public static final GrpcOrganisationsEinheit ORGANISATIONS_EINHEIT = GrpcOrganisationsEinheitTestFactory.create();
+
+	public static GrpcOrganisationsEinheitSearchResponse create() {
+		return createBuilder()
+				.build();
+	}
+
+	public static Builder createBuilder() {
+		return GrpcOrganisationsEinheitSearchResponse.newBuilder()
+				.addOrganisationsEinheiten(ORGANISATIONS_EINHEIT);
+	}
+}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/GrpcOrganisationsEinheitTestFactory.java b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/GrpcOrganisationsEinheitTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..7cb95a9e54f601044af15c30c06e783fdf50a09e
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/GrpcOrganisationsEinheitTestFactory.java
@@ -0,0 +1,44 @@
+package de.ozgcloud.alfa.collaboration;
+
+import com.thedeanda.lorem.LoremIpsum;
+
+import de.ozgcloud.zufi.grpc.organisationseinheit.GrpcAnschrift;
+import de.ozgcloud.zufi.grpc.organisationseinheit.GrpcOrganisationsEinheit;
+import de.ozgcloud.zufi.grpc.organisationseinheit.GrpcOrganisationsEinheit.Builder;
+import de.ozgcloud.zufi.grpc.organisationseinheit.GrpcXzufiId;
+import de.ozgcloud.zufi.grpc.organisationseinheit.GrpcZustaendigkeit;
+
+public class GrpcOrganisationsEinheitTestFactory {
+	public static final String ID = OrganisationsEinheitHeaderTestFactory.ID;
+	public static final GrpcXzufiId XZUFI_ID = GrpcXzufiIdTestFactory.create();
+	public static final String NAME = OrganisationsEinheitHeaderTestFactory.NAME;
+	public static final String SYNONYME = LoremIpsum.getInstance().getWords(5);
+	public static final String VORGANG_MANAGER_ADDRESS = LoremIpsum.getInstance().getUrl();
+	public static final GrpcAnschrift ANSCHRIFT = GrpcAnschriftTestFactory.create();
+	public static final GrpcZustaendigkeit ZUSTAENDIGKEIT = GrpcZustaendigkeitTestFactory.create();
+
+	public static GrpcOrganisationsEinheit create() {
+		return createBuilder().build();
+	}
+
+	public static GrpcOrganisationsEinheit createWithoutSynonyme() {
+		return createBuilderWithoutSynonyme()
+				.build();
+	}
+
+	public static Builder createBuilder() {
+		return createBuilderWithoutSynonyme()
+				.setSynonyme(SYNONYME);
+	}
+
+	public static Builder createBuilderWithoutSynonyme() {
+		return GrpcOrganisationsEinheit.newBuilder()
+				.setId(ID)
+				.setName(NAME)
+				.setAnschrift(ANSCHRIFT)
+				.setVorgangManagerAddress(VORGANG_MANAGER_ADDRESS)
+				.addZustaendigkeiten(ZUSTAENDIGKEIT)
+				.setXzufiId(XZUFI_ID);
+	}
+
+}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/GrpcXzufiIdTestFactory.java b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/GrpcXzufiIdTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..5ed243a1e9fc69b34c7947487c98af3061094153
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/GrpcXzufiIdTestFactory.java
@@ -0,0 +1,23 @@
+package de.ozgcloud.alfa.collaboration;
+
+import java.util.UUID;
+
+import de.ozgcloud.zufi.grpc.organisationseinheit.GrpcXzufiId;
+import de.ozgcloud.zufi.grpc.organisationseinheit.GrpcXzufiId.Builder;
+
+public class GrpcXzufiIdTestFactory {
+	public static final String ORGANISATIONS_EINHEIT_ID = UUID.randomUUID().toString();
+	public static final String SCHEME_AGENCY_ID = UUID.randomUUID().toString();
+
+	public static GrpcXzufiId create() {
+		return createBuilder(ORGANISATIONS_EINHEIT_ID, SCHEME_AGENCY_ID).build();
+	}
+
+	public static GrpcXzufiId create(String id, String schemeAgencyId) {
+		return createBuilder(id, schemeAgencyId).build();
+	}
+
+	public static Builder createBuilder(String id, String schemeAgencyId) {
+		return GrpcXzufiId.newBuilder().setId(id).setSchemeAgencyId(schemeAgencyId);
+	}
+}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/GrpcZustaendigkeitTestFactory.java b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/GrpcZustaendigkeitTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..f3d14432adde69cdbf395ed58bc988befdbd0238
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/GrpcZustaendigkeitTestFactory.java
@@ -0,0 +1,22 @@
+package de.ozgcloud.alfa.collaboration;
+
+import java.util.UUID;
+
+import de.ozgcloud.zufi.grpc.organisationseinheit.GrpcXzufiId;
+import de.ozgcloud.zufi.grpc.organisationseinheit.GrpcZustaendigkeit;
+import de.ozgcloud.zufi.grpc.organisationseinheit.GrpcZustaendigkeit.Builder;
+
+public class GrpcZustaendigkeitTestFactory {
+	public static final GrpcXzufiId ID = GrpcXzufiIdTestFactory.create();
+	public static final String GEBIET_ID = UUID.randomUUID().toString();
+
+	public static GrpcZustaendigkeit create() {
+		return createBuilder().build();
+	}
+
+	private static Builder createBuilder() {
+		return GrpcZustaendigkeit.newBuilder()
+				.setXzufiId(ID)
+				.setGebietId(GEBIET_ID);
+	}
+}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitControllerTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitControllerTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..1edb729801079868c6a347d885ff88d9e659bec3
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitControllerTest.java
@@ -0,0 +1,236 @@
+package de.ozgcloud.alfa.collaboration;
+
+import static org.mockito.Mockito.*;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
+
+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.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.springframework.hateoas.CollectionModel;
+import org.springframework.hateoas.EntityModel;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.ResultActions;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+
+import com.thedeanda.lorem.LoremIpsum;
+
+import lombok.SneakyThrows;
+
+class OrganisationsEinheitControllerTest {
+
+	@InjectMocks
+	private OrganisationsEinheitController controller;
+
+	@Mock
+	private OrganisationsEinheitService service;
+
+	@Mock
+	private OrganisationsEinheitModelAssembler assembler;
+
+	@Mock
+	private OrganisationsEinheitHeaderModelAssembler headerModelAssembler;
+
+	private MockMvc mockMvc;
+
+	@BeforeEach
+	void initTest() {
+		mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
+	}
+
+	@Nested
+	class TestGetById {
+
+		private final OrganisationsEinheit organisationsEinheit = OrganisationsEinheitTestFactory.create();
+
+		@BeforeEach
+		void mockService() {
+			when(service.getById(OrganisationsEinheitTestFactory.ID)).thenReturn(organisationsEinheit);
+		}
+
+		@SneakyThrows
+		@Test
+		void shouldCallOrganisationsEinheitService() {
+			performRequest();
+
+			verify(service).getById(OrganisationsEinheitTestFactory.ID);
+		}
+
+		@Test
+		void shouldCallAssembler() {
+			performRequest();
+
+			verify(assembler).toModel(organisationsEinheit);
+		}
+
+		@SneakyThrows
+		@Test
+		void shouldReturnStatusOk() {
+			when(assembler.toModel(organisationsEinheit)).thenReturn(EntityModel.of(organisationsEinheit));
+
+			var response = performRequest();
+
+			response.andExpect(status().isOk());
+		}
+
+		@SneakyThrows
+		@Test
+		void shouldHaveOrganisationsEinheitId() {
+			when(assembler.toModel(organisationsEinheit)).thenReturn(EntityModel.of(organisationsEinheit));
+
+			var response = performRequest();
+
+			response.andExpect(jsonPath("$.id").value(OrganisationsEinheitTestFactory.ID));
+		}
+
+		@SneakyThrows
+		@Test
+		void shouldHaveOrganisationsEinheitXzufiId() {
+			when(assembler.toModel(organisationsEinheit)).thenReturn(EntityModel.of(organisationsEinheit));
+
+			var response = performRequest();
+
+			response.andExpect(jsonPath("$.xzufiId.id").value(XzufiIdTestFactory.ID));
+		}
+
+		@SneakyThrows
+		@Test
+		void shouldHaveOrganisationsEinheitXzufiSchemeAgencyId() {
+			when(assembler.toModel(organisationsEinheit)).thenReturn(EntityModel.of(organisationsEinheit));
+
+			var response = performRequest();
+
+			response.andExpect(jsonPath("$.xzufiId.schemeAgencyId").value(XzufiIdTestFactory.SCHEME_AGENCY_ID));
+		}
+
+		@SneakyThrows
+		private ResultActions performRequest() {
+			return mockMvc.perform(get(OrganisationsEinheitController.PATH + "/" + OrganisationsEinheitTestFactory.ID));
+		}
+	}
+
+	@Nested
+	class TestSearch {
+
+		private final OrganisationsEinheitHeader organisationsEinheitHeader1 = OrganisationsEinheitHeaderTestFactory.create();
+		private final OrganisationsEinheitHeader organisationsEinheitHeader2 = OrganisationsEinheitHeaderTestFactory.createBuilder()
+				.name(LoremIpsum.getInstance().getName())
+				.build();
+		private final String searchBy = LoremIpsum.getInstance().getWords(5);
+		private final List<OrganisationsEinheitHeader> organisationsEinheitHeaders = List.of(organisationsEinheitHeader1,
+				organisationsEinheitHeader2);
+
+		@BeforeEach
+		void setUpMocks() {
+			when(service.searchOrganisationsEinheiten(searchBy)).thenReturn(Stream.of(organisationsEinheitHeader1, organisationsEinheitHeader2));
+			when(headerModelAssembler.toCollectionModel(organisationsEinheitHeaders))
+					.thenReturn(
+							CollectionModel.of(List.of(EntityModel.of(organisationsEinheitHeader1), EntityModel.of(organisationsEinheitHeader2))));
+		}
+
+		@Test
+		void shouldCallService() {
+			performRequest();
+
+			verify(service).searchOrganisationsEinheiten(searchBy);
+		}
+
+		@Test
+		void shouldCallModelAssembler() {
+			performRequest();
+
+			verify(headerModelAssembler).toCollectionModel(organisationsEinheitHeaders);
+		}
+
+		@SneakyThrows
+		@Test
+		void shouldReturnStatusOk() {
+			var response = performRequest();
+
+			response.andExpect(status().isOk());
+		}
+
+		@Test
+		@SneakyThrows
+		void shouldHaveFirstOrganisationsEinheitName() {
+			var response = performRequest();
+			response.andExpect(jsonPath("$.content[0].name").value(organisationsEinheitHeader1.getName()));
+		}
+
+		@Test
+		@SneakyThrows
+		void shouldHaveFirstOrganisationsEinheitStrasse() {
+			var response = performRequest();
+			response.andExpect(jsonPath("$.content[0].anschrift.strasse").value(organisationsEinheitHeader1.getAnschrift().getStrasse()));
+		}
+
+		@Test
+		@SneakyThrows
+		void shouldHaveFirstOrganisationsEinheitHausnummer() {
+			var response = performRequest();
+			response.andExpect(jsonPath("$.content[0].anschrift.hausnummer").value(organisationsEinheitHeader1.getAnschrift().getHausnummer()));
+		}
+
+		@Test
+		@SneakyThrows
+		void shouldHaveFirstOrganisationsEinheitPlz() {
+			var response = performRequest();
+			response.andExpect(jsonPath("$.content[0].anschrift.plz").value(organisationsEinheitHeader1.getAnschrift().getPlz()));
+		}
+
+		@Test
+		@SneakyThrows
+		void shouldHaveFirstOrganisationsEinheitOrt() {
+			var response = performRequest();
+			response.andExpect(jsonPath("$.content[0].anschrift.ort").value(organisationsEinheitHeader1.getAnschrift().getOrt()));
+		}
+
+		@Test
+		@SneakyThrows
+		void shouldHaveSecondOrganisationsEinheitName() {
+			var response = performRequest();
+			response.andExpect(jsonPath("$.content[1].name").value(organisationsEinheitHeader2.getName()));
+		}
+
+		@Test
+		@SneakyThrows
+		void shouldHaveSecondOrganisationsEinheitStrasse() {
+			var response = performRequest();
+			response.andExpect(jsonPath("$.content[1].anschrift.strasse").value(organisationsEinheitHeader2.getAnschrift().getStrasse()));
+		}
+
+		@Test
+		@SneakyThrows
+		void shouldHaveSecondOrganisationsEinheitHausnummer() {
+			var response = performRequest();
+			response.andExpect(jsonPath("$.content[1].anschrift.hausnummer").value(organisationsEinheitHeader2.getAnschrift().getHausnummer()));
+		}
+
+		@Test
+		@SneakyThrows
+		void shouldHaveSecondOrganisationsEinheitPlz() {
+			var response = performRequest();
+			response.andExpect(jsonPath("$.content[1].anschrift.plz").value(organisationsEinheitHeader2.getAnschrift().getPlz()));
+		}
+
+		@Test
+		@SneakyThrows
+		void shouldHaveSecondOrganisationsEinheitOrt() {
+			var response = performRequest();
+			response.andExpect(jsonPath("$.content[1].anschrift.ort").value(organisationsEinheitHeader2.getAnschrift().getOrt()));
+		}
+
+		@SneakyThrows
+		private ResultActions performRequest() {
+			return mockMvc.perform(get(OrganisationsEinheitController.PATH)
+					.param("searchBy", searchBy)).andExpect(status().isOk());
+
+		}
+	}
+
+}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitHeaderMapperTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitHeaderMapperTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..a259f026c0a25df609a79cff423c8e51b0f3a339
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitHeaderMapperTest.java
@@ -0,0 +1,23 @@
+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.mapstruct.factory.Mappers;
+
+class OrganisationsEinheitHeaderMapperTest {
+
+	private final OrganisationsEinheitHeaderMapper mapper = Mappers.getMapper(OrganisationsEinheitHeaderMapper.class);
+
+	@Nested
+	class TestFromGrpc {
+
+		@Test
+		void shouldMap() {
+			var organisationsEinheitHeader = mapper.fromGrpc(GrpcOrganisationsEinheitTestFactory.create());
+
+			assertThat(organisationsEinheitHeader).usingRecursiveComparison().isEqualTo(OrganisationsEinheitHeaderTestFactory.create());
+		}
+	}
+}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitHeaderModelAssemblerTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitHeaderModelAssemblerTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..a876719e5ea939789c054347b8bdc878115a301b
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitHeaderModelAssemblerTest.java
@@ -0,0 +1,71 @@
+package de.ozgcloud.alfa.collaboration;
+
+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.Spy;
+import org.springframework.hateoas.CollectionModel;
+import org.springframework.hateoas.EntityModel;
+import org.springframework.hateoas.IanaLinkRelations;
+import org.springframework.hateoas.Link;
+
+class OrganisationsEinheitHeaderModelAssemblerTest {
+
+	@Spy
+	private OrganisationsEinheitHeaderModelAssembler assembler;
+
+	@Nested
+	class TestToModel {
+
+		@Test
+		void shouldHaveSelfLink() {
+			var model = assembler.toModel(OrganisationsEinheitHeaderTestFactory.create());
+
+			assertHaveSelfLink(model);
+		}
+
+		private void assertHaveSelfLink(EntityModel<OrganisationsEinheitHeader> model) {
+			assertThat(model.getLink(IanaLinkRelations.SELF_VALUE)).isPresent().get().extracting(Link::getHref)
+					.isEqualTo(OrganisationsEinheitController.PATH + "/" + OrganisationsEinheitHeaderTestFactory.ID);
+		}
+	}
+
+	@Nested
+	class TestToCollectionModel {
+
+		private OrganisationsEinheitHeader organisationsEinheitHeader = OrganisationsEinheitHeaderTestFactory.create();
+
+		@Test
+		void shouldCallToModel() {
+			callAssembler();
+
+			verify(assembler).toModel(organisationsEinheitHeader);
+		}
+
+		@Test
+		void shouldHaveSelfLink() {
+			var model = callAssembler();
+
+			assertThat(model.getLink(IanaLinkRelations.SELF_VALUE)).isPresent().get().extracting(Link::getHref)
+					.isEqualTo(OrganisationsEinheitController.PATH);
+		}
+
+		@Test
+		void shouldContainEntityModel() {
+			var entityModel = EntityModel.of(organisationsEinheitHeader);
+			doReturn(entityModel).when(assembler).toModel(organisationsEinheitHeader);
+
+			var model = callAssembler();
+
+			assertThat(model).containsExactly(entityModel);
+		}
+
+		private CollectionModel<EntityModel<OrganisationsEinheitHeader>> callAssembler() {
+			return assembler.toCollectionModel(List.of(organisationsEinheitHeader));
+		}
+	}
+}
diff --git a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-page-container/wiedervorlage-page/wiedervorlage-breadcrumb-container/wiedervorlage-breadcrumb/wiedervorlage-breadcrumb.component.scss b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitHeaderTestFactory.java
similarity index 53%
rename from alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-page-container/wiedervorlage-page/wiedervorlage-breadcrumb-container/wiedervorlage-breadcrumb/wiedervorlage-breadcrumb.component.scss
rename to alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitHeaderTestFactory.java
index aec918f0e6ec45b7cb161e4fd7a59f18b7d9a4c5..4eef705ebdb94c9d108aab2312d070d6aa63f2ce 100644
--- a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-page-container/wiedervorlage-page/wiedervorlage-breadcrumb-container/wiedervorlage-breadcrumb/wiedervorlage-breadcrumb.component.scss
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitHeaderTestFactory.java
@@ -1,5 +1,5 @@
-/**
- * Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den
+/*
+ * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den
  * Ministerpräsidenten des Landes Schleswig-Holstein
  * Staatskanzlei
  * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
@@ -21,26 +21,27 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-@import 'variables';
+package de.ozgcloud.alfa.collaboration;
 
-:host {
-  display: block;
-  font-size: 18px;
-  margin: 0 -4px 24px -4px;
+import java.util.UUID;
 
-  ::ng-deep span {
-    margin: 0 4px;
-  }
+import com.thedeanda.lorem.LoremIpsum;
 
-  a {
-    text-decoration: none;
-    outline: 0;
-    margin: -3px;
-    padding: 3px;
+import de.ozgcloud.alfa.collaboration.OrganisationsEinheitHeader.OrganisationsEinheitHeaderBuilder;;
 
-    &:focus {
-      border-radius: 12px;
-      background-color: rgba(#777, 0.16);
-    }
-  }
+public class OrganisationsEinheitHeaderTestFactory {
+	public static final String ID = UUID.randomUUID().toString();
+	public static final String NAME = LoremIpsum.getInstance().getName();
+	public static final Anschrift ANSCHRIFT = AnschriftTestFactory.create();
+
+	public static OrganisationsEinheitHeader create() {
+		return createBuilder().build();
+	}
+
+	public static OrganisationsEinheitHeaderBuilder createBuilder() {
+		return OrganisationsEinheitHeader.builder()
+				.id(ID)
+				.name(NAME)
+				.anschrift(ANSCHRIFT);
+	}
 }
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitMapperTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitMapperTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..1dcce17665e45327791fdecbe19ea3b4eaf4be01
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitMapperTest.java
@@ -0,0 +1,23 @@
+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.mapstruct.factory.Mappers;
+
+class OrganisationsEinheitMapperTest {
+
+	private final OrganisationsEinheitMapper mapper = Mappers.getMapper(OrganisationsEinheitMapper.class);
+
+	@Nested
+	class TestFromGrpc {
+
+		@Test
+		void shouldMap() {
+			var organisationsEinheit = mapper.fromGrpc(GrpcOrganisationsEinheitTestFactory.create());
+
+			assertThat(organisationsEinheit).usingRecursiveComparison().isEqualTo(OrganisationsEinheitTestFactory.create());
+		}
+	}
+}
\ No newline at end of file
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitModelAssemblerTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitModelAssemblerTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..fba797d96ceb4bfb9d9ea85b39e0600c9b10b6dd
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitModelAssemblerTest.java
@@ -0,0 +1,32 @@
+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.Spy;
+import org.springframework.hateoas.IanaLinkRelations;
+import org.springframework.hateoas.Link;
+import org.springframework.web.util.UriComponentsBuilder;
+
+class OrganisationsEinheitModelAssemblerTest {
+
+	@Spy
+	private OrganisationsEinheitModelAssembler assembler;
+
+	@Nested
+	class TestToModel {
+
+		@Test
+		void shouldHaveSelfLink() {
+			var expectedHref = UriComponentsBuilder.fromUriString(OrganisationsEinheitController.PATH)
+					.pathSegment(OrganisationsEinheitTestFactory.ID)
+					.build().toString();
+
+			var model = assembler.toModel(OrganisationsEinheitTestFactory.create());
+
+			assertThat(model.getLink(IanaLinkRelations.SELF_VALUE)).isPresent().get().extracting(Link::getHref)
+					.isEqualTo(expectedHref);
+		}
+	}
+}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitRemoteServiceTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitRemoteServiceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..b8c151afaa513c5026966501071c4719c60d21fe
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitRemoteServiceTest.java
@@ -0,0 +1,172 @@
+package de.ozgcloud.alfa.collaboration;
+
+import static org.assertj.core.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.*;
+
+import java.util.stream.Stream;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentMatcher;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Spy;
+
+import com.thedeanda.lorem.LoremIpsum;
+
+import de.ozgcloud.zufi.grpc.organisationseinheit.GrpcOrganisationsEinheitGetRequest;
+import de.ozgcloud.zufi.grpc.organisationseinheit.GrpcOrganisationsEinheitGetResponse;
+import de.ozgcloud.zufi.grpc.organisationseinheit.GrpcOrganisationsEinheitSearchRequest;
+import de.ozgcloud.zufi.grpc.organisationseinheit.GrpcOrganisationsEinheitSearchResponse;
+import de.ozgcloud.zufi.grpc.organisationseinheit.OrganisationsEinheitServiceGrpc.OrganisationsEinheitServiceBlockingStub;
+
+class OrganisationsEinheitRemoteServiceTest {
+
+	@Spy
+	@InjectMocks
+	private OrganisationsEinheitRemoteService service;
+
+	@Mock
+	private OrganisationsEinheitServiceBlockingStub serviceStub;
+
+	@Mock
+	private OrganisationsEinheitHeaderMapper organisationsEinheitHeaderMapper;
+	@Mock
+	private OrganisationsEinheitMapper organisationsEinheitMapper;
+
+	@Nested
+	class TestSearch {
+
+		private final String searchBy = LoremIpsum.getInstance().getWords(5);
+		private final GrpcOrganisationsEinheitSearchResponse grpcOrganisationsEinheitSearchResponse = GrpcOrganisationsEinheitSearchResponseTestFactory
+				.create();
+
+		@BeforeEach
+		void setUpMocks() {
+			when(serviceStub.search(argThat(requestContainsSearchBy()))).thenReturn(grpcOrganisationsEinheitSearchResponse);
+		}
+
+		@Test
+		void shouldCallGrpcStub() {
+			callService();
+
+			verify(serviceStub).search(argThat(requestContainsSearchBy()));
+		}
+
+		@Test
+		void shouldCallMapper() {
+			callService().toList();
+
+			verify(organisationsEinheitHeaderMapper).fromGrpc(GrpcOrganisationsEinheitSearchResponseTestFactory.ORGANISATIONS_EINHEIT);
+		}
+
+		@Test
+		void shouldReturnMappedOrganisationsEinheitHeader() {
+			var organisationsEinheitHeader = OrganisationsEinheitHeaderTestFactory.create();
+			when(organisationsEinheitHeaderMapper.fromGrpc(GrpcOrganisationsEinheitSearchResponseTestFactory.ORGANISATIONS_EINHEIT)).thenReturn(
+					organisationsEinheitHeader);
+
+			var organisationsEinheitHeaders = callService();
+
+			assertThat(organisationsEinheitHeaders).containsExactly(organisationsEinheitHeader);
+		}
+
+		private Stream<OrganisationsEinheitHeader> callService() {
+			return service.search(searchBy);
+		}
+
+		private ArgumentMatcher<GrpcOrganisationsEinheitSearchRequest> requestContainsSearchBy() {
+			return request -> request.getSearchBy().equals(searchBy);
+		}
+	}
+
+	@Nested
+	class TestGetById {
+
+		private final GrpcOrganisationsEinheitGetRequest request = GrpcOrganisationsEinheitGetRequestTestFactory.create();
+		private final GrpcOrganisationsEinheitGetResponse response = GrpcOrganisationsEinheitGetResponseTestFactory.create();
+		private final OrganisationsEinheit organisationsEinheit = OrganisationsEinheitTestFactory.create();
+
+		@BeforeEach
+		void setUp() {
+			doReturn(request).when(service).buildGetByIdRequest(OrganisationsEinheitTestFactory.ID);
+			when(serviceStub.getById(request)).thenReturn(response);
+			doReturn(organisationsEinheit).when(service).getOrganisationsEinheitFromGetByIdResponse(response);
+		}
+
+		@Test
+		void shouldBuildRequest() {
+			callService();
+
+			verify(service).buildGetByIdRequest(OrganisationsEinheitTestFactory.ID);
+		}
+
+		@Test
+		void shouldCallGrpcStub() {
+			callService();
+
+			verify(serviceStub).getById(request);
+		}
+
+		@Test
+		void shouldBuildResponse() {
+			callService();
+
+			verify(service).getOrganisationsEinheitFromGetByIdResponse(response);
+		}
+
+		@Test
+		void shouldReturnOrganisationsEinheit() {
+			var get = service.getById(OrganisationsEinheitTestFactory.ID);
+
+			assertThat(get).isEqualTo(organisationsEinheit);
+		}
+
+		private OrganisationsEinheit callService() {
+			return service.getById(OrganisationsEinheitTestFactory.ID);
+		}
+	}
+
+	@Nested
+	class TestBuildGetByIdRequest {
+
+		@Test
+		void shouldHaveId() {
+			var request = service.buildGetByIdRequest(OrganisationsEinheitTestFactory.ID);
+
+			assertThat(request.getId()).isEqualTo(OrganisationsEinheitTestFactory.ID);
+		}
+	}
+
+	@Nested
+	class TestGetOrganisationsEinheitFromGetByIdResponse {
+
+		private final GrpcOrganisationsEinheitGetResponse response = GrpcOrganisationsEinheitGetResponseTestFactory.create();
+		private final OrganisationsEinheit organisationsEinheit = OrganisationsEinheitTestFactory.create();
+
+		@BeforeEach
+		void setUp() {
+			when(organisationsEinheitMapper.fromGrpc(response.getOrganisationsEinheit())).thenReturn(organisationsEinheit);
+		}
+
+		@Test
+		void shouldCallMapper() {
+			callService();
+
+			verify(organisationsEinheitMapper).fromGrpc(response.getOrganisationsEinheit());
+		}
+
+		@Test
+		void shouldReturnOrgnisationsEinheit() {
+			var built = callService();
+
+			assertThat(built).isEqualTo(organisationsEinheit);
+		}
+
+		private OrganisationsEinheit callService() {
+			return service.getOrganisationsEinheitFromGetByIdResponse(response);
+		}
+	}
+}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitServiceTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitServiceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..a574a5e4aa0b7f3bbc3b0f4d90497d68d98b7b00
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitServiceTest.java
@@ -0,0 +1,71 @@
+package de.ozgcloud.alfa.collaboration;
+
+import static org.assertj.core.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+import java.util.stream.Stream;
+
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+
+import com.thedeanda.lorem.LoremIpsum;
+
+class OrganisationsEinheitServiceTest {
+
+	@InjectMocks
+	private OrganisationsEinheitService service;
+
+	@Mock
+	private OrganisationsEinheitRemoteService remoteService;
+
+	@Nested
+	class TestGetById {
+
+		@Test
+		void shouldCallRemoteService() {
+			service.getById(OrganisationsEinheitTestFactory.ID);
+
+			verify(remoteService).getById(OrganisationsEinheitTestFactory.ID);
+		}
+
+		@Test
+		void shouldReturnOrganisationsEinheit() {
+			var organisationsEinheit = OrganisationsEinheitTestFactory.create();
+			when(remoteService.getById(OrganisationsEinheitTestFactory.ID)).thenReturn(organisationsEinheit);
+
+			var returnedOrganisationsEinheit = service.getById(OrganisationsEinheitTestFactory.ID);
+
+			assertThat(returnedOrganisationsEinheit).isEqualTo(organisationsEinheit);
+		}
+	}
+
+	@Nested
+	class TestSearchOrganisationsEinheiten {
+
+		private final String searchBy = LoremIpsum.getInstance().getWords(5);
+
+		@Test
+		void shouldCallRemoteService() {
+			callService();
+
+			verify(remoteService).search(searchBy);
+		}
+
+		@Test
+		void shouldReturnOrganisationsEinheiten() {
+			var organisationsEinheitHeader = OrganisationsEinheitHeaderTestFactory.create();
+			when(remoteService.search(searchBy)).thenReturn(Stream.of(organisationsEinheitHeader));
+
+			var organisationsEinheitHeaders = callService();
+
+			assertThat(organisationsEinheitHeaders).containsExactly(organisationsEinheitHeader);
+		}
+
+		private Stream<OrganisationsEinheitHeader> callService() {
+			return service.searchOrganisationsEinheiten(searchBy);
+		}
+	}
+
+}
diff --git a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-in-postfach-breadcrumb-container/vorgang-in-postfach-breadcrumb/vorgang-in-postfach-breadcrumb.component.ts b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitTestFactory.java
similarity index 59%
rename from alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-in-postfach-breadcrumb-container/vorgang-in-postfach-breadcrumb/vorgang-in-postfach-breadcrumb.component.ts
rename to alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitTestFactory.java
index 0268ce2c96d75db36678288fd07fd6022af3b069..59c6f03c06961983f4eefbe169474118e11b1087 100644
--- a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-in-postfach-breadcrumb-container/vorgang-in-postfach-breadcrumb/vorgang-in-postfach-breadcrumb.component.ts
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitTestFactory.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den
+ * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den
  * Ministerpräsidenten des Landes Schleswig-Holstein
  * Staatskanzlei
  * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
@@ -21,15 +21,22 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-import { Component, Input } from '@angular/core';
-import { StateResource } from '@alfa-client/tech-shared';
-import { VorgangWithEingangResource } from '@alfa-client/vorgang-shared';
+package de.ozgcloud.alfa.collaboration;
 
-@Component({
-  selector: 'alfa-vorgang-in-postfach-breadcrumb',
-  templateUrl: './vorgang-in-postfach-breadcrumb.component.html',
-  styleUrls: ['./vorgang-in-postfach-breadcrumb.component.scss'],
-})
-export class VorgangInPostfachBreadcrumbComponent {
-  @Input() vorgangStateResource: StateResource<VorgangWithEingangResource>;
+import de.ozgcloud.alfa.collaboration.OrganisationsEinheit.OrganisationsEinheitBuilder;
+
+public class OrganisationsEinheitTestFactory {
+
+	public static final String ID = OrganisationsEinheitHeaderTestFactory.ID;
+	public static final XzufiId XZUFI_ID = XzufiIdTestFactory.create();
+
+	public static OrganisationsEinheit create() {
+		return createBuilder().build();
+	}
+
+	public static OrganisationsEinheitBuilder createBuilder() {
+		return OrganisationsEinheit.builder()
+				.id(ID)
+				.xzufiId(XZUFI_ID);
+	}
 }
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/XzufiIdTestFactory.java b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/XzufiIdTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..49ddf54180fa8074dbc4867fb3b16110797f277a
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/XzufiIdTestFactory.java
@@ -0,0 +1,17 @@
+package de.ozgcloud.alfa.collaboration;
+
+public class XzufiIdTestFactory {
+
+	public static final String ID = GrpcXzufiIdTestFactory.ORGANISATIONS_EINHEIT_ID;
+	public static final String SCHEME_AGENCY_ID = GrpcXzufiIdTestFactory.SCHEME_AGENCY_ID;
+
+	public static XzufiId create() {
+		return createBuilder().build();
+	}
+
+	public static XzufiId.XzufiIdBuilder createBuilder() {
+		return XzufiId.builder()
+				.id(ID)
+				.schemeAgencyId(SCHEME_AGENCY_ID);
+	}
+}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/common/EntityModelTestFactory.java b/alfa-service/src/test/java/de/ozgcloud/alfa/common/EntityModelTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..e280a99cb43da4647f9a8ebcb9cbbd753f80dee3
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/common/EntityModelTestFactory.java
@@ -0,0 +1,20 @@
+package de.ozgcloud.alfa.common;
+
+import org.springframework.hateoas.EntityModel;
+
+import de.ozgcloud.alfa.vorgang.VorgangWithEingang;
+import lombok.NoArgsConstructor;
+
+public class EntityModelTestFactory {
+
+	public static final NullableEntityModel NULLABLE = createNullable();
+
+	private static NullableEntityModel createNullable() {
+		return new NullableEntityModel();
+	}
+
+	@NoArgsConstructor
+	private static class NullableEntityModel extends EntityModel<VorgangWithEingang> {
+
+	}
+}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/common/binaryfile/BinaryFileControllerITCase.java b/alfa-service/src/test/java/de/ozgcloud/alfa/common/binaryfile/BinaryFileControllerITCase.java
index 16cd0b895439464f3feba0aeda52642d63985cc4..18ddf8ce29170a549e2bd63d0c080a5c6ebd3451 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/common/binaryfile/BinaryFileControllerITCase.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/common/binaryfile/BinaryFileControllerITCase.java
@@ -122,7 +122,7 @@ class BinaryFileControllerITCase {
 
 			void setTokenToSecuriyContext(String token) throws Exception {
 				mockMvc.perform(get(DownloadTokenController.DOWNLOAD_TOKEN_PATH + "?" + DownloadTokenController.PARAM_TOKEN + "=" + token)
-								.with(csrf()))
+						.with(csrf()))
 						.andExpect(status().isOk());
 			}
 		}
@@ -168,8 +168,8 @@ class BinaryFileControllerITCase {
 			@Test
 			void shouldReturnValidationMessage() throws Exception {
 				performRequest(createFile(MediaType.TEXT_PLAIN)).andExpect(status().isUnprocessableEntity())
-						.andExpect(jsonPath("$.issues.length()").value(1))
-						.andExpect(jsonPath("$.issues.[0].messageCode").value(ValidationMessageCodes.FIELD_FILE_CONTENT_TYPE_INVALID));
+						.andExpect(jsonPath("$.invalidParams.length()").value(1))
+						.andExpect(jsonPath("$.invalidParams[0].reason").value(ValidationMessageCodes.FIELD_FILE_CONTENT_TYPE_INVALID));
 			}
 
 			@Test
@@ -183,7 +183,7 @@ class BinaryFileControllerITCase {
 				return mockMvc.perform(multipart(
 						String.format("%s/%s/%s/file", BinaryFileController.PATH, VorgangHeaderTestFactory.ID,
 								UploadBinaryFileTestFactory.FIELD)).file(
-						file).with(csrf()));
+										file).with(csrf()));
 			}
 
 			private MockMultipartFile createFile(MediaType contentType) {
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/common/binaryfile/BinaryFileITCase.java b/alfa-service/src/test/java/de/ozgcloud/alfa/common/binaryfile/BinaryFileITCase.java
index dcc9f9afcf7b622d9ac9e5d2f12a1a60b3bb34c2..6ab03aafe02d6aa07594f3622255b66b47e107d5 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/common/binaryfile/BinaryFileITCase.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/common/binaryfile/BinaryFileITCase.java
@@ -85,33 +85,33 @@ class BinaryFileITCase {
 			void shouldReturnConstraintViolationExceptionData() throws Exception {
 				var result = callEndpoint(TEST_FILE, BinaryFileTestFactory.FIELD);
 
-				result.andExpect(jsonPath("issues[0].field").value("uploadBinaryFileRequest"))
-						.andExpect(jsonPath("issues[0].messageCode").value("validation_field_file_size_exceeded"))
-						.andExpect(jsonPath("issues[0].message").value("validation_field_file_size_exceeded"))
-						.andExpect(jsonPath("issues[0].parameters[0].name").value("unit"))
-						.andExpect(jsonPath("issues[0].parameters[0].value").value(UploadBinaryFileSizeValidator.DEFAULT_UNIT_STRING));
+				result.andExpect(jsonPath("invalidParams[0].name").value("uploadFile.uploadBinaryFileRequest"))
+						.andExpect(jsonPath("invalidParams[0].reason").value("validation_field_file_size_exceeded"))
+						.andExpect(jsonPath("invalidParams[0].constraintParameters[0].name").value("unit"))
+						.andExpect(
+								jsonPath("invalidParams[0].constraintParameters[0].value").value(UploadBinaryFileSizeValidator.DEFAULT_UNIT_STRING));
 			}
 
 			@Test
 			void shouldContainsExceptionDataOnDefaultMaxSize() throws Exception {
 				var result = callEndpoint(TEST_FILE, BinaryFileTestFactory.FIELD);
 
-				result.andExpect(jsonPath("issues[0].parameters[1].name").value("max"))
-						.andExpect(jsonPath("issues[0].parameters[1].value").value("40"));
+				result.andExpect(jsonPath("invalidParams[0].constraintParameters[1].name").value("max"))
+						.andExpect(jsonPath("invalidParams[0].constraintParameters[1].value").value("40"));
 			}
 		}
 
 		@Nested
 		class TestForPostfachNachricht {
 
-			private final static String FIELD = "postfachNachrichtAttachment";
+			private static final String FIELD = "postfachNachrichtAttachment";
 
 			@Test
 			void shouldContainsExceptionDataOnPostfachNachrichtMaxSize() throws Exception {
 				var result = callEndpoint(TEST_FILE, FIELD);
 
-				result.andExpect(jsonPath("issues[0].parameters[1].name").value("max"))
-						.andExpect(jsonPath("issues[0].parameters[1].value").value("3"));
+				result.andExpect(jsonPath("invalidParams[0].constraintParameters[1].name").value("max"))
+						.andExpect(jsonPath("invalidParams[0].constraintParameters[1].value").value("3"));
 			}
 		}
 
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/common/command/CommandControllerTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/common/command/CommandControllerTest.java
index 53f6ec125efb2914bb7754ff51211c646f904bbc..47da8200c2c2a6ab2465778f1110f3213e8c139b 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/common/command/CommandControllerTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/common/command/CommandControllerTest.java
@@ -43,6 +43,7 @@ import org.springframework.test.web.servlet.ResultActions;
 import org.springframework.test.web.servlet.setup.MockMvcBuilders;
 
 import de.ozgcloud.alfa.common.errorhandling.ExceptionController;
+import de.ozgcloud.alfa.common.errorhandling.ProblemDetailMapper;
 import de.ozgcloud.alfa.vorgang.VorgangHeaderTestFactory;
 import de.ozgcloud.common.test.TestUtils;
 
@@ -54,12 +55,14 @@ class CommandControllerTest {
 	private CommandService service;
 	@Mock
 	private CommandModelAssembler modelAssembler;
+	@Mock
+	private ProblemDetailMapper problemDetailMapper;
 
 	private MockMvc mockMvc;
 
 	@BeforeEach
 	void initTest() {
-		mockMvc = MockMvcBuilders.standaloneSetup(controller).setControllerAdvice(new ExceptionController()).build();
+		mockMvc = MockMvcBuilders.standaloneSetup(controller).setControllerAdvice(new ExceptionController(problemDetailMapper)).build();
 	}
 
 	@Nested
@@ -171,8 +174,8 @@ class CommandControllerTest {
 
 		private ResultActions doRequest() throws Exception {
 			return mockMvc.perform(get(CommandController.COMMANDS_PATH)
-					.param(CommandController.PARAM_PENDING, Boolean.toString(true))
-					.param(CommandController.PARAM_VORGANG_ID, VorgangHeaderTestFactory.ID))
+							.param(CommandController.PARAM_PENDING, Boolean.toString(true))
+							.param(CommandController.PARAM_VORGANG_ID, VorgangHeaderTestFactory.ID))
 					.andExpect(status().is2xxSuccessful());
 		}
 	}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/common/command/CommandITCase.java b/alfa-service/src/test/java/de/ozgcloud/alfa/common/command/CommandITCase.java
index 7ee0005a679ae552bd6e78cdc24ae00e6ab99213..3f396641e5d9aca17161d0276e9a0fe8d8521a44 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/common/command/CommandITCase.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/common/command/CommandITCase.java
@@ -126,9 +126,9 @@ public class CommandITCase {
 							.email(null).build());
 
 					doRequest(requestContent).andExpect(status().isUnprocessableEntity())
-							.andExpect(jsonPath("$.issues.length()").value(1))
-							.andExpect(jsonPath("$.issues.[0].field").value("command.redirectRequest.email"))
-							.andExpect(jsonPath("$.issues.[0].messageCode").value(ValidationMessageCodes.FIELD_IS_EMPTY));
+							.andExpect(jsonPath("$.invalidParams.length()").value(1))
+							.andExpect(jsonPath("$.invalidParams[0].name").value("createCommand.command.redirectRequest.email"))
+							.andExpect(jsonPath("$.invalidParams[0].reason").value(ValidationMessageCodes.FIELD_IS_EMPTY));
 				}
 			}
 
@@ -145,7 +145,7 @@ public class CommandITCase {
 							.build());
 
 					doRequest(requestContent).andExpect(status().isUnprocessableEntity())
-							.andExpect(jsonPath("$.issues.length()").value(2));
+							.andExpect(jsonPath("$.invalidParams.length()").value(2));
 				}
 			}
 
@@ -153,16 +153,16 @@ public class CommandITCase {
 			@Nested
 			class TestEmail {
 
-				private final String FIELD = "email";
+				private static final String FIELD = "email";
 
 				@Test
 				void shouldReturnErrorOnNullEMail() throws Exception {
 					var requestContent = buildRedirectRequestWithEmail(null);
 
 					doRequest(requestContent).andExpect(status().isUnprocessableEntity())
-							.andExpect(jsonPath("$.issues.length()").value(1))
-							.andExpect(jsonPath("$.issues.[0].field").value("command.redirectRequest." + FIELD))
-							.andExpect(jsonPath("$.issues.[0].messageCode").value(ValidationMessageCodes.FIELD_IS_EMPTY));
+							.andExpect(jsonPath("$.invalidParams.length()").value(1))
+							.andExpect(jsonPath("$.invalidParams[0].name").value("createCommand.command.redirectRequest." + FIELD))
+							.andExpect(jsonPath("$.invalidParams[0].reason").value(ValidationMessageCodes.FIELD_IS_EMPTY));
 				}
 
 				@Test
@@ -170,9 +170,9 @@ public class CommandITCase {
 					var requestContent = buildRedirectRequestWithEmail("local@@domain.com");
 
 					doRequest(requestContent).andExpect(status().isUnprocessableEntity())
-							.andExpect(jsonPath("$.issues.length()").value(1))
-							.andExpect(jsonPath("$.issues.[0].field").value("command.redirectRequest." + FIELD))
-							.andExpect(jsonPath("$.issues.[0].messageCode").value(ValidationMessageCodes.FIELD_INVALID));
+							.andExpect(jsonPath("$.invalidParams.length()").value(1))
+							.andExpect(jsonPath("$.invalidParams[0].name").value("createCommand.command.redirectRequest." + FIELD))
+							.andExpect(jsonPath("$.invalidParams[0].reason").value(ValidationMessageCodes.FIELD_INVALID));
 				}
 
 				private String buildRedirectRequestWithEmail(String eMail) {
@@ -191,13 +191,13 @@ public class CommandITCase {
 					var requestContent = buildRedirectRequestWithPassword(RandomStringUtils.randomAlphabetic(7));
 
 					doRequest(requestContent).andExpect(status().isUnprocessableEntity())
-							.andExpect(jsonPath("$.issues.length()").value(1))
-							.andExpect(jsonPath("$.issues.[0].field").value("command.redirectRequest." + FIELD))
-							.andExpect(jsonPath("$.issues.[0].messageCode").value(ValidationMessageCodes.FIELD_SIZE))
-							.andExpect(jsonPath("$.issues.[0].parameters[0].name").value("min"))
-							.andExpect(jsonPath("$.issues.[0].parameters[0].value").value(8))
-							.andExpect(jsonPath("$.issues.[0].parameters[1].name").value("max"))
-							.andExpect(jsonPath("$.issues.[0].parameters[1].value").value(40));
+							.andExpect(jsonPath("$.invalidParams.length()").value(1))
+							.andExpect(jsonPath("$.invalidParams[0].name").value("createCommand.command.redirectRequest." + FIELD))
+							.andExpect(jsonPath("$.invalidParams[0].reason").value(ValidationMessageCodes.FIELD_SIZE))
+							.andExpect(jsonPath("$.invalidParams[0].constraintParameters[0].name").value("min"))
+							.andExpect(jsonPath("$.invalidParams[0].constraintParameters[0].value").value(8))
+							.andExpect(jsonPath("$.invalidParams[0].constraintParameters[1].name").value("max"))
+							.andExpect(jsonPath("$.invalidParams[0].constraintParameters[1].value").value(40));
 				}
 
 				@Test
@@ -205,9 +205,9 @@ public class CommandITCase {
 					var requestContent = buildRedirectRequestWithPassword(RandomStringUtils.randomAlphabetic(41));
 
 					doRequest(requestContent).andExpect(status().isUnprocessableEntity())
-							.andExpect(jsonPath("$.issues.length()").value(1))
-							.andExpect(jsonPath("$.issues.[0].field").value("command.redirectRequest." + FIELD))
-							.andExpect(jsonPath("$.issues.[0].messageCode").value(ValidationMessageCodes.FIELD_SIZE));
+							.andExpect(jsonPath("$.invalidParams.length()").value(1))
+							.andExpect(jsonPath("$.invalidParams[0].name").value("createCommand.command.redirectRequest." + FIELD))
+							.andExpect(jsonPath("$.invalidParams[0].reason").value(ValidationMessageCodes.FIELD_SIZE));
 				}
 
 				private String buildRedirectRequestWithPassword(String password) {
@@ -245,9 +245,9 @@ public class CommandITCase {
 							.buildSendPostfachMailContent(PostfachMailTestFactory.createBuilder().subject(null).build());
 
 					doRequest(requestContent).andExpect(status().isUnprocessableEntity())
-							.andExpect(jsonPath("$.issues.length()").value(1))
-							.andExpect(jsonPath("$.issues.[0].field").value("command.body.subject"))
-							.andExpect(jsonPath("$.issues.[0].messageCode").value(ValidationMessageCodes.FIELD_IS_EMPTY));
+							.andExpect(jsonPath("$.invalidParams.length()").value(1))
+							.andExpect(jsonPath("$.invalidParams[0].name").value("createCommand.command.body.subject"))
+							.andExpect(jsonPath("$.invalidParams[0].reason").value(ValidationMessageCodes.FIELD_IS_EMPTY));
 				}
 
 				@Test
@@ -257,9 +257,9 @@ public class CommandITCase {
 									PostfachMailTestFactory.createBuilder().subject(RandomStringUtils.randomAlphanumeric(71)).build());
 
 					doRequest(requestContent).andExpect(status().isUnprocessableEntity())
-							.andExpect(jsonPath("$.issues.length()").value(1))
-							.andExpect(jsonPath("$.issues.[0].field").value("command.body.subject"))
-							.andExpect(jsonPath("$.issues.[0].messageCode").value(ValidationMessageCodes.FIELD_MAX_SIZE));
+							.andExpect(jsonPath("$.invalidParams.length()").value(1))
+							.andExpect(jsonPath("$.invalidParams[0].name").value("createCommand.command.body.subject"))
+							.andExpect(jsonPath("$.invalidParams[0].reason").value(ValidationMessageCodes.FIELD_MAX_SIZE));
 				}
 
 				@Test
@@ -280,9 +280,9 @@ public class CommandITCase {
 							.buildSendPostfachMailContent(PostfachMailTestFactory.createBuilder().mailBody(null).build());
 
 					doRequest(request).andExpect(status().isUnprocessableEntity())
-							.andExpect(jsonPath("$.issues.length()").value(1))
-							.andExpect(jsonPath("$.issues.[0].field").value("command.body.mailBody"))
-							.andExpect(jsonPath("$.issues.[0].messageCode").value(ValidationMessageCodes.FIELD_IS_EMPTY));
+							.andExpect(jsonPath("$.invalidParams.length()").value(1))
+							.andExpect(jsonPath("$.invalidParams[0].name").value("createCommand.command.body.mailBody"))
+							.andExpect(jsonPath("$.invalidParams[0].reason").value(ValidationMessageCodes.FIELD_IS_EMPTY));
 				}
 
 				@Test
@@ -299,9 +299,9 @@ public class CommandITCase {
 		ResultActions doRequest(String content) throws Exception {
 			return mockMvc.perform(post("/api/vorgangs/" + CommandTestFactory.VORGANG_ID + "/relations/" + CommandTestFactory.RELATION_ID + "/"
 					+ CommandTestFactory.RELATION_VERSION + "/commands")
-					.with(csrf())
-					.contentType(MediaType.APPLICATION_JSON)
-					.content(content));
+							.with(csrf())
+							.contentType(MediaType.APPLICATION_JSON)
+							.content(content));
 		}
 	}
 }
\ No newline at end of file
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 01c57942b5967158fdf4d50b0e9b7219ae527867..fdf074c51c83c4ad34eb6e1c188f0af89c273dfa 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
@@ -76,7 +76,7 @@ class CommandModelAssemblerTest {
 		@Nested
 		class TestOnVorgang {
 
-			private final String VORGANG_URL = "/api/vorgangs/" + RELATION_ID;
+			private static final String VORGANG_URL = "/api/vorgangs/" + RELATION_ID;
 
 			@ParameterizedTest
 			@EnumSource(mode = Mode.INCLUDE, names = { "FINISHED", "REVOKED" })
@@ -103,7 +103,7 @@ class CommandModelAssemblerTest {
 		@Nested
 		class TestOnForwarding {
 
-			private final String FORWARDING_URL = "/api/forwardings?vorgangId=" + VorgangHeaderTestFactory.ID;
+			private static final String FORWARDING_URL = "/api/forwardings?vorgangId=" + VorgangHeaderTestFactory.ID;
 
 			@ParameterizedTest
 			@ValueSource(strings = { "FORWARD_SUCCESSFULL", "FORWARD_FAILED", "REDIRECT_VORGANG" })
@@ -119,7 +119,7 @@ class CommandModelAssemblerTest {
 		@Nested
 		class TestOnPostfach {
 
-			private final String POSTFACH_URL = "/api/postfachMails?vorgangId=" + VorgangHeaderTestFactory.ID;
+			private static final String POSTFACH_URL = "/api/postfachMails?vorgangId=" + VorgangHeaderTestFactory.ID;
 
 			@ParameterizedTest
 			@ValueSource(strings = { "SEND_POSTFACH_MAIL" })
@@ -135,7 +135,7 @@ class CommandModelAssemblerTest {
 		@Nested
 		class TestOnBescheid {
 
-			private final String BESCHEID_URL = "/api/bescheids?vorgangId=" + VorgangHeaderTestFactory.ID;
+			private static final String BESCHEID_URL = "/api/bescheids?vorgangId=" + VorgangHeaderTestFactory.ID;
 
 			@ParameterizedTest
 			@ValueSource(strings = { "CREATE_BESCHEID", "UPDATE_BESCHEID" })
@@ -152,7 +152,7 @@ class CommandModelAssemblerTest {
 		@Nested
 		class TestOnDocument {
 
-			private final String DOCUMENT_URL = "/api/bescheids/documents/" + RELATION_ID;
+			private static final String DOCUMENT_URL = "/api/bescheids/documents/" + RELATION_ID;
 
 			@Test
 			void shouldHaveLinkToBescheidDokument() {
@@ -166,6 +166,21 @@ class CommandModelAssemblerTest {
 			}
 		}
 
+		@DisplayName("on collaboration")
+		@Nested
+		class TestOnCollaboration {
+
+			private static final String COLLABORATIONS_URL = "/api/vorgangs/" + VORGANG_ID + "/collaborations";
+
+			@Test
+			void shouldHaveLinkToCollaborations() {
+				var model = toModelWithOrder("CREATE_COLLABORATION_REQUEST");
+
+				assertThat(model.getLink(CommandModelAssembler.REL_EFFECTED_RESOURCE)).isPresent().get()
+						.extracting(Link::getHref).isEqualTo(COLLABORATIONS_URL);
+			}
+		}
+
 		@DisplayName("on unknown Order")
 		@Nested
 		class TestOnUnknownOrder {
@@ -223,7 +238,7 @@ class CommandModelAssemblerTest {
 					"UPDATE_ATTACHED_ITEM", "PATCH_ATTACHED_ITEM", "RECEIVE_POSTFACH_NACHRICHT", "VORGANG_LOESCHEN", "DELETE_ATTACHED_ITEM",
 					"VORGANG_ZUM_LOESCHEN_MARKIEREN", "LOESCH_ANFORDERUNG_ZURUECKNEHMEN", "CREATE_BESCHEID", "PROCESS_VORGANG", "SET_AKTENZEICHEN",
 					"DELETE_BESCHEID", "UPDATE_BESCHEID", "CREATE_BESCHEID_DOCUMENT_FROM_FILE", "CREATE_BESCHEID_DOCUMENT", "SEND_BESCHEID",
-					"UNBEKANNT" })
+					"UNBEKANNT", "CREATE_COLLABORATION_REQUEST" })
 			void shouldBePresentOnOrder(CommandOrder order) {
 				var model = toModelWithOrder(order.name());
 
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/common/errorhandling/ExceptionControllerTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/common/errorhandling/ExceptionControllerTest.java
index 489f0a8f4f2504e203d81504db92d12efc76f777..50a0b2d1af3cce26dfd38934071b5cf48264c048 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/common/errorhandling/ExceptionControllerTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/common/errorhandling/ExceptionControllerTest.java
@@ -27,7 +27,6 @@ import static org.assertj.core.api.Assertions.*;
 import static org.mockito.Mockito.*;
 
 import java.util.Collections;
-import java.util.Map;
 
 import jakarta.validation.ConstraintViolationException;
 
@@ -36,10 +35,14 @@ import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
 import org.mockito.InjectMocks;
+import org.mockito.Mock;
 import org.mockito.Spy;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ProblemDetail;
 import org.springframework.security.access.AccessDeniedException;
 
-import de.ozgcloud.alfa.common.binaryfile.DynamicViolationParameter;
+import com.thedeanda.lorem.LoremIpsum;
+
 import de.ozgcloud.alfa.common.command.LegacyOrder;
 import de.ozgcloud.common.errorhandling.TechnicalException;
 
@@ -49,6 +52,9 @@ class ExceptionControllerTest {
 	@InjectMocks
 	private ExceptionController exceptionController;
 
+	@Mock
+	private ProblemDetailMapper problemDetailMapper;
+
 	@Nested
 	class TestHandleFunctionalException {
 
@@ -162,79 +168,42 @@ class ExceptionControllerTest {
 	@Nested
 	class TestContraintValidationException {
 
-		private final ConstraintViolationException exception = new ConstraintViolationException(ExceptionTestFactory.MESSAGE,
-				Collections.singleton(ExceptionTestFactory.buildMockedConstraintViolation()));
-
-		@BeforeEach
-		void mockExceptionId() {
-			doReturn(ExceptionTestFactory.EXCEPTION_ID).when(exceptionController).createExceptionId();
-		}
-
-		@Test
-		void shouldHaveField() {
-			var error = handleException();
-
-			assertThat(error.getIssues()).hasSize(1);
-			assertThat(error.getIssues().get(0).getField()).isEqualTo(ExceptionTestFactory.PATH_FIELD);
-		}
-
-		@Test
-		void shouldHaveMessageCode() {
-			var error = handleException();
-
-			assertThat(error.getIssues()).hasSize(1);
-			assertThat(error.getIssues().get(0).getMessageCode()).isEqualTo(ExceptionTestFactory.MESSAGE_CODE);
-		}
-
-		@Test
-		void shouldHaveMessage() {
-			var error = handleException();
-
-			assertThat(error.getIssues()).hasSize(1);
-			assertThat(error.getIssues().get(0).getMessage()).isEqualTo(ExceptionTestFactory.MESSAGE);
-		}
-
-		@Test
-		void shouldHaveExceptionId() {
-			var error = handleException();
+		@Nested
+		class TestHandleConstraintViolationException {
+			private final String exceptionMessage = LoremIpsum.getInstance().getWords(5);
 
-			assertThat(error.getIssues().get(0).getExceptionId()).isEqualTo(ExceptionTestFactory.EXCEPTION_ID);
-		}
+			private final ConstraintViolationException exception = new ConstraintViolationException(exceptionMessage,
+					Collections.singleton(ExceptionTestFactory.buildMockedConstraintViolation()));
 
-		@Test
-		void shouldHaveIssueParameter() {
-			var error = handleException();
+			@Test
+			void shouldGetMessageWithExceptionId() {
+				handleException();
 
-			var issueParameter = error.getIssues().get(0).getParameters().get(0);
-			assertThat(issueParameter.getName()).isEqualTo(ExceptionTestFactory.PARAM_NAME);
-			assertThat(issueParameter.getValue()).isEqualTo(ExceptionTestFactory.PARAM_DYNAMIC_VALUE);
-		}
+				verify(problemDetailMapper).buildMessageWithExceptionId(exception);
+			}
 
-		@Nested
-		class TestWithDynamicPayload {
+			@Test
+			void shouldBuildConstraintViolationProblemDetail() {
+				handleException();
 
-			private final DynamicViolationParameter dynamicViolationParameter = DynamicViolationParameter.builder()
-					.map(Map.of(ExceptionTestFactory.PARAM_NAME, ExceptionTestFactory.PARAM_DYNAMIC_VALUE)).build();
-			private final ConstraintViolationException exceptionWithDynamicPayload = new ConstraintViolationException(ExceptionTestFactory.MESSAGE,
-					Collections.singleton(ExceptionTestFactory.buildMockedConstraintViolationWithDynamicPayload(dynamicViolationParameter)));
+				verify(problemDetailMapper).fromConstraintViolationException(exception);
+			}
 
 			@Test
-			void shouldHaveReplacedParams() {
-				var error = handleExceptionWithDynamicPayload();
+			void shouldReturnBuiltProblemDetail() {
+				var expectedProblemDetail = ProblemDetail.forStatusAndDetail(HttpStatus.UNPROCESSABLE_ENTITY, exceptionMessage);
+				when(problemDetailMapper.fromConstraintViolationException(exception)).thenReturn(expectedProblemDetail);
+
+				var problemDetail = handleException();
 
-				var issueParameter = error.getIssues().get(0).getParameters().get(0);
-				assertThat(issueParameter.getName()).isEqualTo(ExceptionTestFactory.PARAM_NAME);
-				assertThat(issueParameter.getValue()).isEqualTo(ExceptionTestFactory.PARAM_DYNAMIC_VALUE);
+				assertThat(problemDetail).isEqualTo(expectedProblemDetail);
 			}
 
-			private ApiError handleExceptionWithDynamicPayload() {
-				return exceptionController.handleConstraintViolationException(exceptionWithDynamicPayload);
+			private ProblemDetail handleException() {
+				return exceptionController.handleConstraintViolationException(exception);
 			}
 		}
 
-		private ApiError handleException() {
-			return exceptionController.handleConstraintViolationException(exception);
-		}
 	}
 
 	@Nested
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/common/errorhandling/ExceptionTestFactory.java b/alfa-service/src/test/java/de/ozgcloud/alfa/common/errorhandling/ExceptionTestFactory.java
index d96c42787390b1b99df6bd412efce278c3dd7335..19cdbe389dc959ade05e069b6b820513c980d3c2 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/common/errorhandling/ExceptionTestFactory.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/common/errorhandling/ExceptionTestFactory.java
@@ -48,26 +48,26 @@ public class ExceptionTestFactory {
 	static final String PARAM_DYNAMIC_VALUE = "20";
 	static final String MESSAGE = LoremIpsum.getInstance().getWords(5);
 	static final String MESSAGE_CODE = "message.code";
-	private static final String PATH_SUFFIX = "createCommandByRelation";
+	private static final String PATH_PREFIX = "createCommandByRelation";
 	static final String PATH_FIELD = "command.wiedervorlage.betreff";
-	private static final String PATH = PATH_SUFFIX + "." + PATH_FIELD;
+	public static final String PATH = PATH_PREFIX + "." + PATH_FIELD;
 
 	public static ConstraintViolation<?> buildMockedConstraintViolation() {
 		return ExceptionTestFactory.buildMockedConstraintViolationWithDynamicPayload(null);
 	}
 
-	@SuppressWarnings({ "rawtypes", "unchecked" })
+	@SuppressWarnings({ "unchecked" })
 	public static <T> ConstraintViolation<T> buildMockedConstraintViolationWithDynamicPayload(DynamicViolationParameter dynamicViolationParameter) {
-		ConstraintViolation violation = mock(ConstraintViolation.class);
-		HibernateConstraintViolation hibernateViolation = mock(HibernateConstraintViolation.class);
-		ConstraintDescriptor constraintDescriptor = mock(ConstraintDescriptor.class);
+		var violation = mock(ConstraintViolation.class);
+		var hibernateViolation = mock(HibernateConstraintViolation.class);
+		var constraintDescriptor = mock(ConstraintDescriptor.class);
 
 		var path = mock(Path.class);
 		when(path.toString()).thenReturn(PATH);
 		when(violation.getPropertyPath()).thenReturn(path);
-		when(violation.getMessageTemplate()).thenReturn("{" + MESSAGE_CODE + "}");
 		when(violation.getMessage()).thenReturn(MESSAGE);
 		when(violation.getConstraintDescriptor()).thenReturn(constraintDescriptor);
+		when(violation.getInvalidValue()).thenReturn(PARAM_VALUE);
 		when(constraintDescriptor.getAttributes()).thenReturn(Map.of(PARAM_NAME, PARAM_DYNAMIC_VALUE));
 		when(violation.unwrap(any())).thenReturn(hibernateViolation);
 		when(hibernateViolation.getDynamicPayload(any())).thenReturn(dynamicViolationParameter);
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/common/errorhandling/IssueParamTestFactory.java b/alfa-service/src/test/java/de/ozgcloud/alfa/common/errorhandling/IssueParamTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..2a9a035c179a40230996e0d97cc72ebbb0df7366
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/common/errorhandling/IssueParamTestFactory.java
@@ -0,0 +1,17 @@
+package de.ozgcloud.alfa.common.errorhandling;
+
+import de.ozgcloud.alfa.common.errorhandling.IssueParam.IssueParamBuilder;
+
+public class IssueParamTestFactory {
+	public static final String PARAM_NAME = ExceptionTestFactory.PARAM_NAME;
+	public static final String PARAM_DYNAMIC_VALUE = ExceptionTestFactory.PARAM_DYNAMIC_VALUE;
+
+	public static IssueParam create() {
+		return createBuilder()
+				.build();
+	}
+
+	public static IssueParamBuilder createBuilder() {
+		return IssueParam.builder().name(PARAM_NAME).value(PARAM_DYNAMIC_VALUE);
+	}
+}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/common/errorhandling/ProblemDetailMapperTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/common/errorhandling/ProblemDetailMapperTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..b55e6f4ee9a7f15c902446f1846893ca4614f3b0
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/common/errorhandling/ProblemDetailMapperTest.java
@@ -0,0 +1,313 @@
+package de.ozgcloud.alfa.common.errorhandling;
+
+import static org.assertj.core.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.*;
+
+import java.util.AbstractMap.SimpleEntry;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import java.util.stream.Stream;
+
+import jakarta.validation.ConstraintViolation;
+import jakarta.validation.ConstraintViolationException;
+import jakarta.validation.metadata.ConstraintDescriptor;
+
+import org.hibernate.validator.engine.HibernateConstraintViolation;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mock;
+import org.mockito.Spy;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ProblemDetail;
+
+import com.thedeanda.lorem.LoremIpsum;
+
+import de.ozgcloud.alfa.common.binaryfile.DynamicViolationParameter;
+import de.ozgcloud.common.errorhandling.ExceptionUtil;
+
+class ProblemDetailMapperTest {
+
+	@Spy
+	private ProblemDetailMapper mapper;
+
+	@Nested
+	class TestFromConstraintViolationException {
+		private final String exceptionMessage = LoremIpsum.getInstance().getWords(5);
+		private final Set<ConstraintViolation<?>> violations = Collections.singleton(ExceptionTestFactory.buildMockedConstraintViolation());
+		private final ConstraintViolationException exception = new ConstraintViolationException(exceptionMessage, violations);
+		private final String message = LoremIpsum.getInstance().getWords(5);
+
+		@BeforeEach
+		void mockMapper() {
+			doReturn(message).when(mapper).buildMessageWithExceptionId(exception);
+		}
+
+		@Test
+		void shouldGetMessageWithExcpetionId() {
+			callMapper();
+
+			verify(mapper).buildMessageWithExceptionId(exception);
+		}
+
+		@Test
+		void shouldHaveStatusUnprocessableEntity() {
+			var problemDetail = callMapper();
+
+			assertThat(problemDetail.getStatus()).isEqualTo(HttpStatus.UNPROCESSABLE_ENTITY.value());
+		}
+
+		@Test
+		void shouldHaveMessageInDetail() {
+			var problemDetail = callMapper();
+
+			assertThat(problemDetail.getDetail()).contains(message);
+		}
+
+		@Test
+		void shouldGetDetailedViolationList() {
+			callMapper();
+
+			verify(mapper).buildInvalidParams(violations);
+		}
+
+		@Test
+		void shouldSetPropertyInvalidParams() {
+			var expectedInvalidParamsValue = Map.of();
+			doReturn(Stream.of(expectedInvalidParamsValue)).when(mapper).buildInvalidParams(violations);
+
+			var problemDetail = callMapper();
+
+			assertThat(problemDetail.getProperties())
+					.containsExactly(new SimpleEntry<String, Object>(ProblemDetailMapper.INVALID_PARAMS, List.of(expectedInvalidParamsValue)));
+		}
+
+		private ProblemDetail callMapper() {
+			return mapper.fromConstraintViolationException(exception);
+		}
+	}
+
+	@Nested
+	class TestBuildMessageWithExceptionId {
+
+		private final String exceptionMessage = LoremIpsum.getInstance().getWords(5);
+		private final String exceptionId = UUID.randomUUID().toString();
+		private final ConstraintViolationException exception = new ConstraintViolationException(exceptionMessage, null);
+
+		@BeforeEach
+		void mockCreateExcpetionId() {
+			doReturn(exceptionId).when(mapper).createExceptionId();
+		}
+
+		@Test
+		void shouldCreateExceptionId() {
+			callMapper();
+
+			verify(mapper).createExceptionId();
+		}
+
+		@Test
+		void shouldFormatMessageWithExceptionId() {
+			var messageWithId = callMapper();
+
+			assertThat(messageWithId).isEqualTo(ExceptionUtil.formatMessageWithExceptionId(exceptionMessage, exceptionId));
+		}
+
+		private String callMapper() {
+			return mapper.buildMessageWithExceptionId(exception);
+		}
+	}
+
+	@Nested
+	class TestBuildInvalidParams {
+
+		@Nested
+		class OnViolations {
+			private final Set<ConstraintViolation<?>> violations = Set.of(ExceptionTestFactory.buildMockedConstraintViolation(),
+					ExceptionTestFactory.buildMockedConstraintViolation());
+
+			@Test
+			void shouldCallBuildDetailedViolation() {
+				callMapper().toList();
+
+				violations.forEach(violation -> verify(mapper).buildDetailedViolation(violation));
+			}
+
+			@Test
+			void shouldReturnListWithDetailedViolations() {
+				Map<String, Object> detailsMap = Map.of(LoremIpsum.getInstance().getWords(1), LoremIpsum.getInstance().getWords(1));
+				violations.forEach(violation -> doReturn(detailsMap).when(mapper).buildDetailedViolation(violation));
+
+				var detailedViolations = callMapper();
+
+				assertThat(detailedViolations).containsExactly(detailsMap, detailsMap);
+			}
+
+			private Stream<Map<String, Object>> callMapper() {
+				return mapper.buildInvalidParams(violations);
+			}
+		}
+
+		@Nested
+		class OnEmptyViolations {
+			private final Set<ConstraintViolation<?>> violations = Collections.emptySet();
+
+			@Test
+			void shouldCallNotBuildDetailedViolation() {
+				callMapper();
+
+				verify(mapper, never()).buildDetailedViolation(any());
+			}
+
+			@Test
+			void shouldReturnListWithDetailedViolations() {
+				var detailedViolations = callMapper();
+
+				assertThat(detailedViolations).isEmpty();
+			}
+
+			private Stream<Map<String, Object>> callMapper() {
+				return mapper.buildInvalidParams(violations);
+			}
+		}
+	}
+
+	@Nested
+	class TestBuildDetailedViolation {
+		private final ConstraintViolation<?> violation = ExceptionTestFactory.buildMockedConstraintViolation();
+
+		@Test
+		void shouldContainFieldName() {
+			var expectedEntry = new SimpleEntry<>(ProblemDetailMapper.INVALID_PARAMS_KEY_NAME, ExceptionTestFactory.PATH);
+
+			var detailedViolation = callMapper();
+
+			assertThat(detailedViolation).contains(expectedEntry);
+		}
+
+		@Test
+		void shouldContainValue() {
+			var expectedEntry = new SimpleEntry<>(ProblemDetailMapper.INVALID_PARAMS_KEY_VALUE, ExceptionTestFactory.PARAM_VALUE);
+
+			var detailedViolation = callMapper();
+
+			assertThat(detailedViolation).contains(expectedEntry);
+		}
+
+		@Test
+		void shouldHandleNullValue() {
+			when(violation.getInvalidValue()).thenReturn(null);
+			var expectedEntry = new SimpleEntry<>(ProblemDetailMapper.INVALID_PARAMS_KEY_VALUE,
+					ProblemDetailMapper.PROVIDED_VALUE_WAS_NULL);
+
+			var detailedViolation = callMapper();
+
+			assertThat(detailedViolation).contains(expectedEntry);
+		}
+
+		@Test
+		void shouldContainReason() {
+			var expectedEntry = new SimpleEntry<>(ProblemDetailMapper.INVALID_PARAMS_KEY_REASON, ExceptionTestFactory.MESSAGE);
+
+			var detailedViolation = callMapper();
+
+			assertThat(detailedViolation).contains(expectedEntry);
+		}
+
+		@Test
+		void shouldBuildParameters() {
+			callMapper();
+
+			verify(mapper).buildParameters(violation);
+		}
+
+		@Test
+		void shouldContainConstraintParameters() {
+			var issueParameter = IssueParamTestFactory.create();
+			doReturn(Stream.of(issueParameter)).when(mapper).buildParameters(violation);
+			var expectedEntry = new SimpleEntry<String, Object>(ProblemDetailMapper.INVALID_PARAMS_KEY_CONSTRAINT_PARAMETERS,
+					List.of(issueParameter));
+
+			var detailedViolation = callMapper();
+
+			assertThat(detailedViolation).contains(expectedEntry);
+		}
+
+		private Map<String, Object> callMapper() {
+			return mapper.buildDetailedViolation(violation);
+		}
+	}
+
+	@Nested
+	class TestBuildParameters {
+
+		@Mock
+		private ConstraintViolation<?> violation;
+
+		@Mock
+		@SuppressWarnings("rawtypes")
+		private ConstraintDescriptor constraintDescriptor;
+
+		@Mock
+		@SuppressWarnings("rawtypes")
+		private HibernateConstraintViolation hibernateConstraintViolation;
+
+		@SuppressWarnings("unchecked")
+		@BeforeEach
+		void setUpViolationMocks() {
+			when(violation.getConstraintDescriptor()).thenReturn(constraintDescriptor);
+			when(violation.unwrap(HibernateConstraintViolation.class)).thenReturn(hibernateConstraintViolation);
+			when(constraintDescriptor.getAttributes())
+					.thenReturn(Map.of(ExceptionTestFactory.PARAM_NAME, ExceptionTestFactory.PARAM_DYNAMIC_VALUE));
+		}
+
+		@Nested
+		class OnNonDynamicPayload {
+
+			@Test
+			void shouldBuildIssueParam() {
+				var issueParams = mapper.buildParameters(violation);
+
+				assertThat(issueParams).usingRecursiveFieldByFieldElementComparator().contains(IssueParamTestFactory.create());
+			}
+
+		}
+
+		@Nested
+		class TestWithDynamicPayload {
+
+			@SuppressWarnings("unchecked")
+			@Test
+			void shouldHaveReplacedIssueParameterName() {
+				var dynamicValue = LoremIpsum.getInstance().getWords(1);
+				var dynamicViolationParameter = DynamicViolationParameter.builder()
+						.map(Map.of(ExceptionTestFactory.PARAM_NAME, dynamicValue))
+						.build();
+				when(hibernateConstraintViolation.getDynamicPayload(DynamicViolationParameter.class)).thenReturn(dynamicViolationParameter);
+				var expectedIssueParam = IssueParamTestFactory.createBuilder().value(dynamicValue).build();
+
+				var issueParams = mapper.buildParameters(violation);
+
+				assertThat(issueParams).usingRecursiveFieldByFieldElementComparator().contains(expectedIssueParam);
+			}
+
+			@SuppressWarnings("unchecked")
+			@Test
+			void shouldIgnoreKeyNotPresentInEntry() {
+				var dynamicViolationParameter = DynamicViolationParameter.builder()
+						.map(Map.of(LoremIpsum.getInstance().getWords(1), LoremIpsum.getInstance().getWords(1)))
+						.build();
+				when(hibernateConstraintViolation.getDynamicPayload(DynamicViolationParameter.class)).thenReturn(dynamicViolationParameter);
+				var expectedIssueParam = IssueParamTestFactory.create();
+
+				var issueParams = mapper.buildParameters(violation);
+
+				assertThat(issueParams).usingRecursiveFieldByFieldElementComparator().contains(expectedIssueParam);
+			}
+		}
+	}
+}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/common/user/CurrentUserServiceTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/common/user/CurrentUserServiceTest.java
index e363dc185c06592f6e7e11e35f25c131bd6a83d6..a478cf2de0cf24b12bec1c1279be4b26c3d9a2d5 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/common/user/CurrentUserServiceTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/common/user/CurrentUserServiceTest.java
@@ -35,8 +35,10 @@ import java.util.Optional;
 import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
+import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.Spy;
+import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
 import org.springframework.security.oauth2.jwt.Jwt;
 
 import de.ozgcloud.alfa.JwtTestFactory;
@@ -44,7 +46,12 @@ import de.ozgcloud.alfa.JwtTestFactory;
 class CurrentUserServiceTest {
 
 	@Spy
+	@InjectMocks
 	private CurrentUserService service;
+	@Mock
+	private UserService userService;
+	@Mock
+	private RoleHierarchy roleHierarchy;
 
 	@Nested
 	class TestGetOrganisationseinheit {
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/kommentar/KommentarCommandITCase.java b/alfa-service/src/test/java/de/ozgcloud/alfa/kommentar/KommentarCommandITCase.java
index 87d5be0da2eae911f865f47380307fe8a7fa61b5..0eed2bf6a4c58bdce7d81ccb29f1de9d40ad372d 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/kommentar/KommentarCommandITCase.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/kommentar/KommentarCommandITCase.java
@@ -107,9 +107,9 @@ class KommentarCommandITCase {
 				String content = buildContentWithText(null);
 
 				doRequestByKommentarId(content).andExpect(status().isUnprocessableEntity())
-						.andExpect(jsonPath("$.issues.length()").value(1))
-						.andExpect(jsonPath("$.issues.[0].field").value("kommentar.text"))
-						.andExpect(jsonPath("$.issues.[0].messageCode").value(ValidationMessageCodes.FIELD_IS_EMPTY));
+						.andExpect(jsonPath("$.invalidParams.length()").value(1))
+						.andExpect(jsonPath("$.invalidParams[0].name").value("editKommentar.kommentar.text"))
+						.andExpect(jsonPath("$.invalidParams[0].reason").value(ValidationMessageCodes.FIELD_IS_EMPTY));
 			}
 
 			@SneakyThrows
@@ -119,7 +119,7 @@ class KommentarCommandITCase {
 				String content = buildContentWithText(StringUtils.EMPTY);
 
 				doRequestByKommentarId(content).andExpect(status().isUnprocessableEntity())
-						.andExpect(jsonPath("$.issues.[0].field").value("kommentar.text"));
+						.andExpect(jsonPath("$.invalidParams[0].name").value("editKommentar.kommentar.text"));
 
 			}
 
@@ -130,7 +130,7 @@ class KommentarCommandITCase {
 				String content = buildContentWithText(StringUtils.EMPTY);
 
 				doRequestByKommentarId(content).andExpect(status().isUnprocessableEntity())
-						.andExpect(jsonPath("$.issues[0].parameters.length()").value(2));
+						.andExpect(jsonPath("$.invalidParams[0].constraintParameters.length()").value(2));
 			}
 
 			private String buildContentWithText(String text) {
@@ -190,9 +190,9 @@ class KommentarCommandITCase {
 				String content = buildContentWithText(null);
 
 				doRequestByVorgangId(content).andExpect(status().isUnprocessableEntity())
-						.andExpect(jsonPath("$.issues.length()").value(1))
-						.andExpect(jsonPath("$.issues.[0].field").value("kommentar.text"))
-						.andExpect(jsonPath("$.issues.[0].messageCode").value(ValidationMessageCodes.FIELD_IS_EMPTY));
+						.andExpect(jsonPath("$.invalidParams.length()").value(1))
+						.andExpect(jsonPath("$.invalidParams.[0].name").value("createKommentar.kommentar.text"))
+						.andExpect(jsonPath("$.invalidParams.[0].reason").value(ValidationMessageCodes.FIELD_IS_EMPTY));
 			}
 
 			@SneakyThrows
@@ -202,7 +202,7 @@ class KommentarCommandITCase {
 				String content = buildContentWithText(StringUtils.EMPTY);
 
 				doRequestByVorgangId(content).andExpect(status().isUnprocessableEntity())
-						.andExpect(jsonPath("$.issues.[0].field").value("kommentar.text"));
+						.andExpect(jsonPath("$.invalidParams.[0].name").value("createKommentar.kommentar.text"));
 
 			}
 
@@ -213,7 +213,7 @@ class KommentarCommandITCase {
 				String content = buildContentWithText(StringUtils.EMPTY);
 
 				doRequestByVorgangId(content).andExpect(status().isUnprocessableEntity())
-						.andExpect(jsonPath("$.issues[0].parameters.length()").value(2));
+						.andExpect(jsonPath("$.invalidParams[0].constraintParameters.length()").value(2));
 			}
 
 			private String buildContentWithText(String text) {
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungByVorgangControllerTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungByVorgangControllerTest.java
index 63101495e8422e6f26a9be4389fe19c995f30853..c27019e2998e2ef073b0caf0c15a8daf07f15e8f 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungByVorgangControllerTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungByVorgangControllerTest.java
@@ -26,6 +26,7 @@ import de.ozgcloud.alfa.common.command.CommandOrder;
 import de.ozgcloud.alfa.common.command.CommandTestFactory;
 import de.ozgcloud.alfa.common.command.CreateCommand;
 import de.ozgcloud.alfa.common.errorhandling.ExceptionController;
+import de.ozgcloud.alfa.common.errorhandling.ProblemDetailMapper;
 import de.ozgcloud.alfa.loeschanforderung.LoeschAnforderungController.LoeschAnforderungByVorgangController;
 import de.ozgcloud.alfa.vorgang.VorgangController;
 import de.ozgcloud.alfa.vorgang.VorgangHeaderTestFactory;
@@ -44,11 +45,14 @@ class LoeschAnforderungByVorgangControllerTest {
 	@Mock
 	private VorgangController vorgangController;
 
+	@Mock
+	private ProblemDetailMapper problemDetailMapper;
+
 	private MockMvc mockMvc;
 
 	@BeforeEach
 	void init() {
-		mockMvc = MockMvcBuilders.standaloneSetup(controller).setControllerAdvice(new ExceptionController()).build();
+		mockMvc = MockMvcBuilders.standaloneSetup(controller).setControllerAdvice(new ExceptionController(problemDetailMapper)).build();
 	}
 
 	@DisplayName("Create LoeschAnforderung")
@@ -93,7 +97,7 @@ class LoeschAnforderungByVorgangControllerTest {
 		private ResultActions doRequest() throws Exception {
 			var requestBody = CommandTestFactory.buildCreateVorgangCommandContent(CommandOrder.VORGANG_ZUM_LOESCHEN_MARKIEREN.name());
 			return mockMvc.perform(post(LoeschAnforderungByVorgangController.BASE_PATH,
-					VorgangHeaderTestFactory.ID, VorgangHeaderTestFactory.VERSION)
+							VorgangHeaderTestFactory.ID, VorgangHeaderTestFactory.VERSION)
 							.content(requestBody).contentType(MediaType.APPLICATION_JSON).characterEncoding(StandardCharsets.UTF_8.name()))
 					.andExpect(status().isCreated());
 		}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungCommandControllerTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungCommandControllerTest.java
index 392b53911f57a0836a38022192c77c7d6b72411c..ad87a8ced732c2ec48ef91262ce188a9647aabf3 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungCommandControllerTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/loeschanforderung/LoeschAnforderungCommandControllerTest.java
@@ -3,8 +3,8 @@ package de.ozgcloud.alfa.loeschanforderung;
 import static de.ozgcloud.alfa.common.command.CommandController.*;
 import static org.assertj.core.api.Assertions.*;
 import static org.hamcrest.CoreMatchers.*;
-import static org.mockito.ArgumentMatchers.*;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.*;
 import static org.mockito.Mockito.*;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@@ -40,6 +40,7 @@ import de.ozgcloud.alfa.common.command.CreateCommand;
 import de.ozgcloud.alfa.common.command.LegacyOrder;
 import de.ozgcloud.alfa.common.command.StatusPatch;
 import de.ozgcloud.alfa.common.errorhandling.ExceptionController;
+import de.ozgcloud.alfa.common.errorhandling.ProblemDetailMapper;
 import de.ozgcloud.alfa.vorgang.VorgangController;
 import de.ozgcloud.alfa.vorgang.VorgangHeaderTestFactory;
 import de.ozgcloud.alfa.vorgang.VorgangWithEingang;
@@ -64,11 +65,14 @@ class LoeschAnforderungCommandControllerTest {
 	@Mock
 	private CommandController commandController;
 
+	@Mock
+	private ProblemDetailMapper problemDetailMapper;
+
 	private MockMvc mockMvc;
 
 	@BeforeEach
 	void init() {
-		mockMvc = MockMvcBuilders.standaloneSetup(controller).setControllerAdvice(new ExceptionController()).build();
+		mockMvc = MockMvcBuilders.standaloneSetup(controller).setControllerAdvice(new ExceptionController(problemDetailMapper)).build();
 	}
 
 	@DisplayName("Create command")
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 a0ea03964f79264344bb89b24f16bddcc4cf0ed1..0ccd8259172c85ae64c5b55356d9eadc30e2b9a1 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
@@ -17,6 +17,7 @@ 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;
 
 class LoeschAnforderungControllerTest {
@@ -30,11 +31,14 @@ class LoeschAnforderungControllerTest {
 	@Mock
 	private LoeschAnforderungModelAssembler modelAssembler;
 
+	@Mock
+	private ProblemDetailMapper problemDetailMapper;
+
 	private MockMvc mockMvc;
 
 	@BeforeEach
 	void init() {
-		mockMvc = MockMvcBuilders.standaloneSetup(controller).setControllerAdvice(new ExceptionController()).build();
+		mockMvc = MockMvcBuilders.standaloneSetup(controller).setControllerAdvice(new ExceptionController(problemDetailMapper)).build();
 	}
 
 	@Nested
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 05306f1e29f313ec547dee7e7a8fc5ec1d652614..988b8cd04b8df6ae58cb6923785235828ebd5447 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
@@ -27,7 +27,6 @@ import static de.ozgcloud.alfa.common.UserProfileUrlProviderTestFactory.*;
 import static org.assertj.core.api.Assertions.*;
 import static org.mockito.Mockito.*;
 
-import java.util.Collections;
 import java.util.List;
 
 import org.junit.jupiter.api.BeforeEach;
@@ -45,7 +44,6 @@ import org.springframework.hateoas.LinkRelation;
 import org.springframework.web.util.UriComponentsBuilder;
 import org.springframework.web.util.UriTemplate;
 
-import de.ozgcloud.alfa.common.FeatureToggleProperties;
 import de.ozgcloud.alfa.common.UserProfileUrlProvider;
 import de.ozgcloud.alfa.common.command.CommandController.CommandByRelationController;
 import de.ozgcloud.alfa.common.user.CurrentUserService;
@@ -66,12 +64,6 @@ class VorgangWithEingangProcessorTest {
 	@Mock
 	private UserManagerUrlProvider userManagerUrlProvider;
 
-	@Mock
-	private FeatureToggleProperties featureToggleProperties;
-
-	@Mock
-	private VorgangProperties vorgangProperties;
-
 	@Mock
 	private VorgangProcessorProperties vorgangProcessorProperties;
 
@@ -332,218 +324,6 @@ class VorgangWithEingangProcessorTest {
 		}
 	}
 
-	@Nested
-	class TestHasVorgangCreateBescheidEnabled {
-
-		@Nested
-		class TestOnEmptyBescheidProperties {
-
-			@BeforeEach
-			void setUp() {
-				when(vorgangProperties.getBescheid()).thenReturn(Collections.emptyList());
-			}
-
-			@Test
-			void shouldReturnFalse() {
-				var hasEnabled = callProcessor(VorgangWithEingangTestFactory.create());
-
-				assertThat(hasEnabled).isFalse();
-			}
-
-		}
-
-		@Nested
-		class TestOnBescheidPropertiesSet {
-
-			@BeforeEach
-			void setUp() {
-				when(vorgangProperties.getBescheid()).thenReturn(List.of(VorgangPropertyTestFactory.create()));
-			}
-
-			@Test
-			void shouldReturnFalseIfFormEngineNameNotEquals() {
-				var vorgang = createVorgang(EingangTestFactory.createBuilder()
-						.header(EingangHeaderTestFactory.createBuilder()
-								.formEngineName("different").build())
-						.build());
-
-				var hasEnabled = callProcessor(vorgang);
-
-				assertThat(hasEnabled).isFalse();
-			}
-
-			@Test
-			void shouldReturnTrue() {
-				var hasEnabled = callProcessor(VorgangWithEingangTestFactory.create());
-
-				assertThat(hasEnabled).isTrue();
-			}
-		}
-
-		@Test
-		void shouldReturnFalseOnEmptyEingang() {
-			var vorgangWithEmptyEingang = createVorgang(null);
-
-			var hasEnabled = callProcessor(vorgangWithEmptyEingang);
-
-			assertThat(hasEnabled).isFalse();
-		}
-
-		@Test
-		void shouldReturnFalseOnEmptyEingangHeader() {
-			var vorgangWithEmptyEingangHeader = EingangTestFactory.createBuilder().header(null).build();
-
-			var hasEnabled = callProcessor(createVorgang(vorgangWithEmptyEingangHeader));
-
-			assertThat(hasEnabled).isFalse();
-		}
-
-		@Test
-		void shouldReturnFalseOnEmptyFormEngineName() {
-			var vorgangWithEmptyFormEngineName = createVorgang(
-					EingangTestFactory.createBuilder().header(EingangHeaderTestFactory.createBuilder().formEngineName(null).build()).build());
-
-			var hasEnabled = callProcessor(vorgangWithEmptyFormEngineName);
-
-			assertThat(hasEnabled).isFalse();
-		}
-
-		@Test
-		void shouldReturnFalseOnEmptyFormId() {
-			var vorgangWithEmptyFormId = createVorgang(
-					EingangTestFactory.createBuilder().header(EingangHeaderTestFactory.createBuilder().formId(null).build()).build());
-
-			var hasEnabled = callProcessor(vorgangWithEmptyFormId);
-
-			assertThat(hasEnabled).isFalse();
-		}
-
-		private boolean callProcessor(VorgangWithEingang vorgang) {
-			return processor.hasVorgangCreateBescheidEnabled(vorgang);
-		}
-
-		private VorgangWithEingang createVorgang(Eingang eingang) {
-			return VorgangWithEingangTestFactory.createBuilder().eingang(eingang).build();
-		}
-	}
-
-	@Nested
-	class TestIsCreateBescheidEnabled {
-
-		@Nested
-		class TestFeatureToggleDisabled {
-
-			@BeforeEach
-			void setUp() {
-				when(featureToggleProperties.isCreateBescheid()).thenReturn(false);
-			}
-
-			@Test
-			void shouldCallFeatureToggleProperties() {
-				callProcessor(VorgangWithEingangTestFactory.create());
-
-				verify(featureToggleProperties).isCreateBescheid();
-			}
-
-			@Test
-			void shouldNotCallHasVorgangCreateBescheidEnabled() {
-				var vorgang = VorgangWithEingangTestFactory.create();
-
-				callProcessor(vorgang);
-
-				verify(processor, never()).hasVorgangCreateBescheidEnabled(vorgang);
-			}
-
-			@Test
-			void shouldReturnFalse() {
-				var isEnabled = callProcessor(VorgangWithEingangTestFactory.create());
-
-				assertThat(isEnabled).isFalse();
-			}
-		}
-
-		@Nested
-		class TestFeatureToggleEnabled {
-
-			private final VorgangWithEingang vorgang = VorgangWithEingangTestFactory.create();
-
-			@BeforeEach
-			void setUp() {
-				when(featureToggleProperties.isCreateBescheid()).thenReturn(true);
-			}
-
-			@Test
-			void shouldCallFeatureToggleProperties() {
-				callProcessor(vorgang);
-
-				verify(featureToggleProperties).isCreateBescheid();
-			}
-
-			@Test
-			void shouldCallHasVorgangCreateBescheidEnabled() {
-				callProcessor(vorgang);
-
-				verify(processor).hasVorgangCreateBescheidEnabled(vorgang);
-			}
-
-			@Test
-			void shouldReturnTrue() {
-				doReturn(true).when(processor).hasVorgangCreateBescheidEnabled(vorgang);
-
-				var isEnabled = callProcessor(vorgang);
-
-				assertThat(isEnabled).isTrue();
-			}
-
-			@Test
-			void shouldReturnFalse() {
-				doReturn(false).when(processor).hasVorgangCreateBescheidEnabled(vorgang);
-
-				var isEnabled = callProcessor(vorgang);
-
-				assertThat(isEnabled).isFalse();
-			}
-		}
-
-		private boolean callProcessor(VorgangWithEingang vorgang) {
-			return processor.isCreateBescheidEnabled(vorgang);
-		}
-
-	}
-
-	@Nested
-	class TestCreateBescheidLink {
-
-		private final VorgangWithEingang vorgang = VorgangWithEingangTestFactory.create();
-		private final EntityModel<VorgangWithEingang> vorgangEntityModel = EntityModel.of(vorgang);
-
-		@BeforeEach
-		void activateFeature() {
-			initUserProfileUrlProvider(urlProvider);
-		}
-
-		@Test
-		void shouldHaveCreateBescheidLink() {
-			doReturn(true).when(processor).isCreateBescheidEnabled(vorgang);
-
-			var model = processor.process(vorgangEntityModel);
-
-			assertThat(model.getLink(VorgangWithEingangProcessor.REL_BESCHEID)).isPresent().get()
-					.extracting(Link::getHref)
-					.isEqualTo("/api/vorgangs/" + VorgangHeaderTestFactory.ID + "/relations/" + VorgangHeaderTestFactory.ID + "/"
-							+ VorgangHeaderTestFactory.VERSION + "/commands");
-		}
-
-		@Test
-		void shouldHaveNoLinkIfDisabled() {
-			doReturn(false).when(processor).isCreateBescheidEnabled(vorgang);
-
-			var model = processor.process(vorgangEntityModel);
-
-			assertThat(model.getLink(VorgangWithEingangProcessor.REL_BESCHEID)).isEmpty();
-		}
-	}
-
 	@DisplayName("Process vorgang")
 	@Nested
 	class TestProcessVorgang {
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageCommandByVorgangControllerTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageCommandByVorgangControllerTest.java
index 74d31babe720c7877812b0422b00cb1d76b377c2..f8b56e2cb33333ee2e01cd40d411f201632f79d4 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageCommandByVorgangControllerTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageCommandByVorgangControllerTest.java
@@ -44,11 +44,8 @@ import org.springframework.test.web.servlet.ResultActions;
 import org.springframework.test.web.servlet.setup.MockMvcBuilders;
 
 import de.ozgcloud.alfa.common.binaryfile.BinaryFileTestFactory;
-import de.ozgcloud.alfa.common.command.CommandController.CommandByRelationController;
 import de.ozgcloud.alfa.common.command.CommandTestFactory;
-import de.ozgcloud.alfa.common.command.CreateCommand;
 import de.ozgcloud.alfa.common.command.LegacyOrder;
-import de.ozgcloud.alfa.common.user.CurrentUserService;
 import de.ozgcloud.alfa.vorgang.VorgangHeaderTestFactory;
 import de.ozgcloud.alfa.wiedervorlage.WiedervorlageCommandController.WiedervorlageCommandByVorgangController;
 import lombok.SneakyThrows;
@@ -58,15 +55,10 @@ class WiedervorlageCommandByVorgangControllerTest {
 	@Spy
 	@InjectMocks
 	private WiedervorlageCommandByVorgangController controller;
-	@Mock
-	private CommandByRelationController commandByRelationController;
-	@Mock
-	private CurrentUserService userService;
+
 	@Mock
 	private WiedervorlageService service;
 
-	@Captor
-	private ArgumentCaptor<CreateCommand> createCommandCaptor;
 	private MockMvc mockMvc;
 
 	@BeforeEach
@@ -101,7 +93,11 @@ class WiedervorlageCommandByVorgangControllerTest {
 			void shouldCallServiceToUpdateNextFrist() {
 				doRequest();
 
-				verify(service).updateNextFrist(VorgangHeaderTestFactory.ID);
+				verify(service).updateNextFrist(eq(VorgangHeaderTestFactory.ID), wiedervorlageCaptor.capture());
+				assertThat(wiedervorlageCaptor.getValue())
+						.usingRecursiveComparison()
+						.comparingOnlyFields("betreff", "beschreibung", "frist", "attachments")
+						.isEqualTo(WiedervorlageTestFactory.create());
 			}
 
 			@SneakyThrows
@@ -115,8 +111,8 @@ class WiedervorlageCommandByVorgangControllerTest {
 	@SneakyThrows
 	private ResultActions doRequest() {
 		return mockMvc.perform(
-				post(WiedervorlageCommandByVorgangController.WIEDERVORLAGE_COMMANDS_BY_VORGANG,
-						VorgangHeaderTestFactory.ID)
+						post(WiedervorlageCommandByVorgangController.WIEDERVORLAGE_COMMANDS_BY_VORGANG,
+								VorgangHeaderTestFactory.ID)
 								.content(createRequestContent())
 								.contentType(MediaType.APPLICATION_JSON))
 				.andExpect(status().is2xxSuccessful());
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageCommandControllerTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageCommandControllerTest.java
index 74bc2df86a8f6f8d98dc1fe34365654ef44c2e0e..4ab1dcc715ab7ea4234a59cf2cd79dc30f9d57bb 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageCommandControllerTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageCommandControllerTest.java
@@ -35,6 +35,8 @@ import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.Spy;
@@ -46,7 +48,6 @@ import org.springframework.test.web.servlet.setup.MockMvcBuilders;
 import de.ozgcloud.alfa.common.binaryfile.FileId;
 import de.ozgcloud.alfa.common.command.Command;
 import de.ozgcloud.alfa.common.command.CommandOrder;
-import de.ozgcloud.alfa.common.command.CommandService;
 import de.ozgcloud.alfa.common.command.CommandTestFactory;
 import de.ozgcloud.alfa.common.command.CreateCommand;
 import de.ozgcloud.alfa.common.command.LegacyOrder;
@@ -60,8 +61,6 @@ class WiedervorlageCommandControllerTest {
 	@InjectMocks
 	private WiedervorlageCommandController controller;
 	@Mock
-	private CommandService commandService;
-	@Mock
 	private WiedervorlageService service;
 
 	private MockMvc mockMvc;
@@ -80,6 +79,9 @@ class WiedervorlageCommandControllerTest {
 		@Nested
 		class ControllerMethods {
 
+			@Captor
+			private ArgumentCaptor<Wiedervorlage> wiedervorlageCaptor;
+
 			@BeforeEach
 			void init() {
 				when(service.getById(any())).thenReturn(WiedervorlageTestFactory.create());
@@ -100,7 +102,11 @@ class WiedervorlageCommandControllerTest {
 			void shouldCallServiceUpdateNextFrist() {
 				doRequest();
 
-				verify(service).updateNextFrist(VorgangHeaderTestFactory.ID);
+				verify(service).updateNextFrist(eq(VorgangHeaderTestFactory.ID), wiedervorlageCaptor.capture());
+				assertThat(wiedervorlageCaptor.getValue())
+						.usingRecursiveComparison()
+						.comparingOnlyFields("betreff", "beschreibung", "frist", "attachments")
+						.isEqualTo(WiedervorlageTestFactory.create());
 			}
 
 			@SneakyThrows
@@ -129,8 +135,8 @@ class WiedervorlageCommandControllerTest {
 			@SneakyThrows
 			private ResultActions doRequest() {
 				return mockMvc.perform(
-						post(WiedervorlageCommandController.WIEDERVORLAGE_COMMANDS, WiedervorlageTestFactory.ID, WiedervorlageTestFactory.VERSION)
-								.content(createRequestContent()).contentType(MediaType.APPLICATION_JSON))
+								post(WiedervorlageCommandController.WIEDERVORLAGE_COMMANDS, WiedervorlageTestFactory.ID, WiedervorlageTestFactory.VERSION)
+										.content(createRequestContent()).contentType(MediaType.APPLICATION_JSON))
 						.andExpect(status().is2xxSuccessful());
 			}
 
@@ -148,6 +154,9 @@ class WiedervorlageCommandControllerTest {
 		@Nested
 		class TestCreateCommand {
 
+			@Captor
+			private ArgumentCaptor<Wiedervorlage> wiedervorlageArgumentCaptor;
+
 			@DisplayName("for order 'erledigen'")
 			@Nested
 			class TestOnErledigenOrder {
@@ -158,6 +167,23 @@ class WiedervorlageCommandControllerTest {
 
 					verify(service).erledigen(any(Wiedervorlage.class));
 				}
+
+				@Test
+				void shouldUpdateNextFrist() {
+					callCreateCommand(LegacyOrder.WIEDERVORLAGE_ERLEDIGEN);
+
+					verify(service).updateNextFrist(eq(VorgangHeaderTestFactory.ID), any(Wiedervorlage.class));
+				}
+
+				@Test
+				void shouldSetWiedervorlageAsDone() {
+					callCreateCommand(LegacyOrder.WIEDERVORLAGE_ERLEDIGEN);
+
+					verify(service).updateNextFrist(eq(VorgangHeaderTestFactory.ID), wiedervorlageArgumentCaptor.capture());
+					assertThat(wiedervorlageArgumentCaptor.getValue())
+							.usingRecursiveComparison()
+							.isEqualTo(WiedervorlageTestFactory.createBuilder().done(true).build());
+				}
 			}
 
 			@DisplayName("for order 'wiedereroeffnen'")
@@ -170,6 +196,23 @@ class WiedervorlageCommandControllerTest {
 
 					verify(service).wiedereroeffnen(any(Wiedervorlage.class));
 				}
+
+				@Test
+				void shouldUpdateNextFrist() {
+					callCreateCommand(LegacyOrder.WIEDERVORLAGE_WIEDEREROEFFNEN);
+
+					verify(service).updateNextFrist(eq(VorgangHeaderTestFactory.ID), any(Wiedervorlage.class));
+				}
+
+				@Test
+				void shouldSetWiedervorlageAsOpen() {
+					callCreateCommand(LegacyOrder.WIEDERVORLAGE_WIEDEREROEFFNEN);
+
+					verify(service).updateNextFrist(eq(VorgangHeaderTestFactory.ID), wiedervorlageArgumentCaptor.capture());
+					assertThat(wiedervorlageArgumentCaptor.getValue())
+							.usingRecursiveComparison()
+							.isEqualTo(WiedervorlageTestFactory.createBuilder().done(false).build());
+				}
 			}
 
 			@DisplayName("for order 'edit'")
@@ -184,6 +227,16 @@ class WiedervorlageCommandControllerTest {
 							eq(WiedervorlageTestFactory.VERSION));
 				}
 
+				@Test
+				void shouldUpdateNextFrist() {
+					var wiedervorlage = WiedervorlageTestFactory.create();
+					doReturn(wiedervorlage).when(controller).updateWiedervorlageByCommand(any(), any());
+
+					callCreateCommand(LegacyOrder.EDIT_WIEDERVORLAGE);
+
+					verify(service).updateNextFrist(VorgangHeaderTestFactory.ID, wiedervorlage);
+				}
+
 				@DisplayName("update wiedervorlage by given command")
 				@Nested
 				class TestUpdateWiedervorlageByCommand {
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageCommandITCase.java b/alfa-service/src/test/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageCommandITCase.java
index 88a17b72ba185204edb3514e4a2bfcd90bcf53a6..d0328ea3258d380bf799e934d07e4f20227c4528 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageCommandITCase.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageCommandITCase.java
@@ -103,9 +103,9 @@ class WiedervorlageCommandITCase {
 				String content = buildContentWithBetreff(null);
 
 				doRequest(content).andExpect(status().isUnprocessableEntity())
-						.andExpect(jsonPath("$.issues.length()").value(1))
-						.andExpect(jsonPath("$.issues.[0].field").value("wiedervorlage.betreff"))
-						.andExpect(jsonPath("$.issues.[0].messageCode").value(ValidationMessageCodes.FIELD_IS_EMPTY));
+						.andExpect(jsonPath("$.invalidParams.length()").value(1))
+						.andExpect(jsonPath("$.invalidParams[0].name").value("editWiedervorlage.wiedervorlage.betreff"))
+						.andExpect(jsonPath("$.invalidParams[0].reason").value(ValidationMessageCodes.FIELD_IS_EMPTY));
 			}
 
 			@SneakyThrows
@@ -115,7 +115,7 @@ class WiedervorlageCommandITCase {
 				String content = buildContentWithBetreff("a");
 
 				doRequest(content).andExpect(status().isUnprocessableEntity())
-						.andExpect(jsonPath("$.issues.[0].field").value("wiedervorlage.betreff"));
+						.andExpect(jsonPath("$.invalidParams[0].name").value("editWiedervorlage.wiedervorlage.betreff"));
 
 			}
 
@@ -125,7 +125,8 @@ class WiedervorlageCommandITCase {
 			void minMaxParameter() {
 				String content = buildContentWithBetreff("a");
 
-				doRequest(content).andExpect(status().isUnprocessableEntity()).andExpect(jsonPath("$.issues[0].parameters.length()").value(2));
+				doRequest(content).andExpect(status().isUnprocessableEntity())
+						.andExpect(jsonPath("$.invalidParams[0].constraintParameters.length()").value(2));
 			}
 
 			@SneakyThrows
@@ -148,9 +149,9 @@ class WiedervorlageCommandITCase {
 				String content = createEditContent(WiedervorlageTestFactory.createBuilder().frist(LocalDate.parse("2020-01-01")).build());
 
 				doRequest(content).andExpect(status().isUnprocessableEntity())
-						.andExpect(jsonPath("$.issues.length()").value(1))
-						.andExpect(jsonPath("$.issues.[0].field").value("wiedervorlage.frist"))
-						.andExpect(jsonPath("$.issues.[0].messageCode").value(ValidationMessageCodes.FIELD_DATE_PAST));
+						.andExpect(jsonPath("$.invalidParams.length()").value(1))
+						.andExpect(jsonPath("$.invalidParams[0].name").value("editWiedervorlage.wiedervorlage.frist"))
+						.andExpect(jsonPath("$.invalidParams[0].reason").value(ValidationMessageCodes.FIELD_DATE_PAST));
 			}
 
 			@SneakyThrows
@@ -160,9 +161,9 @@ class WiedervorlageCommandITCase {
 				String content = createEditContent(WiedervorlageTestFactory.createBuilder().frist(null).build());
 
 				doRequest(content).andExpect(status().isUnprocessableEntity())
-						.andExpect(jsonPath("$.issues.length()").value(1))
-						.andExpect(jsonPath("$.issues.[0].field").value("wiedervorlage.frist"))
-						.andExpect(jsonPath("$.issues.[0].messageCode").value(ValidationMessageCodes.FIELD_IS_EMPTY));
+						.andExpect(jsonPath("$.invalidParams.length()").value(1))
+						.andExpect(jsonPath("$.invalidParams[0].name").value("editWiedervorlage.wiedervorlage.frist"))
+						.andExpect(jsonPath("$.invalidParams[0].reason").value(ValidationMessageCodes.FIELD_IS_EMPTY));
 			}
 
 			private String createEditContent(Wiedervorlage wiedervorlage) {
@@ -225,9 +226,9 @@ class WiedervorlageCommandITCase {
 				String content = buildContentWithBetreff(null);
 
 				doRequest(content).andExpect(status().isUnprocessableEntity())
-						.andExpect(jsonPath("$.issues.length()").value(1))
-						.andExpect(jsonPath("$.issues.[0].field").value("wiedervorlage.betreff"))
-						.andExpect(jsonPath("$.issues.[0].messageCode").value(ValidationMessageCodes.FIELD_IS_EMPTY));
+						.andExpect(jsonPath("$.invalidParams.length()").value(1))
+						.andExpect(jsonPath("$.invalidParams[0].name").value("createWiedervorlage.wiedervorlage.betreff"))
+						.andExpect(jsonPath("$.invalidParams[0].reason").value(ValidationMessageCodes.FIELD_IS_EMPTY));
 			}
 
 			@SneakyThrows
@@ -237,7 +238,7 @@ class WiedervorlageCommandITCase {
 				String content = buildContentWithBetreff("a");
 
 				doRequest(content).andExpect(status().isUnprocessableEntity())
-						.andExpect(jsonPath("$.issues.[0].field").value("wiedervorlage.betreff"));
+						.andExpect(jsonPath("$.invalidParams[0].name").value("createWiedervorlage.wiedervorlage.betreff"));
 
 			}
 
@@ -247,7 +248,8 @@ class WiedervorlageCommandITCase {
 			void minMaxParameter() {
 				String content = buildContentWithBetreff("a");
 
-				doRequest(content).andExpect(status().isUnprocessableEntity()).andExpect(jsonPath("$.issues[0].parameters.length()").value(2));
+				doRequest(content).andExpect(status().isUnprocessableEntity())
+						.andExpect(jsonPath("$.invalidParams[0].constraintParameters.length()").value(2));
 			}
 
 			@SneakyThrows
@@ -272,9 +274,9 @@ class WiedervorlageCommandITCase {
 						createWithWiedervorlage(WiedervorlageTestFactory.createBuilder().frist(LocalDate.parse("2020-01-01")).build()));
 
 				doRequest(content).andExpect(status().isUnprocessableEntity())
-						.andExpect(jsonPath("$.issues.length()").value(1))
-						.andExpect(jsonPath("$.issues.[0].field").value("wiedervorlage.frist"))
-						.andExpect(jsonPath("$.issues.[0].messageCode").value(ValidationMessageCodes.FIELD_DATE_PAST));
+						.andExpect(jsonPath("$.invalidParams.length()").value(1))
+						.andExpect(jsonPath("$.invalidParams[0].name").value("createWiedervorlage.wiedervorlage.frist"))
+						.andExpect(jsonPath("$.invalidParams[0].reason").value(ValidationMessageCodes.FIELD_DATE_PAST));
 			}
 
 			@SneakyThrows
@@ -285,9 +287,9 @@ class WiedervorlageCommandITCase {
 						createWithWiedervorlage(WiedervorlageTestFactory.createBuilder().frist(null).build()));
 
 				doRequest(content).andExpect(status().isUnprocessableEntity())
-						.andExpect(jsonPath("$.issues.length()").value(1))
-						.andExpect(jsonPath("$.issues.[0].field").value("wiedervorlage.frist"))
-						.andExpect(jsonPath("$.issues.[0].messageCode").value(ValidationMessageCodes.FIELD_IS_EMPTY));
+						.andExpect(jsonPath("$.invalidParams.length()").value(1))
+						.andExpect(jsonPath("$.invalidParams[0].name").value("createWiedervorlage.wiedervorlage.frist"))
+						.andExpect(jsonPath("$.invalidParams[0].reason").value(ValidationMessageCodes.FIELD_IS_EMPTY));
 			}
 
 		}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageServiceTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageServiceTest.java
index 3af67e13526b1f213bcbd417e2c5b2a45ae78a85..b8ab4843ea90a7148c175f4349f6a23ba62a6d39 100644
--- a/alfa-service/src/test/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageServiceTest.java
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/wiedervorlage/WiedervorlageServiceTest.java
@@ -38,7 +38,6 @@ import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
 import org.mockito.ArgumentCaptor;
-import org.mockito.ArgumentMatchers;
 import org.mockito.Captor;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
@@ -174,84 +173,93 @@ class WiedervorlageServiceTest {
 	@Nested
 	class TestUpdateNextFrist {
 
-		@Nested
-		class ServiceMethod {
+		private final Wiedervorlage wiedervorlage = WiedervorlageTestFactory.create();
+		private final Wiedervorlage foundWiedervorlage = WiedervorlageTestFactory.create();
 
-			@BeforeEach
-			void mockService() {
-				when(remoteService.findByVorgangId(any())).thenReturn(Stream.of(WiedervorlageTestFactory.create()));
-			}
+		@Captor
+		private ArgumentCaptor<Stream<Wiedervorlage>> allWiedervorlagen;
 
-			@Test
-			void shoulDoCalculation() {
-				callUpdateNextFrist();
+		@BeforeEach
+		void mockService() {
+			when(remoteService.findByVorgangId(VorgangHeaderTestFactory.ID)).thenReturn(Stream.of(foundWiedervorlage));
+			doReturn(Optional.of(WiedervorlageTestFactory.FRIST)).when(service).calculateNextFrist(any());
+		}
 
-				verify(service).calculateNextFrist(ArgumentMatchers.<Stream<Wiedervorlage>>any());
-			}
+		@Test
+		void shouldDoCalculation() {
+			callUpdateNextFrist();
 
-			@Test
-			void shouldCallFindByVorgangId() {
-				callUpdateNextFrist();
+			verify(service).calculateNextFrist(any());
+		}
 
-				verify(service).findByVorgangId(VorgangHeaderTestFactory.ID);
-			}
+		@Test
+		void shouldAddWiedervorlageToFoundWiedervorlagen() {
+			callUpdateNextFrist();
 
-			@Test
-			void shouldCallRemoteService() {
-				doReturn(Optional.of(WiedervorlageTestFactory.FRIST)).when(service).calculateNextFrist(any());
+			verify(service).calculateNextFrist(allWiedervorlagen.capture());
+			assertThat(allWiedervorlagen.getValue()).containsExactly(wiedervorlage);
+		}
 
-				callUpdateNextFrist();
+		@Test
+		void shouldCallFindByVorgangId() {
+			callUpdateNextFrist();
 
-				verify(remoteService).updateNextFrist(VorgangHeaderTestFactory.ID, Optional.of(WiedervorlageTestFactory.FRIST));
-			}
+			verify(service).findByVorgangId(VorgangHeaderTestFactory.ID);
+		}
 
-			private void callUpdateNextFrist() {
-				service.updateNextFrist(VorgangHeaderTestFactory.ID);
-			}
+		@Test
+		void shouldCallRemoteService() {
+			callUpdateNextFrist();
+
+			verify(remoteService).updateNextFrist(VorgangHeaderTestFactory.ID, Optional.of(WiedervorlageTestFactory.FRIST));
 		}
 
-		@Nested
-		class Calculation {
+		private void callUpdateNextFrist() {
+			service.updateNextFrist(VorgangHeaderTestFactory.ID, wiedervorlage);
+		}
+	}
 
-			@Test
-			void shouldReturnNullOnAllDone() {
-				var wiedervorlage = WiedervorlageTestFactory.createBuilder().frist(LocalDate.now().plus(1, ChronoUnit.DAYS)).done(true).build();
+	@Nested
+	class TestCalculateNextFrist {
 
-				var nextFrist = calculateNextFrist(Stream.of(wiedervorlage));
+		@Test
+		void shouldReturnNullOnAllDone() {
+			var wiedervorlage = WiedervorlageTestFactory.createBuilder().frist(LocalDate.now().plus(1, ChronoUnit.DAYS)).done(true).build();
 
-				assertThat(nextFrist).isEmpty();
-			}
+			var nextFrist = calculateNextFrist(Stream.of(wiedervorlage));
 
-			@Test
-			void shouldReturnEarliestFrist() {
-				var fristPast2Days = WiedervorlageTestFactory.createBuilder().frist(LocalDate.now().minus(2, ChronoUnit.DAYS)).done(false)
-						.build();
-				var fristPast1Day = WiedervorlageTestFactory.createBuilder().frist(LocalDate.now().minus(1, ChronoUnit.DAYS)).done(false).build();
-				var fristFuture1Day = WiedervorlageTestFactory.createBuilder().frist(LocalDate.now().plus(1, ChronoUnit.DAYS)).done(false)
-						.build();
-				var fristFuture2Days = WiedervorlageTestFactory.createBuilder().frist(LocalDate.now().plus(2, ChronoUnit.DAYS)).done(false)
-						.build();
-
-				var nextFrist = calculateNextFrist(Stream.of(fristPast2Days, fristPast1Day, fristFuture1Day, fristFuture2Days));
-
-				assertThat(nextFrist).contains(LocalDate.now().minus(2, ChronoUnit.DAYS));
-			}
+			assertThat(nextFrist).isEmpty();
+		}
 
-			@Test
-			void shouldReturnFristIgnoringDone() {
-				var fristPast1DayNotDone = WiedervorlageTestFactory.createBuilder().frist(LocalDate.now().plus(1, ChronoUnit.DAYS)).done(false)
-						.build();
-				var fristPast1DayDone = WiedervorlageTestFactory.createBuilder().frist(LocalDate.now().minus(1, ChronoUnit.DAYS)).done(true)
-						.build();
+		@Test
+		void shouldReturnEarliestFrist() {
+			var fristPast2Days = WiedervorlageTestFactory.createBuilder().frist(LocalDate.now().minus(2, ChronoUnit.DAYS)).done(false)
+					.build();
+			var fristPast1Day = WiedervorlageTestFactory.createBuilder().frist(LocalDate.now().minus(1, ChronoUnit.DAYS)).done(false).build();
+			var fristFuture1Day = WiedervorlageTestFactory.createBuilder().frist(LocalDate.now().plus(1, ChronoUnit.DAYS)).done(false)
+					.build();
+			var fristFuture2Days = WiedervorlageTestFactory.createBuilder().frist(LocalDate.now().plus(2, ChronoUnit.DAYS)).done(false)
+					.build();
+
+			var nextFrist = calculateNextFrist(Stream.of(fristPast2Days, fristPast1Day, fristFuture1Day, fristFuture2Days));
+
+			assertThat(nextFrist).contains(LocalDate.now().minus(2, ChronoUnit.DAYS));
+		}
 
-				var nextFrist = calculateNextFrist(Stream.of(fristPast1DayNotDone, fristPast1DayDone));
+		@Test
+		void shouldReturnFristIgnoringDone() {
+			var fristPast1DayNotDone = WiedervorlageTestFactory.createBuilder().frist(LocalDate.now().plus(1, ChronoUnit.DAYS)).done(false)
+					.build();
+			var fristPast1DayDone = WiedervorlageTestFactory.createBuilder().frist(LocalDate.now().minus(1, ChronoUnit.DAYS)).done(true)
+					.build();
 
-				assertThat(nextFrist).contains(LocalDate.now().plus(1, ChronoUnit.DAYS));
-			}
+			var nextFrist = calculateNextFrist(Stream.of(fristPast1DayNotDone, fristPast1DayDone));
 
-			private Optional<LocalDate> calculateNextFrist(Stream<Wiedervorlage> wiedervorlagen) {
-				return service.calculateNextFrist(wiedervorlagen);
-			}
+			assertThat(nextFrist).contains(LocalDate.now().plus(1, ChronoUnit.DAYS));
+		}
+
+		private Optional<LocalDate> calculateNextFrist(Stream<Wiedervorlage> wiedervorlagen) {
+			return service.calculateNextFrist(wiedervorlagen);
 		}
 	}
 }
\ No newline at end of file
diff --git a/alfa-xdomea/pom.xml b/alfa-xdomea/pom.xml
index 6f92cd2bc38e598b1dc2ab97a546ab4c331c7139..c141f0be18aa411909614eadcb8a85bc679f4837 100644
--- a/alfa-xdomea/pom.xml
+++ b/alfa-xdomea/pom.xml
@@ -31,7 +31,7 @@
 	<parent>
 		<groupId>de.ozgcloud.alfa</groupId>
 		<artifactId>alfa</artifactId>
-		<version>2.11.0-SNAPSHOT</version>
+		<version>2.12.0-SNAPSHOT</version>
 	</parent>
 
 	<artifactId>alfa-xdomea</artifactId>
diff --git a/pom.xml b/pom.xml
index 9f392394780ae740b80a1a4c48cc613ae8061467..bac9e0e473b07a7e6bbc10f857de168643db407e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -24,18 +24,20 @@
     unter der Lizenz sind dem Lizenztext zu entnehmen.
 
 -->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
 	<modelVersion>4.0.0</modelVersion>
 
 	<parent>
 		<groupId>de.ozgcloud.common</groupId>
 		<artifactId>ozgcloud-common-parent</artifactId>
-		<version>4.0.1</version>
+		<version>4.4.0-SNAPSHOT</version>
 	</parent>
 
 	<groupId>de.ozgcloud.alfa</groupId>
 	<artifactId>alfa</artifactId>
-	<version>2.11.0-SNAPSHOT</version>
+	<version>2.12.0-SNAPSHOT</version>
 	<name>Alfa Parent</name>
 	<packaging>pom</packaging>
 
@@ -54,6 +56,7 @@
 		<nachrichten-manager.version>2.7.0</nachrichten-manager.version>
 		<ozgcloud-common-pdf.version>3.0.1</ozgcloud-common-pdf.version>
 		<user-manager.version>2.2.0</user-manager.version>
+		<zufi-manager.version>1.2.0-SNAPSHOT</zufi-manager.version>
 
 		<!-- TODO: die Version über ozgcloud-common ziehen -->
 		<jjwt.version>0.11.5</jjwt.version>
@@ -103,10 +106,15 @@
 				<artifactId>vorgang-manager-interface</artifactId>
 				<version>${vorgang-manager.version}</version>
 			</dependency>
+			<dependency>
+				<groupId>de.ozgcloud.zufi</groupId>
+				<artifactId>zufi-manager-interface</artifactId>
+				<version>${zufi-manager.version}</version>
+			</dependency>
 			<dependency>
 				<groupId>de.ozgcloud.nachrichten</groupId>
 				<artifactId>nachrichten-manager-interface</artifactId>
-				<version>2.7.0</version>
+				<version>${nachrichten-manager.version}</version>
 			</dependency>
 			<dependency>
 				<groupId>de.ozgcloud.vorgang</groupId>
@@ -165,4 +173,4 @@
 			<url>https://nexus.ozg-sh.de/repository/ozg-snapshots/</url>
 		</snapshotRepository>
 	</distributionManagement>
-</project>
+</project>
\ No newline at end of file
diff --git a/src/main/helm/templates/deployment.yaml b/src/main/helm/templates/deployment.yaml
index b7221ad6bd6407099a01862c2ffb85bb5199d49d..edfb381cc4c6e5a540411f140df4b359727c044d 100644
--- a/src/main/helm/templates/deployment.yaml
+++ b/src/main/helm/templates/deployment.yaml
@@ -109,6 +109,14 @@ spec:
           value: {{ ((.Values.ozgcloud).xdomea).behoerdenschluesselUri}}
         - name: ozgcloud_xdomea_behoerdenschluesselVersion
           value: {{ ((.Values.ozgcloud).xdomea).behoerdenschluesselVersion | quote }}
+        - name: grpc_client_zufi-manager_address
+          value: {{ .Values.zufiManager.address }}
+        - name: grpc_client_zufi-manager_negotiationType
+          value: {{ (.Values.zufiManager).grpcClientNegotiationType | default "TLS" }}
+        {{- if ((.Values.ozgcloud).feature).collaborationEnabled }}
+        - name: ozgcloud_feature_collaborationEnabled
+          value: {{ ((.Values.ozgcloud).feature).collaborationEnabled | quote }}
+        {{- end }}
 
         image: "{{ .Values.image.repo }}/{{ .Values.image.name }}:{{ coalesce (.Values.image).tag "latest" }}"
         imagePullPolicy: Always
diff --git a/src/main/helm/templates/network_policy.yaml b/src/main/helm/templates/network_policy.yaml
index fde1ca628cf7ea984d4ffceefbdf13f4922c339a..ee37649c47d584833c401a8f68748ba46a4d8fd2 100644
--- a/src/main/helm/templates/network_policy.yaml
+++ b/src/main/helm/templates/network_policy.yaml
@@ -21,6 +21,18 @@ spec:
 {{ toYaml . | indent 2 }}
 {{- end }}
   egress:
+{{- if ((.Values.ozgcloud).feature).collaborationEnabled }}
+  - to:
+    - namespaceSelector:
+        matchLabels:
+          kubernetes.io/metadata.name: {{ required "zufiManager.namespace must be set if zufiManager server is enabled" (.Values.zufiManager).namespace }}
+      podSelector: 
+        matchLabels:
+          component: zufi-server
+    ports:
+      - port: 9090
+        protocol: TCP
+{{- end }}
   - to:
     - podSelector: 
         matchLabels:
diff --git a/src/main/helm/values.yaml b/src/main/helm/values.yaml
index 0e84c312bbfbcf0e243f8b32f2da91f815f353fe..1a13c1ebe2980adc97be000d735850ee5d59b900 100644
--- a/src/main/helm/values.yaml
+++ b/src/main/helm/values.yaml
@@ -31,7 +31,8 @@ replicaCount: 2 # [default: 2]
 
 usermanagerName: user-manager
 
-
+zufiManager:
+  address: zufi-server.zufi:9090
 
 # env:
 #   overrideSpringProfiles: "oc,prod"
diff --git a/src/test/helm-linter-values.yaml b/src/test/helm-linter-values.yaml
index 51a5840b198286e9e6f323503971c3e56981900f..18f72b2662390d78c5e547e1f7b90d403f8edf7d 100644
--- a/src/test/helm-linter-values.yaml
+++ b/src/test/helm-linter-values.yaml
@@ -37,3 +37,6 @@ sso:
   serverUrl: https://sso.company.local
 
 imagePullSecret: image-pull-secret
+
+zufiManager:
+  address: https://url.url
\ No newline at end of file
diff --git a/src/test/helm/deployment_collaboration_env_test.yaml b/src/test/helm/deployment_collaboration_env_test.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..4cb772d0ee55c2dc51d332ecf415bc1526e2b8b2
--- /dev/null
+++ b/src/test/helm/deployment_collaboration_env_test.yaml
@@ -0,0 +1,66 @@
+suite: deployment collaboration env
+release:
+  name: alfa
+  namespace: sh-helm-test
+templates:
+  - templates/deployment.yaml
+set:
+  baseUrl: test.company.local
+  ozgcloud:
+    environment: test
+    bundesland: sh
+    bezeichner: helm
+  sso:
+    serverUrl: https://sso.company.local
+  imagePullSecret: image-pull-secret
+tests:
+  - it: should have set zufi server address
+    set:
+      zufiManager:
+        address: url://url.url
+    asserts:
+      - contains:
+          path: spec.template.spec.containers[0].env
+          content:
+            name: grpc_client_zufi-manager_address
+            value: url://url.url
+  - it: should enable collaboration
+    set:
+      ozgcloud:
+        feature:
+          collaborationEnabled: true
+    asserts:
+      - contains:
+          path: spec.template.spec.containers[0].env
+          content:
+            name: ozgcloud_feature_collaborationEnabled
+            value: "true"
+  - it: should not enable collaboration
+    set:
+      ozgcloud:
+        feature:
+          collaborationEnabled: false
+    asserts:
+      - notContains:
+          path: spec.template.spec.containers[0].env
+          content:
+            name: ozgcloud_feature_collaborationEnabled
+          any: true
+  - it: should set negotiation type
+    set:
+      zufiManager:
+        grpcClientNegotiationType: PLAINTEXT
+    asserts:
+      - contains:
+          path: spec.template.spec.containers[0].env
+          content:
+            name: grpc_client_zufi-manager_negotiationType
+            value: PLAINTEXT
+  - it: negotiation type is TLS in standard
+    set:
+    asserts:
+      - contains:
+          path: spec.template.spec.containers[0].env
+          content:
+            name: grpc_client_zufi-manager_negotiationType
+            value: TLS
\ No newline at end of file
diff --git a/src/test/helm/network_policy_test.yaml b/src/test/helm/network_policy_test.yaml
index af65c804e62b7fb9aebb26f65f2322b536f71550..b1b35ecddd7608c33ed412b7a036829d4e966bb6 100644
--- a/src/test/helm/network_policy_test.yaml
+++ b/src/test/helm/network_policy_test.yaml
@@ -78,7 +78,7 @@ tests:
               - port: 8080
             egress:
             - to:
-              - podSelector: 
+              - podSelector:
                   matchLabels:
                     component: vorgang-manager
               ports:
@@ -223,4 +223,40 @@ tests:
         dnsServerNamespace: test-dns-server-namespace
     asserts:
       - hasDocuments:
-          count: 1
\ No newline at end of file
+          count: 1
+
+  - it: should set egress for zufi if configured
+    set:
+      networkPolicy:
+        ssoPublicIp: 1.1.1.1
+        dnsServerNamespace: test-dns-server-namespace
+      ozgcloud:
+        feature:
+          collaborationEnabled: true
+      zufiManager:
+        namespace: by-zufi-dev
+    asserts:
+      - contains:
+          path: spec.egress
+          content:
+            to:
+              - podSelector:
+                  matchLabels:
+                    component: zufi-server
+                namespaceSelector:
+                  matchLabels:
+                    kubernetes.io/metadata.name: by-zufi-dev
+            ports:
+              - port: 9090
+                protocol: TCP
+  - it: should fail to set egress for zufi if namespace is missing
+    set:
+      networkPolicy:
+        ssoPublicIp: 1.1.1.1
+        dnsServerNamespace: test-dns-server-namespace
+      ozgcloud:
+        feature:
+          collaborationEnabled: true
+    asserts:
+      - failedTemplate:
+          errorMessage: zufiManager.namespace must be set if zufiManager server is enabled
\ No newline at end of file