diff --git a/alfa-client/apps/admin-e2e/src/e2e/main-tests/organisationseinheiten/organisationseinheiten-laden.cy.ts b/alfa-client/apps/admin-e2e/src/e2e/main-tests/organisationseinheiten/organisationseinheiten-laden.cy.ts
index 024419213edd7e67280c2fc9893d6864fd2469df..4ed37075df8da2351a1185a14cf626b5511da4ce 100644
--- a/alfa-client/apps/admin-e2e/src/e2e/main-tests/organisationseinheiten/organisationseinheiten-laden.cy.ts
+++ b/alfa-client/apps/admin-e2e/src/e2e/main-tests/organisationseinheiten/organisationseinheiten-laden.cy.ts
@@ -1,14 +1,14 @@
-import { OrganisationsEinheitenE2EComponent } from '../../components/organisationseinheiten/organisationseinheiten.e2e.component';
-import { MainPage, waitForSpinnerToDisappear } from '../../page-objects/main.po';
-import { exist } from '../../support/cypress.util';
-import { OrganisationsEinheitSyncResultE2E } from '../../support/organisationseinheit';
+import { OrganisationsEinheitenE2EComponent } from '../../../components/organisationseinheiten/organisationseinheiten.e2e.component';
+import { MainPage, waitForSpinnerToDisappear } from '../../../page-objects/main.po';
+import { exist } from '../../../support/cypress.util';
+import { OrganisationsEinheitSyncResultE2E } from '../../../support/organisationseinheit';
 import {
   createBauamtOrganisationsEinheit,
   createDenkmalpflegeOrganisationsEinheit,
   createFundstelleOrganisationsEinheit,
   initOrganisationsEinheiten,
-} from '../../support/organisationseinheit-util';
-import { loginAsAriane } from '../../support/user-util';
+} from '../../../support/organisationseinheit-util';
+import { loginAsAriane } from '../../../support/user-util';
 
 describe('show Organisationsheiten', () => {
   const mainPage: MainPage = new MainPage();
diff --git a/alfa-client/apps/admin-e2e/src/e2e/main-tests/organisationseinheiten/organisationseinheiten-signaturen.cy.ts b/alfa-client/apps/admin-e2e/src/e2e/main-tests/organisationseinheiten/organisationseinheiten-signaturen.cy.ts
index cd484bd20a56578cd03f599cbe2757c000b471ed..53cd8d900df150443bbd18e99c93b1ff5879fe8f 100644
--- a/alfa-client/apps/admin-e2e/src/e2e/main-tests/organisationseinheiten/organisationseinheiten-signaturen.cy.ts
+++ b/alfa-client/apps/admin-e2e/src/e2e/main-tests/organisationseinheiten/organisationseinheiten-signaturen.cy.ts
@@ -1,8 +1,8 @@
-import { OrganisationseinheitenSignaturE2EComponent } from '../../components/organisationseinheiten/organisationseinheiten-signatur.e2e.component';
-import { OrganisationsEinheitenE2EComponent } from '../../components/organisationseinheiten/organisationseinheiten.e2e.component';
-import { MainPage, waitForSpinnerToDisappear } from '../../page-objects/main.po';
-import { haveText } from '../../support/cypress.util';
-import { loginAsAriane } from '../../support/user-util';
+import { OrganisationseinheitenSignaturE2EComponent } from '../../../components/organisationseinheiten/organisationseinheiten-signatur.e2e.component';
+import { OrganisationsEinheitenE2EComponent } from '../../../components/organisationseinheiten/organisationseinheiten.e2e.component';
+import { MainPage, waitForSpinnerToDisappear } from '../../../page-objects/main.po';
+import { haveText } from '../../../support/cypress.util';
+import { loginAsAriane } from '../../../support/user-util';
 
 describe('Signatur', () => {
   const mainPage: MainPage = new MainPage();
diff --git a/alfa-client/apps/admin/src/main/helm/templates/deployment.yaml b/alfa-client/apps/admin/src/main/helm/templates/deployment.yaml
index ebb5ef1aa0f3ea98b137aa1b83401e4076e965ee..313812a726ff3f48bdab917e1b7ecfe8812cc3c0 100644
--- a/alfa-client/apps/admin/src/main/helm/templates/deployment.yaml
+++ b/alfa-client/apps/admin/src/main/helm/templates/deployment.yaml
@@ -1,5 +1,5 @@
 #
-# Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den
+# Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den
 # Ministerpräsidenten des Landes Schleswig-Holstein
 # Staatskanzlei
 # Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
@@ -57,12 +57,12 @@ spec:
         labelSelector:
           matchLabels:
             app.kubernetes.io/name: {{ .Release.Name }}
-      
+
       containers:
-      - env:        
+      - env:
         - name: spring_profiles_active
           value: {{ include "app.envSpringProfiles" . }}
-       
+
         {{- with include "app.getCustomList" . }}
 {{ . | indent 8 }}
         {{- end }}
@@ -89,7 +89,17 @@ spec:
           periodSeconds: 10
           successThreshold: 1
           failureThreshold: 3
-
+        {{- if .Values.enableLivenessProbe }}
+        livenessProbe:
+          httpGet:
+            path: /
+            port: 8080
+            scheme: HTTP
+          timeoutSeconds: 1
+          periodSeconds: 10
+          successThreshold: 1
+          failureThreshold: 3
+        {{- end }}
         resources:
         {{- with .Values.resources }}
 {{ toYaml . | indent 10 }}
@@ -105,12 +115,16 @@ spec:
           {{- with (.Values.securityContext).runAsGroup }}
           runAsGroup: {{ . }}
           {{- end }}
+          {{- with (.Values.securityContext).capabilities }}
+          capabilities:
+{{ toYaml . | indent 12 }}
+          {{- end }}
         stdin: true
         terminationMessagePath: /dev/termination-log
         terminationMessagePolicy: File
         tty: true
-        
-        
+
+
       dnsConfig: {}
       dnsPolicy: ClusterFirst
       imagePullSecrets:
@@ -121,5 +135,8 @@ spec:
 {{ toYaml . | indent 8 }}
       {{- end }}
       schedulerName: default-scheduler
-      securityContext: {}
-      terminationGracePeriodSeconds: 30
+      {{- with .Values.podSecurityContext }}
+      securityContext:
+{{ toYaml . | indent 8 }}
+      {{- end }}
+      terminationGracePeriodSeconds: 30
\ No newline at end of file
diff --git a/alfa-client/apps/admin/src/main/helm/templates/service_account.yaml b/alfa-client/apps/admin/src/main/helm/templates/service_account.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..3bac8e223d1fd108b386d1f06ed4e9fb2284a67c
--- /dev/null
+++ b/alfa-client/apps/admin/src/main/helm/templates/service_account.yaml
@@ -0,0 +1,31 @@
+#
+# 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.
+#
+
+{{- if (.Values.serviceAccount).create }}
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: {{ include "app.serviceAccountName" . }}
+  namespace: {{ include "app.namespace" . }}
+{{- end }}
\ No newline at end of file
diff --git a/src/test/helm/deployment_service_account_test.yaml b/alfa-client/apps/admin/src/test/helm/deployment_service_account_test.yaml
similarity index 81%
rename from src/test/helm/deployment_service_account_test.yaml
rename to alfa-client/apps/admin/src/test/helm/deployment_service_account_test.yaml
index 3bb33d1d8f3c8a173632a567a88b967863718197..98246ba981cba50008edd137c04040383faa5ecc 100644
--- a/src/test/helm/deployment_service_account_test.yaml
+++ b/alfa-client/apps/admin/src/test/helm/deployment_service_account_test.yaml
@@ -1,5 +1,5 @@
 #
-# Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den
+# Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den
 # Ministerpräsidenten des Landes Schleswig-Holstein
 # Staatskanzlei
 # Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
@@ -24,19 +24,15 @@
 
 suite: deployment service account
 release:
-  name: alfa
+  name: admin-client
   namespace: sh-helm-test
 templates:
   - templates/deployment.yaml
 set:
-  baseUrl: test.company.local
   ozgcloud:
-    environment: test
-    bundesland: sh
-    bezeichner: helm
-  sso:
-    serverUrl: https://sso.company.local
-  imagePullSecret: image-pull-secret
+    environment: dev
+  imagePullSecret: test-image-secret
+
 tests:
   - it: should use service account with default name
     set:
@@ -45,7 +41,7 @@ tests:
     asserts:
       - equal:
           path: spec.template.spec.serviceAccountName
-          value: alfa-service-account
+          value: admin-client-service-account
   - it: should use service account with name
     set:
       serviceAccount:
@@ -58,4 +54,4 @@ tests:
   - it: should use default service account
     asserts:
       - isNull:
-          path: spec.template.spec.serviceAccountName
+          path: spec.template.spec.serviceAccountName
\ No newline at end of file
diff --git a/alfa-client/apps/admin/src/test/helm/service_account_test.yaml b/alfa-client/apps/admin/src/test/helm/service_account_test.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..e80dde85e375a7ba052a403807c460969c9fdc4e
--- /dev/null
+++ b/alfa-client/apps/admin/src/test/helm/service_account_test.yaml
@@ -0,0 +1,64 @@
+#
+# 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.
+#
+
+suite: test service account
+release:
+  name: admin-client
+  namespace: sh-helm-test
+templates:
+  - templates/service_account.yaml
+tests:
+  - it: should create service account with default name
+    set:
+      serviceAccount:
+        create: true
+    asserts:
+      - isKind:
+          of: ServiceAccount
+      - isAPIVersion:
+          of: v1
+      - equal:
+          path: metadata.name
+          value: admin-client-service-account
+      - equal:
+          path: metadata.namespace
+          value: sh-helm-test
+  - it: should create service account with name
+    set:
+      serviceAccount:
+        create: true
+        name: helm-service-account
+    asserts:
+      - isKind:
+          of: ServiceAccount
+      - equal:
+          path: metadata.name
+          value: helm-service-account
+      - equal:
+          path: metadata.namespace
+          value: sh-helm-test
+  - it: should not create service account
+    asserts:
+      - hasDocuments:
+        count: 0
\ No newline at end of file
diff --git a/alfa-client/apps/alfa-e2e/src/fixtures/kommentar/kommentar.json b/alfa-client/apps/alfa-e2e/src/fixtures/kommentar/kommentar.json
index f1bad2ba77535e6b15dc38f9b896a3ef04ec7b2e..66fe5c0999da2a440ff52a1378566bd6d6871d76 100644
--- a/alfa-client/apps/alfa-e2e/src/fixtures/kommentar/kommentar.json
+++ b/alfa-client/apps/alfa-e2e/src/fixtures/kommentar/kommentar.json
@@ -1,5 +1,6 @@
 {
   "createdAt": "2024-01-10T12:57:35Z[UTC]",
   "createdBy": "SetInCode",
-  "text": "Test text to test the test text test"
+  "text": "Test text to test the test text test",
+  "attachments": null
 }
diff --git a/alfa-client/apps/demo/src/app/app.component.html b/alfa-client/apps/demo/src/app/app.component.html
index bae7d97a832d82ad6e91c77233ff11ea7eb6bc88..25e02f33b59d8a32db4332a88a6fef1d2e675c76 100644
--- a/alfa-client/apps/demo/src/app/app.component.html
+++ b/alfa-client/apps/demo/src/app/app.component.html
@@ -19,6 +19,7 @@
             <a
               href="#"
               class="flex flex-col items-start justify-between gap-2 rounded-t-md border-primary-600/50 px-6 py-4 hover:bg-background-150 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-focus lg:flex-row lg:gap-6"
+              tooltip="This is tooltip attached to link element"
             >
               <div class="flex-1 basis-5/6">
                 <div class="flex flex-wrap items-center gap-x-3">
@@ -396,7 +397,7 @@
       </form>
       <app-bescheid-dialog-button></app-bescheid-dialog-button>
       <div class="my-4 flex gap-4">
-        <ods-button text="Button 1" />
+        <ods-button text="Button 1" tooltip="Sample tooltip" />
         <ods-button size="medium" [isLoading]="true" text="Button 2" />
         <ods-button type="outline" text="Button 3" />
       </div>
diff --git a/alfa-client/apps/demo/src/app/app.component.ts b/alfa-client/apps/demo/src/app/app.component.ts
index d2ac3257386258a3bd111f893c0afc1616c666cc..eef4a756761f2ad91604ffd019aa645a2c97b9f6 100644
--- a/alfa-client/apps/demo/src/app/app.component.ts
+++ b/alfa-client/apps/demo/src/app/app.component.ts
@@ -15,10 +15,8 @@ import {
   CloseIconComponent,
   ErrorMessageComponent,
   FieldsetComponent,
-  FileIconComponent,
   FileUploadButtonComponent,
   InstantSearchComponent,
-  OfficeIconComponent,
   RadioButtonCardComponent,
   SaveIconComponent,
   SendIconComponent,
@@ -26,6 +24,7 @@ import {
   StampIconComponent,
   TextInputComponent,
   TextareaComponent,
+  TooltipDirective,
 } from '@ods/system';
 
 import { EMPTY_STRING } from '@alfa-client/tech-shared';
@@ -35,8 +34,6 @@ import {
   InstantSearchResult,
 } from 'libs/design-system/src/lib/instant-search/instant-search/instant-search.model';
 import { BescheidDialogExampleComponent } from './components/bescheid-dialog/bescheid-dialog.component';
-import { BescheidPaperComponent } from './components/bescheid-paper/bescheid-paper.component';
-import { BescheidStepperComponent } from './components/bescheid-stepper/bescheid-stepper.component';
 import { CustomStepperComponent } from './components/cdk-demo/custom-stepper.component';
 
 @Component({
@@ -54,12 +51,9 @@ import { CustomStepperComponent } from './components/cdk-demo/custom-stepper.com
     CdkStepperModule,
     CustomStepperComponent,
     BescheidDialogExampleComponent,
-    BescheidStepperComponent,
-    BescheidPaperComponent,
     RadioButtonCardComponent,
     ReactiveFormsModule,
     InstantSearchComponent,
-    OfficeIconComponent,
     SaveIconComponent,
     SendIconComponent,
     StampIconComponent,
@@ -68,11 +62,11 @@ import { CustomStepperComponent } from './components/cdk-demo/custom-stepper.com
     BescheidGenerateIconComponent,
     BescheidUploadIconComponent,
     SpinnerIconComponent,
-    FileIconComponent,
     TextareaComponent,
     TextInputComponent,
     TextareaComponent,
     ErrorMessageComponent,
+    TooltipDirective,
   ],
   selector: 'app-root',
   templateUrl: './app.component.html',
diff --git a/alfa-client/libs/design-system/src/index.ts b/alfa-client/libs/design-system/src/index.ts
index d64022f37b2b81e968b4bed34e2eed7d5741ccae..055062c48ce72b9d037dea89020b24bd0b706fae 100644
--- a/alfa-client/libs/design-system/src/index.ts
+++ b/alfa-client/libs/design-system/src/index.ts
@@ -47,3 +47,4 @@ export * from './lib/list/list.component';
 export * from './lib/navbar/nav-item/nav-item.component';
 export * from './lib/navbar/navbar/navbar.component';
 export * from './lib/testbtn/testbtn.component';
+export * from './lib/tooltip/tooltip.directive';
diff --git a/alfa-client/libs/design-system/src/lib/tooltip/tooltip.component.spec.ts b/alfa-client/libs/design-system/src/lib/tooltip/tooltip.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..fc39cb7ceafa17c9865a7390f9ab98e2298bf127
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/tooltip/tooltip.component.spec.ts
@@ -0,0 +1,21 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { TooltipComponent } from './tooltip.component';
+
+describe('TooltipComponent', () => {
+  let component: TooltipComponent;
+  let fixture: ComponentFixture<TooltipComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: [TooltipComponent],
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(TooltipComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
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
new file mode 100644
index 0000000000000000000000000000000000000000..a3ae962af474a3cf0a5cd2aa6744996e65383611
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/tooltip/tooltip.component.ts
@@ -0,0 +1,22 @@
+import { Component } from '@angular/core';
+
+@Component({
+  selector: 'ods-tooltip',
+  template: `<p
+    class="fixed z-50 mt-2 -translate-x-1/2 animate-fadeIn cursor-default rounded bg-ozggray-900 px-3 py-2 text-sm text-whitetext before:absolute before:-top-2 before:left-[calc(50%-0.5rem)] before:size-0 before:border-b-8 before:border-l-8 before:border-r-8 before:border-b-ozggray-900 before:border-l-transparent before:border-r-transparent before:content-[''] dark:bg-white dark:before:border-b-white"
+    [style.left]="left + 'px'"
+    [style.top]="top + 'px'"
+    [attr.id]="id"
+    role="tooltip"
+  >
+    {{ text }}
+  </p>`,
+  styles: [':host {@apply contents}'],
+  standalone: true,
+})
+export class TooltipComponent {
+  text: string = '';
+  left: number = 0;
+  top: number = 0;
+  id: string;
+}
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
new file mode 100644
index 0000000000000000000000000000000000000000..07895edc7c9aa5622948043a663ea3c940e0375b
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/tooltip/tooltip.directive.spec.ts
@@ -0,0 +1,221 @@
+import { InteractivityChecker } from '@angular/cdk/a11y';
+import { ComponentRef, ElementRef, Renderer2, ViewContainerRef } from '@angular/core';
+import { TestBed } from '@angular/core/testing';
+import { TooltipComponent } from './tooltip.component';
+import { TooltipDirective } from './tooltip.directive';
+
+class MockElementRef extends ElementRef {
+  nativeElement = {
+    contains: jest.fn(),
+    appendChild: jest.fn(),
+  };
+}
+
+describe('TooltipDirective', () => {
+  let directive: TooltipDirective;
+  const mockComponentRef: ComponentRef<TooltipComponent> = {
+    setInput: jest.fn(),
+    destroy: jest.fn(),
+    onDestroy: jest.fn(),
+    componentType: TooltipComponent,
+    changeDetectorRef: null,
+    location: null,
+    hostView: null,
+    injector: null,
+    instance: { id: '', left: 0, top: 0, text: '' },
+  };
+
+  beforeEach((): void => {
+    TestBed.configureTestingModule({
+      providers: [ViewContainerRef, { provide: ElementRef, useClass: MockElementRef }, Renderer2, InteractivityChecker],
+    });
+    TestBed.runInInjectionContext(() => {
+      directive = new TooltipDirective();
+    });
+  });
+
+  it('should create a directive', () => {
+    expect(directive).toBeTruthy();
+  });
+
+  describe('ngOnDestroy', () => {
+    it('should destroy tooltip', () => {
+      directive.destroy = jest.fn();
+
+      directive.ngOnDestroy();
+
+      expect(directive.destroy).toHaveBeenCalled();
+    });
+  });
+
+  describe('createTooltip', () => {
+    beforeEach(() => {
+      directive.viewContainerRef.createComponent = jest.fn().mockReturnValue({ location: { nativeElement: {} } });
+      directive.setDescribedBy = jest.fn();
+      directive.setTooltipProperties = jest.fn();
+    });
+
+    it('should create tooltip component', () => {
+      directive.createTooltip();
+
+      expect(directive.viewContainerRef.createComponent).toHaveBeenCalled();
+    });
+
+    it('should insert tooltip component to parent', () => {
+      directive.createTooltip();
+
+      expect(directive.elementRef.nativeElement.appendChild).toHaveBeenCalled();
+    });
+
+    it('should set aria described by attribute to parent', () => {
+      directive.createTooltip();
+
+      expect(directive.setDescribedBy).toHaveBeenCalled();
+    });
+
+    it('should set tooltip properties', () => {
+      directive.createTooltip();
+
+      expect(directive.setTooltipProperties).toHaveBeenCalled();
+    });
+  });
+
+  describe('destroyTooltip', () => {
+    it('should destroy tooltip', () => {
+      directive.destroy = jest.fn();
+
+      directive.destroyTooltip();
+
+      expect(directive.destroy).toHaveBeenCalled();
+    });
+  });
+
+  describe('onKeydown', () => {
+    it('should destroy tooltip if escape key pressed', () => {
+      directive.destroy = jest.fn();
+      const escapeEvent: KeyboardEvent = { ...new KeyboardEvent('esc'), key: 'Escape' };
+
+      directive.onKeydown(escapeEvent);
+
+      expect(directive.destroy).toHaveBeenCalled();
+    });
+  });
+
+  describe('setTooltipProperties', () => {
+    beforeEach(() => {
+      directive.componentRef = mockComponentRef;
+      directive.elementRef.nativeElement.getBoundingClientRect = jest
+        .fn()
+        .mockReturnValue({ left: 0, right: 1000, bottom: 1000 });
+    });
+
+    it('should get bounding client rect', () => {
+      directive.setTooltipProperties();
+
+      expect(directive.elementRef.nativeElement.getBoundingClientRect).toHaveBeenCalled();
+    });
+
+    it('should set tooltip instance properties', () => {
+      directive.tooltip = 'I am tooltip';
+      directive.tooltipId = 'tooltip-1';
+
+      directive.setTooltipProperties();
+
+      expect(directive.componentRef.instance).toStrictEqual({
+        id: 'tooltip-1',
+        left: 500,
+        text: 'I am tooltip',
+        top: 1000,
+      });
+    });
+
+    it('should add margin if parent element focused', () => {
+      directive.setTooltipProperties(true);
+
+      expect(directive.componentRef.instance.top).toBe(1004);
+    });
+  });
+
+  describe('setDescribedBy', () => {
+    beforeEach(() => {
+      directive.getFocusableElement = jest.fn();
+      directive.renderer.setAttribute = jest.fn();
+      directive.interactivityChecker.isFocusable = jest.fn();
+    });
+
+    it('should check if parent element focusable', () => {
+      directive.setDescribedBy();
+
+      expect(directive.interactivityChecker.isFocusable).toHaveBeenCalled();
+    });
+
+    it('should get focusable element if parent not focusable', () => {
+      directive.setDescribedBy();
+
+      expect(directive.getFocusableElement).toHaveBeenCalled();
+    });
+
+    it('should set describedby attribute', () => {
+      directive.setDescribedBy();
+
+      expect(directive.renderer.setAttribute).toHaveBeenCalled();
+    });
+  });
+
+  describe('removeDescribedBy', () => {
+    beforeEach(() => {
+      directive.renderer.removeAttribute = jest.fn();
+    });
+
+    it('should remove describedby attribute', () => {
+      directive.removeDescribedBy();
+
+      expect(directive.renderer.removeAttribute).toHaveBeenCalled();
+    });
+  });
+
+  describe('getFocusableElement', () => {
+    it('should return null', () => {
+      const simpleElement = document.createElement('a');
+
+      const result: HTMLElement = directive.getFocusableElement(simpleElement);
+
+      expect(result).toBeNull();
+    });
+
+    it('should return focusable child element', () => {
+      const nestedElement = document.createElement('div');
+      const buttonElement = document.createElement('button');
+      nestedElement.appendChild(buttonElement);
+
+      const result: HTMLElement = directive.getFocusableElement(nestedElement);
+
+      expect(result).toBe(buttonElement);
+    });
+  });
+
+  describe('destroy', () => {
+    beforeEach(() => {
+      directive.componentRef = mockComponentRef;
+      directive.removeDescribedBy = jest.fn();
+    });
+
+    it('should set component ref to null', () => {
+      directive.destroy();
+
+      expect(directive.componentRef).toBeNull();
+    });
+
+    it('should remove describedby attribute', () => {
+      directive.destroy();
+
+      expect(directive.removeDescribedBy).toHaveBeenCalled();
+    });
+
+    it('should set focusable element to null', () => {
+      directive.destroy();
+
+      expect(directive.focusableElement).toBeNull();
+    });
+  });
+});
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
new file mode 100644
index 0000000000000000000000000000000000000000..6af9df79e87cf64bdb3c73867a9a631e1f2b210a
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/tooltip/tooltip.directive.ts
@@ -0,0 +1,98 @@
+import { isEscapeKey } from '@alfa-client/tech-shared';
+import { InteractivityChecker } from '@angular/cdk/a11y';
+import {
+  ComponentRef,
+  Directive,
+  ElementRef,
+  HostListener,
+  inject,
+  Input,
+  OnDestroy,
+  Renderer2,
+  ViewContainerRef,
+} from '@angular/core';
+import { uniqueId } from 'lodash-es';
+import { TooltipComponent } from './tooltip.component';
+
+@Directive({
+  selector: '[tooltip]',
+  standalone: true,
+})
+export class TooltipDirective implements OnDestroy {
+  @Input() tooltip: string = '';
+
+  componentRef: ComponentRef<TooltipComponent> = null;
+  focusableElement: HTMLElement = null;
+  tooltipId: string;
+
+  public viewContainerRef: ViewContainerRef = inject(ViewContainerRef);
+  public elementRef: ElementRef<HTMLElement> = inject(ElementRef);
+  public renderer: Renderer2 = inject(Renderer2);
+  public interactivityChecker: InteractivityChecker = inject(InteractivityChecker);
+
+  ngOnDestroy(): void {
+    this.destroy();
+  }
+
+  @HostListener('mouseenter')
+  @HostListener('focusin')
+  createTooltip(): void {
+    if (this.componentRef === null) {
+      const nativeElement: HTMLElement = this.elementRef.nativeElement;
+      const attachedToFocused: boolean = nativeElement.contains(document.activeElement);
+      this.componentRef = this.viewContainerRef.createComponent(TooltipComponent);
+      nativeElement.appendChild(this.componentRef.location.nativeElement);
+      this.setDescribedBy();
+      this.setTooltipProperties(attachedToFocused);
+    }
+  }
+
+  @HostListener('mouseleave')
+  @HostListener('window:scroll')
+  @HostListener('focusout')
+  destroyTooltip(): void {
+    this.destroy();
+  }
+
+  @HostListener('keydown', ['$event'])
+  onKeydown(e: KeyboardEvent): void {
+    if (isEscapeKey(e)) {
+      this.destroy();
+    }
+  }
+
+  setTooltipProperties(attachedToFocused = false): void {
+    if (this.componentRef !== null) {
+      const { left, right, bottom } = this.elementRef.nativeElement.getBoundingClientRect();
+      this.componentRef.instance.left = (right + left) / 2;
+      this.componentRef.instance.top = attachedToFocused ? bottom + 4 : bottom;
+      this.componentRef.instance.text = this.tooltip;
+      this.componentRef.instance.id = this.tooltipId;
+    }
+  }
+
+  setDescribedBy(): void {
+    const nativeElement: HTMLElement = this.elementRef.nativeElement;
+    this.tooltipId = uniqueId('tooltip');
+    this.focusableElement =
+      this.interactivityChecker.isFocusable(nativeElement) ? nativeElement : this.getFocusableElement(nativeElement);
+    this.renderer.setAttribute(this.focusableElement, 'aria-describedby', this.tooltipId);
+  }
+
+  removeDescribedBy(): void {
+    this.renderer.removeAttribute(this.focusableElement, 'aria-describedby');
+  }
+
+  getFocusableElement(element: HTMLElement): HTMLElement {
+    return element.querySelector('a[href], button, input, textarea, select, details, [tabindex]:not([tabindex="-1"])');
+  }
+
+  destroy(): void {
+    if (this.componentRef !== null) {
+      this.componentRef.destroy();
+      this.componentRef = null;
+      this.removeDescribedBy();
+      this.focusableElement = null;
+    }
+  }
+}
diff --git a/alfa-client/libs/design-system/src/lib/tooltip/tooltip.stories.ts b/alfa-client/libs/design-system/src/lib/tooltip/tooltip.stories.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f380cd055b3215670369b0d30fbbe2e00ef18921
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/tooltip/tooltip.stories.ts
@@ -0,0 +1,29 @@
+import { moduleMetadata, type Meta, type StoryObj } from '@storybook/angular';
+import { TooltipDirective } from './tooltip.directive';
+
+const meta: Meta = {
+  title: 'Tooltip',
+  excludeStories: /.*Data$/,
+  tags: ['autodocs'],
+  decorators: [
+    moduleMetadata({
+      imports: [TooltipDirective],
+    }),
+  ],
+  parameters: {
+    docs: {
+      description: {
+        component: 'Tooltip directive that can be used with every element (check out default story to see tooltip working).',
+      },
+    },
+  },
+};
+
+export default meta;
+type Story = StoryObj;
+
+export const Default: Story = {
+  render: () => ({
+    template: '<button tooltip="Hello">I have a tooltip!</button>',
+  }),
+};
diff --git a/alfa-server/src/main/resources/application-dev.yml b/alfa-server/src/main/resources/application-dev.yml
index 6f11904235f17602539afaca47cd695e69deee8b..ec9f40e322dac00e4bc6dd3f274cfb6d481610da 100644
--- a/alfa-server/src/main/resources/application-dev.yml
+++ b/alfa-server/src/main/resources/application-dev.yml
@@ -14,7 +14,3 @@ ozgcloud:
   production: false
   stage:
     production: false
-  xdomea:
-    behoerdenschluessel: "DUMMY-SCHLUESSEL"
-    behoerdenschluessel-uri: "DUMMY-URI"
-    behoerdenschluessel-version: "DUMMY-VERSION"
\ No newline at end of file
diff --git a/alfa-server/src/main/resources/application-e2e.yml b/alfa-server/src/main/resources/application-e2e.yml
index fd8c68442dd1afef3e6dc9f76d2932e0d7b2fc58..1f162b5430da5727476ee84d73e8cdc8dfa51e63 100644
--- a/alfa-server/src/main/resources/application-e2e.yml
+++ b/alfa-server/src/main/resources/application-e2e.yml
@@ -13,7 +13,3 @@ ozgcloud:
       url: /assets/benutzerleitfaden/benutzerleitfaden.pdf
   user-manager:
     url: http://localhost:9092
-  xdomea:
-    behoerdenschluessel: "DUMMY-SCHLUESSEL-E2E"
-    behoerdenschluessel-uri: "DUMMY-URI-E2E"
-    behoerdenschluessel-version: "DUMMY-VERSION-E2E"
\ No newline at end of file
diff --git a/alfa-server/src/main/resources/application.yml b/alfa-server/src/main/resources/application.yml
index ee47f0a2747565c9c998c64bf13e33aee1303306..14fb3b10fdecfbcd1383fb0030be1e1ba3ed33ab 100644
--- a/alfa-server/src/main/resources/application.yml
+++ b/alfa-server/src/main/resources/application.yml
@@ -103,7 +103,3 @@ ozgcloud:
   user-manager:
     profile-template: /api/userProfiles/%s
     search-template: /api/userProfiles/?searchBy={searchBy}
-  xdomea:
-    behoerdenschluessel:
-    behoerdenschluessel-uri:
-    behoerdenschluessel-version:
diff --git a/src/main/helm/templates/deployment.yaml b/src/main/helm/templates/deployment.yaml
index b41bd9f4d1b557a5bd5aa329079d778e8626e2fd..19508dd28a03b2ea0be60fe4e12bd93b3aa6538c 100644
--- a/src/main/helm/templates/deployment.yaml
+++ b/src/main/helm/templates/deployment.yaml
@@ -111,12 +111,6 @@ spec:
           value: {{ $bescheid.formEngineName }}
         {{- end }}
         {{- end}}
-        - name: ozgcloud_xdomea_behoerdenschluessel
-          value: {{ ((.Values.ozgcloud).xdomea).behoerdenschluessel | quote }}
-        - name: ozgcloud_xdomea_behoerdenschluesselUri
-          value: {{ ((.Values.ozgcloud).xdomea).behoerdenschluesselUri}}
-        - name: ozgcloud_xdomea_behoerdenschluesselVersion
-          value: {{ ((.Values.ozgcloud).xdomea).behoerdenschluesselVersion | quote }}
         - name: ozgcloud_administration_address
           value: {{ include "app.spring_cloud_config_administration_address" . }}
         - name: grpc_client_zufi-manager_address
diff --git a/src/test/helm/deployment_xdomea_env_test.yaml b/src/test/helm/deployment_xdomea_env_test.yaml
deleted file mode 100644
index 351acfe65758cf0fda278e66a28e7b7eed3085e1..0000000000000000000000000000000000000000
--- a/src/test/helm/deployment_xdomea_env_test.yaml
+++ /dev/null
@@ -1,55 +0,0 @@
-suite: deployment xdomea env
-release:
-  name: alfa
-  namespace: sh-helm-test
-templates:
-  - templates/deployment.yaml
-set:
-  baseUrl: test.company.local
-  ozgcloud:
-    environment: test
-    bundesland: sh
-    bezeichner: helm
-  sso:
-    serverUrl: https://sso.company.local
-  imagePullSecret: image-pull-secret
-tests:
-  - it: should not require on behoerdenschlüssel properties
-    set:
-      # note: explicitly non-set behoerdenschlüssel properties
-    asserts:
-      - notContains:
-          path: spec.template.spec.containers[0].env
-          content:
-            name: ozgcloud_xdomea_behoerdenschluessel
-      - notContains:
-          path: spec.template.spec.containers[0].env
-          content:
-            name: ozgcloud_xdomea_behoerdenschluesselUri
-      - notContains:
-          path: spec.template.spec.containers[0].env
-          content:
-            name: ozgcloud_xdomea_behoerdenschluesselVersion
-  - it: should set (optional) behoerdenschlüssel properties
-    set:
-      ozgcloud:
-        xdomea:
-          behoerdenschluessel: "123456"
-          behoerdenschluesselUri: "uri.uri:uri"
-          behoerdenschluesselVersion: "version 1"
-    asserts:
-      - contains:
-          path: spec.template.spec.containers[0].env
-          content:
-            name: ozgcloud_xdomea_behoerdenschluessel
-            value: "123456"
-      - contains:
-          path: spec.template.spec.containers[0].env
-          content:
-            name: ozgcloud_xdomea_behoerdenschluesselUri
-            value: "uri.uri:uri"
-      - contains:
-          path: spec.template.spec.containers[0].env
-          content:
-            name: ozgcloud_xdomea_behoerdenschluesselVersion
-            value: "version 1"
\ No newline at end of file