diff --git a/alfa-client/apps/admin-e2e/src/components/benutzer/benutzer.e2e.component.ts b/alfa-client/apps/admin-e2e/src/components/benutzer/benutzer.e2e.component.ts
index 12140f8351c958ba5388638076727ef41bee5053..673ea2c47571873cc69795547f6dc5359609e99a 100644
--- a/alfa-client/apps/admin-e2e/src/components/benutzer/benutzer.e2e.component.ts
+++ b/alfa-client/apps/admin-e2e/src/components/benutzer/benutzer.e2e.component.ts
@@ -100,11 +100,11 @@ export class BenutzerE2EComponent {
   private readonly userBenutzername: string = 'Benutzername-text-input';
   private readonly userMail: string = 'E-Mail-text-input';
 
-  private readonly adminCheckbox: string = 'Admin-checkbox-editor';
-  private readonly loeschenCheckbox: string = 'Loschen-checkbox-editor';
-  private readonly userCheckbox: string = 'User-checkbox-editor';
-  private readonly postCheckbox: string = 'Poststelle-checkbox-editor';
-  private readonly datenbeauftragungCheckbox: string = 'Datenbeauftragung-checkbox-editor';
+  private readonly adminCheckboxLabel: string = 'Admin';
+  private readonly loeschenCheckboxLabel: string = 'Löschen';
+  private readonly userCheckboxLabel: string = 'User';
+  private readonly postCheckboxLabel: string = 'Poststelle';
+  private readonly datenbeauftragungLabel: string = 'Datenbeauftragung';
 
   private readonly organisationsEinheitCheckboxSuffix: string = '-checkbox-editor';
 
@@ -115,6 +115,10 @@ export class BenutzerE2EComponent {
     return cy.getTestElement(this.headline);
   }
 
+  public getHeadline(): Cypress.Chainable<Element> {
+    return cy.getTestElement(this.headline);
+  }
+
   public getVornameInput(): Cypress.Chainable<Element> {
     return cy.getTestElement(this.userVorname);
   }
@@ -131,24 +135,24 @@ export class BenutzerE2EComponent {
     return cy.getTestElement(this.userMail);
   }
 
-  public getAdminCheckbox(): Cypress.Chainable<Element> {
-    return cy.getTestElement(this.adminCheckbox);
+  public getAdminCheckbox(): BenutzerCheckboxE2EComponent {
+    return new BenutzerCheckboxE2EComponent(this.adminCheckboxLabel);
   }
 
-  public getLoeschenCheckbox(): Cypress.Chainable<Element> {
-    return cy.getTestElement(this.loeschenCheckbox);
+  public getLoeschenCheckbox(): BenutzerCheckboxE2EComponent {
+    return new BenutzerCheckboxE2EComponent(this.loeschenCheckboxLabel);
   }
 
-  public getUserCheckbox(): Cypress.Chainable<Element> {
-    return cy.getTestElement(this.userCheckbox);
+  public getUserCheckbox(): BenutzerCheckboxE2EComponent {
+    return new BenutzerCheckboxE2EComponent(this.userCheckboxLabel);
   }
 
-  public getPostCheckbox(): Cypress.Chainable<Element> {
-    return cy.getTestElement(this.postCheckbox);
+  public getPostCheckbox(): BenutzerCheckboxE2EComponent {
+    return new BenutzerCheckboxE2EComponent(this.postCheckboxLabel);
   }
 
-  public getDatenbeauftragungCheckbox(): Cypress.Chainable<Element> {
-    return cy.getTestElement(this.datenbeauftragungCheckbox);
+  public getDatenbeauftragungCheckbox(): BenutzerCheckboxE2EComponent {
+    return new BenutzerCheckboxE2EComponent(this.datenbeauftragungLabel);
   }
 
   public getOrganisationsEinheitCheckbox(einheit: string): Cypress.Chainable<Element> {
@@ -176,3 +180,29 @@ export class BenutzerDeleteDialogE2EComponent {
     return cy.getTestElement(this.deleteButton);
   }
 }
+
+export class BenutzerCheckboxE2EComponent {
+  private rootPrefix: string;
+  private prefix: string;
+
+  private readonly adminCheckbox: string = '-checkbox-editor';
+  private readonly adminInfoButtonSuffix: string = '-role-info-button';
+  private readonly adminInfoButtonTooltipSuffix: string = '-role-info-button-tooltip';
+
+  constructor(label: string) {
+    this.rootPrefix = convertToDataTestId(label);
+    this.prefix = convertToDataTestId(label.toLocaleLowerCase());
+  }
+
+  public getRoot(): Cypress.Chainable<Element> {
+    return cy.getTestElement(`${this.rootPrefix}${this.adminCheckbox}`);
+  }
+
+  public getInfoButton(): Cypress.Chainable<Element> {
+    return cy.getTestElement(`${this.prefix}${this.adminInfoButtonSuffix}`);
+  }
+
+  public getInfoButtonTooltip(): Cypress.Chainable<Element> {
+    return cy.getTestElement(`${this.prefix}${this.adminInfoButtonTooltipSuffix}`);
+  }
+}
diff --git a/alfa-client/apps/admin-e2e/src/components/postfach/postfach.e2e.component.ts b/alfa-client/apps/admin-e2e/src/components/postfach/postfach.e2e.component.ts
index 62527711781b022092af5336db78779b0df2c914..f177cf791efec0113ceaebf9d6098e2008bc21f9 100644
--- a/alfa-client/apps/admin-e2e/src/components/postfach/postfach.e2e.component.ts
+++ b/alfa-client/apps/admin-e2e/src/components/postfach/postfach.e2e.component.ts
@@ -21,19 +21,24 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-import { haveValue, typeText } from '../../support/cypress.util';
+import { haveValue } from '../../support/cypress.util';
 
 export class PostfachE2EComponent {
+  private readonly headline: string = 'headline';
   private readonly signaturText: string = 'signature-textarea';
   private readonly saveSignaturButton: string = 'save-button';
 
+  public getHeadline(): any {
+    return cy.getTestElement(this.headline);
+  }
+
   public getSignaturText(): any {
     return cy.getTestElement(this.signaturText);
   }
 
   public setSignatur(signatur: string): void {
     this.clearSignatur();
-    typeText(this.getSignaturText(), signatur);
+    this.getSignaturText().type(signatur);
   }
 
   public clearSignatur(): void {
diff --git a/alfa-client/apps/admin-e2e/src/components/zustaendige-stelle/zustaendige-stelle-dialog.e2e.component.ts b/alfa-client/apps/admin-e2e/src/components/zustaendige-stelle/zustaendige-stelle-dialog.e2e.component.ts
index 337cad0fe51c3ba1e7bf0b1123e8f324c57dbc73..6bd293d6fc2c39febbea6bfef0fb4e66de7e22b6 100644
--- a/alfa-client/apps/admin-e2e/src/components/zustaendige-stelle/zustaendige-stelle-dialog.e2e.component.ts
+++ b/alfa-client/apps/admin-e2e/src/components/zustaendige-stelle/zustaendige-stelle-dialog.e2e.component.ts
@@ -1,5 +1,3 @@
-import { typeText } from '../../support/cypress.util';
-
 export class ZustaendigeStelleDialogE2EComponent {
   private readonly locatorZustaendigeStelleForm: string = 'search-organisations-einheit';
   private readonly locatorSearchInput: string = 'instant_search-text-input';
@@ -15,7 +13,7 @@ export class ZustaendigeStelleDialogE2EComponent {
   }
 
   public enterSearchTerm(searchTerm: string): void {
-    typeText(this.getSearchInput(), searchTerm);
+    this.getSearchInput().type(searchTerm);
   }
 
   public countSearchEntries(): Cypress.Chainable<number> {
diff --git a/alfa-client/apps/admin-e2e/src/e2e/main-tests/benutzer_rollen/benutzer-anlegen.cy.ts b/alfa-client/apps/admin-e2e/src/e2e/main-tests/benutzer_rollen/benutzer-anlegen.cy.ts
index 0d4a3c538f90b3621783a7f8ccc750429823434f..e2cbf35c6a1488905f98fa26df189a6fe1425ccd 100644
--- a/alfa-client/apps/admin-e2e/src/e2e/main-tests/benutzer_rollen/benutzer-anlegen.cy.ts
+++ b/alfa-client/apps/admin-e2e/src/e2e/main-tests/benutzer_rollen/benutzer-anlegen.cy.ts
@@ -57,4 +57,9 @@ describe('Benutzer anlegen', () => {
   it('should show created user in list', () => {
     benutzerVerifier.verifyUserInList(newUser);
   });
+
+  it('should remove benutzer', () => {
+    benutzerHelper.deleteBenutzer(newUser.username);
+    benutzerVerifier.verifyUserNotInList(newUser.username);
+  });
 });
diff --git a/alfa-client/apps/admin-e2e/src/e2e/main-tests/benutzer_rollen/benutzer_rollen.cy.ts b/alfa-client/apps/admin-e2e/src/e2e/main-tests/benutzer_rollen/benutzer_rollen.cy.ts
index 6f2aeed20740461f3dc978afdc2b974fec471f00..205d661f91365f4bea89867b41ae673a7f1e2c4a 100644
--- a/alfa-client/apps/admin-e2e/src/e2e/main-tests/benutzer_rollen/benutzer_rollen.cy.ts
+++ b/alfa-client/apps/admin-e2e/src/e2e/main-tests/benutzer_rollen/benutzer_rollen.cy.ts
@@ -21,15 +21,11 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
+import { BenutzerE2EComponent, BenutzerListE2EComponent, BenutzerListItemE2EComponent, } from 'apps/admin-e2e/src/components/benutzer/benutzer.e2e.component';
 import { E2EBenutzerHelper } from 'apps/admin-e2e/src/helper/benutzer/benutzer.helper';
 import { OrganisationsEinheitE2E } from 'apps/admin-e2e/src/model/organisations-einheit';
-import {
-  BenutzerE2EComponent,
-  BenutzerListE2EComponent,
-  BenutzerListItemE2EComponent,
-} from '../../../components/benutzer/benutzer.e2e.component';
-import { beChecked, beEnabled, contains, exist, notBeChecked, notBeEnabled } from '../../../support/cypress.util';
-import { AlfaRollen, AlfaUsers, loginAsAriane } from '../../../support/user-util';
+import { beChecked, beEnabled, contains, exist, mouseEnter, notBeChecked, notBeEnabled, visible, } from 'apps/admin-e2e/src/support/cypress.util';
+import { AlfaRollen, AlfaUsers, loginAsAriane } from 'apps/admin-e2e/src/support/user-util';
 
 describe('Benutzer und Rollen', () => {
   const benutzerPage: BenutzerE2EComponent = new BenutzerE2EComponent();
@@ -47,7 +43,7 @@ describe('Benutzer und Rollen', () => {
   it('should show users and attributes in list', () => {
     helper.openBenutzerListPage();
 
-    const ariane: BenutzerListItemE2EComponent = benutzerListPage.getItem(AlfaUsers.ARAINE);
+    const ariane: BenutzerListItemE2EComponent = benutzerListPage.getItem(AlfaUsers.ARIANE);
     exist(ariane.getRoot());
     contains(ariane.getRoles(), AlfaRollen.USER);
 
@@ -76,64 +72,93 @@ describe('Benutzer und Rollen', () => {
     exist(richard.getNoOrganisationsEinheitText());
   });
 
-  it('should show single user screen on click', () => {
+  it('should show checkbox for each role', () => {
     helper.openNewBenutzerPage();
 
-    exist(benutzerPage.getVornameInput());
-    exist(benutzerPage.getNachnameInput());
-    exist(benutzerPage.getBenutzernameInput());
-    exist(benutzerPage.getMailInput());
+    notBeChecked(benutzerPage.getAdminCheckbox().getRoot());
+    notBeChecked(benutzerPage.getDatenbeauftragungCheckbox().getRoot());
+    notBeChecked(benutzerPage.getLoeschenCheckbox().getRoot());
+    notBeChecked(benutzerPage.getUserCheckbox().getRoot());
+    notBeChecked(benutzerPage.getPostCheckbox().getRoot());
+  });
+
+  it('should deactivate other alfa roles if "loeschen" role is selected', () => {
+    benutzerPage.getLoeschenCheckbox().getRoot().click();
+    beChecked(benutzerPage.getLoeschenCheckbox().getRoot());
+    notBeEnabled(benutzerPage.getUserCheckbox().getRoot());
+    notBeEnabled(benutzerPage.getPostCheckbox().getRoot());
 
-    notBeChecked(benutzerPage.getAdminCheckbox());
-    notBeChecked(benutzerPage.getLoeschenCheckbox());
-    notBeChecked(benutzerPage.getUserCheckbox());
-    notBeChecked(benutzerPage.getPostCheckbox());
+    benutzerPage.getLoeschenCheckbox().getRoot().click();
+    notBeChecked(benutzerPage.getLoeschenCheckbox().getRoot());
+    beEnabled(benutzerPage.getUserCheckbox().getRoot());
+    beEnabled(benutzerPage.getPostCheckbox().getRoot());
   });
 
-  it('should activate loeschen checkbox and deactivate the other two checkboxes', () => {
-    benutzerPage.getLoeschenCheckbox().click();
-    beChecked(benutzerPage.getLoeschenCheckbox());
-    notBeEnabled(benutzerPage.getUserCheckbox());
-    notBeEnabled(benutzerPage.getPostCheckbox());
+  it('should deactivate other alfa roles if "user" role is selected', () => {
+    benutzerPage.getUserCheckbox().getRoot().click();
+    beChecked(benutzerPage.getUserCheckbox().getRoot());
+    notBeEnabled(benutzerPage.getLoeschenCheckbox().getRoot());
+    notBeEnabled(benutzerPage.getPostCheckbox().getRoot());
 
-    benutzerPage.getLoeschenCheckbox().click();
-    notBeChecked(benutzerPage.getLoeschenCheckbox());
-    beEnabled(benutzerPage.getUserCheckbox());
-    beEnabled(benutzerPage.getPostCheckbox());
+    benutzerPage.getUserCheckbox().getRoot().click();
+    notBeChecked(benutzerPage.getUserCheckbox().getRoot());
+    beEnabled(benutzerPage.getLoeschenCheckbox().getRoot());
+    beEnabled(benutzerPage.getPostCheckbox().getRoot());
   });
 
-  it('should additionally activate and deactivate admin checkbox', () => {
-    benutzerPage.getLoeschenCheckbox().click();
-    benutzerPage.getAdminCheckbox().click();
-    beChecked(benutzerPage.getLoeschenCheckbox());
-    beChecked(benutzerPage.getAdminCheckbox());
+  it('should deactivate other alfa roles if "poststelle" role is selected', () => {
+    benutzerPage.getPostCheckbox().getRoot().click();
+    beChecked(benutzerPage.getPostCheckbox().getRoot());
+    notBeEnabled(benutzerPage.getLoeschenCheckbox().getRoot());
+    notBeEnabled(benutzerPage.getUserCheckbox().getRoot());
 
-    benutzerPage.getAdminCheckbox().click();
-    notBeChecked(benutzerPage.getAdminCheckbox());
+    benutzerPage.getPostCheckbox().getRoot().click();
+    notBeChecked(benutzerPage.getPostCheckbox().getRoot());
+    beEnabled(benutzerPage.getLoeschenCheckbox().getRoot());
+    beEnabled(benutzerPage.getUserCheckbox().getRoot());
   });
 
-  it('should activate user checkbox and deactivate the other two checkboxes', () => {
-    benutzerPage.getLoeschenCheckbox().click();
-    benutzerPage.getUserCheckbox().click();
-    beChecked(benutzerPage.getUserCheckbox());
-    notBeEnabled(benutzerPage.getLoeschenCheckbox());
-    notBeEnabled(benutzerPage.getPostCheckbox());
-
-    benutzerPage.getUserCheckbox().click();
-    notBeChecked(benutzerPage.getUserCheckbox());
-    beEnabled(benutzerPage.getLoeschenCheckbox());
-    beEnabled(benutzerPage.getPostCheckbox());
+  it('should activate and deactivate admin roles', () => {
+    benutzerPage.getAdminCheckbox().getRoot().click();
+    benutzerPage.getDatenbeauftragungCheckbox().getRoot().click();
+    beChecked(benutzerPage.getAdminCheckbox().getRoot());
+    beChecked(benutzerPage.getDatenbeauftragungCheckbox().getRoot());
+
+    benutzerPage.getAdminCheckbox().getRoot().click();
+    benutzerPage.getDatenbeauftragungCheckbox().getRoot().click();
+    notBeChecked(benutzerPage.getAdminCheckbox().getRoot());
+    notBeChecked(benutzerPage.getDatenbeauftragungCheckbox().getRoot());
   });
 
-  it('should activate post checkbox and deactivate the other two checkboxes', () => {
-    benutzerPage.getPostCheckbox().click();
-    beChecked(benutzerPage.getPostCheckbox());
-    notBeEnabled(benutzerPage.getLoeschenCheckbox());
-    notBeEnabled(benutzerPage.getUserCheckbox());
+  describe('hint text', () => {
+    it('should be visible on admin role mouse hover', () => {
+      mouseEnter(benutzerPage.getAdminCheckbox().getInfoButton());
+
+      visible(benutzerPage.getAdminCheckbox().getInfoButtonTooltip());
+    });
+
+    it('should be visible on loeschen role mouse hover', () => {
+      mouseEnter(benutzerPage.getLoeschenCheckbox().getInfoButton());
+
+      visible(benutzerPage.getLoeschenCheckbox().getInfoButtonTooltip());
+    });
+
+    it('should be visible on user role mouse hover', () => {
+      mouseEnter(benutzerPage.getUserCheckbox().getInfoButton());
+
+      visible(benutzerPage.getUserCheckbox().getInfoButtonTooltip());
+    });
+
+    it('should be visible on poststellt role mouse hover', () => {
+      mouseEnter(benutzerPage.getPostCheckbox().getInfoButton());
+
+      visible(benutzerPage.getPostCheckbox().getInfoButtonTooltip());
+    });
+
+    it('should be visible on datenbeauftragung role mouse hover', () => {
+      mouseEnter(benutzerPage.getDatenbeauftragungCheckbox().getInfoButton());
 
-    benutzerPage.getPostCheckbox().click();
-    notBeChecked(benutzerPage.getPostCheckbox());
-    beEnabled(benutzerPage.getLoeschenCheckbox());
-    beEnabled(benutzerPage.getUserCheckbox());
+      visible(benutzerPage.getDatenbeauftragungCheckbox().getInfoButtonTooltip());
+    });
   });
 });
diff --git a/alfa-client/apps/admin-e2e/src/e2e/main-tests/navigation/ariane.cy.ts b/alfa-client/apps/admin-e2e/src/e2e/main-tests/navigation/ariane.cy.ts
index 80987765996348c4f24f3105abc2328713ef4371..64218bf8c50d791ca4f221c518a454cc54df37fe 100644
--- a/alfa-client/apps/admin-e2e/src/e2e/main-tests/navigation/ariane.cy.ts
+++ b/alfa-client/apps/admin-e2e/src/e2e/main-tests/navigation/ariane.cy.ts
@@ -1,29 +1,33 @@
-import { MainPage, waitForSpinnerToDisappear } from 'apps/admin-e2e/src/page-objects/main.po';
-import { exist, notExist } from 'apps/admin-e2e/src/support/cypress.util';
+import { MainPage } from 'apps/admin-e2e/src/page-objects/main.po';
+import { containClass, exist, notExist } from 'apps/admin-e2e/src/support/cypress.util';
 import { loginAsAriane } from 'apps/admin-e2e/src/support/user-util';
 
-describe('Navigation', () => {
+describe('Ariane Navigation', () => {
   const mainPage: MainPage = new MainPage();
 
   describe('with user ariane', () => {
     before(() => {
       loginAsAriane();
-
-      waitForSpinnerToDisappear();
     });
 
     it('should show benutzer navigation item', () => {
       exist(mainPage.getBenutzerNavigationItem());
     });
 
-    it('should show postfach navigation item', () => {
-      exist(mainPage.getPostfachNavigationItem());
-    });
-
     it('should show organisationseinheiten navigation item', () => {
       exist(mainPage.getOrganisationEinheitNavigationItem());
     });
 
+    describe('postfach navigation item', () => {
+      it('should be visible', () => {
+        exist(mainPage.getPostfachNavigationItem());
+      });
+
+      it('should be selected initial', () => {
+        containClass(mainPage.getPostfachNavigationItem(), 'border-selected');
+      });
+    });
+
     it('should hide statistik navigation item', () => {
       notExist(mainPage.getStatistikNavigationItem());
     });
diff --git a/alfa-client/apps/admin-e2e/src/e2e/main-tests/navigation/daria.cy.ts b/alfa-client/apps/admin-e2e/src/e2e/main-tests/navigation/daria.cy.ts
index 33a06a73b83c3a839b0490f96aa17ddb42106994..4fda0a2dee6bfb74ad354a08e46f27ced5e15bc6 100644
--- a/alfa-client/apps/admin-e2e/src/e2e/main-tests/navigation/daria.cy.ts
+++ b/alfa-client/apps/admin-e2e/src/e2e/main-tests/navigation/daria.cy.ts
@@ -1,43 +1,34 @@
-import { MainPage, waitForSpinnerToDisappear } from 'apps/admin-e2e/src/page-objects/main.po';
-import { exist, notExist, visible } from 'apps/admin-e2e/src/support/cypress.util';
+import { MainPage } from 'apps/admin-e2e/src/page-objects/main.po';
+import { containClass, exist, notExist } from 'apps/admin-e2e/src/support/cypress.util';
 import { loginAsDaria } from 'apps/admin-e2e/src/support/user-util';
-import { StatistikE2EComponent } from '../../../components/statistik/statistik.e2e.component';
 
-describe('Navigation', () => {
+describe('Daria Navigation', () => {
   const mainPage: MainPage = new MainPage();
 
-  const statistikPage: StatistikE2EComponent = new StatistikE2EComponent();
-
   describe('with user daria', () => {
     before(() => {
       loginAsDaria();
-
-      waitForSpinnerToDisappear();
     });
 
-    it('should hide other navigation item', () => {
+    it('should hide benutzer navigation item', () => {
       notExist(mainPage.getBenutzerNavigationItem());
     });
 
-    it('should hide postfach navigation item', () => {
-      notExist(mainPage.getPostfachNavigationItem());
-    });
-
     it('should hide organisationseinheiten navigation item', () => {
       notExist(mainPage.getOrganisationEinheitNavigationItem());
     });
 
-    describe('statistik', () => {
+    it('should hide postfach navigation item', () => {
+      notExist(mainPage.getPostfachNavigationItem());
+    });
+
+    describe('statistik navigation item', () => {
       it('should be visible', () => {
         exist(mainPage.getStatistikNavigationItem());
       });
 
       it('should be initial selected', () => {
-        mainPage.isStatistikNavigationItemSelected();
-      });
-
-      it('should show header text', () => {
-        visible(statistikPage.getHeaderText());
+        containClass(mainPage.getStatistikNavigationItem(), 'border-selected');
       });
     });
   });
diff --git a/alfa-client/apps/admin-e2e/src/e2e/main-tests/navigation/safira.cy.ts b/alfa-client/apps/admin-e2e/src/e2e/main-tests/navigation/safira.cy.ts
index 005da2e5a576948787fdeb1f26165bd250b22138..ae328f579e493b6c493a687da703269120bebbd5 100644
--- a/alfa-client/apps/admin-e2e/src/e2e/main-tests/navigation/safira.cy.ts
+++ b/alfa-client/apps/admin-e2e/src/e2e/main-tests/navigation/safira.cy.ts
@@ -1,50 +1,35 @@
-import { MainPage, waitForSpinnerToDisappear } from 'apps/admin-e2e/src/page-objects/main.po';
-import { exist, visible } from 'apps/admin-e2e/src/support/cypress.util';
+import { MainPage } from 'apps/admin-e2e/src/page-objects/main.po';
+import { containClass, exist } from 'apps/admin-e2e/src/support/cypress.util';
 import { loginAsSafira } from 'apps/admin-e2e/src/support/user-util';
-import { StatistikE2EComponent } from '../../../components/statistik/statistik.e2e.component';
 
-describe('Navigation', () => {
+describe('Safira Navigation', () => {
   const mainPage: MainPage = new MainPage();
 
-  const statistikPage: StatistikE2EComponent = new StatistikE2EComponent();
-
   describe('with user safira', () => {
     before(() => {
       loginAsSafira();
-
-      waitForSpinnerToDisappear();
     });
 
     it('should show benutzer navigation item', () => {
       exist(mainPage.getBenutzerNavigationItem());
     });
 
-    it('should show postfach navigation item', () => {
-      exist(mainPage.getPostfachNavigationItem());
-    });
-
     it('should show organisationseinheiten navigation item', () => {
       exist(mainPage.getOrganisationEinheitNavigationItem());
     });
 
-    describe('statistik', () => {
+    describe('postfach navigation item', () => {
       it('should be visible', () => {
-        exist(mainPage.getStatistikNavigationItem());
+        exist(mainPage.getPostfachNavigationItem());
       });
 
-      describe('on selection', () => {
-        before(() => {
-          mainPage.clickStatistikNavigationItem();
-        });
-
-        it('should show page on selection', () => {
-          visible(statistikPage.getHeaderText());
-        });
-
-        it('should mark navigation item as selected', () => {
-          mainPage.isStatistikNavigationItemSelected();
-        });
+      it('should be selected initial', () => {
+        containClass(mainPage.getPostfachNavigationItem(), 'border-selected');
       });
     });
+
+    it('should show statistik navigation item', () => {
+      exist(mainPage.getStatistikNavigationItem());
+    });
   });
 });
diff --git a/alfa-client/apps/admin-e2e/src/e2e/main-tests/postfach/postfach-signatur.cy.ts b/alfa-client/apps/admin-e2e/src/e2e/main-tests/postfach/postfach-signatur.cy.ts
index 1a8b4a69f8b1f19d1c2daf27b65274f46fea62e0..779a88f3c46a4724f9d188768e7344e9b992cf1d 100644
--- a/alfa-client/apps/admin-e2e/src/e2e/main-tests/postfach/postfach-signatur.cy.ts
+++ b/alfa-client/apps/admin-e2e/src/e2e/main-tests/postfach/postfach-signatur.cy.ts
@@ -21,12 +21,12 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
+import { E2EPostfachHelper } from 'apps/admin-e2e/src/helper/postfach/postfach.helper';
 import { PostfachE2EComponent } from '../../../components/postfach/postfach.e2e.component';
-import { waitForSpinnerToDisappear } from '../../../page-objects/main.po';
-import { exist } from '../../../support/cypress.util';
 import { loginAsAriane } from '../../../support/user-util';
 
-describe('Signatur', () => {
+describe('(TODO: Ist noch wackelig in Bezug auf die Eingabe in das Feld) Postfach Signatur', () => {
+  const postfachHelper: E2EPostfachHelper = new E2EPostfachHelper();
   const postfach: PostfachE2EComponent = new PostfachE2EComponent();
 
   const signaturText: string = 'Signatur\nmit\n\n\n\nZeilenumbruch\n\n';
@@ -35,12 +35,9 @@ describe('Signatur', () => {
     loginAsAriane();
   });
 
-  it('should show Postfach page', () => {
-    waitForSpinnerToDisappear();
-    exist(postfach.getSignaturText());
-  });
-
   it('should show signature input with scrollbar', () => {
+    postfachHelper.openPostfachPage();
+
     postfach.setSignatur(signaturText);
     postfach.saveSignatur();
 
diff --git a/alfa-client/apps/admin-e2e/src/helper/benutzer/benutzer.executor.ts b/alfa-client/apps/admin-e2e/src/helper/benutzer/benutzer.executor.ts
index 320db78e13e0fee0cae8dad0cd94969ad7b0e2de..f0ed339c63bbb596e72915d346b97c8390bf35c1 100644
--- a/alfa-client/apps/admin-e2e/src/helper/benutzer/benutzer.executor.ts
+++ b/alfa-client/apps/admin-e2e/src/helper/benutzer/benutzer.executor.ts
@@ -21,16 +21,16 @@ export class E2EBenutzerExecutor {
     this.benutzerPage.getMailInput().type(user.email);
 
     if (user.isAdmin) {
-      this.benutzerPage.getAdminCheckbox().click();
+      this.benutzerPage.getAdminCheckbox().getRoot().click();
     }
     if (user.isUser) {
-      this.benutzerPage.getUserCheckbox().click();
+      this.benutzerPage.getUserCheckbox().getRoot().click();
     }
     if (user.isLoeschen) {
-      this.benutzerPage.getLoeschenCheckbox().click();
+      this.benutzerPage.getLoeschenCheckbox().getRoot().click();
     }
     if (user.isPoststelle) {
-      this.benutzerPage.getPostCheckbox().click();
+      this.benutzerPage.getPostCheckbox().getRoot().click();
     }
 
     this.modifyOrganisationsEinheiten(user.organisationseinheiten);
diff --git a/alfa-client/apps/admin-e2e/src/helper/postfach/postfach.helper.ts b/alfa-client/apps/admin-e2e/src/helper/postfach/postfach.helper.ts
new file mode 100644
index 0000000000000000000000000000000000000000..90624b0151bdae26e5e1859734132d6b2e24cf62
--- /dev/null
+++ b/alfa-client/apps/admin-e2e/src/helper/postfach/postfach.helper.ts
@@ -0,0 +1,9 @@
+import { E2EPostfachNavigator } from './postfach.navigator';
+
+export class E2EPostfachHelper {
+  private readonly navigator: E2EPostfachNavigator = new E2EPostfachNavigator();
+
+  public openPostfachPage(): void {
+    this.navigator.openPostfachPage();
+  }
+}
diff --git a/alfa-client/apps/admin-e2e/src/helper/postfach/postfach.navigator.ts b/alfa-client/apps/admin-e2e/src/helper/postfach/postfach.navigator.ts
new file mode 100644
index 0000000000000000000000000000000000000000..074438baaaf22cc22669f085412ddd5d2f22046d
--- /dev/null
+++ b/alfa-client/apps/admin-e2e/src/helper/postfach/postfach.navigator.ts
@@ -0,0 +1,18 @@
+import { PostfachE2EComponent } from '../../components/postfach/postfach.e2e.component';
+import { MainPage } from '../../page-objects/main.po';
+import { exist } from '../../support/cypress.util';
+
+export class E2EPostfachNavigator {
+  private mainPage: MainPage = new MainPage();
+  private postfach: PostfachE2EComponent = new PostfachE2EComponent();
+
+  public openPostfachPage(): void {
+    this.navigateToDomain();
+    this.mainPage.getPostfachNavigationItem().click();
+    exist(this.postfach.getHeadline());
+  }
+
+  private navigateToDomain(): void {
+    this.mainPage.getHeader().getLogo().click();
+  }
+}
diff --git a/alfa-client/apps/admin-e2e/src/model/util.ts b/alfa-client/apps/admin-e2e/src/model/util.ts
index 03041ea28be5dae394e7df97d6bf38ae72d2a182..7ad5cd61ab1741c43e02532c38b711c92eb9c8dc 100644
--- a/alfa-client/apps/admin-e2e/src/model/util.ts
+++ b/alfa-client/apps/admin-e2e/src/model/util.ts
@@ -46,6 +46,7 @@ export interface AdminUserE2E {
   username: string;
   email: string;
   isAdmin?: boolean;
+  isDatenbeauftragung?: boolean;
   isUser?: boolean;
   isLoeschen?: boolean;
   isPoststelle?: boolean;
diff --git a/alfa-client/apps/admin-e2e/src/page-objects/main.po.ts b/alfa-client/apps/admin-e2e/src/page-objects/main.po.ts
index 338c98286a6f1fc02e97d52381b99de0dbfc3db6..75ecbdaefa5d692ca637af325afb58ec05f80abe 100644
--- a/alfa-client/apps/admin-e2e/src/page-objects/main.po.ts
+++ b/alfa-client/apps/admin-e2e/src/page-objects/main.po.ts
@@ -22,17 +22,16 @@
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
 import { BuildInfoE2EComponent } from '../components/buildinfo/buildinfo.e2e.component';
-import { containClass, exist } from '../support/cypress.util';
 import { HeaderE2EComponent } from './header.po';
 
 export class MainPage {
   private readonly buildInfo: BuildInfoE2EComponent = new BuildInfoE2EComponent();
   private readonly header: HeaderE2EComponent = new HeaderE2EComponent();
 
-  private readonly benutzerNavigationItem: string = 'caption-Benutzer__Rollen';
-  private readonly postfachNavigationItem: string = 'postfach-navigation';
-  private readonly organisationEinheitNavigationItem: string = 'organisations-einheiten-navigation';
-  private readonly statistikNavigationItem: string = 'statistik-navigation';
+  private readonly benutzerNavigationItem: string = 'link-path-benutzer';
+  private readonly organisationEinheitNavigationItem: string = 'link-path-organisationseinheiten';
+  private readonly postfachNavigationItem: string = 'link-path-postfach';
+  private readonly statistikNavigationItem: string = 'link-path-statistik';
 
   public getBuildInfo(): BuildInfoE2EComponent {
     return this.buildInfo;
@@ -46,41 +45,17 @@ export class MainPage {
     return cy.getTestElement(this.benutzerNavigationItem);
   }
 
-  public clickBenutzerNavigationItem(): void {
-    this.getBenutzerNavigationItem().click();
-  }
-
-  public benutzerNavigationItemIsVisible(): void {
-    exist(this.getBenutzerNavigationItem());
-  }
-
   public getPostfachNavigationItem(): Cypress.Chainable<Element> {
     return cy.getTestElement(this.postfachNavigationItem);
   }
 
-  public clickPostfachNavigationItem(): void {
-    this.getPostfachNavigationItem().click();
-  }
-
   public getOrganisationEinheitNavigationItem(): Cypress.Chainable<Element> {
     return cy.getTestElement(this.organisationEinheitNavigationItem);
   }
 
-  public clickOrganisationsEinheitenNavigationItem(): void {
-    this.getOrganisationEinheitNavigationItem().click();
-  }
-
   public getStatistikNavigationItem(): Cypress.Chainable<Element> {
     return cy.getTestElement(this.statistikNavigationItem);
   }
-
-  public clickStatistikNavigationItem(): void {
-    this.getStatistikNavigationItem().click();
-  }
-
-  public isStatistikNavigationItemSelected(): void {
-    containClass(this.getStatistikNavigationItem().get('a'), 'border-selected');
-  }
 }
 
 export function waitForSpinnerToDisappear(): boolean {
diff --git a/alfa-client/apps/admin-e2e/src/support/cypress.util.ts b/alfa-client/apps/admin-e2e/src/support/cypress.util.ts
index 637963609081aa8cddbd24bbf5f56369b80cf0ef..63f3c24872ebea08644aa85eead331dac07f1b40 100644
--- a/alfa-client/apps/admin-e2e/src/support/cypress.util.ts
+++ b/alfa-client/apps/admin-e2e/src/support/cypress.util.ts
@@ -60,10 +60,6 @@ export function mouseEnter(element: Cypress.Chainable<Element>): void {
   element.trigger('mouseenter');
 }
 
-export function mouseOver(element: Cypress.Chainable<Element>): void {
-  element.trigger('mouseover');
-}
-
 export function contains(element: Cypress.Chainable<Element>, containing: string): void {
   element.should('exist').contains(containing);
 }
@@ -128,10 +124,6 @@ export function enterWith(element: Cypress.Chainable<Element>, value: string, de
   element.type(CypressKeyboardActions.ENTER);
 }
 
-export function typeText(element: Cypress.Chainable<Element>, value: string): void {
-  element.type(value);
-}
-
 export function backspaceOn(element: Cypress.Chainable<Element>): void {
   element.type(CypressKeyboardActions.BACKSPACE);
 }
diff --git a/alfa-client/apps/admin-e2e/src/support/tech-util.ts b/alfa-client/apps/admin-e2e/src/support/tech-util.ts
index a1bbcb74ae2b53c9fc3fc05bbcab81896c4e183e..6e6c57d156a011e83fe53bee52ad26a56a384ad2 100644
--- a/alfa-client/apps/admin-e2e/src/support/tech-util.ts
+++ b/alfa-client/apps/admin-e2e/src/support/tech-util.ts
@@ -10,6 +10,6 @@ export function replaceAllWhitespaces(value: string, replaceWith: string): strin
   return value.replace(/ /g, replaceWith);
 }
 
-export function simpleTransliteration(value: string) {
+export function simpleTransliteration(value: string): string {
   return value.normalize('NFKD').replace(/[^-A-Za-z0-9_]/g, '');
 }
diff --git a/alfa-client/apps/admin-e2e/src/support/user-util.ts b/alfa-client/apps/admin-e2e/src/support/user-util.ts
index d5e7462638087a82b1e4d365e0a59e11932962e5..989e061babc526985e62ace05e516bdb2d058516 100644
--- a/alfa-client/apps/admin-e2e/src/support/user-util.ts
+++ b/alfa-client/apps/admin-e2e/src/support/user-util.ts
@@ -89,10 +89,12 @@ export enum AlfaRollen {
   LOESCHEN = 'VERWALTUNG_LOESCHEN',
   POSTSTELLE = 'VERWALTUNG_POSTSTELLE',
   ADMIN = 'ADMIN_ADMIN',
+  DATEN = 'DATENBEAUFTRAGUNG',
 }
 
 export enum AlfaUsers {
-  ARAINE = 'ariane',
+  ARIANE = 'ariane',
+  DARIA = 'daria',
   DOROTHEA = 'dorothea',
   LUDWIG = 'ludwig',
   PETER = 'peter',
diff --git a/alfa-client/apps/admin/package.json b/alfa-client/apps/admin/package.json
index 924f232583709ebf8224d6a8301cd00d84cb1307..d124f972122f91564b8d04044ab8541beb8b4ae6 100644
--- a/alfa-client/apps/admin/package.json
+++ b/alfa-client/apps/admin/package.json
@@ -1,4 +1,4 @@
 {
   "name": "admin",
-  "version": "1.6.0-SNAPSHOT"
+  "version": "1.7.0-SNAPSHOT"
 }
diff --git a/alfa-client/apps/admin/src/app/app.component.spec.ts b/alfa-client/apps/admin/src/app/app.component.spec.ts
index b0a354caa1b666ad9ad15a4527e77f8a632496c6..baa8c7fcc532a0e859fe596782a94bf7b2257803 100644
--- a/alfa-client/apps/admin/src/app/app.component.spec.ts
+++ b/alfa-client/apps/admin/src/app/app.component.spec.ts
@@ -55,29 +55,31 @@ describe('AppComponent', () => {
   const routerOutletSelector: string = getDataTestIdOf('router-outlet');
   const menuContainer: string = getDataTestIdOf('menu-container');
 
-  const authenticationService: Mock<AuthenticationService> = {
-    ...mock(AuthenticationService),
-    login: jest.fn().mockResolvedValue(Promise.resolve()),
-  };
-
-  const router: Mock<Router> = mock(Router);
-  const route: Mock<ActivatedRoute> = {
-    ...mock(ActivatedRoute),
-    snapshot: {
-      queryParams: {
-        iss: 'some-iss',
-        state: 'some-state',
-        session_state: 'some-session-state',
-        code: 'some-code',
-      },
-    } as any,
-  };
-
-  const apiRootService: Mock<ApiRootService> = mock(ApiRootService);
+  let authenticationService: Mock<AuthenticationService>;
+  let router: Mock<Router>;
+  let route: Mock<ActivatedRoute>;
+  let apiRootService: Mock<ApiRootService>;
   let configurationService: Mock<ConfigurationService>;
   let keycloakTokenService: Mock<KeycloakTokenService>;
 
   beforeEach(async () => {
+    authenticationService = {
+      ...mock(AuthenticationService),
+      login: jest.fn().mockResolvedValue(Promise.resolve()),
+    };
+    router = mock(Router);
+    route = {
+      ...mock(ActivatedRoute),
+      snapshot: {
+        queryParams: {
+          iss: 'some-iss',
+          state: 'some-state',
+          session_state: 'some-session-state',
+          code: 'some-code',
+        },
+      } as any,
+    };
+    apiRootService = mock(ApiRootService);
     configurationService = mock(ConfigurationService);
     keycloakTokenService = mock(KeycloakTokenService);
 
@@ -145,81 +147,110 @@ describe('AppComponent', () => {
         expect(authenticationService.login).toHaveBeenCalled();
       });
 
-      it('should call doAfterLoggedIn', async () => {
-        component.doAfterLoggedIn = jest.fn();
+      it('should call doAfterLoggedIn only once', async () => {
+        component._doAfterLoggedIn = jest.fn();
 
         component.ngOnInit();
         await fixture.whenStable();
 
-        expect(component.doAfterLoggedIn).toHaveBeenCalled();
+        expect(component._doAfterLoggedIn).toHaveBeenCalledTimes(1);
       });
     });
 
     describe('do after logged in', () => {
       beforeEach(() => {
-        component.evaluateInitialNavigation = jest.fn();
+        component._evaluateInitialNavigation = jest.fn();
       });
 
       it('should call apiRootService to getApiRoot', () => {
-        component.doAfterLoggedIn();
+        component._doAfterLoggedIn();
 
         expect(apiRootService.getApiRoot).toHaveBeenCalled();
       });
 
       it('should call keycloak token service to register token provider', () => {
-        component.doAfterLoggedIn();
+        component._doAfterLoggedIn();
 
         expect(keycloakTokenService.registerAccessTokenProvider).toHaveBeenCalled();
       });
 
       it('should call evaluateInitialNavigation', () => {
-        component.doAfterLoggedIn();
+        component._doAfterLoggedIn();
 
-        expect(component.evaluateInitialNavigation).toHaveBeenCalled();
+        expect(component._evaluateInitialNavigation).toHaveBeenCalled();
       });
     });
 
     describe('evaluate initial navigation', () => {
       beforeEach(() => {
-        component.evaluateNavigationByApiRoot = jest.fn();
+        component._evaluateNavigationByApiRoot = jest.fn();
+        component._subscribeApiRootForEvaluation = jest.fn();
       });
 
-      it('should call evaluate navigation by apiRoot', () => {
-        const apiRootResource: ApiRootResource = createApiRootResource();
+      it('should call router navigate', () => {
+        window.location.pathname = '/path';
+        (router as any).url = '/path';
+
+        component._evaluateInitialNavigation();
+
+        expect(router.navigate).toHaveBeenCalledWith([window.location.pathname]);
+      });
+
+      it('should call subscribe api root evaluation if url starts with /?state', () => {
+        (router as any).url = '/?state=some-state';
+
+        component._evaluateInitialNavigation();
+
+        expect(component._subscribeApiRootForEvaluation).toHaveBeenCalled();
+      });
+    });
+
+    describe('subscribeApiRootForEvaluation', () => {
+      const apiRootResource: ApiRootResource = createApiRootResource();
+
+      beforeEach(() => {
         component.apiRootStateResource$ = of(createStateResource(apiRootResource));
+        component._evaluateNavigationByApiRoot = jest.fn();
+      });
 
-        component.evaluateInitialNavigation();
+      it('should set apiRootSubscription', () => {
+        component._subscribeApiRootForEvaluation();
+
+        expect(component.apiRootSubscription).toBeDefined();
+      });
+
+      it('should call evaluate navigation by apiRoot', () => {
+        component._subscribeApiRootForEvaluation();
 
-        expect(component.evaluateNavigationByApiRoot).toHaveBeenCalledWith(apiRootResource);
+        expect(component._evaluateNavigationByApiRoot).toHaveBeenCalledWith(apiRootResource);
       });
 
       it('should NOT call evaluate navigation by apiRoot if resource is loading', () => {
-        component.apiRootStateResource$ = of(createEmptyStateResource<ApiRootResource>(true));
-        component.evaluateNavigationByApiRoot = jest.fn();
+        component.apiRootStateResource$ = of(createStateResource(apiRootResource, true));
 
-        component.evaluateInitialNavigation();
+        component._subscribeApiRootForEvaluation();
 
-        expect(component.evaluateNavigationByApiRoot).not.toHaveBeenCalled();
+        expect(component._evaluateNavigationByApiRoot).not.toHaveBeenCalled();
       });
     });
 
     describe('evaluate navigation api root', () => {
       it('should evaluate navigation by configuration if link exists', () => {
-        component.evaluateNavigationByConfiguration = jest.fn();
+        component._evaluateNavigationByConfiguration = jest.fn();
         const apiRootResource: ApiRootResource = createApiRootResource([ApiRootLinkRel.CONFIGURATION]);
 
-        component.evaluateNavigationByApiRoot(apiRootResource);
+        component._evaluateNavigationByApiRoot(apiRootResource);
 
-        expect(component.evaluateNavigationByConfiguration).toHaveBeenCalled();
+        expect(component._evaluateNavigationByConfiguration).toHaveBeenCalled();
       });
 
       it('should navigate by api root if link is missing', () => {
-        component.navigateByApiRoot = jest.fn();
+        component._navigateByApiRoot = jest.fn();
         const apiRootResource: ApiRootResource = createApiRootResource();
 
-        component.evaluateNavigationByApiRoot(apiRootResource);
+        component._evaluateNavigationByApiRoot(apiRootResource);
 
-        expect(component.navigateByApiRoot).toHaveBeenCalledWith(apiRootResource);
+        expect(component._navigateByApiRoot).toHaveBeenCalledWith(apiRootResource);
       });
     });
 
@@ -228,83 +259,83 @@ describe('AppComponent', () => {
 
       beforeEach(() => {
         configurationService.get.mockReturnValue(of(createStateResource(configurationResource)));
-        component.navigateByConfiguration = jest.fn();
+        component._navigateByConfiguration = jest.fn();
       });
 
       it('should call configuration service to get resource', () => {
-        component.evaluateNavigationByConfiguration();
+        component._evaluateNavigationByConfiguration();
 
         expect(configurationService.get).toHaveBeenCalled();
       });
 
       it('should call navigate by configuration', () => {
-        component.evaluateNavigationByConfiguration();
+        component._evaluateNavigationByConfiguration();
 
-        expect(component.navigateByConfiguration).toHaveBeenCalledWith(configurationResource);
+        expect(component._navigateByConfiguration).toHaveBeenCalledWith(configurationResource);
       });
 
       it('should NOT call navigate by configuration if resource is loading', () => {
         configurationService.get.mockReturnValue(of(createEmptyStateResource<ConfigurationResource>(true)));
 
-        component.evaluateNavigationByConfiguration();
+        component._evaluateNavigationByConfiguration();
 
-        expect(component.navigateByConfiguration).not.toHaveBeenCalled();
+        expect(component._navigateByConfiguration).not.toHaveBeenCalled();
       });
     });
 
     describe('navigate by configuration', () => {
       beforeEach(() => {
-        component.unsubscribe = jest.fn();
+        component._unsubscribe = jest.fn();
       });
 
       it('should navigate to postfach if settings link exists', () => {
-        component.navigateByConfiguration(createConfigurationResource([ConfigurationLinkRel.SETTING]));
+        component._navigateByConfiguration(createConfigurationResource([ConfigurationLinkRel.SETTING]));
 
         expect(router.navigate).toHaveBeenCalledWith(['/postfach']);
       });
 
       it('should navigate to statistik if aggregation mapping link exists', () => {
-        component.navigateByConfiguration(createConfigurationResource([ConfigurationLinkRel.AGGREGATION_MAPPINGS]));
+        component._navigateByConfiguration(createConfigurationResource([ConfigurationLinkRel.AGGREGATION_MAPPINGS]));
 
         expect(router.navigate).toHaveBeenCalledWith(['/statistik']);
       });
 
       it('should navigate to unavailable page if no link exists', () => {
-        component.navigateByConfiguration(createConfigurationResource());
+        component._navigateByConfiguration(createConfigurationResource());
 
         expect(router.navigate).toHaveBeenCalledWith(['/unavailable']);
       });
 
       it('should call unsubscribe', () => {
-        component.navigateByConfiguration(createConfigurationResource());
+        component._navigateByConfiguration(createConfigurationResource());
 
-        expect(component.unsubscribe).toHaveBeenCalled();
+        expect(component._unsubscribe).toHaveBeenCalled();
       });
     });
 
     describe('navigate by api root', () => {
       beforeEach(() => {
-        component.unsubscribe = jest.fn();
+        component._unsubscribe = jest.fn();
       });
 
       it('should navigate to benutzer und rollen if users link exists', () => {
         const apiRootResource: ApiRootResource = createApiRootResource([ApiRootLinkRel.USERS]);
 
-        component.navigateByApiRoot(apiRootResource);
+        component._navigateByApiRoot(apiRootResource);
 
         expect(router.navigate).toHaveBeenCalledWith([`/${ROUTES.BENUTZER}`]);
       });
 
       it('should navigate to unavailable page if no link exists', () => {
-        component.navigateByApiRoot(createApiRootResource());
+        component._navigateByApiRoot(createApiRootResource());
 
         expect(router.navigate).toHaveBeenCalledWith([`/${ROUTES.UNAVAILABLE}`]);
       });
 
       it('should call unsubscribe', () => {
-        component.navigateByApiRoot(createApiRootResource());
+        component._navigateByApiRoot(createApiRootResource());
 
-        expect(component.unsubscribe).toHaveBeenCalled();
+        expect(component._unsubscribe).toHaveBeenCalled();
       });
     });
 
@@ -314,7 +345,7 @@ describe('AppComponent', () => {
           component.apiRootSubscription = <any>mock(Subscription);
           component.apiRootSubscription.unsubscribe = jest.fn();
 
-          component.unsubscribe();
+          component._unsubscribe();
 
           expect(component.apiRootSubscription.unsubscribe).toHaveBeenCalled();
         });
@@ -323,7 +354,7 @@ describe('AppComponent', () => {
           component.apiRootSubscription = undefined;
           const unsubscribeSpy: jest.SpyInstance = jest.spyOn(Subscription.prototype, 'unsubscribe');
 
-          component.unsubscribe();
+          component._unsubscribe();
 
           expect(unsubscribeSpy).not.toHaveBeenCalled();
           unsubscribeSpy.mockRestore();
@@ -335,7 +366,7 @@ describe('AppComponent', () => {
           component.configurationSubscription = <any>mock(Subscription);
           component.configurationSubscription.unsubscribe = jest.fn();
 
-          component.unsubscribe();
+          component._unsubscribe();
 
           expect(component.configurationSubscription.unsubscribe).toHaveBeenCalled();
         });
@@ -344,7 +375,7 @@ describe('AppComponent', () => {
           component.apiRootSubscription = undefined;
           const unsubscribeSpy: jest.SpyInstance = jest.spyOn(Subscription.prototype, 'unsubscribe');
 
-          component.unsubscribe();
+          component._unsubscribe();
 
           expect(unsubscribeSpy).not.toHaveBeenCalled();
           unsubscribeSpy.mockRestore();
diff --git a/alfa-client/apps/admin/src/app/app.component.ts b/alfa-client/apps/admin/src/app/app.component.ts
index bb5f2013fde365c95ae01525f1b8cb170decddd6..909b6cd198bd3ccb91dd61e922abb6a1ed79210c 100644
--- a/alfa-client/apps/admin/src/app/app.component.ts
+++ b/alfa-client/apps/admin/src/app/app.component.ts
@@ -33,13 +33,7 @@ import { Component, inject, OnInit } from '@angular/core';
 import { Router, RouterLink, RouterOutlet } from '@angular/router';
 import { AuthenticationService } from '@authentication';
 import { hasLink } from '@ngxp/rest';
-import {
-  AdminLogoIconComponent,
-  NavbarComponent,
-  NavItemComponent,
-  OrgaUnitIconComponent,
-  UsersIconComponent,
-} from '@ods/system';
+import { AdminLogoIconComponent, NavbarComponent, NavItemComponent, OrgaUnitIconComponent, UsersIconComponent, } from '@ods/system';
 import { filter, Observable, Subscription } from 'rxjs';
 import { UserProfileButtonContainerComponent } from '../../../../libs/admin/user-profile/src/lib/user-menu/user-profile.button-container.component';
 import { UnavailablePageComponent } from '../pages/unavailable/unavailable-page/unavailable-page.component';
@@ -83,37 +77,49 @@ export class AppComponent implements OnInit {
   public readonly routes = ROUTES;
 
   ngOnInit(): void {
-    this.authenticationService.login().then(() => this.doAfterLoggedIn());
+    this.authenticationService.login().then(() => this._doAfterLoggedIn());
   }
 
-  doAfterLoggedIn(): void {
+  _doAfterLoggedIn(): void {
     this.apiRootStateResource$ = this.apiRootService.getApiRoot();
     this.keycloakTokenService.registerAccessTokenProvider();
-    this.evaluateInitialNavigation();
+    this._evaluateInitialNavigation();
   }
 
-  evaluateInitialNavigation(): void {
+  _evaluateInitialNavigation(): void {
+    if (this.router.url.startsWith('/?state')) {
+      this._subscribeApiRootForEvaluation();
+    } else {
+      this.refreshForGuardEvaluation();
+    }
+  }
+
+  _subscribeApiRootForEvaluation(): void {
     this.apiRootSubscription = this.apiRootStateResource$
       .pipe(filter(isLoaded), mapToResource<ApiRootResource>())
-      .subscribe((apiRootResource: ApiRootResource) => this.evaluateNavigationByApiRoot(apiRootResource));
+      .subscribe((apiRootResource: ApiRootResource) => this._evaluateNavigationByApiRoot(apiRootResource));
+  }
+
+  private refreshForGuardEvaluation(): void {
+    this.router.navigate([window.location.pathname]);
   }
 
-  evaluateNavigationByApiRoot(apiRootResource: ApiRootResource): void {
+  _evaluateNavigationByApiRoot(apiRootResource: ApiRootResource): void {
     if (hasLink(apiRootResource, ApiRootLinkRel.CONFIGURATION)) {
-      this.evaluateNavigationByConfiguration();
+      this._evaluateNavigationByConfiguration();
     } else {
-      this.navigateByApiRoot(apiRootResource);
+      this._navigateByApiRoot(apiRootResource);
     }
   }
 
-  evaluateNavigationByConfiguration(): void {
+  _evaluateNavigationByConfiguration(): void {
     this.configurationSubscription = this.configurationService
       .get()
       .pipe(filter(isLoaded), mapToResource<ApiRootResource>())
-      .subscribe((configurationResource: ConfigurationResource) => this.navigateByConfiguration(configurationResource));
+      .subscribe((configurationResource: ConfigurationResource) => this._navigateByConfiguration(configurationResource));
   }
 
-  navigateByConfiguration(configurationResource: ConfigurationResource): void {
+  _navigateByConfiguration(configurationResource: ConfigurationResource): void {
     if (hasLink(configurationResource, ConfigurationLinkRel.SETTING)) {
       this.navigate(ROUTES.POSTFACH);
     } else if (hasLink(configurationResource, ConfigurationLinkRel.AGGREGATION_MAPPINGS)) {
@@ -121,23 +127,23 @@ export class AppComponent implements OnInit {
     } else {
       this.navigate(ROUTES.UNAVAILABLE);
     }
-    this.unsubscribe();
+    this._unsubscribe();
   }
 
-  navigateByApiRoot(apiRootResource: ApiRootResource): void {
+  _navigateByApiRoot(apiRootResource: ApiRootResource): void {
     if (hasLink(apiRootResource, ApiRootLinkRel.USERS)) {
       this.navigate(ROUTES.BENUTZER);
     } else {
       this.navigate(ROUTES.UNAVAILABLE);
     }
-    this.unsubscribe();
+    this._unsubscribe();
   }
 
   private navigate(routePath: string): void {
     this.router.navigate(['/' + routePath]);
   }
 
-  unsubscribe(): void {
+  _unsubscribe(): void {
     if (isNotUndefined(this.apiRootSubscription)) this.apiRootSubscription.unsubscribe();
     if (isNotUndefined(this.configurationSubscription)) this.configurationSubscription.unsubscribe();
   }
diff --git a/alfa-client/apps/admin/src/app/app.guard.spec.ts b/alfa-client/apps/admin/src/app/app.guard.spec.ts
index 24e0a21eca4fb630c66112e19ba4b0024bf983a9..41cfe7506366e35bdd3d16d4f24d054c16eef40c 100644
--- a/alfa-client/apps/admin/src/app/app.guard.spec.ts
+++ b/alfa-client/apps/admin/src/app/app.guard.spec.ts
@@ -27,6 +27,7 @@ import { createStateResource, LinkRelationName, StateResource } from '@alfa-clie
 import { Mock, mock, useFromMock } from '@alfa-client/test-utils';
 import { TestBed } from '@angular/core/testing';
 import { ActivatedRouteSnapshot, Router, UrlTree } from '@angular/router';
+import { AuthenticationService } from '@authentication';
 import { Resource } from '@ngxp/rest';
 import { createConfigurationResource } from 'libs/admin/configuration-shared/test/configuration';
 import { createApiRootResource } from 'libs/api-root-shared/test/api-root';
@@ -139,10 +140,49 @@ describe('Guard', () => {
     const resource: Resource = createDummyResource([DummyLinkRel.DUMMY]);
     const stateResource$: Observable<StateResource<Resource>> = of(createStateResource(resource));
 
+    let authService: Mock<AuthenticationService>;
+    let router: Mock<Router>;
+
+    beforeEach(() => {
+      authService = {
+        ...mock(AuthenticationService),
+        isLoggedIn: jest.fn().mockReturnValue(true),
+      };
+      router = mock(Router);
+
+      TestBed.configureTestingModule({
+        providers: [
+          {
+            provide: Router,
+            useValue: router,
+          },
+          {
+            provide: AuthenticationService,
+            useValue: authService,
+          },
+        ],
+      });
+    });
+
     afterEach(() => {
       jest.restoreAllMocks();
     });
 
+    it('should call authenticationService isLoggedIn', () => {
+      evaluate().subscribe();
+
+      expect(authService.isLoggedIn).toHaveBeenCalled();
+    });
+
+    it('should return observable true if not logged in', (done) => {
+      authService.isLoggedIn.mockReturnValue(false);
+
+      evaluate().subscribe((resolvedValue) => {
+        expect(resolvedValue).toEqual(true);
+        done();
+      });
+    });
+
     it('should evaluate resource', () => {
       const urlTreeMock: Mock<UrlTree> = mock(UrlTree);
       const evaluateResourceSpy: jest.SpyInstance = jest
@@ -151,7 +191,7 @@ describe('Guard', () => {
 
       evaluate().subscribe();
 
-      expect(evaluateResourceSpy).toHaveBeenCalledWith(resource, DummyLinkRel.DUMMY);
+      expect(evaluateResourceSpy).toHaveBeenCalledWith(resource, DummyLinkRel.DUMMY, router);
     });
 
     it('should return evaluated boolean', (done) => {
@@ -181,34 +221,23 @@ describe('Guard', () => {
   });
 
   describe('evaluate resource', () => {
-    let router: Mock<Router>;
-
-    beforeEach(() => {
-      router = mock(Router);
-
-      TestBed.configureTestingModule({
-        providers: [
-          {
-            provide: Router,
-            useValue: router,
-          },
-        ],
-      });
-    });
+    const router: Mock<Router> = mock(Router);
 
     afterEach(() => {
       jest.restoreAllMocks();
     });
 
     it('should return true if link exists', () => {
-      const result: boolean = <boolean>evaluateResource(createDummyResource([DummyLinkRel.DUMMY]));
+      const result: boolean = <boolean>(
+        Guard.evaluateResource(createDummyResource([DummyLinkRel.DUMMY]), DummyLinkRel.DUMMY, useFromMock(router))
+      );
 
       expect(result).toBeTruthy();
     });
 
     describe('if link not exists', () => {
       it('should call router', () => {
-        evaluateResource(createDummyResource());
+        Guard.evaluateResource(createDummyResource(), DummyLinkRel.DUMMY, useFromMock(router));
 
         expect(router.createUrlTree).toHaveBeenCalledWith(['/unavailable']);
       });
@@ -217,14 +246,10 @@ describe('Guard', () => {
         const urlTree: Mock<UrlTree> = mock(UrlTree);
         router.createUrlTree.mockReturnValue(urlTree);
 
-        const result: UrlTree = <UrlTree>evaluateResource(createDummyResource());
+        const result: UrlTree = <UrlTree>Guard.evaluateResource(createDummyResource(), DummyLinkRel.DUMMY, useFromMock(router));
 
         expect(result).toEqual(urlTree);
       });
     });
-
-    function evaluateResource(dummyResource: Resource): boolean | UrlTree {
-      return <boolean | UrlTree>TestBed.runInInjectionContext(() => Guard.evaluateResource(dummyResource, DummyLinkRel.DUMMY));
-    }
   });
 });
diff --git a/alfa-client/apps/admin/src/app/app.guard.ts b/alfa-client/apps/admin/src/app/app.guard.ts
index 85625be095c256aa593faa2d0d415352258aa1e0..c61df188c0c4ea38de5c66cfe69a55e39fc780ce 100644
--- a/alfa-client/apps/admin/src/app/app.guard.ts
+++ b/alfa-client/apps/admin/src/app/app.guard.ts
@@ -21,24 +21,25 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
+import { ConfigurationService } from '@admin-client/configuration-shared';
 import { ROUTES } from '@admin-client/shared';
 import { ApiRootService } from '@alfa-client/api-root-shared';
 import { LinkRelationName, mapToResource, StateResource } from '@alfa-client/tech-shared';
 import { inject } from '@angular/core';
 import { ActivatedRouteSnapshot, CanActivateFn, Router, UrlTree } from '@angular/router';
+import { AuthenticationService } from '@authentication';
 import { hasLink, Resource } from '@ngxp/rest';
-import { filter, map, Observable } from 'rxjs';
+import { filter, map, Observable, of } from 'rxjs';
 import { GuardData } from './app.routes';
-import { ConfigurationService } from '@admin-client/configuration-shared';
 
 import * as Guard from './app.guard';
 
-export const apiRootGuard: CanActivateFn = (route: ActivatedRouteSnapshot) => {
+export const apiRootGuard: CanActivateFn = (route: ActivatedRouteSnapshot): Observable<true | UrlTree> => {
   const apiRootService: ApiRootService = inject(ApiRootService);
   return Guard.evaluate(apiRootService.getApiRoot(), getLinkRelationName(route));
 };
 
-export const configurationGuard: CanActivateFn = (route: ActivatedRouteSnapshot) => {
+export const configurationGuard: CanActivateFn = (route: ActivatedRouteSnapshot): Observable<true | UrlTree> => {
   const configurationService: ConfigurationService = inject(ConfigurationService);
   return Guard.evaluate(configurationService.get(), getLinkRelationName(route));
 };
@@ -46,11 +47,16 @@ export const configurationGuard: CanActivateFn = (route: ActivatedRouteSnapshot)
 export function evaluate(
   stateResource$: Observable<StateResource<Resource>>,
   linkRelationName: LinkRelationName,
-): Observable<boolean | UrlTree> {
+): Observable<true | UrlTree> {
+  const authService = inject(AuthenticationService);
+  const router = inject(Router);
+
+  if (!authService.isLoggedIn()) return of(true);
+
   return stateResource$.pipe(
-    filter((stateResource: StateResource<Resource>) => stateResource.loaded),
+    filter((stateResource: StateResource<Resource>): boolean => stateResource.loaded),
     mapToResource<Resource>(),
-    map((resource: Resource) => Guard.evaluateResource(resource, linkRelationName)),
+    map((resource: Resource): true | UrlTree => Guard.evaluateResource(resource, linkRelationName, router)),
   );
 }
 
@@ -58,10 +64,10 @@ function getLinkRelationName(route: ActivatedRouteSnapshot): string {
   return (<GuardData>route.data).linkRelName;
 }
 
-export function evaluateResource(resource: Resource, linkRelationName: LinkRelationName): boolean | UrlTree {
-  return hasLink(resource, linkRelationName) ? true : redirectToUnavailable();
+export function evaluateResource(resource: Resource, linkRelationName: LinkRelationName, router: Router): true | UrlTree {
+  return hasLink(resource, linkRelationName) ? true : redirectToUnavailable(router);
 }
 
-function redirectToUnavailable(): UrlTree {
-  return inject(Router).createUrlTree(['/' + ROUTES.UNAVAILABLE]);
+function redirectToUnavailable(router: Router): UrlTree {
+  return router.createUrlTree(['/' + ROUTES.UNAVAILABLE]);
 }
diff --git a/alfa-client/apps/admin/src/app/app.routes.ts b/alfa-client/apps/admin/src/app/app.routes.ts
index 279141277b1bbd700ca663d7009e886b89453429..c5974993c237ec15254220a64157b63ae0f46136 100644
--- a/alfa-client/apps/admin/src/app/app.routes.ts
+++ b/alfa-client/apps/admin/src/app/app.routes.ts
@@ -44,6 +44,7 @@ export const appRoutes: Route[] = [
     path: ROUTES.POSTFACH,
     component: PostfachPageComponent,
     title: 'Admin | Postfach',
+    runGuardsAndResolvers: 'always',
     canActivate: [configurationGuard],
     data: <GuardData>{ linkRelName: ConfigurationLinkRel.SETTING },
   },
@@ -51,6 +52,7 @@ export const appRoutes: Route[] = [
     path: ROUTES.BENUTZER,
     component: UserListPageComponent,
     title: 'Admin | Benutzer',
+    runGuardsAndResolvers: 'always',
     canActivate: [apiRootGuard],
     data: <GuardData>{ linkRelName: ApiRootLinkRel.USERS },
   },
@@ -58,6 +60,7 @@ export const appRoutes: Route[] = [
     path: ROUTES.BENUTZER_NEU,
     component: UserFormPageComponent,
     title: 'Admin | Benutzer anlegen',
+    runGuardsAndResolvers: 'always',
     canActivate: [apiRootGuard],
     data: <GuardData>{ linkRelName: ApiRootLinkRel.USERS },
   },
@@ -65,6 +68,7 @@ export const appRoutes: Route[] = [
     path: ROUTES.BENUTZER_ID,
     component: UserFormComponent,
     title: 'Admin | Benutzer bearbeiten',
+    runGuardsAndResolvers: 'always',
     canActivate: [apiRootGuard],
     data: <GuardData>{ linkRelName: ApiRootLinkRel.USERS },
   },
@@ -82,6 +86,7 @@ export const appRoutes: Route[] = [
     path: ROUTES.STATISTIK,
     component: StatistikPageComponent,
     title: 'Admin | Statistik',
+    runGuardsAndResolvers: 'always',
     canActivate: [configurationGuard],
     data: <GuardData>{ linkRelName: ConfigurationLinkRel.AGGREGATION_MAPPINGS },
   },
@@ -89,7 +94,13 @@ export const appRoutes: Route[] = [
     path: ROUTES.STATISTIK_NEU,
     component: StatistikFieldsFormPageComponent,
     title: 'Admin | Statistik weitere Felder auswerten',
+    runGuardsAndResolvers: 'always',
     canActivate: [configurationGuard],
     data: <GuardData>{ linkRelName: ConfigurationLinkRel.AGGREGATION_MAPPINGS },
   },
+  {
+    path: '**',
+    component: UnavailablePageComponent,
+    title: 'Unavailable',
+  },
 ];
diff --git a/alfa-client/apps/alfa/package.json b/alfa-client/apps/alfa/package.json
index c5322d141c5350c1a5a192513595e4a25eb170f9..db8d098a8244e0cfde3ebcd7f8e148c07ffd9316 100644
--- a/alfa-client/apps/alfa/package.json
+++ b/alfa-client/apps/alfa/package.json
@@ -1,4 +1,4 @@
 {
   "name": "alfa",
-  "version": "2.21.0-SNAPSHOT"
+  "version": "2.22.0-SNAPSHOT"
 }
diff --git a/alfa-client/apps/info/package.json b/alfa-client/apps/info/package.json
index 5861518686029b9621a5e39e361c49ce6f462690..f7b9ea61038da3ea7801ac1121b57c21816c49a6 100644
--- a/alfa-client/apps/info/package.json
+++ b/alfa-client/apps/info/package.json
@@ -1,4 +1,4 @@
 {
   "name": "info",
-  "version": "1.6.0-SNAPSHOT"
+  "version": "1.7.0-SNAPSHOT"
 }
diff --git a/alfa-client/libs/admin/keycloak-shared/src/lib/form.util.spec.ts b/alfa-client/libs/admin/keycloak-shared/src/lib/form.util.spec.ts
index be3f115f38c800b3b1cf87b3aaec5044e9b3c121..348a6c4b49125dca4d13765528be6b83f8b6e1de 100644
--- a/alfa-client/libs/admin/keycloak-shared/src/lib/form.util.spec.ts
+++ b/alfa-client/libs/admin/keycloak-shared/src/lib/form.util.spec.ts
@@ -1,18 +1,18 @@
+import { mockWindowError } from '@alfa-client/test-utils';
 import { FormControl, FormGroup } from '@angular/forms';
 import { patchForm } from './form.util';
 
 describe('FormUtil', () => {
   describe('patch form', () => {
     it('should not throw any errors', () => {
-      const errorHandler = jest.fn();
-      window.onerror = errorHandler;
+      const errorSpy: jest.SpyInstance = mockWindowError();
       const formGroup: FormGroup = new FormGroup({
         existingKey: new FormControl(null),
       });
 
       patchForm({ missingKey: 'dummyValue' }, formGroup);
 
-      expect(errorHandler).not.toHaveBeenCalled();
+      expect(errorSpy).not.toHaveBeenCalled();
     });
 
     describe('on strings', () => {
@@ -57,6 +57,15 @@ describe('FormUtil', () => {
         expect(arrayFormGroup.controls['arrayValue1'].value).toBeTruthy();
         expect(arrayFormGroup.controls['arrayValue2'].value).toBeFalsy();
       });
+
+      it('should not throw any error if control is missing', () => {
+        const errorSpy: jest.SpyInstance = mockWindowError();
+        const formGroup: FormGroup = new FormGroup({ array: new FormGroup({}) });
+
+        patchForm({ array: ['arrayValue1'] }, formGroup);
+
+        expect(errorSpy).not.toHaveBeenCalled();
+      });
     });
 
     describe('on object value', () => {
diff --git a/alfa-client/libs/admin/keycloak-shared/src/lib/form.util.ts b/alfa-client/libs/admin/keycloak-shared/src/lib/form.util.ts
index 877cf9e458b14b0d2f7732086f5e033ba3b40bf5..d57cf619353a41d05d4e9d866ca098331d4345b1 100644
--- a/alfa-client/libs/admin/keycloak-shared/src/lib/form.util.ts
+++ b/alfa-client/libs/admin/keycloak-shared/src/lib/form.util.ts
@@ -15,7 +15,9 @@ function patchNonStringValues(valueToPatch: any, formGroup: FormGroup): void {
 
 function patchNonStringValue(value: any, formGroup: FormGroup): void {
   if (Array.isArray(value)) {
-    value.forEach((oneValue: any) => formGroup.controls[oneValue].patchValue(true));
+    value.forEach((oneValue: any) => {
+      if (formGroup.contains(oneValue)) formGroup.controls[oneValue].patchValue(true);
+    });
   } else if (!isString(value) && !isBoolean(value)) {
     patchNonStringValues(value, formGroup);
   }
diff --git a/alfa-client/libs/admin/keycloak-shared/src/lib/user.repository.spec.ts b/alfa-client/libs/admin/keycloak-shared/src/lib/user.repository.spec.ts
index d0806e198efa5090d375832bbd313ca99482149b..afbb09bee049b4e79cda30ee0d97f3e4810799f9 100644
--- a/alfa-client/libs/admin/keycloak-shared/src/lib/user.repository.spec.ts
+++ b/alfa-client/libs/admin/keycloak-shared/src/lib/user.repository.spec.ts
@@ -21,7 +21,7 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-import { User } from '@admin-client/user-shared';
+import { RoleMappings, User } from '@admin-client/user-shared';
 import { UserRepository } from '@admin/keycloak-shared';
 import { StateResource } from '@alfa-client/tech-shared';
 import { Mock, mock } from '@alfa-client/test-utils';
@@ -30,10 +30,10 @@ import { faker } from '@faker-js/faker';
 import KcAdminClient from '@keycloak/keycloak-admin-client';
 import GroupRepresentation from '@keycloak/keycloak-admin-client/lib/defs/groupRepresentation';
 import MappingsRepresentation from '@keycloak/keycloak-admin-client/lib/defs/mappingsRepresentation';
-import RoleRepresentation, { RoleMappingPayload } from '@keycloak/keycloak-admin-client/lib/defs/roleRepresentation';
+import { RoleMappingPayload } from '@keycloak/keycloak-admin-client/lib/defs/roleRepresentation';
 import { Users } from '@keycloak/keycloak-admin-client/lib/resources/users';
 import { cold } from 'jest-marbles';
-import { omit } from 'lodash-es';
+import { omit, times } from 'lodash-es';
 import { throwError } from 'rxjs';
 import { createUser } from '../../../user-shared/test/user';
 import { UserFormService } from '../../../user/src/lib/user-form/user.formservice';
@@ -71,18 +71,18 @@ describe('UserRepository', () => {
       expect(kcAdminClient.users['create']).toHaveBeenCalledWith(omit(user, 'groupIds'));
     });
 
-    it('should call addUserRoles', fakeAsync(() => {
-      repository._addUserRoles = jest.fn();
+    it('should call updateUserRoles', fakeAsync(() => {
+      repository._updateUserRoles = jest.fn();
 
       repository.createInKeycloak(user).subscribe();
       tick();
 
-      expect(repository._addUserRoles).toHaveBeenCalledWith(user.id, user.clientRoles);
+      expect(repository._updateUserRoles).toHaveBeenCalledWith(user.id, user.clientRoles);
     }));
 
     it('should call sendActivationMail', (done) => {
       repository._sendActivationMail = jest.fn();
-      repository._addUserRoles = jest.fn().mockReturnValue(Promise.resolve());
+      repository._updateUserRoles = jest.fn().mockReturnValue(Promise.resolve());
 
       repository.createInKeycloak(user).subscribe(() => {
         expect(repository._sendActivationMail).toHaveBeenCalledWith(user.id);
@@ -107,7 +107,7 @@ describe('UserRepository', () => {
         update: jest.fn().mockReturnValue(Promise.resolve()),
       };
 
-      repository._addUserRoles = jest.fn().mockReturnValue(Promise.resolve());
+      repository._updateUserRoles = jest.fn().mockReturnValue(Promise.resolve());
       repository._updateUserGroups = jest.fn().mockReturnValue(Promise.resolve());
     });
 
@@ -117,11 +117,11 @@ describe('UserRepository', () => {
       expect(kcAdminClient.users['update']).toHaveBeenCalledWith({ id: user.id }, omit(user, 'groupIds'));
     });
 
-    it('should call addUserRoles', fakeAsync(() => {
+    it('should call updateUserRoles', fakeAsync(() => {
       repository.saveInKeycloak(user).subscribe();
       tick();
 
-      expect(repository._addUserRoles).toHaveBeenCalledWith(user.id, user.clientRoles);
+      expect(repository._updateUserRoles).toHaveBeenCalledWith(user.id, user.clientRoles);
     }));
 
     it('should call updateUserGroups', (done) => {
@@ -241,70 +241,197 @@ describe('UserRepository', () => {
     });
   });
 
-  describe('addUserRoles', () => {
-    it('should call addUserRolesForClient for admin', async () => {
-      repository._addUserRolesForClient = jest.fn();
+  describe('UpdateUserRoles', () => {
+    const clientId: string = faker.string.uuid();
 
-      await repository._addUserRoles(user.id, { admin: [UserFormService.ADMIN], alfa: [] });
+    beforeEach(() => {
+      repository._updateUserRolesForClient = jest.fn();
+      repository._getClientId = jest.fn().mockReturnValue(clientId);
+    });
 
-      expect(repository._addUserRolesForClient).toHaveBeenCalledWith(
-        user.id,
-        [UserFormService.ADMIN],
-        UserRepository.ADMIN_CLIENT_NAME,
-      );
+    it('should call getClientId for admin', async () => {
+      await repository._updateUserRoles(user.id, { admin: [UserFormService.ADMIN], alfa: [] });
+
+      expect(repository._getClientId).toHaveBeenCalledWith(UserRepository.ADMIN_CLIENT_NAME);
     });
 
-    it('should call addUserRolesForClient for admin', async () => {
-      repository._addUserRolesForClient = jest.fn();
+    it('should call UpdateUserRolesForClient for admin', async () => {
+      await repository._updateUserRoles(user.id, { admin: [UserFormService.ADMIN], alfa: [] });
 
-      await repository._addUserRoles(user.id, { alfa: [UserFormService.POSTSTELLE], admin: [] });
+      expect(repository._updateUserRolesForClient).toHaveBeenCalledWith(user.id, [UserFormService.ADMIN], clientId);
+    });
 
-      expect(repository._addUserRolesForClient).toHaveBeenCalledWith(
-        user.id,
-        [UserFormService.POSTSTELLE],
-        UserRepository.ALFA_CLIENT_NAME,
-      );
+    it('should call getClientId for admin', async () => {
+      await repository._updateUserRoles(user.id, { alfa: [UserFormService.POSTSTELLE], admin: [] });
+
+      expect(repository._getClientId).toHaveBeenCalledWith(UserRepository.ALFA_CLIENT_NAME);
+    });
+
+    it('should call UpdateUserRolesForClient for admin', async () => {
+      await repository._updateUserRoles(user.id, { alfa: [UserFormService.POSTSTELLE], admin: [] });
+
+      expect(repository._updateUserRolesForClient).toHaveBeenCalledWith(user.id, [UserFormService.POSTSTELLE], clientId);
     });
+  });
+
+  describe('updateUserRolesForClient', () => {
+    const clientId: string = faker.string.uuid();
+    const clientRoles: string[] = times(3, () => faker.word.sample());
+    const newClientRoleMappings: RoleMappingPayload[] = clientRoles.map((role: string) => ({
+      id: faker.string.uuid(),
+      name: role,
+    }));
+    const oldClientRoleMappings: RoleMappingPayload[] = newClientRoleMappings.slice(1);
+    const clientRoleMappings: RoleMappings = { newClientRoleMappings, oldClientRoleMappings };
 
-    it('should not call addUserRolesForClient if clientRoles alfa and admin are empty', async () => {
-      repository._addUserRolesForClient = jest.fn();
+    beforeEach(() => {
+      repository._getClientRoleMappings = jest.fn().mockReturnValue(Promise.resolve(clientRoleMappings));
+      repository._deleteUserRoles = jest.fn();
+      repository._addUserRoles = jest.fn();
+    });
+
+    it('should call getClientRoleMappings', async () => {
+      await repository._updateUserRolesForClient(user.id, clientRoles, clientId);
+
+      expect(repository._getClientRoleMappings).toHaveBeenCalledWith(user.id, clientId, clientRoles);
+    });
 
-      await repository._addUserRoles(user.id, { admin: [], alfa: [] });
+    it('should call deleteUserRoles', async () => {
+      await repository._updateUserRolesForClient(user.id, clientRoles, clientId);
 
-      expect(repository._addUserRolesForClient).not.toHaveBeenCalled();
+      expect(repository._deleteUserRoles).toHaveBeenCalledWith(user.id, clientRoleMappings, clientId);
+    });
+
+    it('should call addUserRoles', async () => {
+      await repository._updateUserRolesForClient(user.id, clientRoles, clientId);
+
+      expect(repository._addUserRoles).toHaveBeenCalledWith(user.id, clientRoleMappings, clientId);
     });
   });
 
-  describe('addUserRolesForClient', () => {
+  describe('getClientRoleMappings', () => {
     const clientId: string = faker.string.uuid();
-    const roleMapping: RoleMappingPayload[] = [{ id: faker.string.uuid(), name: faker.word.sample() }];
+    const newClientRoles: string[] = times(3, () => faker.word.sample());
+    const newClientRoleMappings: RoleMappingPayload[] = newClientRoles.map((role: string) => ({
+      id: faker.string.uuid(),
+      name: role,
+    }));
+    const oldClientRoleMappings: RoleMappingPayload[] = newClientRoleMappings.slice(1);
+    const clientRoleMappings: RoleMappings = { newClientRoleMappings, oldClientRoleMappings };
 
     beforeEach(() => {
+      repository._getOldUserRoleMappings = jest.fn().mockReturnValue(Promise.resolve(oldClientRoleMappings));
       repository._getClientId = jest.fn().mockReturnValue(Promise.resolve(clientId));
-      repository._mapUserRoles = jest.fn().mockReturnValue(Promise.resolve(roleMapping));
-      repository._addUserRolesInKeycloak = jest.fn();
+      repository._mapUserRoles = jest.fn().mockReturnValue(Promise.resolve(newClientRoleMappings));
+      repository._deleteUserRoles = jest.fn();
+      repository._addUserRoles = jest.fn();
+    });
+
+    it('should call mapUserRoles', () => {
+      repository._getClientRoleMappings(user.id, clientId, newClientRoles);
+
+      expect(repository._mapUserRoles).toHaveBeenCalledWith(clientId, newClientRoles);
+    });
+
+    it('should call get old user role mappings', async () => {
+      await repository._getClientRoleMappings(user.id, clientId, newClientRoles);
+
+      expect(repository._getOldUserRoleMappings).toHaveBeenCalledWith(user.id, clientId);
+    });
+
+    it('should return clientRoleMappings', async () => {
+      const result: RoleMappings = await repository._getClientRoleMappings(user.id, clientId, newClientRoles);
+
+      expect(result).toEqual(clientRoleMappings);
+    });
+  });
+
+  describe('getOldUserRoleMappings', () => {
+    const clientId: string = faker.string.uuid();
+    const roleMapping: RoleMappingPayload[] = [{ id: faker.string.uuid(), name: faker.word.sample() }];
+
+    beforeEach(() => {
+      kcAdminClient.users = <any>{
+        listClientRoleMappings: jest.fn().mockReturnValue(Promise.resolve(roleMapping)),
+      };
+    });
+
+    it('should call users listClientRoleMappings', () => {
+      repository._getOldUserRoleMappings(user.id, clientId);
+
+      expect(kcAdminClient.users['listClientRoleMappings']).toHaveBeenCalledWith({ id: user.id, clientUniqueId: clientId });
+    });
+
+    it('should return roleMapping', async () => {
+      const result: RoleMappingPayload[] = await repository._getOldUserRoleMappings(user.id, clientId);
+
+      expect(result).toEqual(roleMapping);
+    });
+  });
+
+  describe('deleteUserRoles', () => {
+    const clientId: string = faker.string.uuid();
+    const clientRoles: string[] = times(3, () => faker.word.sample());
+    const oldClientRoleMappings: RoleMappingPayload[] = clientRoles.map((role: string) => ({
+      id: faker.string.uuid(),
+      name: role,
+    }));
+    const newClientRoleMappings: RoleMappingPayload[] = oldClientRoleMappings.slice(1);
+    const clientRoleMappings: RoleMappings = { newClientRoleMappings, oldClientRoleMappings };
+
+    beforeEach(() => {
+      repository._deleteUserRolesInKeycloak = jest.fn();
 
       kcAdminClient.users = <any>{
         addClientRoleMappings: jest.fn().mockReturnValue(Promise.resolve()),
       };
     });
 
-    it('should call getClientId', async () => {
-      await repository._addUserRolesForClient(user.id, [UserFormService.ADMIN], UserRepository.ADMIN_CLIENT_NAME);
+    it('should call deleteUserRolesInKeycloak', async () => {
+      await repository._deleteUserRoles(user.id, clientRoleMappings, clientId);
+
+      expect(repository._deleteUserRolesInKeycloak).toHaveBeenCalledWith(user.id, clientId, [oldClientRoleMappings[0]]);
+    });
+
+    it('should call not call deleteUserRolesInKeycloak if no roles to delete', async () => {
+      await repository._deleteUserRoles(
+        user.id,
+        { oldClientRoleMappings, newClientRoleMappings: oldClientRoleMappings },
+        clientId,
+      );
 
-      expect(repository._getClientId).toHaveBeenCalled();
+      expect(repository._deleteUserRolesInKeycloak).not.toHaveBeenCalled();
     });
+  });
+
+  describe('addUserRoles', () => {
+    const clientId: string = faker.string.uuid();
+    const clientRoles: string[] = times(3, () => faker.word.sample());
+    const newClientRoleMappings: RoleMappingPayload[] = clientRoles.map((role: string) => ({
+      id: faker.string.uuid(),
+      name: role,
+    }));
+    const oldClientRoleMappings: RoleMappingPayload[] = newClientRoleMappings.slice(1);
+    const clientRoleMappings: RoleMappings = { newClientRoleMappings, oldClientRoleMappings };
 
-    it('should call getAlfaClientId', async () => {
-      await repository._addUserRolesForClient(user.id, [UserFormService.ADMIN], UserRepository.ADMIN_CLIENT_NAME);
+    beforeEach(() => {
+      repository._addUserRolesInKeycloak = jest.fn();
 
-      expect(repository._mapUserRoles).toHaveBeenCalledWith(clientId, [UserFormService.ADMIN]);
+      kcAdminClient.users = <any>{
+        addClientRoleMappings: jest.fn().mockReturnValue(Promise.resolve()),
+      };
     });
 
     it('should call addUserRolesInKeycloak', async () => {
-      await repository._addUserRolesForClient(user.id, [UserFormService.ADMIN], UserRepository.ADMIN_CLIENT_NAME);
+      await repository._addUserRoles(user.id, clientRoleMappings, clientId);
 
-      expect(repository._addUserRolesInKeycloak).toHaveBeenCalledWith(user.id, clientId, roleMapping);
+      expect(repository._addUserRolesInKeycloak).toHaveBeenCalledWith(user.id, clientId, [newClientRoleMappings[0]]);
+    });
+
+    it('should not call addUserRolesInKeycloak if no roles to add', async () => {
+      await repository._addUserRoles(user.id, { newClientRoleMappings, oldClientRoleMappings: newClientRoleMappings }, clientId);
+
+      expect(repository._addUserRolesInKeycloak).not.toHaveBeenCalled();
     });
   });
 
@@ -332,11 +459,11 @@ describe('UserRepository', () => {
 
   describe('mapUserRoles', () => {
     const clientId: string = faker.string.uuid();
-    const clientRoles: RoleRepresentation[] = Array.from({ length: 3 }, () => ({
+    const clientRoles: RoleMappingPayload[] = Array.from({ length: 3 }, () => ({
       id: faker.string.uuid(),
       name: faker.word.sample(),
     }));
-    const userRoles: string[] = clientRoles.map((role) => role.name).slice(1);
+    const userRoles: string[] = clientRoles.map((role: RoleMappingPayload): string => role.name).slice(1);
 
     beforeEach(() => {
       kcAdminClient.clients = <any>{
@@ -353,7 +480,7 @@ describe('UserRepository', () => {
     it('should return roleMapping', async () => {
       const result: RoleMappingPayload[] = await repository._mapUserRoles(clientId, userRoles);
 
-      expect(result).toEqual(clientRoles.slice(1).map((role) => ({ id: role.id, name: role.name })));
+      expect(result).toEqual(clientRoles.slice(1));
     });
 
     it('should filter roles if they are not in clientRoles', async () => {
@@ -383,6 +510,26 @@ describe('UserRepository', () => {
     });
   });
 
+  describe('deleteUserRolesInKeycloak', () => {
+    beforeEach(() => {
+      kcAdminClient.users = <any>{
+        delClientRoleMappings: jest.fn().mockReturnValue(Promise.resolve()),
+      };
+    });
+
+    it('should call kcAdminClient users delClientRoleMappings', async () => {
+      const clientId: string = faker.string.uuid();
+      const roles: RoleMappingPayload[] = Array.from({ length: 3 }, () => ({
+        id: faker.string.uuid(),
+        name: faker.word.sample(),
+      }));
+
+      await repository._deleteUserRolesInKeycloak(user.id, clientId, roles);
+
+      expect(kcAdminClient.users['delClientRoleMappings']).toHaveBeenCalledWith({ id: user.id, clientUniqueId: clientId, roles });
+    });
+  });
+
   describe('sendActivationMail', () => {
     it('should call kcAdminClient users executeActionsEmail', () => {
       const userId: string = faker.string.uuid();
diff --git a/alfa-client/libs/admin/keycloak-shared/src/lib/user.repository.ts b/alfa-client/libs/admin/keycloak-shared/src/lib/user.repository.ts
index a5df128a7de4ceb8bd71c4d2edc337078b57bcca..e5eca5be54120f7fdf51b66d130053a330ced543 100644
--- a/alfa-client/libs/admin/keycloak-shared/src/lib/user.repository.ts
+++ b/alfa-client/libs/admin/keycloak-shared/src/lib/user.repository.ts
@@ -21,18 +21,20 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-import { ClientMapping, ClientRoles, User } from '@admin-client/user-shared';
+import { ClientMapping, ClientRoles, RoleMappings, User } from '@admin-client/user-shared';
 import { createStateResource, StateResource } from '@alfa-client/tech-shared';
 import { inject, Injectable } from '@angular/core';
 import KcAdminClient from '@keycloak/keycloak-admin-client';
 import ClientRepresentation from '@keycloak/keycloak-admin-client/lib/defs/clientRepresentation';
 import GroupRepresentation from '@keycloak/keycloak-admin-client/lib/defs/groupRepresentation';
 import MappingsRepresentation from '@keycloak/keycloak-admin-client/lib/defs/mappingsRepresentation';
-import RoleRepresentation, { RoleMappingPayload } from '@keycloak/keycloak-admin-client/lib/defs/roleRepresentation';
+import { RoleMappingPayload } from '@keycloak/keycloak-admin-client/lib/defs/roleRepresentation';
 import UserRepresentation from '@keycloak/keycloak-admin-client/lib/defs/userRepresentation';
 import { isNil, omit } from 'lodash-es';
 import { catchError, concatMap, forkJoin, from, map, mergeMap, Observable, tap, throwError } from 'rxjs';
 
+import * as _ from 'lodash-es';
+
 @Injectable({
   providedIn: 'root',
 })
@@ -45,7 +47,7 @@ export class UserRepository {
   public createInKeycloak(user: User): Observable<User> {
     return from(this.kcAdminClient.users.create(omit(user, 'groupIds'))).pipe(
       concatMap(async (response: { id: string }): Promise<{ id: string }> => {
-        await this._addUserRoles(response.id, user.clientRoles);
+        await this._updateUserRoles(response.id, user.clientRoles);
         return response;
       }),
       tap((response: { id: string }): void => this._sendActivationMail(response.id)),
@@ -58,7 +60,7 @@ export class UserRepository {
     const { groupIds, ...userToSave } = user;
     return from(this.kcAdminClient.users.update({ id: user.id }, userToSave)).pipe(
       concatMap(async (): Promise<void> => {
-        await this._addUserRoles(user.id, user.clientRoles);
+        await this._updateUserRoles(user.id, user.clientRoles);
         await this._updateUserGroups(user.id, user.groupIds);
       }),
       map((): User => user),
@@ -73,8 +75,10 @@ export class UserRepository {
   }
 
   async _getOldUserGroupIds(userId: string): Promise<string[]> {
-    const oldUserGroupsReps: GroupRepresentation[] = await this.kcAdminClient.users.listGroups({ id: userId });
-    return oldUserGroupsReps.map((group: GroupRepresentation): string => group.id);
+    const oldUserGroupsReps: RoleMappingPayload[] = <RoleMappingPayload[]>(
+      await this.kcAdminClient.users.listGroups({ id: userId })
+    );
+    return _.map(oldUserGroupsReps, 'id');
   }
 
   async _deleteUserGroups(userId: string, newGroupIds: string[], oldGroupIds: string[]): Promise<void> {
@@ -87,7 +91,7 @@ export class UserRepository {
     );
   }
 
-  async _addUserGroups(userId: string, newGroupIds: string[], oldGroupIds): Promise<void> {
+  async _addUserGroups(userId: string, newGroupIds: string[], oldGroupIds: string[]): Promise<void> {
     await Promise.all(
       newGroupIds
         .filter((group) => !oldGroupIds.includes(group))
@@ -97,20 +101,54 @@ export class UserRepository {
     );
   }
 
-  async _addUserRoles(userId: string, clientRoles: ClientRoles): Promise<void> {
-    if (clientRoles.admin.length > 0) {
-      await this._addUserRolesForClient(userId, clientRoles.admin, UserRepository.ADMIN_CLIENT_NAME);
+  async _updateUserRoles(userId: string, clientRoles: ClientRoles): Promise<void> {
+    await this._updateUserRolesForClient(userId, clientRoles.admin, await this._getClientId(UserRepository.ADMIN_CLIENT_NAME));
+    await this._updateUserRolesForClient(userId, clientRoles.alfa, await this._getClientId(UserRepository.ALFA_CLIENT_NAME));
+  }
+
+  async _updateUserRolesForClient(userId: string, clientRoles: string[], clientId: string): Promise<void> {
+    const roleMappings: RoleMappings = await this._getClientRoleMappings(userId, clientId, clientRoles);
+    await this._deleteUserRoles(userId, roleMappings, clientId);
+    await this._addUserRoles(userId, roleMappings, clientId);
+  }
+
+  async _getClientRoleMappings(userId: string, clientId: string, clientRoles: string[]): Promise<RoleMappings> {
+    const newClientRoleMappings: RoleMappingPayload[] = await this._mapUserRoles(clientId, clientRoles);
+    const oldClientRoleMappings: RoleMappingPayload[] = await this._getOldUserRoleMappings(userId, clientId);
+    return { newClientRoleMappings, oldClientRoleMappings };
+  }
+
+  async _getOldUserRoleMappings(userId: string, clientId: string): Promise<RoleMappingPayload[]> {
+    return <RoleMappingPayload[]>await this.kcAdminClient.users.listClientRoleMappings({
+      id: userId,
+      clientUniqueId: clientId,
+    });
+  }
+
+  async _deleteUserRoles(userId: string, roleMappings: RoleMappings, clientId: string): Promise<void> {
+    const rolesToDelete: RoleMappingPayload[] = this.getRolesToDelete(roleMappings);
+    if (rolesToDelete.length > 0) {
+      await this._deleteUserRolesInKeycloak(userId, clientId, rolesToDelete);
     }
+  }
+
+  private getRolesToDelete(roleMappings: RoleMappings): RoleMappingPayload[] {
+    return roleMappings.oldClientRoleMappings.filter(
+      (role: RoleMappingPayload) => !_.map(roleMappings.newClientRoleMappings, 'name').includes(role.name),
+    );
+  }
 
-    if (clientRoles.alfa.length > 0) {
-      await this._addUserRolesForClient(userId, clientRoles.alfa, UserRepository.ALFA_CLIENT_NAME);
+  async _addUserRoles(userId: string, roleMappings: RoleMappings, clientId: string): Promise<void> {
+    const rolesToAdd: RoleMappingPayload[] = this.getRolesToAdd(roleMappings);
+    if (rolesToAdd.length > 0) {
+      await this._addUserRolesInKeycloak(userId, clientId, rolesToAdd);
     }
   }
 
-  async _addUserRolesForClient(userId: string, userRoles: string[], client: string): Promise<void> {
-    const clientId: string = await this._getClientId(client);
-    const roles: RoleMappingPayload[] = await this._mapUserRoles(clientId, userRoles);
-    await this._addUserRolesInKeycloak(userId, clientId, roles);
+  private getRolesToAdd(roleMappings: RoleMappings): RoleMappingPayload[] {
+    return roleMappings.newClientRoleMappings.filter(
+      (role: RoleMappingPayload) => !_.map(roleMappings.oldClientRoleMappings, 'name').includes(role.name),
+    );
   }
 
   async _getClientId(client: string): Promise<string | undefined> {
@@ -119,10 +157,8 @@ export class UserRepository {
   }
 
   async _mapUserRoles(clientId: string, userRoles: string[]): Promise<RoleMappingPayload[]> {
-    const roles: RoleRepresentation[] = await this.kcAdminClient.clients.listRoles({ id: clientId });
-    return roles
-      .filter((role: RoleRepresentation): boolean => userRoles.includes(role.name))
-      .map((role: RoleRepresentation): RoleMappingPayload => ({ id: role.id, name: role.name }));
+    const roles: RoleMappingPayload[] = <RoleMappingPayload[]>await this.kcAdminClient.clients.listRoles({ id: clientId });
+    return roles.filter((role: RoleMappingPayload): boolean => userRoles.includes(role.name));
   }
 
   async _addUserRolesInKeycloak(userId: string, clientId: string, roles: RoleMappingPayload[]): Promise<void> {
@@ -133,6 +169,14 @@ export class UserRepository {
     });
   }
 
+  async _deleteUserRolesInKeycloak(userId: string, clientId: string, roles: RoleMappingPayload[]): Promise<void> {
+    await this.kcAdminClient.users.delClientRoleMappings({
+      id: userId,
+      clientUniqueId: clientId,
+      roles,
+    });
+  }
+
   _sendActivationMail(userId: string): void {
     this.kcAdminClient.users.executeActionsEmail({
       id: userId,
@@ -208,7 +252,7 @@ export class UserRepository {
 
   private getUserGroups(user: User): Observable<string[]> {
     return from(this.kcAdminClient.users.listGroups({ id: user.id })).pipe(
-      map((groups: GroupRepresentation[]): string[] => groups.map((group: GroupRepresentation): string => group.name)),
+      map((groups: GroupRepresentation[]): string[] => _.map(groups, 'name')),
     );
   }
 
@@ -230,6 +274,6 @@ export class UserRepository {
       return [];
     }
 
-    return clientMappingsAlfa.mappings.map((role: RoleRepresentation): string => role.name);
+    return _.map(clientMappingsAlfa.mappings, 'name');
   }
 }
diff --git a/alfa-client/libs/admin/postfach/src/lib/postfach-container/postfach-container.component.html b/alfa-client/libs/admin/postfach/src/lib/postfach-container/postfach-container.component.html
index 3e8e4b49ae09ba083768eb4a1ffa4155ab1bb49c..4cc1c39f9ceae871719596a641734e16f8f966c4 100644
--- a/alfa-client/libs/admin/postfach/src/lib/postfach-container/postfach-container.component.html
+++ b/alfa-client/libs/admin/postfach/src/lib/postfach-container/postfach-container.component.html
@@ -1,2 +1,2 @@
-<h1 class="heading-1">Postfach</h1>
+<h1 class="heading-1" data-test-id="headline">Postfach</h1>
 <admin-postfach-form [postfachStateResource]="postfachStateResource$ | async" />
diff --git a/alfa-client/libs/admin/user-shared/src/lib/user.model.ts b/alfa-client/libs/admin/user-shared/src/lib/user.model.ts
index db185a0209450a60d50e2ffc89a263d62f480d12..f496e42b8734907ab060fe4872fc91cb29b14c42 100644
--- a/alfa-client/libs/admin/user-shared/src/lib/user.model.ts
+++ b/alfa-client/libs/admin/user-shared/src/lib/user.model.ts
@@ -21,7 +21,7 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-import RoleRepresentation from '@keycloak/keycloak-admin-client/lib/defs/roleRepresentation';
+import RoleRepresentation, { RoleMappingPayload } from '@keycloak/keycloak-admin-client/lib/defs/roleRepresentation';
 
 export interface User {
   id?: string;
@@ -43,3 +43,8 @@ export interface ClientRoles {
 export interface ClientMapping {
   mappings: RoleRepresentation[];
 }
+
+export interface RoleMappings {
+  newClientRoleMappings: RoleMappingPayload[];
+  oldClientRoleMappings: RoleMappingPayload[];
+}
diff --git a/alfa-client/libs/admin/user/src/lib/user-form/user-form-roles/user-form-roles.component.html b/alfa-client/libs/admin/user/src/lib/user-form/user-form-roles/user-form-roles.component.html
index 129d8476634e65400913eb770ac3f6b9c9ff017a..a8931fbcb6be03bbd9b0a5c97b7194e2e9605453 100644
--- a/alfa-client/libs/admin/user/src/lib/user-form/user-form-roles/user-form-roles.component.html
+++ b/alfa-client/libs/admin/user/src/lib/user-form/user-form-roles/user-form-roles.component.html
@@ -6,7 +6,21 @@
       <div class="flex items-center gap-2">
         <ods-checkbox-editor [formControlName]="UserFormService.ADMIN" label="Admin" inputId="admin" />
         <button
-          tooltip='Wird nur in Kombination mit "User" verwendet. Diese Rolle kann Funktionen in Keycloak und der Administration konfigurieren, z.B. Benutzer anlegen, Gruppen erstellen bzw. Organisationseinheiten hinzufügen und Rollen zuweisen.'
+          data-test-id="admin-role-info-button"
+          tooltip="Diese Rolle kann Funktionen der OZG-Cloud konfigurieren, z.B. Benutzer anlegen, Organisationseinheiten hinzufügen und Rollen zuweisen."
+        >
+          <ods-info-icon />
+        </button>
+      </div>
+      <div class="flex items-center gap-2">
+        <ods-checkbox-editor
+          [formControlName]="UserFormService.DATENBEAUFTRAGUNG"
+          label="Datenbeauftragung"
+          inputId="datenbeauftragung"
+        />
+        <button
+          data-test-id="datenbeauftragung-role-info-button"
+          tooltip='Diese Rolle kann in der Administration unter dem Menüpunkt "Statistik" Felder zur Auswertung konfigurieren. Sie ist mit allen anderen Rollen kompatibel.'
         >
           <ods-info-icon />
         </button>
@@ -17,7 +31,8 @@
       <div class="flex items-center gap-2">
         <ods-checkbox-editor [formControlName]="UserFormService.LOESCHEN" label="Löschen" inputId="delete" />
         <button
-          tooltip='Diese Rolle hat dieselben Rechte wie die Rolle "User". Zusätzlich kann "Löschen" ausgewählte Vorgänge aus Alfa löschen. Diese Rolle sollten zwei Benutzer haben, da das Löschen einem Vieraugen-Prinzip folgt.'
+          data-test-id="loschen-role-info-button"
+          tooltip='Diese Rolle hat dieselben Rechte wie die Rolle "User". Zusätzlich kann "Löschen" Löschanträge aus Alfa bestätigen. '
         >
           <ods-info-icon />
         </button>
@@ -25,16 +40,15 @@
       <div class="flex items-center gap-2">
         <ods-checkbox-editor [formControlName]="UserFormService.USER" label="User" inputId="user" />
         <button
-          tooltip='Diese Rolle kann alle Vorgänge sehen und bearbeiten, wenn diese seiner Organisationseinheit zugewiesen sind. Ist kompatibel mit "Löschen" und "Admin".'
+          data-test-id="user-role-info-button"
+          tooltip="Diese Rolle kann alle Vorgänge sehen und bearbeiten, wenn diese seiner Organisationseinheit zugewiesen sind."
         >
           <ods-info-icon />
         </button>
       </div>
       <div class="flex items-center gap-2">
         <ods-checkbox-editor [formControlName]="UserFormService.POSTSTELLE" label="Poststelle" inputId="post_office" />
-        <button
-          tooltip='Diese Rolle kann ausschließlich alle neu eingegangenen Vorgänge sehen und anderen Benutzern zuweisen. Sie sollte nur einem Benutzer zugewiesen sein. Dieser sollte keine weiteren Rollen besitzen. (Sie ist aber kompatibel mit der "Admin")'
-        >
+        <button data-test-id="poststelle-role-info-button" tooltip="Diese Rolle kann alle neu eingegangenen Vorgänge sehen.">
           <ods-info-icon />
         </button>
       </div>
diff --git a/alfa-client/libs/admin/user/src/lib/user-form/user.formservice.ts b/alfa-client/libs/admin/user/src/lib/user-form/user.formservice.ts
index 3d0960b1d363fe87688c1c9fd07f7b61ddefc67c..494673b77cf049e6219418f7a726173af20e3fd0 100644
--- a/alfa-client/libs/admin/user/src/lib/user-form/user.formservice.ts
+++ b/alfa-client/libs/admin/user/src/lib/user-form/user.formservice.ts
@@ -52,6 +52,7 @@ export class UserFormService extends KeycloakFormService<User> implements OnDest
   public static readonly GROUPS: string = 'groups';
   public static readonly ADMINISTRATION_GROUP: string = 'admin';
   public static readonly ADMIN: string = 'ADMIN_ADMIN';
+  public static readonly DATENBEAUFTRAGUNG: string = 'DATENBEAUFTRAGUNG';
   public static readonly ALFA_GROUP: string = 'alfa';
   public static readonly LOESCHEN: string = 'VERWALTUNG_LOESCHEN';
   public static readonly USER: string = 'VERWALTUNG_USER';
@@ -100,6 +101,7 @@ export class UserFormService extends KeycloakFormService<User> implements OnDest
         {
           [UserFormService.ADMINISTRATION_GROUP]: this.formBuilder.group({
             [UserFormService.ADMIN]: new FormControl(false),
+            [UserFormService.DATENBEAUFTRAGUNG]: new FormControl(false),
           }),
           [UserFormService.ALFA_GROUP]: this.formBuilder.group({
             [UserFormService.LOESCHEN]: new FormControl(false),
diff --git a/alfa-client/libs/admin/user/test/form.ts b/alfa-client/libs/admin/user/test/form.ts
index 7b3f06850de1ff16504596b38056fb3752b3d5e5..d8ac4bb73c5b96a51e5559e85d8876a1695506aa 100644
--- a/alfa-client/libs/admin/user/test/form.ts
+++ b/alfa-client/libs/admin/user/test/form.ts
@@ -12,6 +12,7 @@ export function createUserFormGroup(): UntypedFormGroup {
     [UserFormService.CLIENT_ROLES]: new UntypedFormGroup({
       [UserFormService.ADMINISTRATION_GROUP]: new UntypedFormGroup({
         [UserFormService.ADMIN]: new FormControl(false),
+        [UserFormService.DATENBEAUFTRAGUNG]: new FormControl(false),
       }),
       [UserFormService.ALFA_GROUP]: new UntypedFormGroup({
         [UserFormService.LOESCHEN]: new FormControl(false),
diff --git a/alfa-client/libs/authentication/src/lib/authentication.service.spec.ts b/alfa-client/libs/authentication/src/lib/authentication.service.spec.ts
index 486415f425de82475e9733ec3f5800cb47128c92..0e2ba5d44dd5054b2fa2b0e651b8205cf0327258 100644
--- a/alfa-client/libs/authentication/src/lib/authentication.service.spec.ts
+++ b/alfa-client/libs/authentication/src/lib/authentication.service.spec.ts
@@ -23,10 +23,11 @@
  */
 import { Mock, mock, useFromMock } from '@alfa-client/test-utils';
 import { UserProfileResource } from '@alfa-client/user-profile-shared';
+import { NavigationEnd, Router } from '@angular/router';
 import { AuthConfig, OAuthEvent, OAuthService } from 'angular-oauth2-oidc';
 import { Environment } from 'libs/environment-shared/src/lib/environment.model';
 import { createUserProfileResource } from 'libs/user-profile-shared/test/user-profile';
-import { Subject } from 'rxjs';
+import { of, Subject } from 'rxjs';
 import { createEnvironment } from '../../../environment-shared/test/environment';
 import { createAuthConfig, createOAuthEvent } from '../../test/authentication';
 import { AuthenticationService } from './authentication.service';
@@ -34,6 +35,7 @@ import { AuthenticationService } from './authentication.service';
 describe('AuthenticationService', () => {
   let service: AuthenticationService;
   let oAuthService: Mock<OAuthService>;
+  let router: Mock<Router>;
   let environmentConfig: Environment;
 
   let eventsSubject: Subject<OAuthEvent>;
@@ -41,6 +43,7 @@ describe('AuthenticationService', () => {
   beforeEach(() => {
     eventsSubject = new Subject<OAuthEvent>();
 
+    router = mock(Router);
     oAuthService = <any>{
       ...mock(OAuthService),
       loadDiscoveryDocumentAndLogin: jest.fn().mockResolvedValue(() => Promise.resolve()),
@@ -50,12 +53,19 @@ describe('AuthenticationService', () => {
     Object.defineProperty(oAuthService, 'events', { get: () => eventsSubject });
 
     environmentConfig = createEnvironment();
-    service = new AuthenticationService(useFromMock(oAuthService), environmentConfig);
+    service = new AuthenticationService(useFromMock(oAuthService), useFromMock(router), environmentConfig);
   });
 
   describe('login', () => {
     beforeEach(() => {
       service.buildAuthEventPromise = jest.fn();
+      service._initialNavigationIsDone = jest.fn().mockResolvedValue(() => Promise.resolve());
+    });
+
+    it('should wait for initial navigation', async () => {
+      await service.login();
+
+      expect(service._initialNavigationIsDone).toHaveBeenCalled();
     });
 
     it('should configure service with authConfig', async () => {
@@ -89,8 +99,8 @@ describe('AuthenticationService', () => {
       expect(service.buildAuthEventPromise).toHaveBeenCalled();
     });
 
-    it('should load discovery document and login', () => {
-      service.login();
+    it('should load discovery document and login', async () => {
+      await service.login();
 
       expect(oAuthService.loadDiscoveryDocumentAndLogin).toHaveBeenCalled();
     });
@@ -105,6 +115,16 @@ describe('AuthenticationService', () => {
     });
   });
 
+  describe('_initialNavigationIsDone', () => {
+    it('should wait for navigation end event', async () => {
+      (router.events as any) = of(new NavigationEnd(0, 'url1', 'url1'));
+
+      const promise: Promise<void> = service._initialNavigationIsDone();
+
+      await expect(promise).resolves.toBeUndefined();
+    });
+  });
+
   describe('build auth event promise', () => {
     const event: OAuthEvent = createOAuthEvent();
 
@@ -350,4 +370,20 @@ describe('AuthenticationService', () => {
       expect(oAuthService.revokeTokenAndLogout).toHaveBeenCalled();
     });
   });
+
+  describe('isLoggedIn', () => {
+    it('should call oAuthService hasValidAccessToken', () => {
+      service.isLoggedIn();
+
+      expect(oAuthService.hasValidAccessToken).toHaveBeenCalled();
+    });
+
+    it('should return result', () => {
+      oAuthService.hasValidAccessToken.mockReturnValue(true);
+
+      const isLoggedIn: boolean = service.isLoggedIn();
+
+      expect(isLoggedIn).toBe(true);
+    });
+  });
 });
diff --git a/alfa-client/libs/authentication/src/lib/authentication.service.ts b/alfa-client/libs/authentication/src/lib/authentication.service.ts
index e350dcafe7cb9312799db97db5eb50c0d25c8319..4918b8f8d7e95c9ff71b2c53a7aa487266e91155 100644
--- a/alfa-client/libs/authentication/src/lib/authentication.service.ts
+++ b/alfa-client/libs/authentication/src/lib/authentication.service.ts
@@ -23,11 +23,12 @@
  */
 import { Environment, ENVIRONMENT_CONFIG } from '@alfa-client/environment-shared';
 import { Inject, Injectable } from '@angular/core';
+import { NavigationEnd, Router } from '@angular/router';
 import { AuthConfig, OAuthEvent, OAuthService } from 'angular-oauth2-oidc';
 import { JwksValidationHandler } from 'angular-oauth2-oidc-jwks';
 import { UserProfileResource } from 'libs/user-profile-shared/src/lib/user-profile.model';
 import { getUserNameInitials } from 'libs/user-profile-shared/src/lib/user-profile.util';
-import { filter, Subscription } from 'rxjs';
+import { filter, firstValueFrom, Subscription } from 'rxjs';
 
 @Injectable({ providedIn: 'root' })
 export class AuthenticationService {
@@ -37,10 +38,13 @@ export class AuthenticationService {
 
   constructor(
     private oAuthService: OAuthService,
+    private router: Router,
     @Inject(ENVIRONMENT_CONFIG) private envConfig: Environment,
   ) {}
 
   public async login(): Promise<void> {
+    await this._initialNavigationIsDone();
+
     this.oAuthService.configure(this.buildConfiguration());
     this.oAuthService.setupAutomaticSilentRefresh();
     this.oAuthService.tokenValidationHandler = new JwksValidationHandler();
@@ -50,6 +54,10 @@ export class AuthenticationService {
     return eventPromise;
   }
 
+  async _initialNavigationIsDone(): Promise<void> {
+    await firstValueFrom(this.router.events.pipe(filter((event) => event instanceof NavigationEnd)));
+  }
+
   buildAuthEventPromise(): Promise<void> {
     return new Promise<void>((resolve, reject) => this.handleAuthEventsForPromise(resolve, reject));
   }
@@ -90,7 +98,7 @@ export class AuthenticationService {
     return {
       issuer: this.envConfig.authServer + '/realms/' + this.envConfig.realm,
       tokenEndpoint: this.envConfig.authServer + '/realms/' + this.envConfig.realm + '/protocol/openid-connect/token',
-      redirectUri: window.location.origin + '/',
+      redirectUri: window.location.origin + window.location.pathname,
       clientId: this.envConfig.clientId,
       scope: 'openid profile',
       requireHttps: false,
@@ -119,4 +127,8 @@ export class AuthenticationService {
   public logout(): void {
     this.oAuthService.revokeTokenAndLogout();
   }
+
+  public isLoggedIn(): boolean {
+    return this.oAuthService.hasValidAccessToken();
+  }
 }
diff --git a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/form/bescheid-wizard-dokumente-hochladen-form.component.html b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/form/bescheid-wizard-dokumente-hochladen-form.component.html
index edd8aff832236fb11a9b372a47c40f4bbb8d06d3..007a02ec854d9001c4eaef88f688760d6db3fa8d 100644
--- a/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/form/bescheid-wizard-dokumente-hochladen-form.component.html
+++ b/alfa-client/libs/bescheid/src/lib/bescheid-wizard-container/bescheid-wizard/dokumente-hochladen-container/form/bescheid-wizard-dokumente-hochladen-form.component.html
@@ -23,7 +23,7 @@
     unter der Lizenz sind dem Lizenztext zu entnehmen.
 
 -->
-<div class="mt-4 flex flex-col gap-4">
+<div class="mt-4 flex max-w-72 flex-col gap-4">
   @if (bescheidResource | hasLink: BescheidLinkRel.CREATE_DOCUMENT) {
     <alfa-bescheid-wizard-create-document-button-container
       [bescheidResource]="bescheidResource"
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 9d26d35e6e9f7a882e0bad43d87f69fcb7562cc3..f32b65dd32e10f8754cb8e138122312211bdac26 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
@@ -21,7 +21,7 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-import { BlobWithFileName, createEmptyStateResource, createStateResource, StateResource } from '@alfa-client/tech-shared';
+import { BlobWithFileName, createEmptyStateResource, createErrorStateResource, createStateResource, StateResource, } from '@alfa-client/tech-shared';
 import { Mock, mock, useFromMock } from '@alfa-client/test-utils';
 import { SnackBarService } from '@alfa-client/ui';
 import { HttpErrorResponse, HttpResponse } from '@angular/common/http';
@@ -36,6 +36,7 @@ import { DummyLinkRel } from 'libs/tech-shared/test/dummy';
 import { createDummyResource } from 'libs/tech-shared/test/resource';
 import { uniqueId } from 'lodash-es';
 import { Observable, of, throwError } from 'rxjs';
+import { createApiError } from '../../../tech-shared/test/error';
 import { createHttpErrorResponse } from '../../../tech-shared/test/http';
 import { multipleCold, singleCold, singleHot } from '../../../tech-shared/test/marbles';
 import { BinaryFileResource, FileUploadType, ToUploadFile, UploadFile, UploadFileByIdentifier } from './binary-file.model';
@@ -98,11 +99,18 @@ describe('BinaryFileService', () => {
     const toUploadFile: ToUploadFile = { type, file, uploadUrl: faker.internet.url() };
 
     beforeEach(() => {
+      service._clearFailedUploads = jest.fn();
       service._generateUniqueId = jest.fn().mockReturnValue(uniqId);
       service._addUploadFileLoading = jest.fn();
       service._doUploadFile = jest.fn();
     });
 
+    it('should clear failed uploads', () => {
+      service.uploadFileNew(toUploadFile);
+
+      expect(service._clearFailedUploads).toHaveBeenCalled();
+    });
+
     it('should create an empty map if type key not exists', () => {
       service._uploadFiles$.next({});
 
@@ -124,6 +132,39 @@ describe('BinaryFileService', () => {
     });
   });
 
+  describe('clear failed uploads', () => {
+    const fileUploadType: string = faker.word.noun();
+    const failedFileKey: string = faker.word.noun();
+    const successFileKey: string = faker.word.noun();
+    const successUploadFile: UploadFile = createUploadFile();
+    const secondSuccessFileKey: string = faker.word.noun();
+    const secondFileUploadType: string = faker.word.noun();
+    const secondSuccessUploadFile: UploadFile = createUploadFile();
+
+    it('should remove failed uploads', () => {
+      service._uploadFiles$.next({
+        [fileUploadType]: {
+          [failedFileKey]: { ...createUploadFile(), uploadedFile: createErrorStateResource(createApiError()) },
+          [successFileKey]: successUploadFile,
+        },
+        [secondFileUploadType]: {
+          [secondSuccessFileKey]: secondSuccessUploadFile,
+        },
+      });
+
+      service._clearFailedUploads(fileUploadType);
+
+      expect(service._uploadFiles$.value).toEqual({
+        [fileUploadType]: {
+          [successFileKey]: successUploadFile,
+        },
+        [secondFileUploadType]: {
+          [secondSuccessFileKey]: secondSuccessUploadFile,
+        },
+      });
+    });
+  });
+
   describe('add upload file loading', () => {
     const uniqId: string = uniqueId();
     const type: string = 'dummyType';
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 223db64a230da606052caaf48a90dc45cd60f6a8..b6a628e32f0ef01e8ab34a02fc44a486ce1e69e9 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
@@ -21,7 +21,7 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-import { BlobWithFileName, createEmptyStateResource, createErrorStateResource, createStateResource, EMPTY_STRING, getMessageForInvalidParam, HttpHeader, isNotNil, isUnprocessableEntity, isValidationFieldFileSizeExceedError, sanitizeFileName, StateResource, } from '@alfa-client/tech-shared';
+import { BlobWithFileName, createEmptyStateResource, createErrorStateResource, createStateResource, EMPTY_STRING, getMessageForInvalidParam, hasStateResourceError, HttpHeader, isNotNil, isUnprocessableEntity, isValidationFieldFileSizeExceedError, sanitizeFileName, StateResource, } from '@alfa-client/tech-shared';
 import { SnackBarService } from '@alfa-client/ui';
 import { HttpErrorResponse, HttpResponse } from '@angular/common/http';
 import { Injectable } from '@angular/core';
@@ -50,12 +50,25 @@ export class BinaryFileService {
   }
 
   public uploadFileNew(toUploadFile: ToUploadFile): void {
+    this._clearFailedUploads(toUploadFile.type);
     this.createEmptyMapIfTypeNotExists(toUploadFile.type);
     const uniqId: string = this._generateUniqueId();
     this._addUploadFileLoading(uniqId, toUploadFile);
     this._doUploadFile(uniqId, toUploadFile);
   }
 
+  _clearFailedUploads(fileUploadType: FileUploadType): void {
+    const uploads: UploadFileByIdentifier = this._uploadFiles$.value[fileUploadType];
+    const keys: string[] = Object.keys(uploads);
+    const successfulUploads: UploadFileByIdentifier = {};
+    for (const key of keys) {
+      if (!hasStateResourceError(uploads[key].uploadedFile)) {
+        successfulUploads[key] = uploads[key];
+      }
+    }
+    this._uploadFiles$.next({ ...this._uploadFiles$.value, [fileUploadType]: successfulUploads });
+  }
+
   _generateUniqueId(): string {
     return uniqueId();
   }
diff --git a/alfa-client/libs/binary-file/src/lib/binary-file-list-container/binary-file-list-container.component.html b/alfa-client/libs/binary-file/src/lib/binary-file-list-container/binary-file-list-container.component.html
index cfa93fbc6b3b9dbd01834a8d31c1bf74f4088299..de2d67af94b520ec15bb8292ef9278cb78d8e395 100644
--- a/alfa-client/libs/binary-file/src/lib/binary-file-list-container/binary-file-list-container.component.html
+++ b/alfa-client/libs/binary-file/src/lib/binary-file-list-container/binary-file-list-container.component.html
@@ -23,9 +23,7 @@
     unter der Lizenz sind dem Lizenztext zu entnehmen.
 
 -->
-<ods-attachment-wrapper>
-  <alfa-binary-file-list
-    [binaryFileListStateResource]="binaryFileListStateResource$ | async"
-    [listOrientation]="listOrientation"
-  ></alfa-binary-file-list>
-</ods-attachment-wrapper>
+<alfa-binary-file-list
+  [binaryFileListStateResource]="binaryFileListStateResource$ | async"
+  [listOrientation]="listOrientation"
+></alfa-binary-file-list>
diff --git a/alfa-client/libs/binary-file/src/lib/binary-file-list-container/binary-file-list-container.component.spec.ts b/alfa-client/libs/binary-file/src/lib/binary-file-list-container/binary-file-list-container.component.spec.ts
index e9473e9ee486bc437328ee6fe85227d12c6293e5..6cca0983e8268484b83772fa1f78dafda782e70e 100644
--- a/alfa-client/libs/binary-file/src/lib/binary-file-list-container/binary-file-list-container.component.spec.ts
+++ b/alfa-client/libs/binary-file/src/lib/binary-file-list-container/binary-file-list-container.component.spec.ts
@@ -34,27 +34,19 @@ import { of } from 'rxjs';
 import { BinaryFileListContainerComponent } from './binary-file-list-container.component';
 import { BinaryFileListComponent } from './binary-file-list/binary-file-list.component';
 
-import { AttachmentWrapperComponent } from '@ods/system';
-
 describe('BinaryFileListContainerComponent', () => {
   let component: BinaryFileListContainerComponent;
   let fixture: ComponentFixture<BinaryFileListContainerComponent>;
 
   const binaryFileService: Mock<BinaryFileService> = mock(BinaryFileService);
 
-  const binaryFileStateResource: StateResource<BinaryFileResource> = createStateResource(
-    createBinaryFileResource(),
-  );
+  const binaryFileStateResource: StateResource<BinaryFileResource> = createStateResource(createBinaryFileResource());
   const resource: Resource = createDummyResource();
   const linkRel: LinkRelationName = DummyLinkRel.DUMMY;
 
   beforeEach(async () => {
     await TestBed.configureTestingModule({
-      declarations: [
-        BinaryFileListContainerComponent,
-        MockComponent(BinaryFileListComponent),
-        MockComponent(AttachmentWrapperComponent),
-      ],
+      declarations: [BinaryFileListContainerComponent, MockComponent(BinaryFileListComponent)],
       providers: [
         {
           provide: BinaryFileService,
@@ -85,8 +77,10 @@ describe('BinaryFileListContainerComponent', () => {
 
   describe('binary file list', () => {
     it('should be called with binary file state resource', () => {
-      const binaryFileListComponent: BinaryFileListComponent =
-        getMockComponent<BinaryFileListComponent>(fixture, BinaryFileListComponent);
+      const binaryFileListComponent: BinaryFileListComponent = getMockComponent<BinaryFileListComponent>(
+        fixture,
+        BinaryFileListComponent,
+      );
 
       expect(binaryFileListComponent.binaryFileListStateResource).toBe(binaryFileStateResource);
     });
diff --git a/alfa-client/libs/binary-file/src/lib/binary-file-list-container/binary-file-list/binary-file-list.component.html b/alfa-client/libs/binary-file/src/lib/binary-file-list-container/binary-file-list/binary-file-list.component.html
index 70054de869940144f9b0e1d3fa0eb7c23ea72a33..a4ee6adc69c75525b8a32dd2e0ad5a9352701c2d 100644
--- a/alfa-client/libs/binary-file/src/lib/binary-file-list-container/binary-file-list/binary-file-list.component.html
+++ b/alfa-client/libs/binary-file/src/lib/binary-file-list-container/binary-file-list/binary-file-list.component.html
@@ -23,11 +23,13 @@
     unter der Lizenz sind dem Lizenztext zu entnehmen.
 
 -->
-<div [binaryFileListOrientation]="listOrientation">
-  <alfa-binary-file2-container
-    *ngFor="let binaryFile of binaryFileListStateResource.resource | toEmbeddedResources: binaryFileListLinkRel.FILE_LIST"
-    [file]="binaryFile"
-    [deletable]="false"
-  >
-  </alfa-binary-file2-container>
-</div>
+@if (binaryFileListStateResource.resource | toEmbeddedResources: binaryFileListLinkRel.FILE_LIST; as binaryFileList) {
+  @if (binaryFileList.length) {
+    <ods-attachment-wrapper data-test-id="binary-file-list-wrapper">
+      <div [binaryFileListOrientation]="listOrientation">
+        <alfa-binary-file2-container *ngFor="let binaryFile of binaryFileList" [file]="binaryFile" [deletable]="false">
+        </alfa-binary-file2-container>
+      </div>
+    </ods-attachment-wrapper>
+  }
+}
diff --git a/alfa-client/libs/binary-file/src/lib/binary-file-list-container/binary-file-list/binary-file-list.component.spec.ts b/alfa-client/libs/binary-file/src/lib/binary-file-list-container/binary-file-list/binary-file-list.component.spec.ts
index fbbc820600ee4d1b3a9235dafd3515f9c1f16404..354a9d2be51cb3f1bd9bdb20d1525ed75b653904 100644
--- a/alfa-client/libs/binary-file/src/lib/binary-file-list-container/binary-file-list/binary-file-list.component.spec.ts
+++ b/alfa-client/libs/binary-file/src/lib/binary-file-list-container/binary-file-list/binary-file-list.component.spec.ts
@@ -23,9 +23,11 @@
  */
 import { BinaryFileListResource, BinaryFileResource } from '@alfa-client/binary-file-shared';
 import { createStateResource, StateResource, ToEmbeddedResourcesPipe } from '@alfa-client/tech-shared';
-import { getMockComponent } from '@alfa-client/test-utils';
+import { existsAsHtmlElement, getMockComponent, notExistsAsHtmlElement } from '@alfa-client/test-utils';
 import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { AttachmentWrapperComponent } from '@ods/system';
 import { createBinaryFileListResource, createBinaryFileResource } from 'libs/binary-file-shared/test/binary-file';
+import { getDataTestIdOf } from 'libs/tech-shared/test/data-test';
 import { MockComponent, MockDirective } from 'ng-mocks';
 import { BinaryFile2ContainerComponent } from '../../binary-file2-container/binary-file2-container.component';
 import { BinaryFileListOrientationDirective } from '../../directive/binary-file-list-orientation/binary-file-list-orientation.directive';
@@ -36,9 +38,11 @@ describe('BinaryFileListComponent', () => {
   let fixture: ComponentFixture<BinaryFileListComponent>;
 
   const binaryFile: BinaryFileResource = createBinaryFileResource();
-  const binaryFileListStateResource: StateResource<BinaryFileListResource> = createStateResource(
-    createBinaryFileListResource([binaryFile]),
-  );
+  function getBinaryFileListStateResource(binaryFiles: BinaryFileResource[]): StateResource<BinaryFileListResource> {
+    return createStateResource(createBinaryFileListResource(binaryFiles));
+  }
+
+  const wrapperSelector: string = getDataTestIdOf('binary-file-list-wrapper');
 
   beforeEach(async () => {
     await TestBed.configureTestingModule({
@@ -46,13 +50,14 @@ describe('BinaryFileListComponent', () => {
         BinaryFileListComponent,
         ToEmbeddedResourcesPipe,
         MockComponent(BinaryFile2ContainerComponent),
+        MockComponent(AttachmentWrapperComponent),
         MockDirective(BinaryFileListOrientationDirective),
       ],
     }).compileComponents();
 
     fixture = TestBed.createComponent(BinaryFileListComponent);
     component = fixture.componentInstance;
-    component.binaryFileListStateResource = binaryFileListStateResource;
+    component.binaryFileListStateResource = getBinaryFileListStateResource([binaryFile]);
     fixture.detectChanges();
   });
 
@@ -60,6 +65,22 @@ describe('BinaryFileListComponent', () => {
     expect(component).toBeTruthy();
   });
 
+  describe('template', () => {
+    describe('attachment wrapper', () => {
+      it('should show', () => {
+        existsAsHtmlElement(fixture, wrapperSelector);
+      });
+
+      it('should hide', () => {
+        component.binaryFileListStateResource = getBinaryFileListStateResource([]);
+
+        fixture.detectChanges();
+
+        notExistsAsHtmlElement(fixture, wrapperSelector);
+      });
+    });
+  });
+
   describe('binary file container', () => {
     it('should be called with file', () => {
       const binaryFileContainerComponent: BinaryFile2ContainerComponent = getMockComponent<BinaryFile2ContainerComponent>(
diff --git a/alfa-client/libs/binary-file/src/lib/directive/binary-file-list-orientation/binary-file-list-orientation.directive.ts b/alfa-client/libs/binary-file/src/lib/directive/binary-file-list-orientation/binary-file-list-orientation.directive.ts
index 3a1a42958aca047046c5aa29edaed15dc77a1705..956be5722cdcd4966e12c8a5216bfb0dde53d706 100644
--- a/alfa-client/libs/binary-file/src/lib/directive/binary-file-list-orientation/binary-file-list-orientation.directive.ts
+++ b/alfa-client/libs/binary-file/src/lib/directive/binary-file-list-orientation/binary-file-list-orientation.directive.ts
@@ -1,7 +1,7 @@
 import { Directive, ElementRef, Input } from '@angular/core';
 
 export const _verticalClasses: string[] = ['flex', 'flex-col'];
-export const _horizontalClasses: string[] = ['flex', 'flex-row', 'flex-wrap'];
+export const _horizontalClasses: string[] = ['flex', 'flex-wrap', 'gap-2'];
 
 export enum BinaryFileListOrientation {
   HORIZONTAL = 'horizontal',
diff --git a/alfa-client/libs/binary-file/src/lib/multi-file-upload-editor/multi-file-upload-editor.component.html b/alfa-client/libs/binary-file/src/lib/multi-file-upload-editor/multi-file-upload-editor.component.html
index 1bfa1fb53740999476b2e6b342777abec551f000..4024dc2de95e58d010447f113834a2b1b0387252 100644
--- a/alfa-client/libs/binary-file/src/lib/multi-file-upload-editor/multi-file-upload-editor.component.html
+++ b/alfa-client/libs/binary-file/src/lib/multi-file-upload-editor/multi-file-upload-editor.component.html
@@ -4,10 +4,12 @@
   [attr.data-test-id]="(label | convertForDataTest) + '-file-upload-button'"
   [multi]="true"
   [isLoading]="isUploadInProgress$ | async"
-  class="relative w-72"
+  [variant]="uploadButtonVariant"
   data-test-id="binary-file-upload"
 >
   <ods-spinner-icon spinner size="medium" />
   <ods-attachment-icon icon size="medium" />
-  <p text class="text-center">{{ label }}</p>
+  @if (label) {
+    <p text data-test-id="upload-button-label" class="text-center">{{ label }}</p>
+  }
 </ods-file-upload-button>
diff --git a/alfa-client/libs/binary-file/src/lib/multi-file-upload-editor/multi-file-upload-editor.component.spec.ts b/alfa-client/libs/binary-file/src/lib/multi-file-upload-editor/multi-file-upload-editor.component.spec.ts
index dc42e69a0f52518ba01f5f3ddf2009ef04e344e9..38303a464c9f128eb05963f94df756663567e129 100644
--- a/alfa-client/libs/binary-file/src/lib/multi-file-upload-editor/multi-file-upload-editor.component.spec.ts
+++ b/alfa-client/libs/binary-file/src/lib/multi-file-upload-editor/multi-file-upload-editor.component.spec.ts
@@ -1,11 +1,17 @@
 import { BinaryFileService, FileUploadType, ToUploadFile } from '@alfa-client/binary-file-shared';
 import { ConvertForDataTestPipe } from '@alfa-client/tech-shared';
-import { existsAsHtmlElement, getElementComponentFromFixtureByCss, mock, Mock } from '@alfa-client/test-utils';
+import {
+  existsAsHtmlElement,
+  getElementComponentFromFixtureByCss,
+  mock,
+  Mock,
+  notExistsAsHtmlElement,
+} from '@alfa-client/test-utils';
 import { ComponentFixture, TestBed } from '@angular/core/testing';
 import { faker } from '@faker-js/faker/.';
 import { expect } from '@jest/globals';
 import { getUrl, Resource } from '@ngxp/rest';
-import { FileUploadButtonComponent, SpinnerIconComponent } from '@ods/system';
+import { FileUploadButtonComponent, SpinnerIconComponent, UploadButtonVariants } from '@ods/system';
 import { getDataTestIdOf } from 'libs/tech-shared/test/data-test';
 import { MockComponent } from 'ng-mocks';
 import { of } from 'rxjs';
@@ -23,6 +29,7 @@ describe('MultiFileUploadEditorComponent', () => {
   const uploadResource: Resource = createDummyResource([uploadLinkRel]);
 
   const buttonTestId: string = getDataTestIdOf('Ein_Label-file-upload-button');
+  const buttonLabelTestId: string = getDataTestIdOf('upload-button-label');
 
   let binaryFileService: Mock<BinaryFileService>;
 
@@ -104,6 +111,24 @@ describe('MultiFileUploadEditorComponent', () => {
         } as ToUploadFile);
       });
     });
+
+    describe('get uploadButtonVariant', () => {
+      it('should return "label"', () => {
+        component.label = 'test';
+
+        const result: UploadButtonVariants['variant'] = component.uploadButtonVariant;
+
+        expect(result).toBe('label');
+      });
+
+      it('should return "icon"', () => {
+        component.label = '';
+
+        const result: UploadButtonVariants['variant'] = component.uploadButtonVariant;
+
+        expect(result).toBe('icon');
+      });
+    });
   });
 
   describe('template', () => {
@@ -125,5 +150,22 @@ describe('MultiFileUploadEditorComponent', () => {
         expect(fileButtonComponent.isLoading).toEqual(true);
       });
     });
+    describe('upload button label', () => {
+      it('should show', () => {
+        component.label = 'test';
+
+        fixture.detectChanges();
+
+        existsAsHtmlElement(fixture, buttonLabelTestId);
+      });
+
+      it('should hide', () => {
+        component.label = '';
+
+        fixture.detectChanges();
+
+        notExistsAsHtmlElement(fixture, buttonLabelTestId);
+      });
+    });
   });
 });
diff --git a/alfa-client/libs/binary-file/src/lib/multi-file-upload-editor/multi-file-upload-editor.component.ts b/alfa-client/libs/binary-file/src/lib/multi-file-upload-editor/multi-file-upload-editor.component.ts
index 4c057b3f3d7b52b25dc63164e62f06bb054b83c8..2a9623612015f5350b39822c605c8faed1903d59 100644
--- a/alfa-client/libs/binary-file/src/lib/multi-file-upload-editor/multi-file-upload-editor.component.ts
+++ b/alfa-client/libs/binary-file/src/lib/multi-file-upload-editor/multi-file-upload-editor.component.ts
@@ -5,7 +5,7 @@ import { AsyncPipe } from '@angular/common';
 import { Component, HostListener, inject, Input, OnInit } from '@angular/core';
 import { ControlContainer, FormGroupDirective, ReactiveFormsModule } from '@angular/forms';
 import { getUrl, Resource } from '@ngxp/rest';
-import { AttachmentIconComponent, FileUploadButtonComponent, SpinnerIconComponent } from '@ods/system';
+import { AttachmentIconComponent, FileUploadButtonComponent, SpinnerIconComponent, UploadButtonVariants } from '@ods/system';
 import { uniqueId } from 'lodash-es';
 import { Observable } from 'rxjs';
 
@@ -55,4 +55,8 @@ export class MultiFileUploadEditorComponent implements OnInit {
       });
     }
   }
+
+  get uploadButtonVariant(): UploadButtonVariants['variant'] {
+    return this.label ? 'label' : 'icon';
+  }
 }
diff --git a/alfa-client/libs/binary-file/src/lib/multi-file-upload/multi-file-upload.component.html b/alfa-client/libs/binary-file/src/lib/multi-file-upload/multi-file-upload.component.html
index 184ac868f9f594da443f6f89b969ce1cc85b1dfc..8efd002c007d46dba8fc79c2526e59e132191c66 100644
--- a/alfa-client/libs/binary-file/src/lib/multi-file-upload/multi-file-upload.component.html
+++ b/alfa-client/libs/binary-file/src/lib/multi-file-upload/multi-file-upload.component.html
@@ -1,13 +1,15 @@
-<ods-file-upload-list-container
-  [parentFormArrayName]="filesFormFieldName"
-  [fileUploadType]="fileUploadType"
-  [filesResource]="filesResource"
-  [filesLinkRel]="filesLinkRelation"
-  data-test-id="file-list"
-></ods-file-upload-list-container>
-<ods-multi-file-upload-editor
-  [fileUploadType]="fileUploadType"
-  [uploadResource]="uploadResource"
-  [uploadLinkRelation]="uploadLinkRelation"
-  data-test-id="multi-file-upload-editor"
-></ods-multi-file-upload-editor>
\ No newline at end of file
+<div class="flex flex-col gap-2">
+  <ods-file-upload-list-container
+    [parentFormArrayName]="filesFormFieldName"
+    [fileUploadType]="fileUploadType"
+    [filesResource]="filesResource"
+    [filesLinkRel]="filesLinkRelation"
+    data-test-id="file-list"
+  />
+  <ods-multi-file-upload-editor
+    [fileUploadType]="fileUploadType"
+    [uploadResource]="uploadResource"
+    [uploadLinkRelation]="uploadLinkRelation"
+    data-test-id="multi-file-upload-editor"
+  />
+</div>
diff --git a/alfa-client/libs/design-component/src/lib/form/single-file-upload-editor/single-file-upload-editor.component.ts b/alfa-client/libs/design-component/src/lib/form/single-file-upload-editor/single-file-upload-editor.component.ts
index a62e384fb3c9ff9c15b453cc9927438d1e1790c4..7de4a0bf3fc04340fa80daed1896235559f6dd18 100644
--- a/alfa-client/libs/design-component/src/lib/form/single-file-upload-editor/single-file-upload-editor.component.ts
+++ b/alfa-client/libs/design-component/src/lib/form/single-file-upload-editor/single-file-upload-editor.component.ts
@@ -24,7 +24,7 @@
 import { ConvertForDataTestPipe, isNotNil } from '@alfa-client/tech-shared';
 import { Component, EventEmitter, HostListener, Input, Output } from '@angular/core';
 import { ReactiveFormsModule } from '@angular/forms';
-import { FileUploadButtonComponent, SpinnerIconComponent } from '@ods/system';
+import { FileUploadButtonComponent } from '@ods/system';
 import { uniqueId } from 'lodash-es';
 import { FormControlEditorAbstractComponent } from '../formcontrol-editor.abstract.component';
 
@@ -32,7 +32,8 @@ import { FormControlEditorAbstractComponent } from '../formcontrol-editor.abstra
   selector: 'ods-single-file-upload-editor',
   templateUrl: './single-file-upload-editor.component.html',
   standalone: true,
-  imports: [FileUploadButtonComponent, SpinnerIconComponent, ReactiveFormsModule, ConvertForDataTestPipe],
+  styles: [':host {@apply contents}'],
+  imports: [FileUploadButtonComponent, ReactiveFormsModule, ConvertForDataTestPipe],
 })
 export class SingleFileUploadEditorComponent extends FormControlEditorAbstractComponent {
   @Input() label: string = '';
diff --git a/alfa-client/libs/design-system/src/lib/form/file-upload-button/file-upload-button.component.html b/alfa-client/libs/design-system/src/lib/form/file-upload-button/file-upload-button.component.html
index dc2b6cef68ea7358023c7791fea0eb6efbaf47bf..b65b88d5b02c74982b872549c6d87aeccdf1644b 100644
--- a/alfa-client/libs/design-system/src/lib/form/file-upload-button/file-upload-button.component.html
+++ b/alfa-client/libs/design-system/src/lib/form/file-upload-button/file-upload-button.component.html
@@ -34,14 +34,13 @@
   [multiple]="multi"
   [attr.data-test-id]="(id | convertForDataTest) + '-file-upload-input'"
 />
-<label
-  [for]="id"
-  class="z-10 inline-flex w-full flex-grow items-center justify-start gap-4 break-words rounded-md bg-background-50 py-3 pl-6 pr-6 text-text hover:bg-background-100 focus:outline-none focus:ring-2 focus:ring-primary peer-focus-visible:outline peer-focus-visible:outline-2 peer-focus-visible:outline-offset-2 peer-focus-visible:outline-ozgblue-800 peer-disabled:cursor-wait peer-disabled:hover:bg-background-50"
-  role="button"
->
-  <ng-content *ngIf="!isLoading" select="[icon]"></ng-content>
-  <ng-content *ngIf="isLoading" select="[spinner]"></ng-content>
-  <div class="flex-grow">
+<label [for]="id" [ngClass]="uploadButtonVariants({ variant })" role="button">
+  @if (isLoading) {
+    <ng-content select="[spinner]"></ng-content>
+  } @else {
+    <ng-content select="[icon]"></ng-content>
+  }
+  <div class="flex-grow empty:hidden">
     <ng-content select="[text]"></ng-content>
   </div>
 </label>
diff --git a/alfa-client/libs/design-system/src/lib/form/file-upload-button/file-upload-button.component.ts b/alfa-client/libs/design-system/src/lib/form/file-upload-button/file-upload-button.component.ts
index 2371918f9cdba62e0ea0ee3a5e315ee9f1d9e378..b5048be11b1b7e67eaf8c077e3d4cd0caab66388 100644
--- a/alfa-client/libs/design-system/src/lib/form/file-upload-button/file-upload-button.component.ts
+++ b/alfa-client/libs/design-system/src/lib/form/file-upload-button/file-upload-button.component.ts
@@ -24,12 +24,33 @@
 import { ConvertForDataTestPipe } from '@alfa-client/tech-shared';
 import { CommonModule } from '@angular/common';
 import { Component, ElementRef, Input, ViewChild } from '@angular/core';
+import { cva, VariantProps } from 'class-variance-authority';
+
+export const uploadButtonVariants = cva(
+  [
+    'z-10 inline-flex flex-grow items-center justify-start gap-4 break-words rounded-md text-primary',
+    'border border-transparent hover:bg-ghost-hover peer-focus-visible:border-background-200',
+    'peer-focus-visible:outline peer-focus-visible:outline-focus peer-focus-visible:bg-ghost-hover peer-focus-visible:outline-offset-1',
+  ],
+  {
+    variants: {
+      variant: {
+        label: 'py-3 px-6 bg-background-50 w-full',
+        icon: 'p-2 w-fit',
+      },
+    },
+    defaultVariants: {
+      variant: 'label',
+    },
+  },
+);
+export type UploadButtonVariants = VariantProps<typeof uploadButtonVariants>;
 
 @Component({
   selector: 'ods-file-upload-button',
   standalone: true,
   imports: [CommonModule, ConvertForDataTestPipe],
-  styles: [':host {@apply inline-flex}'],
+  styles: [':host {@apply relative}'],
   templateUrl: './file-upload-button.component.html',
 })
 export class FileUploadButtonComponent {
@@ -37,9 +58,12 @@ export class FileUploadButtonComponent {
   @Input() isLoading: boolean = false;
   @Input() accept: string = '*/*';
   @Input() multi: boolean = false;
+  @Input() variant: UploadButtonVariants['variant'];
 
   @ViewChild('inputElement') inputElement: ElementRef = new ElementRef({});
 
+  readonly uploadButtonVariants = uploadButtonVariants;
+
   resetInput(): void {
     this.inputElement.nativeElement.value = '';
   }
diff --git a/alfa-client/libs/design-system/src/lib/tooltip/tooltip.component.ts b/alfa-client/libs/design-system/src/lib/tooltip/tooltip.component.ts
index 671af957965555f680862dad37081cc00c537c9d..f62b0e92488cc33d05bbc61112556850a74766e9 100644
--- a/alfa-client/libs/design-system/src/lib/tooltip/tooltip.component.ts
+++ b/alfa-client/libs/design-system/src/lib/tooltip/tooltip.component.ts
@@ -29,6 +29,7 @@ import { TooltipPosition } from './tooltip.directive';
   selector: 'ods-tooltip',
   imports: [NgClass],
   template: `<span
+    [attr.data-test-id]="dataTestId"
     class="tooltip fixed z-[100] animate-fadeIn cursor-default break-words rounded bg-ozggray-900 px-3 py-2 text-sm font-normal text-whitetext before:absolute before:border-l-[0.5rem] before:border-r-[0.5rem] before:border-l-transparent before:border-r-transparent dark:bg-white"
     [ngClass]="class"
     [class.visible]="show"
@@ -58,6 +59,8 @@ export class TooltipComponent {
   class: string;
   leftOffset: number;
 
+  dataTestId: string;
+
   set position(value: TooltipPosition) {
     if (value === TooltipPosition.ABOVE) {
       this.class =
diff --git a/alfa-client/libs/design-system/src/lib/tooltip/tooltip.directive.spec.ts b/alfa-client/libs/design-system/src/lib/tooltip/tooltip.directive.spec.ts
index 76c569e4245841930a5387dc5c8a2e34e6328c1b..3b775dd56d43e4247a3de4cf06fe0a3e4d64bc76 100644
--- a/alfa-client/libs/design-system/src/lib/tooltip/tooltip.directive.spec.ts
+++ b/alfa-client/libs/design-system/src/lib/tooltip/tooltip.directive.spec.ts
@@ -21,6 +21,7 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
+import { assignValue, mock, useFromMock } from '@alfa-client/test-utils';
 import { InteractivityChecker } from '@angular/cdk/a11y';
 import { ComponentRef, ElementRef, Renderer2, ViewContainerRef } from '@angular/core';
 import { fakeAsync, TestBed, tick } from '@angular/core/testing';
@@ -37,6 +38,18 @@ class MockElementRef extends ElementRef {
 
 describe('TooltipDirective', () => {
   let directive: TooltipDirective;
+  const mockComponentRefInstance: TooltipComponent = {
+    id: '',
+    left: 0,
+    top: 0,
+    text: '',
+    show: false,
+    position: TooltipPosition.BELOW,
+    class: '',
+    leftOffset: 0,
+    width: null,
+    dataTestId: undefined,
+  };
   const mockComponentRef: ComponentRef<TooltipComponent> = {
     setInput: jest.fn(),
     destroy: jest.fn(),
@@ -46,17 +59,7 @@ describe('TooltipDirective', () => {
     location: null,
     hostView: null,
     injector: null,
-    instance: {
-      id: '',
-      left: 0,
-      top: 0,
-      text: '',
-      show: false,
-      position: TooltipPosition.BELOW,
-      class: '',
-      leftOffset: 0,
-      width: null,
-    },
+    instance: mockComponentRefInstance,
   };
   const parentRect: DOMRect = { bottom: 0, top: 0, height: 0, left: 0, right: 0, toJSON: jest.fn(), width: 0, x: 0, y: 0 };
 
@@ -119,6 +122,7 @@ describe('TooltipDirective', () => {
       directive.setInitialTooltipProperties = jest.fn();
       directive.getParentElement = jest.fn().mockReturnValue({ appendChild: jest.fn() });
       directive.interactivityChecker.isFocusable = jest.fn();
+      directive._addDataTestId = jest.fn();
     });
 
     it('should create tooltip component', () => {
@@ -156,6 +160,43 @@ describe('TooltipDirective', () => {
 
       expect(directive.getParentElement).not.toHaveBeenCalled();
     });
+
+    it('should call add data test id', () => {
+      directive.createTooltip(tooltipText);
+
+      expect(directive._addDataTestId).toHaveBeenCalled();
+    });
+  });
+
+  describe('add data test id', () => {
+    const dataTestId: string = 'dummyDataTestId';
+
+    beforeEach(() => {
+      directive.componentRef = assignValue(mockComponentRef, 'instance', { ...mockComponentRef.instance, dataTestId: undefined });
+    });
+
+    it('should set attribute to tooltip component if exists', () => {
+      directive.parentElement = mockParentAttribute(dataTestId);
+
+      directive._addDataTestId();
+
+      expect(directive.componentRef.instance.dataTestId).toBe(dataTestId + directive.dataTestIdTooltipSuffix);
+    });
+
+    it('should NOT set attribute to tooltip component if undefined', () => {
+      directive.parentElement = mockParentAttribute(undefined);
+
+      directive._addDataTestId();
+
+      expect(directive.componentRef.instance.dataTestId).toBeUndefined();
+    });
+
+    function mockParentAttribute(value: any): HTMLElement {
+      return useFromMock<HTMLElement>({
+        ...mock(HTMLElement),
+        getAttribute: jest.fn().mockReturnValue(value),
+      });
+    }
   });
 
   describe('showTooltip', () => {
diff --git a/alfa-client/libs/design-system/src/lib/tooltip/tooltip.directive.ts b/alfa-client/libs/design-system/src/lib/tooltip/tooltip.directive.ts
index d8f42d4ab8dd4e8bdab6e49031a00fbbbddbb480..10cca117f0ab929c71c43dc0a33482a57a5c19de 100644
--- a/alfa-client/libs/design-system/src/lib/tooltip/tooltip.directive.ts
+++ b/alfa-client/libs/design-system/src/lib/tooltip/tooltip.directive.ts
@@ -21,7 +21,7 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-import { isEscapeKey, isNotNull } from '@alfa-client/tech-shared';
+import { isEscapeKey, isNotNull, isNotUndefined } from '@alfa-client/tech-shared';
 import { InteractivityChecker } from '@angular/cdk/a11y';
 import {
   ComponentRef,
@@ -80,6 +80,10 @@ export class TooltipDirective implements OnDestroy {
   public readonly renderer: Renderer2 = inject(Renderer2);
   public readonly interactivityChecker: InteractivityChecker = inject(InteractivityChecker);
 
+  dataTestIdParentAttribute: string = 'data-test-id';
+  dataTestIdAttribute: string = 'dataTestId';
+  dataTestIdTooltipSuffix: string = '-tooltip';
+
   ngOnDestroy(): void {
     this.destroy();
   }
@@ -120,12 +124,18 @@ export class TooltipDirective implements OnDestroy {
     const nativeElement: HTMLElement = this.elementRef.nativeElement;
     this.componentRef = this.viewContainerRef.createComponent(TooltipComponent);
     this.parentElement = this.getParentElement(nativeElement);
+    this._addDataTestId();
     this.parentElement.appendChild(this.componentRef.location.nativeElement);
     this.tooltipId = uniqueId('tooltip');
     this.setInitialTooltipProperties(tooltipText, this.tooltipId);
     this.setAriaAttribute(this.tooltipAriaType);
   }
 
+  _addDataTestId(): void {
+    const dataTestId: string = this.parentElement.getAttribute(this.dataTestIdParentAttribute);
+    if (isNotUndefined(dataTestId)) this.componentRef.instance.dataTestId = dataTestId + this.dataTestIdTooltipSuffix;
+  }
+
   setInitialTooltipProperties(text: string, id: string) {
     this.componentRef.instance.text = text;
     this.componentRef.instance.id = id;
diff --git a/alfa-client/libs/kommentar-shared/src/lib/kommentar.service.spec.ts b/alfa-client/libs/kommentar-shared/src/lib/kommentar.service.spec.ts
index 1ceecd9e1f16e3309e234235887150f8e5c6ee3a..522ed1f6ce6a4ae086d1226253f1d1236eb3eb9d 100644
--- a/alfa-client/libs/kommentar-shared/src/lib/kommentar.service.spec.ts
+++ b/alfa-client/libs/kommentar-shared/src/lib/kommentar.service.spec.ts
@@ -259,6 +259,23 @@ describe('KommentarService', () => {
   });
 
   describe('onNavigation', () => {
+    beforeEach(() => {
+      service.clearUploadedFiles = jest.fn();
+      service.hideFormular = jest.fn();
+    });
+
+    it('should clear uploaded files', () => {
+      service.onNavigation({});
+
+      expect(service.clearUploadedFiles).toHaveBeenCalled();
+    });
+
+    it('should hide forumlar', () => {
+      service.onNavigation({});
+
+      expect(service.hideFormular).toHaveBeenCalled();
+    });
+
     describe('to vorgang list', () => {
       it('should set reload flag of kommentar list', () => {
         service.kommentarList$.next(createEmptyStateResource());
diff --git a/alfa-client/libs/kommentar-shared/src/lib/kommentar.service.ts b/alfa-client/libs/kommentar-shared/src/lib/kommentar.service.ts
index 6749d94ff0079091abf5f3a42d6c67786b171d08..0055824e34836c3ad1195ce85d01ff4f2b772a35 100644
--- a/alfa-client/libs/kommentar-shared/src/lib/kommentar.service.ts
+++ b/alfa-client/libs/kommentar-shared/src/lib/kommentar.service.ts
@@ -42,7 +42,7 @@ export class KommentarService {
     createEmptyStateResource<KommentarListResource>(),
   );
   readonly formularVisibility$: BehaviorSubject<boolean> = new BehaviorSubject(false);
-  readonly _currentlyEdited$: BehaviorSubject<ResourceUri> = new BehaviorSubject('');
+  readonly _currentlyEdited$: BehaviorSubject<ResourceUri> = new BehaviorSubject(EMPTY_STRING);
 
   private navigationSub: Subscription;
 
@@ -66,6 +66,8 @@ export class KommentarService {
   }
 
   onNavigation(params: Params): void {
+    this.clearUploadedFiles();
+    this.hideFormular();
     if (NavigationService.isVorgangListPage(params)) {
       this.setKommentarListOnReload();
     }
diff --git a/alfa-client/libs/test-utils/src/lib/mocking.ts b/alfa-client/libs/test-utils/src/lib/mocking.ts
index 20ac6152a4230849892a5f6e5599670b24e05165..d42ae2de44f2a37bec9daeed0388f20812b04364 100644
--- a/alfa-client/libs/test-utils/src/lib/mocking.ts
+++ b/alfa-client/libs/test-utils/src/lib/mocking.ts
@@ -59,3 +59,7 @@ export function mockWindowError(): any {
   window.onerror = errorHandler;
   return errorHandler;
 }
+
+export function assignValue<T>(object: any, attributeName: string, toAssignValue: any): T {
+  return Object.assign(object, { [attributeName]: toAssignValue });
+}
diff --git a/alfa-client/libs/wiedervorlage-shared/src/lib/wiedervorlage.service.spec.ts b/alfa-client/libs/wiedervorlage-shared/src/lib/wiedervorlage.service.spec.ts
index 3b37f2ba12ba7a1fe70501e190a918d95d8d1430..4d6c0e5ba0bca3a14b4e33d989d737fa379552ff 100644
--- a/alfa-client/libs/wiedervorlage-shared/src/lib/wiedervorlage.service.spec.ts
+++ b/alfa-client/libs/wiedervorlage-shared/src/lib/wiedervorlage.service.spec.ts
@@ -442,6 +442,13 @@ describe('WiedervorlageService', () => {
       service.setWiedervorlageListReload = jest.fn();
       (<any>service).forceWiedervorlageReload = jest.fn();
       service.clearWiedervorlagenList = jest.fn();
+      service.clearUploadedFiles = jest.fn();
+    });
+
+    it('should clear uploaded files', () => {
+      service.onNavigation({});
+
+      expect(service.clearUploadedFiles).toHaveBeenCalled();
     });
 
     describe('to vorgang detail', () => {
diff --git a/alfa-client/libs/wiedervorlage-shared/src/lib/wiedervorlage.service.ts b/alfa-client/libs/wiedervorlage-shared/src/lib/wiedervorlage.service.ts
index 38a7b041ad76c71ef06a78f5f7184a0260fd31f0..208bf667e34a682bf13a4022276667409c9f4831 100644
--- a/alfa-client/libs/wiedervorlage-shared/src/lib/wiedervorlage.service.ts
+++ b/alfa-client/libs/wiedervorlage-shared/src/lib/wiedervorlage.service.ts
@@ -152,6 +152,7 @@ export class WiedervorlageService implements OnDestroy {
   }
 
   onNavigation(params: Params): void {
+    this.clearUploadedFiles();
     if (this.navigateToVorgangDetailPage(params)) {
       this.setWiedervorlageListReload();
       this.forceWiedervorlageReload();