diff --git a/alfa-client/Jenkinsfile.e2e b/alfa-client/Jenkinsfile.e2e
index a662c618cc0a6e26e7188e55024c4aeb1edca764..94fcdb512628bbe15ac09a1640bc9e89f8b68920 100644
--- a/alfa-client/Jenkinsfile.e2e
+++ b/alfa-client/Jenkinsfile.e2e
@@ -556,6 +556,7 @@ Void generateAdminNamespaceYaml() {
     envValues.ozgcloud.bezeichner = bezeichner
     envValues.administration.put("image", ['tag': env.ADMINISTRATION_IMAGE_TAG])
     envValues.administration.put("helm", ['version': env.ADMINISTRATION_HELM_CHART_VERSION, 'repoUrl': env.ADMINISTRATION_HELM_REPO_URL])
+    envValues.administration.put("ozgcloud", ['feature': ['organisationsEinheiten' : "true"], 'organisationEinheit': ['zufiSearchUri': generateZufiSearchUri(bezeichner)]])
 
     envValues.admin_client.put("image", ['tag': env.ADMIN_CLIENT_IMAGE_TAG])
     envValues.admin_client.put("helm", ['version': env.ADMIN_CLIENT_HELM_CHART_VERSION, 'repoUrl': env.ADMIN_CLIENT_HELM_REPO_URL])
@@ -563,6 +564,10 @@ Void generateAdminNamespaceYaml() {
   return writeYamlToGitOps(bezeichner, envValues);
 }
 
+String generateZufiSearchUri(String bezeichner) {
+    return "https://${bezeichner}.dev.by.ozg-cloud.de/api/organisationseinheits?searchBy={searchBy}"
+}
+
 String generateEaNamespaceYaml() {
     return generateNamespaceYaml(env.EA_BEZEICHNER, "by-ea-dev.yaml");
 }
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 95761b4df7188b50522c3b6a5d4b845503a64499..018f353c5f8cfca304adf2b0bd15a6f0792482c9 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
@@ -36,6 +36,7 @@ export class BenutzerE2EComponent {
   private readonly loeschenCheckbox: string = 'Loschen-checkbox-editor';
   private readonly userCheckbox: string = 'User-checkbox-editor';
   private readonly postCheckbox: string = 'Poststelle-checkbox-editor';
+  private readonly saveButton: string = 'save-button';
 
   public getHinzufuegenButton(): Cypress.Chainable<Element> {
     return cy.getTestElement(this.benutzerHinzufuegenButton);
@@ -60,18 +61,34 @@ export class BenutzerE2EComponent {
     return cy.getTestElement(this.userVorname);
   }
 
+  public enterVorname(vorname: string): void {
+    this.getVornameInput().type(vorname);
+  }
+
   public getNachnameInput(): Cypress.Chainable<Element> {
     return cy.getTestElement(this.userNachname);
   }
 
+  public enterNachname(nachname: string): void {
+    this.getNachnameInput().type(nachname);
+  }
+
   public getBenutzernameInput(): Cypress.Chainable<Element> {
     return cy.getTestElement(this.userBenutzername);
   }
 
+  public enterBenutzername(benutzername: string): void {
+    this.getBenutzernameInput().type(benutzername);
+  }
+
   public getMailInput(): Cypress.Chainable<Element> {
     return cy.getTestElement(this.userMail);
   }
 
+  public enterMail(mail: string): void {
+    this.getMailInput().type(mail);
+  }
+
   public getOEButton(): Cypress.Chainable<Element> {
     return cy.getTestElement(this.addOEButton);
   }
@@ -111,4 +128,12 @@ export class BenutzerE2EComponent {
   public clickPostCheckbox(): void {
     this.getPostCheckbox().click();
   }
+
+  public getSaveButton(): Cypress.Chainable<Element> {
+    return cy.getTestElement(this.saveButton);
+  }
+
+  public saveUser(): void {
+    this.getSaveButton().click();
+  }
 }
diff --git a/alfa-client/apps/admin-e2e/src/components/statistik/statistik-component.ts b/alfa-client/apps/admin-e2e/src/components/statistik/statistik-component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c088cd85910ceafc4c0f4df93edc403abfd4a630
--- /dev/null
+++ b/alfa-client/apps/admin-e2e/src/components/statistik/statistik-component.ts
@@ -0,0 +1,9 @@
+import { exist } from '../../support/cypress.util';
+
+export class StatistikE2EComponent {
+  private readonly headerText: string = 'statistik-header-text';
+
+  public isHeaderTextVisible(): void {
+    exist(cy.getTestElement(this.headerText));
+  }
+}
diff --git a/alfa-client/apps/admin-e2e/src/components/ui/snackbar.e2e.component.ts b/alfa-client/apps/admin-e2e/src/components/ui/snackbar.e2e.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..903e0d97a994405891c4ae19fa4cc33afa754d01
--- /dev/null
+++ b/alfa-client/apps/admin-e2e/src/components/ui/snackbar.e2e.component.ts
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch den
+ * Ministerpräsidenten des Landes Schleswig-Holstein
+ * Staatskanzlei
+ * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+ *
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+export class SnackBarE2EComponent {
+  private readonly locatorMessage: string = 'snackbar-message';
+  private readonly locatorCloseButton: string = 'snackbar-close-button';
+  private readonly locatorRevokeButton: string = 'snackbar-revoke-button';
+
+  public getMessage() {
+    return cy.getTestElement(this.locatorMessage);
+  }
+
+  public getCloseButton() {
+    return cy.getTestElement(this.locatorCloseButton);
+  }
+
+  public getRevokeButton() {
+    return cy.getTestElement(this.locatorRevokeButton);
+  }
+}
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
new file mode 100644
index 0000000000000000000000000000000000000000..08b27109920f0cc6a67779bfb8d3d262b63bd7bb
--- /dev/null
+++ b/alfa-client/apps/admin-e2e/src/e2e/main-tests/benutzer_rollen/benutzer-anlegen.cy.ts
@@ -0,0 +1,73 @@
+
+import { MainPage } from 'apps/admin-e2e/src/page-objects/main.po';
+import { BenutzerE2EComponent } 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 { SnackBarE2EComponent } from '../../../components/ui/snackbar.e2e.component';
+import { SnackbarMessagesE2E } from '../../../model/util';
+import { wait, waitOfInterceptor } from 'apps/admin-e2e/src/support/cypress-helper';
+
+const mainPage: MainPage = new MainPage();
+const benutzerPage: BenutzerE2EComponent = new BenutzerE2EComponent();
+const snackBar: SnackBarE2EComponent = new SnackBarE2EComponent();
+
+const vorname: string = 'Theo';
+const nachname: string = 'Testuser';
+const benutzername: string = 'testtheo';
+const emailAddress: string = 'theo.test@ozg-sh.de';
+
+describe('Benutzer anlegen', () => {
+  before(() => {
+    loginAsAriane();
+  });
+
+  it('should open Benutzer tab and show Hinzufuegen button', () => {
+    mainPage.clickBenutzerTab();
+
+    exist(benutzerPage.getHinzufuegenButton());
+  });
+
+  it.skip('should not do anything after click on save with missing data', () => {
+    benutzerPage.addUser();
+    benutzerPage.saveUser();
+    
+    //TODO: Fehlermeldungen hinzufügen
+  });
+
+  it('should show snackbar message on error', () => {
+    const interceptor: string = 'postUser';
+    const url: string = 'https://sso.dev.by.ozg-cloud.de/admin/realms/by-e2e-tests-local-dev/users'
+    const errorCode: number = 500;
+    const errorBody: string = 'Internal Server Error';
+
+    cy.intercept('POST', url, {statusCode: errorCode, body: errorBody}).as(interceptor);
+
+    benutzerPage.addUser();
+    benutzerPage.saveUser();
+
+    waitOfInterceptor(interceptor).then(() => {
+      contains(snackBar.getMessage(), SnackbarMessagesE2E.NUTZER_FEHLGESCHLAGEN);
+    });
+  });
+
+  it('should show snackbar message on saving user', () => {
+    snackBar.getCloseButton().click();
+  
+    benutzerPage.enterVorname(vorname);
+    benutzerPage.enterNachname(nachname);
+    benutzerPage.enterBenutzername(benutzername);
+    benutzerPage.enterMail(emailAddress);
+    benutzerPage.clickAdminCheckbox();
+    benutzerPage.clickUserCheckbox();
+
+    benutzerPage.saveUser();
+    contains(snackBar.getMessage(), SnackbarMessagesE2E.NUTZER_ANGELEGT);
+  });
+
+  it('should display new user in users table', () => {
+    benutzerPage.stringExistsInUserEntry(AlfaRollen.USER, benutzername);
+    benutzerPage.stringExistsInUserEntry(vorname, benutzername);
+    benutzerPage.stringExistsInUserEntry(nachname, benutzername);
+    // FEHLT NOCH: benutzerPage.stringExistsInUserEntry(AlfaRollen.ADMIN, benutzername);
+  });
+});
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
new file mode 100644
index 0000000000000000000000000000000000000000..10be61e410d4b9332e05ce3efdd12e65bfd6dc4b
--- /dev/null
+++ b/alfa-client/apps/admin-e2e/src/e2e/main-tests/navigation/ariane.cy.ts
@@ -0,0 +1,31 @@
+import { MainPage, waitForSpinnerToDisappear } from 'apps/admin-e2e/src/page-objects/main.po';
+import { exist, notExist } from 'apps/admin-e2e/src/support/cypress.util';
+import { loginAsAriane } from 'apps/admin-e2e/src/support/user-util';
+
+describe('Navigation', () => {
+  const mainPage: MainPage = new MainPage();
+
+  describe('with user ariane', () => {
+    before(() => {
+      loginAsAriane();
+
+      waitForSpinnerToDisappear();
+    });
+
+    it('should show benutzer navigation item', () => {
+      exist(mainPage.getBenutzerTab());
+    });
+
+    it('should show postfach navigation item', () => {
+      exist(mainPage.getPostfachNavigationItem());
+    });
+
+    it('should hide organisationseinheiten navigation item', () => {
+      notExist(mainPage.getOrganisationEinheitNavigationItem());
+    });
+
+    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
new file mode 100644
index 0000000000000000000000000000000000000000..7082da14ad51b94c655f92de71e898742c07a15d
--- /dev/null
+++ b/alfa-client/apps/admin-e2e/src/e2e/main-tests/navigation/daria.cy.ts
@@ -0,0 +1,44 @@
+import { StatistikE2EComponent } from 'apps/admin-e2e/src/components/statistik/statistik-component';
+import { MainPage, waitForSpinnerToDisappear } from 'apps/admin-e2e/src/page-objects/main.po';
+import { exist, notExist } from 'apps/admin-e2e/src/support/cypress.util';
+import { loginAsDaria } from 'apps/admin-e2e/src/support/user-util';
+
+describe('Navigation', () => {
+  const mainPage: MainPage = new MainPage();
+
+  const statistikPage: StatistikE2EComponent = new StatistikE2EComponent();
+
+  describe('with user daria', () => {
+    before(() => {
+      loginAsDaria();
+
+      waitForSpinnerToDisappear();
+    });
+
+    it('should hide other navigation item', () => {
+      notExist(mainPage.getBenutzerTab());
+    });
+
+    it('should hide postfach navigation item', () => {
+      notExist(mainPage.getPostfachNavigationItem());
+    });
+
+    it('should hide organisationseinheiten navigation item', () => {
+      notExist(mainPage.getOrganisationEinheitNavigationItem());
+    });
+
+    describe('statistik', () => {
+      it('should be visible', () => {
+        exist(mainPage.getStatistikNavigationItem());
+      });
+
+      it('should be initial selected', () => {
+        mainPage.isStatistikNavigationItemSelected();
+      });
+
+      it('should show header text', () => {
+        statistikPage.isHeaderTextVisible();
+      });
+    });
+  });
+});
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
new file mode 100644
index 0000000000000000000000000000000000000000..2b1c1023b9ba8d3bb73e34ce2c36a937816ca716
--- /dev/null
+++ b/alfa-client/apps/admin-e2e/src/e2e/main-tests/navigation/safira.cy.ts
@@ -0,0 +1,50 @@
+import { StatistikE2EComponent } from 'apps/admin-e2e/src/components/statistik/statistik-component';
+import { MainPage, waitForSpinnerToDisappear } from 'apps/admin-e2e/src/page-objects/main.po';
+import { exist } from 'apps/admin-e2e/src/support/cypress.util';
+import { loginAsSafira } from 'apps/admin-e2e/src/support/user-util';
+
+describe('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.getBenutzerTab());
+    });
+
+    it('should show postfach navigation item', () => {
+      exist(mainPage.getPostfachNavigationItem());
+    });
+
+    it('should show organisationseinheiten navigation item', () => {
+      exist(mainPage.getOrganisationEinheitNavigationItem());
+    });
+
+    describe('statistik', () => {
+      it('should be visible', () => {
+        exist(mainPage.getStatistikNavigationItem());
+      });
+
+      describe('on selection', () => {
+        before(() => {
+          mainPage.openStatistik();
+        });
+
+        it('should show page on selection', () => {
+          statistikPage.isHeaderTextVisible();
+        });
+
+        it('should mark navigation item as selected', () => {
+          mainPage.isStatistikNavigationItemSelected();
+        });
+      });
+    });
+  });
+});
diff --git a/alfa-client/apps/admin-e2e/src/fixtures/argocd/by-admin-dev.yaml b/alfa-client/apps/admin-e2e/src/fixtures/argocd/by-admin-dev.yaml
index dadb3ca3ebd8236064c6e473e191ace3552a84e1..cebf220d954ac403b96721579ba03a294698c986 100644
--- a/alfa-client/apps/admin-e2e/src/fixtures/argocd/by-admin-dev.yaml
+++ b/alfa-client/apps/admin-e2e/src/fixtures/argocd/by-admin-dev.yaml
@@ -33,6 +33,8 @@ project:
 
 administration:
   enabled: true
+  env:
+    overrideSpringProfiles: 'oc,e2e,dev'
   sso:
     keycloak_users:
       - name: ariane
diff --git a/alfa-client/apps/admin-e2e/src/fixtures/user/user_ariane.json b/alfa-client/apps/admin-e2e/src/fixtures/user/user_ariane.json
index 144c0dc0cfb644f8d47795c6a5605900c831639a..47c5184edc2a2062bdcfa44b89b72ea3d29a01d2 100644
--- a/alfa-client/apps/admin-e2e/src/fixtures/user/user_ariane.json
+++ b/alfa-client/apps/admin-e2e/src/fixtures/user/user_ariane.json
@@ -1,6 +1,7 @@
 {
   "name": "ariane",
-  "password": "Y9nk43yrQ_zzIPpfFU-I",
+  "password_new": "Y9nk43yrQ_zzIPpfFU-I",
+  "password": "123Test!",
   "firstName": "Ariane",
   "lastName": "Admin",
   "fullName": "Ariane Admin",
diff --git a/alfa-client/apps/admin-e2e/src/fixtures/user/user_daria.json b/alfa-client/apps/admin-e2e/src/fixtures/user/user_daria.json
new file mode 100644
index 0000000000000000000000000000000000000000..0ac9cc99af58292dfa0c13ffac4c7f36d49fef93
--- /dev/null
+++ b/alfa-client/apps/admin-e2e/src/fixtures/user/user_daria.json
@@ -0,0 +1,12 @@
+{
+  "name": "daria",
+  "password": "Y9nk43yrQ_zzIPpfFU-I",
+  "firstName": "Daria",
+  "lastName": "Data",
+  "fullName": "Daria Data",
+  "email": "daria.data@ozg-sh.de",
+  "initials": "DD",
+  "dataTestId": "DARIA_DATENBEAUFTRAGUNG",
+  "clientRoles": ["DATENBEAUFTRAGUNG"],
+  "groups": ["E2E Tests"]
+}
diff --git a/alfa-client/apps/admin-e2e/src/fixtures/user/user_safira.json b/alfa-client/apps/admin-e2e/src/fixtures/user/user_safira.json
new file mode 100644
index 0000000000000000000000000000000000000000..1a978c211c729ec44d0d827034d07bf7cd9d9745
--- /dev/null
+++ b/alfa-client/apps/admin-e2e/src/fixtures/user/user_safira.json
@@ -0,0 +1,12 @@
+{
+  "name": "safira",
+  "password": "Y9nk43yrQ_zzIPpfFU-I",
+  "firstName": "Safira",
+  "lastName": "Super",
+  "fullName": "Safira Super",
+  "email": "safira.super@ozg-sh.de",
+  "initials": "SS",
+  "dataTestId": "SAFIRA_ADMIN_DATENBEAUFTRAGUNG",
+  "clientRoles": ["DATENBEAUFTRAGUNG", "ADMIN_ADMIN"],
+  "groups": ["E2E Tests"]
+}
diff --git a/alfa-client/apps/admin-e2e/src/model/util.ts b/alfa-client/apps/admin-e2e/src/model/util.ts
index 93af4b06cb32e05a076a6b4b2343964356d6ecd5..efd196d5bb608c2f48ef32ec1f46524847da91fd 100644
--- a/alfa-client/apps/admin-e2e/src/model/util.ts
+++ b/alfa-client/apps/admin-e2e/src/model/util.ts
@@ -24,3 +24,8 @@
 export class ObjectIdE2E {
   $oid: string;
 }
+
+export enum SnackbarMessagesE2E {
+  NUTZER_ANGELEGT = 'Der Benutzer wurde hinzugefügt.',
+  NUTZER_FEHLGESCHLAGEN = 'Der Benutzer konnte nicht hinzugefügt werden.'
+}
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 8137fc536242c75461320a28b5d49f2e056f52d0..360f51ce884d2e15ec285c10d7b7c2d8eb66856e 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,15 +22,21 @@
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
 import { BuildInfoE2EComponent } from '../components/buildinfo/buildinfo.e2e.component';
+import { containClass } 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 benutzerTab: string = 'caption-Benutzer__Rollen';
   private readonly postfachTab: string = 'caption-Postfach';
   private readonly organisationsEinheitenTab: string = 'caption-Organisationseinheiten';
 
+  private readonly postfachNavigationItem: string = 'postfach-navigation';
+  private readonly organisationEinheitNavigation: string = 'organisations-einheiten-navigation';
+  private readonly statistikNavigationItem: string = 'statistik-navigation';
+
   public getBuildInfo(): BuildInfoE2EComponent {
     return this.buildInfo;
   }
@@ -47,6 +53,14 @@ export class MainPage {
     this.getBenutzerTab().click();
   }
 
+  public getPostfachNavigationItem(): Cypress.Chainable<Element> {
+    return cy.getTestElement(this.postfachNavigationItem);
+  }
+
+  public getOrganisationEinheitNavigationItem(): Cypress.Chainable<Element> {
+    return cy.getTestElement(this.organisationEinheitNavigation);
+  }
+
   public getOrganisationsEinheitenMenu(): Cypress.Chainable<Element> {
     return cy.getTestElement(this.organisationsEinheitenTab);
   }
@@ -54,6 +68,18 @@ export class MainPage {
   public openOrganisationsEinheiten(): void {
     this.getOrganisationsEinheitenMenu().click();
   }
+
+  public getStatistikNavigationItem(): Cypress.Chainable<Element> {
+    return cy.getTestElement(this.statistikNavigationItem);
+  }
+
+  public isStatistikNavigationItemSelected(): void {
+    containClass(this.getStatistikNavigationItem().get('a'), 'border-selected');
+  }
+
+  public openStatistik(): void {
+    this.getStatistikNavigationItem().click();
+  }
 }
 
 export function waitForSpinnerToDisappear(): boolean {
diff --git a/alfa-client/apps/admin-e2e/src/support/angular.util.ts b/alfa-client/apps/admin-e2e/src/support/angular.util.ts
index 7dbeb3b9cc5ff07185971dacf56729a404222d2c..8345e751b5781769282164d36aa7fb6b0bd4636d 100644
--- a/alfa-client/apps/admin-e2e/src/support/angular.util.ts
+++ b/alfa-client/apps/admin-e2e/src/support/angular.util.ts
@@ -39,8 +39,7 @@ enum AngularElementE2E {
 
 export function hasTooltip(element: any, value: string) {
   mouseEnter(element);
-  element.get('mat-tooltip-component').contains(value);
-  // element.get(`div[title="${value}"]`);
+  element.get('ods-tooltip').contains(value);
 }
 
 export function isChecked(element: any) {
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 60db5d0f8610ec03e2cd6c0c34a71e45555612ca..505762fe8f5193921ee7b5bffb76234f5b21393b 100644
--- a/alfa-client/apps/admin-e2e/src/support/cypress.util.ts
+++ b/alfa-client/apps/admin-e2e/src/support/cypress.util.ts
@@ -25,7 +25,7 @@ import { wait } from './cypress-helper';
 
 //TODO Naming der Methoden geradeziehen
 
-export function containClass(element: Cypress.Chainable<Element>, cssClass: string): void {
+export function containClass(element: Cypress.Chainable<any>, cssClass: string): void {
   element.should('have.class', cssClass);
 }
 
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 e05c80cd5947165fef7e2fd7a3dfca65885a0fe2..46f07823c27eee9c7872cc8f72a39a33a5326548 100644
--- a/alfa-client/apps/admin-e2e/src/support/user-util.ts
+++ b/alfa-client/apps/admin-e2e/src/support/user-util.ts
@@ -26,15 +26,23 @@ import { HeaderE2EComponent } from '../page-objects/header.po';
 import { MainPage } from '../page-objects/main.po';
 
 export function loginAsAriane(): void {
-  cy.fixture('user/user_ariane.json').then((user) => {
-    loginByUi(user);
-  });
+  login(UserJsonPath.ARIANE);
+}
+
+export function loginAsDaria(): void {
+  login(UserJsonPath.DARIA);
 }
 
 export function loginAsSabine(): void {
-  cy.fixture('user/user_sabine.json').then((user) => {
-    loginByUi(user);
-  });
+  login(UserJsonPath.SABINE);
+}
+
+export function loginAsSafira(): void {
+  login(UserJsonPath.SAFIRA);
+}
+
+function login(userJson: string): void {
+  cy.fixture(userJson).then((user) => loginByUi(user));
 }
 
 // Hinweis: cacheAcrossSpecs: true lässt Tests umfallen
@@ -60,6 +68,13 @@ export function loginByUi(user: UserE2E): void {
   );
 }
 
+enum UserJsonPath {
+  ARIANE = 'user/user_ariane.json',
+  DARIA = 'user/user_daria.json',
+  SABINE = 'user/user_sabine.json',
+  SAFIRA = 'user/user_safira.json',
+}
+
 export function logout(): void {
   const mainPage: MainPage = new MainPage();
   const header: HeaderE2EComponent = mainPage.getHeader();
@@ -70,6 +85,7 @@ export enum AlfaRollen {
   USER = 'VERWALTUNG_USER',
   LOESCHEN = 'VERWALTUNG_LOESCHEN',
   POSTSTELLE = 'VERWALTUNG_POSTSTELLE',
+  ADMIN = 'ADMIN_ADMIN'
 }
 
 export enum AlfaUsers {
diff --git a/alfa-client/apps/admin/Jenkinsfile b/alfa-client/apps/admin/Jenkinsfile
index 466c2b7d229a7fe30477cd5a464f2120c4307d7c..8ae0ccfcdb74541493558353c758eb9896742caa 100644
--- a/alfa-client/apps/admin/Jenkinsfile
+++ b/alfa-client/apps/admin/Jenkinsfile
@@ -72,7 +72,7 @@ pipeline {
 
                     withNPM(npmrcConfig: 'npm-nexus-auth') {
                         dir('alfa-client') {
-                            sh 'pnpm install --frozen-lockfile --network-concurrency=8'
+                            sh 'pnpm install --frozen-lockfile'
 
 	                        if (isReleaseBranch()) {
 	                        	sh 'pnpm run ci-prodBuild-admin'
diff --git a/alfa-client/apps/admin/src/app/app.component.html b/alfa-client/apps/admin/src/app/app.component.html
index 1bf3181be49c2b39c5f0273266c0f5a07cf75d57..6409e8398c47509d3cfa668979eb5d0e1cd91b26 100644
--- a/alfa-client/apps/admin/src/app/app.component.html
+++ b/alfa-client/apps/admin/src/app/app.component.html
@@ -40,28 +40,24 @@
   </header>
   <div class="flex h-screen w-full justify-center overflow-y-auto">
     <ods-navbar data-test-id="navigation">
-      <ng-container *ngIf="apiRoot | hasLink: apiRootLinkRel.CONFIGURATION">
-        <ng-container *ngIf="environment.features.benutzerRollen">
-          <ods-nav-item data-test-id="users-roles-navigation" caption="Benutzer & Rollen" path="/benutzer_und_rollen">
-            <ods-users-icon class="stroke-text" icon />
-          </ods-nav-item>
-          <hr />
-        </ng-container>
-        <ng-container *ngIf="environment.features.postfach">
-          <ods-nav-item data-test-id="postfach-navigation" caption="Postfach" path="/postfach">
-            <ods-mailbox-icon icon />
-          </ods-nav-item>
-        </ng-container>
-        <ng-container *ngIf="apiRoot | hasLink: apiRootLinkRel.ORGANISATIONS_EINHEIT">
-          <ods-nav-item
-            data-test-id="organisations-einheiten-navigation"
-            caption="Organisationseinheiten"
-            path="/organisationseinheiten"
-          >
-            <ods-orga-unit-icon icon />
-          </ods-nav-item>
-        </ng-container>
-      </ng-container>
+      @if (apiRoot | hasLink: apiRootLinkRel.USERS) {
+        <ods-nav-item data-test-id="users-roles-navigation" caption="Benutzer & Rollen" path="/benutzer_und_rollen">
+          <ods-users-icon class="stroke-text" icon />
+        </ods-nav-item>
+      }
+      @if (apiRoot | hasLink: apiRootLinkRel.ORGANISATIONS_EINHEIT) {
+        <ods-nav-item
+          data-test-id="organisations-einheiten-navigation"
+          caption="Organisationseinheiten"
+          path="/organisationseinheiten"
+        >
+          <ods-orga-unit-icon icon />
+        </ods-nav-item>
+        <hr />
+      }
+      @if (apiRoot | hasLink: apiRootLinkRel.CONFIGURATION) {
+        <admin-menu-container data-test-id="menu-container"></admin-menu-container>
+      }
     </ods-navbar>
     <main class="flex-1 overflow-y-auto bg-white px-6 py-4">
       <router-outlet
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 47e52ca32268a84cd26ea728858fad6b0265e96a..86fda2c791f984af8fbb569cb101d7d7a5911151 100644
--- a/alfa-client/apps/admin/src/app/app.component.spec.ts
+++ b/alfa-client/apps/admin/src/app/app.component.spec.ts
@@ -21,20 +21,14 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
+import { ConfigurationLinkRel, ConfigurationResource, ConfigurationService } from '@admin-client/configuration-shared';
 import { ApiRootLinkRel, ApiRootResource, ApiRootService } from '@alfa-client/api-root-shared';
 import { BuildInfoComponent } from '@alfa-client/common';
-import { getEnvironmentFactory } from '@alfa-client/environment-shared';
 import { HasLinkPipe, createEmptyStateResource, createStateResource } from '@alfa-client/tech-shared';
-import {
-  Mock,
-  dispatchEventFromFixture,
-  existsAsHtmlElement,
-  getElementFromFixture,
-  mock,
-  notExistsAsHtmlElement,
-} from '@alfa-client/test-utils';
+import { Mock, existsAsHtmlElement, mock, notExistsAsHtmlElement } from '@alfa-client/test-utils';
 import { ComponentFixture, TestBed } from '@angular/core/testing';
 import { ActivatedRoute, Router, RouterOutlet } from '@angular/router';
+import { AuthenticationService } from '@authentication';
 import {
   AdminLogoIconComponent,
   MailboxIconComponent,
@@ -43,18 +37,16 @@ import {
   OrgaUnitIconComponent,
   UsersIconComponent,
 } from '@ods/system';
-import { AuthenticationService } from 'authentication';
+import { createConfigurationResource } from 'libs/admin/configuration-shared/test/configuration';
+import { MenuContainerComponent } from 'libs/admin/configuration/src/lib/menu-container/menu-container.component';
 import { createApiRootResource } from 'libs/api-root-shared/test/api-root';
-import { createEnvironment } from 'libs/environment-shared/test/environment';
 import { getDataTestIdOf } from 'libs/tech-shared/test/data-test';
 import { MockComponent, MockDirective } from 'ng-mocks';
-import { of } from 'rxjs';
+import { Subscription, of } from 'rxjs';
 import { UserProfileButtonContainerComponent } from '../common/user-profile-button-container/user-profile.button-container.component';
 import { UnavailablePageComponent } from '../pages/unavailable/unavailable-page/unavailable-page.component';
 import { AppComponent } from './app.component';
 
-jest.mock('@alfa-client/environment-shared');
-
 describe('AppComponent', () => {
   let component: AppComponent;
   let fixture: ComponentFixture<AppComponent>;
@@ -62,15 +54,11 @@ describe('AppComponent', () => {
   const adminHeaderSelector: string = getDataTestIdOf('admin-header');
   const buildInfoSelector: string = getDataTestIdOf('build-info');
   const userProfileButtonSelector: string = getDataTestIdOf('user-profile-button');
-  const navigationSelector: string = getDataTestIdOf('navigation');
   const usersRolesNavigationSelector: string = getDataTestIdOf('users-roles-navigation');
-  const postfachNavigationSelector: string = getDataTestIdOf('postfach-navigation');
+
   const organisationsEinheitenNavigationSelector: string = getDataTestIdOf('organisations-einheiten-navigation');
-  const logoLink: string = getDataTestIdOf('logo-link');
   const routerOutletSelector: string = getDataTestIdOf('router-outlet');
-
-  const environment = createEnvironment();
-  (getEnvironmentFactory as jest.Mock).mockReturnValue(environment);
+  const menuContainer: string = getDataTestIdOf('menu-container');
 
   const authenticationService: Mock<AuthenticationService> = {
     ...mock(AuthenticationService),
@@ -91,9 +79,13 @@ describe('AppComponent', () => {
   };
 
   const apiRootService: Mock<ApiRootService> = mock(ApiRootService);
+  let configurationService: Mock<ConfigurationService>;
 
   beforeEach(async () => {
+    configurationService = mock(ConfigurationService);
+
     await TestBed.configureTestingModule({
+      imports: [HasLinkPipe],
       declarations: [
         AppComponent,
         MockComponent(AdminLogoIconComponent),
@@ -105,7 +97,7 @@ describe('AppComponent', () => {
         MockComponent(NavbarComponent),
         MockComponent(NavItemComponent),
         MockComponent(BuildInfoComponent),
-        HasLinkPipe,
+        MockComponent(MenuContainerComponent),
         MockDirective(RouterOutlet),
       ],
       providers: [
@@ -117,6 +109,10 @@ describe('AppComponent', () => {
           provide: ApiRootService,
           useValue: apiRootService,
         },
+        {
+          provide: ConfigurationService,
+          useValue: configurationService,
+        },
         {
           provide: Router,
           useValue: router,
@@ -159,127 +155,272 @@ describe('AppComponent', () => {
     });
 
     describe('do after logged in', () => {
+      beforeEach(() => {
+        component.evaluateInitialNavigation = jest.fn();
+      });
+
       it('should call apiRootService to getApiRoot', () => {
         component.doAfterLoggedIn();
 
         expect(apiRootService.getApiRoot).toHaveBeenCalled();
       });
 
-      it('should call forwardWithoutAuthenticationParams', () => {
-        component.forwardWithoutAuthenticationParams = jest.fn();
+      it('should call evaluateInitialNavigation', () => {
+        component.evaluateInitialNavigation = jest.fn();
 
         component.doAfterLoggedIn();
 
-        expect(component.forwardWithoutAuthenticationParams).toHaveBeenCalled();
+        expect(component.evaluateInitialNavigation).toHaveBeenCalled();
       });
     });
 
-    describe('forward without authentication params', () => {
-      it('should navigate to same route without authentication params', () => {
-        component.forwardWithoutAuthenticationParams();
+    describe('evaluate initial navigation', () => {
+      beforeEach(() => {
+        component.evaluateNavigationByApiRoot = jest.fn();
+      });
+
+      it('should call evaluate navigation by apiRoot', () => {
+        const apiRootResource: ApiRootResource = createApiRootResource();
+        component.apiRootStateResource$ = of(createStateResource(apiRootResource));
 
-        expect(router.navigate).toHaveBeenCalledWith([], { queryParams: {} });
+        component.evaluateInitialNavigation();
+
+        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.evaluateInitialNavigation();
+
+        expect(component.evaluateNavigationByApiRoot).not.toHaveBeenCalled();
       });
     });
-  });
 
-  describe('template', () => {
-    it('show not show header if apiRoot is not loaded', () => {
-      component.apiRootStateResource$ = of(createEmptyStateResource<ApiRootResource>());
+    describe('evaluate navigation api root', () => {
+      it('should evaluate navigation by configuration if link exists', () => {
+        component.evaluateNavigationByConfiguration = jest.fn();
+        const apiRootResource: ApiRootResource = createApiRootResource([ApiRootLinkRel.CONFIGURATION]);
 
-      notExistsAsHtmlElement(fixture, adminHeaderSelector);
+        component.evaluateNavigationByApiRoot(apiRootResource);
+
+        expect(component.evaluateNavigationByConfiguration).toHaveBeenCalled();
+      });
+
+      it('should navigate by api root if link is missing', () => {
+        component.navigateByApiRoot = jest.fn();
+        const apiRootResource: ApiRootResource = createApiRootResource();
+
+        component.evaluateNavigationByApiRoot(apiRootResource);
+
+        expect(component.navigateByApiRoot).toHaveBeenCalledWith(apiRootResource);
+      });
     });
 
-    describe('user profile button', () => {
+    describe('evaluate navigation by configuration', () => {
+      const configurationResource: ConfigurationResource = createConfigurationResource();
+
       beforeEach(() => {
-        component.apiRootStateResource$ = of(createStateResource(createApiRootResource()));
+        configurationService.get.mockReturnValue(of(createStateResource(configurationResource)));
+        component.navigateByConfiguration = jest.fn();
       });
 
-      it('should show if apiRoot exists', () => {
-        fixture.detectChanges();
+      it('should call configuration service to get resource', () => {
+        component.evaluateNavigationByConfiguration();
 
-        existsAsHtmlElement(fixture, userProfileButtonSelector);
+        expect(configurationService.get).toHaveBeenCalled();
+      });
+
+      it('should call navigate by configuration', () => {
+        component.evaluateNavigationByConfiguration();
+
+        expect(component.navigateByConfiguration).toHaveBeenCalledWith(configurationResource);
       });
-    });
 
-    describe('administration logo', () => {
-      const apiResource: ApiRootResource = createApiRootResource();
+      it('should NOT call navigate by configuration if resource is loading', () => {
+        configurationService.get.mockReturnValue(of(createEmptyStateResource<ConfigurationResource>(true)));
 
+        component.evaluateNavigationByConfiguration();
+
+        expect(component.navigateByConfiguration).not.toHaveBeenCalled();
+      });
+    });
+
+    describe('navigate by configuration', () => {
       beforeEach(() => {
-        component.apiRootStateResource$ = of(createStateResource(apiResource));
-        fixture.detectChanges();
+        component.unsubscribe = jest.fn();
+      });
+
+      it('should navigate to postfach if settings link exists', () => {
+        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]));
+
+        expect(router.navigate).toHaveBeenCalledWith(['/statistik']);
       });
 
-      it('should navigate to start page on click', () => {
-        dispatchEventFromFixture(fixture, logoLink, 'click');
+      it('should navigate to unavailable page if no link exists', () => {
+        component.navigateByConfiguration(createConfigurationResource());
 
-        expect(router.navigate).toHaveBeenCalledWith([], { queryParams: {} });
+        expect(router.navigate).toHaveBeenCalledWith(['/unavailable']);
+      });
+
+      it('should call unsubscribe', () => {
+        component.navigateByConfiguration(createConfigurationResource());
+
+        expect(component.unsubscribe).toHaveBeenCalled();
       });
     });
 
-    describe('navigation', () => {
+    describe('navigate by api root', () => {
       beforeEach(() => {
-        component.apiRootStateResource$ = of(createStateResource(createApiRootResource([ApiRootLinkRel.CONFIGURATION])));
+        component.unsubscribe = jest.fn();
       });
 
-      it('should show links if configuration link exists', () => {
-        fixture.detectChanges();
+      it('should navigate to benutzer und rollen if users link exists', () => {
+        const apiRootResource: ApiRootResource = createApiRootResource([ApiRootLinkRel.USERS]);
 
-        const navbarElement: HTMLElement = getElementFromFixture(fixture, navigationSelector);
+        component.navigateByApiRoot(apiRootResource);
 
-        expect(navbarElement.children.length).toBeGreaterThan(0);
+        expect(router.navigate).toHaveBeenCalledWith(['/benutzer_und_rollen']);
       });
 
-      it('should not not show links if configuration resource not available', () => {
-        component.apiRootStateResource$ = of(createStateResource(createApiRootResource([])));
-        fixture.detectChanges();
+      it('should navigate to unavailable page if no link exists', () => {
+        component.navigateByApiRoot(createApiRootResource());
 
-        const navbarElement: HTMLElement = getElementFromFixture(fixture, navigationSelector);
+        expect(router.navigate).toHaveBeenCalledWith(['/unavailable']);
+      });
 
-        expect(navbarElement.children.length).toBe(0);
+      it('should call unsubscribe', () => {
+        component.navigateByApiRoot(createApiRootResource());
+
+        expect(component.unsubscribe).toHaveBeenCalled();
       });
+    });
 
-      it('should show postfach link if postfach feature toggle is true', () => {
-        component.environment.features.postfach = true;
-        fixture.detectChanges();
+    describe('unsubscribe', () => {
+      describe('apiRoot subscription', () => {
+        it('should unsubscribe if exists', () => {
+          component.apiRootSubscription = <any>mock(Subscription);
+          component.apiRootSubscription.unsubscribe = jest.fn();
+
+          component.unsubscribe();
+
+          expect(component.apiRootSubscription.unsubscribe).toHaveBeenCalled();
+        });
+
+        it('should do nothing if not exists', () => {
+          component.apiRootSubscription = undefined;
+          const unsubscribeSpy: jest.SpyInstance = jest.spyOn(Subscription.prototype, 'unsubscribe');
 
-        existsAsHtmlElement(fixture, postfachNavigationSelector);
+          component.unsubscribe();
+
+          expect(unsubscribeSpy).not.toHaveBeenCalled();
+          unsubscribeSpy.mockRestore();
+        });
       });
 
-      it('should not show postfach link if postfach feature toggle is false', () => {
-        component.environment.features.postfach = false;
-        fixture.detectChanges();
+      describe('configuration subscription', () => {
+        it('should unsubscribe if exists', () => {
+          component.configurationSubscription = <any>mock(Subscription);
+          component.configurationSubscription.unsubscribe = jest.fn();
+
+          component.unsubscribe();
+
+          expect(component.configurationSubscription.unsubscribe).toHaveBeenCalled();
+        });
+
+        it('should do nothing if not exists', () => {
+          component.apiRootSubscription = undefined;
+          const unsubscribeSpy: jest.SpyInstance = jest.spyOn(Subscription.prototype, 'unsubscribe');
+
+          component.unsubscribe();
 
-        notExistsAsHtmlElement(fixture, postfachNavigationSelector);
+          expect(unsubscribeSpy).not.toHaveBeenCalled();
+          unsubscribeSpy.mockRestore();
+        });
       });
+    });
+  });
 
-      it('should show benutzer & rollen if benutzerRollen feature toggle is true', () => {
-        component.environment.features.benutzerRollen = true;
-        fixture.detectChanges();
+  describe('template', () => {
+    it('show not show header if apiRoot is not loaded', () => {
+      component.apiRootStateResource$ = of(createEmptyStateResource<ApiRootResource>());
 
-        existsAsHtmlElement(fixture, usersRolesNavigationSelector);
+      notExistsAsHtmlElement(fixture, adminHeaderSelector);
+    });
+
+    describe('user profile button', () => {
+      beforeEach(() => {
+        component.apiRootStateResource$ = of(createStateResource(createApiRootResource()));
       });
 
-      it('should not show benutzer & rollen if benutzerRollen feature toggle is false', () => {
-        component.environment.features.benutzerRollen = false;
+      it('should show if apiRoot exists', () => {
         fixture.detectChanges();
 
-        notExistsAsHtmlElement(fixture, usersRolesNavigationSelector);
+        existsAsHtmlElement(fixture, userProfileButtonSelector);
       });
+    });
 
-      it('should show organisationsEinheiten if link in apiRoot exists', () => {
-        component.apiRootStateResource$ = of(
-          createStateResource(createApiRootResource([ApiRootLinkRel.ORGANISATIONS_EINHEIT, ApiRootLinkRel.CONFIGURATION])),
-        );
-        fixture.detectChanges();
+    describe('navigation', () => {
+      describe('user and roles', () => {
+        it('should show if users link is present', () => {
+          component.apiRootStateResource$ = of(
+            createStateResource(createApiRootResource([ApiRootLinkRel.CONFIGURATION, ApiRootLinkRel.USERS])),
+          );
+
+          fixture.detectChanges();
+
+          existsAsHtmlElement(fixture, usersRolesNavigationSelector);
+        });
 
-        existsAsHtmlElement(fixture, organisationsEinheitenNavigationSelector);
+        it('should hide if link is missing', () => {
+          component.apiRootStateResource$ = of(createStateResource(createApiRootResource([ApiRootLinkRel.CONFIGURATION])));
+
+          fixture.detectChanges();
+
+          notExistsAsHtmlElement(fixture, usersRolesNavigationSelector);
+        });
       });
 
-      it('should not show organisationsEinheiten if link in apiRoot does not exist', () => {
-        fixture.detectChanges();
+      describe('organisationEinheiten', () => {
+        it('should show if link in apiRoot exists', () => {
+          component.apiRootStateResource$ = of(
+            createStateResource(createApiRootResource([ApiRootLinkRel.ORGANISATIONS_EINHEIT, ApiRootLinkRel.CONFIGURATION])),
+          );
+          fixture.detectChanges();
+
+          existsAsHtmlElement(fixture, organisationsEinheitenNavigationSelector);
+        });
+
+        it('should hide if link in apiRoot does not exist', () => {
+          fixture.detectChanges();
+
+          notExistsAsHtmlElement(fixture, organisationsEinheitenNavigationSelector);
+        });
+      });
+
+      describe('menu', () => {
+        it('should show if link exists', () => {
+          component.apiRootStateResource$ = of(createStateResource(createApiRootResource([ApiRootLinkRel.CONFIGURATION])));
+
+          fixture.detectChanges();
+
+          existsAsHtmlElement(fixture, menuContainer);
+        });
+
+        it('should hide if link is missing', () => {
+          component.apiRootStateResource$ = of(createStateResource(createApiRootResource()));
+
+          fixture.detectChanges();
 
-        notExistsAsHtmlElement(fixture, organisationsEinheitenNavigationSelector);
+          notExistsAsHtmlElement(fixture, menuContainer);
+        });
       });
     });
 
diff --git a/alfa-client/apps/admin/src/app/app.component.ts b/alfa-client/apps/admin/src/app/app.component.ts
index 11944356c6944e3fcd7faf4a6e1cbb030ddc90a0..c9d3c4f536cf6cee9f74f43f206bf02bdc01f397 100644
--- a/alfa-client/apps/admin/src/app/app.component.ts
+++ b/alfa-client/apps/admin/src/app/app.component.ts
@@ -21,23 +21,25 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
+import { MenuContainerComponent } from '@admin-client/configuration';
+import { ConfigurationLinkRel, ConfigurationResource, ConfigurationService } from '@admin-client/configuration-shared';
+import { ROUTES } from '@admin-client/shared';
 import { ApiRootLinkRel, ApiRootResource, ApiRootService } from '@alfa-client/api-root-shared';
 import { BuildInfoComponent } from '@alfa-client/common';
-import { Environment, getEnvironmentFactory } from '@alfa-client/environment-shared';
-import { StateResource, TechSharedModule } from '@alfa-client/tech-shared';
+import { isLoaded, isNotUndefined, mapToResource, StateResource, TechSharedModule } from '@alfa-client/tech-shared';
 import { CommonModule } from '@angular/common';
-import { Component, OnInit } from '@angular/core';
-import { ActivatedRoute, Params, Router, RouterOutlet } from '@angular/router';
+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,
-  MailboxIconComponent,
   NavbarComponent,
   NavItemComponent,
   OrgaUnitIconComponent,
   UsersIconComponent,
 } from '@ods/system';
-import { AuthenticationService } from 'libs/authentication/src/lib/authentication.service';
-import { Observable } from 'rxjs';
+import { filter, Observable, Subscription } from 'rxjs';
 import { UserProfileButtonContainerComponent } from '../common/user-profile-button-container/user-profile.button-container.component';
 import { UnavailablePageComponent } from '../pages/unavailable/unavailable-page/unavailable-page.component';
 
@@ -53,28 +55,29 @@ import { UnavailablePageComponent } from '../pages/unavailable/unavailable-page/
     UsersIconComponent,
     UserProfileButtonContainerComponent,
     AdminLogoIconComponent,
-    MailboxIconComponent,
     OrgaUnitIconComponent,
     RouterOutlet,
     UnavailablePageComponent,
     BuildInfoComponent,
     TechSharedModule,
+    MenuContainerComponent,
+    RouterLink,
   ],
 })
 export class AppComponent implements OnInit {
-  readonly title = 'admin';
+  readonly title: string = 'admin';
+
+  private readonly authenticationService = inject(AuthenticationService);
+  private readonly apiRootService = inject(ApiRootService);
+  private readonly router = inject(Router);
+  private readonly configurationService = inject(ConfigurationService);
 
   public apiRootStateResource$: Observable<StateResource<ApiRootResource>>;
-  public readonly environment: Environment = getEnvironmentFactory();
 
-  public readonly apiRootLinkRel = ApiRootLinkRel;
+  apiRootSubscription: Subscription;
+  configurationSubscription: Subscription;
 
-  constructor(
-    public authenticationService: AuthenticationService,
-    private apiRootService: ApiRootService,
-    private router: Router,
-    private route: ActivatedRoute,
-  ) {}
+  public readonly apiRootLinkRel = ApiRootLinkRel;
 
   ngOnInit(): void {
     this.authenticationService.login().then(() => this.doAfterLoggedIn());
@@ -82,16 +85,56 @@ export class AppComponent implements OnInit {
 
   doAfterLoggedIn(): void {
     this.apiRootStateResource$ = this.apiRootService.getApiRoot();
-    this.forwardWithoutAuthenticationParams();
+    this.evaluateInitialNavigation();
+  }
+
+  evaluateInitialNavigation(): void {
+    this.apiRootSubscription = this.apiRootStateResource$
+      .pipe(filter(isLoaded), mapToResource<ApiRootResource>())
+      .subscribe((apiRootResource: ApiRootResource) => this.evaluateNavigationByApiRoot(apiRootResource));
+  }
+
+  evaluateNavigationByApiRoot(apiRootResource: ApiRootResource): void {
+    if (hasLink(apiRootResource, ApiRootLinkRel.CONFIGURATION)) {
+      this.evaluateNavigationByConfiguration();
+    } else {
+      this.navigateByApiRoot(apiRootResource);
+    }
+  }
+
+  evaluateNavigationByConfiguration(): void {
+    this.configurationSubscription = this.configurationService
+      .get()
+      .pipe(filter(isLoaded), mapToResource<ApiRootResource>())
+      .subscribe((configurationResource: ConfigurationResource) => this.navigateByConfiguration(configurationResource));
+  }
+
+  navigateByConfiguration(configurationResource: ConfigurationResource): void {
+    if (hasLink(configurationResource, ConfigurationLinkRel.SETTING)) {
+      this.navigate(ROUTES.POSTFACH);
+    } else if (hasLink(configurationResource, ConfigurationLinkRel.AGGREGATION_MAPPINGS)) {
+      this.navigate(ROUTES.STATISTIK);
+    } else {
+      this.navigate(ROUTES.UNAVAILABLE);
+    }
+    this.unsubscribe();
+  }
+
+  navigateByApiRoot(apiRootResource: ApiRootResource): void {
+    if (hasLink(apiRootResource, ApiRootLinkRel.USERS)) {
+      this.navigate(ROUTES.BENUTZER_UND_ROLLEN);
+    } else {
+      this.navigate(ROUTES.UNAVAILABLE);
+    }
+    this.unsubscribe();
   }
 
-  forwardWithoutAuthenticationParams() {
-    const queryParams = this.getQueryParamsWithoutAuthentication();
-    this.router.navigate([], { queryParams });
+  private navigate(routePath: string): void {
+    this.router.navigate(['/' + routePath]);
   }
 
-  private getQueryParamsWithoutAuthentication(): Params {
-    const { iss, state, session_state, code, ...queryParams } = this.route.snapshot.queryParams;
-    return queryParams;
+  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
new file mode 100644
index 0000000000000000000000000000000000000000..24e0a21eca4fb630c66112e19ba4b0024bf983a9
--- /dev/null
+++ b/alfa-client/apps/admin/src/app/app.guard.spec.ts
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2025 Das Land Schleswig-Holstein vertreten durch den
+ * Ministerpräsidenten des Landes Schleswig-Holstein
+ * Staatskanzlei
+ * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+ *
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+import { ConfigurationResource, ConfigurationService } from '@admin-client/configuration-shared';
+import { ApiRootResource, ApiRootService } from '@alfa-client/api-root-shared';
+import { createStateResource, LinkRelationName, StateResource } from '@alfa-client/tech-shared';
+import { Mock, mock, useFromMock } from '@alfa-client/test-utils';
+import { TestBed } from '@angular/core/testing';
+import { ActivatedRouteSnapshot, Router, UrlTree } from '@angular/router';
+import { Resource } from '@ngxp/rest';
+import { createConfigurationResource } from 'libs/admin/configuration-shared/test/configuration';
+import { createApiRootResource } from 'libs/api-root-shared/test/api-root';
+import { DummyLinkRel } from 'libs/tech-shared/test/dummy';
+import { createDummyResource } from 'libs/tech-shared/test/resource';
+import { Observable, of } from 'rxjs';
+import { GuardData } from './app.routes';
+
+import * as Guard from './app.guard';
+
+describe('Guard', () => {
+  const linkRelName: LinkRelationName = DummyLinkRel.DUMMY;
+  const route: ActivatedRouteSnapshot = <any>{ data: <GuardData>{ linkRelName } };
+
+  describe('api root guard', () => {
+    let apiRootService: Mock<ApiRootService>;
+
+    const apiRootStateResource$: Observable<StateResource<ApiRootResource>> = of(createStateResource(createApiRootResource()));
+
+    beforeEach(() => {
+      apiRootService = mock(ApiRootService);
+
+      TestBed.configureTestingModule({
+        providers: [
+          {
+            provide: ApiRootService,
+            useValue: apiRootService,
+          },
+        ],
+      });
+    });
+
+    beforeEach(() => {
+      apiRootService.getApiRoot.mockReturnValue(apiRootStateResource$);
+      jest.spyOn(Guard, 'evaluate').mockReturnValue(of(true));
+    });
+
+    afterEach(() => {
+      jest.restoreAllMocks();
+    });
+
+    it('should call apiRootService', () => {
+      runGuard().subscribe();
+
+      expect(apiRootService.getApiRoot).toHaveBeenCalled();
+    });
+
+    it('should call evaluate', () => {
+      const evaluateSpy: jest.SpyInstance = jest.spyOn(Guard, 'evaluate').mockReturnValue(of(true));
+
+      runGuard().subscribe();
+
+      expect(evaluateSpy).toHaveBeenCalledWith(apiRootStateResource$, DummyLinkRel.DUMMY);
+    });
+
+    function runGuard(): Observable<boolean | UrlTree> {
+      return <Observable<boolean | UrlTree>>TestBed.runInInjectionContext(() => Guard.apiRootGuard(route, null));
+    }
+  });
+
+  describe('configuration guard', () => {
+    let configurationService: Mock<ConfigurationService>;
+
+    const configurationStateResource$: Observable<StateResource<ConfigurationResource>> = of(
+      createStateResource(createConfigurationResource()),
+    );
+
+    beforeEach(() => {
+      configurationService = mock(ConfigurationService);
+
+      TestBed.configureTestingModule({
+        providers: [
+          {
+            provide: ConfigurationService,
+            useValue: configurationService,
+          },
+        ],
+      });
+    });
+
+    beforeEach(() => {
+      configurationService.get.mockReturnValue(configurationStateResource$);
+      jest.spyOn(Guard, 'evaluate').mockReturnValue(of(true));
+    });
+
+    afterEach(() => {
+      jest.restoreAllMocks();
+    });
+
+    it('should call configurationService', () => {
+      runGuard().subscribe();
+
+      expect(configurationService.get).toHaveBeenCalled();
+    });
+
+    it('should call evaluate', () => {
+      const evaluateSpy: jest.SpyInstance = jest.spyOn(Guard, 'evaluate').mockReturnValue(of(true));
+
+      runGuard().subscribe();
+
+      expect(evaluateSpy).toHaveBeenCalledWith(configurationStateResource$, DummyLinkRel.DUMMY);
+    });
+
+    function runGuard(): Observable<boolean | UrlTree> {
+      return <Observable<boolean | UrlTree>>TestBed.runInInjectionContext(() => Guard.configurationGuard(route, null));
+    }
+  });
+
+  describe('evaluate', () => {
+    const resource: Resource = createDummyResource([DummyLinkRel.DUMMY]);
+    const stateResource$: Observable<StateResource<Resource>> = of(createStateResource(resource));
+
+    afterEach(() => {
+      jest.restoreAllMocks();
+    });
+
+    it('should evaluate resource', () => {
+      const urlTreeMock: Mock<UrlTree> = mock(UrlTree);
+      const evaluateResourceSpy: jest.SpyInstance = jest
+        .spyOn(Guard, 'evaluateResource')
+        .mockReturnValue(useFromMock(urlTreeMock));
+
+      evaluate().subscribe();
+
+      expect(evaluateResourceSpy).toHaveBeenCalledWith(resource, DummyLinkRel.DUMMY);
+    });
+
+    it('should return evaluated boolean', (done) => {
+      jest.spyOn(Guard, 'evaluateResource').mockReturnValue(true);
+
+      evaluate().subscribe((resolvedValue) => {
+        expect(resolvedValue).toEqual(true);
+        done();
+      });
+    });
+
+    it('should return evaluated url tree', (done) => {
+      const urlTreeMock: Mock<UrlTree> = mock(UrlTree);
+      jest.spyOn(Guard, 'evaluateResource').mockReturnValue(useFromMock(urlTreeMock));
+
+      evaluate().subscribe((resolvedValue) => {
+        expect(resolvedValue).toEqual(urlTreeMock);
+        done();
+      });
+    });
+
+    function evaluate(): Observable<boolean | UrlTree> {
+      return <Observable<boolean | UrlTree>>(
+        TestBed.runInInjectionContext(() => Guard.evaluate(stateResource$, DummyLinkRel.DUMMY))
+      );
+    }
+  });
+
+  describe('evaluate resource', () => {
+    let router: Mock<Router>;
+
+    beforeEach(() => {
+      router = mock(Router);
+
+      TestBed.configureTestingModule({
+        providers: [
+          {
+            provide: Router,
+            useValue: router,
+          },
+        ],
+      });
+    });
+
+    afterEach(() => {
+      jest.restoreAllMocks();
+    });
+
+    it('should return true if link exists', () => {
+      const result: boolean = <boolean>evaluateResource(createDummyResource([DummyLinkRel.DUMMY]));
+
+      expect(result).toBeTruthy();
+    });
+
+    describe('if link not exists', () => {
+      it('should call router', () => {
+        evaluateResource(createDummyResource());
+
+        expect(router.createUrlTree).toHaveBeenCalledWith(['/unavailable']);
+      });
+
+      it('should return redirect route', () => {
+        const urlTree: Mock<UrlTree> = mock(UrlTree);
+        router.createUrlTree.mockReturnValue(urlTree);
+
+        const result: UrlTree = <UrlTree>evaluateResource(createDummyResource());
+
+        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
new file mode 100644
index 0000000000000000000000000000000000000000..85625be095c256aa593faa2d0d415352258aa1e0
--- /dev/null
+++ b/alfa-client/apps/admin/src/app/app.guard.ts
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2025 Das Land Schleswig-Holstein vertreten durch den
+ * Ministerpräsidenten des Landes Schleswig-Holstein
+ * Staatskanzlei
+ * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+ *
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+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 { hasLink, Resource } from '@ngxp/rest';
+import { filter, map, Observable } 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) => {
+  const apiRootService: ApiRootService = inject(ApiRootService);
+  return Guard.evaluate(apiRootService.getApiRoot(), getLinkRelationName(route));
+};
+
+export const configurationGuard: CanActivateFn = (route: ActivatedRouteSnapshot) => {
+  const configurationService: ConfigurationService = inject(ConfigurationService);
+  return Guard.evaluate(configurationService.get(), getLinkRelationName(route));
+};
+
+export function evaluate(
+  stateResource$: Observable<StateResource<Resource>>,
+  linkRelationName: LinkRelationName,
+): Observable<boolean | UrlTree> {
+  return stateResource$.pipe(
+    filter((stateResource: StateResource<Resource>) => stateResource.loaded),
+    mapToResource<Resource>(),
+    map((resource: Resource) => Guard.evaluateResource(resource, linkRelationName)),
+  );
+}
+
+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();
+}
+
+function redirectToUnavailable(): UrlTree {
+  return inject(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 0886fc15cf87a9708f8939ce22e603b1bf312cf1..a7ed852a6132c902566603a81021da5d46f2357f 100644
--- a/alfa-client/apps/admin/src/app/app.routes.ts
+++ b/alfa-client/apps/admin/src/app/app.routes.ts
@@ -21,34 +21,44 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
+import { ConfigurationLinkRel } from '@admin-client/configuration-shared';
 import { ROUTES } from '@admin-client/shared';
+import { ApiRootLinkRel } from '@alfa-client/api-root-shared';
 import { Route } from '@angular/router';
 import { OrganisationsEinheitFormPageComponent } from '../pages/organisationseinheit/organisationseinheit-form-page/organisationseinheit-form-page.component';
 import { OrganisationsEinheitPageComponent } from '../pages/organisationseinheit/organisationseinheit-page/organisationseinheit-page.component';
 import { PostfachPageComponent } from '../pages/postfach/postfach-page/postfach-page.component';
+import { StatistikPageComponent } from '../pages/statistik/statistik-page/statistik-page.component';
+import { UnavailablePageComponent } from '../pages/unavailable/unavailable-page/unavailable-page.component';
 import { UserAddPageComponent } from '../pages/users-roles/user-add-page/user-add-page.component';
 import { UserRolesPageComponent } from '../pages/users-roles/user-roles-page/user-roles-page.component';
+import { apiRootGuard, configurationGuard } from './app.guard';
+
+export interface GuardData {
+  linkRelName: string;
+}
 
 export const appRoutes: Route[] = [
-  {
-    path: '',
-    redirectTo: ROUTES.POSTFACH,
-    pathMatch: 'full',
-  },
   {
     path: ROUTES.POSTFACH,
     component: PostfachPageComponent,
     title: 'Admin | Postfach',
+    canActivate: [configurationGuard],
+    data: <GuardData>{ linkRelName: ConfigurationLinkRel.SETTING },
   },
   {
     path: ROUTES.BENUTZER_UND_ROLLEN,
     component: UserRolesPageComponent,
     title: 'Admin | Benutzer & Rollen',
+    canActivate: [apiRootGuard],
+    data: <GuardData>{ linkRelName: ApiRootLinkRel.USERS },
   },
   {
     path: ROUTES.BENUTZER_UND_ROLLEN_NEU,
     component: UserAddPageComponent,
     title: 'Admin | Benutzer anlegen',
+    canActivate: [apiRootGuard],
+    data: <GuardData>{ linkRelName: ApiRootLinkRel.USERS },
   },
   {
     path: ROUTES.ORGANISATIONSEINHEITEN,
@@ -60,4 +70,16 @@ export const appRoutes: Route[] = [
     component: OrganisationsEinheitFormPageComponent,
     title: 'Admin | Organisationseinheit',
   },
+  {
+    path: ROUTES.UNAVAILABLE,
+    component: UnavailablePageComponent,
+    title: 'Unavailable',
+  },
+  {
+    path: ROUTES.STATISTIK,
+    component: StatistikPageComponent,
+    title: 'Admin | Statistik',
+    canActivate: [configurationGuard],
+    data: <GuardData>{ linkRelName: ConfigurationLinkRel.AGGREGATION_MAPPINGS },
+  },
 ];
diff --git a/alfa-client/apps/admin/src/common/user-profile-button-container/user-profile-button-container.component.spec.ts b/alfa-client/apps/admin/src/common/user-profile-button-container/user-profile-button-container.component.spec.ts
index 4593934bfd05732c53156c7d324a877c4de3a6f5..b40a661442d6728f6c7819a0548e556d615197a8 100644
--- a/alfa-client/apps/admin/src/common/user-profile-button-container/user-profile-button-container.component.spec.ts
+++ b/alfa-client/apps/admin/src/common/user-profile-button-container/user-profile-button-container.component.spec.ts
@@ -25,7 +25,7 @@ import { dispatchEventFromFixture, getElementFromFixture, mock, Mock } from '@al
 import { ComponentFixture, TestBed } from '@angular/core/testing';
 import { RouterTestingModule } from '@angular/router/testing';
 import { DropdownMenuButtonItemComponent, DropdownMenuComponent, LogoutIconComponent } from '@ods/system';
-import { AuthenticationService } from 'authentication';
+import { AuthenticationService } from '@authentication';
 import { getDataTestIdOf } from 'libs/tech-shared/test/data-test';
 import { MockComponent } from 'ng-mocks';
 import { UserProfileButtonContainerComponent } from './user-profile.button-container.component';
diff --git a/alfa-client/apps/admin/src/common/user-profile-button-container/user-profile.button-container.component.ts b/alfa-client/apps/admin/src/common/user-profile-button-container/user-profile.button-container.component.ts
index 439d995011c6250518b0b57bd70629bfd1e08055..f2f4bd8351b8eb6be525ce81a68c8aec3c081a6e 100644
--- a/alfa-client/apps/admin/src/common/user-profile-button-container/user-profile.button-container.component.ts
+++ b/alfa-client/apps/admin/src/common/user-profile-button-container/user-profile.button-container.component.ts
@@ -23,7 +23,7 @@
  */
 import { Component, OnInit } from '@angular/core';
 import { DropdownMenuButtonItemComponent, DropdownMenuComponent, LogoutIconComponent } from '@ods/system';
-import { AuthenticationService } from 'authentication';
+import { AuthenticationService } from '@authentication';
 
 @Component({
   selector: 'user-profile-button-container',
diff --git a/alfa-client/apps/admin/src/main.ts b/alfa-client/apps/admin/src/main.ts
index 6d84faade1f163c40b471a12d75778e7aba687ca..a11d1ca1749fda041fdb06e60534a92fa4da183a 100644
--- a/alfa-client/apps/admin/src/main.ts
+++ b/alfa-client/apps/admin/src/main.ts
@@ -38,7 +38,7 @@ import { StoreRouterConnectingModule } from '@ngrx/router-store';
 import { StoreModule } from '@ngrx/store';
 import { StoreDevtoolsModule } from '@ngrx/store-devtools';
 import { OAuthModule } from 'angular-oauth2-oidc';
-import { HttpUnauthorizedInterceptor } from 'authentication';
+import { HttpUnauthorizedInterceptor } from '@authentication';
 import { ConfigurationsProviders } from 'libs/admin/configuration-shared/src/lib/configuration.providers';
 import { OrganisationEinheitProviders } from 'libs/admin/organisations-einheit-shared/src/lib/organisations-einheit.providers';
 import { PostfachProviders } from 'libs/admin/postfach-shared/src/lib/postfach.providers';
diff --git a/alfa-client/apps/admin/src/pages/organisationseinheit/organisationseinheit-form-page/organisationseinheit-form-page.component.html b/alfa-client/apps/admin/src/pages/organisationseinheit/organisationseinheit-form-page/organisationseinheit-form-page.component.html
index cb9bf3ffd04a1caacde740c71fc98b9ead6a057e..676e114ce2927e1c3fec27e3f602d572b1c9f978 100644
--- a/alfa-client/apps/admin/src/pages/organisationseinheit/organisationseinheit-form-page/organisationseinheit-form-page.component.html
+++ b/alfa-client/apps/admin/src/pages/organisationseinheit/organisationseinheit-form-page/organisationseinheit-form-page.component.html
@@ -23,8 +23,4 @@
     unter der Lizenz sind dem Lizenztext zu entnehmen.
 
 -->
-<ng-container *ngIf="(apiRootStateResource$ | async)?.resource as apiRoot">
-  @if (apiRoot | hasLink: apiRootLinkRel.ORGANISATIONS_EINHEIT) {
-    <admin-organisations-einheit-form-container data-test-id="organisations-einheit-form" />
-  }
-</ng-container>
\ No newline at end of file
+<admin-organisations-einheit-form-container data-test-id="organisations-einheit-form" />
\ No newline at end of file
diff --git a/alfa-client/apps/admin/src/pages/organisationseinheit/organisationseinheit-form-page/organisationseinheit-form-page.component.spec.ts b/alfa-client/apps/admin/src/pages/organisationseinheit/organisationseinheit-form-page/organisationseinheit-form-page.component.spec.ts
index 081e864d889b4390e5951d5ae3a757b687cde6ab..4777b881b3bbf511f7effed9cfb8d48bf355fbe7 100644
--- a/alfa-client/apps/admin/src/pages/organisationseinheit/organisationseinheit-form-page/organisationseinheit-form-page.component.spec.ts
+++ b/alfa-client/apps/admin/src/pages/organisationseinheit/organisationseinheit-form-page/organisationseinheit-form-page.component.spec.ts
@@ -22,33 +22,18 @@
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
 import { OrganisationsEinheitFormContainerComponent } from '@admin-client/organisations-einheit';
-import { ApiRootLinkRel, ApiRootResource, ApiRootService } from '@alfa-client/api-root-shared';
-import { createStateResource, StateResource, TechSharedModule } from '@alfa-client/tech-shared';
-import { existsAsHtmlElement, mock, Mock, notExistsAsHtmlElement } from '@alfa-client/test-utils';
-import { CommonModule } from '@angular/common';
 import { ComponentFixture, TestBed } from '@angular/core/testing';
-import { createApiRootResource } from 'libs/api-root-shared/test/api-root';
-import { getDataTestIdOf } from 'libs/tech-shared/test/data-test';
-import { singleColdCompleted } from 'libs/tech-shared/test/marbles';
 import { MockComponent } from 'ng-mocks';
-import { Observable, of } from 'rxjs';
 import { OrganisationsEinheitFormPageComponent } from './organisationseinheit-form-page.component';
 
 describe('OrganisationsEinheitFormPageComponent', () => {
   let component: OrganisationsEinheitFormPageComponent;
   let fixture: ComponentFixture<OrganisationsEinheitFormPageComponent>;
 
-  const organisationsEinheitFormSelector: string = getDataTestIdOf('organisations-einheit-form');
-
-  let apiRootService: Mock<ApiRootService>;
-
   beforeEach(async () => {
-    apiRootService = mock(ApiRootService);
-
     await TestBed.configureTestingModule({
-      imports: [CommonModule, TechSharedModule],
+      imports: [],
       declarations: [OrganisationsEinheitFormPageComponent, MockComponent(OrganisationsEinheitFormContainerComponent)],
-      providers: [{ provide: ApiRootService, useValue: apiRootService }],
     }).compileComponents();
   });
 
@@ -62,45 +47,4 @@ describe('OrganisationsEinheitFormPageComponent', () => {
   it('should create', () => {
     expect(component).toBeTruthy();
   });
-
-  describe('component', () => {
-    describe('ngOnInit', () => {
-      const apiRootStateResource: StateResource<ApiRootResource> = createStateResource(createApiRootResource());
-      const apiRootStateResource$: Observable<StateResource<ApiRootResource>> = of(apiRootStateResource);
-
-      beforeEach(() => {
-        apiRootService.getApiRoot.mockReturnValue(apiRootStateResource$);
-      });
-
-      it('should call apiRootService getApiRoot', () => {
-        component.ngOnInit();
-
-        expect(apiRootService.getApiRoot).toHaveBeenCalled();
-      });
-
-      it('should get apiRootStateResource$', () => {
-        component.ngOnInit();
-
-        expect(component.apiRootStateResource$).toBeObservable(singleColdCompleted(apiRootStateResource));
-      });
-    });
-  });
-
-  describe('template', () => {
-    describe('admin-organisationseinheit-form-container', () => {
-      it('should be rendered if apiRootState has link', () => {
-        component.apiRootStateResource$ = of(createStateResource(createApiRootResource([ApiRootLinkRel.ORGANISATIONS_EINHEIT])));
-        fixture.detectChanges();
-
-        existsAsHtmlElement(fixture, organisationsEinheitFormSelector);
-      });
-
-      it('should not be rendered if apiRootState has no link', () => {
-        component.apiRootStateResource$ = of(createStateResource(createApiRootResource()));
-        fixture.detectChanges();
-
-        notExistsAsHtmlElement(fixture, organisationsEinheitFormSelector);
-      });
-    });
-  });
 });
diff --git a/alfa-client/apps/admin/src/pages/organisationseinheit/organisationseinheit-form-page/organisationseinheit-form-page.component.ts b/alfa-client/apps/admin/src/pages/organisationseinheit/organisationseinheit-form-page/organisationseinheit-form-page.component.ts
index d92144b1e58138e50682790bfdede8198bb1ebbb..109509a3721d88b943d87b35ab75c76be7cd202c 100644
--- a/alfa-client/apps/admin/src/pages/organisationseinheit/organisationseinheit-form-page/organisationseinheit-form-page.component.ts
+++ b/alfa-client/apps/admin/src/pages/organisationseinheit/organisationseinheit-form-page/organisationseinheit-form-page.component.ts
@@ -22,27 +22,12 @@
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
 import { OrganisationsEinheitFormContainerComponent } from '@admin-client/organisations-einheit';
-import { ApiRootLinkRel, ApiRootResource, ApiRootService } from '@alfa-client/api-root-shared';
-import { createEmptyStateResource, StateResource } from '@alfa-client/tech-shared';
-import { UiModule } from '@alfa-client/ui';
-import { CommonModule } from '@angular/common';
-import { Component, inject, OnInit } from '@angular/core';
-import { Observable, of } from 'rxjs';
+import { Component } from '@angular/core';
 
 @Component({
   selector: 'organisationseinheit-form-page',
   templateUrl: './organisationseinheit-form-page.component.html',
   standalone: true,
-  imports: [CommonModule, UiModule, OrganisationsEinheitFormContainerComponent],
+  imports: [OrganisationsEinheitFormContainerComponent],
 })
-export class OrganisationsEinheitFormPageComponent implements OnInit {
-  private apiRootService = inject(ApiRootService);
-
-  public apiRootStateResource$: Observable<StateResource<ApiRootResource>> = of(createEmptyStateResource<ApiRootResource>());
-
-  public readonly apiRootLinkRel = ApiRootLinkRel;
-
-  ngOnInit(): void {
-    this.apiRootStateResource$ = this.apiRootService.getApiRoot();
-  }
-}
+export class OrganisationsEinheitFormPageComponent {}
diff --git a/alfa-client/apps/admin/src/pages/organisationseinheit/organisationseinheit-page/organisationseinheit-page.component.html b/alfa-client/apps/admin/src/pages/organisationseinheit/organisationseinheit-page/organisationseinheit-page.component.html
index f1c8abdc407045cf77eb1b673b22fe82c31ff1c7..33d2af56ffabe4eb1148b6b1f4feaf6f8a8c06e3 100644
--- a/alfa-client/apps/admin/src/pages/organisationseinheit/organisationseinheit-page/organisationseinheit-page.component.html
+++ b/alfa-client/apps/admin/src/pages/organisationseinheit/organisationseinheit-page/organisationseinheit-page.component.html
@@ -23,8 +23,4 @@
     unter der Lizenz sind dem Lizenztext zu entnehmen.
 
 -->
-<ng-container *ngIf="(apiRootStateResource$ | async)?.resource as apiRoot">
-  @if (apiRoot | hasLink: apiRootLinkRel.ORGANISATIONS_EINHEIT) {
-    <admin-organisations-einheit-container data-test-id="organisations-einheit-container" />
-  }
-</ng-container>
+<admin-organisations-einheit-container data-test-id="organisations-einheit-container" />
diff --git a/alfa-client/apps/admin/src/pages/organisationseinheit/organisationseinheit-page/organisationseinheit-page.component.spec.ts b/alfa-client/apps/admin/src/pages/organisationseinheit/organisationseinheit-page/organisationseinheit-page.component.spec.ts
index d6b708a413afe74806a4e040ec5c5affc7490678..b106381fa75af3ab154e376ced46f3a288d7364b 100644
--- a/alfa-client/apps/admin/src/pages/organisationseinheit/organisationseinheit-page/organisationseinheit-page.component.spec.ts
+++ b/alfa-client/apps/admin/src/pages/organisationseinheit/organisationseinheit-page/organisationseinheit-page.component.spec.ts
@@ -22,33 +22,18 @@
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
 import { OrganisationsEinheitContainerComponent } from '@admin-client/organisations-einheit';
-import { ApiRootLinkRel, ApiRootResource, ApiRootService } from '@alfa-client/api-root-shared';
-import { createStateResource, StateResource, TechSharedModule } from '@alfa-client/tech-shared';
-import { existsAsHtmlElement, mock, Mock, notExistsAsHtmlElement } from '@alfa-client/test-utils';
-import { CommonModule } from '@angular/common';
 import { ComponentFixture, TestBed } from '@angular/core/testing';
-import { createApiRootResource } from 'libs/api-root-shared/test/api-root';
-import { getDataTestIdOf } from 'libs/tech-shared/test/data-test';
-import { singleColdCompleted } from 'libs/tech-shared/test/marbles';
 import { MockComponent } from 'ng-mocks';
-import { Observable, of } from 'rxjs';
 import { OrganisationsEinheitPageComponent } from './organisationseinheit-page.component';
 
 describe('OrganisationsEinheitPageComponent', () => {
   let component: OrganisationsEinheitPageComponent;
   let fixture: ComponentFixture<OrganisationsEinheitPageComponent>;
 
-  const organisationsEinheitContainerSelector: string = getDataTestIdOf('organisations-einheit-container');
-
-  let apiRootService: Mock<ApiRootService>;
-
   beforeEach(async () => {
-    apiRootService = mock(ApiRootService);
-
     await TestBed.configureTestingModule({
-      imports: [CommonModule, TechSharedModule],
+      imports: [],
       declarations: [OrganisationsEinheitPageComponent, MockComponent(OrganisationsEinheitContainerComponent)],
-      providers: [{ provide: ApiRootService, useValue: apiRootService }],
     }).compileComponents();
   });
 
@@ -62,45 +47,4 @@ describe('OrganisationsEinheitPageComponent', () => {
   it('should create', () => {
     expect(component).toBeTruthy();
   });
-
-  describe('component', () => {
-    describe('ngOnInit', () => {
-      const apiRootStateResource: StateResource<ApiRootResource> = createStateResource(createApiRootResource());
-      const apiRootStateResource$: Observable<StateResource<ApiRootResource>> = of(apiRootStateResource);
-
-      beforeEach(() => {
-        apiRootService.getApiRoot.mockReturnValue(apiRootStateResource$);
-      });
-
-      it('should call apiRootService getApiRoot', () => {
-        component.ngOnInit();
-
-        expect(apiRootService.getApiRoot).toHaveBeenCalled();
-      });
-
-      it('should get apiRootStateResource$', () => {
-        component.ngOnInit();
-
-        expect(component.apiRootStateResource$).toBeObservable(singleColdCompleted(apiRootStateResource));
-      });
-    });
-  });
-
-  describe('template', () => {
-    describe('admin-organisationseinheit-container', () => {
-      it('should be rendered if apiRootState has link', () => {
-        component.apiRootStateResource$ = of(createStateResource(createApiRootResource([ApiRootLinkRel.ORGANISATIONS_EINHEIT])));
-        fixture.detectChanges();
-
-        existsAsHtmlElement(fixture, organisationsEinheitContainerSelector);
-      });
-
-      it('should not be rendered if apiRootState has no link', () => {
-        component.apiRootStateResource$ = of(createStateResource(createApiRootResource()));
-        fixture.detectChanges();
-
-        notExistsAsHtmlElement(fixture, organisationsEinheitContainerSelector);
-      });
-    });
-  });
 });
diff --git a/alfa-client/apps/admin/src/pages/organisationseinheit/organisationseinheit-page/organisationseinheit-page.component.ts b/alfa-client/apps/admin/src/pages/organisationseinheit/organisationseinheit-page/organisationseinheit-page.component.ts
index 031470f244f8776ca9d4448a1e55c1464a8ae2fe..d2d9e1334032279c2fd0aa5b32ffc76a89944534 100644
--- a/alfa-client/apps/admin/src/pages/organisationseinheit/organisationseinheit-page/organisationseinheit-page.component.ts
+++ b/alfa-client/apps/admin/src/pages/organisationseinheit/organisationseinheit-page/organisationseinheit-page.component.ts
@@ -22,27 +22,12 @@
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
 import { OrganisationsEinheitContainerComponent } from '@admin-client/organisations-einheit';
-import { ApiRootLinkRel, ApiRootResource, ApiRootService } from '@alfa-client/api-root-shared';
-import { createEmptyStateResource, StateResource } from '@alfa-client/tech-shared';
-import { UiModule } from '@alfa-client/ui';
-import { CommonModule } from '@angular/common';
-import { Component, inject, OnInit } from '@angular/core';
-import { Observable, of } from 'rxjs';
+import { Component } from '@angular/core';
 
 @Component({
   selector: 'organisationseinheit-page',
   templateUrl: './organisationseinheit-page.component.html',
   standalone: true,
-  imports: [CommonModule, OrganisationsEinheitContainerComponent, UiModule],
+  imports: [OrganisationsEinheitContainerComponent],
 })
-export class OrganisationsEinheitPageComponent implements OnInit {
-  private apiRootService = inject(ApiRootService);
-
-  public apiRootStateResource$: Observable<StateResource<ApiRootResource>> = of(createEmptyStateResource<ApiRootResource>());
-
-  public readonly apiRootLinkRel = ApiRootLinkRel;
-
-  ngOnInit(): void {
-    this.apiRootStateResource$ = this.apiRootService.getApiRoot();
-  }
-}
+export class OrganisationsEinheitPageComponent {}
diff --git a/alfa-client/apps/admin/src/pages/postfach/postfach-page/postfach-page.component.html b/alfa-client/apps/admin/src/pages/postfach/postfach-page/postfach-page.component.html
index 323961ecd53f966827744fef12654efaa6444c92..165154d705f18b6e09896e98a9b6ab6f7f845690 100644
--- a/alfa-client/apps/admin/src/pages/postfach/postfach-page/postfach-page.component.html
+++ b/alfa-client/apps/admin/src/pages/postfach/postfach-page/postfach-page.component.html
@@ -23,6 +23,4 @@
     unter der Lizenz sind dem Lizenztext zu entnehmen.
 
 -->
-@if (environment.features.postfach) {
-  <admin-postfach-container data-test-id="postfach-container" />
-}
+<admin-postfach-container data-test-id="postfach-container" />
diff --git a/alfa-client/apps/admin/src/pages/postfach/postfach-page/postfach-page.component.spec.ts b/alfa-client/apps/admin/src/pages/postfach/postfach-page/postfach-page.component.spec.ts
index 1b1555bcacff75394b0aa8a882090913b38e84bf..b5e58a8b8dbe2a45c5ec280cdc3349cf98c9c217 100644
--- a/alfa-client/apps/admin/src/pages/postfach/postfach-page/postfach-page.component.spec.ts
+++ b/alfa-client/apps/admin/src/pages/postfach/postfach-page/postfach-page.component.spec.ts
@@ -22,25 +22,14 @@
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
 import { PostfachContainerComponent } from '@admin-client/postfach';
-import { getEnvironmentFactory } from '@alfa-client/environment-shared';
-import { existsAsHtmlElement, notExistsAsHtmlElement } from '@alfa-client/test-utils';
 import { ComponentFixture, TestBed } from '@angular/core/testing';
-import { createEnvironment } from 'libs/environment-shared/test/environment';
-import { getDataTestIdOf } from 'libs/tech-shared/test/data-test';
 import { MockComponent } from 'ng-mocks';
 import { PostfachPageComponent } from './postfach-page.component';
 
-jest.mock('@alfa-client/environment-shared');
-
 describe('PostfachPageComponent', () => {
   let component: PostfachPageComponent;
   let fixture: ComponentFixture<PostfachPageComponent>;
 
-  const postfachContainerSelector: string = getDataTestIdOf('postfach-container');
-
-  const environment = createEnvironment();
-  (getEnvironmentFactory as jest.Mock).mockReturnValue(environment);
-
   beforeEach(async () => {
     await TestBed.configureTestingModule({
       declarations: [PostfachPageComponent, MockComponent(PostfachContainerComponent)],
@@ -56,22 +45,4 @@ describe('PostfachPageComponent', () => {
   it('should create', () => {
     expect(component).toBeTruthy();
   });
-
-  describe('template', () => {
-    describe('admin-postfach-container', () => {
-      it('should be rendered if feature toggle postfach is true', () => {
-        environment.features.postfach = true;
-        fixture.detectChanges();
-
-        existsAsHtmlElement(fixture, postfachContainerSelector);
-      });
-
-      it('should not be rendered if feature toggle postfach is false', () => {
-        environment.features.postfach = false;
-        fixture.detectChanges();
-
-        notExistsAsHtmlElement(fixture, postfachContainerSelector);
-      });
-    });
-  });
 });
diff --git a/alfa-client/apps/admin/src/pages/postfach/postfach-page/postfach-page.component.ts b/alfa-client/apps/admin/src/pages/postfach/postfach-page/postfach-page.component.ts
index c77fed5ff6e0e78283a2be7b408bf36db27dbab2..5089c002559f37c3dd5c1b288753032a93c74509 100644
--- a/alfa-client/apps/admin/src/pages/postfach/postfach-page/postfach-page.component.ts
+++ b/alfa-client/apps/admin/src/pages/postfach/postfach-page/postfach-page.component.ts
@@ -21,7 +21,6 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-import { Environment, getEnvironmentFactory } from '@alfa-client/environment-shared';
 import { PostfachContainerComponent } from '@admin-client/postfach';
 import { Component } from '@angular/core';
 
@@ -31,6 +30,4 @@ import { Component } from '@angular/core';
   standalone: true,
   imports: [PostfachContainerComponent],
 })
-export class PostfachPageComponent {
-  public readonly environment: Environment = getEnvironmentFactory();
-}
+export class PostfachPageComponent {}
diff --git a/alfa-client/apps/admin/src/pages/statistik/statistik-page/statistik-page.component.html b/alfa-client/apps/admin/src/pages/statistik/statistik-page/statistik-page.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..5213f512591359ed5e619f95d17e27b36dc4d3a7
--- /dev/null
+++ b/alfa-client/apps/admin/src/pages/statistik/statistik-page/statistik-page.component.html
@@ -0,0 +1,26 @@
+<!--
+
+    Copyright (C) 2025 Das Land Schleswig-Holstein vertreten durch den
+    Ministerpräsidenten des Landes Schleswig-Holstein
+    Staatskanzlei
+    Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+
+    Lizenziert unter der EUPL, Version 1.2 oder - sobald
+    diese von der Europäischen Kommission genehmigt wurden -
+    Folgeversionen der EUPL ("Lizenz");
+    Sie dürfen dieses Werk ausschließlich gemäß
+    dieser Lizenz nutzen.
+    Eine Kopie der Lizenz finden Sie hier:
+
+    https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+
+    Sofern nicht durch anwendbare Rechtsvorschriften
+    gefordert oder in schriftlicher Form vereinbart, wird
+    die unter der Lizenz verbreitete Software "so wie sie
+    ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+    ausdrücklich oder stillschweigend - verbreitet.
+    Die sprachspezifischen Genehmigungen und Beschränkungen
+    unter der Lizenz sind dem Lizenztext zu entnehmen.
+
+-->
+<admin-statistik-container data-test-id="statistik-container" />
diff --git a/alfa-client/apps/admin/src/pages/statistik/statistik-page/statistik-page.component.spec.ts b/alfa-client/apps/admin/src/pages/statistik/statistik-page/statistik-page.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2166339888793c63b712e4b4d67cd286002ac6b0
--- /dev/null
+++ b/alfa-client/apps/admin/src/pages/statistik/statistik-page/statistik-page.component.spec.ts
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2025 Das Land Schleswig-Holstein vertreten durch den
+ * Ministerpräsidenten des Landes Schleswig-Holstein
+ * Staatskanzlei
+ * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+ *
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+import { StatistikContainerComponent } from '@admin-client/statistik';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { MockComponent } from 'ng-mocks';
+import { StatistikPageComponent } from './statistik-page.component';
+
+describe('StatistikPageComponent', () => {
+  let component: StatistikPageComponent;
+  let fixture: ComponentFixture<StatistikPageComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: [],
+      declarations: [StatistikPageComponent, MockComponent(StatistikContainerComponent)],
+    }).compileComponents();
+  });
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(StatistikPageComponent);
+    component = fixture.componentInstance;
+
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/alfa-client/apps/admin/src/pages/statistik/statistik-page/statistik-page.component.ts b/alfa-client/apps/admin/src/pages/statistik/statistik-page/statistik-page.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1e74b105df36af783a691e857f71f8697c4c95b2
--- /dev/null
+++ b/alfa-client/apps/admin/src/pages/statistik/statistik-page/statistik-page.component.ts
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2025 Das Land Schleswig-Holstein vertreten durch den
+ * Ministerpräsidenten des Landes Schleswig-Holstein
+ * Staatskanzlei
+ * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+ *
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+import { StatistikContainerComponent } from '@admin-client/statistik';
+import { Component } from '@angular/core';
+
+@Component({
+  selector: 'app-statistik-page',
+  standalone: true,
+  imports: [StatistikContainerComponent],
+  templateUrl: './statistik-page.component.html',
+})
+export class StatistikPageComponent {}
diff --git a/alfa-client/apps/admin/src/pages/users-roles/user-add-page/user-add-page.component.html b/alfa-client/apps/admin/src/pages/users-roles/user-add-page/user-add-page.component.html
index 51a20e77113f69a4974e2886c91ea147f47fc9de..e8bcd63d2f35daea2cb655013ad7a28de1679d77 100644
--- a/alfa-client/apps/admin/src/pages/users-roles/user-add-page/user-add-page.component.html
+++ b/alfa-client/apps/admin/src/pages/users-roles/user-add-page/user-add-page.component.html
@@ -23,6 +23,4 @@
     unter der Lizenz sind dem Lizenztext zu entnehmen.
 
 -->
-@if (environment.features.benutzerRollen) {
-  <admin-user-add-form data-test-id="user-add-form" />
-}
+<admin-user-add-form data-test-id="user-add-form" />
diff --git a/alfa-client/apps/admin/src/pages/users-roles/user-add-page/user-add-page.component.spec.ts b/alfa-client/apps/admin/src/pages/users-roles/user-add-page/user-add-page.component.spec.ts
index facb1f6d4f1b2493b43c881222f3bfde83e90890..6c13973fa0b634e253c29ee4354b48da911efc3b 100644
--- a/alfa-client/apps/admin/src/pages/users-roles/user-add-page/user-add-page.component.spec.ts
+++ b/alfa-client/apps/admin/src/pages/users-roles/user-add-page/user-add-page.component.spec.ts
@@ -22,25 +22,14 @@
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
 import { UserAddFormComponent } from '@admin-client/user';
-import { getEnvironmentFactory } from '@alfa-client/environment-shared';
-import { existsAsHtmlElement, notExistsAsHtmlElement } from '@alfa-client/test-utils';
 import { ComponentFixture, TestBed } from '@angular/core/testing';
-import { createEnvironment } from 'libs/environment-shared/test/environment';
-import { getDataTestIdOf } from 'libs/tech-shared/test/data-test';
 import { MockComponent } from 'ng-mocks';
 import { UserAddPageComponent } from './user-add-page.component';
 
-jest.mock('@alfa-client/environment-shared');
-
 describe('UserAddPageComponent', () => {
   let component: UserAddPageComponent;
   let fixture: ComponentFixture<UserAddPageComponent>;
 
-  const userAddFormSelector: string = getDataTestIdOf('user-add-form');
-
-  const environment = createEnvironment();
-  (getEnvironmentFactory as jest.Mock).mockReturnValue(environment);
-
   beforeEach(async () => {
     await TestBed.configureTestingModule({
       declarations: [UserAddPageComponent, MockComponent(UserAddFormComponent)],
@@ -54,22 +43,4 @@ describe('UserAddPageComponent', () => {
   it('should create', () => {
     expect(component).toBeTruthy();
   });
-
-  describe('template', () => {
-    describe('admin-user-add-form', () => {
-      it('should be rendered if feature toggle for benutzerRollen is true', () => {
-        environment.features.benutzerRollen = true;
-        fixture.detectChanges();
-
-        existsAsHtmlElement(fixture, userAddFormSelector);
-      });
-
-      it('should not be rendered if feature toggle for benutzerRollen is false', () => {
-        environment.features.benutzerRollen = false;
-        fixture.detectChanges();
-
-        notExistsAsHtmlElement(fixture, userAddFormSelector);
-      });
-    });
-  });
 });
diff --git a/alfa-client/apps/admin/src/pages/users-roles/user-add-page/user-add-page.component.ts b/alfa-client/apps/admin/src/pages/users-roles/user-add-page/user-add-page.component.ts
index 0e022f312b04c2f22d3432683d58d2f324261f94..0df47d3f99a92af7ba262020ec16b2ad9466a8e6 100644
--- a/alfa-client/apps/admin/src/pages/users-roles/user-add-page/user-add-page.component.ts
+++ b/alfa-client/apps/admin/src/pages/users-roles/user-add-page/user-add-page.component.ts
@@ -21,7 +21,6 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-import { Environment, getEnvironmentFactory } from '@alfa-client/environment-shared';
 import { UserAddFormComponent } from '@admin-client/user';
 import { Component } from '@angular/core';
 
@@ -31,6 +30,4 @@ import { Component } from '@angular/core';
   standalone: true,
   imports: [UserAddFormComponent],
 })
-export class UserAddPageComponent {
-  public readonly environment: Environment = getEnvironmentFactory();
-}
+export class UserAddPageComponent {}
diff --git a/alfa-client/apps/admin/src/pages/users-roles/user-roles-page/user-roles-page.component.html b/alfa-client/apps/admin/src/pages/users-roles/user-roles-page/user-roles-page.component.html
index 35bbbc0007a18979bf7904595c5910d09316cb3b..b4f2c21ecb76e734d0a91b08d61db3e332ab3acb 100644
--- a/alfa-client/apps/admin/src/pages/users-roles/user-roles-page/user-roles-page.component.html
+++ b/alfa-client/apps/admin/src/pages/users-roles/user-roles-page/user-roles-page.component.html
@@ -23,6 +23,4 @@
     unter der Lizenz sind dem Lizenztext zu entnehmen.
 
 -->
-@if (environment.features.benutzerRollen) {
-  <admin-users-roles data-test-id="users-roles" />
-}
+<admin-users-roles data-test-id="users-roles" />
diff --git a/alfa-client/apps/admin/src/pages/users-roles/user-roles-page/user-roles-page.component.spec.ts b/alfa-client/apps/admin/src/pages/users-roles/user-roles-page/user-roles-page.component.spec.ts
index 77b415071c8a7e4d5ce966bae33b30bd48d4f14c..dcff9ea1f54b16ed94d2bf2f37957d37749c34b7 100644
--- a/alfa-client/apps/admin/src/pages/users-roles/user-roles-page/user-roles-page.component.spec.ts
+++ b/alfa-client/apps/admin/src/pages/users-roles/user-roles-page/user-roles-page.component.spec.ts
@@ -22,25 +22,14 @@
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
 import { UsersRolesComponent } from '@admin-client/user';
-import { getEnvironmentFactory } from '@alfa-client/environment-shared';
-import { existsAsHtmlElement, notExistsAsHtmlElement } from '@alfa-client/test-utils';
 import { ComponentFixture, TestBed } from '@angular/core/testing';
-import { createEnvironment } from 'libs/environment-shared/test/environment';
-import { getDataTestIdOf } from 'libs/tech-shared/test/data-test';
 import { MockComponent } from 'ng-mocks';
 import { UserRolesPageComponent } from './user-roles-page.component';
 
-jest.mock('@alfa-client/environment-shared');
-
 describe('UserRolesPageComponent', () => {
   let component: UserRolesPageComponent;
   let fixture: ComponentFixture<UserRolesPageComponent>;
 
-  const usersRolesSelector: string = getDataTestIdOf('users-roles');
-
-  const environment = createEnvironment();
-  (getEnvironmentFactory as jest.Mock).mockReturnValue(environment);
-
   beforeEach(async () => {
     await TestBed.configureTestingModule({
       declarations: [UserRolesPageComponent],
@@ -55,22 +44,4 @@ describe('UserRolesPageComponent', () => {
   it('should create', () => {
     expect(component).toBeTruthy();
   });
-
-  describe('template', () => {
-    describe('admin-users-roles', () => {
-      it('should be rendered if feature toggle benutzerRollen is true', () => {
-        environment.features.benutzerRollen = true;
-        fixture.detectChanges();
-
-        existsAsHtmlElement(fixture, usersRolesSelector);
-      });
-
-      it('should not be rendered component if feature toggle benutzerRollen is false', () => {
-        environment.features.benutzerRollen = false;
-        fixture.detectChanges();
-
-        notExistsAsHtmlElement(fixture, usersRolesSelector);
-      });
-    });
-  });
 });
diff --git a/alfa-client/apps/admin/src/pages/users-roles/user-roles-page/user-roles-page.component.ts b/alfa-client/apps/admin/src/pages/users-roles/user-roles-page/user-roles-page.component.ts
index b19feb8a0d942320087afe30f32bfe5872fef661..2d2cf9efdf2de388854a19148634c734b5587297 100644
--- a/alfa-client/apps/admin/src/pages/users-roles/user-roles-page/user-roles-page.component.ts
+++ b/alfa-client/apps/admin/src/pages/users-roles/user-roles-page/user-roles-page.component.ts
@@ -21,7 +21,6 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-import { Environment, getEnvironmentFactory } from '@alfa-client/environment-shared';
 import { UsersRolesComponent } from '@admin-client/user';
 import { Component } from '@angular/core';
 
@@ -31,6 +30,4 @@ import { Component } from '@angular/core';
   standalone: true,
   imports: [UsersRolesComponent],
 })
-export class UserRolesPageComponent {
-  public readonly environment: Environment = getEnvironmentFactory();
-}
+export class UserRolesPageComponent {}
diff --git a/alfa-client/apps/admin/src/styles.scss b/alfa-client/apps/admin/src/styles.scss
index a70d56fcf0868ff075899d9cc14eeee7d26be531..5bf38c604f5517809686de44624f416bbea468d1 100644
--- a/alfa-client/apps/admin/src/styles.scss
+++ b/alfa-client/apps/admin/src/styles.scss
@@ -29,8 +29,9 @@
 
 @import 'libs/design-system/src/lib/tailwind-preset/root.css';
 @import 'libs/ui/src/lib/font/font_material';
-@import 'variables';
 @import 'typeface-roboto/index.css';
+@import '../../alfa/src/styles/abstracts/variables';
+@import '../../alfa/src/styles/material/snackbar';
 
 @include mat.all-component-typographies();
 @include mat.core();
diff --git a/alfa-client/apps/alfa-e2e/src/components/user-profile/current-user-profile.component.e2e.ts b/alfa-client/apps/alfa-e2e/src/components/user-profile/current-user-profile.component.e2e.ts
index 202c5d3ef538a45931d9dc855e1ad99dba5610fd..93a38796fd04ecade67ecf9995a417a73ce687ba 100644
--- a/alfa-client/apps/alfa-e2e/src/components/user-profile/current-user-profile.component.e2e.ts
+++ b/alfa-client/apps/alfa-e2e/src/components/user-profile/current-user-profile.component.e2e.ts
@@ -40,7 +40,7 @@ export class CurrentUserProfileE2EComponent {
 
   public logout(): void {
     this.getUserIconButton().click();
-    this.getLogoutButton().click();
+    this.getLogoutButton().click({ force: true });
   }
 
   public getUserIconButton() {
diff --git a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/init-users.cy.ts b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/init-users.cy.ts
index b5325689ff01c2b61199ae06ef1e07ebc483a5b1..0558e553cf1915d2e288b730be3b06d6adbf4a61 100644
--- a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/init-users.cy.ts
+++ b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/init-users.cy.ts
@@ -68,6 +68,6 @@ describe('Init users', () => {
     waitForSpinnerToDisappear();
     exist(header.getLogo());
     header.getCurrentUserProfile().getUserIconButton().click();
-    header.getCurrentUserProfile().getLogoutButton().click();
+    header.getCurrentUserProfile().getLogoutButton().click({ force: true });
   }
 });
diff --git a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-detailansicht/vorgang-detailansicht.cy.ts b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-detailansicht/vorgang-detailansicht.cy.ts
index ac09ea4046a74327aaa0e0460b1cd89afd6af003..7fa1b271ad7f923a8757a96e1e73854837fe101c 100644
--- a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-detailansicht/vorgang-detailansicht.cy.ts
+++ b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/vorgang-detailansicht/vorgang-detailansicht.cy.ts
@@ -37,18 +37,13 @@ import {
   contains,
   exist,
   haveText,
+  haveTextWithoutChildren,
   shouldFirstContains,
   shouldHaveAttributeBeGreaterThan,
   shouldHaveAttributeBeLowerThan,
 } from '../../../support/cypress.util';
 import { loginAsSabine } from '../../../support/user-util';
-import {
-  AntragstellerE2ETestData,
-  buildVorgang,
-  createVorgang,
-  initVorgaenge,
-  objectIds,
-} from '../../../support/vorgang-util';
+import { AntragstellerE2ETestData, buildVorgang, createVorgang, initVorgaenge, objectIds } from '../../../support/vorgang-util';
 
 registerLocaleData(localeDe, 'de', localeDeExtra);
 
@@ -57,13 +52,10 @@ describe('Vorgang Detailansicht', () => {
   const vorgangList: VorgangListE2EComponent = mainPage.getVorgangList();
 
   const vorgangPage: VorgangPage = new VorgangPage();
-  const vorgangDatenFormular: VorgangFormularDatenE2EComponent =
-    vorgangPage.getFormularDatenContainer();
+  const vorgangDatenFormular: VorgangFormularDatenE2EComponent = vorgangPage.getFormularDatenContainer();
 
   const vorgangHeader: VorgangDetailHeaderE2EComponent = vorgangPage.getVorgangDetailHeader();
-  const expansionPanelContainer: ExpansionPanelE2Eomponent = vorgangPage
-    .getFormularDatenContainer()
-    .getExpansionPanelContainer();
+  const expansionPanelContainer: ExpansionPanelE2Eomponent = vorgangPage.getFormularDatenContainer().getExpansionPanelContainer();
   const antragsteller: AntragstellerE2EComponent = vorgangPage.getAntragstellerContainer();
 
   const vorgang: VorgangE2E = { ...createVorgang(), name: 'TestVorgang' };
@@ -97,16 +89,10 @@ describe('Vorgang Detailansicht', () => {
 
       it('should have header data', () => {
         haveText(vorgangHeader.getStatus(), vorgangStatusLabelE2E[vorgang.status]);
-        haveText(
-          vorgangHeader.getAktenzeichen(),
-          vorgang.aktenzeichen ? vorgang.aktenzeichen : NO_AKTENZEICHEN,
-        );
-        haveText(vorgangHeader.getVorgangNummer(), vorgang.nummer);
+        haveTextWithoutChildren(vorgangHeader.getAktenzeichen(), vorgang.aktenzeichen ? vorgang.aktenzeichen : NO_AKTENZEICHEN);
+        haveTextWithoutChildren(vorgangHeader.getVorgangNummer(), vorgang.nummer);
         haveText(vorgangHeader.getName(), vorgang.name);
-        haveText(
-          vorgangHeader.getCreatedAt(),
-          formatDate(vorgang.createdAt.$date, 'EEEE, dd. MMMM y, HH:mm', 'de'),
-        );
+        haveText(vorgangHeader.getCreatedAt(), formatDate(vorgang.createdAt.$date, 'EEEE, dd. MMMM y, HH:mm', 'de'));
       });
 
       it('should have header data after reload', () => {
@@ -114,16 +100,10 @@ describe('Vorgang Detailansicht', () => {
 
         exist(vorgangHeader.getRoot());
         haveText(vorgangHeader.getStatus(), vorgangStatusLabelE2E[vorgang.status]);
-        haveText(
-          vorgangHeader.getAktenzeichen(),
-          vorgang.aktenzeichen ? vorgang.aktenzeichen : NO_AKTENZEICHEN,
-        );
-        haveText(vorgangHeader.getVorgangNummer(), vorgang.nummer);
+        haveTextWithoutChildren(vorgangHeader.getAktenzeichen(), vorgang.aktenzeichen ? vorgang.aktenzeichen : NO_AKTENZEICHEN);
+        haveTextWithoutChildren(vorgangHeader.getVorgangNummer(), vorgang.nummer);
         haveText(vorgangHeader.getName(), vorgang.name);
-        haveText(
-          vorgangHeader.getCreatedAt(),
-          formatDate(vorgang.createdAt.$date, 'EEEE, dd. MMMM y, HH:mm', 'de'),
-        );
+        haveText(vorgangHeader.getCreatedAt(), formatDate(vorgang.createdAt.$date, 'EEEE, dd. MMMM y, HH:mm', 'de'));
       });
     });
 
@@ -136,10 +116,7 @@ describe('Vorgang Detailansicht', () => {
       });
 
       it('should show "empfangendestelle"', () => {
-        contains(
-          vorgangDatenFormular.getRoot(),
-          vorgang.eingangs[0].formData.empfangendestelle.emailadresse,
-        );
+        contains(vorgangDatenFormular.getRoot(), vorgang.eingangs[0].formData.empfangendestelle.emailadresse);
       });
     });
 
@@ -174,21 +151,13 @@ describe('Vorgang Detailansicht', () => {
       });
 
       it('should have Formulardaten panel open initial', () => {
-        shouldHaveAttributeBeGreaterThan(
-          expansionPanelContainer.getExpansionPanel(),
-          'outerHeight',
-          50,
-        );
+        shouldHaveAttributeBeGreaterThan(expansionPanelContainer.getExpansionPanel(), 'outerHeight', 50);
       });
 
       it('should close the panel', () => {
         expansionPanelContainer.getExpansionPanelTitle().first().click();
 
-        shouldHaveAttributeBeLowerThan(
-          expansionPanelContainer.getExpansionPanel(),
-          'outerHeight',
-          50,
-        );
+        shouldHaveAttributeBeLowerThan(expansionPanelContainer.getExpansionPanel(), 'outerHeight', 50);
       });
     });
   });
diff --git a/alfa-client/apps/alfa-e2e/src/support/angular.util.ts b/alfa-client/apps/alfa-e2e/src/support/angular.util.ts
index 4f8427775eba70bc3c69837580ff307ecdc2fded..a8929a5a22b1fc8073e1717241b8e7141a20ee99 100644
--- a/alfa-client/apps/alfa-e2e/src/support/angular.util.ts
+++ b/alfa-client/apps/alfa-e2e/src/support/angular.util.ts
@@ -40,8 +40,7 @@ enum AngularElementE2E {
 
 export function hasTooltip(element: any, value: string) {
   mouseEnter(element);
-  element.get('mat-tooltip-component').contains(value);
-  // element.get(`div[title="${value}"]`);
+  element.get('ods-tooltip').contains(value);
 }
 
 export function isChecked(element: any) {
diff --git a/alfa-client/apps/alfa-e2e/src/support/cypress.util.ts b/alfa-client/apps/alfa-e2e/src/support/cypress.util.ts
index ce27ac7e46551eb1cebe36055894341e23ae6106..69e7bccdfc44a17993598e6c49a8e81bd066db33 100644
--- a/alfa-client/apps/alfa-e2e/src/support/cypress.util.ts
+++ b/alfa-client/apps/alfa-e2e/src/support/cypress.util.ts
@@ -52,6 +52,16 @@ export function haveText(element: any, text: string): void {
     .should('equal', text);
 }
 
+export function haveTextWithoutChildren(element: any, text: string): void {
+  element
+    .invoke('clone')
+    .then((element) => {
+      element.children().remove();
+      return element.text().trim();
+    })
+    .should('equal', text);
+}
+
 export function haveValue(element: any, value: string): void {
   element.should('have.value', value);
 }
@@ -93,11 +103,7 @@ export function shouldFirstContains(element: any, containing: string) {
   element.first().should('exist').contains(containing);
 }
 
-export function shouldHaveAttributeBeGreaterThan(
-  element: any,
-  attributeName: string,
-  value: number,
-) {
+export function shouldHaveAttributeBeGreaterThan(element: any, attributeName: string, value: number) {
   element.first().should('exist').invoke(attributeName).should('be.gt', value);
 }
 
@@ -122,11 +128,7 @@ export function enter(element: any): void {
   element.clear().type(CypressKeyboardActions.ENTER);
 }
 
-export function enterWith(
-  element: Cypress.Chainable<JQuery<HTMLElement>>,
-  value: string,
-  delayBeforeEnter: number = 200,
-): void {
+export function enterWith(element: Cypress.Chainable<JQuery<HTMLElement>>, value: string, delayBeforeEnter: number = 200): void {
   element.clear().type(value);
   wait(delayBeforeEnter);
   element.type(CypressKeyboardActions.ENTER);
diff --git a/alfa-client/apps/alfa/Jenkinsfile b/alfa-client/apps/alfa/Jenkinsfile
index 0dde2edb6c4f78bb6a77e54d7607b327db26a115..1464cec669b290d51f5bd201ea89f264cf7f3974 100644
--- a/alfa-client/apps/alfa/Jenkinsfile
+++ b/alfa-client/apps/alfa/Jenkinsfile
@@ -78,7 +78,7 @@ pipeline {
                         sh 'node --version'
 
                         dir('alfa-client') {
-                            sh 'pnpm install  --frozen-lockfile --network-concurrency=8'
+                            sh 'pnpm install  --frozen-lockfile'
 
                             if (isMainBranch()) {
                                 withSonarQubeEnv('sonarqube-ozg-sh'){
diff --git a/alfa-client/apps/alfa/src/styles/main.scss b/alfa-client/apps/alfa/src/styles/main.scss
index 38f3732fb91b31d208be4e0704ac2084f6506e3a..748d65e101e890ac85ac7c6edcd9bffc19b7dde8 100644
--- a/alfa-client/apps/alfa/src/styles/main.scss
+++ b/alfa-client/apps/alfa/src/styles/main.scss
@@ -43,8 +43,8 @@
 @import 'material/icons';
 @import 'material/list';
 @import 'material/menu';
-@import 'material/snackbar';
 @import 'material/tabs';
+@import 'material/snackbar';
 @import 'material/typography';
 @import 'libs/navigation/src/lib/header-container/header/header.theme';
 @import 'libs/ui/src/lib/ui/expansion-panel/expansion-panel.theme';
diff --git a/alfa-client/apps/info/Jenkinsfile b/alfa-client/apps/info/Jenkinsfile
index dd670c32603c9b721c60ac02dcfa3c32388c0a0a..e8c582e1e0332dc4618e99a2d145e602bb6c7998 100644
--- a/alfa-client/apps/info/Jenkinsfile
+++ b/alfa-client/apps/info/Jenkinsfile
@@ -46,7 +46,7 @@ pipeline {
           FAILED_STAGE = env.STAGE_NAME
           dir('alfa-client') {
             withNPM(npmrcConfig: 'npm-nexus-auth') {
-              sh 'pnpm install --frozen-lockfile --network-concurrency=8'
+              sh 'pnpm install --frozen-lockfile'
               sh 'pnpm exec nx run info:test'
               sh 'pnpm exec nx run info:test -- --runInBand --codeCoverage --coverageReporters=lcov --testResultsProcessor=jest-sonar-reporter && pnpm exec sonar-scanner'
 
diff --git a/alfa-client/libs/admin/configuration-shared/README.md b/alfa-client/libs/admin/configuration-shared/README.md
index 6f5030b70bcee5425a71ad582b478c8007bb6169..1e9f46fa0c35148f61b66d5b1e5d5a37a2da822c 100644
--- a/alfa-client/libs/admin/configuration-shared/README.md
+++ b/alfa-client/libs/admin/configuration-shared/README.md
@@ -4,4 +4,4 @@ This library was generated with [Nx](https://nx.dev).
 
 ## Running unit tests
 
-Run `nx test configuration` to execute the unit tests.
+Run `nx test configuration-shared` to execute the unit tests.
diff --git a/alfa-client/libs/admin/configuration-shared/jest.config.ts b/alfa-client/libs/admin/configuration-shared/jest.config.ts
index 62ec3a0768ca632eface9c5965a666571b6f526c..9689743d8f6262d45b94cf069ac946a79101cd06 100644
--- a/alfa-client/libs/admin/configuration-shared/jest.config.ts
+++ b/alfa-client/libs/admin/configuration-shared/jest.config.ts
@@ -1,5 +1,5 @@
 export default {
-  displayName: 'admin-configuration',
+  displayName: 'admin-configuration-shared',
   preset: '../../../jest.preset.js',
   setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
   coverageDirectory: '../../../coverage/libs/admin/configuration-shared',
diff --git a/alfa-client/libs/admin/configuration-shared/project.json b/alfa-client/libs/admin/configuration-shared/project.json
index ce13ed7f5533688a16237678622655a7117a4c41..da6c4ac258f5dae5682333c952fd6dad6a98a1e6 100644
--- a/alfa-client/libs/admin/configuration-shared/project.json
+++ b/alfa-client/libs/admin/configuration-shared/project.json
@@ -1,5 +1,5 @@
 {
-  "name": "admin-configuration",
+  "name": "admin-configuration-shared",
   "$schema": "../../../node_modules/nx/schemas/project-schema.json",
   "sourceRoot": "libs/admin/configuration-shared/src",
   "prefix": "admin",
diff --git a/alfa-client/libs/admin/configuration-shared/src/lib/configuration.linkrel.ts b/alfa-client/libs/admin/configuration-shared/src/lib/configuration.linkrel.ts
index 1468b2b4e4354bd245f83cc28dd6f6c2c5fb00f3..f38803351591db0d6ac7fb13c7bef7c0a9ce7a34 100644
--- a/alfa-client/libs/admin/configuration-shared/src/lib/configuration.linkrel.ts
+++ b/alfa-client/libs/admin/configuration-shared/src/lib/configuration.linkrel.ts
@@ -23,4 +23,5 @@
  */
 export enum ConfigurationLinkRel {
   SETTING = 'settings',
+  AGGREGATION_MAPPINGS = 'aggregationMappings',
 }
diff --git a/alfa-client/libs/admin/configuration-shared/test/configuration.ts b/alfa-client/libs/admin/configuration-shared/test/configuration.ts
index 9b188cb1c2bd4bb8fec2db9dd4ba0d5830f09f41..5552d59c4ef83855927de673d83aee92ecba0725 100644
--- a/alfa-client/libs/admin/configuration-shared/test/configuration.ts
+++ b/alfa-client/libs/admin/configuration-shared/test/configuration.ts
@@ -1,6 +1,6 @@
-import { ConfigurationLinkRel, ConfigurationResource } from '@admin-client/configuration-shared';
+import { ConfigurationResource } from '@admin-client/configuration-shared';
 import { toResource } from '../../../tech-shared/test/resource';
 
-export function createConfigurationResource(): ConfigurationResource {
-  return toResource({}, [ConfigurationLinkRel.SETTING]);
+export function createConfigurationResource(linkRels: string[] = []): ConfigurationResource {
+  return toResource({}, linkRels);
 }
diff --git a/alfa-client/libs/admin/configuration/.eslintrc.json b/alfa-client/libs/admin/configuration/.eslintrc.json
new file mode 100644
index 0000000000000000000000000000000000000000..b10f9813a8f5c59432cf245301dc4d01a8031fd1
--- /dev/null
+++ b/alfa-client/libs/admin/configuration/.eslintrc.json
@@ -0,0 +1,33 @@
+{
+  "extends": ["../../../.eslintrc.json"],
+  "ignorePatterns": ["!**/*"],
+  "overrides": [
+    {
+      "files": ["*.ts"],
+      "extends": ["plugin:@nx/angular", "plugin:@angular-eslint/template/process-inline-templates"],
+      "rules": {
+        "@angular-eslint/directive-selector": [
+          "error",
+          {
+            "type": "attribute",
+            "prefix": "lib",
+            "style": "camelCase"
+          }
+        ],
+        "@angular-eslint/component-selector": [
+          "error",
+          {
+            "type": "element",
+            "prefix": "lib",
+            "style": "kebab-case"
+          }
+        ]
+      }
+    },
+    {
+      "files": ["*.html"],
+      "extends": ["plugin:@nx/angular-template"],
+      "rules": {}
+    }
+  ]
+}
diff --git a/alfa-client/libs/admin/configuration/README.md b/alfa-client/libs/admin/configuration/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..6f5030b70bcee5425a71ad582b478c8007bb6169
--- /dev/null
+++ b/alfa-client/libs/admin/configuration/README.md
@@ -0,0 +1,7 @@
+# configuration
+
+This library was generated with [Nx](https://nx.dev).
+
+## Running unit tests
+
+Run `nx test configuration` to execute the unit tests.
diff --git a/alfa-client/libs/admin/configuration/jest.config.ts b/alfa-client/libs/admin/configuration/jest.config.ts
new file mode 100644
index 0000000000000000000000000000000000000000..7b8ab3df6e12af6c69e5a52778822c7fd33ec9e3
--- /dev/null
+++ b/alfa-client/libs/admin/configuration/jest.config.ts
@@ -0,0 +1,21 @@
+export default {
+  displayName: 'admin-configuration',
+  preset: '../../../jest.preset.js',
+  setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
+  coverageDirectory: '../../../coverage/libs/admin/configuration',
+  transform: {
+    '^.+\\.(ts|mjs|js|html)$': [
+      'jest-preset-angular',
+      {
+        tsconfig: '<rootDir>/tsconfig.spec.json',
+        stringifyContentPathRegex: '\\.(html|svg)$',
+      },
+    ],
+  },
+  transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
+  snapshotSerializers: [
+    'jest-preset-angular/build/serializers/no-ng-attributes',
+    'jest-preset-angular/build/serializers/ng-snapshot',
+    'jest-preset-angular/build/serializers/html-comment',
+  ],
+};
diff --git a/alfa-client/libs/admin/configuration/project.json b/alfa-client/libs/admin/configuration/project.json
new file mode 100644
index 0000000000000000000000000000000000000000..29871bddc31df4176f2e079ff268b880111f1b8f
--- /dev/null
+++ b/alfa-client/libs/admin/configuration/project.json
@@ -0,0 +1,20 @@
+{
+  "name": "admin-configuration",
+  "$schema": "../../../node_modules/nx/schemas/project-schema.json",
+  "sourceRoot": "libs/admin/configuration/src",
+  "prefix": "lib",
+  "projectType": "library",
+  "tags": [],
+  "targets": {
+    "test": {
+      "executor": "@nx/jest:jest",
+      "outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
+      "options": {
+        "jestConfig": "libs/admin/configuration/jest.config.ts"
+      }
+    },
+    "lint": {
+      "executor": "@nx/eslint:lint"
+    }
+  }
+}
diff --git a/alfa-client/libs/admin/configuration/src/index.ts b/alfa-client/libs/admin/configuration/src/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..221b8b737643d3ef9facd8ae2f520efc97099c91
--- /dev/null
+++ b/alfa-client/libs/admin/configuration/src/index.ts
@@ -0,0 +1 @@
+export * from './lib/menu-container/menu-container.component';
diff --git a/alfa-client/libs/admin/configuration/src/lib/menu-container/menu-container.component.html b/alfa-client/libs/admin/configuration/src/lib/menu-container/menu-container.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..fd97589d60cd2ca0c583ca7ae1a143f7bba98121
--- /dev/null
+++ b/alfa-client/libs/admin/configuration/src/lib/menu-container/menu-container.component.html
@@ -0,0 +1 @@
+<admin-menu [configurationStateResource]="configurationStateResource$ | async"></admin-menu>
\ No newline at end of file
diff --git a/alfa-client/libs/admin/configuration/src/lib/menu-container/menu-container.component.spec.ts b/alfa-client/libs/admin/configuration/src/lib/menu-container/menu-container.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..69d8eb3bd3bb34964306f755e3c9d00acb7f58c6
--- /dev/null
+++ b/alfa-client/libs/admin/configuration/src/lib/menu-container/menu-container.component.spec.ts
@@ -0,0 +1,55 @@
+import { ConfigurationResource, ConfigurationService } from '@admin-client/configuration-shared';
+import { createStateResource, StateResource } from '@alfa-client/tech-shared';
+import { getMockComponent, mock, Mock } from '@alfa-client/test-utils';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { MockComponent } from 'ng-mocks';
+import { of } from 'rxjs';
+import { createConfigurationResource } from '../../../../configuration-shared/test/configuration';
+import { MenuContainerComponent } from './menu-container.component';
+import { MenuComponent } from './menu/menu.component';
+
+describe('MenuContainerComponent', () => {
+  let component: MenuContainerComponent;
+  let fixture: ComponentFixture<MenuContainerComponent>;
+
+  let configurationService: Mock<ConfigurationService>;
+
+  const configurationStateResource: StateResource<ConfigurationResource> = createStateResource(createConfigurationResource());
+
+  beforeEach(async () => {
+    configurationService = { ...mock(ConfigurationService), get: jest.fn().mockReturnValue(of(configurationStateResource)) };
+
+    await TestBed.configureTestingModule({
+      imports: [MenuContainerComponent],
+      declarations: [MockComponent(MenuComponent)],
+      providers: [
+        {
+          provide: ConfigurationService,
+          useValue: configurationService,
+        },
+      ],
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(MenuContainerComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+
+  describe('ngOnInit', () => {
+    it('should call service', () => {
+      component.ngOnInit();
+
+      expect(configurationService.get).toHaveBeenCalled();
+    });
+  });
+
+  it('should call menu', () => {
+    const menu: MenuComponent = getMockComponent(fixture, MenuComponent);
+
+    expect(menu.configurationStateResource).toBe(configurationStateResource);
+  });
+});
diff --git a/alfa-client/libs/admin/configuration/src/lib/menu-container/menu-container.component.ts b/alfa-client/libs/admin/configuration/src/lib/menu-container/menu-container.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..7cb838c535b0a87efd570d6ee6a6d58024fd8d19
--- /dev/null
+++ b/alfa-client/libs/admin/configuration/src/lib/menu-container/menu-container.component.ts
@@ -0,0 +1,22 @@
+import { ConfigurationResource, ConfigurationService } from '@admin-client/configuration-shared';
+import { StateResource } from '@alfa-client/tech-shared';
+import { CommonModule } from '@angular/common';
+import { Component, inject, OnInit } from '@angular/core';
+import { Observable } from 'rxjs';
+import { MenuComponent } from './menu/menu.component';
+
+@Component({
+  selector: 'admin-menu-container',
+  standalone: true,
+  imports: [CommonModule, MenuComponent],
+  templateUrl: './menu-container.component.html',
+})
+export class MenuContainerComponent implements OnInit {
+  private readonly configurationService = inject(ConfigurationService);
+
+  public configurationStateResource$: Observable<StateResource<ConfigurationResource>>;
+
+  ngOnInit(): void {
+    this.configurationStateResource$ = this.configurationService.get();
+  }
+}
diff --git a/alfa-client/libs/admin/configuration/src/lib/menu-container/menu/menu.component.html b/alfa-client/libs/admin/configuration/src/lib/menu-container/menu/menu.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..0c1102a4c22c1603d4cc93f6baaaf5fcb2f94d40
--- /dev/null
+++ b/alfa-client/libs/admin/configuration/src/lib/menu-container/menu/menu.component.html
@@ -0,0 +1,10 @@
+@if (configurationStateResource.resource | hasLink: configurationLinkRel.SETTING) {
+  <ods-nav-item data-test-id="postfach-navigation" caption="Postfach" path="/postfach">
+    <ods-mailbox-icon icon />
+  </ods-nav-item>
+}
+@if (configurationStateResource.resource | hasLink: configurationLinkRel.AGGREGATION_MAPPINGS) {
+  <ods-nav-item data-test-id="statistik-navigation" caption="Statistik" path="/statistik">
+    <ods-statistic-icon icon />
+  </ods-nav-item>
+}
diff --git a/alfa-client/libs/admin/configuration/src/lib/menu-container/menu/menu.component.spec.ts b/alfa-client/libs/admin/configuration/src/lib/menu-container/menu/menu.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1f417e5febf09fcf523cd7c2d01a273d65630e79
--- /dev/null
+++ b/alfa-client/libs/admin/configuration/src/lib/menu-container/menu/menu.component.spec.ts
@@ -0,0 +1,71 @@
+import { ConfigurationLinkRel } from '@admin-client/configuration-shared';
+import { createEmptyStateResource, createStateResource, HasLinkPipe } from '@alfa-client/tech-shared';
+import { existsAsHtmlElement, notExistsAsHtmlElement } from '@alfa-client/test-utils';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { MailboxIconComponent, NavItemComponent } from '@ods/system';
+import { createConfigurationResource } from 'libs/admin/configuration-shared/test/configuration';
+import { getDataTestIdOf } from 'libs/tech-shared/test/data-test';
+import { MockComponent } from 'ng-mocks';
+import { MenuComponent } from './menu.component';
+
+describe('MenuComponent', () => {
+  let component: MenuComponent;
+  let fixture: ComponentFixture<MenuComponent>;
+
+  const postfachNavigation: string = getDataTestIdOf('postfach-navigation');
+  const statistikNavigationSelector: string = getDataTestIdOf('statistik-navigation');
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: [MenuComponent],
+      declarations: [HasLinkPipe, MockComponent(NavItemComponent), MockComponent(MailboxIconComponent)],
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(MenuComponent);
+    component = fixture.componentInstance;
+    component.configurationStateResource = createEmptyStateResource();
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+
+  describe('postfach navigation', () => {
+    it('should show if settings link is present', () => {
+      component.configurationStateResource = createStateResource(createConfigurationResource([ConfigurationLinkRel.SETTING]));
+
+      fixture.detectChanges();
+
+      existsAsHtmlElement(fixture, postfachNavigation);
+    });
+
+    it('should hide if settings link is missing', () => {
+      component.configurationStateResource = createStateResource(createConfigurationResource());
+
+      fixture.detectChanges();
+
+      notExistsAsHtmlElement(fixture, postfachNavigation);
+    });
+  });
+
+  describe('statistic navigation', () => {
+    it('should show if settings link is present', () => {
+      component.configurationStateResource = createStateResource(
+        createConfigurationResource([ConfigurationLinkRel.AGGREGATION_MAPPINGS]),
+      );
+
+      fixture.detectChanges();
+
+      existsAsHtmlElement(fixture, statistikNavigationSelector);
+    });
+
+    it('should hide if settings link is missing', () => {
+      component.configurationStateResource = createStateResource(createConfigurationResource());
+
+      fixture.detectChanges();
+
+      notExistsAsHtmlElement(fixture, statistikNavigationSelector);
+    });
+  });
+});
diff --git a/alfa-client/libs/admin/configuration/src/lib/menu-container/menu/menu.component.ts b/alfa-client/libs/admin/configuration/src/lib/menu-container/menu/menu.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..19cc60bab45d9e098ace89450e3c7efa50e96c30
--- /dev/null
+++ b/alfa-client/libs/admin/configuration/src/lib/menu-container/menu/menu.component.ts
@@ -0,0 +1,17 @@
+import { ConfigurationLinkRel, ConfigurationResource } from '@admin-client/configuration-shared';
+import { StateResource, TechSharedModule } from '@alfa-client/tech-shared';
+import { CommonModule } from '@angular/common';
+import { Component, Input } from '@angular/core';
+import { MailboxIconComponent, NavItemComponent, StatisticIconComponent } from '@ods/system';
+
+@Component({
+  selector: 'admin-menu',
+  standalone: true,
+  imports: [CommonModule, NavItemComponent, MailboxIconComponent, TechSharedModule, StatisticIconComponent],
+  templateUrl: './menu.component.html',
+})
+export class MenuComponent {
+  @Input() configurationStateResource: StateResource<ConfigurationResource>;
+
+  public readonly configurationLinkRel = ConfigurationLinkRel;
+}
diff --git a/alfa-client/libs/admin/configuration/src/test-setup.ts b/alfa-client/libs/admin/configuration/src/test-setup.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c408668266d2fec3a9803c0ec044bc163fb987fe
--- /dev/null
+++ b/alfa-client/libs/admin/configuration/src/test-setup.ts
@@ -0,0 +1,12 @@
+import '@testing-library/jest-dom';
+import 'jest-preset-angular/setup-jest';
+
+import { getTestBed } from '@angular/core/testing';
+import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
+
+getTestBed().resetTestEnvironment();
+getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting(), {
+  teardown: { destroyAfterEach: false },
+  errorOnUnknownProperties: true,
+  errorOnUnknownElements: true,
+});
diff --git a/alfa-client/libs/admin/configuration/tsconfig.json b/alfa-client/libs/admin/configuration/tsconfig.json
new file mode 100644
index 0000000000000000000000000000000000000000..8ca9ad312c2bd4dc364383853ddd91a2ed8f86fd
--- /dev/null
+++ b/alfa-client/libs/admin/configuration/tsconfig.json
@@ -0,0 +1,16 @@
+{
+  "extends": "../../../tsconfig.base.json",
+  "files": [],
+  "include": [],
+  "references": [
+    {
+      "path": "./tsconfig.lib.json"
+    },
+    {
+      "path": "./tsconfig.spec.json"
+    }
+  ],
+  "compilerOptions": {
+    "target": "es2022"
+  }
+}
diff --git a/alfa-client/libs/admin/configuration/tsconfig.lib.json b/alfa-client/libs/admin/configuration/tsconfig.lib.json
new file mode 100644
index 0000000000000000000000000000000000000000..8441346f6e5858b2ef4235cb3c3160eda256f94a
--- /dev/null
+++ b/alfa-client/libs/admin/configuration/tsconfig.lib.json
@@ -0,0 +1,12 @@
+{
+  "extends": "./tsconfig.json",
+  "compilerOptions": {
+    "outDir": "../../../dist/out-tsc",
+    "declaration": true,
+    "declarationMap": true,
+    "inlineSources": true,
+    "types": []
+  },
+  "exclude": ["src/**/*.spec.ts", "src/test-setup.ts", "jest.config.ts", "src/**/*.test.ts"],
+  "include": ["src/**/*.ts"]
+}
diff --git a/alfa-client/libs/admin/configuration/tsconfig.spec.json b/alfa-client/libs/admin/configuration/tsconfig.spec.json
new file mode 100644
index 0000000000000000000000000000000000000000..723782fbd367969806c5992aea882773ab65af8b
--- /dev/null
+++ b/alfa-client/libs/admin/configuration/tsconfig.spec.json
@@ -0,0 +1,12 @@
+{
+  "extends": "./tsconfig.json",
+  "compilerOptions": {
+    "outDir": "../../../dist/out-tsc",
+    "module": "commonjs",
+    "types": ["jest", "node"],
+    "target": "ES2022",
+    "useDefineForClassFields": false
+  },
+  "files": ["src/test-setup.ts"],
+  "include": ["**/*.test.ts", "**/*.spec.ts", "**/*.d.ts", "jest.config.ts"]
+}
diff --git a/alfa-client/libs/admin/organisations-einheit/src/lib/organisations-einheit-container/organisations-einheit-list/organisations-einheit-list.component.html b/alfa-client/libs/admin/organisations-einheit/src/lib/organisations-einheit-container/organisations-einheit-list/organisations-einheit-list.component.html
index b90eaca0ebe2582b649a5ddc44cdc3cc84f76e67..8dc8279de55dc9926954798e2eece9dbc68eee0c 100644
--- a/alfa-client/libs/admin/organisations-einheit/src/lib/organisations-einheit-container/organisations-einheit-list/organisations-einheit-list.component.html
+++ b/alfa-client/libs/admin/organisations-einheit/src/lib/organisations-einheit-container/organisations-einheit-list/organisations-einheit-list.component.html
@@ -48,7 +48,7 @@
       <dd class="mt-1" data-test-id="organisations-einheit-sync-error">
         <ods-exclamation-icon
           *ngIf="organisationsEinheitResource.syncResult === AdminOrganisationsEinheitSyncResult.NOT_FOUND_IN_PVOG"
-          matTooltip="Organisationseinheit wurde nicht in den PVOG-Daten gefunden."
+          tooltip="Organisationseinheit wurde nicht in den PVOG-Daten gefunden."
           size="small"
         />
         <ods-exclamation-icon
diff --git a/alfa-client/libs/admin/organisations-einheit/src/lib/organisations-einheit-container/organisations-einheit-list/organisations-einheit-list.component.spec.ts b/alfa-client/libs/admin/organisations-einheit/src/lib/organisations-einheit-container/organisations-einheit-list/organisations-einheit-list.component.spec.ts
index f7ce733a741f7c9c8a2162bca39ece86ad04b76f..0d5d5364e04fbe0e99026fb099091d7f7d641495 100644
--- a/alfa-client/libs/admin/organisations-einheit/src/lib/organisations-einheit-container/organisations-einheit-list/organisations-einheit-list.component.spec.ts
+++ b/alfa-client/libs/admin/organisations-einheit/src/lib/organisations-einheit-container/organisations-einheit-list/organisations-einheit-list.component.spec.ts
@@ -31,16 +31,15 @@ import {
 } from '@alfa-client/test-utils';
 import { CommonModule } from '@angular/common';
 import { ComponentFixture, TestBed } from '@angular/core/testing';
-import { MatTooltipModule } from '@angular/material/tooltip';
 import { ActivatedRoute } from '@angular/router';
-import { ExclamationIconComponent, ListComponent, ListItemComponent } from '@ods/system';
+import { ExclamationIconComponent, ListComponent, ListItemComponent, TooltipDirective } from '@ods/system';
 import {
   AdminOrganisationsEinheitResource,
   AdminOrganisationsEinheitSyncResult,
 } from 'libs/admin/organisations-einheit-shared/src/lib/organisations-einheit.model';
 import { createAdminOrganisationsEinheitResource } from 'libs/admin/organisations-einheit-shared/src/test/organisations-einheit';
 import { getDataTestIdOf } from 'libs/tech-shared/test/data-test';
-import { MockComponent, MockModule } from 'ng-mocks';
+import { MockComponent, MockDirective } from 'ng-mocks';
 import { OrganisationsEinheitListComponent } from './organisations-einheit-list.component';
 
 describe('OrganisationsEinheitListComponent', () => {
@@ -71,7 +70,7 @@ describe('OrganisationsEinheitListComponent', () => {
         MockComponent(ListComponent),
         MockComponent(ListItemComponent),
         MockComponent(ExclamationIconComponent),
-        MockModule(MatTooltipModule),
+        MockDirective(TooltipDirective),
       ],
     }).compileComponents();
 
diff --git a/alfa-client/libs/admin/organisations-einheit/src/lib/organisations-einheit-container/organisations-einheit-list/organisations-einheit-list.component.ts b/alfa-client/libs/admin/organisations-einheit/src/lib/organisations-einheit-container/organisations-einheit-list/organisations-einheit-list.component.ts
index 826556819ed09bee47196d4f0667a466d18fd3c0..fadda5a235ab06b9230cbd0d88552e8caa770f8d 100644
--- a/alfa-client/libs/admin/organisations-einheit/src/lib/organisations-einheit-container/organisations-einheit-list/organisations-einheit-list.component.ts
+++ b/alfa-client/libs/admin/organisations-einheit/src/lib/organisations-einheit-container/organisations-einheit-list/organisations-einheit-list.component.ts
@@ -28,14 +28,13 @@ import {
 import { TechSharedModule } from '@alfa-client/tech-shared';
 import { CommonModule } from '@angular/common';
 import { Component, Input } from '@angular/core';
-import { MatTooltip } from '@angular/material/tooltip';
-import { ExclamationIconComponent, ListComponent, ListItemComponent } from '@ods/system';
+import { ExclamationIconComponent, ListComponent, ListItemComponent, TooltipDirective } from '@ods/system';
 
 @Component({
   selector: 'admin-organisations-einheit-list',
   templateUrl: './organisations-einheit-list.component.html',
   standalone: true,
-  imports: [CommonModule, ListComponent, ListItemComponent, ExclamationIconComponent, MatTooltip, TechSharedModule],
+  imports: [CommonModule, ListComponent, ListItemComponent, ExclamationIconComponent, TooltipDirective, TechSharedModule],
 })
 export class OrganisationsEinheitListComponent {
   private _organisationsEinheitResources: AdminOrganisationsEinheitResource[] = [];
diff --git a/alfa-client/libs/admin/shared/src/lib/routes.ts b/alfa-client/libs/admin/shared/src/lib/routes.ts
index 4867284b8af315446b304fac9496612723910aaa..36d67d9ecc4785084d02668c47a63aa0392cd710 100644
--- a/alfa-client/libs/admin/shared/src/lib/routes.ts
+++ b/alfa-client/libs/admin/shared/src/lib/routes.ts
@@ -26,4 +26,6 @@ export const ROUTES = {
   BENUTZER_UND_ROLLEN: 'benutzer_und_rollen',
   BENUTZER_UND_ROLLEN_NEU: 'benutzer_und_rollen/neu',
   ORGANISATIONSEINHEITEN: 'organisationseinheiten',
+  UNAVAILABLE: 'unavailable',
+  STATISTIK: 'statistik',
 };
diff --git a/alfa-client/libs/admin/statistik/.eslintrc.json b/alfa-client/libs/admin/statistik/.eslintrc.json
new file mode 100644
index 0000000000000000000000000000000000000000..7474579d583c598ae092a906b3e6cf1ad3c08a50
--- /dev/null
+++ b/alfa-client/libs/admin/statistik/.eslintrc.json
@@ -0,0 +1,33 @@
+{
+  "extends": ["../../../.eslintrc.json"],
+  "ignorePatterns": ["!**/*"],
+  "overrides": [
+    {
+      "files": ["*.ts"],
+      "extends": ["plugin:@nx/angular", "plugin:@angular-eslint/template/process-inline-templates"],
+      "rules": {
+        "@angular-eslint/directive-selector": [
+          "error",
+          {
+            "type": "attribute",
+            "prefix": "admin",
+            "style": "camelCase"
+          }
+        ],
+        "@angular-eslint/component-selector": [
+          "error",
+          {
+            "type": "element",
+            "prefix": "admin",
+            "style": "kebab-case"
+          }
+        ]
+      }
+    },
+    {
+      "files": ["*.html"],
+      "extends": ["plugin:@nx/angular-template"],
+      "rules": {}
+    }
+  ]
+}
diff --git a/alfa-client/libs/admin/statistik/README.md b/alfa-client/libs/admin/statistik/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..ad651ba5c6b2577aae0af1c1ac56ca839db65022
--- /dev/null
+++ b/alfa-client/libs/admin/statistik/README.md
@@ -0,0 +1,7 @@
+# statistik
+
+This library was generated with [Nx](https://nx.dev).
+
+## Running unit tests
+
+Run `nx test statistik` to execute the unit tests.
diff --git a/alfa-client/libs/admin/statistik/jest.config.ts b/alfa-client/libs/admin/statistik/jest.config.ts
new file mode 100644
index 0000000000000000000000000000000000000000..fc41bd8816868cdd6f860b9908d0f06dbc9defc9
--- /dev/null
+++ b/alfa-client/libs/admin/statistik/jest.config.ts
@@ -0,0 +1,21 @@
+export default {
+  displayName: 'admin-statistik',
+  preset: '../../../jest.preset.js',
+  setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
+  coverageDirectory: '../../../coverage/libs/admin/statistik',
+  transform: {
+    '^.+\\.(ts|mjs|js|html)$': [
+      'jest-preset-angular',
+      {
+        tsconfig: '<rootDir>/tsconfig.spec.json',
+        stringifyContentPathRegex: '\\.(html|svg)$',
+      },
+    ],
+  },
+  transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
+  snapshotSerializers: [
+    'jest-preset-angular/build/serializers/no-ng-attributes',
+    'jest-preset-angular/build/serializers/ng-snapshot',
+    'jest-preset-angular/build/serializers/html-comment',
+  ],
+};
diff --git a/alfa-client/libs/admin/statistik/project.json b/alfa-client/libs/admin/statistik/project.json
new file mode 100644
index 0000000000000000000000000000000000000000..a5c36fc013da6fcc3504172dad9627628b42cfd9
--- /dev/null
+++ b/alfa-client/libs/admin/statistik/project.json
@@ -0,0 +1,22 @@
+{
+  "name": "admin-statistik",
+  "$schema": "../../../node_modules/nx/schemas/project-schema.json",
+  "sourceRoot": "libs/admin/statistik/src",
+  "prefix": "admin",
+  "projectType": "library",
+  "tags": [],
+  "targets": {
+    "test": {
+      "executor": "@nx/jest:jest",
+      "outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
+      "options": {
+        "tsConfig": "libs/admin/statistik/tsconfig.lib.json",
+        "jestConfig": "libs/admin/statistik/jest.config.ts"
+      }
+    },
+    "lint": {
+      "executor": "@nx/eslint:lint",
+      "outputs": ["{options.outputFile}"]
+    }
+  }
+}
diff --git a/alfa-client/libs/admin/statistik/src/index.ts b/alfa-client/libs/admin/statistik/src/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..cdc5d7b64f24d50920b721f3ab01c5b69cb41b99
--- /dev/null
+++ b/alfa-client/libs/admin/statistik/src/index.ts
@@ -0,0 +1 @@
+export * from './lib/statistik-container/statistik-container.component';
diff --git a/alfa-client/libs/admin/statistik/src/lib/statistik-container/statistik-container.component.html b/alfa-client/libs/admin/statistik/src/lib/statistik-container/statistik-container.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..eb8c0eaa7fd1b08d5028ff9abbd5001ba0f89ea4
--- /dev/null
+++ b/alfa-client/libs/admin/statistik/src/lib/statistik-container/statistik-container.component.html
@@ -0,0 +1,26 @@
+<!--
+
+    Copyright (C) 2025 Das Land Schleswig-Holstein vertreten durch den
+    Ministerpräsidenten des Landes Schleswig-Holstein
+    Staatskanzlei
+    Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+
+    Lizenziert unter der EUPL, Version 1.2 oder - sobald
+    diese von der Europäischen Kommission genehmigt wurden -
+    Folgeversionen der EUPL ("Lizenz");
+    Sie dürfen dieses Werk ausschließlich gemäß
+    dieser Lizenz nutzen.
+    Eine Kopie der Lizenz finden Sie hier:
+
+    https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+
+    Sofern nicht durch anwendbare Rechtsvorschriften
+    gefordert oder in schriftlicher Form vereinbart, wird
+    die unter der Lizenz verbreitete Software "so wie sie
+    ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+    ausdrücklich oder stillschweigend - verbreitet.
+    Die sprachspezifischen Genehmigungen und Beschränkungen
+    unter der Lizenz sind dem Lizenztext zu entnehmen.
+
+-->
+<h1 class="heading-1" data-test-id="statistik-header-text">Statistik</h1>
diff --git a/alfa-client/libs/admin/statistik/src/lib/statistik-container/statistik-container.component.spec.ts b/alfa-client/libs/admin/statistik/src/lib/statistik-container/statistik-container.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..84b58ee0de584e0b5445a79865b4154cc60bb4c7
--- /dev/null
+++ b/alfa-client/libs/admin/statistik/src/lib/statistik-container/statistik-container.component.spec.ts
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2025 Das Land Schleswig-Holstein vertreten durch den
+ * Ministerpräsidenten des Landes Schleswig-Holstein
+ * Staatskanzlei
+ * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+ *
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { StatistikContainerComponent } from './statistik-container.component';
+
+describe('StatistikContainerComponent', () => {
+  let component: StatistikContainerComponent;
+  let fixture: ComponentFixture<StatistikContainerComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: [StatistikContainerComponent],
+    });
+  });
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(StatistikContainerComponent);
+    component = fixture.componentInstance;
+
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/alfa-client/libs/ui/src/lib/ui/mattooltip/mattooltip.default.ts b/alfa-client/libs/admin/statistik/src/lib/statistik-container/statistik-container.component.ts
similarity index 71%
rename from alfa-client/libs/ui/src/lib/ui/mattooltip/mattooltip.default.ts
rename to alfa-client/libs/admin/statistik/src/lib/statistik-container/statistik-container.component.ts
index af14a745eb9b5d1fe8556ab9ea07ccac3b14ded4..05e7e9db912474d8f6991acdf8f20d480b309fe2 100644
--- a/alfa-client/libs/ui/src/lib/ui/mattooltip/mattooltip.default.ts
+++ b/alfa-client/libs/admin/statistik/src/lib/statistik-container/statistik-container.component.ts
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den
+ * Copyright (C) 2025 Das Land Schleswig-Holstein vertreten durch den
  * Ministerpräsidenten des Landes Schleswig-Holstein
  * Staatskanzlei
  * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
@@ -21,12 +21,13 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-import { MatTooltipDefaultOptions } from '@angular/material/tooltip';
+import { CommonModule } from '@angular/common';
+import { Component } from '@angular/core';
 
-export const matTooltipDefaultOptions: MatTooltipDefaultOptions = {
-  showDelay: 1500,
-  hideDelay: 0,
-  touchendHideDelay: 1500,
-  positionAtOrigin: true,
-  disableTooltipInteractivity: true,
-};
+@Component({
+  selector: 'admin-statistik-container',
+  templateUrl: './statistik-container.component.html',
+  standalone: true,
+  imports: [CommonModule],
+})
+export class StatistikContainerComponent {}
diff --git a/alfa-client/libs/admin/statistik/src/test-setup.ts b/alfa-client/libs/admin/statistik/src/test-setup.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ef358fbdf02a6bfc0ca9a7c2f5c73766b01ef584
--- /dev/null
+++ b/alfa-client/libs/admin/statistik/src/test-setup.ts
@@ -0,0 +1,7 @@
+globalThis.ngJest = {
+  testEnvironmentOptions: {
+    errorOnUnknownElements: true,
+    errorOnUnknownProperties: true,
+  },
+};
+import 'jest-preset-angular/setup-jest';
diff --git a/alfa-client/libs/admin/statistik/tsconfig.json b/alfa-client/libs/admin/statistik/tsconfig.json
new file mode 100644
index 0000000000000000000000000000000000000000..8ca9ad312c2bd4dc364383853ddd91a2ed8f86fd
--- /dev/null
+++ b/alfa-client/libs/admin/statistik/tsconfig.json
@@ -0,0 +1,16 @@
+{
+  "extends": "../../../tsconfig.base.json",
+  "files": [],
+  "include": [],
+  "references": [
+    {
+      "path": "./tsconfig.lib.json"
+    },
+    {
+      "path": "./tsconfig.spec.json"
+    }
+  ],
+  "compilerOptions": {
+    "target": "es2022"
+  }
+}
diff --git a/alfa-client/libs/admin/statistik/tsconfig.lib.json b/alfa-client/libs/admin/statistik/tsconfig.lib.json
new file mode 100644
index 0000000000000000000000000000000000000000..8441346f6e5858b2ef4235cb3c3160eda256f94a
--- /dev/null
+++ b/alfa-client/libs/admin/statistik/tsconfig.lib.json
@@ -0,0 +1,12 @@
+{
+  "extends": "./tsconfig.json",
+  "compilerOptions": {
+    "outDir": "../../../dist/out-tsc",
+    "declaration": true,
+    "declarationMap": true,
+    "inlineSources": true,
+    "types": []
+  },
+  "exclude": ["src/**/*.spec.ts", "src/test-setup.ts", "jest.config.ts", "src/**/*.test.ts"],
+  "include": ["src/**/*.ts"]
+}
diff --git a/alfa-client/libs/admin/statistik/tsconfig.spec.json b/alfa-client/libs/admin/statistik/tsconfig.spec.json
new file mode 100644
index 0000000000000000000000000000000000000000..723782fbd367969806c5992aea882773ab65af8b
--- /dev/null
+++ b/alfa-client/libs/admin/statistik/tsconfig.spec.json
@@ -0,0 +1,12 @@
+{
+  "extends": "./tsconfig.json",
+  "compilerOptions": {
+    "outDir": "../../../dist/out-tsc",
+    "module": "commonjs",
+    "types": ["jest", "node"],
+    "target": "ES2022",
+    "useDefineForClassFields": false
+  },
+  "files": ["src/test-setup.ts"],
+  "include": ["**/*.test.ts", "**/*.spec.ts", "**/*.d.ts", "jest.config.ts"]
+}
diff --git a/alfa-client/libs/admin/user-shared/src/lib/user.model.ts b/alfa-client/libs/admin/user-shared/src/lib/user.model.ts
index 2e933072b14ea8f5bd080cfb143a05a54389e27b..f6dcac00ce2ddc7b7e50c0f908271e4140eaadde 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,12 +21,24 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
+import RoleRepresentation from '@keycloak/keycloak-admin-client/lib/defs/roleRepresentation';
+
 export interface User {
   id: string;
   username: string;
   email: string;
   firstName: string;
   lastName: string;
+  enabled: boolean;
   groups?: string[];
-  roles?: string[];
+  clientRoles: ClientRoles;
+}
+
+export interface ClientRoles {
+  alfa: string[];
+  admin: string[];
+}
+
+export interface ClientMapping {
+  mappings: RoleRepresentation[];
 }
diff --git a/alfa-client/libs/admin/user-shared/src/lib/user.repository.service.spec.ts b/alfa-client/libs/admin/user-shared/src/lib/user.repository.service.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ea7250024c77cbb16ce65dc76e499ce02c137c2c
--- /dev/null
+++ b/alfa-client/libs/admin/user-shared/src/lib/user.repository.service.spec.ts
@@ -0,0 +1,300 @@
+/*
+ * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den
+ * Ministerpräsidenten des Landes Schleswig-Holstein
+ * Staatskanzlei
+ * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+ *
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+import { Mock, mock } from '@alfa-client/test-utils';
+import { TestBed, fakeAsync, tick } from '@angular/core/testing';
+import { faker } from '@faker-js/faker';
+import KcAdminClient from '@keycloak/keycloak-admin-client';
+import { TokenProvider } from '@keycloak/keycloak-admin-client/lib/client';
+import GroupRepresentation from '@keycloak/keycloak-admin-client/lib/defs/groupRepresentation';
+import MappingsRepresentation from '@keycloak/keycloak-admin-client/lib/defs/mappingsRepresentation';
+import { RoleMappingPayload } from '@keycloak/keycloak-admin-client/lib/defs/roleRepresentation';
+import { OAuthService } from 'angular-oauth2-oidc';
+import { cold } from 'jest-marbles';
+import { throwError } from 'rxjs';
+import { UserAddFormservice } from '../../../user/src/lib/users-roles/user-add-form/user-add.formservice';
+import { createUser } from '../../test/user';
+import { User } from './user.model';
+import { UserRepository } from './user.repository.service';
+
+describe('UserRepository', () => {
+  const accessToken: string = faker.string.alphanumeric(40);
+
+  let repository: UserRepository;
+
+  let kcAdminClient: Mock<KcAdminClient>;
+  let oAuthService: Mock<OAuthService>;
+
+  beforeEach(() => {
+    kcAdminClient = mock(KcAdminClient);
+    oAuthService = mock(OAuthService);
+    TestBed.configureTestingModule({
+      providers: [
+        { provide: OAuthService, useValue: oAuthService },
+        { provide: KcAdminClient, useValue: kcAdminClient },
+      ],
+    });
+    oAuthService.getAccessToken.mockReturnValue(accessToken);
+    repository = TestBed.inject(UserRepository);
+  });
+
+  it('should be created', () => {
+    expect(repository).toBeTruthy();
+  });
+
+  describe('registerTokenProvider', () => {
+    it('should register token provider from oauth service', async () => {
+      const tokenProvider: TokenProvider = kcAdminClient.registerTokenProvider.mock.calls[0][0];
+      const token: string = await tokenProvider.getAccessToken();
+      expect(token).toEqual(accessToken);
+    });
+  });
+
+  describe('createInKeycloak', () => {
+    const user: User = createUser();
+
+    beforeEach(() => {
+      kcAdminClient.users = <any>{
+        create: jest.fn().mockReturnValue(Promise.resolve({ id: user.id })),
+        findOne: jest.fn().mockReturnValue(Promise.resolve(user)),
+        addClientRoleMappings: jest.fn().mockReturnValue(Promise.resolve()),
+        executeActionsEmail: jest.fn().mockReturnValue(Promise.resolve()),
+      };
+      kcAdminClient.clients = <any>{
+        find: jest.fn().mockReturnValue(Promise.resolve([{ id: faker.string.uuid() }])),
+        listRoles: jest.fn().mockReturnValue(Promise.resolve([{ id: faker.string.uuid(), name: faker.word.sample() }])),
+      };
+    });
+
+    it('should call kcAdminClient users create', () => {
+      repository.createInKeycloak(user);
+
+      expect(kcAdminClient.users['create']).toBeCalledWith(user);
+    });
+
+    it('should call addUserRoles', fakeAsync(() => {
+      const addUserRolesSpy: jest.SpyInstance = jest.spyOn(repository, 'addUserRoles');
+
+      repository.createInKeycloak(user).subscribe();
+      tick();
+
+      expect(addUserRolesSpy).toBeCalledWith(user.id, user.clientRoles);
+    }));
+
+    it('should call sendActivationMail', (done) => {
+      const sendActivationMailSpy: jest.SpyInstance = jest.spyOn(repository, 'sendActivationMail');
+      jest.spyOn(repository, 'addUserRoles').mockReturnValue(Promise.resolve());
+
+      repository.createInKeycloak(user).subscribe(() => {
+        expect(sendActivationMailSpy).toBeCalledWith(user.id);
+        done();
+      });
+    });
+
+    it('should call getUserById', (done) => {
+      const getUserByIdSpy: jest.SpyInstance = jest.spyOn(repository, 'getUserById');
+
+      repository.createInKeycloak(user).subscribe(() => {
+        expect(getUserByIdSpy).toBeCalledWith(user.id);
+        done();
+      });
+    });
+
+    it('should call handleError', fakeAsync(() => {
+      const handleErrorSpy: jest.SpyInstance = jest.spyOn(repository, 'handleError');
+      kcAdminClient.users['create'] = jest.fn().mockReturnValue(throwError(() => new Error('error')));
+
+      repository.createInKeycloak(user).subscribe({ error: () => {} });
+      tick();
+
+      expect(handleErrorSpy).toHaveBeenCalled();
+    }));
+
+    describe('addUserRoles', () => {
+      it('should call addUserRolesForClient for admin', async () => {
+        const addUserRolesForClientSpy: jest.SpyInstance = jest.spyOn(repository, 'addUserRolesForClient');
+
+        await repository.addUserRoles(user.id, { admin: [UserAddFormservice.ADMIN], alfa: [] });
+
+        expect(addUserRolesForClientSpy).toBeCalledWith(user.id, [UserAddFormservice.ADMIN], UserRepository.ADMIN_CLIENT_NAME);
+      });
+
+      it('should call addUserRolesForClient for admin', async () => {
+        const addUserRolesForClientSpy: jest.SpyInstance = jest.spyOn(repository, 'addUserRolesForClient');
+
+        await repository.addUserRoles(user.id, { alfa: [UserAddFormservice.POSTSTELLE], admin: [] });
+
+        expect(addUserRolesForClientSpy).toBeCalledWith(
+          user.id,
+          [UserAddFormservice.POSTSTELLE],
+          UserRepository.ALFA_CLIENT_NAME,
+        );
+      });
+
+      it('should not call addUserRolesForClient if clientRoles alfa and admin are empty', async () => {
+        const addUserRolesForClientSpy: jest.SpyInstance = jest.spyOn(repository, 'addUserRolesForClient');
+
+        await repository.addUserRoles(user.id, { admin: [], alfa: [] });
+
+        expect(addUserRolesForClientSpy).not.toHaveBeenCalled();
+      });
+    });
+
+    describe('addUserRolesForClient', () => {
+      const clientId: string = faker.string.uuid();
+      const roleMapping: RoleMappingPayload[] = [{ id: faker.string.uuid(), name: faker.word.sample() }];
+      let getClientIdSpy: jest.SpyInstance;
+      let mapUserRolesSpy: jest.SpyInstance;
+      let addUserRolesInKeycloak: jest.SpyInstance;
+
+      beforeEach(() => {
+        getClientIdSpy = jest.spyOn(repository, 'getClientId').mockReturnValue(Promise.resolve(clientId));
+        mapUserRolesSpy = jest.spyOn(repository, 'mapUserRoles').mockReturnValue(Promise.resolve(roleMapping));
+        addUserRolesInKeycloak = jest.spyOn(repository, 'addUserRolesInKeycloak');
+      });
+
+      it('should call getClientId', async () => {
+        await repository.addUserRolesForClient(user.id, [UserAddFormservice.ADMIN], UserRepository.ADMIN_CLIENT_NAME);
+
+        expect(getClientIdSpy).toBeCalled();
+      });
+
+      it('should call getAlfaClientId', async () => {
+        await repository.addUserRolesForClient(user.id, [UserAddFormservice.ADMIN], UserRepository.ADMIN_CLIENT_NAME);
+
+        expect(mapUserRolesSpy).toHaveBeenCalledWith(clientId, [UserAddFormservice.ADMIN]);
+      });
+
+      it('should call addUserRolesInKeycloak', async () => {
+        await repository.addUserRolesForClient(user.id, [UserAddFormservice.ADMIN], UserRepository.ADMIN_CLIENT_NAME);
+
+        expect(addUserRolesInKeycloak).toHaveBeenCalledWith(user.id, clientId, roleMapping);
+      });
+    });
+
+    describe('sendActivationMail', () => {
+      it('should call kcAdminClient users executeActionsEmail', () => {
+        const userId: string = faker.string.uuid();
+
+        repository.sendActivationMail(userId);
+
+        expect(kcAdminClient.users['executeActionsEmail']).toBeCalledWith({
+          id: userId,
+          actions: ['VERIFY_EMAIL'],
+          lifespan: 3600 * 24 * 7,
+        });
+      });
+    });
+
+    describe('getUserById', () => {
+      it('should call kcAdminClient users findOne', () => {
+        const userId: string = faker.string.uuid();
+
+        repository.getUserById(userId);
+
+        expect(kcAdminClient.users['findOne']).toBeCalledWith({ id: userId });
+      });
+    });
+
+    describe('handleError', () => {
+      it('should throw error', () => {
+        const error: Error = new Error('error');
+        const result = repository.handleError(error);
+
+        expect(result).toBeObservable(cold('#', null, new Error('An error occurred while creating the user.')));
+      });
+    });
+  });
+
+  describe('getUsers', () => {
+    const userRep: User = createUser();
+    const userRepArray: User[] = [userRep, userRep, userRep];
+    const group: string = faker.word.sample();
+    const alfaRole: string = faker.word.sample();
+    const adminRole: string = faker.word.sample();
+    const groupRep: GroupRepresentation[] = [{ name: group }];
+    const roleRep: MappingsRepresentation = {
+      clientMappings: {
+        alfa: { mappings: [{ name: alfaRole }] },
+        admin: { mappings: [{ name: adminRole }] },
+      },
+    };
+
+    beforeEach(() => {
+      jest.clearAllMocks();
+      kcAdminClient.users = <any>{
+        find: jest.fn().mockReturnValue(Promise.resolve(userRepArray)),
+        listGroups: jest.fn().mockReturnValue(Promise.resolve(groupRep)),
+        listRoleMappings: jest.fn().mockReturnValue(Promise.resolve(roleRep)),
+      };
+    });
+
+    it('should call kcAdminClient users find', () => {
+      repository.getUsers();
+
+      expect(kcAdminClient.users['find']).toHaveBeenCalled();
+    });
+
+    it('should call mapToUser', fakeAsync(() => {
+      const mapToUser: jest.SpyInstance<User> = jest.spyOn(repository, 'mapToUser');
+
+      repository.getUsers().subscribe();
+      tick();
+
+      expect(mapToUser).toBeCalledTimes(userRepArray.length);
+    }));
+
+    it('should call kcadminClient listGroups for every user', fakeAsync(() => {
+      repository.getUsers().subscribe();
+      tick();
+
+      expect(kcAdminClient.users['listGroups']).toBeCalledTimes(userRepArray.length);
+    }));
+
+    it('should call kcadminClient listRoleMappings for every user', fakeAsync(() => {
+      repository.getUsers().subscribe();
+      tick();
+
+      expect(kcAdminClient.users['listRoleMappings']).toBeCalledTimes(userRepArray.length);
+    }));
+
+    it('should return users with groups and roles', (done) => {
+      repository.getUsers().subscribe((users: User[]) => {
+        users.forEach((user) =>
+          expect(user).toEqual({ ...userRep, groups: [group], clientRoles: { alfa: [alfaRole], admin: [adminRole] } }),
+        );
+        done();
+      });
+    });
+
+    it('should return users with empty groups and roles if they have none', (done) => {
+      kcAdminClient.users['listGroups'] = jest.fn().mockReturnValue(Promise.resolve([]));
+      kcAdminClient.users['listRoleMappings'] = jest.fn().mockReturnValue(Promise.resolve({}));
+
+      repository.getUsers().subscribe((users: User[]) => {
+        users.forEach((user) => expect(user).toEqual({ ...userRep, groups: [], clientRoles: { alfa: [], admin: [] } }));
+        done();
+      });
+    });
+  });
+});
diff --git a/alfa-client/libs/admin/user-shared/src/lib/user.repository.service.ts b/alfa-client/libs/admin/user-shared/src/lib/user.repository.service.ts
index 06fb8e0a8a8f76657d0dbdd6d1d85a11db443f5b..2b0ded61b000f7c95eaa6fe3ebbb0437636d3b95 100644
--- a/alfa-client/libs/admin/user-shared/src/lib/user.repository.service.ts
+++ b/alfa-client/libs/admin/user-shared/src/lib/user.repository.service.ts
@@ -24,14 +24,15 @@
 import { Injectable } from '@angular/core';
 import KcAdminClient from '@keycloak/keycloak-admin-client';
 import { TokenProvider } from '@keycloak/keycloak-admin-client/lib/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 from '@keycloak/keycloak-admin-client/lib/defs/roleRepresentation';
+import RoleRepresentation, { RoleMappingPayload } from '@keycloak/keycloak-admin-client/lib/defs/roleRepresentation';
 import UserRepresentation from '@keycloak/keycloak-admin-client/lib/defs/userRepresentation';
 import { OAuthService } from 'angular-oauth2-oidc';
 import { isNil } from 'lodash-es';
-import { Observable, forkJoin, from, map, mergeMap } from 'rxjs';
-import { User } from './user.model';
+import { Observable, catchError, concatMap, forkJoin, from, map, mergeMap, switchMap, tap, throwError } from 'rxjs';
+import { ClientMapping, ClientRoles, User } from './user.model';
 
 @Injectable({
   providedIn: 'root',
@@ -44,6 +45,9 @@ export class UserRepository {
     this.registerAccessTokenProvider();
   }
 
+  public static readonly ALFA_CLIENT_NAME: string = 'alfa';
+  public static readonly ADMIN_CLIENT_NAME: string = 'admin';
+
   private registerAccessTokenProvider(): void {
     this.kcAdminClient.registerTokenProvider(this.getTokenProvider());
   }
@@ -54,6 +58,69 @@ export class UserRepository {
     };
   }
 
+  public createInKeycloak(user: Partial<User>): Observable<User> {
+    return from(this.kcAdminClient.users.create(user)).pipe(
+      concatMap(async (response: { id: string }) => {
+        await this.addUserRoles(response.id, user.clientRoles);
+        return response;
+      }),
+      tap((response: { id: string }) => this.sendActivationMail(response.id)),
+      switchMap((response: { id: string }): Observable<User> => this.getUserById(response.id)),
+      catchError((err) => this.handleError(err)),
+    );
+  }
+
+  async addUserRoles(userId: string, clientRoles: ClientRoles): Promise<void> {
+    if (clientRoles.admin.length > 0) {
+      await this.addUserRolesForClient(userId, clientRoles.admin, UserRepository.ADMIN_CLIENT_NAME);
+    }
+
+    if (clientRoles.alfa.length > 0) {
+      await this.addUserRolesForClient(userId, clientRoles.alfa, UserRepository.ALFA_CLIENT_NAME);
+    }
+  }
+
+  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);
+  }
+
+  async getClientId(client: string): Promise<string | undefined> {
+    const clients: ClientRepresentation[] = await this.kcAdminClient.clients.find({ clientId: client });
+    return clients?.[0].id;
+  }
+
+  async mapUserRoles(clientId: string, userRoles: string[]): Promise<RoleMappingPayload[]> {
+    const roles: RoleRepresentation[] = await this.kcAdminClient.clients.listRoles({ id: clientId });
+    return roles.filter((role) => userRoles.includes(role.name)).map((role) => ({ id: role.id, name: role.name }));
+  }
+
+  async addUserRolesInKeycloak(userId: string, clientId: string, roles: RoleMappingPayload[]): Promise<void> {
+    await this.kcAdminClient.users.addClientRoleMappings({
+      id: userId,
+      clientUniqueId: clientId,
+      roles,
+    });
+  }
+
+  sendActivationMail(userId: string): void {
+    this.kcAdminClient.users.executeActionsEmail({
+      id: userId,
+      actions: ['VERIFY_EMAIL'],
+      lifespan: 3600 * 24 * 7,
+    });
+  }
+
+  getUserById(userId: string): Observable<User> {
+    return from(this.kcAdminClient.users.findOne({ id: userId })) as Observable<User>;
+  }
+
+  handleError(err: any): Observable<never> {
+    console.error('Error creating user in Keycloak:', err);
+    return throwError(() => new Error('An error occurred while creating the user.'));
+  }
+
   public getUsers(): Observable<User[]> {
     return from(this.kcAdminClient.users.find()).pipe(
       map((userReps: UserRepresentation[]) => userReps.map((userReps) => this.mapToUser(userReps))),
@@ -68,17 +135,21 @@ export class UserRepository {
       username: userRepresentation.username,
       firstName: userRepresentation.firstName,
       lastName: userRepresentation.lastName,
+      enabled: userRepresentation.enabled,
       groups: null,
-      roles: null,
+      clientRoles: {
+        alfa: [],
+        admin: [],
+      },
     };
   }
 
   private addInformationToUser(user: User): Observable<User> {
-    return forkJoin([this.getUserGroups(user), this.getAlfaClientRoles(user)]).pipe(
-      map(([groups, roles]) => ({
+    return forkJoin([this.getUserGroups(user), this.getClientRoles(user)]).pipe(
+      map(([groups, clientRoles]) => ({
         ...user,
         groups,
-        roles,
+        clientRoles,
       })),
     );
   }
@@ -89,17 +160,24 @@ export class UserRepository {
     );
   }
 
-  private getAlfaClientRoles(user: User): Observable<string[]> {
+  private getClientRoles(user: User): Observable<ClientRoles> {
     return from(this.kcAdminClient.users.listRoleMappings({ id: user.id })).pipe(
-      map((clientMappings: MappingsRepresentation) => this.mapToAlfaClientRoleNames(clientMappings)),
+      map((roleMappings: MappingsRepresentation) => {
+        return {
+          alfa: this.mapToClientRoleNames(roleMappings, UserRepository.ALFA_CLIENT_NAME),
+          admin: this.mapToClientRoleNames(roleMappings, UserRepository.ADMIN_CLIENT_NAME),
+        };
+      }),
     );
   }
 
-  private mapToAlfaClientRoleNames(roleMappings: MappingsRepresentation): string[] {
-    if (isNil(roleMappings?.clientMappings?.['alfa'])) {
+  private mapToClientRoleNames(roleMappings: MappingsRepresentation, client: string): string[] {
+    const clientMappingsAlfa: ClientMapping | undefined = roleMappings?.clientMappings?.[client];
+
+    if (isNil(clientMappingsAlfa)) {
       return [];
     }
 
-    return roleMappings.clientMappings['alfa'].mappings.map((role: RoleRepresentation) => role.name);
+    return clientMappingsAlfa.mappings.map((role: RoleRepresentation) => role.name);
   }
 }
diff --git a/alfa-client/libs/admin/user-shared/src/lib/user.repository.spec.ts b/alfa-client/libs/admin/user-shared/src/lib/user.repository.spec.ts
deleted file mode 100644
index 35173f88cd008f41212d12306dcf3ac1f834a27d..0000000000000000000000000000000000000000
--- a/alfa-client/libs/admin/user-shared/src/lib/user.repository.spec.ts
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den
- * Ministerpräsidenten des Landes Schleswig-Holstein
- * Staatskanzlei
- * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
- *
- * Lizenziert unter der EUPL, Version 1.2 oder - sobald
- * diese von der Europäischen Kommission genehmigt wurden -
- * Folgeversionen der EUPL ("Lizenz");
- * Sie dürfen dieses Werk ausschließlich gemäß
- * dieser Lizenz nutzen.
- * Eine Kopie der Lizenz finden Sie hier:
- *
- * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
- *
- * Sofern nicht durch anwendbare Rechtsvorschriften
- * gefordert oder in schriftlicher Form vereinbart, wird
- * die unter der Lizenz verbreitete Software "so wie sie
- * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
- * ausdrücklich oder stillschweigend - verbreitet.
- * Die sprachspezifischen Genehmigungen und Beschränkungen
- * unter der Lizenz sind dem Lizenztext zu entnehmen.
- */
-import { Mock, mock } from '@alfa-client/test-utils';
-import { TestBed, fakeAsync, tick } from '@angular/core/testing';
-import { faker } from '@faker-js/faker';
-import KcAdminClient from '@keycloak/keycloak-admin-client';
-import { TokenProvider } from '@keycloak/keycloak-admin-client/lib/client';
-import GroupRepresentation from '@keycloak/keycloak-admin-client/lib/defs/groupRepresentation';
-import MappingsRepresentation from '@keycloak/keycloak-admin-client/lib/defs/mappingsRepresentation';
-import { OAuthService } from 'angular-oauth2-oidc';
-import { createUser } from '../../test/user';
-import { User } from './user.model';
-import { UserRepository } from './user.repository.service';
-
-describe('UserRepository', () => {
-  const accessToken: string = faker.string.alphanumeric(40);
-
-  let repository: UserRepository;
-
-  let kcAdminClient: Mock<KcAdminClient>;
-  let oAuthService: Mock<OAuthService>;
-
-  beforeEach(() => {
-    kcAdminClient = mock(KcAdminClient);
-    oAuthService = mock(OAuthService);
-    TestBed.configureTestingModule({
-      providers: [
-        { provide: OAuthService, useValue: oAuthService },
-        { provide: KcAdminClient, useValue: kcAdminClient },
-      ],
-    });
-    oAuthService.getAccessToken.mockReturnValue(accessToken);
-    repository = TestBed.inject(UserRepository);
-  });
-
-  it('should be created', () => {
-    expect(repository).toBeTruthy();
-  });
-
-  describe('registerTokenProvider', () => {
-    it('should register token provider from oauth service', async () => {
-      const tokenProvider: TokenProvider = kcAdminClient.registerTokenProvider.mock.calls[0][0];
-      const token: string = await tokenProvider.getAccessToken();
-      expect(token).toEqual(accessToken);
-    });
-  });
-
-  describe('getUsers', () => {
-    const userRep: User = createUser();
-    const userRepArray: User[] = [userRep, userRep, userRep];
-    const group: string = faker.word.sample();
-    const role: string = faker.word.sample();
-    const groupRep: GroupRepresentation[] = [{ name: group }];
-    const roleRep: MappingsRepresentation = {
-      clientMappings: { alfa: { mappings: [{ name: role }] } },
-    };
-
-    beforeEach(() => {
-      jest.clearAllMocks();
-      kcAdminClient.users = <any>{
-        find: jest.fn().mockReturnValue(Promise.resolve(userRepArray)),
-        listGroups: jest.fn().mockReturnValue(Promise.resolve(groupRep)),
-        listRoleMappings: jest.fn().mockReturnValue(Promise.resolve(roleRep)),
-      };
-    });
-
-    it('should call kcAdminClient users find', () => {
-      repository.getUsers();
-
-      expect(kcAdminClient.users['find']).toHaveBeenCalled();
-    });
-
-    it('should call mapToUser', fakeAsync(() => {
-      const mapToUser: jest.SpyInstance<User> = jest.spyOn(repository, 'mapToUser');
-
-      repository.getUsers().subscribe();
-      tick();
-
-      expect(mapToUser).toBeCalledTimes(userRepArray.length);
-    }));
-
-    it('should call kcadminClient listGroups for every user', fakeAsync(() => {
-      repository.getUsers().subscribe();
-      tick();
-
-      expect(kcAdminClient.users['listGroups']).toBeCalledTimes(userRepArray.length);
-    }));
-
-    it('should call kcadminClient listRoleMappings for every user', fakeAsync(() => {
-      repository.getUsers().subscribe();
-      tick();
-
-      expect(kcAdminClient.users['listRoleMappings']).toBeCalledTimes(userRepArray.length);
-    }));
-
-    it('should return users with groups and roles', (done) => {
-      repository.getUsers().subscribe((users: User[]) => {
-        users.forEach((user) => expect(user).toEqual({ ...userRep, groups: [group], roles: [role] }));
-        done();
-      });
-    });
-
-    it('should return users with empty groups and roles if they have none', (done) => {
-      kcAdminClient.users['listGroups'] = jest.fn().mockReturnValue(Promise.resolve([]));
-      kcAdminClient.users['listRoleMappings'] = jest.fn().mockReturnValue(Promise.resolve({}));
-
-      repository.getUsers().subscribe((users: User[]) => {
-        users.forEach((user) => expect(user).toEqual({ ...userRep, groups: [], roles: [] }));
-        done();
-      });
-    });
-  });
-});
diff --git a/alfa-client/libs/admin/user-shared/src/lib/user.service.spec.ts b/alfa-client/libs/admin/user-shared/src/lib/user.service.spec.ts
index f0067611db8651f2b00ecdd8faec239f37807086..c1148ee01e76d476ddf204eafee43060a936ad38 100644
--- a/alfa-client/libs/admin/user-shared/src/lib/user.service.spec.ts
+++ b/alfa-client/libs/admin/user-shared/src/lib/user.service.spec.ts
@@ -57,4 +57,14 @@ describe('UserService', () => {
       expect(sortUsersByLastNameSpy).toHaveBeenCalled();
     }));
   });
+
+  describe('createInKeycloak', () => {
+    const user: User = createUser();
+
+    it('should call createInKeycloak from userRepository', () => {
+      service.createInKeycloak(user);
+
+      expect(repository.createInKeycloak).toHaveBeenCalledWith(user);
+    });
+  });
 });
diff --git a/alfa-client/libs/admin/user-shared/src/lib/user.service.ts b/alfa-client/libs/admin/user-shared/src/lib/user.service.ts
index 8b4b5dbfba75332786ad7bf395b972f54a9c3af0..af05eea872bcb10f9383ba790efd3e89e14fae34 100644
--- a/alfa-client/libs/admin/user-shared/src/lib/user.service.ts
+++ b/alfa-client/libs/admin/user-shared/src/lib/user.service.ts
@@ -40,11 +40,11 @@ export class UserService extends KeycloakResourceService<User> {
     return this.userRepository.getUsers().pipe(map(sortUsersByLastName));
   }
 
-  createInKeycloak(item: Partial<User>): Observable<User> {
-    throw new Error('Method not implemented.');
+  createInKeycloak(user: Partial<User>): Observable<User> {
+    return this.userRepository.createInKeycloak(user);
   }
 
-  saveInKeycloak(item: User): Observable<void> {
+  saveInKeycloak(user: User): Observable<void> {
     throw new Error('Method not implemented.');
   }
 
diff --git a/alfa-client/libs/admin/user-shared/test/user.ts b/alfa-client/libs/admin/user-shared/test/user.ts
index 511f24510c38a12b07cd73b74a4a4a895df023c7..680d60824d2cebb018ca1c26b096f8c368d4bbbe 100644
--- a/alfa-client/libs/admin/user-shared/test/user.ts
+++ b/alfa-client/libs/admin/user-shared/test/user.ts
@@ -22,6 +22,7 @@
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
 import { faker } from '@faker-js/faker';
+import { UserAddFormservice } from '../../user/src/lib/users-roles/user-add-form/user-add.formservice';
 import { User } from '../src/lib/user.model';
 
 export function createUser(): User {
@@ -31,7 +32,11 @@ export function createUser(): User {
     firstName: faker.person.firstName(),
     lastName: faker.person.lastName(),
     email: faker.internet.email(),
-    roles: null,
+    enabled: true,
+    clientRoles: {
+      alfa: [UserAddFormservice.POSTSTELLE],
+      admin: [UserAddFormservice.ADMIN],
+    },
     groups: null,
   };
 }
diff --git a/alfa-client/libs/admin/user/src/lib/users-roles/user-add-form/user-add-form.component.html b/alfa-client/libs/admin/user/src/lib/users-roles/user-add-form/user-add-form.component.html
index 915c537c21ae378ea7638bb3891f6fbfaca8eb9a..e95ce249045910cd9c9951d9f4851e905832a883 100644
--- a/alfa-client/libs/admin/user/src/lib/users-roles/user-add-form/user-add-form.component.html
+++ b/alfa-client/libs/admin/user/src/lib/users-roles/user-add-form/user-add-form.component.html
@@ -26,28 +26,30 @@
 <div class="max-w-[960px]" [formGroup]="formService.form">
   <h1 class="heading-1 mb-4">Benutzer anlegen</h1>
   <div class="mb-4 grid gap-4 xl:grid-cols-2">
-    <ods-text-editor [formControlName]="UserAddFormService.VORNAME" label="Vorname" required="true" />
-    <ods-text-editor [formControlName]="UserAddFormService.NACHNAME" label="Nachname" required="true" />
-    <ods-text-editor [formControlName]="UserAddFormService.BENUTZERNAME" label="Benutzername" required="true" />
-    <ods-text-editor [formControlName]="UserAddFormService.EMAIL" label="E-Mail" required="true" />
+    <ods-text-editor [formControlName]="UserAddFormService.VORNAME" [isRequired]="true" label="Vorname"/>
+    <ods-text-editor [formControlName]="UserAddFormService.NACHNAME" [isRequired]="true" label="Nachname"/>
+    <ods-text-editor [formControlName]="UserAddFormService.BENUTZERNAME" [isRequired]="true" label="Benutzername"/>
+    <ods-text-editor [formControlName]="UserAddFormService.EMAIL" [isRequired]="true" label="E-Mail"/>
   </div>
 
   <h3 class="text-md mb-4 block font-medium text-text">Organisationseinheiten</h3>
-  <ods-button-with-spinner text="Organisationseinheit hinzufügen" variant="outline" dataTestId="Add-organisationseinheit-button" />
+  <ods-button-with-spinner text="Organisationseinheit hinzufügen" variant="outline"
+                           dataTestId="Add-organisationseinheit-button"/>
 
   <h2 class="heading-2 mt-4">Rollen für OZG-Cloud</h2>
   <div [formGroupName]="UserAddFormService.ROLLEN_GROUP" class="mb-8 flex gap-56">
     <div [formGroupName]="UserAddFormService.ADMINISTRATION_GROUP" class="flex flex-col gap-2">
       <h3 class="text-md block font-medium text-text">Administration</h3>
-      <ods-checkbox-editor [formControlName]="UserAddFormService.ADMIN" label="Admin" inputId="admin" />
+      <ods-checkbox-editor [formControlName]="UserAddFormService.ADMIN" label="Admin" inputId="admin"/>
     </div>
     <div [formGroupName]="UserAddFormService.ALFA_GROUP" class="flex flex-col gap-2">
       <h3 class="text-md block font-medium text-text">Alfa</h3>
-      <ods-checkbox-editor [formControlName]="UserAddFormService.LOESCHEN" label="Löschen" inputId="delete" />
-      <ods-checkbox-editor [formControlName]="UserAddFormService.USER" label="User" inputId="user" />
-      <ods-checkbox-editor [formControlName]="UserAddFormService.POSTSTELLE" label="Poststelle" inputId="post_office" />
+      <ods-checkbox-editor [formControlName]="UserAddFormService.LOESCHEN" label="Löschen" inputId="delete"/>
+      <ods-checkbox-editor [formControlName]="UserAddFormService.USER" label="User" inputId="user"/>
+      <ods-checkbox-editor [formControlName]="UserAddFormService.POSTSTELLE" label="Poststelle" inputId="post_office"/>
     </div>
   </div>
 
-  <ods-button-with-spinner text="Speichern" dataTestId="save-button" />
+  <ods-button-with-spinner [stateResource]="submitStateResource$ | async" (clickEmitter)="submit()" text="Speichern"
+                           dataTestId="save-button"/>
 </div>
diff --git a/alfa-client/libs/admin/user/src/lib/users-roles/user-add-form/user-add-form.component.spec.ts b/alfa-client/libs/admin/user/src/lib/users-roles/user-add-form/user-add-form.component.spec.ts
index 9e6abab7af6c7ad7633633967240034746c226cb..085cc24dc7a7e2e2bdd84a63287424511d428146 100644
--- a/alfa-client/libs/admin/user/src/lib/users-roles/user-add-form/user-add-form.component.spec.ts
+++ b/alfa-client/libs/admin/user/src/lib/users-roles/user-add-form/user-add-form.component.spec.ts
@@ -21,35 +21,122 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
+import { User, UserService } from '@admin-client/user-shared';
+import { NavigationService } from '@alfa-client/navigation-shared';
+import { createStateResource, StateResource } from '@alfa-client/tech-shared';
+import { dispatchEventFromFixture, getDebugElementFromFixtureByCss, mock, Mock } from '@alfa-client/test-utils';
+import { SnackBarService } from '@alfa-client/ui';
 import { CommonModule } from '@angular/common';
 import { ComponentFixture, TestBed } from '@angular/core/testing';
 import { ReactiveFormsModule } from '@angular/forms';
 import { ButtonWithSpinnerComponent, CheckboxEditorComponent, TextEditorComponent } from '@ods/component';
+import { cold } from 'jest-marbles';
+import { createUser } from 'libs/admin/user-shared/test/user';
 import { MockComponent } from 'ng-mocks';
+import { of } from 'rxjs';
+import { getDataTestIdAttributeOf } from '../../../../../../tech-shared/test/data-test';
 import { UserAddFormComponent } from './user-add-form.component';
+import { UserAddFormservice } from './user-add.formservice';
 
 describe('UserAddFormComponent', () => {
   let component: UserAddFormComponent;
   let fixture: ComponentFixture<UserAddFormComponent>;
 
+  let formService: UserAddFormservice;
+
+  let userService: Mock<UserService>;
+  let navigationService: Mock<NavigationService>;
+  let snackBarService: Mock<SnackBarService>;
+
+  const saveButton: string = getDataTestIdAttributeOf('save-button');
+
   beforeEach(async () => {
+    userService = mock(UserService);
+    navigationService = mock(NavigationService);
+    snackBarService = mock(SnackBarService);
+
     await TestBed.configureTestingModule({
-      imports: [
+      imports: [CommonModule, ReactiveFormsModule],
+      declarations: [
         UserAddFormComponent,
-        CommonModule,
-        ReactiveFormsModule,
         MockComponent(ButtonWithSpinnerComponent),
         MockComponent(TextEditorComponent),
         MockComponent(CheckboxEditorComponent),
       ],
+      providers: [
+        UserAddFormservice,
+        { provide: UserService, useValue: userService },
+        { provide: NavigationService, useValue: navigationService },
+        { provide: SnackBarService, useValue: snackBarService },
+      ],
     }).compileComponents();
 
     fixture = TestBed.createComponent(UserAddFormComponent);
     component = fixture.componentInstance;
+    formService = component.formService;
     fixture.detectChanges();
   });
 
   it('should create', () => {
     expect(component).toBeTruthy();
   });
+
+  describe('component', () => {
+    describe('submit', () => {
+      const userStateResource: StateResource<User> = createStateResource(createUser());
+
+      beforeEach(() => {
+        formService.submit = jest.fn().mockReturnValue(of(userStateResource));
+      });
+
+      it('should call formService submit if form is valid', () => {
+        jest.spyOn(formService.form, 'invalid', 'get').mockReturnValue(false);
+
+        component.submit();
+
+        expect(formService.submit).toHaveBeenCalled();
+      });
+
+      it('should not call formService submit if form is not valid', () => {
+        jest.spyOn(formService.form, 'invalid', 'get').mockReturnValue(true);
+
+        component.submit();
+
+        expect(formService.submit).not.toHaveBeenCalled();
+      });
+
+      it('should set submitState$ if form is valid', () => {
+        jest.spyOn(formService.form, 'invalid', 'get').mockReturnValue(false);
+
+        component.submit();
+
+        expect(component.submitStateResource$).toBeObservable(cold('(a|)', { a: userStateResource }));
+      });
+    });
+  });
+
+  describe('template', () => {
+    describe('ods-button-with-spinner save', () => {
+      describe('input', () => {
+        it('should be set', () => {
+          const stateResource: StateResource<User> = createStateResource(createUser());
+          component.submitStateResource$ = of(stateResource);
+
+          fixture.detectChanges();
+
+          expect(getDebugElementFromFixtureByCss(fixture, saveButton).componentInstance.stateResource).toEqual(stateResource);
+        });
+      });
+
+      describe('output', () => {
+        it('should call submit', () => {
+          const submitSpy: jest.SpyInstance = jest.spyOn(component, 'submit');
+
+          dispatchEventFromFixture(fixture, saveButton, 'clickEmitter');
+
+          expect(submitSpy).toHaveBeenCalled();
+        });
+      });
+    });
+  });
 });
diff --git a/alfa-client/libs/admin/user/src/lib/users-roles/user-add-form/user-add-form.component.ts b/alfa-client/libs/admin/user/src/lib/users-roles/user-add-form/user-add-form.component.ts
index e62729b8f391032dc1e2cc27675251702a794d91..e5df17d9fb3bbf0f95105085e1943d58a13dbab7 100644
--- a/alfa-client/libs/admin/user/src/lib/users-roles/user-add-form/user-add-form.component.ts
+++ b/alfa-client/libs/admin/user/src/lib/users-roles/user-add-form/user-add-form.component.ts
@@ -21,20 +21,39 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
+import { User } from '@admin-client/user-shared';
+import { StateResource } from '@alfa-client/tech-shared';
+import { AsyncPipe } from '@angular/common';
 import { Component, inject } from '@angular/core';
 import { FormsModule, ReactiveFormsModule } from '@angular/forms';
 import { ButtonWithSpinnerComponent, CheckboxEditorComponent, TextEditorComponent } from '@ods/component';
-import { UserAddFormService } from './user-add-form.service';
+import { Observable } from 'rxjs';
+import { UserAddFormservice } from './user-add.formservice';
 
 @Component({
   selector: 'admin-user-add-form',
-  providers: [UserAddFormService],
+  providers: [UserAddFormservice],
   templateUrl: './user-add-form.component.html',
   standalone: true,
-  imports: [FormsModule, ReactiveFormsModule, TextEditorComponent, ButtonWithSpinnerComponent, CheckboxEditorComponent],
+  imports: [
+    FormsModule,
+    ReactiveFormsModule,
+    TextEditorComponent,
+    ButtonWithSpinnerComponent,
+    CheckboxEditorComponent,
+    AsyncPipe,
+  ],
 })
 export class UserAddFormComponent {
-  formService = inject(UserAddFormService);
+  public readonly formService = inject(UserAddFormservice);
 
-  protected readonly UserAddFormService = UserAddFormService;
+  submitStateResource$: Observable<StateResource<User>>;
+
+  protected readonly UserAddFormService = UserAddFormservice;
+
+  public submit(): void {
+    if (!this.formService.form.invalid) {
+      this.submitStateResource$ = this.formService.submit();
+    }
+  }
 }
diff --git a/alfa-client/libs/admin/user/src/lib/users-roles/user-add-form/user-add-form.service.ts b/alfa-client/libs/admin/user/src/lib/users-roles/user-add-form/user-add-form.service.ts
deleted file mode 100644
index 708b66353058db36bc8b913942cf9d50553e6f67..0000000000000000000000000000000000000000
--- a/alfa-client/libs/admin/user/src/lib/users-roles/user-add-form/user-add-form.service.ts
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den
- * Ministerpräsidenten des Landes Schleswig-Holstein
- * Staatskanzlei
- * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
- *
- * Lizenziert unter der EUPL, Version 1.2 oder - sobald
- * diese von der Europäischen Kommission genehmigt wurden -
- * Folgeversionen der EUPL ("Lizenz");
- * Sie dürfen dieses Werk ausschließlich gemäß
- * dieser Lizenz nutzen.
- * Eine Kopie der Lizenz finden Sie hier:
- *
- * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
- *
- * Sofern nicht durch anwendbare Rechtsvorschriften
- * gefordert oder in schriftlicher Form vereinbart, wird
- * die unter der Lizenz verbreitete Software "so wie sie
- * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
- * ausdrücklich oder stillschweigend - verbreitet.
- * Die sprachspezifischen Genehmigungen und Beschränkungen
- * unter der Lizenz sind dem Lizenztext zu entnehmen.
- */
-import { AbstractFormService, EMPTY_STRING, StateResource } from '@alfa-client/tech-shared';
-import { Injectable } from '@angular/core';
-import { AbstractControl, FormControl, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
-import { Resource } from '@ngxp/rest';
-import { Observable } from 'rxjs';
-
-@Injectable()
-export class UserAddFormService extends AbstractFormService {
-  public static readonly VORNAME: string = 'vorname';
-  public static readonly NACHNAME: string = 'nachname';
-  public static readonly BENUTZERNAME: string = 'benutzername';
-  public static readonly EMAIL: string = 'e-mail';
-
-  public static readonly ROLLEN_GROUP: string = 'rollen';
-  public static readonly ADMINISTRATION_GROUP: string = 'administration';
-  public static readonly ADMIN: string = 'admin';
-  public static readonly ALFA_GROUP: string = 'alfa';
-  public static readonly LOESCHEN: string = 'loeschen';
-  public static readonly USER: string = 'user';
-  public static readonly POSTSTELLE: string = 'poststelle';
-
-  public static readonly USER_ADD_PREFIX: string = 'userAdd';
-
-  constructor(public formBuilder: UntypedFormBuilder) {
-    super(formBuilder);
-    this.initAlfaGroupLogic();
-  }
-
-  protected initForm(): UntypedFormGroup {
-    return this.formBuilder.group({
-      [UserAddFormService.VORNAME]: new FormControl(EMPTY_STRING),
-      [UserAddFormService.NACHNAME]: new FormControl(EMPTY_STRING),
-      [UserAddFormService.BENUTZERNAME]: new FormControl(EMPTY_STRING),
-      [UserAddFormService.EMAIL]: new FormControl(EMPTY_STRING),
-      [UserAddFormService.ROLLEN_GROUP]: this.formBuilder.group({
-        [UserAddFormService.ADMINISTRATION_GROUP]: this.formBuilder.group({
-          [UserAddFormService.ADMIN]: new FormControl(false),
-        }),
-        [UserAddFormService.ALFA_GROUP]: this.formBuilder.group({
-          [UserAddFormService.LOESCHEN]: new FormControl(false),
-          [UserAddFormService.USER]: new FormControl(false),
-          [UserAddFormService.POSTSTELLE]: new FormControl(false),
-        }),
-      }),
-    });
-  }
-
-  protected initAlfaGroupLogic(): void {
-    const alfaGroup: UntypedFormGroup = this.getAlfaGroup();
-    alfaGroup.valueChanges.subscribe(() => {
-      this.handleAlfaGroupChange(alfaGroup);
-    });
-  }
-
-  private getAlfaGroup(): UntypedFormGroup {
-    return <UntypedFormGroup>this.form.get(UserAddFormService.ROLLEN_GROUP).get(UserAddFormService.ALFA_GROUP);
-  }
-
-  handleAlfaGroupChange(group: UntypedFormGroup): void {
-    const anyChecked: boolean = this.isAnyChecked(group);
-    if (anyChecked) {
-      this.disableUncheckedCheckboxes(group);
-    } else {
-      this.enableAllCheckboxes(group);
-    }
-  }
-
-  isAnyChecked(group: UntypedFormGroup): boolean {
-    return Object.keys(group.controls).some((key) => group.controls[key].value);
-  }
-
-  disableUncheckedCheckboxes(alfaGroup: UntypedFormGroup): void {
-    for (const control of Object.values<AbstractControl>(alfaGroup.controls)) {
-      if (control.value === false) control.disable({ emitEvent: false });
-    }
-  }
-
-  enableAllCheckboxes(group: UntypedFormGroup): void {
-    for (const control of Object.values<AbstractControl>(group.controls)) {
-      control.enable({ emitEvent: false });
-    }
-  }
-
-  protected doSubmit(): Observable<StateResource<Resource>> {
-    throw new Error('Method not implemented.');
-  }
-
-  protected getPathPrefix(): string {
-    return UserAddFormService.USER_ADD_PREFIX;
-  }
-}
diff --git a/alfa-client/libs/admin/user/src/lib/users-roles/user-add-form/user-add-formservice.spec.ts b/alfa-client/libs/admin/user/src/lib/users-roles/user-add-form/user-add-formservice.spec.ts
deleted file mode 100644
index fef180f7f196639c25f2ab265c343a14d7d64d2e..0000000000000000000000000000000000000000
--- a/alfa-client/libs/admin/user/src/lib/users-roles/user-add-form/user-add-formservice.spec.ts
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den
- * Ministerpräsidenten des Landes Schleswig-Holstein
- * Staatskanzlei
- * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
- *
- * Lizenziert unter der EUPL, Version 1.2 oder - sobald
- * diese von der Europäischen Kommission genehmigt wurden -
- * Folgeversionen der EUPL ("Lizenz");
- * Sie dürfen dieses Werk ausschließlich gemäß
- * dieser Lizenz nutzen.
- * Eine Kopie der Lizenz finden Sie hier:
- *
- * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
- *
- * Sofern nicht durch anwendbare Rechtsvorschriften
- * gefordert oder in schriftlicher Form vereinbart, wird
- * die unter der Lizenz verbreitete Software "so wie sie
- * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
- * ausdrücklich oder stillschweigend - verbreitet.
- * Die sprachspezifischen Genehmigungen und Beschränkungen
- * unter der Lizenz sind dem Lizenztext zu entnehmen.
- */
-import { fakeAsync, TestBed, tick } from '@angular/core/testing';
-import { AbstractControl, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
-import { UserAddFormService } from './user-add-form.service';
-import SpyInstance = jest.SpyInstance;
-
-describe('UserAddFormService', () => {
-  let formService: UserAddFormService;
-  let alfaGroup: UntypedFormGroup;
-
-  beforeEach(() => {
-    TestBed.configureTestingModule({
-      providers: [UserAddFormService, UntypedFormBuilder],
-    });
-
-    formService = TestBed.inject(UserAddFormService);
-    alfaGroup = <UntypedFormGroup>formService.form.get(UserAddFormService.ROLLEN_GROUP).get(UserAddFormService.ALFA_GROUP);
-  });
-
-  it('should create', () => {
-    expect(formService).toBeTruthy();
-  });
-
-  describe('initAlfaGroupLogic', () => {
-    it('should call handleAlfaGroupChange when value of form element changes', fakeAsync(() => {
-      const handleAlfaGroupChangeSpy: SpyInstance = jest.spyOn(formService as any, 'handleAlfaGroupChange');
-
-      alfaGroup.get(UserAddFormService.LOESCHEN).setValue(true);
-
-      tick();
-
-      expect(handleAlfaGroupChangeSpy).toHaveBeenCalled();
-    }));
-  });
-
-  describe('handleAlfaGroupChange', () => {
-    it('should call disableUncheckedCheckboxes if any checkbox is checked', () => {
-      jest.spyOn(formService as any, 'isAnyChecked').mockReturnValue(true);
-      const disableUncheckedCheckboxesSpy: SpyInstance = jest.spyOn(formService as any, 'disableUncheckedCheckboxes');
-
-      formService.handleAlfaGroupChange(alfaGroup);
-
-      expect(disableUncheckedCheckboxesSpy).toHaveBeenCalled();
-    });
-
-    it('should call enableAllCheckboxes if not any checkbox is checked', () => {
-      jest.spyOn(formService as any, 'isAnyChecked').mockReturnValue(false);
-      const enableAllCheckboxesSpy: SpyInstance = jest.spyOn(formService as any, 'enableAllCheckboxes');
-
-      formService.handleAlfaGroupChange(alfaGroup);
-
-      expect(enableAllCheckboxesSpy).toHaveBeenCalled();
-    });
-  });
-
-  describe('isAnyChecked', () => {
-    it('should return false if no checkbox is checked', () => {
-      const result = formService.isAnyChecked(alfaGroup);
-
-      expect(result).toBe(false);
-    });
-
-    it('should return true if any checkbox is checked', () => {
-      alfaGroup.get(UserAddFormService.LOESCHEN).setValue(true);
-
-      const result = formService.isAnyChecked(alfaGroup);
-
-      expect(result).toBe(true);
-    });
-  });
-
-  describe('disableUncheckedCheckboxes', () => {
-    it('if control value is false then control should be disabled', () => {
-      const control: AbstractControl = alfaGroup.get(UserAddFormService.LOESCHEN);
-      control.setValue(false);
-
-      formService.disableUncheckedCheckboxes(alfaGroup);
-
-      expect(control.disabled).toBe(true);
-    });
-
-    it('if control value is true then control should NOT be disabled', () => {
-      const control: AbstractControl = alfaGroup.get(UserAddFormService.LOESCHEN);
-      control.setValue(true);
-
-      formService.disableUncheckedCheckboxes(alfaGroup);
-
-      expect(control.disabled).toBe(false);
-    });
-  });
-
-  describe('updateCheckboxStates', () => {
-    it('if control value is false then control should be disabled', () => {
-      const control: AbstractControl = alfaGroup.get(UserAddFormService.LOESCHEN);
-      control.setValue(false);
-
-      formService.disableUncheckedCheckboxes(alfaGroup);
-
-      expect(control.disabled).toBe(true);
-    });
-  });
-
-  describe('enableAllCheckboxes', () => {
-    it('if control value is true then control should be enabled', () => {
-      const control: AbstractControl = alfaGroup.get(UserAddFormService.LOESCHEN);
-      const enableSpy = jest.spyOn(control, 'enable');
-
-      formService.enableAllCheckboxes(alfaGroup);
-
-      expect(enableSpy).toHaveBeenCalled();
-    });
-  });
-});
diff --git a/alfa-client/libs/admin/user/src/lib/users-roles/user-add-form/user-add.formservice.spec.ts b/alfa-client/libs/admin/user/src/lib/users-roles/user-add-form/user-add.formservice.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..93b68bb79ea62249b7864cd63bc3f5d706e0dfcf
--- /dev/null
+++ b/alfa-client/libs/admin/user/src/lib/users-roles/user-add-form/user-add.formservice.spec.ts
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den
+ * Ministerpräsidenten des Landes Schleswig-Holstein
+ * Staatskanzlei
+ * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+ *
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+import { ROUTES } from '@admin-client/shared';
+import { User, UserService } from '@admin-client/user-shared';
+import { NavigationService } from '@alfa-client/navigation-shared';
+import { createEmptyStateResource, createStateResource } from '@alfa-client/tech-shared';
+import { Mock, mock } from '@alfa-client/test-utils';
+import { SnackBarService } from '@alfa-client/ui';
+import { fakeAsync, TestBed, tick } from '@angular/core/testing';
+import { AbstractControl, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
+import { cold } from 'jest-marbles';
+import { createUser } from 'libs/admin/user-shared/test/user';
+import { singleCold } from 'libs/tech-shared/test/marbles';
+import { of, throwError } from 'rxjs';
+import { UserAddFormservice } from './user-add.formservice';
+import SpyInstance = jest.SpyInstance;
+
+describe('UserAddFormService', () => {
+  let formService: UserAddFormservice;
+  let roleGroup: UntypedFormGroup;
+  let alfaGroup: UntypedFormGroup;
+  let administrationGroup: UntypedFormGroup;
+
+  let userService: Mock<UserService>;
+  let navigationService: Mock<NavigationService>;
+  let snackBarService: Mock<SnackBarService>;
+
+  beforeEach(() => {
+    userService = { ...mock(UserService), refresh: jest.fn() };
+    navigationService = mock(NavigationService);
+    snackBarService = mock(SnackBarService);
+
+    TestBed.configureTestingModule({
+      providers: [
+        UserAddFormservice,
+        UntypedFormBuilder,
+        { provide: UserService, useValue: userService },
+        { provide: NavigationService, useValue: navigationService },
+        { provide: SnackBarService, useValue: snackBarService },
+      ],
+    });
+
+    formService = TestBed.inject(UserAddFormservice);
+    roleGroup = <UntypedFormGroup>formService.form.get(UserAddFormservice.ROLLEN_GROUP);
+    alfaGroup = <UntypedFormGroup>roleGroup.get(UserAddFormservice.ALFA_GROUP);
+    administrationGroup = <UntypedFormGroup>roleGroup.get(UserAddFormservice.ADMINISTRATION_GROUP);
+  });
+
+  it('should create', () => {
+    expect(formService).toBeTruthy();
+  });
+
+  describe('initAlfaGroupLogic', () => {
+    it('should call handleAlfaGroupChange when value of form element changes', fakeAsync(() => {
+      const handleAlfaGroupChangeSpy: SpyInstance = jest.spyOn(formService as any, 'handleAlfaGroupChange');
+
+      alfaGroup.get(UserAddFormservice.LOESCHEN).setValue(true);
+
+      tick();
+
+      expect(handleAlfaGroupChangeSpy).toHaveBeenCalled();
+    }));
+  });
+
+  describe('roleValidator', () => {
+    it('should return error if no role is selected', () => {
+      const result = formService.roleValidator()(roleGroup);
+
+      expect(result).toEqual({ atLeastOneRoleSelected: true });
+    });
+
+    it('should return null if at least one role is selected', () => {
+      alfaGroup.get(UserAddFormservice.LOESCHEN).setValue(true);
+
+      const result = formService.roleValidator()(roleGroup);
+
+      expect(result).toBeNull();
+    });
+  });
+
+  describe('handleAlfaGroupChange', () => {
+    it('should call disableUncheckedCheckboxes if any checkbox is checked', () => {
+      jest.spyOn(formService as any, 'isAnyChecked').mockReturnValue(true);
+      const disableUncheckedCheckboxesSpy: SpyInstance = jest.spyOn(formService as any, 'disableUncheckedCheckboxes');
+
+      formService.handleAlfaGroupChange(alfaGroup);
+
+      expect(disableUncheckedCheckboxesSpy).toHaveBeenCalled();
+    });
+
+    it('should call enableAllCheckboxes if not any checkbox is checked', () => {
+      jest.spyOn(formService as any, 'isAnyChecked').mockReturnValue(false);
+      const enableAllCheckboxesSpy: SpyInstance = jest.spyOn(formService as any, 'enableAllCheckboxes');
+
+      formService.handleAlfaGroupChange(alfaGroup);
+
+      expect(enableAllCheckboxesSpy).toHaveBeenCalled();
+    });
+  });
+
+  describe('isAnyChecked', () => {
+    it('should return false if no checkbox is checked', () => {
+      const result = formService.isAnyChecked(alfaGroup);
+
+      expect(result).toBe(false);
+    });
+
+    it('should return true if any checkbox is checked', () => {
+      alfaGroup.get(UserAddFormservice.LOESCHEN).setValue(true);
+
+      const result = formService.isAnyChecked(alfaGroup);
+
+      expect(result).toBe(true);
+    });
+  });
+
+  describe('disableUncheckedCheckboxes', () => {
+    it('if control value is false then control should be disabled', () => {
+      const control: AbstractControl = alfaGroup.get(UserAddFormservice.LOESCHEN);
+      control.setValue(false);
+
+      formService.disableUncheckedCheckboxes(alfaGroup);
+
+      expect(control.disabled).toBe(true);
+    });
+
+    it('if control value is true then control should NOT be disabled', () => {
+      const control: AbstractControl = alfaGroup.get(UserAddFormservice.LOESCHEN);
+      control.setValue(true);
+
+      formService.disableUncheckedCheckboxes(alfaGroup);
+
+      expect(control.disabled).toBe(false);
+    });
+  });
+
+  describe('updateCheckboxStates', () => {
+    it('if control value is false then control should be disabled', () => {
+      const control: AbstractControl = alfaGroup.get(UserAddFormservice.LOESCHEN);
+      control.setValue(false);
+
+      formService.disableUncheckedCheckboxes(alfaGroup);
+
+      expect(control.disabled).toBe(true);
+    });
+  });
+
+  describe('enableAllCheckboxes', () => {
+    it('if control value is true then control should be enabled', () => {
+      const control: AbstractControl = alfaGroup.get(UserAddFormservice.LOESCHEN);
+      const enableSpy = jest.spyOn(control, 'enable');
+
+      formService.enableAllCheckboxes(alfaGroup);
+
+      expect(enableSpy).toHaveBeenCalled();
+    });
+  });
+
+  describe('doSubmit', () => {
+    const user: User = createUser();
+
+    beforeEach(() => {
+      userService.createInKeycloak.mockReturnValue(of(user));
+    });
+
+    it('should call createUser', () => {
+      const createUserSpy: SpyInstance = jest.spyOn(formService as any, 'createUser');
+
+      formService.submit();
+
+      expect(createUserSpy).toHaveBeenCalled();
+    });
+
+    it('should call userService createInKeycloak', () => {
+      formService.submit();
+
+      expect(userService.createInKeycloak).toHaveBeenCalled();
+    });
+
+    it('should return user as stateResource', fakeAsync(() => {
+      userService.createInKeycloak.mockReturnValue(singleCold(user, '-a'));
+
+      const result = formService.submit();
+
+      expect(result).toBeObservable(
+        cold('ab', {
+          a: createEmptyStateResource<User>(true),
+          b: createStateResource(user),
+        }),
+      );
+    }));
+
+    it('should call handleOnCreateUserSuccess', fakeAsync(() => {
+      const handleOnCreateUserSuccessSpy: SpyInstance = jest.spyOn(formService, 'handleOnCreateUserSuccess');
+
+      formService.submit().subscribe();
+      tick();
+
+      expect(handleOnCreateUserSuccessSpy).toHaveBeenCalled();
+    }));
+
+    it('should call handleSubmitError on error', fakeAsync(() => {
+      userService.createInKeycloak.mockReturnValue(throwError(() => new Error()));
+      const handleSubmitErrorSpy: SpyInstance = jest.spyOn(formService, 'handleSubmitError');
+
+      formService.submit().subscribe();
+      tick();
+
+      expect(handleSubmitErrorSpy).toHaveBeenCalled();
+    }));
+  });
+
+  describe('handleOnCreateUserSuccess', () => {
+    it('should show success message', () => {
+      formService.handleOnCreateUserSuccess();
+
+      expect(snackBarService.showInfo).toHaveBeenCalledWith('Der Benutzer wurde hinzugefügt.');
+    });
+
+    it('should navigate back to user list', () => {
+      formService.handleOnCreateUserSuccess();
+
+      expect(navigationService.navigate).toHaveBeenCalledWith(ROUTES.BENUTZER_UND_ROLLEN);
+    });
+
+    it('should refresh userList', () => {
+      formService.handleOnCreateUserSuccess();
+
+      expect(userService.refresh).toHaveBeenCalled();
+    });
+  });
+
+  describe('handleSubmitError', () => {
+    it('should return empty stateResource', () => {
+      const result = formService.handleSubmitError();
+
+      expect(result).toBeObservable(cold('(a|)', { a: createEmptyStateResource<User>() }));
+    });
+
+    it('should show error message', fakeAsync(() => {
+      formService.handleSubmitError().subscribe();
+      tick();
+
+      expect(snackBarService.showError).toHaveBeenCalledWith('Der Benutzer konnte nicht hinzugefügt werden.');
+    }));
+  });
+
+  describe('getRoles', () => {
+    it('should return no roles when none are active', () => {
+      const result: string[] = formService.getRoles(UserAddFormservice.ALFA_GROUP);
+
+      expect(result).toEqual([]);
+    });
+
+    it('should return poststelle role when active', () => {
+      alfaGroup.get(UserAddFormservice.POSTSTELLE).setValue(true);
+
+      const result: string[] = formService.getRoles(UserAddFormservice.ALFA_GROUP);
+
+      expect(result).toEqual([UserAddFormservice.POSTSTELLE]);
+    });
+  });
+});
diff --git a/alfa-client/libs/admin/user/src/lib/users-roles/user-add-form/user-add.formservice.ts b/alfa-client/libs/admin/user/src/lib/users-roles/user-add-form/user-add.formservice.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5a6769f495ca2e04048c715bd878959a94486395
--- /dev/null
+++ b/alfa-client/libs/admin/user/src/lib/users-roles/user-add-form/user-add.formservice.ts
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den
+ * Ministerpräsidenten des Landes Schleswig-Holstein
+ * Staatskanzlei
+ * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+ *
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+import { ROUTES } from '@admin-client/shared';
+import { User, UserService } from '@admin-client/user-shared';
+import { NavigationService } from '@alfa-client/navigation-shared';
+import {
+  AbstractFormService,
+  createEmptyStateResource,
+  createStateResource,
+  EMPTY_STRING,
+  StateResource,
+} from '@alfa-client/tech-shared';
+import { SnackBarService } from '@alfa-client/ui';
+import { Injectable } from '@angular/core';
+import {
+  AbstractControl,
+  FormControl,
+  UntypedFormBuilder,
+  UntypedFormGroup,
+  ValidationErrors,
+  ValidatorFn,
+  Validators,
+} from '@angular/forms';
+import { catchError, map, Observable, of, startWith, tap } from 'rxjs';
+
+@Injectable()
+export class UserAddFormservice extends AbstractFormService<User> {
+  public static readonly VORNAME: string = 'vorname';
+  public static readonly NACHNAME: string = 'nachname';
+  public static readonly BENUTZERNAME: string = 'benutzername';
+  public static readonly EMAIL: string = 'e-mail';
+
+  public static readonly ROLLEN_GROUP: string = 'rollen';
+  public static readonly ADMINISTRATION_GROUP: string = 'administration';
+  public static readonly ADMIN: string = 'ADMIN_ADMIN';
+  public static readonly ALFA_GROUP: string = 'alfa';
+  public static readonly LOESCHEN: string = 'VERWALTUNG_LOESCHEN';
+  public static readonly USER: string = 'VERWALTUNG_USER';
+  public static readonly POSTSTELLE: string = 'VERWALTUNG_POSTSTELLE';
+
+  public static readonly USER_ADD_PREFIX: string = 'userAdd';
+
+  constructor(
+    public formBuilder: UntypedFormBuilder,
+    private userService: UserService,
+    private navigationService: NavigationService,
+    private snackBarService: SnackBarService,
+  ) {
+    super(formBuilder);
+    this.initAlfaGroupLogic();
+  }
+
+  protected initForm(): UntypedFormGroup {
+    return this.formBuilder.group({
+      [UserAddFormservice.VORNAME]: new FormControl(EMPTY_STRING, Validators.required),
+      [UserAddFormservice.NACHNAME]: new FormControl(EMPTY_STRING, Validators.required),
+      [UserAddFormservice.BENUTZERNAME]: new FormControl(EMPTY_STRING, Validators.required),
+      [UserAddFormservice.EMAIL]: new FormControl(EMPTY_STRING, [Validators.required, Validators.email]),
+      [UserAddFormservice.ROLLEN_GROUP]: this.formBuilder.group(
+        {
+          [UserAddFormservice.ADMINISTRATION_GROUP]: this.formBuilder.group({
+            [UserAddFormservice.ADMIN]: new FormControl(false),
+          }),
+          [UserAddFormservice.ALFA_GROUP]: this.formBuilder.group({
+            [UserAddFormservice.LOESCHEN]: new FormControl(false),
+            [UserAddFormservice.USER]: new FormControl(false),
+            [UserAddFormservice.POSTSTELLE]: new FormControl(false),
+          }),
+        },
+        { validators: this.roleValidator() },
+      ),
+    });
+  }
+
+  roleValidator(): ValidatorFn {
+    return (control: AbstractControl<UntypedFormGroup>): ValidationErrors | null => {
+      const rolesGroups: UntypedFormGroup = control.value;
+
+      if (this.anyRoleSelected(rolesGroups)) {
+        return null;
+      }
+
+      return { atLeastOneRoleSelected: true };
+    };
+  }
+
+  private anyRoleSelected(rolesGroups: UntypedFormGroup): boolean {
+    for (const subGroup of Object.values(rolesGroups)) {
+      if (Object.values(subGroup).includes(true)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  protected initAlfaGroupLogic(): void {
+    const alfaGroup: UntypedFormGroup = this.getRoleGroup(UserAddFormservice.ALFA_GROUP);
+    alfaGroup.valueChanges.subscribe(() => {
+      this.handleAlfaGroupChange(alfaGroup);
+    });
+  }
+
+  handleAlfaGroupChange(group: UntypedFormGroup): void {
+    const anyChecked: boolean = this.isAnyChecked(group);
+    if (anyChecked) {
+      this.disableUncheckedCheckboxes(group);
+    } else {
+      this.enableAllCheckboxes(group);
+    }
+  }
+
+  isAnyChecked(group: UntypedFormGroup): boolean {
+    return Object.keys(group.controls).some((key) => group.controls[key].value);
+  }
+
+  disableUncheckedCheckboxes(alfaGroup: UntypedFormGroup): void {
+    for (const control of Object.values<AbstractControl>(alfaGroup.controls)) {
+      if (control.value === false) control.disable({ emitEvent: false });
+    }
+  }
+
+  enableAllCheckboxes(group: UntypedFormGroup): void {
+    for (const control of Object.values<AbstractControl>(group.controls)) {
+      control.enable({ emitEvent: false });
+    }
+  }
+
+  protected doSubmit(): Observable<StateResource<User>> {
+    const user: Partial<User> = this.createUser();
+    return this.userService.createInKeycloak(user).pipe(
+      map((createdUser: User): StateResource<User> => createStateResource(createdUser)),
+      tap(() => this.handleOnCreateUserSuccess()),
+      catchError((): Observable<StateResource<User>> => this.handleSubmitError()),
+      startWith(createEmptyStateResource<User>(true)),
+    );
+  }
+
+  handleOnCreateUserSuccess(): void {
+    this.snackBarService.showInfo('Der Benutzer wurde hinzugefügt.');
+    this.navigationService.navigate(ROUTES.BENUTZER_UND_ROLLEN);
+    this.userService.refresh();
+  }
+
+  handleSubmitError(): Observable<StateResource<User>> {
+    this.snackBarService.showError('Der Benutzer konnte nicht hinzugefügt werden.');
+    return of(createEmptyStateResource<User>());
+  }
+
+  createUser(): Partial<User> {
+    return {
+      email: this.form.get(UserAddFormservice.EMAIL).value,
+      username: this.form.get(UserAddFormservice.BENUTZERNAME).value,
+      firstName: this.form.get(UserAddFormservice.VORNAME).value,
+      lastName: this.form.get(UserAddFormservice.NACHNAME).value,
+      enabled: true,
+      clientRoles: {
+        alfa: this.getRoles(UserAddFormservice.ALFA_GROUP),
+        admin: this.getRoles(UserAddFormservice.ADMINISTRATION_GROUP),
+      },
+    };
+  }
+
+  getRoles(roleGroup: string): string[] {
+    return this.getActiveRoles(this.getRoleGroup(roleGroup));
+  }
+
+  private getActiveRoles(formGroup: UntypedFormGroup): string[] {
+    return Object.keys(formGroup.controls).filter((key) => formGroup.get(key).value);
+  }
+
+  private getRoleGroup(roleGroup: string): UntypedFormGroup {
+    return <UntypedFormGroup>this.form.get(UserAddFormservice.ROLLEN_GROUP).get(roleGroup);
+  }
+
+  protected getPathPrefix(): string {
+    return UserAddFormservice.USER_ADD_PREFIX;
+  }
+}
diff --git a/alfa-client/libs/admin/user/src/lib/users-roles/users-roles.component.html b/alfa-client/libs/admin/user/src/lib/users-roles/users-roles.component.html
index a6c6bab29fd949acc9456e737c89e9288ebadff4..4fb48e8cbc912f251454cf28d5e7a05109b93384 100644
--- a/alfa-client/libs/admin/user/src/lib/users-roles/users-roles.component.html
+++ b/alfa-client/libs/admin/user/src/lib/users-roles/users-roles.component.html
@@ -38,7 +38,7 @@
         <dl class="flex flex-wrap gap-2">
           <dt class="sr-only">Rollen:</dt>
           <dd
-            *ngFor="let role of user.roles"
+            *ngFor="let role of getRoles(user)"
             class="inline-flex flex-shrink-0 items-center rounded-full bg-green-50 px-1.5 py-0.5 text-sm font-medium text-green-700 ring-1 ring-inset ring-green-600/20"
           >
             {{ role }}
diff --git a/alfa-client/libs/admin/user/src/lib/users-roles/users-roles.component.spec.ts b/alfa-client/libs/admin/user/src/lib/users-roles/users-roles.component.spec.ts
index 4f8219c95ede01238172d6191c53b42a587a78c5..8532424baa0925e4b9fa9b71525382b98edb8e0c 100644
--- a/alfa-client/libs/admin/user/src/lib/users-roles/users-roles.component.spec.ts
+++ b/alfa-client/libs/admin/user/src/lib/users-roles/users-roles.component.spec.ts
@@ -85,6 +85,15 @@ describe('UsersRolesComponent', () => {
         expect(routerSpy).toHaveBeenCalledWith([ROUTES.BENUTZER_UND_ROLLEN_NEU]);
       });
     });
+
+    describe('getRoles', () => {
+      it('should return roles', () => {
+        const user = createUser();
+        const roles = component.getRoles(user);
+
+        expect(roles).toEqual([...user.clientRoles.alfa, ...user.clientRoles.admin]);
+      });
+    });
   });
 
   describe('template', () => {
diff --git a/alfa-client/libs/admin/user/src/lib/users-roles/users-roles.component.ts b/alfa-client/libs/admin/user/src/lib/users-roles/users-roles.component.ts
index 16e5dad34bd2ab5fb2af1dfa5d0bae9ddff7cc04..027e57aec2f26b7d10a359a306678c6fc36000c6 100644
--- a/alfa-client/libs/admin/user/src/lib/users-roles/users-roles.component.ts
+++ b/alfa-client/libs/admin/user/src/lib/users-roles/users-roles.component.ts
@@ -50,13 +50,20 @@ export class UsersRolesComponent implements OnInit {
   private userService = inject(UserService);
 
   public users$: Observable<StateResource<User[]>>;
-  public readonly GROUPS_TO_DISPLAY = 3;
+  public readonly GROUPS_TO_DISPLAY: number = 3;
 
   ngOnInit() {
     this.users$ = this.userService.get();
   }
 
-  navigateToAddUser(): void {
+  public navigateToAddUser(): void {
     this.router.navigate([ROUTES.BENUTZER_UND_ROLLEN_NEU]);
   }
+
+  getRoles(user: User): string[] {
+    return Object.keys(user.clientRoles).reduce((acc: string[], client: string): string[] => {
+      acc.push(...user.clientRoles[client]);
+      return acc;
+    }, []);
+  }
 }
diff --git a/alfa-client/libs/api-root-shared/src/lib/api-root.linkrel.ts b/alfa-client/libs/api-root-shared/src/lib/api-root.linkrel.ts
index 4e39dc6551fae399b2557a29e47c88b329fc6a39..8628c7d5a2ad48b0e493e132d66c77ff3d8970b9 100644
--- a/alfa-client/libs/api-root-shared/src/lib/api-root.linkrel.ts
+++ b/alfa-client/libs/api-root-shared/src/lib/api-root.linkrel.ts
@@ -62,4 +62,5 @@ export enum ApiRootLinkRel {
   HINTS = 'hints',
   RESOURCE = 'resource',
   ORGANISATIONS_EINHEIT = 'organisationsEinheiten',
+  USERS = 'users',
 }
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 bd176bb9141d31dce01662b6431a1222be6a2506..486415f425de82475e9733ec3f5800cb47128c92 100644
--- a/alfa-client/libs/authentication/src/lib/authentication.service.spec.ts
+++ b/alfa-client/libs/authentication/src/lib/authentication.service.spec.ts
@@ -23,30 +23,39 @@
  */
 import { Mock, mock, useFromMock } from '@alfa-client/test-utils';
 import { UserProfileResource } from '@alfa-client/user-profile-shared';
+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 { AuthConfig, OAuthService } from 'angular-oauth2-oidc';
-import { AuthenticationService } from './authentication.service';
-import { createAuthConfig } from '../../test/authentication';
+import { Subject } from 'rxjs';
 import { createEnvironment } from '../../../environment-shared/test/environment';
-import { Environment } from 'libs/environment-shared/src/lib/environment.model';
+import { createAuthConfig, createOAuthEvent } from '../../test/authentication';
+import { AuthenticationService } from './authentication.service';
 
 describe('AuthenticationService', () => {
   let service: AuthenticationService;
   let oAuthService: Mock<OAuthService>;
   let environmentConfig: Environment;
 
+  let eventsSubject: Subject<OAuthEvent>;
+
   beforeEach(() => {
+    eventsSubject = new Subject<OAuthEvent>();
+
     oAuthService = <any>{
       ...mock(OAuthService),
       loadDiscoveryDocumentAndLogin: jest.fn().mockResolvedValue(() => Promise.resolve()),
+      hasValidAccessToken: jest.fn(),
+      hasValidIdToken: jest.fn(),
     };
+    Object.defineProperty(oAuthService, 'events', { get: () => eventsSubject });
+
     environmentConfig = createEnvironment();
     service = new AuthenticationService(useFromMock(oAuthService), environmentConfig);
   });
 
   describe('login', () => {
     beforeEach(() => {
-      service.setCurrentUser = jest.fn();
+      service.buildAuthEventPromise = jest.fn();
     });
 
     it('should configure service with authConfig', async () => {
@@ -72,16 +81,227 @@ describe('AuthenticationService', () => {
       expect(oAuthService.tokenValidationHandler).not.toBeNull();
     });
 
+    it('should build auth event promise', async () => {
+      service.buildAuthEventPromise = jest.fn().mockResolvedValue(() => Promise.resolve());
+
+      await service.login();
+
+      expect(service.buildAuthEventPromise).toHaveBeenCalled();
+    });
+
     it('should load discovery document and login', () => {
       service.login();
 
       expect(oAuthService.loadDiscoveryDocumentAndLogin).toHaveBeenCalled();
     });
 
-    it('should set current user', async () => {
-      await service.login();
+    it('should return eventPromise', async () => {
+      const promise: Promise<void> = Promise.resolve();
+      service.buildAuthEventPromise = jest.fn().mockResolvedValue(promise);
+
+      const returnPromise: Promise<void> = service.login();
+
+      await expect(returnPromise).resolves.toBeUndefined();
+    });
+  });
+
+  describe('build auth event promise', () => {
+    const event: OAuthEvent = createOAuthEvent();
+
+    beforeEach(() => {
+      service.shouldProceedByAuthEvent = jest.fn().mockReturnValue(true);
+      service.setCurrentUser = jest.fn();
+      service.unsubscribeEvents = jest.fn();
+    });
+
+    it('should call shouldProceedByAuthEvent on event trigger', () => {
+      service.buildAuthEventPromise();
+      eventsSubject.next(event);
+
+      expect(service.shouldProceedByAuthEvent).toHaveBeenCalledWith(event);
+    });
+
+    describe('on next', () => {
+      it('should set current user', () => {
+        service.buildAuthEventPromise();
+        eventsSubject.next(event);
+
+        expect(service.setCurrentUser).toHaveBeenCalled();
+      });
+
+      it('should unsubscribe event', () => {
+        service.buildAuthEventPromise();
+        eventsSubject.next(event);
+
+        expect(service.unsubscribeEvents).toHaveBeenCalled();
+      });
+
+      it('should resolved promise with a valid event', async () => {
+        const promise: Promise<void> = service.buildAuthEventPromise();
+        eventsSubject.next(event);
+
+        await expect(promise).resolves.toBeUndefined();
+      });
+    });
+
+    describe('on error', () => {
+      const errorMessage: string = 'Test Error';
+      const error: Error = new Error(errorMessage);
+
+      it('should unsubscribe event', () => {
+        service.buildAuthEventPromise();
+        eventsSubject.error(error);
+
+        expect(service.unsubscribeEvents).toHaveBeenCalled();
+      });
+
+      it('should reject the promise with an error', async () => {
+        const promise: Promise<void> = service.buildAuthEventPromise();
+
+        eventsSubject.error(error);
+
+        await expect(promise).rejects.toThrow(errorMessage);
+      });
+    });
+  });
+
+  describe('should proceed by auth event', () => {
+    const event: OAuthEvent = createOAuthEvent();
+
+    it('should call considered as login event', () => {
+      service.consideredAsLoginEvent = jest.fn();
+
+      service.shouldProceedByAuthEvent(event);
+
+      expect(service.consideredAsLoginEvent).toHaveBeenCalledWith(event.type);
+    });
+
+    it('should return true on login event', () => {
+      service.consideredAsLoginEvent = jest.fn().mockReturnValue(true);
+
+      const proceed: boolean = service.shouldProceedByAuthEvent(event);
+
+      expect(proceed).toBeTruthy();
+    });
+
+    it('should call considered as page reload event', () => {
+      service.consideredAsLoginEvent = jest.fn().mockReturnValue(false);
+      service.consideredAsPageReloadEvent = jest.fn();
+
+      service.shouldProceedByAuthEvent(event);
+
+      expect(service.consideredAsPageReloadEvent).toHaveBeenCalledWith(event.type);
+    });
+
+    it('should return true on page reload event', () => {
+      service.consideredAsLoginEvent = jest.fn().mockReturnValue(false);
+      service.consideredAsPageReloadEvent = jest.fn().mockReturnValue(true);
+
+      const proceed: boolean = service.shouldProceedByAuthEvent(event);
+
+      expect(proceed).toBeTruthy();
+    });
+
+    it('should return false on non login or page reload event', () => {
+      service.consideredAsLoginEvent = jest.fn().mockReturnValue(false);
+      service.consideredAsPageReloadEvent = jest.fn().mockReturnValue(false);
+
+      const proceed: boolean = service.shouldProceedByAuthEvent(event);
+
+      expect(proceed).toBeFalsy();
+    });
+  });
+
+  describe('consideredAsLoginEvent', () => {
+    it('should return true if event is "token_received"', () => {
+      const event: string = 'token_received';
+
+      const result: boolean = service.consideredAsLoginEvent(event);
+
+      expect(result).toBeTruthy();
+    });
+
+    it('should return false if event is not "token_received"', () => {
+      const event: string = 'something_else';
+
+      const result: boolean = service.consideredAsLoginEvent(event);
+
+      expect(result).toBeFalsy();
+    });
+  });
+
+  describe('consideredAsPageReloadEvent', () => {
+    it('should return true if event is "discovery_document_loaded" and tokens are valid', () => {
+      service.hasValidToken = jest.fn().mockReturnValue(true);
+      const event: string = 'discovery_document_loaded';
+
+      const result: boolean = service.consideredAsPageReloadEvent(event);
+
+      expect(result).toBeTruthy();
+    });
+
+    it('should return false if event is "discovery_document_loaded" and tokens are invalid', () => {
+      service.hasValidToken = jest.fn().mockReturnValue(false);
+      const event: string = 'discovery_document_loaded';
+
+      const result: boolean = service.consideredAsPageReloadEvent(event);
+
+      expect(result).toBeFalsy();
+    });
+
+    it('should return false if event is not "discovery_document_loaded" and tokens are valid', () => {
+      service.hasValidToken = jest.fn().mockReturnValue(true);
+      const event: string = 'something_else';
+
+      const result: boolean = service.consideredAsPageReloadEvent(event);
+
+      expect(result).toBeFalsy();
+    });
+
+    it('should return false if event is not "discovery_document_loaded" and tokens are invalid', () => {
+      service.hasValidToken = jest.fn().mockReturnValue(false);
+      const event: string = 'something_else';
+
+      const result: boolean = service.consideredAsPageReloadEvent(event);
+
+      expect(result).toBeFalsy();
+    });
+  });
+
+  describe('hasValidToken', () => {
+    it('should return true if both tokens are valid', () => {
+      oAuthService.hasValidAccessToken.mockReturnValue(true);
+      oAuthService.hasValidIdToken.mockReturnValue(true);
+
+      const result: boolean = service.hasValidToken();
+
+      expect(result).toBeTruthy();
+    });
+
+    it('should return false if access token is invalid', () => {
+      oAuthService.hasValidAccessToken.mockReturnValue(false);
+
+      const result: boolean = service.hasValidToken();
+
+      expect(result).toBeFalsy();
+    });
+
+    it('should return false if id token is invalid', () => {
+      oAuthService.hasValidAccessToken.mockReturnValue(true);
+      oAuthService.hasValidIdToken.mockReturnValue(false);
+
+      const result: boolean = service.hasValidToken();
+
+      expect(result).toBeFalsy();
+    });
+
+    it('should return false if both tokens are invalid', () => {
+      oAuthService.hasValidAccessToken.mockReturnValue(false);
+      oAuthService.hasValidIdToken.mockReturnValue(false);
+
+      const result: boolean = service.hasValidToken();
 
-      expect(service.setCurrentUser).toHaveBeenCalled();
+      expect(result).toBeFalsy();
     });
   });
 
diff --git a/alfa-client/libs/authentication/src/lib/authentication.service.ts b/alfa-client/libs/authentication/src/lib/authentication.service.ts
index 9b094a2ba2b953f715c8389735f6f40e21196ffd..e350dcafe7cb9312799db97db5eb50c0d25c8319 100644
--- a/alfa-client/libs/authentication/src/lib/authentication.service.ts
+++ b/alfa-client/libs/authentication/src/lib/authentication.service.ts
@@ -23,15 +23,18 @@
  */
 import { Environment, ENVIRONMENT_CONFIG } from '@alfa-client/environment-shared';
 import { Inject, Injectable } from '@angular/core';
-import { AuthConfig, OAuthService } from 'angular-oauth2-oidc';
+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';
 
 @Injectable({ providedIn: 'root' })
 export class AuthenticationService {
   currentUserResource: UserProfileResource;
 
+  private eventSubscription: Subscription;
+
   constructor(
     private oAuthService: OAuthService,
     @Inject(ENVIRONMENT_CONFIG) private envConfig: Environment,
@@ -41,18 +44,52 @@ export class AuthenticationService {
     this.oAuthService.configure(this.buildConfiguration());
     this.oAuthService.setupAutomaticSilentRefresh();
     this.oAuthService.tokenValidationHandler = new JwksValidationHandler();
+
+    const eventPromise: Promise<void> = this.buildAuthEventPromise();
     await this.oAuthService.loadDiscoveryDocumentAndLogin();
-    this.setCurrentUser();
+    return eventPromise;
+  }
+
+  buildAuthEventPromise(): Promise<void> {
+    return new Promise<void>((resolve, reject) => this.handleAuthEventsForPromise(resolve, reject));
+  }
+
+  private handleAuthEventsForPromise(resolve: (value: void | PromiseLike<void>) => void, reject: (reason?: any) => void): void {
+    this.eventSubscription = this.oAuthService.events
+      .pipe(filter((event: OAuthEvent) => this.shouldProceedByAuthEvent(event)))
+      .subscribe({
+        next: () => {
+          this.setCurrentUser();
+          this.unsubscribeEvents();
+          resolve();
+        },
+        error: (error: any) => {
+          this.unsubscribeEvents();
+          reject(error);
+        },
+      });
+  }
+
+  shouldProceedByAuthEvent(event: OAuthEvent): boolean {
+    return this.consideredAsLoginEvent(event.type) || this.consideredAsPageReloadEvent(event.type);
+  }
+
+  consideredAsLoginEvent(eventType: string): boolean {
+    return eventType === 'token_received';
+  }
+
+  consideredAsPageReloadEvent(eventType: string): boolean {
+    return eventType === 'discovery_document_loaded' && this.hasValidToken();
+  }
+
+  hasValidToken(): boolean {
+    return this.oAuthService.hasValidAccessToken() && this.oAuthService.hasValidIdToken();
   }
 
   buildConfiguration(): AuthConfig {
     return {
       issuer: this.envConfig.authServer + '/realms/' + this.envConfig.realm,
-      tokenEndpoint:
-        this.envConfig.authServer +
-        '/realms/' +
-        this.envConfig.realm +
-        '/protocol/openid-connect/token',
+      tokenEndpoint: this.envConfig.authServer + '/realms/' + this.envConfig.realm + '/protocol/openid-connect/token',
       redirectUri: window.location.origin + '/',
       clientId: this.envConfig.clientId,
       scope: 'openid profile',
@@ -71,6 +108,10 @@ export class AuthenticationService {
     this.currentUserResource = userResource;
   }
 
+  unsubscribeEvents(): void {
+    this.eventSubscription.unsubscribe();
+  }
+
   public getCurrentUserInitials(): string {
     return getUserNameInitials(this.currentUserResource);
   }
diff --git a/alfa-client/libs/authentication/test/authentication.ts b/alfa-client/libs/authentication/test/authentication.ts
index 34223905913df6f0a941a02f0b8a63723a959b50..3cf143c030717a12d98d8d6c75e0188e586b34b7 100644
--- a/alfa-client/libs/authentication/test/authentication.ts
+++ b/alfa-client/libs/authentication/test/authentication.ts
@@ -21,8 +21,13 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-import { AuthConfig } from 'angular-oauth2-oidc';
+import { faker } from '@faker-js/faker';
+import { AuthConfig, OAuthEvent } from 'angular-oauth2-oidc';
 
 export function createAuthConfig(): AuthConfig {
   return {};
 }
+
+export function createOAuthEvent(): OAuthEvent {
+  return { type: <any>faker.lorem.word() };
+}
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 9c15cc2b3f6ad8c021b0367f88dc7c37d41597dc..0f2d961a4b48fae71acf2ed14685e34697da1b22 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,12 +21,7 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-import {
-  BlobWithFileName,
-  StateResource,
-  createEmptyStateResource,
-  createStateResource,
-} from '@alfa-client/tech-shared';
+import { BlobWithFileName, StateResource, createEmptyStateResource, createStateResource } 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';
@@ -35,13 +30,10 @@ import { faker } from '@faker-js/faker';
 import { Resource, ResourceUri } from '@ngxp/rest';
 import { cold, hot } from 'jest-marbles';
 import { createBinaryFileResource, createBlob } from 'libs/binary-file-shared/test/binary-file';
-import {
-  VALIDATION_MESSAGES,
-  ValidationMessageCode,
-} from 'libs/tech-shared/src/lib/validation/tech.validation.messages';
+import { VALIDATION_MESSAGES, ValidationMessageCode } from 'libs/tech-shared/src/lib/validation/tech.validation.messages';
 import { DummyLinkRel } from 'libs/tech-shared/test/dummy';
 import { createDummyResource } from 'libs/tech-shared/test/resource';
-import { Observable, of } from 'rxjs';
+import { Observable, of, throwError } from 'rxjs';
 import { createHttpErrorResponse } from '../../../tech-shared/test/http';
 import { singleHot } from '../../../tech-shared/test/marbles';
 import { BinaryFileResource } from './binary-file.model';
@@ -85,10 +77,7 @@ describe('BinaryFileService', () => {
     it('should return value', () => {
       repository.download.mockReturnValue(singleHot(blob, '-a'));
 
-      const returnValue: Observable<StateResource<Blob>> = service.downloadFile(
-        binaryFileResource,
-        downloadNamePrefix,
-      );
+      const returnValue: Observable<StateResource<Blob>> = service.downloadFile(binaryFileResource, downloadNamePrefix);
 
       expect(returnValue).toBeObservable(
         cold('ab', {
@@ -109,18 +98,11 @@ describe('BinaryFileService', () => {
         it('should save file with prefix', () => {
           service.saveBinaryFile(blob, binaryFileResource, downloadNamePrefix);
 
-          expect(service.save).toHaveBeenCalledWith(
-            blob,
-            downloadNamePrefix + '_' + binaryFileResource.name,
-          );
+          expect(service.save).toHaveBeenCalledWith(blob, downloadNamePrefix + '_' + binaryFileResource.name);
         });
 
         it('should return loaded stateResource', () => {
-          const result: StateResource<Blob> = service.saveBinaryFile(
-            blob,
-            binaryFileResource,
-            downloadNamePrefix,
-          );
+          const result: StateResource<Blob> = service.saveBinaryFile(blob, binaryFileResource, downloadNamePrefix);
 
           expect(result).toEqual(createStateResource(blob));
         });
@@ -128,16 +110,36 @@ describe('BinaryFileService', () => {
 
       describe('on non existing response', () => {
         it('should return loading stateResource', () => {
-          const result: StateResource<Blob> = service.saveBinaryFile(
-            undefined,
-            binaryFileResource,
-            downloadNamePrefix,
-          );
+          const result: StateResource<Blob> = service.saveBinaryFile(undefined, binaryFileResource, downloadNamePrefix);
 
           expect(result).toEqual(createEmptyStateResource(true));
         });
       });
     });
+
+    it('should call handleDownloadError on error', fakeAsync(() => {
+      service.handleDownloadError = jest.fn().mockReturnValue(of(createEmptyStateResource()));
+      repository.download.mockReturnValue(throwError(() => new Error('Download error')));
+
+      service.downloadFile(binaryFileResource, downloadNamePrefix).subscribe();
+      tick();
+
+      expect(service.handleDownloadError).toHaveBeenCalled();
+    }));
+
+    describe('handle download error', () => {
+      it('should call snackbarService showError', () => {
+        service.handleDownloadError();
+
+        expect(snackBarService.showError).toHaveBeenCalledWith('Die Datei konnte nicht heruntergeladen werden.');
+      });
+
+      it('should return empty state resource', () => {
+        const result: Observable<StateResource<Blob>> = service.handleDownloadError();
+
+        expect(result).toBeObservable(cold('(a|)', { a: createEmptyStateResource() }));
+      });
+    });
   });
 
   describe('download archive', () => {
@@ -273,10 +275,7 @@ describe('BinaryFileService', () => {
       });
 
       it('should not call snackbarService if not file size exceeded error', () => {
-        service.handleSnackBar(
-          buildUnprocessableEntityErrorResponse(ValidationMessageCode.FIELD_EMPTY),
-          true,
-        );
+        service.handleSnackBar(buildUnprocessableEntityErrorResponse(ValidationMessageCode.FIELD_EMPTY), true);
 
         expect(snackBarService.showError).not.toHaveBeenCalled();
       });
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 ff76416759fc55e2e8c20fc75e1a9077061a34b0..e06c03dff2f58d8e33467a52c08fc6a5f5e2f047 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
@@ -60,27 +60,17 @@ export class BinaryFileService {
     showValidationErrorSnackBar: boolean = true,
   ): Observable<StateResource<BinaryFileResource>> {
     return this.repository.uploadFile(resource, linkRel, file).pipe(
-      mergeMap((response: HttpResponse<Object>) =>
-        this.getFile(response.headers.get(HttpHeader.LOCATION)),
-      ),
-      catchError((errorResponse) =>
-        this.handleError(errorResponse.error, showValidationErrorSnackBar),
-      ),
+      mergeMap((response: HttpResponse<Object>) => this.getFile(response.headers.get(HttpHeader.LOCATION))),
+      catchError((errorResponse) => this.handleError(errorResponse.error, showValidationErrorSnackBar)),
       startWith(createEmptyStateResource<BinaryFileResource>(true)),
     );
   }
 
-  private handleError(
-    errorResponse: HttpErrorResponse,
-    showValidationErrorSnackBar: boolean,
-  ): Observable<StateResource<any>> {
+  private handleError(errorResponse: HttpErrorResponse, showValidationErrorSnackBar: boolean): Observable<StateResource<any>> {
     return of(this.handleErrorByStatus(errorResponse, showValidationErrorSnackBar));
   }
 
-  handleErrorByStatus(
-    error: HttpErrorResponse,
-    showValidationErrorSnackBar: boolean,
-  ): StateResource<any> {
+  handleErrorByStatus(error: HttpErrorResponse, showValidationErrorSnackBar: boolean): StateResource<any> {
     if (isUnprocessableEntity(error.status)) {
       this.handleSnackBar(error, showValidationErrorSnackBar);
       return createErrorStateResource(error.error);
@@ -90,22 +80,23 @@ export class BinaryFileService {
 
   handleSnackBar(error: HttpErrorResponse, showValidationErrorSnackBar: boolean) {
     if (showValidationErrorSnackBar && isValidationFieldFileSizeExceedError(error.error)) {
-      this.snackbarService.showError(
-        getMessageForInvalidParam(EMPTY_STRING, error.error.invalidParams[0]),
-      );
+      this.snackbarService.showError(getMessageForInvalidParam(EMPTY_STRING, error.error.invalidParams[0]));
     }
   }
 
-  public downloadFile(
-    file: BinaryFileResource,
-    fileNamePrefix: string,
-  ): Observable<StateResource<any>> {
+  public downloadFile(file: BinaryFileResource, fileNamePrefix: string): Observable<StateResource<Blob>> {
     return this.repository.download(file).pipe(
       map((data) => this.saveBinaryFile(data, file, fileNamePrefix)),
-      startWith(createEmptyStateResource(true)),
+      startWith(createEmptyStateResource<Blob>(true)),
+      catchError(() => this.handleDownloadError()),
     );
   }
 
+  handleDownloadError(): Observable<StateResource<Blob>> {
+    this.snackbarService.showError('Die Datei konnte nicht heruntergeladen werden.');
+    return of(createEmptyStateResource<Blob>());
+  }
+
   saveBinaryFile(data: any, file: BinaryFileResource, fileNamePrefix: string): StateResource<Blob> {
     if (isNil(data)) {
       return createEmptyStateResource(true);
@@ -148,10 +139,7 @@ export class BinaryFileService {
     );
   }
 
-  public getFiles(
-    resource: Resource,
-    linkRel: string,
-  ): Observable<StateResource<BinaryFileListResource>> {
+  public getFiles(resource: Resource, linkRel: string): Observable<StateResource<BinaryFileListResource>> {
     return this.repository.getFiles(resource, linkRel).pipe(
       map((fileList: BinaryFileListResource) => createStateResource(fileList)),
       startWith(createEmptyStateResource<BinaryFileListResource>(true)),
diff --git a/alfa-client/libs/binary-file/src/lib/binary-file-container/binary-file-container.component.ts b/alfa-client/libs/binary-file/src/lib/binary-file-container/binary-file-container.component.ts
index 900442515338e6700e012dc31e4f7f69b0fe7290..70c92ec582ab178bdef09a16ba7634540491b4dd 100644
--- a/alfa-client/libs/binary-file/src/lib/binary-file-container/binary-file-container.component.ts
+++ b/alfa-client/libs/binary-file/src/lib/binary-file-container/binary-file-container.component.ts
@@ -21,10 +21,10 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-import { Component, EventEmitter, Input, Output } from '@angular/core';
 import { ApiDownloadToken, ApiRootService } from '@alfa-client/api-root-shared';
 import { BinaryFileResource, BinaryFileService } from '@alfa-client/binary-file-shared';
 import { StateResource } from '@alfa-client/tech-shared';
+import { Component, EventEmitter, Input, Output } from '@angular/core';
 import { Observable } from 'rxjs';
 
 @Component({
@@ -39,7 +39,7 @@ export class BinaryFileContainerComponent {
 
   @Output() startDelete: EventEmitter<BinaryFileResource> = new EventEmitter();
 
-  fileStateResource$: Observable<StateResource<any>>;
+  fileStateResource$: Observable<StateResource<Blob>>;
   downloadToken$: Observable<ApiDownloadToken>;
 
   constructor(
@@ -48,10 +48,7 @@ export class BinaryFileContainerComponent {
   ) {}
 
   startDownload(file: BinaryFileResource): void {
-    this.fileStateResource$ = this.binaryFileService.downloadFile(
-      file,
-      this.downloadFileNamePrefix,
-    );
+    this.fileStateResource$ = this.binaryFileService.downloadFile(file, this.downloadFileNamePrefix);
   }
 
   getDownloadToken(): void {
diff --git a/alfa-client/libs/binary-file/src/lib/binary-file-container/binary-file/binary-file.component.html b/alfa-client/libs/binary-file/src/lib/binary-file-container/binary-file/binary-file.component.html
index bef7fe52816ac23dc5c4fc7dff6e1f7e25a99f1b..ad0a9c152b8652d95b4a737339645dd30283cfff 100644
--- a/alfa-client/libs/binary-file/src/lib/binary-file-container/binary-file/binary-file.component.html
+++ b/alfa-client/libs/binary-file/src/lib/binary-file-container/binary-file/binary-file.component.html
@@ -23,12 +23,7 @@
     unter der Lizenz sind dem Lizenztext zu entnehmen.
 
 -->
-<div
-  class="container"
-  [class.deletable]="deletable"
-  [matTooltip]="file.name"
-  matTooltipClass="word-break"
->
+<div class="container" [class.deletable]="deletable" [tooltip]="file.name">
   <div
     class="download-container"
     [class.downloadable]="file | hasLink: fileLinkRel.DOWNLOAD"
diff --git a/alfa-client/libs/binary-file/src/lib/binary-file-container/binary-file/binary-file.component.spec.ts b/alfa-client/libs/binary-file/src/lib/binary-file-container/binary-file/binary-file.component.spec.ts
index 8aaaf66f276b3cadf34437f02d4fcff5e48eb0e3..975c2bf58293f58f8a9f02ad52a7478d25051f13 100644
--- a/alfa-client/libs/binary-file/src/lib/binary-file-container/binary-file/binary-file.component.spec.ts
+++ b/alfa-client/libs/binary-file/src/lib/binary-file-container/binary-file/binary-file.component.spec.ts
@@ -28,11 +28,11 @@ import { getElementFromFixture } from '@alfa-client/test-utils';
 import { IconButtonWithSpinnerComponent, SpinnerComponent } from '@alfa-client/ui';
 import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing';
 import { MatIcon } from '@angular/material/icon';
-import { MatTooltipModule } from '@angular/material/tooltip';
 import { faker } from '@faker-js/faker';
+import { TooltipDirective } from '@ods/system';
 import { createBinaryFileResource } from 'libs/binary-file-shared/test/binary-file';
 import { getDataTestClassOf } from 'libs/tech-shared/test/data-test';
-import { MockComponent, MockModule } from 'ng-mocks';
+import { MockComponent, MockDirective } from 'ng-mocks';
 import { BinaryFileComponent } from './binary-file.component';
 
 describe('BinaryFileComponent', () => {
@@ -49,9 +49,9 @@ describe('BinaryFileComponent', () => {
         MatIcon,
         FileSizePipe,
         HasLinkPipe,
-        MockModule(MatTooltipModule),
         MockComponent(SpinnerComponent),
         MockComponent(IconButtonWithSpinnerComponent),
+        MockDirective(TooltipDirective),
       ],
     });
   });
diff --git a/alfa-client/libs/binary-file/src/lib/binary-file.module.ts b/alfa-client/libs/binary-file/src/lib/binary-file.module.ts
index 1617356e95e80d98fbc07625f3b8fb876b930fbf..ee4cacdb5f276222620c9a4297808dc6e836c007 100644
--- a/alfa-client/libs/binary-file/src/lib/binary-file.module.ts
+++ b/alfa-client/libs/binary-file/src/lib/binary-file.module.ts
@@ -32,6 +32,7 @@ import {
   AttachmentWrapperComponent,
   CloseIconComponent,
   SpinnerIconComponent,
+  TooltipDirective,
 } from '@ods/system';
 import { BinaryFileAttachmentContainerComponent } from './binary-file-attachment-container/binary-file-attachment-container.component';
 import { BinaryFileContainerComponent } from './binary-file-container/binary-file-container.component';
@@ -56,6 +57,7 @@ import { VerticalBinaryFileListComponent } from './vertical-binary-file-list/ver
     SpinnerIconComponent,
     CloseIconComponent,
     DownloadButtonComponent,
+    TooltipDirective,
   ],
   declarations: [
     BinaryFileAttachmentContainerComponent,
diff --git a/alfa-client/libs/binary-file/src/lib/binary-file2-container/binary-file2-container.component.ts b/alfa-client/libs/binary-file/src/lib/binary-file2-container/binary-file2-container.component.ts
index fb9892699cc3a2eda14be01752457906e4d59f26..a0d53c398dc37d5f06af744b9fed8c89487c1519 100644
--- a/alfa-client/libs/binary-file/src/lib/binary-file2-container/binary-file2-container.component.ts
+++ b/alfa-client/libs/binary-file/src/lib/binary-file2-container/binary-file2-container.component.ts
@@ -38,7 +38,7 @@ export class BinaryFile2ContainerComponent {
 
   @Output() startDelete: EventEmitter<BinaryFileResource> = new EventEmitter();
 
-  fileStateResource$: Observable<StateResource<any>>;
+  fileStateResource$: Observable<StateResource<Blob>>;
   downloadToken$: Observable<ApiDownloadToken>;
 
   constructor(
@@ -47,10 +47,7 @@ export class BinaryFile2ContainerComponent {
   ) {}
 
   startDownload(file: BinaryFileResource): void {
-    this.fileStateResource$ = this.binaryFileService.downloadFile(
-      file,
-      this.downloadFileNamePrefix,
-    );
+    this.fileStateResource$ = this.binaryFileService.downloadFile(file, this.downloadFileNamePrefix);
   }
 
   getDownloadToken(): void {
diff --git a/alfa-client/libs/design-system/src/index.ts b/alfa-client/libs/design-system/src/index.ts
index 886dbc3377ed2be0887f68565cf76d1c6af61413..4c577c9087024d16b200f280a1ab6b90d3a8a32d 100644
--- a/alfa-client/libs/design-system/src/index.ts
+++ b/alfa-client/libs/design-system/src/index.ts
@@ -68,6 +68,7 @@ export * from './lib/icons/search-icon/search-icon.component';
 export * from './lib/icons/send-icon/send-icon.component';
 export * from './lib/icons/spinner-icon/spinner-icon.component';
 export * from './lib/icons/stamp-icon/stamp-icon.component';
+export * from './lib/icons/statistic-icon/statistic-icon.component';
 export * from './lib/icons/user-icon/user-icon.component';
 export * from './lib/icons/users-icon/users-icon.component';
 export * from './lib/instant-search/instant-search/instant-search.component';
diff --git a/alfa-client/libs/design-system/src/lib/dropdown-menu/dropdown-menu-button-item/dropdown-menu-button-item.component.ts b/alfa-client/libs/design-system/src/lib/dropdown-menu/dropdown-menu-button-item/dropdown-menu-button-item.component.ts
index 90badf1ab01696f8203a8af8caee1af377c9cbae..2c1b5427927141d6b7ca40515ee64432d9d50e2e 100644
--- a/alfa-client/libs/design-system/src/lib/dropdown-menu/dropdown-menu-button-item/dropdown-menu-button-item.component.ts
+++ b/alfa-client/libs/design-system/src/lib/dropdown-menu/dropdown-menu-button-item/dropdown-menu-button-item.component.ts
@@ -32,6 +32,7 @@ import { Component, EventEmitter, Input, Output } from '@angular/core';
     class="flex min-h-12 w-full items-center gap-4 border-2 border-transparent px-4 py-3 text-start outline-none hover:border-primary focus-visible:border-focus"
     role="menuitem"
     (click)="itemClicked.emit()"
+    [attr.data-test-id]="dataTestId"
   >
     <ng-content select="[icon]" />
     <p class="text-text">{{ caption }}</p>
@@ -39,6 +40,7 @@ import { Component, EventEmitter, Input, Output } from '@angular/core';
 })
 export class DropdownMenuButtonItemComponent {
   @Input({ required: true }) caption!: string;
+  @Input() dataTestId: string;
 
   @Output() itemClicked: EventEmitter<MouseEvent> = new EventEmitter();
 }
diff --git a/alfa-client/libs/design-system/src/lib/dropdown-menu/dropdown-menu/dropdown-menu.component.ts b/alfa-client/libs/design-system/src/lib/dropdown-menu/dropdown-menu/dropdown-menu.component.ts
index 20d8fd4a4742512a13322ef6ffbcb274fd6867c2..5a7a7bba99728581d60fa65fd9fda66dbf093391 100644
--- a/alfa-client/libs/design-system/src/lib/dropdown-menu/dropdown-menu/dropdown-menu.component.ts
+++ b/alfa-client/libs/design-system/src/lib/dropdown-menu/dropdown-menu/dropdown-menu.component.ts
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den
+ * Copyright (C) 2025 Das Land Schleswig-Holstein vertreten durch den
  * Ministerpräsidenten des Landes Schleswig-Holstein
  * Staatskanzlei
  * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
@@ -33,7 +33,7 @@ import { twMerge } from 'tailwind-merge';
   imports: [CommonModule, CdkTrapFocus],
   template: ` <div class="relative w-fit">
     <button
-      [ngClass]="[twMerge('block w-fit outline-2 outline-offset-2 outline-focus', buttonClass)]"
+      [ngClass]="[twMerge('block w-fit outline-2 outline-offset-2 outline-focus empty:hidden', buttonClass)]"
       (click)="handleButtonClick()"
       [attr.aria-expanded]="isPopupOpen"
       aria-haspopup="true"
diff --git a/alfa-client/libs/design-system/src/lib/icons/settings-icon/settengs-icon.stories.ts b/alfa-client/libs/design-system/src/lib/icons/settings-icon/settengs-icon.stories.ts
new file mode 100644
index 0000000000000000000000000000000000000000..790a794f4807fcc24841e66aac74a84846d9ec86
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/icons/settings-icon/settengs-icon.stories.ts
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den
+ * Ministerpräsidenten des Landes Schleswig-Holstein
+ * Staatskanzlei
+ * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+ *
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+import type { Meta, StoryObj } from '@storybook/angular';
+
+import { SettingsIconComponent } from './settings-icon.component';
+
+const meta: Meta<SettingsIconComponent> = {
+  title: 'Icons/Settings icon',
+  component: SettingsIconComponent,
+  excludeStories: /.*Data$/,
+  tags: ['autodocs'],
+};
+
+export default meta;
+type Story = StoryObj<SettingsIconComponent>;
+
+export const Default: Story = {
+  args: { size: 'large' },
+  argTypes: {
+    size: {
+      control: 'select',
+      options: ['small', 'medium', 'large', 'extra-large', 'full'],
+      description: 'Size of icon. Property "full" means 100%',
+      table: {
+        defaultValue: { summary: 'medium' },
+      },
+    },
+  },
+};
diff --git a/alfa-client/libs/design-system/src/lib/icons/statistic-icon/statistic-icon.component.spec.ts b/alfa-client/libs/design-system/src/lib/icons/statistic-icon/statistic-icon.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..9f6bddf811de36b7005098584a3c436010fc9bb3
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/icons/statistic-icon/statistic-icon.component.spec.ts
@@ -0,0 +1,21 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { StatisticIconComponent } from './statistic-icon.component';
+
+describe('StatisticIconComponent', () => {
+  let component: StatisticIconComponent;
+  let fixture: ComponentFixture<StatisticIconComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: [StatisticIconComponent],
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(StatisticIconComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/alfa-client/libs/design-system/src/lib/icons/statistic-icon/statistic-icon.component.ts b/alfa-client/libs/design-system/src/lib/icons/statistic-icon/statistic-icon.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..df5d2b5bdcba9549b60cea9ee4b04d7e8bc4d8c4
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/icons/statistic-icon/statistic-icon.component.ts
@@ -0,0 +1,24 @@
+import { NgClass } from '@angular/common';
+import { Component, Input } from '@angular/core';
+import { twMerge } from 'tailwind-merge';
+import { iconVariants, IconVariants } from '../iconVariants';
+
+@Component({
+  selector: 'ods-statistic-icon',
+  standalone: true,
+  imports: [NgClass],
+  template: `<svg
+    viewBox="0 0 24 24"
+    xmlns="http://www.w3.org/2000/svg"
+    [ngClass]="twMerge(iconVariants({ size }), 'fill-black', class)"
+  >
+    <path d="M2 21V19H22V21H2ZM3 18V11H6V18H3ZM8 18V6H11V18H8ZM13 18V9H16V18H13ZM18 18V3H21V18H18Z" />
+  </svg>`,
+})
+export class StatisticIconComponent {
+  @Input() size: IconVariants['size'] = 'medium';
+  @Input() class: string = undefined;
+
+  readonly iconVariants = iconVariants;
+  readonly twMerge = twMerge;
+}
diff --git a/alfa-client/libs/design-system/src/lib/icons/statistic-icon/statistic-icon.stories.ts b/alfa-client/libs/design-system/src/lib/icons/statistic-icon/statistic-icon.stories.ts
new file mode 100644
index 0000000000000000000000000000000000000000..272f6fe850c3862c1a7c8212bf2807369a41064b
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/icons/statistic-icon/statistic-icon.stories.ts
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den
+ * Ministerpräsidenten des Landes Schleswig-Holstein
+ * Staatskanzlei
+ * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+ *
+ * Lizenziert unter der EUPL, Version 1.2 oder - sobald
+ * diese von der Europäischen Kommission genehmigt wurden -
+ * Folgeversionen der EUPL ("Lizenz");
+ * Sie dürfen dieses Werk ausschließlich gemäß
+ * dieser Lizenz nutzen.
+ * Eine Kopie der Lizenz finden Sie hier:
+ *
+ * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+ *
+ * Sofern nicht durch anwendbare Rechtsvorschriften
+ * gefordert oder in schriftlicher Form vereinbart, wird
+ * die unter der Lizenz verbreitete Software "so wie sie
+ * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+ * ausdrücklich oder stillschweigend - verbreitet.
+ * Die sprachspezifischen Genehmigungen und Beschränkungen
+ * unter der Lizenz sind dem Lizenztext zu entnehmen.
+ */
+import type { Meta, StoryObj } from '@storybook/angular';
+
+import { StatisticIconComponent } from './statistic-icon.component';
+
+const meta: Meta<StatisticIconComponent> = {
+  title: 'Icons/Statistic icon',
+  component: StatisticIconComponent,
+  excludeStories: /.*Data$/,
+  tags: ['autodocs'],
+};
+
+export default meta;
+type Story = StoryObj<StatisticIconComponent>;
+
+export const Default: Story = {
+  args: { size: 'large' },
+  argTypes: {
+    size: {
+      control: 'select',
+      options: ['small', 'medium', 'large', 'extra-large', 'full'],
+      description: 'Size of icon. Property "full" means 100%',
+      table: {
+        defaultValue: { summary: 'medium' },
+      },
+    },
+  },
+};
diff --git a/alfa-client/libs/design-system/src/lib/tooltip/tooltip.component.ts b/alfa-client/libs/design-system/src/lib/tooltip/tooltip.component.ts
index 85e9b48d104df61a2139cdf829bc78f9728bc914..1f813a9e5ea79cb5e30111a132dca50be8ebcc2f 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
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den
+ * Copyright (C) 2025 Das Land Schleswig-Holstein vertreten durch den
  * Ministerpräsidenten des Landes Schleswig-Holstein
  * Staatskanzlei
  * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
@@ -29,7 +29,7 @@ import { TooltipPosition } from './tooltip.directive';
   selector: 'ods-tooltip',
   imports: [NgClass],
   template: `<span
-    class="tooltip fixed z-[100] max-w-xs animate-fadeIn cursor-default break-words rounded bg-ozggray-900 px-3 py-2 text-sm 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 md:max-w-[calc(90vw)]"
+    class="tooltip fixed z-[100] max-w-md animate-fadeIn cursor-default whitespace-pre rounded bg-ozggray-900 px-3 py-2 text-sm 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 md:max-w-[calc(90vw)]"
     [ngClass]="class"
     [class.visible]="show"
     [class.invisible]="!show"
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 9265a021a9ce2e988257793c5474970b79d06fc3..e41c410f0efb001d9c7896eaec93fb388fb9d23a 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,7 +21,6 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-import { EMPTY_STRING } from '@alfa-client/tech-shared';
 import { InteractivityChecker } from '@angular/cdk/a11y';
 import { ComponentRef, ElementRef, Renderer2, ViewContainerRef } from '@angular/core';
 import { TestBed } from '@angular/core/testing';
@@ -64,11 +63,28 @@ describe('TooltipDirective', () => {
     expect(directive).toBeTruthy();
   });
 
-  describe('ngAfterViewInit', () => {
-    it('should create tooltip', () => {
+  describe('set tooltip', () => {
+    beforeEach(() => {
       directive.createTooltip = jest.fn();
+      directive.destroy = jest.fn();
+    });
+
+    it('should destroy tooltip if it exists already', () => {
+      directive.componentRef = mockComponentRef;
 
-      directive.ngAfterViewInit();
+      directive.tooltip = 'test';
+
+      expect(directive.destroy).toHaveBeenCalled();
+    });
+
+    it('should not create tooltip if text is empty', () => {
+      directive.tooltip = '';
+
+      expect(directive.createTooltip).not.toHaveBeenCalled();
+    });
+
+    it('should create tooltip', () => {
+      directive.tooltip = 'test';
 
       expect(directive.createTooltip).toHaveBeenCalled();
     });
@@ -85,49 +101,48 @@ describe('TooltipDirective', () => {
   });
 
   describe('createTooltip', () => {
+    const tooltipText: string = faker.lorem.sentence();
+
     beforeEach(() => {
       directive.viewContainerRef.createComponent = jest.fn().mockReturnValue({ location: { nativeElement: {} } });
       directive.setAriaAttribute = jest.fn();
       directive.setInitialTooltipProperties = jest.fn();
       directive.getParentElement = jest.fn().mockReturnValue({ appendChild: jest.fn() });
       directive.interactivityChecker.isFocusable = jest.fn();
-      directive.tooltip = faker.lorem.sentence();
     });
 
     it('should create tooltip component', () => {
-      directive.createTooltip();
+      directive.createTooltip(tooltipText);
 
       expect(directive.viewContainerRef.createComponent).toHaveBeenCalled();
     });
 
     it('should get parent element', () => {
-      directive.createTooltip();
+      directive.createTooltip(tooltipText);
 
       expect(directive.getParentElement).toHaveBeenCalled();
     });
 
     it('should insert tooltip component to parent element', () => {
-      directive.createTooltip();
+      directive.createTooltip(tooltipText);
 
       expect(directive.parentElement.appendChild).toHaveBeenCalled();
     });
 
     it('should set initial tooltip properties', () => {
-      directive.createTooltip();
+      directive.createTooltip(tooltipText);
 
       expect(directive.setInitialTooltipProperties).toHaveBeenCalled();
     });
 
     it('should set aria attribute to parent', () => {
-      directive.createTooltip();
+      directive.createTooltip(tooltipText);
 
       expect(directive.setAriaAttribute).toHaveBeenCalled();
     });
 
     it('should not create tooltip', () => {
-      directive.tooltip = EMPTY_STRING;
-
-      directive.createTooltip();
+      directive.createTooltip('');
 
       expect(directive.getParentElement).not.toHaveBeenCalled();
     });
@@ -135,10 +150,19 @@ describe('TooltipDirective', () => {
 
   describe('showTooltip', () => {
     beforeEach(() => {
+      directive.componentRef = mockComponentRef;
       directive.setTooltipProperties = jest.fn();
       directive.elementRef.nativeElement.contains = jest.fn().mockReturnValue(true);
     });
 
+    it('should not set tooltip properties if component ref is null', () => {
+      directive.componentRef = null;
+
+      directive.showTooltip();
+
+      expect(directive.setTooltipProperties).not.toHaveBeenCalled();
+    });
+
     it('should check if element focused', () => {
       directive.showTooltip();
 
@@ -218,9 +242,6 @@ describe('TooltipDirective', () => {
     });
 
     it('should set tooltip instance properties', () => {
-      directive.tooltip = 'I am tooltip';
-      directive.tooltipId = 'tooltip-1';
-
       directive.setTooltipProperties();
 
       expect(directive.componentRef.instance).toMatchObject({
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 cdc414d0e3f580d085037276f26f03697f98decc..ce1f687ce7a0df7411b5d3169f42d9c152f9c88e 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,10 +21,9 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-import { isEscapeKey } from '@alfa-client/tech-shared';
+import { isEscapeKey, isNotNull } from '@alfa-client/tech-shared';
 import { InteractivityChecker } from '@angular/cdk/a11y';
 import {
-  AfterViewInit,
   ComponentRef,
   Directive,
   ElementRef,
@@ -49,8 +48,18 @@ type TooltipAriaType = 'aria-describedby' | 'aria-labelledby';
   selector: '[tooltip]',
   standalone: true,
 })
-export class TooltipDirective implements AfterViewInit, OnDestroy {
-  @Input() tooltip: string = '';
+export class TooltipDirective implements OnDestroy {
+  @Input() set tooltip(value: string) {
+    if (isNotNull(this.componentRef)) {
+      this.destroy();
+    }
+
+    if (isEmpty(value)) {
+      return;
+    }
+
+    this.createTooltip(value);
+  }
   @Input() tooltipPosition: TooltipPosition = TooltipPosition.BELOW;
   @Input() tooltipAriaType: TooltipAriaType = 'aria-describedby';
 
@@ -61,14 +70,10 @@ export class TooltipDirective implements AfterViewInit, OnDestroy {
   position: TooltipPosition;
   leftOffset: number = 0;
 
-  public viewContainerRef: ViewContainerRef = inject(ViewContainerRef);
-  public elementRef: ElementRef<HTMLElement> = inject(ElementRef);
-  public renderer: Renderer2 = inject(Renderer2);
-  public interactivityChecker: InteractivityChecker = inject(InteractivityChecker);
-
-  ngAfterViewInit(): void {
-    this.createTooltip();
-  }
+  public readonly viewContainerRef: ViewContainerRef = inject(ViewContainerRef);
+  public readonly elementRef: ElementRef<HTMLElement> = inject(ElementRef);
+  public readonly renderer: Renderer2 = inject(Renderer2);
+  public readonly interactivityChecker: InteractivityChecker = inject(InteractivityChecker);
 
   ngOnDestroy(): void {
     this.destroy();
@@ -77,6 +82,10 @@ export class TooltipDirective implements AfterViewInit, OnDestroy {
   @HostListener('mouseenter')
   @HostListener('focusin')
   showTooltip(): void {
+    if (isNull(this.componentRef)) {
+      return;
+    }
+
     const nativeElement: HTMLElement = this.elementRef.nativeElement;
     this.attachedToFocused = nativeElement.contains(document.activeElement);
     this.setTooltipProperties();
@@ -97,8 +106,8 @@ export class TooltipDirective implements AfterViewInit, OnDestroy {
     }
   }
 
-  createTooltip(): void {
-    if (isEmpty(this.tooltip)) {
+  createTooltip(tooltipText: string): void {
+    if (isEmpty(tooltipText)) {
       return;
     }
 
@@ -107,7 +116,7 @@ export class TooltipDirective implements AfterViewInit, OnDestroy {
     this.parentElement = this.getParentElement(nativeElement);
     this.parentElement.appendChild(this.componentRef.location.nativeElement);
     this.tooltipId = uniqueId('tooltip');
-    this.setInitialTooltipProperties(this.tooltip, this.tooltipId);
+    this.setInitialTooltipProperties(tooltipText, this.tooltipId);
     this.setAriaAttribute(this.tooltipAriaType);
   }
 
@@ -199,6 +208,10 @@ export class TooltipDirective implements AfterViewInit, OnDestroy {
   }
 
   hide(): void {
+    if (isNull(this.componentRef)) {
+      return;
+    }
+
     this.componentRef.instance.show = false;
   }
 
diff --git a/alfa-client/libs/environment-shared/src/lib/environment.model.ts b/alfa-client/libs/environment-shared/src/lib/environment.model.ts
index 751085929a4e9756a07fd3b7615197b75dd77553..83e2674c9e48c189746d57f5751496a00d655f5f 100644
--- a/alfa-client/libs/environment-shared/src/lib/environment.model.ts
+++ b/alfa-client/libs/environment-shared/src/lib/environment.model.ts
@@ -30,8 +30,4 @@ export interface Environment {
   realm: string;
   clientId: string;
   processorNames: string[];
-  features: {
-    postfach: boolean;
-    benutzerRollen: boolean;
-  };
 }
diff --git a/alfa-client/libs/environment-shared/src/lib/environment.service.ts b/alfa-client/libs/environment-shared/src/lib/environment.service.ts
index df9f879478212ef196191edaba9de6a134ae0277..51d2b60795077165455bfc1c78ef31b3e3890a08 100644
--- a/alfa-client/libs/environment-shared/src/lib/environment.service.ts
+++ b/alfa-client/libs/environment-shared/src/lib/environment.service.ts
@@ -25,7 +25,7 @@ import { getBaseUrl } from '@alfa-client/tech-shared';
 import { InjectionToken } from '@angular/core';
 import { Environment } from './environment.model';
 
-export const ENVIRONMENT_CONFIG = new InjectionToken('environmentConfig');
+export const ENVIRONMENT_CONFIG = new InjectionToken<Environment>('environmentConfig');
 
 export function getEnvironmentFactory(): Environment {
   // @ts-ignore
diff --git a/alfa-client/libs/environment-shared/test/environment.ts b/alfa-client/libs/environment-shared/test/environment.ts
index a0b3bf79e50da3351ab61283e7903d4747956942..ef29099703a89b5bb9d0fc989a1de91a13070bc4 100644
--- a/alfa-client/libs/environment-shared/test/environment.ts
+++ b/alfa-client/libs/environment-shared/test/environment.ts
@@ -32,10 +32,6 @@ const environment: Environment = {
   realm: faker.word.sample(),
   clientId: faker.string.uuid(),
   processorNames: [faker.person.fullName()],
-  features: {
-    postfach: true,
-    benutzerRollen: true,
-  },
 };
 
 export function createEnvironment(): Environment {
diff --git a/alfa-client/libs/tech-shared/src/lib/service/formservice.abstract.ts b/alfa-client/libs/tech-shared/src/lib/service/formservice.abstract.ts
index faabb47b7a8addbc06449f48ab9b4ecb1f68de77..59f82aaf5ade160fccaaebb794f117926b91e148 100644
--- a/alfa-client/libs/tech-shared/src/lib/service/formservice.abstract.ts
+++ b/alfa-client/libs/tech-shared/src/lib/service/formservice.abstract.ts
@@ -34,7 +34,7 @@ import { isNotUndefined } from '../tech.util';
 import { setInvalidParamValidationError } from '../validation/tech.validation.util';
 
 @Injectable()
-export abstract class AbstractFormService<T extends Resource = Resource> {
+export abstract class AbstractFormService<T = Resource> {
   form: UntypedFormGroup;
   pathPrefix: string;
   source: any;
diff --git a/alfa-client/libs/ui/src/lib/ui/back-button/back-button.component.html b/alfa-client/libs/ui/src/lib/ui/back-button/back-button.component.html
index 15b7525df35717921a5d10f25db575a969fa6070..29c6b91fcdefa4629cae62422ee8b56fe62346b2 100644
--- a/alfa-client/libs/ui/src/lib/ui/back-button/back-button.component.html
+++ b/alfa-client/libs/ui/src/lib/ui/back-button/back-button.component.html
@@ -1,6 +1,6 @@
 <!--
 
-    Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch den
+    Copyright (C) 2025 Das Land Schleswig-Holstein vertreten durch den
     Ministerpräsidenten des Landes Schleswig-Holstein
     Staatskanzlei
     Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
@@ -28,8 +28,8 @@
   mat-icon-button
   data-test-id="back-button"
   class="back-button"
-  [attr.aria-label]="label"
-  [matTooltip]="label"
+  [tooltip]="label"
+  tooltipAriaType="aria-labelledby"
 >
   <mat-icon>arrow_back</mat-icon>
 </a>
diff --git a/alfa-client/libs/ui/src/lib/ui/back-button/back-button.component.spec.ts b/alfa-client/libs/ui/src/lib/ui/back-button/back-button.component.spec.ts
index c27ac7f78d4ef8f71075e09a7e872f11e8d15398..9ca87b6fea4263137d68e5451ad05639cff3666d 100644
--- a/alfa-client/libs/ui/src/lib/ui/back-button/back-button.component.spec.ts
+++ b/alfa-client/libs/ui/src/lib/ui/back-button/back-button.component.spec.ts
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch den
+ * Copyright (C) 2025 Das Land Schleswig-Holstein vertreten durch den
  * Ministerpräsidenten des Landes Schleswig-Holstein
  * Staatskanzlei
  * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
@@ -24,11 +24,11 @@
 import { getElementFromFixture } from '@alfa-client/test-utils';
 import { ComponentFixture, TestBed } from '@angular/core/testing';
 import { MatIcon } from '@angular/material/icon';
-import { MatTooltipModule } from '@angular/material/tooltip';
 import { RouterTestingModule } from '@angular/router/testing';
 import { faker } from '@faker-js/faker';
+import { TooltipDirective } from '@ods/system';
 import { getDataTestIdOf } from 'libs/tech-shared/test/data-test';
-import { MockModule } from 'ng-mocks';
+import { MockDirective } from 'ng-mocks';
 import { BackButtonComponent } from './back-button.component';
 
 describe('BackButtonComponent', () => {
@@ -41,7 +41,7 @@ describe('BackButtonComponent', () => {
 
   beforeEach(async () => {
     await TestBed.configureTestingModule({
-      declarations: [BackButtonComponent, MockModule(MatTooltipModule)],
+      declarations: [BackButtonComponent, MockDirective(TooltipDirective)],
       imports: [MatIcon, RouterTestingModule],
     }).compileComponents();
 
@@ -54,19 +54,6 @@ describe('BackButtonComponent', () => {
     expect(component).toBeTruthy();
   });
 
-  describe('label', () => {
-    beforeEach(() => {
-      component.label = faker.lorem.sentence();
-      fixture.detectChanges();
-    });
-
-    it('should set aria-label attribute', () => {
-      const backButtonElement: HTMLAnchorElement = getElementFromFixture(fixture, backButton);
-
-      expect(backButtonElement).toHaveAttribute('aria-label', component.label);
-    });
-  });
-
   describe('linkTo', () => {
     it('string path should set href attribute', () => {
       component.linkTo = linkToAsString;
diff --git a/alfa-client/libs/ui/src/lib/ui/download-button/download-button.component.html b/alfa-client/libs/ui/src/lib/ui/download-button/download-button.component.html
index 837eb1f03cfbac8cffcdb498528ac68a87927009..5c65fd900ce1b07a5ae957e00295792655481bee 100644
--- a/alfa-client/libs/ui/src/lib/ui/download-button/download-button.component.html
+++ b/alfa-client/libs/ui/src/lib/ui/download-button/download-button.component.html
@@ -28,7 +28,7 @@
   data-test-id="open-url-in-new-window"
   [href]="url"
   [attr.aria-label]="text"
-  [matTooltip]="text"
+  [tooltip]="text"
   [download]="targetName"
   [color]="'primary'"
 >
diff --git a/alfa-client/libs/ui/src/lib/ui/icon-button-with-spinner/icon-button-with-spinner.component.html b/alfa-client/libs/ui/src/lib/ui/icon-button-with-spinner/icon-button-with-spinner.component.html
index 17f6df625694ad4a805506963c8278fe055a3d48..1bb8fb6c9424bb9fb420a5f0007d61a88ffe6beb 100644
--- a/alfa-client/libs/ui/src/lib/ui/icon-button-with-spinner/icon-button-with-spinner.component.html
+++ b/alfa-client/libs/ui/src/lib/ui/icon-button-with-spinner/icon-button-with-spinner.component.html
@@ -1,6 +1,6 @@
 <!--
 
-    Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch den
+    Copyright (C) 2025 Das Land Schleswig-Holstein vertreten durch den
     Ministerpräsidenten des Landes Schleswig-Holstein
     Staatskanzlei
     Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
@@ -26,36 +26,18 @@
 <button
   mat-icon-button
   data-test-class="icon-button"
-  [attr.aria-label]="
-    toolTip ? toolTip : 'Icon Button mit einem ' + (icon ? icon : svgIcon) + ' Icon'
-  "
   [disabled]="isDisabled"
-  [matTooltip]="toolTip"
+  [tooltip]="toolTip"
+  tooltipAriaType="aria-labelledby"
   [matMenuTriggerFor]="matMenuTriggerFor"
   (click)="clickEmitter.emit($event)"
   type="button"
 >
-  <mat-icon
-    *ngIf="icon"
-    data-test-class="icon"
-    [style.visibility]="isDisabled ? 'hidden' : 'visible'"
-  >
+  <mat-icon *ngIf="icon" data-test-class="icon" [style.visibility]="isDisabled ? 'hidden' : 'visible'">
     {{ icon }}
   </mat-icon>
 
-  <mat-icon
-    *ngIf="svgIcon"
-    data-test-class="icon"
-    [svgIcon]="svgIcon"
-    [style.visibility]="isDisabled ? 'hidden' : 'visible'"
-  >
-  </mat-icon>
+  <mat-icon *ngIf="svgIcon" data-test-class="icon" [svgIcon]="svgIcon" [style.visibility]="isDisabled ? 'hidden' : 'visible'" />
 
-  <ozgcloud-spinner
-    [stateResource]="getStateResource()"
-    [diameter]="22"
-    [show]="showSpinner"
-    padding="0"
-  >
-  </ozgcloud-spinner>
+  <ozgcloud-spinner [stateResource]="getStateResource()" [diameter]="22" [show]="showSpinner" padding="0" />
 </button>
diff --git a/alfa-client/libs/ui/src/lib/ui/icon-button-with-spinner/icon-button-with-spinner.component.spec.ts b/alfa-client/libs/ui/src/lib/ui/icon-button-with-spinner/icon-button-with-spinner.component.spec.ts
index e303e74c6fd61eef05ccc6cef15bff6f60607866..7cf06e5752ca8ebf4c3b0b797b97631bc3e04c25 100644
--- a/alfa-client/libs/ui/src/lib/ui/icon-button-with-spinner/icon-button-with-spinner.component.spec.ts
+++ b/alfa-client/libs/ui/src/lib/ui/icon-button-with-spinner/icon-button-with-spinner.component.spec.ts
@@ -25,8 +25,8 @@ import { createEmptyStateResource } from '@alfa-client/tech-shared';
 import { ComponentFixture, TestBed } from '@angular/core/testing';
 import { MatIcon } from '@angular/material/icon';
 import { MatMenuModule } from '@angular/material/menu';
-import { MatTooltipModule } from '@angular/material/tooltip';
-import { MockComponent, MockModule } from 'ng-mocks';
+import { TooltipDirective } from '@ods/system';
+import { MockComponent, MockDirective, MockModule } from 'ng-mocks';
 import { SpinnerComponent } from '../spinner/spinner.component';
 import { IconButtonWithSpinnerComponent } from './icon-button-with-spinner.component';
 
@@ -43,7 +43,7 @@ describe('IconButtonWithSpinnerComponent', () => {
         IconButtonWithSpinnerComponent,
         MatIcon,
         MockComponent(SpinnerComponent),
-        MockModule(MatTooltipModule),
+        MockDirective(TooltipDirective),
         MockModule(MatMenuModule),
       ],
     });
diff --git a/alfa-client/libs/ui/src/lib/ui/open-url-button/open-url-button.component.html b/alfa-client/libs/ui/src/lib/ui/open-url-button/open-url-button.component.html
index 9c27adeed48b413aba66c4816fc1f993b8567a70..39ef61cb6485f2d1a8704f729e75f4c13b57fa8d 100644
--- a/alfa-client/libs/ui/src/lib/ui/open-url-button/open-url-button.component.html
+++ b/alfa-client/libs/ui/src/lib/ui/open-url-button/open-url-button.component.html
@@ -29,7 +29,7 @@
   [href]="url"
   [target]="targetName"
   [attr.aria-label]="text"
-  [matTooltip]="tooltip"
+  [tooltip]="tooltip"
   [color]="'primary'"
   [title]="tooltip"
   class="button"
diff --git a/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-button-with-spinner/ozgcloud-button-with-spinner.component.html b/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-button-with-spinner/ozgcloud-button-with-spinner.component.html
index 93bcb7d18bb803fb08dedf587b10a3261d0099a5..374a22364102cade464a3fad961bbffe1a7b330a 100644
--- a/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-button-with-spinner/ozgcloud-button-with-spinner.component.html
+++ b/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-button-with-spinner/ozgcloud-button-with-spinner.component.html
@@ -30,7 +30,7 @@
   [color]="color"
   [type]="type"
   [disabled]="isDisabled"
-  [matTooltip]="toolTip"
+  [tooltip]="toolTip"
   [class.with-text]="text"
   (click)="clickEmitter.emit($event)"
 >
diff --git a/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-button-with-spinner/ozgcloud-button-with-spinner.component.spec.ts b/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-button-with-spinner/ozgcloud-button-with-spinner.component.spec.ts
index cb73ead5c66d13042bc5ddb7476b59c7aed81703..ee97fa55891a3b5ea04917c80ea255458f58d68b 100644
--- a/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-button-with-spinner/ozgcloud-button-with-spinner.component.spec.ts
+++ b/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-button-with-spinner/ozgcloud-button-with-spinner.component.spec.ts
@@ -24,13 +24,13 @@
 import { ComponentFixture, TestBed } from '@angular/core/testing';
 import { MatButton } from '@angular/material/button';
 import { MatRipple } from '@angular/material/core';
-import { MatTooltipModule } from '@angular/material/tooltip';
 import { createCommandResource } from 'libs/command-shared/test/command';
 import { getDataTestClassOf } from 'libs/tech-shared/test/data-test';
-import { MockComponent, MockModule } from 'ng-mocks';
+import { MockComponent, MockDirective } from 'ng-mocks';
 import { OzgcloudButtonContentComponent } from '../shared/ozgcloud-button-content/ozgcloud-button-content.component';
 import { OzgcloudButtonWithSpinnerComponent } from './ozgcloud-button-with-spinner.component';
 
+import { TooltipDirective } from '@ods/system';
 import * as ResourceUtils from 'libs/tech-shared/src/lib/resource/resource.util';
 
 describe('OzgcloudButtonWithSpinnerComponent', () => {
@@ -45,7 +45,7 @@ describe('OzgcloudButtonWithSpinnerComponent', () => {
         MatButton,
         MatRipple,
         OzgcloudButtonWithSpinnerComponent,
-        MockModule(MatTooltipModule),
+        MockDirective(TooltipDirective),
         MockComponent(OzgcloudButtonContentComponent),
       ],
     }).compileComponents();
diff --git a/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-icon-button-primary/ozgcloud-icon-button-primary.component.html b/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-icon-button-primary/ozgcloud-icon-button-primary.component.html
index b0ecf6c5de127cddea84861601dde60fb1e2efb1..21035dd8675511d51040c8f6aa627b995bab54ed 100644
--- a/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-icon-button-primary/ozgcloud-icon-button-primary.component.html
+++ b/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-icon-button-primary/ozgcloud-icon-button-primary.component.html
@@ -27,7 +27,7 @@
   mat-icon-button
   data-test-class="icon-button-primary"
   [attr.aria-label]="ariaLabel"
-  [matTooltip]="tooltip"
+  [tooltip]="tooltip"
   (click)="clickEmitter.emit($event)"
   color="primary"
   type="button"
diff --git a/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-icon-button-primary/ozgcloud-icon-button-primary.component.scss b/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-icon-button-primary/ozgcloud-icon-button-primary.component.scss
index af82db8c6ff99b292d748f41a135b0e811f8a879..a01b48881d53d2d9f8ee17768a885a76c7d902c5 100644
--- a/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-icon-button-primary/ozgcloud-icon-button-primary.component.scss
+++ b/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-icon-button-primary/ozgcloud-icon-button-primary.component.scss
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den
+ * Copyright (C) 2025 Das Land Schleswig-Holstein vertreten durch den
  * Ministerpräsidenten des Landes Schleswig-Holstein
  * Staatskanzlei
  * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
@@ -23,4 +23,5 @@
  */
 :host {
   position: relative;
+  z-index: 1;
 }
diff --git a/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-icon-button-primary/ozgcloud-icon-button-primary.component.spec.ts b/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-icon-button-primary/ozgcloud-icon-button-primary.component.spec.ts
index ad86b2f5b418a6a2fc6c8ef74c69dc32063f165a..976c0b0c396b7dfc68b3f7e53148d1d75cf1baa8 100644
--- a/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-icon-button-primary/ozgcloud-icon-button-primary.component.spec.ts
+++ b/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-icon-button-primary/ozgcloud-icon-button-primary.component.spec.ts
@@ -26,9 +26,9 @@ import { getElementFromFixture } from '@alfa-client/test-utils';
 import { ComponentFixture, TestBed } from '@angular/core/testing';
 import { MatIcon } from '@angular/material/icon';
 import { MatIconTestingModule } from '@angular/material/icon/testing';
-import { MatTooltipModule } from '@angular/material/tooltip';
+import { TooltipDirective } from '@ods/system';
 import { getDataTestClassOf } from 'libs/tech-shared/test/data-test';
-import { MockComponent, MockModule } from 'ng-mocks';
+import { MockComponent, MockDirective } from 'ng-mocks';
 import { OzgcloudIconButtonPrimaryComponent } from './ozgcloud-icon-button-primary.component';
 
 jest.mock('@alfa-client/tech-shared');
@@ -41,11 +41,7 @@ describe('IconButtonPrimaryWithSpinnerComponent', () => {
   beforeEach(() => {
     TestBed.configureTestingModule({
       imports: [MatIconTestingModule],
-      declarations: [
-        OzgcloudIconButtonPrimaryComponent,
-        MockComponent(MatIcon),
-        MockModule(MatTooltipModule),
-      ],
+      declarations: [OzgcloudIconButtonPrimaryComponent, MockComponent(MatIcon), MockDirective(TooltipDirective)],
     });
   });
 
diff --git a/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-stroked-button-with-spinner/ozgcloud-stroked-button-with-spinner.component.html b/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-stroked-button-with-spinner/ozgcloud-stroked-button-with-spinner.component.html
index 58afc8842e49c8afe650594a94757aca75f23b3f..1c6c7d85154956f4d5ae0a1c0c09225accde76f9 100644
--- a/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-stroked-button-with-spinner/ozgcloud-stroked-button-with-spinner.component.html
+++ b/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-stroked-button-with-spinner/ozgcloud-stroked-button-with-spinner.component.html
@@ -30,7 +30,7 @@
   [color]="color"
   [type]="type"
   [disabled]="isDisabled"
-  [matTooltip]="toolTip"
+  [tooltip]="toolTip"
   [class.with-text]="text"
   (click)="clickEmitter.emit($event)"
 >
diff --git a/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-stroked-button-with-spinner/ozgcloud-stroked-button-with-spinner.component.spec.ts b/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-stroked-button-with-spinner/ozgcloud-stroked-button-with-spinner.component.spec.ts
index 8703dcf19b3978964792b7874155cca2aec699eb..208868555e600c7fd81f6edc4bd1e8fd541827e6 100644
--- a/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-stroked-button-with-spinner/ozgcloud-stroked-button-with-spinner.component.spec.ts
+++ b/alfa-client/libs/ui/src/lib/ui/ozgcloud-button/ozgcloud-stroked-button-with-spinner/ozgcloud-stroked-button-with-spinner.component.spec.ts
@@ -24,13 +24,13 @@
 import { ComponentFixture, TestBed } from '@angular/core/testing';
 import { MatButton } from '@angular/material/button';
 import { MatRipple } from '@angular/material/core';
-import { MatTooltipModule } from '@angular/material/tooltip';
 import { createCommandResource } from 'libs/command-shared/test/command';
 import { getDataTestClassOf } from 'libs/tech-shared/test/data-test';
-import { MockComponent, MockModule } from 'ng-mocks';
+import { MockComponent, MockDirective } from 'ng-mocks';
 import { OzgcloudButtonContentComponent } from '../shared/ozgcloud-button-content/ozgcloud-button-content.component';
 import { OzgcloudStrokedButtonWithSpinnerComponent } from './ozgcloud-stroked-button-with-spinner.component';
 
+import { TooltipDirective } from '@ods/system';
 import * as ResourceUtils from 'libs/tech-shared/src/lib/resource/resource.util';
 
 describe('OzgcloudStrokedButtonWithSpinnerComponent', () => {
@@ -45,7 +45,7 @@ describe('OzgcloudStrokedButtonWithSpinnerComponent', () => {
         MatButton,
         MatRipple,
         OzgcloudStrokedButtonWithSpinnerComponent,
-        MockModule(MatTooltipModule),
+        MockDirective(TooltipDirective),
         MockComponent(OzgcloudButtonContentComponent),
       ],
     }).compileComponents();
diff --git a/alfa-client/libs/ui/src/lib/ui/ozgcloud-paste-text-button/ozgcloud-paste-text-button.component.spec.ts b/alfa-client/libs/ui/src/lib/ui/ozgcloud-paste-text-button/ozgcloud-paste-text-button.component.spec.ts
index 22a817c9b19c19c5c6a5981e94bc533d62759b36..e91b91840bb1f855e5821d6eaac5949bc815181c 100644
--- a/alfa-client/libs/ui/src/lib/ui/ozgcloud-paste-text-button/ozgcloud-paste-text-button.component.spec.ts
+++ b/alfa-client/libs/ui/src/lib/ui/ozgcloud-paste-text-button/ozgcloud-paste-text-button.component.spec.ts
@@ -28,9 +28,9 @@ import { EventEmitter } from '@angular/core';
 import { ComponentFixture, TestBed } from '@angular/core/testing';
 import { MatIcon } from '@angular/material/icon';
 import { MatIconTestingModule } from '@angular/material/icon/testing';
-import { MatTooltipModule } from '@angular/material/tooltip';
+import { TooltipDirective } from '@ods/system';
 import { getDataTestIdOf } from 'libs/tech-shared/test/data-test';
-import { MockComponent, MockModule } from 'ng-mocks';
+import { MockComponent, MockDirective } from 'ng-mocks';
 import { OzgcloudPasteTextButtonComponent } from './ozgcloud-paste-text-button.component';
 
 jest.mock('@alfa-client/tech-shared');
@@ -55,7 +55,7 @@ describe('OzgcloudPasteTextButtonComponent', () => {
         OzgcloudPasteTextButtonComponent,
         MockComponent(MatIcon),
         MockComponent(OzgcloudIconButtonPrimaryComponent),
-        MockModule(MatTooltipModule),
+        MockDirective(TooltipDirective),
       ],
     }).compileComponents();
 
diff --git a/alfa-client/libs/ui/src/lib/ui/slide-toggle/slide-toggle.component.html b/alfa-client/libs/ui/src/lib/ui/slide-toggle/slide-toggle.component.html
index 366854df1b2cb313dc452750c536d10a208bdbb3..8d302a06932bc9a1adfad5834af5bbf3ec69d88f 100644
--- a/alfa-client/libs/ui/src/lib/ui/slide-toggle/slide-toggle.component.html
+++ b/alfa-client/libs/ui/src/lib/ui/slide-toggle/slide-toggle.component.html
@@ -26,7 +26,7 @@
 <mat-slide-toggle
   color="primary"
   [disabled]="disabled"
-  [matTooltip]="toolTip"
+  [tooltip]="toolTip"
   [checked]="checked"
   (change)="valueChanged.emit($event.checked)"
   ><span class="text-sm">{{ label }}</span>
diff --git a/alfa-client/libs/ui/src/lib/ui/slide-toggle/slide-toggle.component.spec.ts b/alfa-client/libs/ui/src/lib/ui/slide-toggle/slide-toggle.component.spec.ts
index 35d63c5fa5c386e8907a09f8a985c36ba555a4dd..39488cb32fad62fe43a90bd77a5a409cbfb41541 100644
--- a/alfa-client/libs/ui/src/lib/ui/slide-toggle/slide-toggle.component.spec.ts
+++ b/alfa-client/libs/ui/src/lib/ui/slide-toggle/slide-toggle.component.spec.ts
@@ -24,8 +24,8 @@
 import { ComponentFixture, TestBed } from '@angular/core/testing';
 import { MatRippleModule } from '@angular/material/core';
 import { MatSlideToggle } from '@angular/material/slide-toggle';
-import { MatTooltipModule } from '@angular/material/tooltip';
-import { MockModule } from 'ng-mocks';
+import { TooltipDirective } from '@ods/system';
+import { MockDirective } from 'ng-mocks';
 import { SlideToggleComponent } from './slide-toggle.component';
 
 describe('SlideToggleComponent', () => {
@@ -35,7 +35,7 @@ describe('SlideToggleComponent', () => {
   beforeEach(async () => {
     await TestBed.configureTestingModule({
       imports: [MatRippleModule, MatSlideToggle],
-      declarations: [SlideToggleComponent, MockModule(MatTooltipModule)],
+      declarations: [SlideToggleComponent, MockDirective(TooltipDirective)],
     }).compileComponents();
 
     fixture = TestBed.createComponent(SlideToggleComponent);
diff --git a/alfa-client/libs/ui/src/lib/ui/ui.module.ts b/alfa-client/libs/ui/src/lib/ui/ui.module.ts
index 1738c23448649c9653efaa1f8f266b4426136286..eeff7417056ee49e49cbe8c4206a2e72aa5dd9a5 100644
--- a/alfa-client/libs/ui/src/lib/ui/ui.module.ts
+++ b/alfa-client/libs/ui/src/lib/ui/ui.module.ts
@@ -46,9 +46,8 @@ import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
 import { MatSlideToggleModule } from '@angular/material/slide-toggle';
 import { MatSnackBarModule } from '@angular/material/snack-bar';
 import { MatTabsModule } from '@angular/material/tabs';
-import { MAT_TOOLTIP_DEFAULT_OPTIONS, MatTooltipModule } from '@angular/material/tooltip';
 import { RouterModule } from '@angular/router';
-import { FileUploadButtonComponent, SpinnerIconComponent } from '@ods/system';
+import { FileUploadButtonComponent, SpinnerIconComponent, TooltipDirective } from '@ods/system';
 import { de } from 'date-fns/locale';
 import { AppIconComponent } from '../icon/app-icon/app-icon.component';
 import { PostfachIconComponent } from '../icon/postfach-icon/postfach-icon.component';
@@ -73,7 +72,6 @@ import { FixedDialogComponent } from './fixed-dialog/fixed-dialog.component';
 import { ConnectionTimeoutRetryDialogComponent } from './http-error-dialog/connection-timeout-retry-dialog/connection-timeout-retry-dialog.component';
 import { ConnectionTimeoutRetryFailDialogComponent } from './http-error-dialog/connection-timeout-retry-fail-dialog/connection-timeout-retry-fail-dialog.component';
 import { IconButtonWithSpinnerComponent } from './icon-button-with-spinner/icon-button-with-spinner.component';
-import { matTooltipDefaultOptions } from './mattooltip/mattooltip.default';
 import { InternalServerErrorDialogComponent } from './notification/internal-server-error-dialog/internal-server-error-dialog.component';
 import { OpenUrlButtonComponent } from './open-url-button/open-url-button.component';
 import { OzgcloudButtonWithSpinnerComponent } from './ozgcloud-button/ozgcloud-button-with-spinner/ozgcloud-button-with-spinner.component';
@@ -156,7 +154,6 @@ import { ValidationErrorComponent } from './validation-error/validation-error.co
     MatAutocompleteModule,
     MatDialogModule,
     MatTabsModule,
-    MatTooltipModule,
     MatBadgeModule,
     CommonModule,
     TechSharedModule,
@@ -164,6 +161,7 @@ import { ValidationErrorComponent } from './validation-error/validation-error.co
     MatButtonToggleModule,
     FileUploadButtonComponent,
     SpinnerIconComponent,
+    TooltipDirective,
   ],
   exports: [
     MatButtonModule,
@@ -186,7 +184,6 @@ import { ValidationErrorComponent } from './validation-error/validation-error.co
     MatAutocompleteModule,
     MatDialogModule,
     MatTabsModule,
-    MatTooltipModule,
     MatBadgeModule,
     CommonModule,
     TechSharedModule,
@@ -253,7 +250,6 @@ import { ValidationErrorComponent } from './validation-error/validation-error.co
       useClass: DateFnsAdapter,
       deps: [MAT_DATE_LOCALE],
     },
-    { provide: MAT_TOOLTIP_DEFAULT_OPTIONS, useValue: matTooltipDefaultOptions },
   ],
 })
 export class UiModule {}
diff --git a/alfa-client/libs/user-profile/src/lib/link-with-user-name-tooltip-container/link-with-user-name-tooltip/link-with-user-name-tooltip.component.html b/alfa-client/libs/user-profile/src/lib/link-with-user-name-tooltip-container/link-with-user-name-tooltip/link-with-user-name-tooltip.component.html
index df527af17224d0db0a84f10f81052589f4b0485b..8789fcac61ca88a8a0d8b96204aa967c1b7fc606 100644
--- a/alfa-client/libs/user-profile/src/lib/link-with-user-name-tooltip-container/link-with-user-name-tooltip/link-with-user-name-tooltip.component.html
+++ b/alfa-client/libs/user-profile/src/lib/link-with-user-name-tooltip-container/link-with-user-name-tooltip/link-with-user-name-tooltip.component.html
@@ -23,6 +23,6 @@
     unter der Lizenz sind dem Lizenztext zu entnehmen.
 
 -->
-<a routerLink="{{ routerLinkString }}" [matTooltip]="tooltip" class="link">
+<a routerLink="{{ routerLinkString }}" [tooltip]="tooltip" class="link">
   <ng-content></ng-content>
 </a>
diff --git a/alfa-client/libs/user-profile/src/lib/link-with-user-name-tooltip-container/link-with-user-name-tooltip/link-with-user-name-tooltip.component.spec.ts b/alfa-client/libs/user-profile/src/lib/link-with-user-name-tooltip-container/link-with-user-name-tooltip/link-with-user-name-tooltip.component.spec.ts
index ce240696e45f53cab52a250b9222facdd53094fb..6907e8674b1417d075237a4975c2ce0f1dd4295c 100644
--- a/alfa-client/libs/user-profile/src/lib/link-with-user-name-tooltip-container/link-with-user-name-tooltip/link-with-user-name-tooltip.component.spec.ts
+++ b/alfa-client/libs/user-profile/src/lib/link-with-user-name-tooltip-container/link-with-user-name-tooltip/link-with-user-name-tooltip.component.spec.ts
@@ -24,10 +24,10 @@
 import { createStateResource } from '@alfa-client/tech-shared';
 import { UserProfileResource } from '@alfa-client/user-profile-shared';
 import { ComponentFixture, TestBed } from '@angular/core/testing';
-import { MatTooltipModule } from '@angular/material/tooltip';
 import { RouterTestingModule } from '@angular/router/testing';
+import { TooltipDirective } from '@ods/system';
 import { createUserProfileResource } from 'libs/user-profile-shared/test/user-profile';
-import { MockModule } from 'ng-mocks';
+import { MockDirective } from 'ng-mocks';
 import { LinkWithUserNameTooltipComponent } from './link-with-user-name-tooltip.component';
 
 describe('LinkWithUserNameTooltipComponent', () => {
@@ -40,7 +40,7 @@ describe('LinkWithUserNameTooltipComponent', () => {
   beforeEach(async () => {
     await TestBed.configureTestingModule({
       imports: [RouterTestingModule],
-      declarations: [LinkWithUserNameTooltipComponent, MockModule(MatTooltipModule)],
+      declarations: [LinkWithUserNameTooltipComponent, MockDirective(TooltipDirective)],
     }).compileComponents();
   });
 
diff --git a/alfa-client/libs/user-profile/src/lib/text-with-user-name-tooltip-container/text-with-user-name-tooltip/text-with-user-name-tooltip.component.html b/alfa-client/libs/user-profile/src/lib/text-with-user-name-tooltip-container/text-with-user-name-tooltip/text-with-user-name-tooltip.component.html
index 27535f64fdc19260a6eae325f3e1f4f2334a9b83..d659fff0fa6e49f8332bef42998e9da5fd6ae992 100644
--- a/alfa-client/libs/user-profile/src/lib/text-with-user-name-tooltip-container/text-with-user-name-tooltip/text-with-user-name-tooltip.component.html
+++ b/alfa-client/libs/user-profile/src/lib/text-with-user-name-tooltip-container/text-with-user-name-tooltip/text-with-user-name-tooltip.component.html
@@ -23,4 +23,4 @@
     unter der Lizenz sind dem Lizenztext zu entnehmen.
 
 -->
-<p [matTooltip]="tooltip">{{ text }}</p>
+<p [tooltip]="tooltip">{{ text }}</p>
diff --git a/alfa-client/libs/user-profile/src/lib/text-with-user-name-tooltip-container/text-with-user-name-tooltip/text-with-user-name-tooltip.component.spec.ts b/alfa-client/libs/user-profile/src/lib/text-with-user-name-tooltip-container/text-with-user-name-tooltip/text-with-user-name-tooltip.component.spec.ts
index 9fd7e0083708d0957f4d55df8fad4bf7a6257c6e..23163b82f8921f720872808dc86348c65b83dad8 100644
--- a/alfa-client/libs/user-profile/src/lib/text-with-user-name-tooltip-container/text-with-user-name-tooltip/text-with-user-name-tooltip.component.spec.ts
+++ b/alfa-client/libs/user-profile/src/lib/text-with-user-name-tooltip-container/text-with-user-name-tooltip/text-with-user-name-tooltip.component.spec.ts
@@ -24,9 +24,9 @@
 import { createStateResource } from '@alfa-client/tech-shared';
 import { UserProfileResource } from '@alfa-client/user-profile-shared';
 import { ComponentFixture, TestBed } from '@angular/core/testing';
-import { MatTooltipModule } from '@angular/material/tooltip';
+import { TooltipDirective } from '@ods/system';
 import { createUserProfileResource } from 'libs/user-profile-shared/test/user-profile';
-import { MockModule } from 'ng-mocks';
+import { MockDirective } from 'ng-mocks';
 import { TextWithUserNameTooltipComponent } from './text-with-user-name-tooltip.component';
 
 describe('TextWithUserNameTooltipComponent', () => {
@@ -38,7 +38,7 @@ describe('TextWithUserNameTooltipComponent', () => {
 
   beforeEach(async () => {
     await TestBed.configureTestingModule({
-      declarations: [TextWithUserNameTooltipComponent, MockModule(MatTooltipModule)],
+      declarations: [TextWithUserNameTooltipComponent, MockDirective(TooltipDirective)],
     }).compileComponents();
   });
 
diff --git a/alfa-client/libs/user-profile/src/lib/user-icon/user-icon.component.html b/alfa-client/libs/user-profile/src/lib/user-icon/user-icon.component.html
index d5b5d476d5720e7005f3c70871d57b9a1d376f47..a6866ab9d0a536f9c4af983e893e4408600efb69 100644
--- a/alfa-client/libs/user-profile/src/lib/user-icon/user-icon.component.html
+++ b/alfa-client/libs/user-profile/src/lib/user-icon/user-icon.component.html
@@ -25,11 +25,10 @@
 -->
 <ozgcloud-spinner [stateResource]="userProfileStateResource" diameter="30" padding="3">
   <div
-    [matTooltipDisabled]="disableTooltip"
     data-test-class="user-profile-icon"
     class="relative flex size-9 items-center justify-center overflow-hidden rounded-full text-lg text-white"
     [class.bg-ozggray-900]="userProfileStateResource.resource || errorMessageCode === messageCode.RESOURCE_NOT_FOUND"
-    [matTooltip]="tooltip"
+    [tooltip]="tooltip"
   >
     <ng-container *ngIf="userProfileStateResource.resource; else noUser">
       <span data-test-class="user-profile-assigned">{{ initials }}</span>
diff --git a/alfa-client/libs/user-profile/src/lib/user-icon/user-icon.component.spec.ts b/alfa-client/libs/user-profile/src/lib/user-icon/user-icon.component.spec.ts
index c4a359cdc07d4b7e08c992414ba82bf33c191665..5a26a51d01121a4d0c41f18a75d49b03df411b00 100644
--- a/alfa-client/libs/user-profile/src/lib/user-icon/user-icon.component.spec.ts
+++ b/alfa-client/libs/user-profile/src/lib/user-icon/user-icon.component.spec.ts
@@ -34,12 +34,11 @@ import { SpinnerComponent } from '@alfa-client/ui';
 import { NO_NAME_MESSAGE, UserProfileResource, userProfileMessage } from '@alfa-client/user-profile-shared';
 import { ComponentFixture, TestBed } from '@angular/core/testing';
 import { MatIcon } from '@angular/material/icon';
-import { MatTooltipModule } from '@angular/material/tooltip';
 import { faker } from '@faker-js/faker';
-import { ErrorIconComponent, UserIconComponent as OdsUserIconComponent } from '@ods/system';
+import { ErrorIconComponent, UserIconComponent as OdsUserIconComponent, TooltipDirective } from '@ods/system';
 import { getDataTestClassOf } from 'libs/tech-shared/test/data-test';
 import { createUserProfileResource } from 'libs/user-profile-shared/test/user-profile';
-import { MockComponent, MockModule } from 'ng-mocks';
+import { MockComponent, MockDirective } from 'ng-mocks';
 import { createApiError, createIssue } from '../../../../tech-shared/test/error';
 import { UserIconComponent } from './user-icon.component';
 
@@ -60,7 +59,7 @@ describe('UserIconComponent', () => {
         UserIconComponent,
         MatIcon,
         MockComponent(SpinnerComponent),
-        MockModule(MatTooltipModule),
+        MockDirective(TooltipDirective),
         MockComponent(ErrorIconComponent),
         MockComponent(OdsUserIconComponent),
       ],
diff --git a/alfa-client/libs/user-profile/src/lib/user-icon/user-icon.component.ts b/alfa-client/libs/user-profile/src/lib/user-icon/user-icon.component.ts
index a691fdefc542600e33cdac2b9a3b0864fd59c3f8..787e1e16eabcd6eedb875ed7e203f229bfcc9df1 100644
--- a/alfa-client/libs/user-profile/src/lib/user-icon/user-icon.component.ts
+++ b/alfa-client/libs/user-profile/src/lib/user-icon/user-icon.component.ts
@@ -32,7 +32,6 @@ import { isUndefined } from 'lodash-es';
 })
 export class UserIconComponent {
   @Input() userProfileStateResource: StateResource<UserProfileResource> = createEmptyStateResource<UserProfileResource>();
-  @Input() disableTooltip: boolean = false;
 
   readonly messageCode = MessageCode;
 
diff --git a/alfa-client/libs/user-profile/src/lib/user-profile-in-header-container/user-profile-in-header/user-profile-in-header.component.html b/alfa-client/libs/user-profile/src/lib/user-profile-in-header-container/user-profile-in-header/user-profile-in-header.component.html
index 8808114310f78fe0a7addeb9417dc889456a6e21..a2aac078aaf9d5fc6783864da5b363cf460d9bee 100644
--- a/alfa-client/libs/user-profile/src/lib/user-profile-in-header-container/user-profile-in-header/user-profile-in-header.component.html
+++ b/alfa-client/libs/user-profile/src/lib/user-profile-in-header-container/user-profile-in-header/user-profile-in-header.component.html
@@ -26,16 +26,17 @@
 <ods-dropdown-menu
   buttonClass="rounded-full p-1 hover:bg-neutral-100 focus:bg-neutral-200 focus:outline-none dark:hover:bg-neutral-700 dark:focus:bg-neutral-600"
   [label]="buttonLabel"
+  buttonTestId="user-icon-button"
   data-test-id="user-icon-dropdown-menu"
 >
   <alfa-user-icon
     button-content
-    data-test-id="user-icon-button"
+    data-test-id="user-icon"
     [userProfileStateResource]="currentUserResource"
     class="user-profile-icon"
   >
   </alfa-user-icon>
-  <ods-dropdown-menu-button-item caption="Abmelden" (itemClicked)="logoutEmitter.emit()" data-test-id="logout-button">
+  <ods-dropdown-menu-button-item caption="Abmelden" (itemClicked)="logoutEmitter.emit()" dataTestId="logout-button">
     <ods-logout-icon icon />
   </ods-dropdown-menu-button-item>
 </ods-dropdown-menu>
diff --git a/alfa-client/libs/user-profile/src/lib/user-profile-in-header-container/user-profile-in-header/user-profile-in-header.component.spec.ts b/alfa-client/libs/user-profile/src/lib/user-profile-in-header-container/user-profile-in-header/user-profile-in-header.component.spec.ts
index 536a5722d27b6afced3eb3d91b8c1bfc0fc163db..1f91ba4533ee9c3ee1b09102a7df8deb9de9b849 100644
--- a/alfa-client/libs/user-profile/src/lib/user-profile-in-header-container/user-profile-in-header/user-profile-in-header.component.spec.ts
+++ b/alfa-client/libs/user-profile/src/lib/user-profile-in-header-container/user-profile-in-header/user-profile-in-header.component.spec.ts
@@ -30,7 +30,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
 import { MatIcon } from '@angular/material/icon';
 import { NoopAnimationsModule } from '@angular/platform-browser/animations';
 import { DropdownMenuButtonItemComponent, DropdownMenuComponent, LogoutIconComponent } from '@ods/system';
-import { getDataTestIdOf } from 'libs/tech-shared/test/data-test';
+import { getDataTestIdAttributeOf, getDataTestIdOf } from 'libs/tech-shared/test/data-test';
 import { createUserProfileResource } from 'libs/user-profile-shared/test/user-profile';
 import { MockComponent } from 'ng-mocks';
 import { UserProfileInHeaderComponent } from './user-profile-in-header.component';
@@ -39,7 +39,7 @@ describe('UserProfileInHeaderComponent', () => {
   let component: UserProfileInHeaderComponent;
   let fixture: ComponentFixture<UserProfileInHeaderComponent>;
 
-  const logoutButton: string = getDataTestIdOf('logout-button');
+  const logoutButton: string = getDataTestIdAttributeOf('logout-button');
   const userIconDropDownMenu: string = getDataTestIdOf('user-icon-dropdown-menu');
 
   const userProfile: UserProfileResource = createUserProfileResource();
diff --git a/alfa-client/libs/user-profile/src/lib/user-profile.module.ts b/alfa-client/libs/user-profile/src/lib/user-profile.module.ts
index 6bd1588ea1c21f419e2e78828ab9a466f0add14f..11ab2e9213281a32febbbd4664fa79d59d4969f4 100644
--- a/alfa-client/libs/user-profile/src/lib/user-profile.module.ts
+++ b/alfa-client/libs/user-profile/src/lib/user-profile.module.ts
@@ -34,6 +34,7 @@ import {
   ErrorIconComponent,
   LogoutIconComponent,
   UserIconComponent as OdsUserIconComponent,
+  TooltipDirective,
 } from '@ods/system';
 import { AssignUserProfileButtonContainerComponent } from './assign-user-profile-button-container/assign-user-profile-button-container.component';
 import { LinkWithUserNameTooltipContainerComponent } from './link-with-user-name-tooltip-container/link-with-user-name-tooltip-container.component';
@@ -68,6 +69,7 @@ import { UserProfileComponent } from './user-profile/user-profile.component';
     DropdownMenuComponent,
     DropdownMenuItemComponent,
     DropdownMenuButtonItemComponent,
+    TooltipDirective,
   ],
   declarations: [
     UserIconComponent,
diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-action-buttons/vorgang-detail-action-buttons.component.scss b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-action-buttons/vorgang-detail-action-buttons.component.scss
index cbc6bcde3a27788c790ba3e0e879ee27b28881b7..073c7c4392d2b1dd921d4ac949942297033a68c4 100644
--- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-action-buttons/vorgang-detail-action-buttons.component.scss
+++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-action-buttons/vorgang-detail-action-buttons.component.scss
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch den
+ * Copyright (C) 2025 Das Land Schleswig-Holstein vertreten durch den
  * Ministerpräsidenten des Landes Schleswig-Holstein
  * Staatskanzlei
  * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
@@ -24,6 +24,7 @@
 :host {
   display: flex;
   flex-grow: 1;
+  z-index: 1;
 
   ::ng-deep {
     a {
diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-back-button-container/vorgang-detail-back-button-container.component.scss b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-back-button-container/vorgang-detail-back-button-container.component.scss
index 54c4f3eb8c92af93694c03cdf577fed23cf9f86b..d3c1422dbfc51198d27b9a9abf05525c6c3b3196 100644
--- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-back-button-container/vorgang-detail-back-button-container.component.scss
+++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-back-button-container/vorgang-detail-back-button-container.component.scss
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch den
+ * Copyright (C) 2025 Das Land Schleswig-Holstein vertreten durch den
  * Ministerpräsidenten des Landes Schleswig-Holstein
  * Staatskanzlei
  * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
@@ -21,3 +21,6 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
+:host {
+  z-index: 1;
+}
diff --git a/alfa-client/libs/vorgang-shared-ui/src/lib/aktenzeichen/aktenzeichen.component.html b/alfa-client/libs/vorgang-shared-ui/src/lib/aktenzeichen/aktenzeichen.component.html
index a68da5c1302fdc7e652ecfdd960550162eb795c1..8c0250145675de160686ed311fd4ee34fc76b181 100644
--- a/alfa-client/libs/vorgang-shared-ui/src/lib/aktenzeichen/aktenzeichen.component.html
+++ b/alfa-client/libs/vorgang-shared-ui/src/lib/aktenzeichen/aktenzeichen.component.html
@@ -26,7 +26,7 @@
 <div
   class="line-clamp-1 flex-shrink overflow-hidden break-all text-base font-normal lg:line-clamp-none lg:flex"
   data-test-id="aktenzeichen"
-  [matTooltip]="aktenzeichen"
+  [tooltip]="aktenzeichen"
 >
   {{ aktenzeichen }}
 </div>
diff --git a/alfa-client/libs/vorgang-shared-ui/src/lib/aktenzeichen/aktenzeichen.component.spec.ts b/alfa-client/libs/vorgang-shared-ui/src/lib/aktenzeichen/aktenzeichen.component.spec.ts
index be991fb41f4c0b6b9282959b28478160a33a56aa..d2fa4010f6b41217c0e0a3c16467012c83f7d7af 100644
--- a/alfa-client/libs/vorgang-shared-ui/src/lib/aktenzeichen/aktenzeichen.component.spec.ts
+++ b/alfa-client/libs/vorgang-shared-ui/src/lib/aktenzeichen/aktenzeichen.component.spec.ts
@@ -23,9 +23,9 @@
  */
 import { VorgangResource } from '@alfa-client/vorgang-shared';
 import { ComponentFixture, TestBed } from '@angular/core/testing';
-import { MatTooltipModule } from '@angular/material/tooltip';
+import { TooltipDirective } from '@ods/system';
 import { createVorgangResource } from 'libs/vorgang-shared/test/vorgang';
-import { MockModule } from 'ng-mocks';
+import { MockDirective } from 'ng-mocks';
 import { VORGANG_KEIN_AKTENZEICHEN_ZUGEWIESEN } from '../vorgang-util';
 import { AktenzeichenComponent } from './aktenzeichen.component';
 
@@ -39,7 +39,7 @@ describe('AktenzeichenComponent', () => {
 
   beforeEach(async () => {
     await TestBed.configureTestingModule({
-      declarations: [AktenzeichenComponent, MockModule(MatTooltipModule)],
+      declarations: [AktenzeichenComponent, MockDirective(TooltipDirective)],
     }).compileComponents();
   });
 
diff --git a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-nummer/vorgang-nummer.component.html b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-nummer/vorgang-nummer.component.html
index b6c4a666d805ca9138db7480ad8b35aef0f64bc3..3a5eabc30c87191c1257dc4952ce8d5ba65b2ab9 100644
--- a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-nummer/vorgang-nummer.component.html
+++ b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-nummer/vorgang-nummer.component.html
@@ -29,7 +29,7 @@
 <div
   class="line-clamp-1 flex-shrink overflow-hidden break-all text-base font-normal lg:line-clamp-none lg:flex"
   data-test-id="vorgang-nummer"
-  [matTooltip]="vorgang.nummer"
+  [tooltip]="vorgang.nummer"
 >
   {{ vorgang.nummer }}
 </div>
diff --git a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-nummer/vorgang-nummer.component.spec.ts b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-nummer/vorgang-nummer.component.spec.ts
index c92ef713ea14d618417ee0e3d52b92597d105f48..c6b0813916c7f1dacd623532a7bbc78a31a7ffa6 100644
--- a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-nummer/vorgang-nummer.component.spec.ts
+++ b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-nummer/vorgang-nummer.component.spec.ts
@@ -26,10 +26,10 @@ import { VorgangResource } from '@alfa-client/vorgang-shared';
 import { ComponentFixture, TestBed } from '@angular/core/testing';
 import { MatIcon } from '@angular/material/icon';
 import { MatIconTestingModule } from '@angular/material/icon/testing';
-import { MatTooltipModule } from '@angular/material/tooltip';
+import { TooltipDirective } from '@ods/system';
 import { getDataTestIdOf } from 'libs/tech-shared/test/data-test';
 import { createVorgangResource } from 'libs/vorgang-shared/test/vorgang';
-import { MockModule } from 'ng-mocks';
+import { MockDirective } from 'ng-mocks';
 import { VorgangNummerComponent } from './vorgang-nummer.component';
 
 describe('VorgangNummerComponent', () => {
@@ -41,7 +41,7 @@ describe('VorgangNummerComponent', () => {
 
   beforeEach(async () => {
     await TestBed.configureTestingModule({
-      declarations: [MockModule(MatTooltipModule), VorgangNummerComponent],
+      declarations: [MockDirective(TooltipDirective), VorgangNummerComponent],
       imports: [MatIcon, MatIconTestingModule],
     }).compileComponents();
   });
diff --git a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-shared-ui.module.ts b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-shared-ui.module.ts
index 3ae0643465d4492367f4787a699453b7ebe1a799..a6549aff7c59fa5979d55f7fbb7bb130b9c068fc 100644
--- a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-shared-ui.module.ts
+++ b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-shared-ui.module.ts
@@ -27,6 +27,7 @@ import { VorgangSharedModule } from '@alfa-client/vorgang-shared';
 import { CommonModule } from '@angular/common';
 import { NgModule } from '@angular/core';
 import { RouterModule } from '@angular/router';
+import { TooltipDirective } from '@ods/system';
 import { AktenzeichenComponent } from './aktenzeichen/aktenzeichen.component';
 import { VorgangNummerComponent } from './vorgang-nummer/vorgang-nummer.component';
 import { VorgangSearchContainerComponent } from './vorgang-search-container/vorgang-search-container.component';
@@ -38,7 +39,7 @@ import { VorgangStatusTextComponent } from './vorgang-status-text/vorgang-status
 import { WiedervorlageIconComponent } from './wiedervorlage-icon/wiedervorlage-icon.component';
 
 @NgModule({
-  imports: [CommonModule, VorgangSharedModule, UiModule, RouterModule, TechSharedModule],
+  imports: [CommonModule, VorgangSharedModule, UiModule, RouterModule, TechSharedModule, TooltipDirective],
   declarations: [
     VorgangSearchContainerComponent,
     VorgangSearchComponent,
diff --git a/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-created-at/vorgang-created-at.component.html b/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-created-at/vorgang-created-at.component.html
index bbf247957fa5a6a1be70c6ec1af5e88c75ccad33..edfe41eb178ce5a0f3dddefc33585fe2e465c96b 100644
--- a/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-created-at/vorgang-created-at.component.html
+++ b/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-created-at/vorgang-created-at.component.html
@@ -23,7 +23,7 @@
     unter der Lizenz sind dem Lizenztext zu entnehmen.
 
 -->
-<div matTooltip="Eingang: {{ vorgang.createdAt | formatDateWithTimePipe }}">
+<div tooltip="Eingang: {{ vorgang.createdAt | formatDateWithTimePipe }}">
   <mat-icon svgIcon="incoming"></mat-icon>
   <span data-test-id="created-at">{{ vorgang.createdAt | formatDateWithoutYearWithTime }}</span>
 </div>
diff --git a/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-created-at/vorgang-created-at.component.spec.ts b/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-created-at/vorgang-created-at.component.spec.ts
index 01dce45c92b20a216875e28e00370fcd0a5bf490..b551e0550b2ce804d1a28a22416428c704b1cbc2 100644
--- a/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-created-at/vorgang-created-at.component.spec.ts
+++ b/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-created-at/vorgang-created-at.component.spec.ts
@@ -33,10 +33,10 @@ import localeDe from '@angular/common/locales/de';
 import { ComponentFixture, TestBed } from '@angular/core/testing';
 import { MatIcon } from '@angular/material/icon';
 import { MatIconTestingModule } from '@angular/material/icon/testing';
-import { MatTooltipModule } from '@angular/material/tooltip';
+import { TooltipDirective } from '@ods/system';
 import { getDataTestIdOf } from 'libs/tech-shared/test/data-test';
 import { createVorgangResource } from 'libs/vorgang-shared/test/vorgang';
-import { MockModule } from 'ng-mocks';
+import { MockDirective } from 'ng-mocks';
 import { VorgangCreatedAtComponent } from './vorgang-created-at.component';
 
 registerLocaleData(localeDe);
@@ -54,7 +54,7 @@ describe('VorgangCreatedAtComponent', () => {
         FormatDateWithoutYearWithTimePipe,
         FormatDateWithTimePipe,
         VorgangCreatedAtComponent,
-        MockModule(MatTooltipModule),
+        MockDirective(TooltipDirective),
       ],
       imports: [MatIcon, MatIconTestingModule],
     }).compileComponents();
diff --git a/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-list-item.component.spec.ts b/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-list-item.component.spec.ts
index 19cf045603cf83efe2acddffaabc484dd7c63f2c..cfab40f848188662f2d0f2ea1db7074d60ff7ef7 100644
--- a/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-list-item.component.spec.ts
+++ b/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-list-item.component.spec.ts
@@ -48,12 +48,11 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
 import { MAT_DATE_LOCALE } from '@angular/material/core';
 import { MatIcon } from '@angular/material/icon';
 import { MatIconTestingModule } from '@angular/material/icon/testing';
-import { MatTooltipModule } from '@angular/material/tooltip';
 import { RouterTestingModule } from '@angular/router/testing';
 import { getDataTestClassOf, getDataTestIdOf } from 'libs/tech-shared/test/data-test';
 import { createUserProfileResource } from 'libs/user-profile-shared/test/user-profile';
 import { createVorgangResource } from 'libs/vorgang-shared/test/vorgang';
-import { MockComponent, MockModule } from 'ng-mocks';
+import { MockComponent } from 'ng-mocks';
 import { of } from 'rxjs';
 import { VorgangArchiveStatusComponent } from './vorgang-archive-status/vorgang-archive-status.component';
 import { VorgangBescheidStatusComponent } from './vorgang-bescheid-status/vorgang-bescheid-status.component';
@@ -97,7 +96,6 @@ describe('VorgangListItemComponent', () => {
         MockComponent(VorgangCreatedAtComponent),
         MockComponent(VorgangBescheidStatusComponent),
         MockComponent(VorgangArchiveStatusComponent),
-        MockModule(MatTooltipModule),
       ],
       providers: [
         { provide: UserProfileService, useValue: userProfileService },
diff --git a/alfa-client/libs/vorgang/src/lib/vorgang.module.ts b/alfa-client/libs/vorgang/src/lib/vorgang.module.ts
index 4a58042a60125194bd7fd2b2b4953188c1f4aa28..cf3421cb9ed957b151e3cf8948828bde38b7f6b1 100644
--- a/alfa-client/libs/vorgang/src/lib/vorgang.module.ts
+++ b/alfa-client/libs/vorgang/src/lib/vorgang.module.ts
@@ -34,7 +34,7 @@ import { NgModule } from '@angular/core';
 import { MatButtonToggleModule } from '@angular/material/button-toggle';
 import { RouterModule, Routes } from '@angular/router';
 import { ButtonToggleGroupComponent } from '@ods/component';
-import { ArchiveIconComponent, ButtonToggleComponent } from '@ods/system';
+import { ArchiveIconComponent, ButtonToggleComponent, TooltipDirective } from '@ods/system';
 import { vorgangFilterViewGuard } from './vorgang-filter-view.guard';
 import { VorgangListContainerComponent } from './vorgang-list-container/vorgang-list-container.component';
 import { EmptyListComponent } from './vorgang-list-container/vorgang-list/empty-list/empty-list.component';
@@ -182,6 +182,7 @@ const routes: Routes = [
     ButtonToggleComponent,
     ButtonToggleGroupComponent,
     ArchiveIconComponent,
+    TooltipDirective,
   ],
   declarations: [
     VorgangListComponent,
diff --git a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-container/wiedervorlage-list-in-vorgang/wiedervorlage-in-vorgang/wiedervorlage-in-vorgang.component.html b/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-container/wiedervorlage-list-in-vorgang/wiedervorlage-in-vorgang/wiedervorlage-in-vorgang.component.html
index 04ee9bbaeebc4f00c72b095b49a514b4f652aa16..bdef88d210bb2d4b5e240b70f638a0efeb10c9e3 100644
--- a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-container/wiedervorlage-list-in-vorgang/wiedervorlage-in-vorgang/wiedervorlage-in-vorgang.component.html
+++ b/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-container/wiedervorlage-list-in-vorgang/wiedervorlage-in-vorgang/wiedervorlage-in-vorgang.component.html
@@ -30,7 +30,7 @@
   <div class="row">
     <alfa-wiedervorlage-status
       data-test-class="status"
-      [matTooltip]="wiedervorlageResource.frist | toTrafficLightTooltip"
+      [tooltip]="wiedervorlageResource.frist | toTrafficLightTooltip"
       [wiedervorlageResource]="wiedervorlageResource"
     >
     </alfa-wiedervorlage-status>
diff --git a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-container/wiedervorlage-list-in-vorgang/wiedervorlage-in-vorgang/wiedervorlage-in-vorgang.component.spec.ts b/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-container/wiedervorlage-list-in-vorgang/wiedervorlage-in-vorgang/wiedervorlage-in-vorgang.component.spec.ts
index 5d7273682e8e067353ec1a1ff5ca47d9f9fc393a..6673dc39b36123bb4d9bdd8bbb3e06e1e1dc2dc1 100644
--- a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-container/wiedervorlage-list-in-vorgang/wiedervorlage-in-vorgang/wiedervorlage-in-vorgang.component.spec.ts
+++ b/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-container/wiedervorlage-list-in-vorgang/wiedervorlage-in-vorgang/wiedervorlage-in-vorgang.component.spec.ts
@@ -43,10 +43,10 @@ import { LOCALE_ID } from '@angular/core';
 import { ComponentFixture, TestBed } from '@angular/core/testing';
 import { MAT_DATE_LOCALE } from '@angular/material/core';
 import { MatIcon } from '@angular/material/icon';
-import { MatTooltipModule } from '@angular/material/tooltip';
 import { RouterTestingModule } from '@angular/router/testing';
+import { TooltipDirective } from '@ods/system';
 import { createWiedervorlageResource } from 'libs/wiedervorlage-shared/test/wiedervorlage';
-import { MockComponent, MockModule } from 'ng-mocks';
+import { MockComponent, MockDirective } from 'ng-mocks';
 import { WiedervorlageStatusComponent } from '../../../wiedervorlage-status/wiedervorlage-status.component';
 import { WiedervorlageAttachmentListContainerComponent } from './wiedervorlage-attachment-list-container/wiedervorlage-attachment-list-container.component';
 import { WiedervorlageInVorgangExpandButtonComponent } from './wiedervorlage-in-vorgang-expand-button/wiedervorlage-in-vorgang-expand-button.component';
@@ -78,7 +78,7 @@ describe('WiedervorlageInVorgangComponent', () => {
         MockComponent(WiedervorlageInVorgangExpandButtonComponent),
         MockComponent(LinkWithUserNameTooltipContainerComponent),
         MockComponent(TextWithUserNameTooltipContainerComponent),
-        MockModule(MatTooltipModule),
+        MockDirective(TooltipDirective),
       ],
       imports: [RouterTestingModule],
       providers: [
diff --git a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-list-container/wiedervorlage-list-in-vorgang-list-container.component.html b/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-list-container/wiedervorlage-list-in-vorgang-list-container.component.html
index 30f5ee2bb76434da75135c98eea8eff8141f52ef..d70d62eca2546b3e4e322a16040e18b403e70b7e 100644
--- a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-list-container/wiedervorlage-list-in-vorgang-list-container.component.html
+++ b/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-list-container/wiedervorlage-list-in-vorgang-list-container.component.html
@@ -37,7 +37,7 @@
       <td>
         <div class="status">
           <alfa-wiedervorlage-status
-            [matTooltip]="wiedervorlageResource.frist | toTrafficLightTooltip"
+            [tooltip]="wiedervorlageResource.frist | toTrafficLightTooltip"
             [wiedervorlageResource]="wiedervorlageResource"
             data-test-class="status"
           >
diff --git a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-list-container/wiedervorlage-list-in-vorgang-list-container.component.spec.ts b/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-list-container/wiedervorlage-list-in-vorgang-list-container.component.spec.ts
index e3a91dc026d83280f12fdc55a05d220a01e85a47..9ae9dd5c0812065834a9802f17fcc27883f757f0 100644
--- a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-list-container/wiedervorlage-list-in-vorgang-list-container.component.spec.ts
+++ b/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-list-in-vorgang-list-container/wiedervorlage-list-in-vorgang-list-container.component.spec.ts
@@ -29,9 +29,9 @@ import {
 import { mock } from '@alfa-client/test-utils';
 import { WiedervorlageService } from '@alfa-client/wiedervorlage-shared';
 import { ComponentFixture, TestBed } from '@angular/core/testing';
-import { MatTooltipModule } from '@angular/material/tooltip';
+import { TooltipDirective } from '@ods/system';
 import { createWiedervorlageListResource } from 'libs/wiedervorlage-shared/test/wiedervorlage';
-import { MockComponent, MockModule } from 'ng-mocks';
+import { MockComponent, MockDirective } from 'ng-mocks';
 import { of } from 'rxjs';
 import { WiedervorlageStatusComponent } from '../wiedervorlage-status/wiedervorlage-status.component';
 import { WiedervorlageListInVorgangListContainerComponent } from './wiedervorlage-list-in-vorgang-list-container.component';
@@ -52,7 +52,7 @@ describe('WiedervorlageListInVorgangListContainerComponent', () => {
         FormatToPrettyDatePipe,
         ToTrafficLightTooltipPipe,
         MockComponent(WiedervorlageStatusComponent),
-        MockModule(MatTooltipModule),
+        MockDirective(TooltipDirective),
       ],
       providers: [
         {
diff --git a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-status/wiedervorlage-status.component.spec.ts b/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-status/wiedervorlage-status.component.spec.ts
index 92614350fe078c2e66fb3a659050a551eedc9daf..ab2dd54f9740cb097bff0679157bc920bf8e762e 100644
--- a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-status/wiedervorlage-status.component.spec.ts
+++ b/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage-status/wiedervorlage-status.component.spec.ts
@@ -24,9 +24,7 @@
 import { ToTrafficLightPipe } from '@alfa-client/tech-shared';
 import { ComponentFixture, TestBed } from '@angular/core/testing';
 import { MatIcon } from '@angular/material/icon';
-import { MatTooltipModule } from '@angular/material/tooltip';
 import { createWiedervorlageResource } from 'libs/wiedervorlage-shared/test/wiedervorlage';
-import { MockModule } from 'ng-mocks';
 import { WiedervorlageStatusComponent } from './wiedervorlage-status.component';
 
 const doneIcon: string = '[data-test-class="done-icon"]';
@@ -37,12 +35,8 @@ describe('WiedervorlageStatusComponent', () => {
 
   beforeEach(async () => {
     await TestBed.configureTestingModule({
-      declarations: [
-        WiedervorlageStatusComponent,
-        ToTrafficLightPipe,
-        MatIcon,
-        MockModule(MatTooltipModule),
-      ],
+      declarations: [WiedervorlageStatusComponent, ToTrafficLightPipe],
+      imports: [MatIcon],
     }).compileComponents();
   });
 
diff --git a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage.module.ts b/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage.module.ts
index 73ccc935276138242f2e14f9d14aadf427bdf54b..fec88f242f4f485bf156ef60e5fe897c210b0f59 100644
--- a/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage.module.ts
+++ b/alfa-client/libs/wiedervorlage/src/lib/wiedervorlage.module.ts
@@ -21,15 +21,16 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-import { CommonModule, DatePipe } from '@angular/common';
-import { NgModule } from '@angular/core';
-import { RouterModule, Routes } from '@angular/router';
 import { BinaryFileModule } from '@alfa-client/binary-file';
 import { TechSharedModule } from '@alfa-client/tech-shared';
 import { UiModule } from '@alfa-client/ui';
 import { UserProfileModule } from '@alfa-client/user-profile';
 import { VorgangSharedModule } from '@alfa-client/vorgang-shared';
 import { VorgangSharedUiModule } from '@alfa-client/vorgang-shared-ui';
+import { CommonModule, DatePipe } from '@angular/common';
+import { NgModule } from '@angular/core';
+import { RouterModule, Routes } from '@angular/router';
+import { TooltipDirective } from '@ods/system';
 import { CreateWiedervorlageButtonContainerComponent } from './create-wiedervorlage-button-container/create-wiedervorlage-button-container.component';
 import { ErledigenButtonContainerComponent } from './erledigen-button-container/erledigen-button-container.component';
 import { SubmitWiedervorlageButtonComponent } from './submit-wiedervorlage-button/submit-wiedervorlage-button.component';
@@ -69,6 +70,7 @@ const routes: Routes = [
     VorgangSharedUiModule,
     BinaryFileModule,
     UserProfileModule,
+    TooltipDirective,
   ],
   declarations: [
     WiedervorlagePageComponent,
diff --git a/alfa-client/tsconfig.base.json b/alfa-client/tsconfig.base.json
index f6e9e575c23782986c485ac2912154cf9ed224a7..deeabaafe3641c159f6a14ebdf3db81c51e267a0 100644
--- a/alfa-client/tsconfig.base.json
+++ b/alfa-client/tsconfig.base.json
@@ -17,12 +17,14 @@
     "baseUrl": ".",
     "paths": {
       "@admin-client/configuration-shared": ["libs/admin/configuration-shared/src/index.ts"],
+      "@admin-client/configuration": ["libs/admin/configuration/src/index.ts"],
       "@admin-client/organisations-einheit": ["libs/admin/organisations-einheit/src/index.ts"],
       "@admin-client/organisations-einheit-shared": ["libs/admin/organisations-einheit-shared/src/index.ts"],
       "@admin-client/postfach": ["libs/admin/postfach/src/index.ts"],
       "@admin-client/postfach-shared": ["libs/admin/postfach-shared/src/index.ts"],
       "@admin-client/settings-shared": ["libs/admin/settings-shared/src/index.ts"],
       "@admin-client/shared": ["libs/admin/shared/src/index.ts"],
+      "@admin-client/statistik": ["libs/admin/statistik/src/index.ts"],
       "@admin-client/user": ["libs/admin/user/src/index.ts"],
       "@admin-client/user-shared": ["libs/admin/user-shared/src/index.ts"],
       "@alfa-client/api-root-shared": ["libs/api-root-shared/src/index.ts"],
@@ -72,9 +74,9 @@
       "@alfa-client/wiedervorlage-shared": ["libs/wiedervorlage-shared/src/index.ts"],
       "@alfa-client/zustaendige-stelle": ["libs/zustaendige-stelle/src/index.ts"],
       "@alfa-client/zustaendige-stelle-shared": ["libs/zustaendige-stelle-shared/src/index.ts"],
+      "@authentication": ["libs/authentication/src/index.ts"],
       "@ods/component": ["libs/design-component/src/index.ts"],
-      "@ods/system": ["libs/design-system/src/index.ts"],
-      "authentication": ["libs/authentication/src/index.ts"]
+      "@ods/system": ["libs/design-system/src/index.ts"]
     }
   },
   "exclude": ["node_modules", "tmp"]