diff --git a/alfa-client/apps/alfa-e2e/src/components/attachment/attachment.e2e.component.ts b/alfa-client/apps/alfa-e2e/src/components/attachment/attachment.e2e.component.ts
index fe12579e28ed202ae4b72b4f54003a2ae149cd75..c7988c3ce98a476aa50c0a28b1341331a790d4e4 100644
--- a/alfa-client/apps/alfa-e2e/src/components/attachment/attachment.e2e.component.ts
+++ b/alfa-client/apps/alfa-e2e/src/components/attachment/attachment.e2e.component.ts
@@ -32,7 +32,7 @@ export class AttachmentContainerE2EComponent {
   }
 
   public getUploadInput() {
-    return cy.getTestElement(this.locatorFileUploadInput);
+    return cy.getTestElementContaining(this.locatorFileUploadInput);
   }
 }
 
diff --git a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/kommentar-attachment/kommentar-attachment.cy.ts b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/kommentar-attachment/kommentar-attachment.cy.ts
index c85070d6378af981222dca9bbaf595db77d6fff5..e3d96d18276ee39862dd14f25d9a0ed02169b812 100644
--- a/alfa-client/apps/alfa-e2e/src/e2e/main-tests/kommentar-attachment/kommentar-attachment.cy.ts
+++ b/alfa-client/apps/alfa-e2e/src/e2e/main-tests/kommentar-attachment/kommentar-attachment.cy.ts
@@ -22,10 +22,7 @@
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
 import { sleep } from '@alfa-client/tech-shared';
-import {
-  AttachmentContainerE2EComponent,
-  AttachmentListE2EComponent,
-} from '../../../components/attachment/attachment.e2e.component';
+import { AttachmentContainerE2EComponent, AttachmentListE2EComponent, } from '../../../components/attachment/attachment.e2e.component';
 import { KommentareInVorgangE2EComponent } from '../../../components/kommentar/kommentar-list.e2e.component';
 import { VorgangListE2EComponent } from '../../../components/vorgang/vorgang-list.e2e.component';
 import { UserE2E } from '../../../model/user';
@@ -34,7 +31,7 @@ import { MainPage, waitForSpinnerToDisappear } from '../../../page-objects/main.
 import { VorgangPage } from '../../../page-objects/vorgang.po';
 import { dropCollections, readFileFromDownloads } from '../../../support/cypress-helper';
 import { exist, notExist } from '../../../support/cypress.util';
-import { TEST_FILE_WITHOUT_CONTENT, TEST_FILE_WITH_CONTENT } from '../../../support/data.util';
+import { TEST_FILE_WITH_CONTENT, TEST_FILE_WITHOUT_CONTENT } from '../../../support/data.util';
 import { uploadFile } from '../../../support/file-upload';
 import { getUserSabine, loginAsSabine } from '../../../support/user-util';
 import { createVorgang, initVorgang } from '../../../support/vorgang-util';
@@ -46,8 +43,7 @@ describe('Kommentar attachments', () => {
   const vorgangPage: VorgangPage = new VorgangPage();
   const kommentarContainer: KommentareInVorgangE2EComponent = vorgangPage.getKommentarContainer();
 
-  const attachmentContainer: AttachmentContainerE2EComponent =
-    kommentarContainer.getAttachmentContainer();
+  const attachmentContainer: AttachmentContainerE2EComponent = kommentarContainer.getAttachmentContainer();
   const attachmentList: AttachmentListE2EComponent = attachmentContainer.getList();
 
   const kommentarText: string = 'Test text to test the test text test';
diff --git a/alfa-client/apps/alfa-e2e/src/support/commands.ts b/alfa-client/apps/alfa-e2e/src/support/commands.ts
index 8873b6afe8672819cf9ea75cf441955fabb0f004..30e88fd0f58f79fb5d3db717bb46a835fc2b5b54 100644
--- a/alfa-client/apps/alfa-e2e/src/support/commands.ts
+++ b/alfa-client/apps/alfa-e2e/src/support/commands.ts
@@ -73,6 +73,7 @@ declare namespace Cypress {
   interface Chainable<Subject> {
     getTestElementWithOid(oid: string, ...args);
     getTestElement(selector: string, ...args);
+    getTestElementContaining(selector: string, ...args);
     getTestElementWithClass(selector: string, ...args);
     findTestElementWithClass(selector: string, ...args);
     findElement(selector: string);
@@ -90,6 +91,10 @@ Cypress.Commands.add('getTestElement', (selector, ...args) => {
   return cy.get(`[${DATA_TEST_ID}~="${selector}"]`, ...args);
 });
 
+Cypress.Commands.add('getTestElementContaining', (selector, ...args) => {
+  return cy.get(`[${DATA_TEST_ID}*="${selector}"]`, ...args);
+});
+
 Cypress.Commands.add('getTestElementWithClass', (selector, ...args) => {
   console.log(
     'Achtung: Potentiell nicht eindeutiges Ergebnis, weil eine data-test-class mit cy.get() von der DOM-Root aus gesucht wird.',
@@ -101,13 +106,9 @@ Cypress.Commands.add('getTestElementWithOid', (oid, ...args) => {
   return cy.getTestElement(oid, ...args);
 });
 
-Cypress.Commands.add(
-  'findTestElementWithClass',
-  { prevSubject: true },
-  (subject: any, selector) => {
-    return subject.find(`[${DATA_TEST_CLASS}="${selector}"]`);
-  },
-);
+Cypress.Commands.add('findTestElementWithClass', { prevSubject: true }, (subject: any, selector) => {
+  return subject.find(`[${DATA_TEST_CLASS}="${selector}"]`);
+});
 
 Cypress.Commands.add('findElement', { prevSubject: true }, (subject: any, selector: string) => {
   return subject.find(selector);
diff --git a/alfa-client/libs/admin/user/src/lib/user-form/user.formservice.spec.ts b/alfa-client/libs/admin/user/src/lib/user-form/user.formservice.spec.ts
index 8e823be03c1f064fe2cd152da724bb3e0fcdc001..85dd58354b2597416aad10898d5c437edb445cfe 100644
--- a/alfa-client/libs/admin/user/src/lib/user-form/user.formservice.spec.ts
+++ b/alfa-client/libs/admin/user/src/lib/user-form/user.formservice.spec.ts
@@ -26,7 +26,7 @@ import { ROUTES } from '@admin-client/shared';
 import { User, UserService } from '@admin-client/user-shared';
 import { PatchConfig } from '@admin/keycloak-shared';
 import { NavigationService } from '@alfa-client/navigation-shared';
-import { createEmptyStateResource, createStateResource, EMPTY_ARRAY, StateResource } from '@alfa-client/tech-shared';
+import { createEmptyStateResource, createStateResource, StateResource } 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';
@@ -69,7 +69,7 @@ describe('UserFormService', () => {
     };
     navigationService = mock(NavigationService);
     snackBarService = mock(SnackBarService);
-    activatedRoute = <any>{ ...mock(ActivatedRoute), url: of<UrlSegment[]>(EMPTY_ARRAY) };
+    activatedRoute = <any>{ ...mock(ActivatedRoute), url: of<UrlSegment[]>([]) };
 
     TestBed.configureTestingModule({
       providers: [
diff --git a/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.spec.ts b/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.spec.ts
index ab845cf6b4f7e3156ebb7a940e418780e9a410d2..ddb4bc98ad09c5415e2e3ca6c4853002c17c32d7 100644
--- a/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.spec.ts
+++ b/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.spec.ts
@@ -26,7 +26,6 @@ import { CommandOrder, CommandResource, CommandService, CreateCommandProps } fro
 import { PostfachService } from '@alfa-client/postfach-shared';
 import {
   ApiError,
-  EMPTY_ARRAY,
   EMPTY_STRING,
   HttpError,
   StateResource,
@@ -1325,7 +1324,7 @@ describe('BescheidService', () => {
     it('should return empty array', () => {
       const resultdBescheide: BescheidResource[] = service.filterBySentStatus(null);
 
-      expect(resultdBescheide).toBe(EMPTY_ARRAY);
+      expect(resultdBescheide).toEqual([]);
     });
   });
 
diff --git a/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.ts b/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.ts
index 7b8a2f737d688302a3a9f30e218b126a9fad285e..f2df99ebc8b9b47adb3244134990a129aedfe731 100644
--- a/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.ts
+++ b/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.ts
@@ -33,7 +33,6 @@ import {
 } from '@alfa-client/command-shared';
 import { PostfachService } from '@alfa-client/postfach-shared';
 import {
-  EMPTY_ARRAY,
   HttpError,
   ResourceListService,
   StateResource,
@@ -524,7 +523,7 @@ export class BescheidService {
   }
 
   filterBySentStatus(bescheide: BescheidResource[]): BescheidResource[] {
-    return isNotNil(bescheide) ? bescheide.filter(this.hasSentStatus) : EMPTY_ARRAY;
+    return isNotNil(bescheide) ? bescheide.filter(this.hasSentStatus) : [];
   }
 
   private hasSentStatus(bescheid: BescheidResource): boolean {
diff --git a/alfa-client/libs/binary-file-shared/src/index.ts b/alfa-client/libs/binary-file-shared/src/index.ts
index 84a2d2d428e583925dbf769d0d3e759aec1d4469..89abbed2825506534bc5be9bb248855c2c2c10dc 100644
--- a/alfa-client/libs/binary-file-shared/src/index.ts
+++ b/alfa-client/libs/binary-file-shared/src/index.ts
@@ -27,4 +27,3 @@ export * from './lib/binary-file-shared.module';
 export * from './lib/binary-file.linkrel';
 export * from './lib/binary-file.model';
 export * from './lib/binary-file.service';
-export * from './lib/binary-file.util';
diff --git a/alfa-client/libs/binary-file-shared/src/lib/binary-file.model.ts b/alfa-client/libs/binary-file-shared/src/lib/binary-file.model.ts
index b315da1908251ee8a163da0ac755d1f9d0fb20f7..68b3862e4a27ccfa63c8c66930f1d980af233663 100644
--- a/alfa-client/libs/binary-file-shared/src/lib/binary-file.model.ts
+++ b/alfa-client/libs/binary-file-shared/src/lib/binary-file.model.ts
@@ -21,7 +21,7 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-import { ListResource } from '@alfa-client/tech-shared';
+import { ListResource, StateResource } from '@alfa-client/tech-shared';
 import { Resource } from '@ngxp/rest';
 
 export interface BinaryFile {
@@ -33,3 +33,38 @@ export interface BinaryFile {
 export interface BinaryFileResource extends BinaryFile, Resource {}
 
 export interface BinaryFileListResource extends ListResource {}
+
+export interface ToUploadFile {
+  type: FileUploadType;
+  file: File;
+  uploadUrl: string;
+}
+
+export declare type FileUploadType = string;
+
+export interface UploadFile {
+  fileToUpload?: File;
+  uploadedFile: StateResource<BinaryFileResource>;
+}
+
+export type UploadFileByIdentifier = { [key: string]: UploadFile };
+export type UploadFilesByType = { [type: string]: UploadFileByIdentifier };
+
+export interface FileToDelete {
+  key: string;
+  binaryFileResource: BinaryFileResource;
+}
+
+export enum BinaryFileIcon {
+  'application/pdf' = 'pdf',
+  'application/json' = 'json',
+  'application/msword' = 'doc',
+  'application/vnd.openxmlformats-officedocument.wordprocessingml.document' = 'doc',
+  'application/xml' = 'xml',
+  'text/xml' = 'xml',
+  'image/apng' = 'image',
+  'image/gif' = 'image',
+  'image/jpeg' = 'image',
+  'image/png' = 'image',
+  'image/svg+xml' = 'image',
+}
diff --git a/alfa-client/libs/binary-file-shared/src/lib/binary-file.repository.spec.ts b/alfa-client/libs/binary-file-shared/src/lib/binary-file.repository.spec.ts
index 27377b3854e4b1e87900b83f4d957a7751641b1b..dfec001d129c806b4212ebb4dce6f0e54d40213e 100644
--- a/alfa-client/libs/binary-file-shared/src/lib/binary-file.repository.spec.ts
+++ b/alfa-client/libs/binary-file-shared/src/lib/binary-file.repository.spec.ts
@@ -30,15 +30,17 @@ import {
   ListResource,
 } from '@alfa-client/tech-shared';
 import { mock, mockClass, useFromMock } from '@alfa-client/test-utils';
-import { HttpClient, HttpHeaders } from '@angular/common/http';
+import { HttpClient, HttpHeaders, HttpResponse } from '@angular/common/http';
 import { faker } from '@faker-js/faker';
 import { Resource, ResourceFactory, ResourceUri, getUrl } from '@ngxp/rest';
 import { cold, hot } from 'jest-marbles';
 import { InjectorService } from 'libs/tech-shared/src/lib/injector/injector.service';
 import { DummyLinkRel } from 'libs/tech-shared/test/dummy';
+import { createHttpResponse } from 'libs/tech-shared/test/http';
+import { singleCold } from 'libs/tech-shared/test/marbles';
 import { createDummyListResource, createDummyResource } from 'libs/tech-shared/test/resource';
 import { Observable, of } from 'rxjs';
-import { createBinaryFileResource, createBlob, createGetRequestOptions } from '../../test/binary-file';
+import { createBinaryFileResource, createBlob, createFile, createGetRequestOptions } from '../../test/binary-file';
 import { BinaryFileLinkRel } from './binary-file.linkrel';
 import { BinaryFileResource } from './binary-file.model';
 import { BinaryFileRepository } from './binary-file.repository';
@@ -69,10 +71,52 @@ describe('BinaryFileRepository', () => {
     expect(repository).toBeTruthy();
   });
 
+  describe('upload file new', () => {
+    const dummyLinkRel: string = DummyLinkRel.DUMMY;
+    const dummyResource: Resource = createDummyResource([dummyLinkRel]);
+    const uri: ResourceUri = getUrl(dummyResource, dummyLinkRel);
+
+    const file: File = createFile();
+    const binaryFileResource: BinaryFileResource = createBinaryFileResource();
+    const httpResponse: HttpResponse<Object> = createHttpResponse();
+
+    const blob: Blob = createBlob();
+
+    beforeEach(() => {
+      httpClient.post.mockReturnValue(of(httpResponse));
+      repository.getFile = jest.fn().mockReturnValue(of(binaryFileResource));
+    });
+
+    it('should call post on http client', () => {
+      const formData: FormData = new FormData();
+      formData.append('file', blob, file.name);
+
+      repository.uploadFileNew(uri, <File>blob);
+
+      expect(httpClient.post).toHaveBeenCalledWith(getUrl(dummyResource, dummyLinkRel), formData, {
+        observe: 'response',
+      });
+    });
+
+    it('should call get file', () => {
+      repository.uploadFileNew(uri, <File>blob).subscribe();
+
+      expect(repository.getFile).toHaveBeenCalledWith(httpResponse.headers.get(HttpHeader.LOCATION));
+    });
+
+    it('should return binary file', () => {
+      repository.getFile = jest.fn().mockReturnValue(singleCold(binaryFileResource));
+
+      const result: Observable<BinaryFileResource> = repository.uploadFileNew(uri, <File>blob);
+
+      expect(result).toBeObservable(singleCold(binaryFileResource));
+    });
+  });
+
   describe('uploadFile', () => {
     const dummyLinkRel: string = DummyLinkRel.DUMMY;
     const dummyResource: Resource = createDummyResource([dummyLinkRel]);
-    const blob: Blob = new Blob(['test text'], { type: 'text/plain' });
+    const blob: Blob = createBlob();
 
     beforeEach(() => {
       httpClient.post.mockReturnValue(of({}));
@@ -82,7 +126,7 @@ describe('BinaryFileRepository', () => {
       const formData: FormData = new FormData();
       formData.append('file', blob, 'filename');
 
-      repository.uploadFile(dummyResource, dummyLinkRel, <File>blob);
+      repository.uploadFile(getUrl(dummyResource, dummyLinkRel), <File>blob);
 
       expect(httpClient.post).toHaveBeenCalledWith(getUrl(dummyResource, dummyLinkRel), formData, {
         observe: 'response',
@@ -90,7 +134,7 @@ describe('BinaryFileRepository', () => {
     });
 
     it('and return result', () => {
-      let result = repository.uploadFile(dummyResource, dummyLinkRel, <File>blob);
+      const result: Observable<HttpResponse<Object>> = repository.uploadFile(getUrl(dummyResource, dummyLinkRel), <File>blob);
 
       expect(result).not.toBeNull();
     });
diff --git a/alfa-client/libs/binary-file-shared/src/lib/binary-file.repository.ts b/alfa-client/libs/binary-file-shared/src/lib/binary-file.repository.ts
index c98079edeeaaf591b8efdb327dd5a5e5a5fe16c1..c3cdeb7e53cb71d9771066f8ad7e61138636b435 100644
--- a/alfa-client/libs/binary-file-shared/src/lib/binary-file.repository.ts
+++ b/alfa-client/libs/binary-file-shared/src/lib/binary-file.repository.ts
@@ -32,7 +32,7 @@ import {
 import { HttpClient, HttpHeaders, HttpResponse } from '@angular/common/http';
 import { Injectable } from '@angular/core';
 import { Resource, ResourceFactory, ResourceUri, getUrl } from '@ngxp/rest';
-import { Observable, map } from 'rxjs';
+import { Observable, map, mergeMap } from 'rxjs';
 import { BinaryFileLinkRel } from './binary-file.linkrel';
 import { BinaryFileListResource, BinaryFileResource } from './binary-file.model';
 
@@ -43,23 +43,33 @@ export class BinaryFileRepository {
     private resourceFactory: ResourceFactory,
   ) {}
 
-  public uploadFile(
-    resource: Resource,
-    linkRel: string,
-    file: File,
-  ): Observable<HttpResponse<Object>> {
+  public uploadFileNew(uri: ResourceUri, file: File): Observable<BinaryFileResource> {
     const formData: FormData = new FormData();
 
     formData.append('file', file, file.name);
 
-    return this.httpClient.post(getUrl(resource, linkRel), formData, { observe: 'response' });
+    return this.httpClient
+      .post(uri, formData, { observe: 'response' })
+      .pipe(mergeMap((response: HttpResponse<Object>) => this.getFile(this.getLocation(response))));
+  }
+
+  private getLocation(response: HttpResponse<Object>): ResourceUri {
+    return response.headers.get(HttpHeader.LOCATION);
+  }
+
+  /**
+   * @deprecated Use uploadFileNew instead
+   */
+  public uploadFile(uri: ResourceUri, file: File): Observable<HttpResponse<Object>> {
+    const formData: FormData = new FormData();
+
+    formData.append('file', file, file.name);
+
+    return this.httpClient.post(uri, formData, { observe: 'response' });
   }
 
   public download(fileResource: BinaryFileResource): Observable<Blob> {
-    return this.doDownload(
-      getUrl(fileResource, BinaryFileLinkRel.DOWNLOAD),
-      this.buildRequestOptions(),
-    );
+    return this.doDownload(getUrl(fileResource, BinaryFileLinkRel.DOWNLOAD), this.buildRequestOptions());
   }
 
   buildRequestOptions(): GetRequestOptions {
@@ -76,10 +86,7 @@ export class BinaryFileRepository {
   }
 
   buildPdfRequestOptions(): GetRequestOptions {
-    return this.buildBaseRequestOptions([
-      ContentType.APPLICATION_PDF,
-      ContentType.APPLICATION_JSON,
-    ]);
+    return this.buildBaseRequestOptions([ContentType.APPLICATION_PDF, ContentType.APPLICATION_JSON]);
   }
 
   buildBaseRequestOptions(contentTypes: ContentType[]): GetRequestOptions {
@@ -97,9 +104,7 @@ export class BinaryFileRepository {
   }
 
   public downloadArchive(uri: ResourceUri): Observable<BlobWithFileName> {
-    return this.httpClient
-      .get<HttpResponse<Blob>>(uri, this.buildRequestOptionsForArchive())
-      .pipe(map(buildBlobWithFileName));
+    return this.httpClient.get<HttpResponse<Blob>>(uri, this.buildRequestOptionsForArchive()).pipe(map(buildBlobWithFileName));
   }
 
   buildRequestOptionsForArchive(): GetRequestOptions {
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 0f2d961a4b48fae71acf2ed14685e34697da1b22..9d26d35e6e9f7a882e0bad43d87f69fcb7562cc3 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,22 +21,24 @@
  * 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, createEmptyStateResource, createStateResource, StateResource } from '@alfa-client/tech-shared';
 import { Mock, mock, useFromMock } from '@alfa-client/test-utils';
 import { SnackBarService } from '@alfa-client/ui';
 import { HttpErrorResponse, HttpResponse } from '@angular/common/http';
 import { fakeAsync, tick } from '@angular/core/testing';
 import { faker } from '@faker-js/faker';
-import { Resource, ResourceUri } from '@ngxp/rest';
+import { expect } from '@jest/globals';
+import { getUrl, Resource, ResourceUri } from '@ngxp/rest';
 import { cold, hot } from 'jest-marbles';
-import { createBinaryFileResource, createBlob } from 'libs/binary-file-shared/test/binary-file';
+import { createBinaryFileResource, createBlob, createFile, createUploadFile } from 'libs/binary-file-shared/test/binary-file';
 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 { uniqueId } from 'lodash-es';
 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';
+import { multipleCold, singleCold, singleHot } from '../../../tech-shared/test/marbles';
+import { BinaryFileResource, FileUploadType, ToUploadFile, UploadFile, UploadFileByIdentifier } from './binary-file.model';
 import { BinaryFileRepository } from './binary-file.repository';
 import { BinaryFileService } from './binary-file.service';
 
@@ -57,6 +59,283 @@ describe('BinaryFileService', () => {
     expect(service).toBeTruthy();
   });
 
+  describe('addFiles', () => {
+    const type: FileUploadType = faker.word.noun();
+    const uniqueId: string = faker.word.noun();
+
+    beforeEach(() => {
+      service._generateUniqueId = jest.fn().mockReturnValue(uniqueId);
+    });
+
+    it('should not set uploaded file', () => {
+      service.addFiles(type, null);
+
+      expect(service._uploadFiles$).toBeObservable(singleCold({}));
+    });
+
+    it('should generate unique id', () => {
+      const binaryFileResource: BinaryFileResource = createBinaryFileResource();
+
+      service.addFiles(type, [binaryFileResource]);
+
+      expect(service._generateUniqueId).toHaveBeenCalled();
+    });
+
+    it('should set uploaded file', () => {
+      const binaryFileResource: BinaryFileResource = createBinaryFileResource();
+
+      service.addFiles(type, [binaryFileResource]);
+
+      const uploadedFile: UploadFile = service._uploadFiles$.value[type][uniqueId];
+      expect(uploadedFile).toEqual({ uploadedFile: createStateResource(binaryFileResource) } as UploadFile);
+    });
+  });
+
+  describe('upload file new', () => {
+    const uniqId: string = uniqueId();
+    const type: string = 'dummyType';
+    const file: File = createFile();
+    const toUploadFile: ToUploadFile = { type, file, uploadUrl: faker.internet.url() };
+
+    beforeEach(() => {
+      service._generateUniqueId = jest.fn().mockReturnValue(uniqId);
+      service._addUploadFileLoading = jest.fn();
+      service._doUploadFile = jest.fn();
+    });
+
+    it('should create an empty map if type key not exists', () => {
+      service._uploadFiles$.next({});
+
+      service.uploadFileNew(toUploadFile);
+
+      expect(service._uploadFiles$.value[type]).not.toBeUndefined();
+    });
+
+    it('should call addUploadFileLoading', () => {
+      service.uploadFileNew(toUploadFile);
+
+      expect(service._addUploadFileLoading).toHaveBeenCalledWith(uniqId, toUploadFile);
+    });
+
+    it('should call doUploadFile', () => {
+      service.uploadFileNew(toUploadFile);
+
+      expect(service._doUploadFile).toHaveBeenCalledWith(uniqId, toUploadFile);
+    });
+  });
+
+  describe('add upload file loading', () => {
+    const uniqId: string = uniqueId();
+    const type: string = 'dummyType';
+    const file: File = createFile();
+    const toUploadFile: ToUploadFile = { type, file, uploadUrl: faker.internet.url() };
+
+    it('should add loading entry by type', () => {
+      service._addUploadFileLoading(uniqId, toUploadFile);
+
+      expect((<UploadFileByIdentifier>service._uploadFiles$.value[type])[uniqId]).toEqual({
+        fileToUpload: file,
+        uploadedFile: createEmptyStateResource(true),
+      });
+    });
+
+    it('should add loading entry by type and keep existing entries', () => {
+      service._uploadFiles$.next({
+        ...service._uploadFiles$.value,
+        [toUploadFile.type]: {
+          ['keepId']: { fileToUpload: toUploadFile.file, uploadedFile: createStateResource(createBinaryFileResource()) },
+        },
+      });
+
+      service._addUploadFileLoading(uniqId, toUploadFile);
+
+      expect((<UploadFileByIdentifier>service._uploadFiles$.value[type])['keepId']).not.toBeUndefined();
+      expect((<UploadFileByIdentifier>service._uploadFiles$.value[type])[uniqId]).not.toBeUndefined();
+    });
+  });
+
+  describe('do upload file', () => {
+    const uniqId: string = 'id';
+    const type: string = 'dummyType';
+    const file: File = createFile();
+    const toUploadFile: ToUploadFile = { type, file, uploadUrl: faker.internet.url() };
+
+    const binaryFileResource: BinaryFileResource = createBinaryFileResource();
+
+    beforeEach(() => {
+      repository.uploadFileNew.mockReturnValue(of(binaryFileResource));
+      service._handleError = jest.fn();
+      service._updateUploadedFile = jest.fn();
+    });
+
+    it('should call repository', () => {
+      service._doUploadFile(uniqId, toUploadFile);
+
+      expect(repository.uploadFileNew).toHaveBeenCalledWith(toUploadFile.uploadUrl, file);
+    });
+
+    it('should call update uploaded file', () => {
+      service._doUploadFile(uniqId, toUploadFile);
+
+      expect(service._updateUploadedFile).toHaveBeenCalledWith(uniqId, toUploadFile, createStateResource(binaryFileResource));
+    });
+
+    it('should handle error', () => {
+      const errorResponse: HttpErrorResponse = createHttpErrorResponse();
+      repository.uploadFileNew.mockReturnValue(throwError(() => errorResponse));
+
+      service._doUploadFile(uniqId, toUploadFile);
+
+      expect(service._handleError).toHaveBeenCalledWith(errorResponse.error, false);
+    });
+
+    it('should update uploaded file on error', () => {
+      const errorResponse: HttpErrorResponse = createHttpErrorResponse();
+      service._handleError = jest.fn().mockReturnValue(of(createStateResource(errorResponse.error)));
+      repository.uploadFileNew.mockReturnValue(throwError(() => errorResponse));
+
+      service._doUploadFile(uniqId, toUploadFile);
+
+      expect(service._updateUploadedFile).toHaveBeenCalledWith(uniqId, toUploadFile, createStateResource(errorResponse.error));
+    });
+  });
+
+  describe('update upload file state', () => {
+    const type: string = 'dummyType';
+    const file: File = createFile();
+    const toUploadFile: ToUploadFile = { type, file, uploadUrl: faker.internet.url() };
+
+    const binaryFileResource: BinaryFileResource = createBinaryFileResource();
+
+    it('should set resource to state value', () => {
+      service._uploadFiles$.next({
+        ...service._uploadFiles$.value,
+        [toUploadFile.type]: {
+          ['keepEntryId']: { fileToUpload: toUploadFile.file, uploadedFile: createStateResource(binaryFileResource) },
+          ['updateEntryId']: { fileToUpload: toUploadFile.file, uploadedFile: createEmptyStateResource(true) },
+        },
+      });
+
+      service._updateUploadedFile('updateEntryId', toUploadFile, createStateResource(binaryFileResource));
+
+      expect((<UploadFileByIdentifier>service._uploadFiles$.value[type])['keepEntryId']).not.toBeUndefined();
+      expect((<UploadFileByIdentifier>service._uploadFiles$.value[type])['updateEntryId']).not.toBeUndefined();
+    });
+  });
+
+  describe('get uploaded files', () => {
+    const type: FileUploadType = 'DummyType';
+    const uploadFile: UploadFile = createUploadFile();
+
+    it('should return uploaded files by key', (done) => {
+      service._uploadFiles$.next({
+        ...service._uploadFiles$.value,
+        [type]: {
+          ['keepEntryId']: uploadFile,
+        },
+      });
+
+      service.getUploadedFiles(type).subscribe((uploadedFiles: UploadFileByIdentifier) => {
+        expect(uploadedFiles).toEqual({ ['keepEntryId']: uploadFile });
+        done();
+      });
+    });
+
+    describe('on non existing key', () => {
+      beforeEach(() => {
+        service._uploadFiles$.next({});
+      });
+
+      it('should return empty object', (done) => {
+        service.getUploadedFiles(type).subscribe((uploadedFiles: UploadFileByIdentifier) => {
+          expect(uploadedFiles).toEqual({});
+          done();
+        });
+      });
+
+      it('should set state value', () => {
+        service.getUploadedFiles(type).subscribe();
+
+        expect(service._uploadFiles$.value[type]).toEqual({});
+      });
+    });
+  });
+
+  describe('is upload in progress', () => {
+    const type: FileUploadType = 'DummyType';
+    const loadingUploadedFileEntry = {
+      fileToUpload: createFile(),
+      uploadedFile: createEmptyStateResource<BinaryFileResource>(true),
+    };
+    const loadedUploadedFileEntry = {
+      fileToUpload: createFile(),
+      uploadedFile: createStateResource<BinaryFileResource>(createBinaryFileResource()),
+    };
+
+    it('should return false on empty state', () => {
+      const uploadInProgress: Observable<boolean> = service.isUploadInProgress(type);
+
+      expect(uploadInProgress).toBeObservable(singleCold(false));
+    });
+
+    it('should return true if uploadedFiles contains loading stateResource by key', () => {
+      service._uploadFiles$.next({
+        ...service._uploadFiles$.value,
+        [type]: { ['loadingEntryId']: loadingUploadedFileEntry, ['loadedEntryId']: loadedUploadedFileEntry },
+      });
+
+      const uploadInProgress: Observable<boolean> = service.isUploadInProgress(type);
+
+      expect(uploadInProgress).toBeObservable(singleCold(true));
+    });
+
+    it('should return false if uploadedFiles contains loaded stateResources only', () => {
+      service._uploadFiles$.next({
+        ...service._uploadFiles$.value,
+        [type]: { ['loadedEntry1Id']: loadedUploadedFileEntry, ['loadedEntry2Id']: loadedUploadedFileEntry },
+      });
+
+      const uploadInProgress: Observable<boolean> = service.isUploadInProgress(type);
+
+      expect(uploadInProgress).toBeObservable(singleCold(false));
+    });
+  });
+
+  describe('delete uploaded file', () => {
+    const type: string = 'dummyType';
+    const file: File = createFile();
+    const toUploadFile: ToUploadFile = { type, file, uploadUrl: faker.internet.url() };
+
+    it('should remove entry by type and key', () => {
+      service._uploadFiles$.next({
+        ...service._uploadFiles$.value,
+        [toUploadFile.type]: {
+          ['keepEntryId']: { fileToUpload: toUploadFile.file, uploadedFile: createStateResource(createBinaryFileResource()) },
+          ['toRemoveEntryId']: {
+            fileToUpload: toUploadFile.file,
+            uploadedFile: createStateResource(createBinaryFileResource()),
+          },
+        },
+      });
+
+      service.deleteUploadedFile(toUploadFile.type, 'toRemoveEntryId');
+
+      expect((<UploadFileByIdentifier>service._uploadFiles$.value[type])['keepEntryId']).not.toBeUndefined();
+      expect((<UploadFileByIdentifier>service._uploadFiles$.value[type])['toRemoveEntryId']).toBeUndefined();
+    });
+  });
+
+  describe('clear uploaded files', () => {
+    it('should remove map by type from state', () => {
+      const type: FileUploadType = 'dummyType';
+      service._uploadFiles$.next({ ...service._uploadFiles$.value, [type]: {} });
+
+      service.clearUploadedFiles(type);
+
+      expect(service._uploadFiles$.value.hasOwnProperty(type)).toBeFalsy();
+    });
+  });
+
   describe('download file', () => {
     const binaryFileResource: BinaryFileResource = createBinaryFileResource();
     const downloadNamePrefix: string = 'VorgangsNummerAsPrefix';
@@ -79,12 +358,7 @@ describe('BinaryFileService', () => {
 
       const returnValue: Observable<StateResource<Blob>> = service.downloadFile(binaryFileResource, downloadNamePrefix);
 
-      expect(returnValue).toBeObservable(
-        cold('ab', {
-          a: createEmptyStateResource(true),
-          b: createStateResource(blob),
-        }),
-      );
+      expect(returnValue).toBeObservable(multipleCold(createEmptyStateResource(true), createStateResource(blob)));
     });
 
     describe('save data', () => {
@@ -203,8 +477,8 @@ describe('BinaryFileService', () => {
   });
 
   describe('upload file', () => {
-    const dummyResource: Resource = createDummyResource();
     const dummyLinkRel: string = DummyLinkRel.DUMMY;
+    const dummyResource: Resource = createDummyResource([dummyLinkRel]);
 
     const fileLocation: string = 'fileLocation';
     const uploadFileResponse: HttpResponse<Object> = <any>{
@@ -222,7 +496,7 @@ describe('BinaryFileService', () => {
     it('should call repository', () => {
       service.uploadFile(dummyResource, dummyLinkRel, testFile);
 
-      expect(repository.uploadFile).toHaveBeenCalledWith(dummyResource, dummyLinkRel, testFile);
+      expect(repository.uploadFile).toHaveBeenCalledWith(getUrl(dummyResource, dummyLinkRel), testFile);
     });
 
     it.skip('should call get file', fakeAsync(() => {
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 e06c03dff2f58d8e33467a52c08fc6a5f5e2f047..223db64a230da606052caaf48a90dc45cd60f6a8 100644
--- a/alfa-client/libs/binary-file-shared/src/lib/binary-file.service.ts
+++ b/alfa-client/libs/binary-file-shared/src/lib/binary-file.service.ts
@@ -21,52 +21,131 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-import {
-  BlobWithFileName,
-  EMPTY_STRING,
-  HttpHeader,
-  StateResource,
-  createEmptyStateResource,
-  createErrorStateResource,
-  createStateResource,
-  getMessageForInvalidParam,
-  isNotNil,
-  isUnprocessableEntity,
-  isValidationFieldFileSizeExceedError,
-  sanitizeFileName,
-} from '@alfa-client/tech-shared';
+import { BlobWithFileName, createEmptyStateResource, createErrorStateResource, createStateResource, EMPTY_STRING, getMessageForInvalidParam, HttpHeader, isNotNil, isUnprocessableEntity, isValidationFieldFileSizeExceedError, sanitizeFileName, StateResource, } from '@alfa-client/tech-shared';
 import { SnackBarService } from '@alfa-client/ui';
 import { HttpErrorResponse, HttpResponse } from '@angular/common/http';
 import { Injectable } from '@angular/core';
-import { Resource, ResourceUri } from '@ngxp/rest';
+import { getUrl, Resource, ResourceUri } from '@ngxp/rest';
 import { saveAs } from 'file-saver';
-import { isNil } from 'lodash-es';
-import { Observable, of, throwError } from 'rxjs';
-import { catchError, map, mergeMap, startWith } from 'rxjs/operators';
-import { BinaryFileListResource, BinaryFileResource } from './binary-file.model';
+import { isNil, uniqueId } from 'lodash-es';
+import { BehaviorSubject, Observable, of, throwError } from 'rxjs';
+import { catchError, first, map, mergeMap, startWith } from 'rxjs/operators';
+import { BinaryFileListResource, BinaryFileResource, FileUploadType, ToUploadFile, UploadFile, UploadFileByIdentifier, UploadFilesByType, } from './binary-file.model';
 import { BinaryFileRepository } from './binary-file.repository';
 
 @Injectable({ providedIn: 'root' })
 export class BinaryFileService {
+  _uploadFiles$: BehaviorSubject<UploadFilesByType> = new BehaviorSubject({});
+
   constructor(
     private repository: BinaryFileRepository,
     private snackbarService: SnackBarService,
   ) {}
 
+  public addFiles(type: FileUploadType, binaryFileResources: BinaryFileResource[]): void {
+    if (isNil(binaryFileResources)) return;
+    binaryFileResources.forEach((resource: BinaryFileResource) =>
+      this.setUploadedFile(this._generateUniqueId(), type, { uploadedFile: createStateResource(resource) }),
+    );
+  }
+
+  public uploadFileNew(toUploadFile: ToUploadFile): void {
+    this.createEmptyMapIfTypeNotExists(toUploadFile.type);
+    const uniqId: string = this._generateUniqueId();
+    this._addUploadFileLoading(uniqId, toUploadFile);
+    this._doUploadFile(uniqId, toUploadFile);
+  }
+
+  _generateUniqueId(): string {
+    return uniqueId();
+  }
+
+  _addUploadFileLoading(uniqId: string, toUploadFile: ToUploadFile): void {
+    this.setUploadedFile(uniqId, toUploadFile.type, {
+      fileToUpload: toUploadFile.file,
+      uploadedFile: createEmptyStateResource(true),
+    });
+  }
+
+  _doUploadFile(uniqId: string, toUploadFile: ToUploadFile): void {
+    this.repository
+      .uploadFileNew(toUploadFile.uploadUrl, toUploadFile.file)
+      .pipe(
+        first(),
+        map((resource: BinaryFileResource) => createStateResource(resource)),
+        catchError((errorResponse) => this._handleError(errorResponse.error, false)),
+      )
+      .subscribe((stateResource: StateResource<BinaryFileResource>) =>
+        this._updateUploadedFile(uniqId, toUploadFile, stateResource),
+      );
+  }
+
+  _updateUploadedFile(
+    uniqId: string,
+    toUploadFile: ToUploadFile,
+    binaryFileStateResource: StateResource<BinaryFileResource>,
+  ): void {
+    this.setUploadedFile(uniqId, toUploadFile.type, {
+      fileToUpload: toUploadFile.file,
+      uploadedFile: binaryFileStateResource,
+    });
+  }
+
+  private setUploadedFile(uniqId: string, type: FileUploadType, uploadedFile: UploadFile): void {
+    this._uploadFiles$.next({
+      ...this._uploadFiles$.value,
+      [type]: { ...this._uploadFiles$.value[type], [uniqId]: uploadedFile },
+    });
+  }
+
+  public getUploadedFiles(type: FileUploadType): Observable<UploadFileByIdentifier> {
+    this.createEmptyMapIfTypeNotExists(type);
+    return this._uploadFiles$.asObservable().pipe(map((files: UploadFilesByType) => files[type]));
+  }
+
+  private createEmptyMapIfTypeNotExists(type: FileUploadType): void {
+    if (!(type in this._uploadFiles$.value)) this._uploadFiles$.value[type] = {};
+  }
+
+  public isUploadInProgress(type: FileUploadType): Observable<boolean> {
+    return this._uploadFiles$.asObservable().pipe(
+      map((files: UploadFilesByType) => Object.values(files[type] || []).map((file: UploadFile) => file.uploadedFile)),
+      map((files: StateResource<BinaryFileResource>[]) =>
+        files.some((stateResource: StateResource<BinaryFileResource>) => stateResource.loading),
+      ),
+    );
+  }
+
+  public deleteUploadedFile(type: FileUploadType, key: string): void {
+    const currentMap: UploadFileByIdentifier = this._uploadFiles$.value[type];
+    this._uploadFiles$.next({
+      ...this._uploadFiles$.value,
+      [type]: Object.keys(currentMap).reduce((acc, uploadFileKey) => {
+        if (uploadFileKey !== key) acc[uploadFileKey] = currentMap[uploadFileKey];
+        return acc;
+      }, {}),
+    });
+  }
+
+  public clearUploadedFiles(type: FileUploadType): void {
+    delete this._uploadFiles$.value[type];
+  }
+
+  //TODO Rename to uploadFileOld OR refactor all use cases to uploadFileNew
   public uploadFile(
     resource: Resource,
     linkRel: string,
     file: File,
     showValidationErrorSnackBar: boolean = true,
   ): Observable<StateResource<BinaryFileResource>> {
-    return this.repository.uploadFile(resource, linkRel, file).pipe(
+    return this.repository.uploadFile(getUrl(resource, linkRel), file).pipe(
       mergeMap((response: HttpResponse<Object>) => this.getFile(response.headers.get(HttpHeader.LOCATION))),
-      catchError((errorResponse) => this.handleError(errorResponse.error, showValidationErrorSnackBar)),
+      catchError((errorResponse) => this._handleError(errorResponse.error, showValidationErrorSnackBar)),
       startWith(createEmptyStateResource<BinaryFileResource>(true)),
     );
   }
 
-  private handleError(errorResponse: HttpErrorResponse, showValidationErrorSnackBar: boolean): Observable<StateResource<any>> {
+  _handleError(errorResponse: HttpErrorResponse, showValidationErrorSnackBar: boolean): Observable<StateResource<any>> {
     return of(this.handleErrorByStatus(errorResponse, showValidationErrorSnackBar));
   }
 
diff --git a/alfa-client/libs/binary-file-shared/src/lib/binary-file.util.spec.ts b/alfa-client/libs/binary-file-shared/src/lib/binary-file.util.spec.ts
deleted file mode 100644
index c0ef7f3e2161b4bf245df02ac4c85b8fe4e445a4..0000000000000000000000000000000000000000
--- a/alfa-client/libs/binary-file-shared/src/lib/binary-file.util.spec.ts
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch den
- * Ministerpräsidenten des Landes Schleswig-Holstein
- * Staatskanzlei
- * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
- *
- * Lizenziert unter der EUPL, Version 1.2 oder - sobald
- * diese von der Europäischen Kommission genehmigt wurden -
- * Folgeversionen der EUPL ("Lizenz");
- * Sie dürfen dieses Werk ausschließlich gemäß
- * dieser Lizenz nutzen.
- * Eine Kopie der Lizenz finden Sie hier:
- *
- * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
- *
- * Sofern nicht durch anwendbare Rechtsvorschriften
- * gefordert oder in schriftlicher Form vereinbart, wird
- * die unter der Lizenz verbreitete Software "so wie sie
- * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
- * ausdrücklich oder stillschweigend - verbreitet.
- * Die sprachspezifischen Genehmigungen und Beschränkungen
- * unter der Lizenz sind dem Lizenztext zu entnehmen.
- */
-import { StateResource, createStateResource } from '@alfa-client/tech-shared';
-import {
-  createBinaryFileListResource,
-  createBinaryFileResource,
-} from 'libs/binary-file-shared/test/binary-file';
-import { BinaryFileListResource, BinaryFileResource } from './binary-file.model';
-import { getBinaryFiles } from './binary-file.util';
-
-describe('BinaryFile Util', () => {
-  describe('getBinaryFiles', () => {
-    it('should extract resource', () => {
-      const binaryFileResources: BinaryFileResource[] = [createBinaryFileResource()];
-      const binaryFileListStateResource: StateResource<BinaryFileListResource> =
-        createStateResource(createBinaryFileListResource(binaryFileResources));
-
-      const resources: BinaryFileResource[] = getBinaryFiles(binaryFileListStateResource);
-
-      expect(resources).toEqual(binaryFileResources);
-    });
-  });
-});
diff --git a/alfa-client/libs/binary-file-shared/src/lib/binary-file.util.ts b/alfa-client/libs/binary-file-shared/src/lib/binary-file.util.ts
deleted file mode 100644
index 2f43cda4d54bbb7c13428cefc46a5580c6a63e7b..0000000000000000000000000000000000000000
--- a/alfa-client/libs/binary-file-shared/src/lib/binary-file.util.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch den
- * Ministerpräsidenten des Landes Schleswig-Holstein
- * Staatskanzlei
- * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
- *
- * Lizenziert unter der EUPL, Version 1.2 oder - sobald
- * diese von der Europäischen Kommission genehmigt wurden -
- * Folgeversionen der EUPL ("Lizenz");
- * Sie dürfen dieses Werk ausschließlich gemäß
- * dieser Lizenz nutzen.
- * Eine Kopie der Lizenz finden Sie hier:
- *
- * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
- *
- * Sofern nicht durch anwendbare Rechtsvorschriften
- * gefordert oder in schriftlicher Form vereinbart, wird
- * die unter der Lizenz verbreitete Software "so wie sie
- * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
- * ausdrücklich oder stillschweigend - verbreitet.
- * Die sprachspezifischen Genehmigungen und Beschränkungen
- * unter der Lizenz sind dem Lizenztext zu entnehmen.
- */
-import { StateResource, getEmbeddedResources } from '@alfa-client/tech-shared';
-import { BinaryFileListLinkRel } from './binary-file.linkrel';
-import { BinaryFileListResource, BinaryFileResource } from './binary-file.model';
-
-export function getBinaryFiles(
-  binaryFileListResource: StateResource<BinaryFileListResource>,
-): BinaryFileResource[] {
-  return getEmbeddedResources(binaryFileListResource, BinaryFileListLinkRel.FILE_LIST);
-}
-
-export enum BinaryFileIcon {
-  'application/pdf' = 'pdf',
-  'application/json' = 'json',
-  'application/msword' = 'doc',
-  'application/vnd.openxmlformats-officedocument.wordprocessingml.document' = 'doc',
-  'application/xml' = 'xml',
-  'text/xml' = 'xml',
-  'image/apng' = 'image',
-  'image/gif' = 'image',
-  'image/jpeg' = 'image',
-  'image/png' = 'image',
-  'image/svg+xml' = 'image',
-}
diff --git a/alfa-client/libs/binary-file-shared/test/binary-file.ts b/alfa-client/libs/binary-file-shared/test/binary-file.ts
index 9ff52a575cc75251741005b7c38acacb30389b72..b0aca564400e4ee49266e1c529f89ce2346f211c 100644
--- a/alfa-client/libs/binary-file-shared/test/binary-file.ts
+++ b/alfa-client/libs/binary-file-shared/test/binary-file.ts
@@ -21,13 +21,15 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-import { GetRequestOptions, StateResource, createStateResource } from '@alfa-client/tech-shared';
+import { createStateResource, GetRequestOptions, StateResource } from '@alfa-client/tech-shared';
 import { faker } from '@faker-js/faker';
 import { BinaryFileListLinkRel } from 'libs/binary-file-shared/src/lib/binary-file.linkrel';
 import {
   BinaryFile,
   BinaryFileListResource,
   BinaryFileResource,
+  ToUploadFile,
+  UploadFile,
 } from 'libs/binary-file-shared/src/lib/binary-file.model';
 import { toResource } from 'libs/tech-shared/test/resource';
 import { times } from 'lodash-es';
@@ -65,10 +67,35 @@ export function createLoadedBinaryFileResource(): StateResource<BinaryFileResour
   return createStateResource(createBinaryFileResource());
 }
 
+export function createGetRequestOptions(): GetRequestOptions {
+  return <GetRequestOptions>{};
+}
+
 export function createBlob(): Blob {
-  return <Blob>{};
+  const dummyData = new Uint8Array([65, 66, 67]);
+  return new Blob([dummyData], { type: 'text/plain' });
 }
 
-export function createGetRequestOptions(): GetRequestOptions {
-  return <GetRequestOptions>{};
+export function createFile(): File {
+  return {
+    ...createBlob(),
+    name: faker.string.alpha({ length: { min: 1, max: 50 } }),
+    lastModified: faker.date.past().getTime(),
+    webkitRelativePath: null,
+  };
+}
+
+export function createUploadFile(): UploadFile {
+  return {
+    fileToUpload: createFile(),
+    uploadedFile: createStateResource(createBinaryFileResource()),
+  };
+}
+
+export function createToUploadFile(): ToUploadFile {
+  return {
+    file: createFile(),
+    type: faker.word.noun(),
+    uploadUrl: faker.internet.url(),
+  };
 }
diff --git a/alfa-client/libs/binary-file/src/index.ts b/alfa-client/libs/binary-file/src/index.ts
index 0de3c8e5665e8ef1080af949ee0833d3d7f6b762..0797fec271485748cb2070218373df404cf2f29b 100644
--- a/alfa-client/libs/binary-file/src/index.ts
+++ b/alfa-client/libs/binary-file/src/index.ts
@@ -27,5 +27,7 @@ export * from './lib/binary-file-list-container/binary-file-list-container.compo
 export * from './lib/binary-file-uri-container/binary-file-uri-container.component';
 export * from './lib/binary-file.module';
 export * from './lib/binary-file2-container/binary-file2-container.component';
+export * from './lib/file-upload-list-container/file-upload-list-container.component';
 export * from './lib/horizontal-binary-file-list/horizontal-binary-file-list.component';
+export * from './lib/multi-file-upload-editor/multi-file-upload-editor.component';
 export * from './lib/vertical-binary-file-list/vertical-binary-file-list.component';
diff --git a/alfa-client/libs/binary-file/src/lib/binary-file-attachment-container/binary-file-attachment-container.component.ts b/alfa-client/libs/binary-file/src/lib/binary-file-attachment-container/binary-file-attachment-container.component.ts
index 895af8531079cc44bd5b1a76c691e9fd0c838be4..73d241e3fcf664c3a7dc19f1ac00d01a3079cfc3 100644
--- a/alfa-client/libs/binary-file/src/lib/binary-file-attachment-container/binary-file-attachment-container.component.ts
+++ b/alfa-client/libs/binary-file/src/lib/binary-file-attachment-container/binary-file-attachment-container.component.ts
@@ -21,15 +21,9 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-import { Component, Input } from '@angular/core';
 import { BinaryFileResource, BinaryFileService } from '@alfa-client/binary-file-shared';
-import {
-  EMPTY_ARRAY,
-  StateResource,
-  createEmptyStateResource,
-  doOnValidStateResource,
-  isNotNil,
-} from '@alfa-client/tech-shared';
+import { StateResource, createEmptyStateResource, doOnValidStateResource, isNotNil } from '@alfa-client/tech-shared';
+import { Component, Input } from '@angular/core';
 import { Resource, getUrl } from '@ngxp/rest';
 import { Observable, of } from 'rxjs';
 import { tap } from 'rxjs/operators';
@@ -44,11 +38,11 @@ export class BinaryFileAttachmentContainerComponent {
   @Input() uploadStateResource: StateResource<Resource>;
   @Input() linkRelUploadAttachment: string;
   @Input() set existFiles(value: BinaryFileResource[]) {
-    this.fileList = isNotNil(value) ? value : EMPTY_ARRAY;
+    this.fileList = isNotNil(value) ? value : [];
   }
 
   uploadInProgress$: Observable<StateResource<Resource>> = of(createEmptyStateResource<Resource>());
-  fileList: BinaryFileResource[] = EMPTY_ARRAY;
+  fileList: BinaryFileResource[] = [];
 
   constructor(private binaryFileService: BinaryFileService) {}
 
@@ -63,18 +57,11 @@ export class BinaryFileAttachmentContainerComponent {
   uploadAndGetFile(file: File): Observable<StateResource<BinaryFileResource>> {
     return this.binaryFileService
       .uploadFile(this.uploadStateResource.resource, this.linkRelUploadAttachment, file)
-      .pipe(
-        tap((stateResource: StateResource<BinaryFileResource>) =>
-          this.doAfterFileUpload(stateResource),
-        ),
-      );
+      .pipe(tap((stateResource: StateResource<BinaryFileResource>) => this.doAfterFileUpload(stateResource)));
   }
 
   doAfterFileUpload(stateResource: StateResource<BinaryFileResource>): void {
-    doOnValidStateResource(
-      stateResource,
-      () => (this.fileList = [...this.fileList, stateResource.resource]),
-    );
+    doOnValidStateResource(stateResource, () => (this.fileList = [...this.fileList, stateResource.resource]));
   }
 
   public deleteAttachment(binaryFile: BinaryFileResource): void {
diff --git a/alfa-client/libs/binary-file/src/lib/binary-file-list-container/binary-file-list-container.component.html b/alfa-client/libs/binary-file/src/lib/binary-file-list-container/binary-file-list-container.component.html
index b6efd87e00828c83f8bb8b4a0ff6d3dfb509fa41..cfa93fbc6b3b9dbd01834a8d31c1bf74f4088299 100644
--- a/alfa-client/libs/binary-file/src/lib/binary-file-list-container/binary-file-list-container.component.html
+++ b/alfa-client/libs/binary-file/src/lib/binary-file-list-container/binary-file-list-container.component.html
@@ -26,5 +26,6 @@
 <ods-attachment-wrapper>
   <alfa-binary-file-list
     [binaryFileListStateResource]="binaryFileListStateResource$ | async"
+    [listOrientation]="listOrientation"
   ></alfa-binary-file-list>
 </ods-attachment-wrapper>
diff --git a/alfa-client/libs/binary-file/src/lib/binary-file-list-container/binary-file-list-container.component.ts b/alfa-client/libs/binary-file/src/lib/binary-file-list-container/binary-file-list-container.component.ts
index 4515dda8f1d00fb992b3b613e8dc9ab79360bf91..b4dce3b40b8590f8037ad669d5469f6c88942f93 100644
--- a/alfa-client/libs/binary-file/src/lib/binary-file-list-container/binary-file-list-container.component.ts
+++ b/alfa-client/libs/binary-file/src/lib/binary-file-list-container/binary-file-list-container.component.ts
@@ -21,15 +21,12 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-import {
-  BinaryFileListLinkRel,
-  BinaryFileListResource,
-  BinaryFileService,
-} from '@alfa-client/binary-file-shared';
+import { BinaryFileListResource, BinaryFileService } from '@alfa-client/binary-file-shared';
 import { LinkRelationName, StateResource } from '@alfa-client/tech-shared';
 import { Component, Input, OnInit } from '@angular/core';
 import { Resource } from '@ngxp/rest';
 import { Observable } from 'rxjs';
+import { BinaryFileListOrientation } from '../directive/binary-file-list-orientation/binary-file-list-orientation.directive';
 
 @Component({
   selector: 'alfa-binary-file-list-container',
@@ -38,11 +35,10 @@ import { Observable } from 'rxjs';
 export class BinaryFileListContainerComponent implements OnInit {
   @Input() resource: Resource;
   @Input() linkRel: LinkRelationName;
+  @Input() listOrientation: BinaryFileListOrientation = BinaryFileListOrientation.HORIZONTAL;
 
   public binaryFileListStateResource$: Observable<StateResource<BinaryFileListResource>>;
 
-  public readonly binaryFileListLinkRel = BinaryFileListLinkRel;
-
   constructor(private service: BinaryFileService) {}
 
   ngOnInit(): void {
diff --git a/alfa-client/libs/binary-file/src/lib/binary-file-list-container/binary-file-list/binary-file-list.component.html b/alfa-client/libs/binary-file/src/lib/binary-file-list-container/binary-file-list/binary-file-list.component.html
index ca935c68da85787e1a6404452d9be4dd0c466cbf..70054de869940144f9b0e1d3fa0eb7c23ea72a33 100644
--- a/alfa-client/libs/binary-file/src/lib/binary-file-list-container/binary-file-list/binary-file-list.component.html
+++ b/alfa-client/libs/binary-file/src/lib/binary-file-list-container/binary-file-list/binary-file-list.component.html
@@ -23,12 +23,11 @@
     unter der Lizenz sind dem Lizenztext zu entnehmen.
 
 -->
-<alfa-binary-file2-container
-  *ngFor="
-    let binaryFile of binaryFileListStateResource.resource
-      | toEmbeddedResources: binaryFileListLinkRel.FILE_LIST
-  "
-  [file]="binaryFile"
-  [deletable]="false"
->
-</alfa-binary-file2-container>
+<div [binaryFileListOrientation]="listOrientation">
+  <alfa-binary-file2-container
+    *ngFor="let binaryFile of binaryFileListStateResource.resource | toEmbeddedResources: binaryFileListLinkRel.FILE_LIST"
+    [file]="binaryFile"
+    [deletable]="false"
+  >
+  </alfa-binary-file2-container>
+</div>
diff --git a/alfa-client/libs/binary-file/src/lib/binary-file-list-container/binary-file-list/binary-file-list.component.spec.ts b/alfa-client/libs/binary-file/src/lib/binary-file-list-container/binary-file-list/binary-file-list.component.spec.ts
index b90c651f44cba9b96f13aec0f6dec08348572bba..fbbc820600ee4d1b3a9235dafd3515f9c1f16404 100644
--- a/alfa-client/libs/binary-file/src/lib/binary-file-list-container/binary-file-list/binary-file-list.component.spec.ts
+++ b/alfa-client/libs/binary-file/src/lib/binary-file-list-container/binary-file-list/binary-file-list.component.spec.ts
@@ -22,19 +22,13 @@
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
 import { BinaryFileListResource, BinaryFileResource } from '@alfa-client/binary-file-shared';
-import {
-  StateResource,
-  ToEmbeddedResourcesPipe,
-  createStateResource,
-} from '@alfa-client/tech-shared';
+import { createStateResource, StateResource, ToEmbeddedResourcesPipe } from '@alfa-client/tech-shared';
 import { getMockComponent } from '@alfa-client/test-utils';
 import { ComponentFixture, TestBed } from '@angular/core/testing';
-import {
-  createBinaryFileListResource,
-  createBinaryFileResource,
-} from 'libs/binary-file-shared/test/binary-file';
-import { MockComponent } from 'ng-mocks';
+import { createBinaryFileListResource, createBinaryFileResource } from 'libs/binary-file-shared/test/binary-file';
+import { MockComponent, MockDirective } from 'ng-mocks';
 import { BinaryFile2ContainerComponent } from '../../binary-file2-container/binary-file2-container.component';
+import { BinaryFileListOrientationDirective } from '../../directive/binary-file-list-orientation/binary-file-list-orientation.directive';
 import { BinaryFileListComponent } from './binary-file-list.component';
 
 describe('BinaryFileListComponent', () => {
@@ -52,6 +46,7 @@ describe('BinaryFileListComponent', () => {
         BinaryFileListComponent,
         ToEmbeddedResourcesPipe,
         MockComponent(BinaryFile2ContainerComponent),
+        MockDirective(BinaryFileListOrientationDirective),
       ],
     }).compileComponents();
 
@@ -67,15 +62,19 @@ describe('BinaryFileListComponent', () => {
 
   describe('binary file container', () => {
     it('should be called with file', () => {
-      const binaryFileContainerComponent: BinaryFile2ContainerComponent =
-        getMockComponent<BinaryFile2ContainerComponent>(fixture, BinaryFile2ContainerComponent);
+      const binaryFileContainerComponent: BinaryFile2ContainerComponent = getMockComponent<BinaryFile2ContainerComponent>(
+        fixture,
+        BinaryFile2ContainerComponent,
+      );
 
       expect(binaryFileContainerComponent.file).toBe(binaryFile);
     });
 
     it('should be called with deleteable', () => {
-      const binaryFileContainerComponent: BinaryFile2ContainerComponent =
-        getMockComponent<BinaryFile2ContainerComponent>(fixture, BinaryFile2ContainerComponent);
+      const binaryFileContainerComponent: BinaryFile2ContainerComponent = getMockComponent<BinaryFile2ContainerComponent>(
+        fixture,
+        BinaryFile2ContainerComponent,
+      );
 
       expect(binaryFileContainerComponent.deletable).toBeFalsy();
     });
diff --git a/alfa-client/libs/binary-file/src/lib/binary-file-list-container/binary-file-list/binary-file-list.component.ts b/alfa-client/libs/binary-file/src/lib/binary-file-list-container/binary-file-list/binary-file-list.component.ts
index 33f6ef5e25a5b1a1dc06033c9354befc355cf204..f0ddb940344f0afeabe9b855b04a1d189b9f2840 100644
--- a/alfa-client/libs/binary-file/src/lib/binary-file-list-container/binary-file-list/binary-file-list.component.ts
+++ b/alfa-client/libs/binary-file/src/lib/binary-file-list-container/binary-file-list/binary-file-list.component.ts
@@ -24,6 +24,7 @@
 import { BinaryFileListLinkRel, BinaryFileListResource } from '@alfa-client/binary-file-shared';
 import { StateResource } from '@alfa-client/tech-shared';
 import { Component, Input } from '@angular/core';
+import { BinaryFileListOrientation } from '../../directive/binary-file-list-orientation/binary-file-list-orientation.directive';
 
 @Component({
   selector: 'alfa-binary-file-list',
@@ -31,6 +32,7 @@ import { Component, Input } from '@angular/core';
 })
 export class BinaryFileListComponent {
   @Input() public binaryFileListStateResource: StateResource<BinaryFileListResource>;
+  @Input() listOrientation: BinaryFileListOrientation = BinaryFileListOrientation.HORIZONTAL;
 
   public readonly binaryFileListLinkRel = BinaryFileListLinkRel;
 }
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 9327cbb0be7ef4527eff2aaf36b8f4ffac6e0cb3..362e1cbf5dc20d32ce56b18adbafad5e0ecd7b65 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
@@ -28,14 +28,7 @@ import { NgModule } from '@angular/core';
 import { MatIcon } from '@angular/material/icon';
 import { MatTooltip } from '@angular/material/tooltip';
 import { DownloadButtonComponent } from '@ods/component';
-import {
-  AttachmentComponent,
-  AttachmentHeaderComponent,
-  AttachmentWrapperComponent,
-  CloseIconComponent,
-  SpinnerIconComponent,
-  TooltipDirective,
-} from '@ods/system';
+import { AttachmentComponent, AttachmentHeaderComponent, AttachmentWrapperComponent, CloseIconComponent, SpinnerIconComponent, TooltipDirective, } from '@ods/system';
 import { FileSizePlainPipe } from '../../../tech-shared/src/lib/pipe/file-size-plain.pipe';
 import { FileUploadEditorComponent } from '../../../ui/src/lib/ui/editor/file-upload-editor/file-upload-editor.component';
 import { BinaryFileAttachmentContainerComponent } from './binary-file-attachment-container/binary-file-attachment-container.component';
@@ -46,6 +39,7 @@ import { BinaryFileListComponent } from './binary-file-list-container/binary-fil
 import { BinaryFileUriContainerComponent } from './binary-file-uri-container/binary-file-uri-container.component';
 import { BinaryFile2ContainerComponent } from './binary-file2-container/binary-file2-container.component';
 import { BinaryFile2Component } from './binary-file2-container/binary-file2/binary-file2.component';
+import { BinaryFileListOrientationDirective } from './directive/binary-file-list-orientation/binary-file-list-orientation.directive';
 import { DownloadArchiveFileButtonContainerComponent } from './download-archive-file-button-container/download-archive-file-button-container.component';
 import { HorizontalBinaryFileListComponent } from './horizontal-binary-file-list/horizontal-binary-file-list.component';
 import { VerticalBinaryFileListComponent } from './vertical-binary-file-list/vertical-binary-file-list.component';
@@ -70,6 +64,7 @@ import { VerticalBinaryFileListComponent } from './vertical-binary-file-list/ver
     ToEmbeddedResourcesPipe,
     FileSizePlainPipe,
     TooltipDirective,
+    BinaryFileListOrientationDirective,
   ],
   declarations: [
     BinaryFileAttachmentContainerComponent,
diff --git a/alfa-client/libs/binary-file/src/lib/binary-file2-container/binary-file2/binary-file2.component.html b/alfa-client/libs/binary-file/src/lib/binary-file2-container/binary-file2/binary-file2.component.html
index 96927c6b043705cd333e9783282e98ceeca9bc79..28d0e68be052035a9f7b7ce8cdbb940fb3decda2 100644
--- a/alfa-client/libs/binary-file/src/lib/binary-file2-container/binary-file2/binary-file2.component.html
+++ b/alfa-client/libs/binary-file/src/lib/binary-file2-container/binary-file2/binary-file2.component.html
@@ -40,6 +40,7 @@
       (click)="deleteFile($event)"
       title="Anhang löschen"
       aria-label="Anhang löschen Button"
+      data-test-class="delete-file-button"
     >
       <ods-close-icon class="fill-text"></ods-close-icon>
     </button>
diff --git a/alfa-client/libs/binary-file/src/lib/directive/binary-file-list-orientation/binary-file-list-orientation.directive.spec.ts b/alfa-client/libs/binary-file/src/lib/directive/binary-file-list-orientation/binary-file-list-orientation.directive.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..82a862b8793d0ae55026acbcc19c83488eb0d610
--- /dev/null
+++ b/alfa-client/libs/binary-file/src/lib/directive/binary-file-list-orientation/binary-file-list-orientation.directive.spec.ts
@@ -0,0 +1,64 @@
+import { expect } from '@jest/globals';
+import {
+  _horizontalClasses,
+  _verticalClasses,
+  BinaryFileListOrientation,
+  BinaryFileListOrientationDirective,
+} from './binary-file-list-orientation.directive';
+
+describe('BinaryFileListOrientationDirective', () => {
+  let directive: BinaryFileListOrientationDirective;
+  let elementRef: any = {};
+
+  beforeEach(() => {
+    elementRef = {
+      nativeElement: {
+        classList: {
+          add: jest.fn(),
+        },
+      },
+    };
+    directive = new BinaryFileListOrientationDirective(elementRef);
+  });
+
+  describe('set binaryFileListOrientation', () => {
+    beforeEach(() => {
+      directive._evaluateClasses = jest.fn().mockReturnValue([]);
+    });
+
+    it('should evaluate classes', () => {
+      directive.binaryFileListOrientation = BinaryFileListOrientation.HORIZONTAL;
+
+      expect(directive._evaluateClasses).toHaveBeenCalledWith(BinaryFileListOrientation.HORIZONTAL);
+    });
+
+    it('should add classes', () => {
+      const classes: string[] = ['test'];
+      directive._evaluateClasses = jest.fn().mockReturnValue(classes);
+
+      directive.binaryFileListOrientation = BinaryFileListOrientation.HORIZONTAL;
+
+      expect(elementRef.nativeElement.classList.add).toHaveBeenCalledWith('test');
+    });
+  });
+
+  describe('_evaluateClasses', () => {
+    it('should return horizontal classes', () => {
+      const classes: string[] = directive._evaluateClasses(BinaryFileListOrientation.HORIZONTAL);
+
+      expect(classes).toEqual(_horizontalClasses);
+    });
+
+    it('should return vertical classes', () => {
+      const classes: string[] = directive._evaluateClasses(BinaryFileListOrientation.VERTICAL);
+
+      expect(classes).toEqual(_verticalClasses);
+    });
+
+    it('should return horizontal classes by default', () => {
+      const classes: string[] = directive._evaluateClasses(null);
+
+      expect(classes).toEqual(_horizontalClasses);
+    });
+  });
+});
diff --git a/alfa-client/libs/binary-file/src/lib/directive/binary-file-list-orientation/binary-file-list-orientation.directive.ts b/alfa-client/libs/binary-file/src/lib/directive/binary-file-list-orientation/binary-file-list-orientation.directive.ts
new file mode 100644
index 0000000000000000000000000000000000000000..3a1a42958aca047046c5aa29edaed15dc77a1705
--- /dev/null
+++ b/alfa-client/libs/binary-file/src/lib/directive/binary-file-list-orientation/binary-file-list-orientation.directive.ts
@@ -0,0 +1,32 @@
+import { Directive, ElementRef, Input } from '@angular/core';
+
+export const _verticalClasses: string[] = ['flex', 'flex-col'];
+export const _horizontalClasses: string[] = ['flex', 'flex-row', 'flex-wrap'];
+
+export enum BinaryFileListOrientation {
+  HORIZONTAL = 'horizontal',
+  VERTICAL = 'vertical',
+}
+
+@Directive({
+  selector: '[binaryFileListOrientation]',
+  standalone: true,
+})
+export class BinaryFileListOrientationDirective {
+  @Input() set binaryFileListOrientation(orientation: BinaryFileListOrientation) {
+    this.el.nativeElement.classList.add(...this._evaluateClasses(orientation));
+  }
+
+  constructor(private readonly el: ElementRef) {}
+
+  _evaluateClasses(orientation: BinaryFileListOrientation): string[] {
+    switch (orientation) {
+      case BinaryFileListOrientation.VERTICAL:
+        return _verticalClasses;
+      case BinaryFileListOrientation.HORIZONTAL:
+        return _horizontalClasses;
+      default:
+        return _horizontalClasses;
+    }
+  }
+}
diff --git a/alfa-client/libs/binary-file/src/lib/file-upload-list-container/file-upload-list-container.component.html b/alfa-client/libs/binary-file/src/lib/file-upload-list-container/file-upload-list-container.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..e95763af4b9cb08c7b3164618e4910199d2dafd5
--- /dev/null
+++ b/alfa-client/libs/binary-file/src/lib/file-upload-list-container/file-upload-list-container.component.html
@@ -0,0 +1,6 @@
+<ods-file-upload-list
+  [uploadedFiles]="uploadedFiles$ | async"
+  [parentFormArrayName]="parentFormArrayName"
+  [listOrientation]="listOrientation"
+  (delete)="onDelete($event)"
+></ods-file-upload-list>
diff --git a/alfa-client/libs/binary-file/src/lib/file-upload-list-container/file-upload-list-container.component.spec.ts b/alfa-client/libs/binary-file/src/lib/file-upload-list-container/file-upload-list-container.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..379778effd26148200f2700038bb76a38fa23bb7
--- /dev/null
+++ b/alfa-client/libs/binary-file/src/lib/file-upload-list-container/file-upload-list-container.component.spec.ts
@@ -0,0 +1,134 @@
+import { BinaryFileListLinkRel, BinaryFileListResource, BinaryFileService, UploadFile } from '@alfa-client/binary-file-shared';
+import { createStateResource, getEmbeddedResources, StateResource } from '@alfa-client/tech-shared';
+import { mock, Mock } from '@alfa-client/test-utils';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { faker } from '@faker-js/faker';
+import { expect } from '@jest/globals';
+import { cold } from 'jest-marbles';
+import { MockComponent } from 'ng-mocks';
+import { EMPTY, of } from 'rxjs';
+import { createBinaryFileListResource, createUploadFile } from '../../../../binary-file-shared/test/binary-file';
+import { DummyLinkRel } from '../../../../tech-shared/test/dummy';
+import { singleColdCompleted } from '../../../../tech-shared/test/marbles';
+import { createDummyResource } from '../../../../tech-shared/test/resource';
+import { BinaryFileListOrientation } from '../directive/binary-file-list-orientation/binary-file-list-orientation.directive';
+import { FileUploadListContainerComponent } from './file-upload-list-container.component';
+import { FileUploadListComponent } from './file-upload-list/file-upload-list.component';
+
+describe('FileUploadListContainerComponent', () => {
+  let component: FileUploadListContainerComponent;
+  let fixture: ComponentFixture<FileUploadListContainerComponent>;
+
+  let binaryFileService: Mock<BinaryFileService>;
+
+  beforeEach(() => {
+    binaryFileService = mock(BinaryFileService);
+  });
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: [FileUploadListContainerComponent],
+      declarations: [MockComponent(FileUploadListComponent)],
+      providers: [{ provide: BinaryFileService, useValue: binaryFileService }],
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(FileUploadListContainerComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  describe('component', () => {
+    it('should create', () => {
+      expect(component).toBeTruthy();
+    });
+
+    it('should have default value', () => {
+      expect(component.listOrientation).toEqual(BinaryFileListOrientation.HORIZONTAL);
+    });
+
+    describe('ngOnInit', () => {
+      beforeEach(() => {
+        binaryFileService.getFiles.mockReturnValue(EMPTY);
+      });
+
+      describe('on existing files', () => {
+        beforeEach(() => {
+          component.filesResource = createDummyResource([DummyLinkRel.DUMMY]);
+          component.filesLinkRel = DummyLinkRel.DUMMY;
+          component.fileUploadType = faker.word.noun();
+        });
+
+        it('should load existing files', () => {
+          component.filesResource = createDummyResource([DummyLinkRel.DUMMY]);
+          component.filesLinkRel = DummyLinkRel.DUMMY;
+
+          component.ngOnInit();
+
+          expect(binaryFileService.getFiles).toHaveBeenCalledWith(component.filesResource, component.filesLinkRel);
+        });
+
+        it('should add loaded files', () => {
+          const stateResource: StateResource<BinaryFileListResource> = createStateResource(createBinaryFileListResource());
+          binaryFileService.getFiles.mockReturnValue(of(stateResource));
+
+          component.ngOnInit();
+          component.uploadedFiles$.subscribe();
+
+          expect(binaryFileService.addFiles).toHaveBeenCalledWith(
+            component.fileUploadType,
+            getEmbeddedResources(stateResource, BinaryFileListLinkRel.FILE_LIST),
+          );
+        });
+
+        it('should get uploaded files', () => {
+          const stateResource: StateResource<BinaryFileListResource> = createStateResource(createBinaryFileListResource());
+          binaryFileService.getFiles.mockReturnValue(of(stateResource));
+
+          component.ngOnInit();
+          component.uploadedFiles$.subscribe();
+
+          expect(binaryFileService.getUploadedFiles).toHaveBeenCalledWith(component.fileUploadType);
+        });
+
+        it('should emit values', () => {
+          const stateResource: StateResource<BinaryFileListResource> = createStateResource(createBinaryFileListResource());
+          binaryFileService.getFiles.mockReturnValue(cold('-a', { a: stateResource }));
+          const uploadedFiles: UploadFile[] = [createUploadFile()];
+          binaryFileService.getUploadedFiles.mockReturnValue(cold('-a', { a: uploadedFiles }));
+
+          component.ngOnInit();
+
+          expect(component.uploadedFiles$).toBeObservable(cold('a-b', { a: {}, b: uploadedFiles }));
+        });
+      });
+
+      describe('on none existing files', () => {
+        beforeEach(() => {
+          component.filesResource = createDummyResource();
+          component.filesLinkRel = DummyLinkRel.DUMMY;
+        });
+
+        it('should NOT load existing files', () => {
+          component.ngOnInit();
+
+          expect(binaryFileService.getFiles).not.toHaveBeenCalled();
+        });
+
+        it('should get uploaded files', () => {
+          component.ngOnInit();
+
+          expect(binaryFileService.getUploadedFiles).toHaveBeenCalledWith(component.fileUploadType);
+        });
+
+        it('should set uploaded files', () => {
+          const uploadFile: UploadFile = createUploadFile();
+          binaryFileService.getUploadedFiles = jest.fn().mockReturnValue(singleColdCompleted(uploadFile));
+
+          component.ngOnInit();
+
+          expect(component.uploadedFiles$).toBeObservable(singleColdCompleted(uploadFile));
+        });
+      });
+    });
+  });
+});
diff --git a/alfa-client/libs/binary-file/src/lib/file-upload-list-container/file-upload-list-container.component.ts b/alfa-client/libs/binary-file/src/lib/file-upload-list-container/file-upload-list-container.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b469cf13efa570da4d4e4ca4374d4a75043592fb
--- /dev/null
+++ b/alfa-client/libs/binary-file/src/lib/file-upload-list-container/file-upload-list-container.component.ts
@@ -0,0 +1,52 @@
+import {
+  BinaryFileListLinkRel,
+  BinaryFileListResource,
+  BinaryFileResource,
+  BinaryFileService,
+  UploadFileByIdentifier,
+} from '@alfa-client/binary-file-shared';
+import { getEmbeddedResources, isLoaded, StateResource } from '@alfa-client/tech-shared';
+import { AsyncPipe } from '@angular/common';
+import { Component, inject, Input, OnInit } from '@angular/core';
+import { hasLink, Resource } from '@ngxp/rest';
+import { filter, map, Observable, startWith, switchMap } from 'rxjs';
+import { tap } from 'rxjs/operators';
+import { BinaryFileListOrientation } from '../directive/binary-file-list-orientation/binary-file-list-orientation.directive';
+import { FileUploadListComponent } from './file-upload-list/file-upload-list.component';
+
+@Component({
+  selector: 'ods-file-upload-list-container',
+  standalone: true,
+  templateUrl: './file-upload-list-container.component.html',
+  imports: [FileUploadListComponent, AsyncPipe],
+})
+export class FileUploadListContainerComponent implements OnInit {
+  @Input() fileUploadType: string;
+  @Input() parentFormArrayName: string;
+  @Input() listOrientation: BinaryFileListOrientation = BinaryFileListOrientation.HORIZONTAL;
+  @Input() filesResource: Resource;
+  @Input() filesLinkRel: string;
+  private readonly binaryFileService: BinaryFileService = inject(BinaryFileService);
+
+  public uploadedFiles$: Observable<UploadFileByIdentifier>;
+
+  ngOnInit(): void {
+    if (hasLink(this.filesResource, this.filesLinkRel)) {
+      this.uploadedFiles$ = this.binaryFileService.getFiles(this.filesResource, this.filesLinkRel).pipe(
+        filter(isLoaded),
+        map((files: StateResource<BinaryFileListResource>) => getEmbeddedResources(files, BinaryFileListLinkRel.FILE_LIST)),
+        tap((binaryFileResources: BinaryFileResource[]) =>
+          this.binaryFileService.addFiles(this.fileUploadType, binaryFileResources),
+        ),
+        switchMap(() => this.binaryFileService.getUploadedFiles(this.fileUploadType)),
+        startWith({}),
+      );
+    } else {
+      this.uploadedFiles$ = this.binaryFileService.getUploadedFiles(this.fileUploadType);
+    }
+  }
+
+  public onDelete(key: string): void {
+    this.binaryFileService.deleteUploadedFile(this.fileUploadType, key);
+  }
+}
diff --git a/alfa-client/libs/binary-file/src/lib/file-upload-list-container/file-upload-list-item/file-upload-list-item.component.html b/alfa-client/libs/binary-file/src/lib/file-upload-list-container/file-upload-list-item/file-upload-list-item.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..edb77f9c7dc133422248b79b4f99f1204900a46c
--- /dev/null
+++ b/alfa-client/libs/binary-file/src/lib/file-upload-list-container/file-upload-list-item/file-upload-list-item.component.html
@@ -0,0 +1,20 @@
+@if (uploadFile.uploadedFile.loading || uploadFile.uploadedFile.error) {
+  <ods-attachment
+    [loadingCaption]="uploadFile.fileToUpload.name"
+    errorCaption="Fehler beim Hochladen"
+    [errorMessages]="uploadFile.uploadedFile.error | convertProblemDetailToErrorMessages"
+    description="Anhang wird hochgeladen"
+    [isLoading]="uploadFile.uploadedFile.loading"
+    data-test-id="file-upload-list-item-attachment-upload"
+  ></ods-attachment>
+} @else if (uploadFile.uploadedFile.resource) {
+  <ods-attachment-wrapper>
+    <alfa-binary-file2-container
+      [file]="uploadFile.uploadedFile.resource"
+      [deletable]="true"
+      (startDelete)="delete.emit({ key, binaryFileResource: $event })"
+      data-test-id="file-upload-list-item-uploaded"
+    >
+    </alfa-binary-file2-container>
+  </ods-attachment-wrapper>
+}
diff --git a/alfa-client/libs/binary-file/src/lib/file-upload-list-container/file-upload-list-item/file-upload-list-item.component.spec.ts b/alfa-client/libs/binary-file/src/lib/file-upload-list-container/file-upload-list-item/file-upload-list-item.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f60c72fda9d26b37343f543116eee01113fc394b
--- /dev/null
+++ b/alfa-client/libs/binary-file/src/lib/file-upload-list-container/file-upload-list-item/file-upload-list-item.component.spec.ts
@@ -0,0 +1,153 @@
+import { BinaryFile2ContainerComponent, BinaryFileModule } from '@alfa-client/binary-file';
+import { BinaryFileResource } from '@alfa-client/binary-file-shared';
+import {
+  ConvertProblemDetailToErrorMessagesPipe,
+  createEmptyStateResource,
+  createErrorStateResource,
+  createStateResource,
+} from '@alfa-client/tech-shared';
+import {
+  existsAsHtmlElement,
+  getElementComponentFromFixtureByCss,
+  notExistsAsHtmlElement,
+  triggerEvent,
+} from '@alfa-client/test-utils';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { expect } from '@jest/globals';
+import { AttachmentComponent } from '@ods/system';
+import { MockComponent, MockModule } from 'ng-mocks';
+import {
+  createBinaryFileResource,
+  createFile,
+  createLoadingBinaryFileStateResource,
+} from '../../../../../binary-file-shared/test/binary-file';
+import { getDataTestIdOf } from '../../../../../tech-shared/test/data-test';
+import { createProblemDetail } from '../../../../../tech-shared/test/error';
+import { FileUploadListItemComponent } from './file-upload-list-item.component';
+
+describe('FileUploadListItemComponent', () => {
+  let component: FileUploadListItemComponent;
+  let fixture: ComponentFixture<FileUploadListItemComponent>;
+
+  const attachmentTestId: string = getDataTestIdOf('file-upload-list-item-attachment-upload');
+  const binaryFileContainerTestId: string = getDataTestIdOf('file-upload-list-item-uploaded');
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: [FileUploadListItemComponent, ConvertProblemDetailToErrorMessagesPipe],
+      declarations: [MockModule(BinaryFileModule), MockComponent(BinaryFile2ContainerComponent)],
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(FileUploadListItemComponent);
+    component = fixture.componentInstance;
+    component.uploadFile = { uploadedFile: createEmptyStateResource() };
+    fixture.detectChanges();
+  });
+
+  describe('component', () => {
+    it('should create', () => {
+      expect(component).toBeTruthy();
+    });
+
+    describe('template', () => {
+      const file: File = createFile();
+
+      beforeEach(() => {
+        component.uploadFile.fileToUpload = file;
+      });
+
+      describe('attachment upload', () => {
+        it('should exists on loading', () => {
+          component.uploadFile.uploadedFile = createLoadingBinaryFileStateResource();
+
+          fixture.detectChanges();
+
+          existsAsHtmlElement(fixture, attachmentTestId);
+        });
+
+        it('should exists on error', () => {
+          component.uploadFile.uploadedFile = createErrorStateResource(createProblemDetail());
+
+          fixture.detectChanges();
+
+          existsAsHtmlElement(fixture, attachmentTestId);
+        });
+
+        it('should NOT exists on loaded', () => {
+          component.uploadFile.uploadedFile = createStateResource(createBinaryFileResource());
+
+          fixture.detectChanges();
+
+          notExistsAsHtmlElement(fixture, attachmentTestId);
+        });
+
+        it('should have inputs', () => {
+          component.uploadFile.fileToUpload = createFile();
+          component.uploadFile.uploadedFile = createEmptyStateResource(true);
+
+          fixture.detectChanges();
+
+          const attachmentComponent: AttachmentComponent = getElementComponentFromFixtureByCss(fixture, attachmentTestId);
+
+          expect(attachmentComponent.loadingCaption).toEqual(component.uploadFile.fileToUpload.name);
+          expect(attachmentComponent.errorMessages).toEqual([]);
+          expect(attachmentComponent.isLoading).toEqual(true);
+        });
+      });
+
+      describe('uploaded file', () => {
+        it('should exists', () => {
+          component.uploadFile.uploadedFile = createStateResource(createBinaryFileResource());
+
+          fixture.detectChanges();
+
+          existsAsHtmlElement(fixture, binaryFileContainerTestId);
+        });
+
+        it('should NOT exists', () => {
+          component.uploadFile.uploadedFile = createEmptyStateResource(true);
+
+          fixture.detectChanges();
+
+          notExistsAsHtmlElement(fixture, binaryFileContainerTestId);
+        });
+
+        it('should have inputs', () => {
+          component.uploadFile.uploadedFile = createStateResource(createBinaryFileResource());
+
+          fixture.detectChanges();
+
+          const binaryFileComponent: BinaryFile2ContainerComponent = getElementComponentFromFixtureByCss(
+            fixture,
+            binaryFileContainerTestId,
+          );
+
+          expect(binaryFileComponent.file).toEqual(component.uploadFile.uploadedFile.resource);
+          expect(binaryFileComponent.deletable).toEqual(true);
+        });
+
+        describe('output', () => {
+          describe('startDelete', () => {
+            it('should emit', () => {
+              component.delete.emit = jest.fn();
+              component.key = 'test';
+              const binaryFileResource: BinaryFileResource = createBinaryFileResource();
+              component.uploadFile.uploadedFile = createStateResource(binaryFileResource);
+
+              fixture.detectChanges();
+
+              triggerEvent({
+                fixture,
+                elementSelector: binaryFileContainerTestId,
+                name: 'startDelete',
+                data: binaryFileResource,
+              });
+
+              expect(component.delete.emit).toHaveBeenCalledWith({ key: component.key, binaryFileResource });
+            });
+          });
+        });
+      });
+    });
+  });
+});
diff --git a/alfa-client/libs/binary-file/src/lib/file-upload-list-container/file-upload-list-item/file-upload-list-item.component.ts b/alfa-client/libs/binary-file/src/lib/file-upload-list-container/file-upload-list-item/file-upload-list-item.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..25527119bdaa6e87a88335557e8bf8e13054127d
--- /dev/null
+++ b/alfa-client/libs/binary-file/src/lib/file-upload-list-container/file-upload-list-item/file-upload-list-item.component.ts
@@ -0,0 +1,18 @@
+import { BinaryFileModule } from '@alfa-client/binary-file';
+import { FileToDelete, UploadFile } from '@alfa-client/binary-file-shared';
+import { ConvertProblemDetailToErrorMessagesPipe } from '@alfa-client/tech-shared';
+import { Component, EventEmitter, Input, Output } from '@angular/core';
+import { AttachmentComponent, AttachmentWrapperComponent } from '@ods/system';
+
+@Component({
+  selector: 'ods-file-upload-list-item',
+  standalone: true,
+  templateUrl: './file-upload-list-item.component.html',
+  imports: [AttachmentComponent, AttachmentWrapperComponent, BinaryFileModule, ConvertProblemDetailToErrorMessagesPipe],
+})
+export class FileUploadListItemComponent {
+  @Input() key: string;
+  @Input() uploadFile: UploadFile;
+
+  @Output() delete: EventEmitter<FileToDelete> = new EventEmitter();
+}
diff --git a/alfa-client/libs/binary-file/src/lib/file-upload-list-container/file-upload-list/file-upload-list.component.html b/alfa-client/libs/binary-file/src/lib/file-upload-list-container/file-upload-list/file-upload-list.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..b29089f98c4488b9be682850a39331f2cd46a607
--- /dev/null
+++ b/alfa-client/libs/binary-file/src/lib/file-upload-list-container/file-upload-list/file-upload-list.component.html
@@ -0,0 +1,9 @@
+<div [binaryFileListOrientation]="listOrientation">
+  @for (uploadItem of uploadItems | keyvalue; track uploadItem.key) {
+    <ods-file-upload-list-item
+      [key]="uploadItem.key"
+      [uploadFile]="uploadItem.value"
+      (delete)="onDelete($event)"
+    ></ods-file-upload-list-item>
+  }
+</div>
diff --git a/alfa-client/libs/binary-file/src/lib/file-upload-list-container/file-upload-list/file-upload-list.component.spec.ts b/alfa-client/libs/binary-file/src/lib/file-upload-list-container/file-upload-list/file-upload-list.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..3405027b7836f6a23dcd63d43f2bf00dbb7c07a5
--- /dev/null
+++ b/alfa-client/libs/binary-file/src/lib/file-upload-list-container/file-upload-list/file-upload-list.component.spec.ts
@@ -0,0 +1,179 @@
+import { BinaryFileResource, UploadFileByIdentifier } from '@alfa-client/binary-file-shared';
+import { createEmptyStateResource, createStateResource, StateResource } from '@alfa-client/tech-shared';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { FormGroupDirective, UntypedFormArray, UntypedFormBuilder, UntypedFormControl } from '@angular/forms';
+import { faker } from '@faker-js/faker/.';
+import { getUrl } from '@ngxp/rest';
+import { createBinaryFileResource, createUploadFile } from 'libs/binary-file-shared/test/binary-file';
+import { FileUploadListComponent } from './file-upload-list.component';
+
+describe('FileUploadListComponent', () => {
+  let component: FileUploadListComponent;
+  let fixture: ComponentFixture<FileUploadListComponent>;
+
+  const fb: UntypedFormBuilder = new UntypedFormBuilder();
+  const formGroupDirective: FormGroupDirective = new FormGroupDirective([], []);
+  formGroupDirective.form = fb.group({
+    attachments: fb.control(null),
+  });
+
+  const fileKey: string = '21';
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: [FileUploadListComponent],
+      providers: [
+        {
+          provide: FormGroupDirective,
+          useValue: formGroupDirective,
+        },
+      ],
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(FileUploadListComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+
+  describe('component', () => {
+    describe('set uploaded files', () => {
+      it('should update upload items', () => {
+        component._updateUploadItems = jest.fn();
+        const uploadedFiles: UploadFileByIdentifier = { [fileKey]: createUploadFile() };
+
+        component.uploadedFiles = uploadedFiles;
+
+        expect(component._updateUploadItems).toHaveBeenCalledWith(uploadedFiles);
+      });
+    });
+
+    describe('ngOnInit', () => {
+      it('should set file link controls', () => {
+        component.parentFormArrayName = 'attachments';
+
+        component.ngOnInit();
+
+        expect(component._fileLinkControls).toEqual(formGroupDirective.form.get('attachments'));
+      });
+    });
+
+    describe('_updateUploadItems', () => {
+      beforeEach(() => {
+        component._addFileUrl = jest.fn();
+        component._updateForm = jest.fn();
+      });
+
+      it('should set upload items', () => {
+        const uploadedFiles: UploadFileByIdentifier = { [fileKey]: createUploadFile() };
+
+        component._updateUploadItems(uploadedFiles);
+
+        expect(component.uploadItems).toEqual(uploadedFiles);
+      });
+
+      it('should set file urls', () => {
+        const uploadStateResource: StateResource<BinaryFileResource> = createStateResource(createBinaryFileResource());
+        const uploadedFiles: UploadFileByIdentifier = { [fileKey]: { ...createUploadFile(), uploadedFile: uploadStateResource } };
+
+        component._updateUploadItems(uploadedFiles);
+
+        expect(component._fileUrls).toEqual([getUrl(uploadStateResource.resource)]);
+      });
+
+      it('should NOT add file url on loading', () => {
+        const uploadedFiles: UploadFileByIdentifier = { [fileKey]: { uploadedFile: createEmptyStateResource(true) } };
+
+        component._updateUploadItems(uploadedFiles);
+
+        expect(component._fileUrls).toEqual([]);
+      });
+
+      it('should update form', () => {
+        const uploadedFiles: UploadFileByIdentifier = { [fileKey]: { uploadedFile: createEmptyStateResource(true) } };
+
+        component._updateUploadItems(uploadedFiles);
+
+        expect(component._updateForm).toHaveBeenCalled();
+      });
+    });
+
+    describe('_addFileUrl', () => {
+      beforeEach(() => {
+        component._updateForm = jest.fn();
+      });
+
+      it('should add file url', () => {
+        const binaryFileResource: BinaryFileResource = createBinaryFileResource();
+
+        component._addFileUrl(binaryFileResource);
+
+        expect(component._fileUrls).toEqual([getUrl(binaryFileResource)]);
+      });
+
+      it('should update form', () => {
+        const binaryFileResource: BinaryFileResource = createBinaryFileResource();
+
+        component._addFileUrl(binaryFileResource);
+
+        expect(component._updateForm).toHaveBeenCalled();
+      });
+    });
+
+    describe('_updateForm', () => {
+      beforeEach(() => {
+        component._fileLinkControls = new UntypedFormArray([new UntypedFormControl(faker.internet.url())]);
+      });
+
+      it('should clear file control list', () => {
+        component._fileUrls = [faker.internet.url()];
+
+        component._updateForm();
+
+        expect(component._fileLinkControls.length).toEqual(1);
+      });
+      it('should update file control list', () => {
+        const fileUrl: string = faker.internet.url();
+        component._fileUrls = [fileUrl];
+
+        component._updateForm();
+
+        expect(component._fileLinkControls.controls[0].value).toEqual(fileUrl);
+      });
+    });
+
+    describe('onDelete', () => {
+      const binaryFileResource: BinaryFileResource = createBinaryFileResource();
+      const fileUrl1: string = faker.internet.url();
+      const fileUrl2: string = getUrl(binaryFileResource);
+      const key: string = faker.word.noun();
+
+      beforeEach(() => {
+        component.delete.emit = jest.fn();
+        component._fileUrls = [fileUrl1, fileUrl2];
+        component._updateForm = jest.fn();
+      });
+
+      it('should update file urls', () => {
+        component.onDelete({ binaryFileResource, key });
+
+        expect(component._fileUrls).toEqual([fileUrl1]);
+      });
+
+      it('should emit', () => {
+        component.onDelete({ binaryFileResource, key });
+
+        expect(component.delete.emit).toHaveBeenCalledWith(key);
+      });
+
+      it('should update form', () => {
+        component.onDelete({ binaryFileResource, key });
+
+        expect(component._updateForm).toHaveBeenCalled();
+      });
+    });
+  });
+});
diff --git a/alfa-client/libs/binary-file/src/lib/file-upload-list-container/file-upload-list/file-upload-list.component.ts b/alfa-client/libs/binary-file/src/lib/file-upload-list-container/file-upload-list/file-upload-list.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..29b1cae5ed2a6ca63e6274a2fff1ddd96bdb212b
--- /dev/null
+++ b/alfa-client/libs/binary-file/src/lib/file-upload-list-container/file-upload-list/file-upload-list.component.ts
@@ -0,0 +1,64 @@
+import { BinaryFileResource, FileToDelete, UploadFile, UploadFileByIdentifier } from '@alfa-client/binary-file-shared';
+import { isLoaded, StateResource } from '@alfa-client/tech-shared';
+import { KeyValuePipe } from '@angular/common';
+import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
+import { FormGroupDirective, UntypedFormArray, UntypedFormControl } from '@angular/forms';
+import { getUrl } from '@ngxp/rest';
+import {
+  BinaryFileListOrientation,
+  BinaryFileListOrientationDirective,
+} from '../../directive/binary-file-list-orientation/binary-file-list-orientation.directive';
+import { FileUploadListItemComponent } from '../file-upload-list-item/file-upload-list-item.component';
+
+@Component({
+  selector: 'ods-file-upload-list',
+  standalone: true,
+  templateUrl: './file-upload-list.component.html',
+  imports: [FileUploadListItemComponent, KeyValuePipe, BinaryFileListOrientationDirective],
+})
+export class FileUploadListComponent implements OnInit {
+  @Input() parentFormArrayName: string;
+  @Input() listOrientation: BinaryFileListOrientation;
+
+  @Input() set uploadedFiles(value: UploadFileByIdentifier) {
+    this._updateUploadItems(value);
+  }
+
+  @Output() delete: EventEmitter<string> = new EventEmitter();
+
+  public uploadItems: UploadFileByIdentifier;
+
+  _fileLinkControls: UntypedFormArray = new UntypedFormArray([]);
+  _fileUrls: string[] = [];
+
+  constructor(public parentForm: FormGroupDirective) {}
+
+  ngOnInit(): void {
+    this._fileLinkControls = this.parentForm.form.get(this.parentFormArrayName) as UntypedFormArray;
+  }
+
+  _updateUploadItems(uploadFiles: UploadFileByIdentifier): void {
+    this.uploadItems = uploadFiles;
+    this._fileUrls = Object.values(uploadFiles)
+      .map((value: UploadFile) => value.uploadedFile)
+      .filter(isLoaded)
+      .map((stateResource: StateResource<BinaryFileResource>) => getUrl(stateResource.resource));
+    this._updateForm();
+  }
+
+  _addFileUrl(binaryFileResource: BinaryFileResource): void {
+    this._fileUrls = [...this._fileUrls, getUrl(binaryFileResource)];
+    this._updateForm();
+  }
+
+  _updateForm(): void {
+    this._fileLinkControls.clear();
+    this._fileUrls.forEach((link: string) => this._fileLinkControls.push(new UntypedFormControl(link)));
+  }
+
+  public onDelete(fileToDelete: FileToDelete): void {
+    this._fileUrls = this._fileUrls.filter((url: string) => url !== getUrl(fileToDelete.binaryFileResource));
+    this._updateForm();
+    this.delete.emit(fileToDelete.key);
+  }
+}
diff --git a/alfa-client/libs/binary-file/src/lib/multi-file-upload-editor/multi-file-upload-editor.component.html b/alfa-client/libs/binary-file/src/lib/multi-file-upload-editor/multi-file-upload-editor.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..1bfa1fb53740999476b2e6b342777abec551f000
--- /dev/null
+++ b/alfa-client/libs/binary-file/src/lib/multi-file-upload-editor/multi-file-upload-editor.component.html
@@ -0,0 +1,13 @@
+<ods-file-upload-button
+  [id]="uploadButtonId"
+  [accept]="accept"
+  [attr.data-test-id]="(label | convertForDataTest) + '-file-upload-button'"
+  [multi]="true"
+  [isLoading]="isUploadInProgress$ | async"
+  class="relative w-72"
+  data-test-id="binary-file-upload"
+>
+  <ods-spinner-icon spinner size="medium" />
+  <ods-attachment-icon icon size="medium" />
+  <p text class="text-center">{{ label }}</p>
+</ods-file-upload-button>
diff --git a/alfa-client/libs/binary-file/src/lib/multi-file-upload-editor/multi-file-upload-editor.component.spec.ts b/alfa-client/libs/binary-file/src/lib/multi-file-upload-editor/multi-file-upload-editor.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..0620a5f50612f4eeb3243f599d57fc9e1d1e3353
--- /dev/null
+++ b/alfa-client/libs/binary-file/src/lib/multi-file-upload-editor/multi-file-upload-editor.component.spec.ts
@@ -0,0 +1,119 @@
+import { BinaryFileService, ToUploadFile } from '@alfa-client/binary-file-shared';
+import { ConvertForDataTestPipe } from '@alfa-client/tech-shared';
+import { existsAsHtmlElement, getElementComponentFromFixtureByCss, mock, Mock } from '@alfa-client/test-utils';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { expect } from '@jest/globals';
+import { getUrl, Resource } from '@ngxp/rest';
+import { FileUploadButtonComponent, SpinnerIconComponent } from '@ods/system';
+import { getDataTestIdOf } from 'libs/tech-shared/test/data-test';
+import { MockComponent } from 'ng-mocks';
+import { of } from 'rxjs';
+import { createFileList } from '../../../../tech-shared/test/file';
+import { singleColdCompleted } from '../../../../tech-shared/test/marbles';
+import { createDummyResource } from '../../../../tech-shared/test/resource';
+import { MultiFileUploadEditorComponent } from './multi-file-upload-editor.component';
+
+describe('MultiFileUploadEditorComponent', () => {
+  let component: MultiFileUploadEditorComponent;
+  let fixture: ComponentFixture<MultiFileUploadEditorComponent>;
+
+  const uploadLinkRel: string = 'upload';
+  const uploadResource: Resource = createDummyResource([uploadLinkRel]);
+
+  const buttonTestId: string = getDataTestIdOf('Ein_Label-file-upload-button');
+
+  let binaryFileService: Mock<BinaryFileService>;
+
+  beforeEach(() => {
+    binaryFileService = mock(BinaryFileService);
+  });
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      declarations: [
+        MultiFileUploadEditorComponent,
+        ConvertForDataTestPipe,
+        MockComponent(SpinnerIconComponent),
+        MockComponent(FileUploadButtonComponent),
+      ],
+      providers: [
+        {
+          provide: BinaryFileService,
+          useValue: binaryFileService,
+        },
+      ],
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(MultiFileUploadEditorComponent);
+    component = fixture.componentInstance;
+    component.uploadResource = uploadResource;
+    component.uploadLinkRelation = uploadLinkRel;
+    component.label = 'Ein Label';
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+
+  describe('component', () => {
+    describe('ngOnInit', () => {
+      it('should set upload in progress', () => {
+        binaryFileService.isUploadInProgress = jest.fn().mockReturnValue(of(true));
+
+        component.ngOnInit();
+
+        expect(component.isUploadInProgress$).toBeObservable(singleColdCompleted(true));
+      });
+    });
+
+    describe('onFilesUpload', () => {
+      beforeEach(() => {
+        component._uploadFiles = jest.fn();
+      });
+
+      it('should upload files', () => {
+        const fileList: FileList = createFileList();
+
+        component.onFilesUpload(fileList);
+
+        expect(component._uploadFiles).toHaveBeenCalledWith(fileList);
+      });
+    });
+
+    describe('_uploadFiles', () => {
+      it('should call binary file service', () => {
+        const fileList: FileList = createFileList();
+
+        component._uploadFiles(fileList);
+
+        expect(binaryFileService.uploadFileNew).toHaveBeenCalledWith({
+          file: fileList.item(0),
+          type: component.fileUploadType,
+          uploadUrl: getUrl(uploadResource, uploadLinkRel),
+        } as ToUploadFile);
+      });
+    });
+  });
+
+  describe('template', () => {
+    describe('upload button', () => {
+      it('should exists', () => {
+        existsAsHtmlElement(fixture, buttonTestId);
+      });
+
+      it('should have inputs', () => {
+        binaryFileService.isUploadInProgress = jest.fn().mockReturnValue(of(true));
+        component.ngOnInit();
+
+        fixture.detectChanges();
+        const fileButtonComponent: FileUploadButtonComponent = getElementComponentFromFixtureByCss(fixture, buttonTestId);
+
+        expect(fileButtonComponent.id).toEqual(component.uploadButtonId);
+        expect(fileButtonComponent.accept).toEqual(component.accept);
+        expect(fileButtonComponent.multi).toEqual(true);
+        expect(fileButtonComponent.isLoading).toEqual(true);
+      });
+    });
+  });
+});
diff --git a/alfa-client/libs/binary-file/src/lib/multi-file-upload-editor/multi-file-upload-editor.component.ts b/alfa-client/libs/binary-file/src/lib/multi-file-upload-editor/multi-file-upload-editor.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f69f78656a70336abe6b7a9cd72d8c12051177f4
--- /dev/null
+++ b/alfa-client/libs/binary-file/src/lib/multi-file-upload-editor/multi-file-upload-editor.component.ts
@@ -0,0 +1,59 @@
+import { BinaryFileModule } from '@alfa-client/binary-file';
+import { BinaryFileService, FileUploadType } from '@alfa-client/binary-file-shared';
+import { KOMMENTAR_UPLOADED_ATTACHMENTS } from '@alfa-client/kommentar-shared';
+import { ConvertForDataTestPipe } from '@alfa-client/tech-shared';
+import { AsyncPipe } from '@angular/common';
+import { Component, HostListener, inject, Input, OnInit } from '@angular/core';
+import { ControlContainer, FormGroupDirective, ReactiveFormsModule } from '@angular/forms';
+import { getUrl, Resource } from '@ngxp/rest';
+import { AttachmentIconComponent, FileUploadButtonComponent, SpinnerIconComponent } from '@ods/system';
+import { uniqueId } from 'lodash-es';
+import { Observable } from 'rxjs';
+
+@Component({
+  selector: 'ods-multi-file-upload-editor',
+  templateUrl: './multi-file-upload-editor.component.html',
+  viewProviders: [{ provide: ControlContainer, useExisting: FormGroupDirective }],
+  standalone: true,
+  imports: [
+    AsyncPipe,
+    FileUploadButtonComponent,
+    AttachmentIconComponent,
+    SpinnerIconComponent,
+    ReactiveFormsModule,
+    BinaryFileModule,
+    ConvertForDataTestPipe,
+  ],
+})
+export class MultiFileUploadEditorComponent implements OnInit {
+  @Input() label: string = '';
+  @Input() accept: string = '*/*';
+  @Input() fileUploadType: FileUploadType;
+  @Input() uploadResource: Resource;
+  @Input() uploadLinkRelation: string;
+
+  private readonly binaryFileService: BinaryFileService = inject(BinaryFileService);
+
+  public isUploadInProgress$: Observable<boolean>;
+
+  public readonly uploadButtonId: string = uniqueId();
+
+  ngOnInit(): void {
+    this.isUploadInProgress$ = this.binaryFileService.isUploadInProgress(KOMMENTAR_UPLOADED_ATTACHMENTS);
+  }
+
+  @HostListener('change', ['$event.target.files'])
+  public onFilesUpload(fileList: FileList): void {
+    this._uploadFiles(fileList);
+  }
+
+  _uploadFiles(fileList: FileList) {
+    for (let i = 0; i < fileList.length; i++) {
+      this.binaryFileService.uploadFileNew({
+        file: fileList.item(i),
+        type: this.fileUploadType,
+        uploadUrl: getUrl(this.uploadResource, this.uploadLinkRelation),
+      });
+    }
+  }
+}
diff --git a/alfa-client/libs/design-system/src/lib/form/file-upload-button/file-upload-button.component.html b/alfa-client/libs/design-system/src/lib/form/file-upload-button/file-upload-button.component.html
index ece1c85988571d733845ce9403521c3b804d0c23..dc2b6cef68ea7358023c7791fea0eb6efbaf47bf 100644
--- a/alfa-client/libs/design-system/src/lib/form/file-upload-button/file-upload-button.component.html
+++ b/alfa-client/libs/design-system/src/lib/form/file-upload-button/file-upload-button.component.html
@@ -31,6 +31,7 @@
   [accept]="accept"
   (click)="resetInput()"
   [disabled]="isLoading"
+  [multiple]="multi"
   [attr.data-test-id]="(id | convertForDataTest) + '-file-upload-input'"
 />
 <label
diff --git a/alfa-client/libs/design-system/src/lib/form/file-upload-button/file-upload-button.component.spec.ts b/alfa-client/libs/design-system/src/lib/form/file-upload-button/file-upload-button.component.spec.ts
index fee4fa492f168106fce4c7f8c97dc6b31a956ddd..54b7d3b7dde522ce018e0efae8b4210f6e2e2cff 100644
--- a/alfa-client/libs/design-system/src/lib/form/file-upload-button/file-upload-button.component.spec.ts
+++ b/alfa-client/libs/design-system/src/lib/form/file-upload-button/file-upload-button.component.spec.ts
@@ -25,6 +25,7 @@ import { ConvertForDataTestPipe } from '@alfa-client/tech-shared';
 import { getElementFromFixture } from '@alfa-client/test-utils';
 import { ComponentFixture, TestBed } from '@angular/core/testing';
 import { faker } from '@faker-js/faker';
+import { expect } from '@jest/globals';
 import { getDataTestIdOf } from 'libs/tech-shared/test/data-test';
 import { FileUploadButtonComponent } from './file-upload-button.component';
 
@@ -61,4 +62,15 @@ describe('FileUploadButtonComponent', () => {
       expect(component.resetInput).toHaveBeenCalled();
     });
   });
+
+  describe('template', () => {
+    it('should have inputs', () => {
+      component.multi = true;
+      fixture.detectChanges();
+
+      const inputElement: HTMLInputElement = getElementFromFixture(fixture, inputTestClass);
+
+      expect(inputElement.multiple).toEqual(component.multi);
+    });
+  });
 });
diff --git a/alfa-client/libs/design-system/src/lib/form/file-upload-button/file-upload-button.component.ts b/alfa-client/libs/design-system/src/lib/form/file-upload-button/file-upload-button.component.ts
index 3e111b19ad208b4b4505a67bb8ef343ae6de0d2e..2371918f9cdba62e0ea0ee3a5e315ee9f1d9e378 100644
--- a/alfa-client/libs/design-system/src/lib/form/file-upload-button/file-upload-button.component.ts
+++ b/alfa-client/libs/design-system/src/lib/form/file-upload-button/file-upload-button.component.ts
@@ -36,6 +36,7 @@ export class FileUploadButtonComponent {
   @Input({ required: true }) id!: string;
   @Input() isLoading: boolean = false;
   @Input() accept: string = '*/*';
+  @Input() multi: boolean = false;
 
   @ViewChild('inputElement') inputElement: ElementRef = new ElementRef({});
 
diff --git a/alfa-client/libs/design-system/src/lib/icons/spinner-icon/spinner-icon.component.ts b/alfa-client/libs/design-system/src/lib/icons/spinner-icon/spinner-icon.component.ts
index 503f6865258a83c1ce2073c288e47f68b87e99ef..d361292b08e026c2f05e245276dae53b82fa2805 100644
--- a/alfa-client/libs/design-system/src/lib/icons/spinner-icon/spinner-icon.component.ts
+++ b/alfa-client/libs/design-system/src/lib/icons/spinner-icon/spinner-icon.component.ts
@@ -30,13 +30,15 @@ import { IconVariants, iconVariants } from '../iconVariants';
   selector: 'ods-spinner-icon',
   standalone: true,
   imports: [NgClass],
-  template: `<svg
+  template: `
+    <svg
       xmlns="http://www.w3.org/2000/svg"
       [ngClass]="iconVariants({ size })"
       class="animate-spin fill-primary text-gray-200 dark:text-gray-600"
       aria-hidden="true"
       viewBox="0 0 100 100"
       fill="none"
+      data-test-class="spinner"
     >
       <path
         d="M100 50.59c0 27.615-22.386 50.001-50 50.001s-50-22.386-50-50 22.386-50 50-50 50 22.386 50 50Zm-90.919 0c0 22.6 18.32 40.92 40.919 40.92 22.599 0 40.919-18.32 40.919-40.92 0-22.598-18.32-40.918-40.919-40.918-22.599 0-40.919 18.32-40.919 40.919Z"
@@ -46,7 +48,8 @@ import { IconVariants, iconVariants } from '../iconVariants';
         d="M93.968 39.04c2.425-.636 3.894-3.128 3.04-5.486A50 50 0 0 0 41.735 1.279c-2.474.414-3.922 2.919-3.285 5.344.637 2.426 3.12 3.849 5.6 3.484a40.916 40.916 0 0 1 44.131 25.769c.902 2.34 3.361 3.802 5.787 3.165Z"
       />
     </svg>
-    <span class="sr-only">Loading...</span> `,
+    <span class="sr-only">Loading...</span>
+  `,
 })
 export class SpinnerIconComponent {
   @Input() size: IconVariants['size'] = 'full';
diff --git a/alfa-client/libs/kommentar-shared/src/lib/kommentar.model.ts b/alfa-client/libs/kommentar-shared/src/lib/kommentar.model.ts
index f6109a2ea77cff02a183eddaa6a4178244c68e93..2a6aa6711ee3df877983926e9d2d8add9c5fe663 100644
--- a/alfa-client/libs/kommentar-shared/src/lib/kommentar.model.ts
+++ b/alfa-client/libs/kommentar-shared/src/lib/kommentar.model.ts
@@ -32,4 +32,7 @@ export interface Kommentar {
 }
 
 export interface KommentarResource extends Kommentar, Resource {}
+
 export interface KommentarListResource extends ListResource {}
+
+export const KOMMENTAR_UPLOADED_ATTACHMENTS: string = 'kommentar_uploaded_attachments';
diff --git a/alfa-client/libs/kommentar-shared/src/lib/kommentar.service.spec.ts b/alfa-client/libs/kommentar-shared/src/lib/kommentar.service.spec.ts
index 329ac2f142356ce68c2d841605541322ac458dbb..98a918c03eb9d525d9bc2977f1885838dd873da3 100644
--- a/alfa-client/libs/kommentar-shared/src/lib/kommentar.service.spec.ts
+++ b/alfa-client/libs/kommentar-shared/src/lib/kommentar.service.spec.ts
@@ -22,32 +22,20 @@
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
 import { BinaryFileService } from '@alfa-client/binary-file-shared';
-import {
-  CommandOrder,
-  CommandResource,
-  CommandService,
-  CreateCommand,
-} from '@alfa-client/command-shared';
+import { CommandOrder, CommandResource, CommandService, CreateCommand } from '@alfa-client/command-shared';
 import { NavigationService } from '@alfa-client/navigation-shared';
-import {
-  StateResource,
-  createEmptyStateResource,
-  createStateResource,
-} from '@alfa-client/tech-shared';
+import { createEmptyStateResource, createStateResource, StateResource } from '@alfa-client/tech-shared';
 import { Mock, mock, useFromMock } from '@alfa-client/test-utils';
 import { VorgangService, VorgangWithEingangResource } from '@alfa-client/vorgang-shared';
+import { expect } from '@jest/globals';
 import { cold, hot } from 'jest-marbles';
 import { CommandLinkRel } from 'libs/command-shared/src/lib/command.linkrel';
 import { createCommandResource } from 'libs/command-shared/test/command';
-import {
-  createKommentar,
-  createKommentarListResource,
-  createKommentarResource,
-} from 'libs/kommentar-shared/test/kommentar';
+import { createKommentar, createKommentarListResource, createKommentarResource } from 'libs/kommentar-shared/test/kommentar';
 import { createVorgangWithEingangResource } from 'libs/vorgang-shared/test/vorgang';
 import { of } from 'rxjs';
 import { KommentarLinkRel, KommentarListLinkRel } from './kommentar.linkrel';
-import { Kommentar, KommentarListResource, KommentarResource } from './kommentar.model';
+import { Kommentar, KOMMENTAR_UPLOADED_ATTACHMENTS, KommentarListResource, KommentarResource } from './kommentar.model';
 import { KommentarRepository } from './kommentar.repository';
 import { KommentarService } from './kommentar.service';
 
@@ -120,9 +108,7 @@ describe('KommentarService', () => {
       it('should be return', () => {
         const result = service.createKommentar(kommentar);
 
-        expect(result).toBeObservable(
-          cold('ab', { a: createEmptyStateResource(true), b: commandStateResource }),
-        );
+        expect(result).toBeObservable(cold('ab', { a: createEmptyStateResource(true), b: commandStateResource }));
       });
     });
 
@@ -174,9 +160,7 @@ describe('KommentarService', () => {
       it('should be return', () => {
         const result = service.editKommentar(kommentarResource, kommentar);
 
-        expect(result).toBeObservable(
-          cold('ab', { a: createEmptyStateResource(true), b: commandStateResource }),
-        );
+        expect(result).toBeObservable(cold('ab', { a: createEmptyStateResource(true), b: commandStateResource }));
       });
     });
 
@@ -298,10 +282,7 @@ describe('KommentarService', () => {
       const kommentarResource = createKommentarResource([KommentarLinkRel.ATTACHMENTS]);
       service.getAttachments(kommentarResource);
 
-      expect(binaryFileService.getFiles).toHaveBeenCalledWith(
-        kommentarResource,
-        KommentarLinkRel.ATTACHMENTS,
-      );
+      expect(binaryFileService.getFiles).toHaveBeenCalledWith(kommentarResource, KommentarLinkRel.ATTACHMENTS);
     });
 
     it('should not be loaded if no link available', () => {
@@ -315,9 +296,7 @@ describe('KommentarService', () => {
     it('should create new Kommentare', () => {
       const canCreateNewKommentar$ = cold('a', { a: true });
 
-      const observable = service.canCreateNewKommentar(
-        createKommentarListResource([KommentarListLinkRel.CREATE_KOMMENTAR]),
-      );
+      const observable = service.canCreateNewKommentar(createKommentarListResource([KommentarListLinkRel.CREATE_KOMMENTAR]));
 
       expect(observable).toBeObservable(canCreateNewKommentar$);
     });
@@ -326,9 +305,7 @@ describe('KommentarService', () => {
       const canCreateNewKommentar$ = cold('a', { a: false });
       service.formularVisibility$.next(true);
 
-      const observable = service.canCreateNewKommentar(
-        createKommentarListResource([KommentarListLinkRel.CREATE_KOMMENTAR]),
-      );
+      const observable = service.canCreateNewKommentar(createKommentarListResource([KommentarListLinkRel.CREATE_KOMMENTAR]));
 
       expect(observable).toBeObservable(canCreateNewKommentar$);
     });
@@ -342,4 +319,12 @@ describe('KommentarService', () => {
       expect(observable).toBeObservable(canCreateNewKommentar$);
     });
   });
+
+  describe('clearUploadedFiles', () => {
+    it('should call binary file service', () => {
+      service.clearUploadedFiles();
+
+      expect(binaryFileService.clearUploadedFiles).toHaveBeenCalledWith(KOMMENTAR_UPLOADED_ATTACHMENTS);
+    });
+  });
 });
diff --git a/alfa-client/libs/kommentar-shared/src/lib/kommentar.service.ts b/alfa-client/libs/kommentar-shared/src/lib/kommentar.service.ts
index 1fd80c539fcdbb6c58223c3969a18e577f88d7e1..27efa8ae9da9e852906f3917b070e27e9faeca2d 100644
--- a/alfa-client/libs/kommentar-shared/src/lib/kommentar.service.ts
+++ b/alfa-client/libs/kommentar-shared/src/lib/kommentar.service.ts
@@ -22,35 +22,25 @@
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
 import { BinaryFileListResource, BinaryFileService } from '@alfa-client/binary-file-shared';
-import {
-  CommandOrder,
-  CommandResource,
-  CommandService,
-  CreateCommand,
-  isDone,
-} from '@alfa-client/command-shared';
+import { CommandOrder, CommandResource, CommandService, CreateCommand, isDone } from '@alfa-client/command-shared';
 import { NavigationService } from '@alfa-client/navigation-shared';
-import {
-  StateResource,
-  createEmptyStateResource,
-  createStateResource,
-  doIfLoadingRequired,
-} from '@alfa-client/tech-shared';
+import { createEmptyStateResource, createStateResource, doIfLoadingRequired, StateResource } from '@alfa-client/tech-shared';
 import { VorgangResource, VorgangService } from '@alfa-client/vorgang-shared';
 import { Injectable } from '@angular/core';
 import { Params } from '@angular/router';
-import { Resource, hasLink } from '@ngxp/rest';
+import { hasLink, Resource } from '@ngxp/rest';
 import { isNil } from 'lodash-es';
-import { BehaviorSubject, Observable, Subscription, of } from 'rxjs';
+import { BehaviorSubject, Observable, of, Subscription } from 'rxjs';
 import { map, startWith, tap } from 'rxjs/operators';
 import { KommentarLinkRel, KommentarListLinkRel } from './kommentar.linkrel';
-import { Kommentar, KommentarListResource, KommentarResource } from './kommentar.model';
+import { Kommentar, KOMMENTAR_UPLOADED_ATTACHMENTS, KommentarListResource, KommentarResource } from './kommentar.model';
 import { KommentarRepository } from './kommentar.repository';
 
 @Injectable({ providedIn: 'root' })
 export class KommentarService {
-  readonly kommentarList$: BehaviorSubject<StateResource<KommentarListResource>> =
-    new BehaviorSubject(createEmptyStateResource<KommentarListResource>());
+  readonly kommentarList$: BehaviorSubject<StateResource<KommentarListResource>> = new BehaviorSubject(
+    createEmptyStateResource<KommentarListResource>(),
+  );
   readonly formularVisibility$: BehaviorSubject<boolean> = new BehaviorSubject(false);
 
   private navigationSub: Subscription;
@@ -67,9 +57,7 @@ export class KommentarService {
 
   private listenToNavigation(): void {
     this.unsubscribe();
-    this.navigationSub = this.navigationService
-      .urlChanged()
-      .subscribe((params: Params) => this.onNavigation(params));
+    this.navigationSub = this.navigationService.urlChanged().subscribe((params: Params) => this.onNavigation(params));
   }
 
   private unsubscribe(): void {
@@ -89,9 +77,7 @@ export class KommentarService {
     this.kommentarList$.next({ ...this.kommentarList$.value, reload: true });
   }
 
-  public getKommentareByVorgang(
-    vorgang: VorgangResource,
-  ): Observable<StateResource<KommentarListResource>> {
+  public getKommentareByVorgang(vorgang: VorgangResource): Observable<StateResource<KommentarListResource>> {
     doIfLoadingRequired(this.kommentarList$.value, () => this.loadKommentare(vorgang));
     return this.kommentarList$.asObservable();
   }
@@ -99,12 +85,10 @@ export class KommentarService {
   private loadKommentare(vorgang: VorgangResource): void {
     this.setListLoadingTrue();
 
-    const sub: Subscription = this.repository
-      .findKommentare(vorgang)
-      .subscribe((kommentarList: KommentarListResource) => {
-        this.setKommentarList(kommentarList);
-        sub.unsubscribe();
-      });
+    const sub: Subscription = this.repository.findKommentare(vorgang).subscribe((kommentarList: KommentarListResource) => {
+      this.setKommentarList(kommentarList);
+      sub.unsubscribe();
+    });
   }
 
   setListLoadingTrue(): void {
@@ -125,11 +109,7 @@ export class KommentarService {
 
   public canCreateNewKommentar(kommentareListResource: KommentarListResource): Observable<boolean> {
     return this.formularVisibility$.pipe(
-      map(
-        (formularVisibility) =>
-          !formularVisibility &&
-          hasLink(kommentareListResource, KommentarListLinkRel.CREATE_KOMMENTAR),
-      ),
+      map((formularVisibility) => !formularVisibility && hasLink(kommentareListResource, KommentarListLinkRel.CREATE_KOMMENTAR)),
     );
   }
 
@@ -153,15 +133,8 @@ export class KommentarService {
     return { order: CommandOrder.CREATE_KOMMENTAR, body: kommentar };
   }
 
-  public editKommentar(
-    kommentar: KommentarResource,
-    toPatch: Kommentar,
-  ): Observable<StateResource<CommandResource>> {
-    return this.createKommentarCommand(
-      kommentar,
-      KommentarLinkRel.EDIT,
-      this.createEditKommentarCommand(toPatch),
-    );
+  public editKommentar(kommentar: KommentarResource, toPatch: Kommentar): Observable<StateResource<CommandResource>> {
+    return this.createKommentarCommand(kommentar, KommentarLinkRel.EDIT, this.createEditKommentarCommand(toPatch));
   }
 
   createEditKommentarCommand(kommentar: Kommentar): CreateCommand {
@@ -174,9 +147,7 @@ export class KommentarService {
     command: CreateCommand,
   ): Observable<StateResource<CommandResource>> {
     return this.commandService.createCommand(resource, linkRel, command).pipe(
-      tap((createdCommand: StateResource<CommandResource>) =>
-        this.afterCreateOrEditKommentar(createdCommand),
-      ),
+      tap((createdCommand: StateResource<CommandResource>) => this.afterCreateOrEditKommentar(createdCommand)),
       startWith(createEmptyStateResource<CommandResource>(true)),
     );
   }
@@ -195,4 +166,8 @@ export class KommentarService {
     }
     return of(createEmptyStateResource<BinaryFileListResource>());
   }
+
+  public clearUploadedFiles(): void {
+    this.binaryFileService.clearUploadedFiles(KOMMENTAR_UPLOADED_ATTACHMENTS);
+  }
 }
diff --git a/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-form/kommentar-form.component.html b/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-form/kommentar-form.component.html
index b6c374e27ae36f03b027cf262faa477281b79346..8a5168bf1dc59de260e7e7a5ece9c9a6167153c1 100644
--- a/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-form/kommentar-form.component.html
+++ b/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-form/kommentar-form.component.html
@@ -24,21 +24,22 @@
 
 -->
 <form class="form" [formGroup]="formService.form">
-  <ozgcloud-textarea-editor
-    [formControlName]="formServiceClass.TEXT"
-    label="Kommentar"
-    [required]="true"
-  >
+  <ozgcloud-textarea-editor [formControlName]="formServiceClass.TEXT" label="Kommentar" [required]="true">
   </ozgcloud-textarea-editor>
 
-  <alfa-binary-file-attachment-container
-    data-test-id="kommentar-attachment-list"
-    [existFiles]="attachments$ | async"
-    [formArrayName]="formServiceClass.FIELD_ATTACHMENTS"
-    [uploadStateResource]="kommentarListStateResource"
-    [linkRelUploadAttachment]="kommentarListLinkRel.UPLOAD_FILE"
-  >
-  </alfa-binary-file-attachment-container>
+  <ods-file-upload-list-container
+    [parentFormArrayName]="formServiceClass.FIELD_ATTACHMENTS"
+    [fileUploadType]="KOMMENTAR_UPLOADED_ATTACHMENTS"
+    [filesResource]="kommentar"
+    [filesLinkRel]="KommentarLinkRel.ATTACHMENTS"
+    data-test-id="kommentar-multi-file-upload-list"
+  ></ods-file-upload-list-container>
+  <ods-multi-file-upload-editor
+    [fileUploadType]="KOMMENTAR_UPLOADED_ATTACHMENTS"
+    [uploadResource]="kommentarListStateResource.resource"
+    [uploadLinkRelation]="kommentarListLinkRel.UPLOAD_FILE"
+    data-test-id="kommentar-multi-file-upload-editor"
+  ></ods-multi-file-upload-editor>
 
   <div class="buttons">
     <ozgcloud-stroked-button-with-spinner
@@ -57,7 +58,7 @@
       icon="clear"
       color=""
       class="cancel-button"
-      (clickEmitter)="cancel.emit()"
+      (clickEmitter)="onCancel()"
     >
     </ozgcloud-stroked-button-with-spinner>
   </div>
diff --git a/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-form/kommentar-form.component.spec.ts b/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-form/kommentar-form.component.spec.ts
index a8af3d1f1dc2208e0502f3fef2dfa759083fc1ed..15d300ef0ad665960ee7349b31d2678d60ac7c30 100644
--- a/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-form/kommentar-form.component.spec.ts
+++ b/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-form/kommentar-form.component.spec.ts
@@ -21,21 +21,24 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
+import { BinaryFileAttachmentContainerComponent, FileUploadListContainerComponent, MultiFileUploadEditorComponent, } from '@alfa-client/binary-file';
+import { CommandResource } from '@alfa-client/command-shared';
+import { KOMMENTAR_UPLOADED_ATTACHMENTS, KommentarLinkRel, KommentarListLinkRel, KommentarListResource, KommentarService, } from '@alfa-client/kommentar-shared';
+import { createEmptyStateResource, createErrorStateResource, createStateResource, StateResource } from '@alfa-client/tech-shared';
+import { existsAsHtmlElement, getElementComponentFromFixtureByCss, Mock, mock, triggerEvent, useFromMock, } from '@alfa-client/test-utils';
+import { OzgcloudStrokedButtonWithSpinnerComponent, TextAreaEditorComponent } from '@alfa-client/ui';
 import { ComponentFixture, TestBed } from '@angular/core/testing';
-import { ReactiveFormsModule } from '@angular/forms';
+import { FormBuilder, ReactiveFormsModule } from '@angular/forms';
 import { MatFormFieldModule } from '@angular/material/form-field';
-import { BinaryFileAttachmentContainerComponent } from '@alfa-client/binary-file';
-import { KommentarLinkRel, KommentarService } from '@alfa-client/kommentar-shared';
-import { createStateResource } from '@alfa-client/tech-shared';
-import { mock } from '@alfa-client/test-utils';
-import {
-  OzgcloudStrokedButtonWithSpinnerComponent,
-  TextAreaEditorComponent,
-} from '@alfa-client/ui';
+import { expect } from '@jest/globals';
 import { MockComponent } from 'ng-mocks';
-import { of } from 'rxjs';
+import { EMPTY, of } from 'rxjs';
 import { createBinaryFileListResource } from '../../../../../binary-file-shared/test/binary-file';
-import { createKommentarResource } from '../../../../../kommentar-shared/test/kommentar';
+import { createSuccessfullyDoneCommandStateResource } from '../../../../../command-shared/test/command';
+import { createKommentarListResource, createKommentarResource } from '../../../../../kommentar-shared/test/kommentar';
+import { getDataTestIdOf } from '../../../../../tech-shared/test/data-test';
+import { createProblemDetail } from '../../../../../tech-shared/test/error';
+import { singleColdCompleted } from '../../../../../tech-shared/test/marbles';
 import { KommentarFormComponent } from './kommentar-form.component';
 import { KommentarFormService } from './kommentar.formservice';
 
@@ -43,8 +46,19 @@ describe('KommentarFormComponent', () => {
   let component: KommentarFormComponent;
   let fixture: ComponentFixture<KommentarFormComponent>;
 
-  const formService = mock(KommentarFormService);
-  const kommentarService = mock(KommentarService);
+  const cancelButtonTestId: string = getDataTestIdOf('cancel-button');
+  const fileUploadListTestId: string = getDataTestIdOf('kommentar-multi-file-upload-list');
+  const fileUploadEditorTestId: string = getDataTestIdOf('kommentar-multi-file-upload-editor');
+
+  const kommentarListStateResource: StateResource<KommentarListResource> = createStateResource(createKommentarListResource());
+
+  let kommentarService: Mock<KommentarService>;
+  let formService: KommentarFormService;
+
+  beforeEach(() => {
+    formService = new KommentarFormService(new FormBuilder(), useFromMock(kommentarService));
+    kommentarService = mock(KommentarService);
+  });
 
   beforeEach(async () => {
     await TestBed.configureTestingModule({
@@ -53,24 +67,32 @@ describe('KommentarFormComponent', () => {
         MockComponent(TextAreaEditorComponent),
         MockComponent(OzgcloudStrokedButtonWithSpinnerComponent),
         MockComponent(BinaryFileAttachmentContainerComponent),
+        MockComponent(FileUploadListContainerComponent),
+        MockComponent(MultiFileUploadEditorComponent),
       ],
       imports: [MatFormFieldModule, ReactiveFormsModule],
       providers: [
-        {
-          provide: KommentarFormService,
-          useValue: formService,
-        },
         {
           provide: KommentarService,
           useValue: kommentarService,
         },
       ],
-    });
-  });
+    })
+      .overrideComponent(KommentarFormComponent, {
+        set: {
+          providers: [
+            {
+              provide: KommentarFormService,
+              useValue: formService,
+            },
+          ],
+        },
+      })
+      .compileComponents();
 
-  beforeEach(() => {
     fixture = TestBed.createComponent(KommentarFormComponent);
     component = fixture.componentInstance;
+    component.kommentarListStateResource = kommentarListStateResource;
     fixture.detectChanges();
   });
 
@@ -82,9 +104,7 @@ describe('KommentarFormComponent', () => {
     const patchSpy = jest.spyOn(KommentarFormService.prototype, 'patch').mockImplementation();
     const kommentarResource = createKommentarResource([KommentarLinkRel.ATTACHMENTS]);
     component.kommentar = kommentarResource;
-    kommentarService.getAttachments.mockReturnValue(
-      of(createStateResource(createBinaryFileListResource())),
-    );
+    kommentarService.getAttachments.mockReturnValue(of(createStateResource(createBinaryFileListResource())));
 
     component.ngOnChanges();
 
@@ -93,9 +113,7 @@ describe('KommentarFormComponent', () => {
 
   it('should load attachments', (done) => {
     component.kommentar = createKommentarResource([KommentarLinkRel.ATTACHMENTS]);
-    kommentarService.getAttachments.mockReturnValue(
-      of(createStateResource(createBinaryFileListResource())),
-    );
+    kommentarService.getAttachments.mockReturnValue(of(createStateResource(createBinaryFileListResource())));
 
     component.ngOnChanges();
 
@@ -108,12 +126,131 @@ describe('KommentarFormComponent', () => {
   it('should call kommentarService', () => {
     const kommentarResource = createKommentarResource([KommentarLinkRel.ATTACHMENTS]);
     component.kommentar = kommentarResource;
-    kommentarService.getAttachments.mockReturnValue(
-      of(createStateResource(createBinaryFileListResource())),
-    );
+    kommentarService.getAttachments.mockReturnValue(of(createStateResource(createBinaryFileListResource())));
 
     component.ngOnChanges();
 
     expect(kommentarService.getAttachments).toHaveBeenCalledWith(kommentarResource);
   });
+
+  describe('submit', () => {
+    it('should submit form', () => {
+      formService.submit = jest.fn().mockReturnValue(EMPTY);
+
+      component.submit();
+
+      expect(formService.submit).toHaveBeenCalled();
+    });
+
+    it('should set submit in progress', () => {
+      const command: StateResource<CommandResource> = createSuccessfullyDoneCommandStateResource();
+      formService.submit = jest.fn().mockReturnValue(of(command));
+
+      component.submit();
+
+      expect(component.submitInProgress$).toBeObservable(singleColdCompleted(command));
+    });
+
+    it('should clear uploaded attachments', () => {
+      formService.submit = jest.fn().mockReturnValue(of(createSuccessfullyDoneCommandStateResource()));
+
+      component.submit();
+      component.submitInProgress$.subscribe();
+
+      expect(kommentarService.clearUploadedFiles).toHaveBeenCalled();
+    });
+
+    it('should NOT clear uploaded attachments on loading', () => {
+      formService.submit = jest.fn().mockReturnValue(of(createEmptyStateResource(true)));
+
+      component.submit();
+      component.submitInProgress$.subscribe();
+
+      expect(kommentarService.clearUploadedFiles).not.toHaveBeenCalled();
+    });
+
+    it('should NOT clear uploaded attachments on error', () => {
+      formService.submit = jest.fn().mockReturnValue(of(createErrorStateResource(createProblemDetail())));
+
+      component.submit();
+      component.submitInProgress$.subscribe();
+
+      expect(kommentarService.clearUploadedFiles).not.toHaveBeenCalled();
+    });
+  });
+
+  describe('onCancel', () => {
+    beforeEach(() => {
+      component.cancel.emit = jest.fn();
+    });
+
+    it('should clear uploaded attachments', () => {
+      component.onCancel();
+
+      expect(kommentarService.clearUploadedFiles).toHaveBeenCalled();
+    });
+
+    it('should emit', () => {
+      component.onCancel();
+
+      expect(component.cancel.emit).toHaveBeenCalled();
+    });
+  });
+
+  describe('template', () => {
+    describe('file upload list', () => {
+      it('should exists', () => {
+        existsAsHtmlElement(fixture, fileUploadListTestId);
+      });
+
+      it('should have inputs', () => {
+        fixture.detectChanges();
+
+        const fileUploadListComponent: FileUploadListContainerComponent = getElementComponentFromFixtureByCss(
+          fixture,
+          fileUploadListTestId,
+        );
+
+        expect(fileUploadListComponent.parentFormArrayName).toEqual(KommentarFormService.FIELD_ATTACHMENTS);
+        expect(fileUploadListComponent.fileUploadType).toEqual(KOMMENTAR_UPLOADED_ATTACHMENTS);
+      });
+    });
+
+    describe('file upload editor', () => {
+      it('should exists', () => {
+        existsAsHtmlElement(fixture, fileUploadEditorTestId);
+      });
+
+      it('should have inputs', () => {
+        fixture.detectChanges();
+
+        const fileUploadEditorComponent: MultiFileUploadEditorComponent = getElementComponentFromFixtureByCss(
+          fixture,
+          fileUploadEditorTestId,
+        );
+
+        expect(fileUploadEditorComponent.fileUploadType).toEqual(KOMMENTAR_UPLOADED_ATTACHMENTS);
+        expect(fileUploadEditorComponent.uploadResource).toEqual(component.kommentarListStateResource.resource);
+        expect(fileUploadEditorComponent.uploadLinkRelation).toEqual(KommentarListLinkRel.UPLOAD_FILE);
+      });
+    });
+
+    describe('cancel button', () => {
+      it('should exists', () => {
+        existsAsHtmlElement(fixture, cancelButtonTestId);
+      });
+
+      describe('output', () => {
+        describe('clickEmitter', () => {
+          it('should call handler', () => {
+            component.onCancel = jest.fn();
+
+            triggerEvent({ fixture, elementSelector: cancelButtonTestId, name: 'clickEmitter' });
+
+            expect(component.onCancel).toHaveBeenCalled();
+          });
+        });
+      });
+    });
+  });
 });
diff --git a/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-form/kommentar-form.component.ts b/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-form/kommentar-form.component.ts
index 473d6a84137c0f56dac572f9992c6e6830c5ba44..0566d0f19efcc3e09aff3d5a726465eae21371d9 100644
--- a/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-form/kommentar-form.component.ts
+++ b/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-form/kommentar-form.component.ts
@@ -21,24 +21,15 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
+import { BinaryFileListLinkRel, BinaryFileResource } from '@alfa-client/binary-file-shared';
+import { CommandResource, tapOnCommandSuccessfullyDone } from '@alfa-client/command-shared';
+import { KOMMENTAR_UPLOADED_ATTACHMENTS, KommentarLinkRel, KommentarListLinkRel, KommentarListResource, KommentarResource, KommentarService, } from '@alfa-client/kommentar-shared';
+import { createEmptyStateResource, getEmbeddedResources, StateResource } from '@alfa-client/tech-shared';
 import { Component, EventEmitter, Input, OnChanges, Output } from '@angular/core';
-import { CommandResource } from '@alfa-client/command-shared';
-import {
-  KommentarListLinkRel,
-  KommentarListResource,
-  KommentarResource,
-  KommentarService,
-} from '@alfa-client/kommentar-shared';
-import {
-  createEmptyStateResource,
-  getEmbeddedResources,
-  StateResource,
-} from '@alfa-client/tech-shared';
 import { isNil } from 'lodash-es';
 import { Observable, of } from 'rxjs';
-import { KommentarFormService } from './kommentar.formservice';
-import { BinaryFileListLinkRel, BinaryFileResource } from '@alfa-client/binary-file-shared';
 import { map } from 'rxjs/operators';
+import { KommentarFormService } from './kommentar.formservice';
 
 @Component({
   selector: 'alfa-kommentar-form',
@@ -52,12 +43,12 @@ export class KommentarFormComponent implements OnChanges {
 
   @Output() cancel: EventEmitter<void> = new EventEmitter();
 
-  submitInProgress$: Observable<StateResource<CommandResource>> = of(
-    createEmptyStateResource<CommandResource>(),
-  );
+  submitInProgress$: Observable<StateResource<CommandResource>> = of(createEmptyStateResource<CommandResource>());
 
-  readonly formServiceClass = KommentarFormService;
-  readonly kommentarListLinkRel = KommentarListLinkRel;
+  public readonly formServiceClass = KommentarFormService;
+  public readonly kommentarListLinkRel = KommentarListLinkRel;
+  public readonly KommentarLinkRel = KommentarLinkRel;
+  public readonly KOMMENTAR_UPLOADED_ATTACHMENTS = KOMMENTAR_UPLOADED_ATTACHMENTS;
 
   attachments$: Observable<BinaryFileResource[]> = of([]);
 
@@ -76,18 +67,21 @@ export class KommentarFormComponent implements OnChanges {
   private updateAttachments() {
     this.attachments$ = this.kommentarService
       .getAttachments(this.kommentar)
-      .pipe(
-        map((stateResource) =>
-          getEmbeddedResources<BinaryFileResource>(stateResource, BinaryFileListLinkRel.FILE_LIST),
-        ),
-      );
+      .pipe(map((stateResource) => getEmbeddedResources<BinaryFileResource>(stateResource, BinaryFileListLinkRel.FILE_LIST)));
   }
 
   patch(): void {
     this.formService.patch(this.kommentar);
   }
 
-  submit(): void {
-    this.submitInProgress$ = <Observable<StateResource<CommandResource>>>this.formService.submit();
+  public submit(): void {
+    this.submitInProgress$ = <Observable<StateResource<CommandResource>>>(
+      this.formService.submit().pipe(tapOnCommandSuccessfullyDone(() => this.kommentarService.clearUploadedFiles()))
+    );
+  }
+
+  public onCancel(): void {
+    this.kommentarService.clearUploadedFiles();
+    this.cancel.emit();
   }
 }
diff --git a/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang/kommentar-list-in-vorgang.component.spec.ts b/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang/kommentar-list-in-vorgang.component.spec.ts
index 2e0e94f295129d7a65d7c9ca23c94ed384e83c38..4e267cefae258f6898249931a1b7495823d4e168 100644
--- a/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang/kommentar-list-in-vorgang.component.spec.ts
+++ b/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang/kommentar-list-in-vorgang.component.spec.ts
@@ -21,17 +21,13 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
+import { KommentarListLinkRel } from '@alfa-client/kommentar-shared';
+import { createEmptyStateResource, createStateResource } from '@alfa-client/tech-shared';
 import { ComponentFixture, TestBed } from '@angular/core/testing';
 import { MockComponent } from 'ng-mocks';
+import { createKommentarListResource } from '../../../../../kommentar-shared/test/kommentar';
 import { KommentarListInVorgangComponent } from './kommentar-list-in-vorgang.component';
 import { KommentarListItemInVorgangComponent } from './kommentar-list-item-in-vorgang/kommentar-list-item-in-vorgang.component';
-import {
-  createEmptyStateResource,
-  createStateResource,
-  EMPTY_ARRAY,
-} from '@alfa-client/tech-shared';
-import { createKommentarListResource } from '../../../../../kommentar-shared/test/kommentar';
-import { KommentarListLinkRel } from '@alfa-client/kommentar-shared';
 
 describe('KommentarListInVorgangComponent', () => {
   let component: KommentarListInVorgangComponent;
@@ -39,10 +35,7 @@ describe('KommentarListInVorgangComponent', () => {
 
   beforeEach(async () => {
     await TestBed.configureTestingModule({
-      declarations: [
-        KommentarListInVorgangComponent,
-        MockComponent(KommentarListItemInVorgangComponent),
-      ],
+      declarations: [KommentarListInVorgangComponent, MockComponent(KommentarListItemInVorgangComponent)],
     });
   });
 
@@ -60,22 +53,20 @@ describe('KommentarListInVorgangComponent', () => {
     it('should return empty array if state resource is null', () => {
       component.kommentarListStateResource = null;
 
-      expect(component.getKommentare()).toEqual(EMPTY_ARRAY);
+      expect(component.getKommentare()).toEqual([]);
     });
 
     it('should return empty array if resource is null', () => {
       component.kommentarListStateResource = createEmptyStateResource();
 
-      expect(component.getKommentare()).toEqual(EMPTY_ARRAY);
+      expect(component.getKommentare()).toEqual([]);
     });
 
     it('should return embedded resource', () => {
       const kommentareListResource = createKommentarListResource();
       component.kommentarListStateResource = createStateResource(kommentareListResource);
 
-      expect(component.getKommentare()).toEqual(
-        kommentareListResource._embedded[KommentarListLinkRel.KOMMENTAR_LIST],
-      );
+      expect(component.getKommentare()).toEqual(kommentareListResource._embedded[KommentarListLinkRel.KOMMENTAR_LIST]);
     });
   });
 });
diff --git a/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang/kommentar-list-item-in-vorgang/kommentar-list-item-in-vorgang.component.html b/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang/kommentar-list-item-in-vorgang/kommentar-list-item-in-vorgang.component.html
index e1e4dbdf6cd4e216ce96f189eed122d62ed74782..78ac673c8e3c3a2b871f8f0af621b8bf5b2d09e3 100644
--- a/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang/kommentar-list-item-in-vorgang/kommentar-list-item-in-vorgang.component.html
+++ b/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang/kommentar-list-item-in-vorgang/kommentar-list-item-in-vorgang.component.html
@@ -24,10 +24,7 @@
 
 -->
 <div *ngIf="!editMode" class="plain-text text-sm">
-  <button
-    [attr.data-test-id]="'kommentar-item-' + (kommentar.text | convertForDataTest)"
-    (click)="edit()"
-  >
+  <button [attr.data-test-id]="'kommentar-item-' + (kommentar.text | convertForDataTest)" (click)="edit()">
     <div class="kommentar-head">
       <alfa-user-profile-in-kommentar-container
         class="username"
@@ -42,12 +39,12 @@
     <p class="text">{{ kommentar.text }}</p>
   </button>
 
-  <alfa-horizontal-binary-file-list
-    *ngIf="kommentar | hasLink: kommentarLinkRel.ATTACHMENTS"
-    [deletable]="false"
-    [fileListResource]="attachments$ | async"
-  >
-  </alfa-horizontal-binary-file-list>
+  @if (kommentar | hasLink: kommentarLinkRel.ATTACHMENTS) {
+    <alfa-binary-file-list-container
+      [resource]="kommentar"
+      [linkRel]="kommentarLinkRel.ATTACHMENTS"
+    ></alfa-binary-file-list-container>
+  }
 </div>
 
 <alfa-kommentar-form
diff --git a/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang/kommentar-list-item-in-vorgang/kommentar-list-item-in-vorgang.component.ts b/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang/kommentar-list-item-in-vorgang/kommentar-list-item-in-vorgang.component.ts
index d94fdd3c555be42544f58e660a91e7030edbac4d..cf6a951f4bd32c241281ce7c3207092387f92ce1 100644
--- a/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang/kommentar-list-item-in-vorgang/kommentar-list-item-in-vorgang.component.ts
+++ b/alfa-client/libs/kommentar/src/lib/kommentar-list-in-vorgang-container/kommentar-list-in-vorgang/kommentar-list-item-in-vorgang/kommentar-list-item-in-vorgang.component.ts
@@ -21,15 +21,10 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-import { Component, Input, OnInit } from '@angular/core';
 import { BinaryFileListResource } from '@alfa-client/binary-file-shared';
-import {
-  KommentarLinkRel,
-  KommentarListResource,
-  KommentarResource,
-  KommentarService,
-} from '@alfa-client/kommentar-shared';
-import { StateResource, createEmptyStateResource } from '@alfa-client/tech-shared';
+import { KommentarLinkRel, KommentarListResource, KommentarResource, KommentarService } from '@alfa-client/kommentar-shared';
+import { createEmptyStateResource, StateResource } from '@alfa-client/tech-shared';
+import { Component, Input, OnInit } from '@angular/core';
 import { hasLink } from '@ngxp/rest';
 import { Observable, of } from 'rxjs';
 
@@ -42,9 +37,7 @@ export class KommentarListItemInVorgangComponent implements OnInit {
   @Input() kommentar: KommentarResource;
 
   @Input() kommentarListStateResource: StateResource<KommentarListResource>;
-  attachments$: Observable<StateResource<BinaryFileListResource>> = of(
-    createEmptyStateResource<BinaryFileListResource>(),
-  );
+  attachments$: Observable<StateResource<BinaryFileListResource>> = of(createEmptyStateResource<BinaryFileListResource>());
 
   editMode: boolean = false;
 
diff --git a/alfa-client/libs/kommentar/src/lib/kommentar.module.ts b/alfa-client/libs/kommentar/src/lib/kommentar.module.ts
index 4c9da054bee43f9411bd2e93ce3c4242246bf3aa..3a8e4dd40a4a53552567b81b69fad3af2c230312 100644
--- a/alfa-client/libs/kommentar/src/lib/kommentar.module.ts
+++ b/alfa-client/libs/kommentar/src/lib/kommentar.module.ts
@@ -30,6 +30,8 @@ import { VorgangSharedModule } from '@alfa-client/vorgang-shared';
 import { CommonModule } from '@angular/common';
 import { NgModule } from '@angular/core';
 import { ReactiveFormsModule } from '@angular/forms';
+import { FileUploadListContainerComponent } from '../../../binary-file/src/lib/file-upload-list-container/file-upload-list-container.component';
+import { MultiFileUploadEditorComponent } from '../../../binary-file/src/lib/multi-file-upload-editor/multi-file-upload-editor.component';
 import { KommentarFormComponent } from './kommentar-list-in-vorgang-container/kommentar-form/kommentar-form.component';
 import { KommentarListInVorgangContainerComponent } from './kommentar-list-in-vorgang-container/kommentar-list-in-vorgang-container.component';
 import { KommentarListInVorgangComponent } from './kommentar-list-in-vorgang-container/kommentar-list-in-vorgang/kommentar-list-in-vorgang.component';
@@ -42,6 +44,8 @@ import { KommentarListItemInVorgangComponent } from './kommentar-list-in-vorgang
     KommentarSharedModule,
     UserProfileModule,
     BinaryFileModule,
+    MultiFileUploadEditorComponent,
+    FileUploadListContainerComponent,
     ReactiveFormsModule,
     TextAreaEditorComponent,
     OzgcloudStrokedButtonWithSpinnerComponent,
diff --git a/alfa-client/libs/postfach-shared/src/lib/postfach.service.ts b/alfa-client/libs/postfach-shared/src/lib/postfach.service.ts
index 483377d3c54a2d43db97f549a428b1d00312593c..189ab9a2059f0941773bc7754a8929799889bf30 100644
--- a/alfa-client/libs/postfach-shared/src/lib/postfach.service.ts
+++ b/alfa-client/libs/postfach-shared/src/lib/postfach.service.ts
@@ -22,10 +22,10 @@
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
 import {
+  BinaryFileListLinkRel,
   BinaryFileListResource,
   BinaryFileResource,
   BinaryFileService,
-  getBinaryFiles,
 } from '@alfa-client/binary-file-shared';
 import {
   CommandResource,
@@ -41,6 +41,7 @@ import {
   createEmptyStateResource,
   createStateResource,
   doIfLoadingRequired,
+  getEmbeddedResources,
   isNotNull,
   isNotUndefined,
 } from '@alfa-client/tech-shared';
@@ -69,9 +70,7 @@ import { createResendPostfachMailCommand, createSendPostfachMailCommand } from '
 
 @Injectable({ providedIn: 'root' })
 export class PostfachService {
-  private readonly isPollSendPostachMail: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(
-    false,
-  );
+  private readonly isPollSendPostachMail: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
   postfachMailList$: BehaviorSubject<StateResource<PostfachMailListResource>> = new BehaviorSubject<
     StateResource<PostfachMailListResource>
   >(createEmptyStateResource<PostfachMailListResource>());
@@ -108,16 +107,10 @@ export class PostfachService {
     postfachMailResource: PostfachMailResource,
     postfachMail: PostfachMail,
   ): Observable<StateResource<CommandResource>> {
-    return this.doSendNachricht(
-      postfachMailResource,
-      PostfachMailLinkRel.SEND,
-      createSendPostfachMailCommand(postfachMail),
-    );
+    return this.doSendNachricht(postfachMailResource, PostfachMailLinkRel.SEND, createSendPostfachMailCommand(postfachMail));
   }
 
-  public resendMail(
-    postfachMailResource: PostfachMailResource,
-  ): Observable<StateResource<CommandResource>> {
+  public resendMail(postfachMailResource: PostfachMailResource): Observable<StateResource<CommandResource>> {
     return this.doSendNachricht(
       postfachMailResource,
       PostfachMailLinkRel.RESEND_POSTFACH_MAIL,
@@ -168,9 +161,7 @@ export class PostfachService {
 
   listenToNavigation(): void {
     this.unsubscribeToNavigation();
-    this.navigationSubscription = this.navigationService
-      .urlChanged()
-      .subscribe((params) => this.onNavigation(params));
+    this.navigationSubscription = this.navigationService.urlChanged().subscribe((params) => this.onNavigation(params));
   }
 
   unsubscribeToNavigation(): void {
@@ -205,10 +196,8 @@ export class PostfachService {
   }
 
   unsubscribe(): void {
-    if (isNotUndefined(this.sendPostfachMailSubscription))
-      this.sendPostfachMailSubscription.unsubscribe();
-    if (isNotUndefined(this.loadPostfachMailSubscription))
-      this.loadPostfachMailSubscription.unsubscribe();
+    if (isNotUndefined(this.sendPostfachMailSubscription)) this.sendPostfachMailSubscription.unsubscribe();
+    if (isNotUndefined(this.loadPostfachMailSubscription)) this.loadPostfachMailSubscription.unsubscribe();
     if (isNotUndefined(this.vorgangSubscription)) this.vorgangSubscription.unsubscribe();
   }
 
@@ -217,45 +206,31 @@ export class PostfachService {
   }
 
   resetHasNewPostfachNachrichten(): void {
-    this.postfachNachrichtenListSubscription = this.getPostfachMailListByVorgang().subscribe(
-      (postfachNachrichtenList) => {
-        if (isNotNull(postfachNachrichtenList.resource)) {
-          setTimeout(() => this.postfachNachrichtenListSubscription.unsubscribe(), 0);
-          this.doResetHasNewPostfachNachrichten();
-        }
-      },
-    );
+    this.postfachNachrichtenListSubscription = this.getPostfachMailListByVorgang().subscribe((postfachNachrichtenList) => {
+      if (isNotNull(postfachNachrichtenList.resource)) {
+        setTimeout(() => this.postfachNachrichtenListSubscription.unsubscribe(), 0);
+        this.doResetHasNewPostfachNachrichten();
+      }
+    });
   }
 
   doResetHasNewPostfachNachrichten(): void {
-    if (
-      hasLink(
-        this.postfachMailList$.value.resource,
-        PostfachMailListLinkRel.RESET_HAS_NEW_POSTFACH_NACHRICHT,
-      )
-    ) {
-      this.repository
-        .resetHasNewPostfachNachrichten(this.postfachMailList$.value.resource)
-        .pipe(take(1))
-        .subscribe();
+    if (hasLink(this.postfachMailList$.value.resource, PostfachMailListLinkRel.RESET_HAS_NEW_POSTFACH_NACHRICHT)) {
+      this.repository.resetHasNewPostfachNachrichten(this.postfachMailList$.value.resource).pipe(take(1)).subscribe();
     }
   }
 
-  pollSendPostfachMailCommand(
-    command: StateResource<CommandResource>,
-  ): StateResource<CommandResource> {
+  pollSendPostfachMailCommand(command: StateResource<CommandResource>): StateResource<CommandResource> {
     if (this.shouldPoll(command)) {
       this.setPollingTrue();
-      this.sendPostfachMailSubscription = this.commandService
-        .pollCommand(command.resource)
-        .subscribe((updatedStateResource) => {
-          this.vorgangService.setPendingSendPostfachMailCommand(updatedStateResource);
-
-          if (isDone(updatedStateResource.resource)) {
-            this.handleSendPostfachMailIsDone(updatedStateResource);
-            setTimeout(() => this.sendPostfachMailSubscription.unsubscribe(), 0);
-          }
-        });
+      this.sendPostfachMailSubscription = this.commandService.pollCommand(command.resource).subscribe((updatedStateResource) => {
+        this.vorgangService.setPendingSendPostfachMailCommand(updatedStateResource);
+
+        if (isDone(updatedStateResource.resource)) {
+          this.handleSendPostfachMailIsDone(updatedStateResource);
+          setTimeout(() => this.sendPostfachMailSubscription.unsubscribe(), 0);
+        }
+      });
     }
     return command;
   }
@@ -282,17 +257,11 @@ export class PostfachService {
       });
   }
 
-  getEffectedResource(
-    updatedStateResource: StateResource<CommandResource>,
-  ): Observable<PostfachMailListResource> {
-    return this.commandService.getEffectedResource<PostfachMailListResource>(
-      updatedStateResource.resource,
-    );
+  getEffectedResource(updatedStateResource: StateResource<CommandResource>): Observable<PostfachMailListResource> {
+    return this.commandService.getEffectedResource<PostfachMailListResource>(updatedStateResource.resource);
   }
 
-  public getPostfachMailListByGivenVorgang(
-    vorgang: VorgangResource,
-  ): Observable<StateResource<PostfachMailListResource>> {
+  public getPostfachMailListByGivenVorgang(vorgang: VorgangResource): Observable<StateResource<PostfachMailListResource>> {
     doIfLoadingRequired(this.postfachMailList$.value, () => {
       this.setPostfachMailListLoading();
       this.loadPostfachMailsByVorgang(vorgang);
@@ -303,14 +272,12 @@ export class PostfachService {
   public getPostfachMailListByVorgang(): Observable<StateResource<PostfachMailListResource>> {
     doIfLoadingRequired(this.postfachMailList$.value, () => {
       this.setPostfachMailListLoading();
-      this.vorgangSubscription = this.vorgangService
-        .getVorgangWithEingang()
-        .subscribe((vorgangWithEingangStateResource) => {
-          if (vorgangWithEingangStateResource.resource) {
-            this.loadPostfachMailsByVorgang(vorgangWithEingangStateResource.resource);
-            setTimeout(() => this.vorgangSubscription.unsubscribe(), 0);
-          }
-        });
+      this.vorgangSubscription = this.vorgangService.getVorgangWithEingang().subscribe((vorgangWithEingangStateResource) => {
+        if (vorgangWithEingangStateResource.resource) {
+          this.loadPostfachMailsByVorgang(vorgangWithEingangStateResource.resource);
+          setTimeout(() => this.vorgangSubscription.unsubscribe(), 0);
+        }
+      });
     });
     return this.postfachMailList$.asObservable();
   }
@@ -320,31 +287,24 @@ export class PostfachService {
   }
 
   public loadPostfachMailsByVorgang(vorgang: VorgangResource): void {
-    this.loadPostfachMailSubscription = this.repository
-      .loadPostfachMailList(vorgang)
-      .subscribe((postfachMaiList) => {
-        if (!isNull(postfachMaiList)) {
-          this.setPostfachMailList(postfachMaiList);
-          setTimeout(() => this.loadPostfachMailSubscription.unsubscribe(), 0);
-        }
-      });
+    this.loadPostfachMailSubscription = this.repository.loadPostfachMailList(vorgang).subscribe((postfachMaiList) => {
+      if (!isNull(postfachMaiList)) {
+        this.setPostfachMailList(postfachMaiList);
+        setTimeout(() => this.loadPostfachMailSubscription.unsubscribe(), 0);
+      }
+    });
   }
 
   setPostfachMailList(postfachMailList: PostfachMailListResource): void {
     this.postfachMailList$.next(createStateResource(postfachMailList));
   }
 
-  public loadAttachments(
-    postfachNachricht: PostfachMailResource,
-  ): Observable<StateResource<BinaryFileListResource>> {
+  public loadAttachments(postfachNachricht: PostfachMailResource): Observable<StateResource<BinaryFileListResource>> {
     return this.binaryFileService.getFiles(postfachNachricht, PostfachMailLinkRel.ATTACHMENTS);
   }
 
   public isDownloadPdfInProgress(): Observable<boolean> {
-    return combineLatest([
-      this.vorgangService.getVorgangWithEingang(),
-      this.postfachFacade.isDownloadPdfInProgress(),
-    ]).pipe(
+    return combineLatest([this.vorgangService.getVorgangWithEingang(), this.postfachFacade.isDownloadPdfInProgress()]).pipe(
       tap(([vorgang, isDownloadInProgress]) => {
         if (isDownloadInProgress && vorgang.resource) {
           this.postfachFacade.downloadPdf(vorgang.resource);
@@ -361,11 +321,11 @@ export class PostfachService {
   public getAttachments(postfachNachricht: PostfachMailResource): Observable<BinaryFileResource[]> {
     return this.postfachFacade.getAttachmentList().pipe(
       tap((attachmentList) =>
-        doIfLoadingRequired(attachmentList, () =>
-          this.postfachFacade.loadAttachmentList(postfachNachricht),
-        ),
+        doIfLoadingRequired(attachmentList, () => this.postfachFacade.loadAttachmentList(postfachNachricht)),
+      ),
+      map((binaryFileListResource: StateResource<BinaryFileListResource>) =>
+        getEmbeddedResources(binaryFileListResource, BinaryFileListLinkRel.FILE_LIST),
       ),
-      map(getBinaryFiles),
     );
   }
 
@@ -375,19 +335,13 @@ export class PostfachService {
 
   public getFeatures(): Observable<PostfachFeatures> {
     return this.getPostfachMailListByVorgang().pipe(
-      map(
-        (listStateResource: StateResource<PostfachMailListResource>) =>
-          listStateResource.resource.features,
-      ),
+      map((listStateResource: StateResource<PostfachMailListResource>) => listStateResource.resource.features),
     );
   }
 
   public getSettings(): Observable<PostfachSettings> {
     return this.getPostfachMailListByVorgang().pipe(
-      map(
-        (listStateResource: StateResource<PostfachMailListResource>) =>
-          listStateResource.resource.settings,
-      ),
+      map((listStateResource: StateResource<PostfachMailListResource>) => listStateResource.resource.settings),
     );
   }
 }
diff --git a/alfa-client/libs/postfach-shared/test/postfach.ts b/alfa-client/libs/postfach-shared/test/postfach.ts
index cc96efe9a93fdde304d17e460277bd4a146d429a..831f9b7eeafd5401719b392b56d1a79b2c0cb212 100644
--- a/alfa-client/libs/postfach-shared/test/postfach.ts
+++ b/alfa-client/libs/postfach-shared/test/postfach.ts
@@ -21,7 +21,7 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-import { EMPTY_ARRAY, createStateResource } from '@alfa-client/tech-shared';
+import { createStateResource } from '@alfa-client/tech-shared';
 import { faker } from '@faker-js/faker';
 import { Resource } from '@ngxp/rest';
 import { toResource } from 'libs/tech-shared/test/resource';
@@ -61,18 +61,14 @@ export function createPostfachMailResources(linkRelations: string[] = []): Postf
   return times(10, () => toResource(createPostfachMailResource(), [...linkRelations]));
 }
 
-export function createPostfachMailListResource(
-  linkRelations: string[] = [],
-): PostfachMailListResource {
+export function createPostfachMailListResource(linkRelations: string[] = []): PostfachMailListResource {
   return toResource(createPostfachMailList(), [...linkRelations], {
     [PostfachMailListLinkRel.POSTFACH_MAIL_LIST]: createPostfachMailResources(),
   });
 }
 
 function createPostfachMailList(): Resource {
-  return toResource({ features: createPostfachFeatures(), settings: createPostfachSettings() }, [
-    'sendPostfachMail',
-  ]);
+  return toResource({ features: createPostfachFeatures(), settings: createPostfachSettings() }, ['sendPostfachMail']);
 }
 
 export function createPostfachFeatures(): PostfachFeatures {
@@ -100,10 +96,7 @@ export class PostfachTestFactory {
     attachments: faker.string.uuid(),
   };
 
-  public static POSTFACH_NACHRICHT_RESOURCE: PostfachMailResource = toResource(
-    PostfachTestFactory.POSTFACH_NACHRICHT,
-    EMPTY_ARRAY,
-  );
+  public static POSTFACH_NACHRICHT_RESOURCE: PostfachMailResource = toResource(PostfachTestFactory.POSTFACH_NACHRICHT, []);
   public static POSTFACH_NACHRICHT_LIST_RESOURCE = createPostfachMailListResource();
   public static POSTFACH_NACHRICHT_LIST_STATE_RESOURCE = createStateResource(
     PostfachTestFactory.POSTFACH_NACHRICHT_LIST_RESOURCE,
diff --git a/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-nachricht-attachment-container/postfach-nachricht-attachment-container.component.ts b/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-nachricht-attachment-container/postfach-nachricht-attachment-container.component.ts
index ff5ef4cdaa751d6a7c746fee18c23aef08a0a527..0d3b7339b30a9ca15d03d791d60db92e7e42299b 100644
--- a/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-nachricht-attachment-container/postfach-nachricht-attachment-container.component.ts
+++ b/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-nachricht-attachment-container/postfach-nachricht-attachment-container.component.ts
@@ -21,7 +21,6 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-import { Component, Input, OnDestroy } from '@angular/core';
 import { BinaryFileResource } from '@alfa-client/binary-file-shared';
 import {
   PostfachMailLinkRel,
@@ -30,7 +29,8 @@ import {
   PostfachMailResource,
   PostfachService,
 } from '@alfa-client/postfach-shared';
-import { EMPTY_ARRAY, FormProvider, StateResource, isNotNil } from '@alfa-client/tech-shared';
+import { FormProvider, StateResource, isNotNil } from '@alfa-client/tech-shared';
+import { Component, Input, OnDestroy } from '@angular/core';
 import { hasLink } from '@ngxp/rest';
 import { Observable, of } from 'rxjs';
 import { PostfachMailFormservice } from '../postfach-mail.formservice';
@@ -45,7 +45,7 @@ export class PostfachNachrichtAttachmentContainerComponent implements OnDestroy
   @Input() postfachNachricht: PostfachMailResource;
 
   postfachNachrichtListStateResource$: Observable<StateResource<PostfachMailListResource>>;
-  attachments$: Observable<BinaryFileResource[]> = of<BinaryFileResource[]>(EMPTY_ARRAY);
+  attachments$: Observable<BinaryFileResource[]> = of<BinaryFileResource[]>([]);
 
   public readonly postfachMailListLinkRel = PostfachMailListLinkRel;
   public readonly formServiceClass = PostfachMailFormservice;
diff --git a/alfa-client/libs/tech-shared/src/lib/pipe/to-embedded-resource.pipe.spec.ts b/alfa-client/libs/tech-shared/src/lib/pipe/to-embedded-resource.pipe.spec.ts
index bfd30ddd0afb673c9ab9eb285d33643eace88139..5420e9992163adac652466364d736c6c50c78860 100644
--- a/alfa-client/libs/tech-shared/src/lib/pipe/to-embedded-resource.pipe.spec.ts
+++ b/alfa-client/libs/tech-shared/src/lib/pipe/to-embedded-resource.pipe.spec.ts
@@ -25,7 +25,6 @@ import { getEmbeddedResource } from '@ngxp/rest';
 import { DummyListLinkRel } from 'libs/tech-shared/test/dummy';
 import { createDummyListResource, toResource } from 'libs/tech-shared/test/resource';
 import { ListResource } from '../resource/resource.util';
-import { EMPTY_ARRAY } from '../tech.util';
 import { ToEmbeddedResourcesPipe } from './to-embedded-resource.pipe';
 
 describe('ToEmbeddedResourcesPipe', () => {
@@ -47,19 +46,19 @@ describe('ToEmbeddedResourcesPipe', () => {
     it('should return an empty array on null as listResource', () => {
       const result: unknown[] = pipe.transform(null, DummyListLinkRel.LIST);
 
-      expect(result).toBe(EMPTY_ARRAY);
+      expect(result).toEqual([]);
     });
 
     it('should return empty array on null as linkel', () => {
       const result: unknown[] = pipe.transform(listResource, null);
 
-      expect(result).toBe(EMPTY_ARRAY);
+      expect(result).toEqual([]);
     });
 
     it('should return empty array non existing resources', () => {
       const result: unknown[] = pipe.transform(toResource({}), DummyListLinkRel.LIST);
 
-      expect(result).toBe(EMPTY_ARRAY);
+      expect(result).toEqual([]);
     });
   });
 });
diff --git a/alfa-client/libs/tech-shared/src/lib/pipe/to-embedded-resource.pipe.ts b/alfa-client/libs/tech-shared/src/lib/pipe/to-embedded-resource.pipe.ts
index dbb7025753327feff619bd1a0559951bf8b6ebe0..7b746907bf222789faf57e003583e46bcb5e16ed 100644
--- a/alfa-client/libs/tech-shared/src/lib/pipe/to-embedded-resource.pipe.ts
+++ b/alfa-client/libs/tech-shared/src/lib/pipe/to-embedded-resource.pipe.ts
@@ -26,7 +26,6 @@ import { Resource, getEmbeddedResource } from '@ngxp/rest';
 import { isNil, isNull } from 'lodash-es';
 import { LinkRelationName } from '../resource/resource.model';
 import { ListResource } from '../resource/resource.util';
-import { EMPTY_ARRAY } from '../tech.util';
 
 @Pipe({
   name: 'toEmbeddedResources',
@@ -34,8 +33,8 @@ import { EMPTY_ARRAY } from '../tech.util';
 })
 export class ToEmbeddedResourcesPipe implements PipeTransform {
   transform(listResource: ListResource, linkRel: LinkRelationName): Resource[] {
-    if (isNil(listResource) || isNil(linkRel)) return EMPTY_ARRAY;
+    if (isNil(listResource) || isNil(linkRel)) return [];
     const embeddedReources: Resource[] = getEmbeddedResource(listResource, linkRel);
-    return isNull(embeddedReources) ? EMPTY_ARRAY : embeddedReources;
+    return isNull(embeddedReources) ? [] : embeddedReources;
   }
 }
diff --git a/alfa-client/libs/tech-shared/src/lib/resource/list-resource.service.spec.ts b/alfa-client/libs/tech-shared/src/lib/resource/list-resource.service.spec.ts
index 60c4640d92c10a70d0bec7d763d80a8f9618ff33..aa2dee9b6966288e6326463b82a4568abef68ecd 100644
--- a/alfa-client/libs/tech-shared/src/lib/resource/list-resource.service.spec.ts
+++ b/alfa-client/libs/tech-shared/src/lib/resource/list-resource.service.spec.ts
@@ -30,7 +30,6 @@ import { DummyLinkRel, DummyListLinkRel } from 'libs/tech-shared/test/dummy';
 import { createDummyListResource, createDummyResource, createFilledDummyListResource } from 'libs/tech-shared/test/resource';
 import { BehaviorSubject, Observable, of } from 'rxjs';
 import { multipleCold, singleCold, singleHot } from '../../../test/marbles';
-import { EMPTY_ARRAY } from '../tech.util';
 import { ResourceListService } from './list-resource.service';
 import { CreateResourceData, LinkRelationName, ListItemResource, ListResourceServiceConfig } from './resource.model';
 import { ResourceRepository } from './resource.repository';
@@ -547,7 +546,7 @@ describe('ListResourceService', () => {
       service.getList = jest.fn().mockReturnValue(of(createEmptyStateResource()));
 
       service.getItems().subscribe((items) => {
-        expect(items).toEqual(EMPTY_ARRAY);
+        expect(items).toEqual([]);
         done();
       });
     });
diff --git a/alfa-client/libs/tech-shared/src/lib/resource/resource.util.spec.ts b/alfa-client/libs/tech-shared/src/lib/resource/resource.util.spec.ts
index 3bfc293f96169bd19c2db03eb6c3030a15d8a8f1..5e5a9f2b37a30aeda80c61e09986d021e556cd41 100644
--- a/alfa-client/libs/tech-shared/src/lib/resource/resource.util.spec.ts
+++ b/alfa-client/libs/tech-shared/src/lib/resource/resource.util.spec.ts
@@ -26,7 +26,6 @@ import { createCommandStateResource } from 'libs/command-shared/test/command';
 import { DummyListLinkRel } from '../../../test/dummy';
 import { createApiError } from '../../../test/error';
 import { createDummyListResource, createDummyResource, toResource } from '../../../test/resource';
-import { EMPTY_ARRAY } from '../tech.util';
 import {
   StateResource,
   containsLoading,
@@ -139,13 +138,13 @@ describe('resource util', () => {
     it('should return empty array if state resource null', () => {
       const embedded = getEmbeddedResources(null, null);
 
-      expect(embedded).toEqual(EMPTY_ARRAY);
+      expect(embedded).toEqual([]);
     });
 
     it('should return empty array if resource null', () => {
       const embedded = getEmbeddedResources(createEmptyStateResource(), null);
 
-      expect(embedded).toEqual(EMPTY_ARRAY);
+      expect(embedded).toEqual([]);
     });
 
     it('should return null if embedded relation does not exist', () => {
diff --git a/alfa-client/libs/tech-shared/src/lib/tech.util.ts b/alfa-client/libs/tech-shared/src/lib/tech.util.ts
index 01a8ec90cdc85a6ea0145415c50095c5366c79a6..baed9187b7bf29b1d6e18b958e3bdb4888b090bd 100644
--- a/alfa-client/libs/tech-shared/src/lib/tech.util.ts
+++ b/alfa-client/libs/tech-shared/src/lib/tech.util.ts
@@ -30,7 +30,6 @@ import { LinkRelationName } from './resource/resource.model';
 import { ApiError } from './tech.model';
 
 export const EMPTY_STRING: string = '';
-export const EMPTY_ARRAY = [];
 
 export function getBaseUrl(): string {
   const { protocol, host } = window.location;
@@ -44,9 +43,7 @@ export function isEmptyObject(obj: any): boolean {
 
 export function replacePlaceholders(text: string, placeholders: { [key: string]: string }): string {
   let replaced: string = text;
-  Object.keys(placeholders).forEach(
-    (key: string) => (replaced = replacePlaceholder(replaced, key, placeholders[key])),
-  );
+  Object.keys(placeholders).forEach((key: string) => (replaced = replacePlaceholder(replaced, key, placeholders[key])));
   return replaced;
 }
 
@@ -56,9 +53,7 @@ export function replacePlaceholder(text: string, placeholder: string, value: str
 }
 
 export function hasExceptionId(apiError: ApiError): boolean {
-  return (
-    isNotNil(apiError) && isNotNil(apiError.issues) && isNotNil(apiError.issues[0].exceptionId)
-  );
+  return isNotNil(apiError) && isNotNil(apiError.issues) && isNotNil(apiError.issues[0].exceptionId);
 }
 
 export function sleep(delayInMs: number): void {
@@ -152,9 +147,5 @@ export function notHasAnyLink(resource: Resource, ...links: LinkRelationName[]):
 }
 
 export function hasAnyLink(resource: Resource, ...links: LinkRelationName[]): boolean {
-  return !isEmpty(
-    links
-      .map((link: LinkRelationName) => hasLink(resource, link))
-      .filter((hasLink: boolean) => hasLink === true),
-  );
+  return !isEmpty(links.map((link: LinkRelationName) => hasLink(resource, link)).filter((hasLink: boolean) => hasLink === true));
 }
diff --git a/alfa-client/libs/tech-shared/test/file.ts b/alfa-client/libs/tech-shared/test/file.ts
index 5feadc2fcd75f4e7b9144afa4c53194e995b43d3..5f4a0578aa673642049ba6ed8e54f5eb99f39222 100644
--- a/alfa-client/libs/tech-shared/test/file.ts
+++ b/alfa-client/libs/tech-shared/test/file.ts
@@ -26,3 +26,12 @@ import { faker } from '@faker-js/faker';
 export function createFile(): File {
   return <any>{ name: faker.string.sample(10), type: 'image/png', size: 512 };
 }
+
+export function createFileList(): FileList {
+  const file = createFile();
+  return {
+    0: file,
+    length: 2,
+    item: (index: number) => file,
+  };
+}
diff --git a/alfa-client/libs/tech-shared/test/http.ts b/alfa-client/libs/tech-shared/test/http.ts
index 76abc5588ba27b70f755cc07437150add45375c7..0f03449f6400f456d027b4b2fa524b101b337155 100644
--- a/alfa-client/libs/tech-shared/test/http.ts
+++ b/alfa-client/libs/tech-shared/test/http.ts
@@ -21,7 +21,8 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-import { HttpErrorResponse, HttpStatusCode } from '@angular/common/http';
+import { HttpHeader } from '@alfa-client/tech-shared';
+import { HttpErrorResponse, HttpResponse, HttpStatusCode } from '@angular/common/http';
 import { createApiError } from './error';
 
 export function createHttpErrorResponse(): HttpErrorResponse {
@@ -30,3 +31,16 @@ export function createHttpErrorResponse(): HttpErrorResponse {
     status: HttpStatusCode.ServiceUnavailable,
   };
 }
+
+export function createHttpResponse(): HttpResponse<Object> {
+  return {
+    status: HttpStatusCode.Accepted,
+    body: null,
+    clone: null,
+    headers: <any>{ get: (headerName: HttpHeader) => 'headerDummyUrl' },
+    ok: null,
+    statusText: null,
+    type: null,
+    url: null,
+  };
+}
diff --git a/alfa-client/libs/tech-shared/test/marbles.ts b/alfa-client/libs/tech-shared/test/marbles.ts
index fecda8769f38a80dd34c693c9ca39bf175a69eef..c84c4c3f8b35246ac3782d714d993be1bd36d9a8 100644
--- a/alfa-client/libs/tech-shared/test/marbles.ts
+++ b/alfa-client/libs/tech-shared/test/marbles.ts
@@ -21,7 +21,8 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-import { ObservableWithSubscriptions, cold, hot } from 'jest-marbles';
+import { cold, hot, ObservableWithSubscriptions } from 'jest-marbles';
+import { HttpError } from '../src/lib/tech.model';
 
 export function singleHot(object: any, frame: string = 'a'): ObservableWithSubscriptions {
   return hot(frame, { a: object });
@@ -38,3 +39,11 @@ export function singleColdCompleted(object: any, frame: string = 'a'): Observabl
 export function multipleCold(first: any, second: any): ObservableWithSubscriptions {
   return cold('ab', { a: first, b: second });
 }
+
+export function coldError(error: HttpError): ObservableWithSubscriptions {
+  return cold('-#', null, { error: { error: error } });
+}
+
+export function coldStartWithError(startWith: any, error: any): ObservableWithSubscriptions {
+  return cold('a(b|)', { a: startWith, b: error });
+}
diff --git a/alfa-client/libs/ui/src/lib/ui/back-button/back-button.component.ts b/alfa-client/libs/ui/src/lib/ui/back-button/back-button.component.ts
index a5c00893b3fa0fe9c3745afa4a750f395f06df70..db593f08cb17ab00615fb0314f68d044491e9665 100644
--- a/alfa-client/libs/ui/src/lib/ui/back-button/back-button.component.ts
+++ b/alfa-client/libs/ui/src/lib/ui/back-button/back-button.component.ts
@@ -22,9 +22,6 @@
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
 import { Component, Input } from '@angular/core';
-import { MatIconAnchor } from '@angular/material/button';
-import { MatIcon } from '@angular/material/icon';
-import { MatTooltip } from '@angular/material/tooltip';
 import { RouterLink } from '@angular/router';
 import { ArrowBackIconComponent, ButtonComponent, TooltipDirective } from '@ods/system';
 
@@ -33,7 +30,7 @@ import { ArrowBackIconComponent, ButtonComponent, TooltipDirective } from '@ods/
   templateUrl: './back-button.component.html',
   styleUrls: ['./back-button.component.scss'],
   standalone: true,
-  imports: [MatIconAnchor, RouterLink, MatTooltip, MatIcon, TooltipDirective, ButtonComponent, ArrowBackIconComponent],
+  imports: [RouterLink, TooltipDirective, ButtonComponent, ArrowBackIconComponent],
 })
 export class BackButtonComponent {
   @Input() label: string;
diff --git a/alfa-client/libs/vorgang-shared/src/lib/+state/vorgang.reducer.spec.ts b/alfa-client/libs/vorgang-shared/src/lib/+state/vorgang.reducer.spec.ts
index 49ef271f9dfe7e93af9a114ad8840972db003a6f..c3358acb510534afa4df0bca712d8b2ff8161bb5 100644
--- a/alfa-client/libs/vorgang-shared/src/lib/+state/vorgang.reducer.spec.ts
+++ b/alfa-client/libs/vorgang-shared/src/lib/+state/vorgang.reducer.spec.ts
@@ -23,17 +23,11 @@
  */
 import { ApiRootResource } from '@alfa-client/api-root-shared';
 import { BinaryFileListResource } from '@alfa-client/binary-file-shared';
-import {
-  CommandListResource,
-  CommandOrder,
-  CommandResource,
-  CreateCommand,
-} from '@alfa-client/command-shared';
+import { CommandListResource, CommandOrder, CommandResource, CreateCommand } from '@alfa-client/command-shared';
 import { RouteData } from '@alfa-client/navigation-shared';
 import {
   ApiError,
   ApiErrorAction,
-  EMPTY_ARRAY,
   EMPTY_STRING,
   StateResource,
   createEmptyStateResource,
@@ -45,11 +39,7 @@ import { Action } from '@ngrx/store';
 import { Resource, ResourceUri } from '@ngxp/rest';
 import { createApiRootResource } from 'libs/api-root-shared/test/api-root';
 import { createBinaryFileListResource } from 'libs/binary-file-shared/test/binary-file';
-import {
-  createCommand,
-  createCommandListResource,
-  createCommandResource,
-} from 'libs/command-shared/test/command';
+import { createCommand, createCommandListResource, createCommandResource } from 'libs/command-shared/test/command';
 import { createRouteData } from 'libs/navigation-shared/test/navigation-test-factory';
 import { createDummyResource } from 'libs/tech-shared/test/resource';
 import {
@@ -129,9 +119,7 @@ describe('Vorgang Reducer', () => {
         ...createVorgangListResourceWithResource(vorgaenge, [VorgangListLinkRel.NEXT]),
         statistic,
       };
-      const action: VorgangListAction & Action<string> = VorgangActions.loadVorgangListSuccess(
-        { vorgangList },
-      );
+      const action: VorgangListAction & Action<string> = VorgangActions.loadVorgangListSuccess({ vorgangList });
 
       it('should set loaded resource', () => {
         const state: VorgangState = reducer(initialState, action);
@@ -207,10 +195,7 @@ describe('Vorgang Reducer', () => {
       });
 
       it('should add vorgaenge', () => {
-        const state: VorgangState = reducer(
-          { ...initialState, vorgaenge: [createVorgangResource()] },
-          action,
-        );
+        const state: VorgangState = reducer({ ...initialState, vorgaenge: [createVorgangResource()] }, action);
 
         expect(state.vorgaenge.length).toBe(11);
       });
@@ -251,8 +236,7 @@ describe('Vorgang Reducer', () => {
         ...createVorgangListResourceWithResource(vorgaenge),
         statistic,
       };
-      const action: VorgangListAction & Action<string> =
-        VorgangActions.searchVorgaengeBySuccess({ vorgangList });
+      const action: VorgangListAction & Action<string> = VorgangActions.searchVorgaengeBySuccess({ vorgangList });
 
       it('should set vorgangList', () => {
         const state: VorgangState = reducer(initialState, action);
@@ -501,10 +485,7 @@ describe('Vorgang Reducer', () => {
           ...createCommandResource(),
           order: CommandOrder.REDIRECT_VORGANG,
         };
-        const commandList: CommandListResource = createCommandListResource([
-          createCommandResource(),
-          forwardCommand,
-        ]);
+        const commandList: CommandListResource = createCommandListResource([createCommandResource(), forwardCommand]);
         const action = VorgangActions.loadPendingCommandListSuccess({ commandList });
 
         const state: VorgangState = reducer(initialState, action);
@@ -525,9 +506,7 @@ describe('Vorgang Reducer', () => {
 
         const state: VorgangState = reducer(initialState, action);
 
-        expect(state.sendPostfachNachrichtPendingCommand.resource).toBe(
-          sendPostfachNachrichtCommand,
-        );
+        expect(state.sendPostfachNachrichtPendingCommand.resource).toBe(sendPostfachNachrichtCommand);
       });
     });
   });
@@ -545,8 +524,7 @@ describe('Vorgang Reducer', () => {
 
     describe('on "setForwardingSingleCommand" action', () => {
       it('should set forward pending command', () => {
-        const commandStateResource: StateResource<CommandResource> =
-          createStateResource(createCommandResource());
+        const commandStateResource: StateResource<CommandResource> = createStateResource(createCommandResource());
         const action = VorgangActions.setForwardingSingleCommand({ commandStateResource });
 
         const state: VorgangState = reducer(initialState, action);
@@ -569,8 +547,7 @@ describe('Vorgang Reducer', () => {
 
     describe('on "setSendPostfachNachrichtSingleCommand" action', () => {
       it('should set forward pending command', () => {
-        const commandStateResource: StateResource<CommandResource> =
-          createStateResource(createCommandResource());
+        const commandStateResource: StateResource<CommandResource> = createStateResource(createCommandResource());
         const action = VorgangActions.setSendPostfachNachrichtSingleCommand({
           commandStateResource,
         });
@@ -710,10 +687,7 @@ describe('Vorgang Reducer', () => {
           order: CommandOrder.VORGANG_ANNEHMEN,
         };
 
-        const statusCommandMap: StatusCommandMap = Reducer.getStatusCommandMapByCreateCommand(
-          initialState,
-          command,
-        );
+        const statusCommandMap: StatusCommandMap = Reducer.getStatusCommandMapByCreateCommand(initialState, command);
 
         expect(statusCommandMap[command.order].loading).toBeTruthy();
       });
@@ -723,10 +697,7 @@ describe('Vorgang Reducer', () => {
       it('should return state value', () => {
         const command: CommandResource = { ...createCommandResource(), order: 'quatsch' };
 
-        const statusCommandMap: StatusCommandMap = Reducer.getStatusCommandMapByCreateCommand(
-          initialState,
-          command,
-        );
+        const statusCommandMap: StatusCommandMap = Reducer.getStatusCommandMapByCreateCommand(initialState, command);
 
         expect(statusCommandMap).toBe(initialState.statusCommandMap);
       });
@@ -741,8 +712,7 @@ describe('Vorgang Reducer', () => {
           order: CommandOrder.VORGANG_ANNEHMEN,
         };
 
-        const statusCommandMap: StatusCommandMap =
-          Reducer.getStatusCommandMapByCreateCommandSuccess(initialState, command);
+        const statusCommandMap: StatusCommandMap = Reducer.getStatusCommandMapByCreateCommandSuccess(initialState, command);
 
         expect(statusCommandMap[command.order].resource).toBe(command);
       });
@@ -752,8 +722,7 @@ describe('Vorgang Reducer', () => {
       it('should return state value', () => {
         const command: CommandResource = { ...createCommandResource(), order: 'quatsch' };
 
-        const statusCommandMap: StatusCommandMap =
-          Reducer.getStatusCommandMapByCreateCommandSuccess(initialState, command);
+        const statusCommandMap: StatusCommandMap = Reducer.getStatusCommandMapByCreateCommandSuccess(initialState, command);
 
         expect(statusCommandMap).toBe(initialState.statusCommandMap);
       });
@@ -768,8 +737,10 @@ describe('Vorgang Reducer', () => {
           order: CommandOrder.ASSIGN_USER,
         };
 
-        const assignUserCommand: StateResource<CommandResource> =
-          Reducer.getAssignUserCommandByCreateCommand(initialState, command);
+        const assignUserCommand: StateResource<CommandResource> = Reducer.getAssignUserCommandByCreateCommand(
+          initialState,
+          command,
+        );
 
         expect(assignUserCommand.loading).toBeTruthy();
       });
@@ -779,8 +750,10 @@ describe('Vorgang Reducer', () => {
       it('should return state value', () => {
         const command: CommandResource = { ...createCommandResource(), order: 'quatsch' };
 
-        const assignUserCommand: StateResource<CommandResource> =
-          Reducer.getAssignUserCommandByCreateCommand(initialState, command);
+        const assignUserCommand: StateResource<CommandResource> = Reducer.getAssignUserCommandByCreateCommand(
+          initialState,
+          command,
+        );
 
         expect(assignUserCommand).toBe(initialState.assignUserCommand);
       });
@@ -795,8 +768,10 @@ describe('Vorgang Reducer', () => {
           order: CommandOrder.ASSIGN_USER,
         };
 
-        const assignUserCommand: StateResource<CommandResource> =
-          Reducer.getAssignUserCommandByCreateCommandSuccess(initialState, command);
+        const assignUserCommand: StateResource<CommandResource> = Reducer.getAssignUserCommandByCreateCommandSuccess(
+          initialState,
+          command,
+        );
 
         expect(assignUserCommand.resource).toBe(command);
       });
@@ -806,8 +781,10 @@ describe('Vorgang Reducer', () => {
       it('should return state value', () => {
         const command: CommandResource = { ...createCommandResource(), order: 'quatsch' };
 
-        const assignUserCommand: StateResource<CommandResource> =
-          Reducer.getAssignUserCommandByCreateCommandSuccess(initialState, command);
+        const assignUserCommand: StateResource<CommandResource> = Reducer.getAssignUserCommandByCreateCommandSuccess(
+          initialState,
+          command,
+        );
 
         expect(assignUserCommand).toBe(initialState.assignUserCommand);
       });
@@ -881,10 +858,7 @@ describe('Vorgang Reducer', () => {
       it('should clear stateResource', () => {
         const action = VorgangActions.exportVorgangSuccess();
 
-        const state: VorgangState = reducer(
-          { ...initialState, vorgangExport: createEmptyStateResource(true) },
-          action,
-        );
+        const state: VorgangState = reducer({ ...initialState, vorgangExport: createEmptyStateResource(true) }, action);
 
         expect(state.vorgangExport).toEqual(createStateResource(true));
       });
@@ -897,10 +871,7 @@ describe('Vorgang Reducer', () => {
         const action = NavigationActions.updateCurrentRouteData({
           routeData: buildCurrentRouteData('search like me'),
         });
-        const state: VorgangState = reducer(
-          { ...initialState, searchString: 'existingSearchString' },
-          action,
-        );
+        const state: VorgangState = reducer({ ...initialState, searchString: 'existingSearchString' }, action);
 
         expect(state.searchPreviewList.reload).toBeTruthy();
       });
@@ -943,25 +914,18 @@ describe('Vorgang Reducer', () => {
         });
 
         it('should be updated by given vorgangFilter and default view', () => {
-          const urlSegments: UrlSegment[] = [
-            <any>{ path: ROUTE_PARAM_BY_VORGANG_FILTER[VorgangFilter.ALLE] },
-          ];
+          const urlSegments: UrlSegment[] = [<any>{ path: ROUTE_PARAM_BY_VORGANG_FILTER[VorgangFilter.ALLE] }];
           const routeData: RouteData = { ...createRouteData(), urlSegments };
           const localStorageSpy = jest.spyOn(Reducer, 'updateLocalStorage');
 
           Reducer.updateByRouteData(initialState, routeData);
 
-          expect(localStorageSpy).toHaveBeenCalledWith(
-            VorgangFilter.ALLE,
-            VorgangView.VORGANG_LIST,
-          );
+          expect(localStorageSpy).toHaveBeenCalledWith(VorgangFilter.ALLE, VorgangView.VORGANG_LIST);
         });
       });
 
       describe('filter only', () => {
-        const urlSegments: UrlSegment[] = [
-          <any>{ path: ROUTE_PARAM_BY_VORGANG_FILTER[VorgangFilter.ALLE] },
-        ];
+        const urlSegments: UrlSegment[] = [<any>{ path: ROUTE_PARAM_BY_VORGANG_FILTER[VorgangFilter.ALLE] }];
         const routeData: RouteData = { ...createRouteData(), urlSegments };
 
         it('should set reload vorgangList', () => {
@@ -979,9 +943,7 @@ describe('Vorgang Reducer', () => {
         it('should set vorgangFilter', () => {
           const routeData: RouteData = {
             ...createRouteData(),
-            urlSegments: [
-              <any>{ path: ROUTE_PARAM_BY_VORGANG_FILTER[VorgangFilter.MEINE_VORGAENGE] },
-            ],
+            urlSegments: [<any>{ path: ROUTE_PARAM_BY_VORGANG_FILTER[VorgangFilter.MEINE_VORGAENGE] }],
           };
 
           const state: VorgangState = Reducer.updateByRouteData(initialState, routeData);
@@ -992,7 +954,7 @@ describe('Vorgang Reducer', () => {
         it('should clear vorgaenge', () => {
           const state: VorgangState = Reducer.updateByRouteData(initialState, routeData);
 
-          expect(state.vorgaenge).toBe(EMPTY_ARRAY);
+          expect(state.vorgaenge).toEqual([]);
         });
       });
 
@@ -1024,7 +986,7 @@ describe('Vorgang Reducer', () => {
         it('should clear vorgaenge', () => {
           const state: VorgangState = Reducer.updateByRouteData(initialState, routeData);
 
-          expect(state.vorgaenge).toBe(EMPTY_ARRAY);
+          expect(state.vorgaenge).toEqual([]);
         });
       });
     });
@@ -1057,65 +1019,56 @@ describe('Vorgang Reducer', () => {
     describe('vorgangStatistic', () => {
       describe('byStatus', () => {
         it('should have null as neu', () => {
-          const vorgangStatistic: StateResource<VorgangStatistic> =
-            Reducer.initialState.vorgangStatistic;
+          const vorgangStatistic: StateResource<VorgangStatistic> = Reducer.initialState.vorgangStatistic;
 
           expect(vorgangStatistic.resource.byStatus.neu).toBeNull();
         });
 
         it('should have null as angenommen', () => {
-          const vorgangStatistic: StateResource<VorgangStatistic> =
-            Reducer.initialState.vorgangStatistic;
+          const vorgangStatistic: StateResource<VorgangStatistic> = Reducer.initialState.vorgangStatistic;
 
           expect(vorgangStatistic.resource.byStatus.angenommen).toBeNull();
         });
 
         it('should have null as inBearbeitung', () => {
-          const vorgangStatistic: StateResource<VorgangStatistic> =
-            Reducer.initialState.vorgangStatistic;
+          const vorgangStatistic: StateResource<VorgangStatistic> = Reducer.initialState.vorgangStatistic;
 
           expect(vorgangStatistic.resource.byStatus.inBearbeitung).toBeNull();
         });
 
         it('should have null as beschieden', () => {
-          const vorgangStatistic: StateResource<VorgangStatistic> =
-            Reducer.initialState.vorgangStatistic;
+          const vorgangStatistic: StateResource<VorgangStatistic> = Reducer.initialState.vorgangStatistic;
 
           expect(vorgangStatistic.resource.byStatus.beschieden).toBeNull();
         });
 
         it('should have null as abgeschlossen', () => {
-          const vorgangStatistic: StateResource<VorgangStatistic> =
-            Reducer.initialState.vorgangStatistic;
+          const vorgangStatistic: StateResource<VorgangStatistic> = Reducer.initialState.vorgangStatistic;
 
           expect(vorgangStatistic.resource.byStatus.abgeschlossen).toBeNull();
         });
 
         it('should have null as verworfen', () => {
-          const vorgangStatistic: StateResource<VorgangStatistic> =
-            Reducer.initialState.vorgangStatistic;
+          const vorgangStatistic: StateResource<VorgangStatistic> = Reducer.initialState.vorgangStatistic;
 
           expect(vorgangStatistic.resource.byStatus.verworfen).toBeNull();
         });
 
         it('should have null as zuLoeschen', () => {
-          const vorgangStatistic: StateResource<VorgangStatistic> =
-            Reducer.initialState.vorgangStatistic;
+          const vorgangStatistic: StateResource<VorgangStatistic> = Reducer.initialState.vorgangStatistic;
 
           expect(vorgangStatistic.resource.byStatus.zuLoeschen).toBeNull();
         });
       });
 
       it('should have null as wiedervorlagen', () => {
-        const vorgangStatistic: StateResource<VorgangStatistic> =
-          Reducer.initialState.vorgangStatistic;
+        const vorgangStatistic: StateResource<VorgangStatistic> = Reducer.initialState.vorgangStatistic;
 
         expect(vorgangStatistic.resource.wiedervorlagen).toBeNull();
       });
 
       it('should have false as existsWiedervorlageOverdue', () => {
-        const vorgangStatistic: StateResource<VorgangStatistic> =
-          Reducer.initialState.vorgangStatistic;
+        const vorgangStatistic: StateResource<VorgangStatistic> = Reducer.initialState.vorgangStatistic;
 
         expect(vorgangStatistic.resource.existsWiedervorlageOverdue).toBeFalsy();
       });
diff --git a/alfa-client/libs/vorgang-shared/src/lib/+state/vorgang.reducer.ts b/alfa-client/libs/vorgang-shared/src/lib/+state/vorgang.reducer.ts
index 33bc13ea4c0b70755cc6df22869c44eb794af8eb..0f200a551da43386ab80c67938d561a277bed11d 100644
--- a/alfa-client/libs/vorgang-shared/src/lib/+state/vorgang.reducer.ts
+++ b/alfa-client/libs/vorgang-shared/src/lib/+state/vorgang.reducer.ts
@@ -21,15 +21,8 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-import {
-  removeLocalStorageView,
-  setFilterIntoStorage,
-  setViewIntoStorage,
-} from '@alfa-client/app-shared';
-import {
-  BinaryFileListResource,
-  LoadBinaryFileListSuccessProps,
-} from '@alfa-client/binary-file-shared';
+import { removeLocalStorageView, setFilterIntoStorage, setViewIntoStorage } from '@alfa-client/app-shared';
+import { BinaryFileListResource, LoadBinaryFileListSuccessProps } from '@alfa-client/binary-file-shared';
 import {
   CommandOrder,
   CommandProps,
@@ -43,7 +36,6 @@ import {
 import { RouteData } from '@alfa-client/navigation-shared';
 import {
   ApiErrorAction,
-  EMPTY_ARRAY,
   EMPTY_STRING,
   StateResource,
   createEmptyStateResource,
@@ -72,12 +64,7 @@ import {
   VorgangWithEingangResource,
 } from '../vorgang.model';
 import { getVorgaengeFromList, isAssignUserCommand, isStatusCommand } from '../vorgang.util';
-import {
-  HttpErrorAction,
-  StringBasedProps,
-  VorgangListAction,
-  VorgangWithEingangAction,
-} from './vorgang.actions';
+import { HttpErrorAction, StringBasedProps, VorgangListAction, VorgangWithEingangAction } from './vorgang.actions';
 
 import * as CommandActions from '../../../../command-shared/src/lib/+state/command.actions';
 import * as NavigationActions from '../../../../navigation-shared/src/lib/+state/navigation.actions';
@@ -113,7 +100,7 @@ export interface VorgangState {
 export const initialState: VorgangState = {
   vorgangList: createEmptyStateResource(),
   vorgangStatistic: createStateResource(createEmptyVorgangStatistic()),
-  vorgaenge: EMPTY_ARRAY,
+  vorgaenge: [],
   searchString: EMPTY_STRING,
   searchPreviewList: createEmptyStateResource(),
   vorgangView: VorgangView.VORGANG_LIST,
@@ -197,7 +184,7 @@ const vorgangReducer: ActionReducer<VorgangState, Action> = createReducer(
     (state: VorgangState): VorgangState => ({
       ...state,
       vorgangList: { ...state.vorgangList, loading: true },
-      vorgaenge: EMPTY_ARRAY,
+      vorgaenge: [],
       searchPreviewList: createEmptyStateResource(),
     }),
   ),
@@ -215,9 +202,7 @@ const vorgangReducer: ActionReducer<VorgangState, Action> = createReducer(
     VorgangActions.searchVorgaengeByFailure,
     (state: VorgangState, action: HttpErrorAction): VorgangState => ({
       ...state,
-      vorgangList: createErrorStateResource(
-        getApiErrorFromHttpErrorResponse(action.httpErrorResponse),
-      ),
+      vorgangList: createErrorStateResource(getApiErrorFromHttpErrorResponse(action.httpErrorResponse)),
       searchPreviewList: createEmptyStateResource(),
     }),
   ),
@@ -227,10 +212,7 @@ const vorgangReducer: ActionReducer<VorgangState, Action> = createReducer(
     (state: VorgangState, props: StringBasedProps): VorgangState => ({
       ...state,
       searchString: props.string,
-      searchPreviewList:
-        clearPreviewList(props) ?
-          createEmptyStateResource()
-        : { ...state.searchPreviewList, reload: true },
+      searchPreviewList: clearPreviewList(props) ? createEmptyStateResource() : { ...state.searchPreviewList, reload: true },
     }),
   ),
   on(
@@ -251,9 +233,7 @@ const vorgangReducer: ActionReducer<VorgangState, Action> = createReducer(
     VorgangActions.searchForPreviewFailure,
     (state: VorgangState, action: HttpErrorAction): VorgangState => ({
       ...state,
-      searchPreviewList: createErrorStateResource(
-        getApiErrorFromHttpErrorResponse(action.httpErrorResponse),
-      ),
+      searchPreviewList: createErrorStateResource(getApiErrorFromHttpErrorResponse(action.httpErrorResponse)),
     }),
   ),
 
@@ -347,9 +327,7 @@ const vorgangReducer: ActionReducer<VorgangState, Action> = createReducer(
     VorgangActions.loadPendingCommandListSuccess,
     (state: VorgangState, props: LoadCommandListSuccessProps): VorgangState => ({
       ...state,
-      forwardPendingCommand: createStateResource(
-        getPendingCommandByOrder(props.commandList, [CommandOrder.REDIRECT_VORGANG]),
-      ),
+      forwardPendingCommand: createStateResource(getPendingCommandByOrder(props.commandList, [CommandOrder.REDIRECT_VORGANG])),
       sendPostfachNachrichtPendingCommand: createStateResource(
         getPendingCommandByOrder(props.commandList, [CommandOrder.SEND_POSTFACH_NACHRICHT]),
       ),
@@ -420,21 +398,12 @@ const vorgangReducer: ActionReducer<VorgangState, Action> = createReducer(
   on(CommandActions.createCommandSuccess, (state, props: CommandProps): VorgangState => {
     return {
       ...state,
-      statusCommandMap: VorgangReducer.getStatusCommandMapByCreateCommandSuccess(
-        state,
-        props.command,
-      ),
-      assignUserCommand: VorgangReducer.getAssignUserCommandByCreateCommandSuccess(
-        state,
-        props.command,
-      ),
+      statusCommandMap: VorgangReducer.getStatusCommandMapByCreateCommandSuccess(state, props.command),
+      assignUserCommand: VorgangReducer.getAssignUserCommandByCreateCommandSuccess(state, props.command),
       /**
        * @deprecated Das Nachladen des Vorgangs im Service, nach erfolgreicher Beendigung des Commands, durchfuehren
        */
-      vorgangWithEingang: VorgangReducer.getVorgangWithEingangStateResourceByCreateCommandSucces(
-        state,
-        props.command,
-      ),
+      vorgangWithEingang: VorgangReducer.getVorgangWithEingangStateResourceByCreateCommandSucces(state, props.command),
     };
   }),
   on(CommandActions.revokeCommand, (state): VorgangState => {
@@ -483,40 +452,27 @@ export function getVorgangWithEingangStateResourceByCreateCommandSucces(
     : state.vorgangWithEingang;
 }
 
-export function getStatusCommandMapByCreateCommand(
-  state: VorgangState,
-  command: CreateCommand,
-): StatusCommandMap {
+export function getStatusCommandMapByCreateCommand(state: VorgangState, command: CreateCommand): StatusCommandMap {
   return isStatusCommand(command.order) ?
       { ...state.statusCommandMap, [command.order]: createEmptyStateResource(true) }
     : state.statusCommandMap;
 }
 
-export function getStatusCommandMapByCreateCommandSuccess(
-  state: VorgangState,
-  command: CommandResource,
-): StatusCommandMap {
+export function getStatusCommandMapByCreateCommandSuccess(state: VorgangState, command: CommandResource): StatusCommandMap {
   return isStatusCommand(command.order) ?
       { ...state.statusCommandMap, [command.order]: createStateResource(command) }
     : state.statusCommandMap;
 }
 
-export function getAssignUserCommandByCreateCommand(
-  state: VorgangState,
-  command: CreateCommand,
-): StateResource<CommandResource> {
-  return isAssignUserCommand(command.order) ?
-      createEmptyStateResource(true)
-    : state.assignUserCommand;
+export function getAssignUserCommandByCreateCommand(state: VorgangState, command: CreateCommand): StateResource<CommandResource> {
+  return isAssignUserCommand(command.order) ? createEmptyStateResource(true) : state.assignUserCommand;
 }
 
 export function getAssignUserCommandByCreateCommandSuccess(
   state: VorgangState,
   command: CommandResource,
 ): StateResource<CommandResource> {
-  return isAssignUserCommand(command.order) ?
-      createStateResource(command)
-    : state.assignUserCommand;
+  return isAssignUserCommand(command.order) ? createStateResource(command) : state.assignUserCommand;
 }
 
 function clearPreviewList(props: StringBasedProps): boolean {
@@ -527,7 +483,7 @@ export function updateByRouteData(state: VorgangState, routeData: RouteData): Vo
   let newState = {
     ...state,
     vorgangList: { ...state.vorgangList, reload: true },
-    vorgaenge: EMPTY_ARRAY,
+    vorgaenge: [],
   };
 
   if (isUebersichtsSeite(routeData)) {
@@ -539,10 +495,7 @@ export function updateByRouteData(state: VorgangState, routeData: RouteData): Vo
   return newState;
 }
 
-function prepareStateOnVorgangListNavigation(
-  state: VorgangState,
-  routeData: RouteData,
-): VorgangState {
+function prepareStateOnVorgangListNavigation(state: VorgangState, routeData: RouteData): VorgangState {
   let newState: VorgangState = {
     ...state,
     vorgangFilter: getVorgangFilter(routeData),
diff --git a/alfa-client/libs/vorgang-shared/src/lib/vorgang.util.ts b/alfa-client/libs/vorgang-shared/src/lib/vorgang.util.ts
index 64a8f39b55caa29b47c651e43fde340d486902ab..806b5ea58f19c6a646ef6dcbd9a7c41c93b8dbd0 100644
--- a/alfa-client/libs/vorgang-shared/src/lib/vorgang.util.ts
+++ b/alfa-client/libs/vorgang-shared/src/lib/vorgang.util.ts
@@ -22,7 +22,7 @@
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
 import { CommandOrder, CreateCommand } from '@alfa-client/command-shared';
-import { EMPTY_ARRAY, isNotNil } from '@alfa-client/tech-shared';
+import { isNotNil } from '@alfa-client/tech-shared';
 import { ResourceUri, getEmbeddedResource } from '@ngxp/rest';
 import { isNull } from 'lodash-es';
 import { VorgangListLinkRel } from './vorgang.linkrel';
@@ -72,13 +72,10 @@ export function createForwardCommand(redirectRequest: ForwardRequest): CreateFor
 
 export function getVorgaengeFromList(vorgangList: VorgangListResource): VorgangResource[] {
   if (isNotNil(vorgangList)) {
-    const embeddedResource: VorgangResource[] = getEmbeddedResource(
-      vorgangList,
-      VorgangListLinkRel.VORGANG_HEADER_LIST,
-    );
-    return isNull(embeddedResource) ? EMPTY_ARRAY : embeddedResource;
+    const embeddedResource: VorgangResource[] = getEmbeddedResource(vorgangList, VorgangListLinkRel.VORGANG_HEADER_LIST);
+    return isNull(embeddedResource) ? [] : embeddedResource;
   }
-  return EMPTY_ARRAY;
+  return [];
 }
 
 export function createAssignUserCommand(assignedTo: ResourceUri): CreateAssignUserCommand {
diff --git a/alfa-client/libs/zustaendige-stelle-shared/src/lib/externe-fachstelle/externe-fachstelle.service.spec.ts b/alfa-client/libs/zustaendige-stelle-shared/src/lib/externe-fachstelle/externe-fachstelle.service.spec.ts
index 99231c0db52685014185c54da0ccff7f83393525..3c25ba4614aa332c0c79bddb04206cbb740ee7fc 100644
--- a/alfa-client/libs/zustaendige-stelle-shared/src/lib/externe-fachstelle/externe-fachstelle.service.spec.ts
+++ b/alfa-client/libs/zustaendige-stelle-shared/src/lib/externe-fachstelle/externe-fachstelle.service.spec.ts
@@ -21,7 +21,7 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-import { EMPTY_ARRAY, StateResource, createStateResource } from '@alfa-client/tech-shared';
+import { StateResource, createStateResource } from '@alfa-client/tech-shared';
 import { Mock, mock, useFromMock } from '@alfa-client/test-utils';
 import { faker } from '@faker-js/faker';
 import { InstantSearchResult } from '@ods/system';
@@ -111,7 +111,7 @@ describe('ExterneFachstelleService', () => {
         createStateResource(createEmptyListResource<ExterneFachstelleListResource>()),
       );
 
-      expect(result).toEqual(EMPTY_ARRAY);
+      expect(result).toEqual([]);
     });
   });
 
diff --git a/alfa-client/libs/zustaendige-stelle-shared/src/lib/externe-fachstelle/externe-fachstelle.service.ts b/alfa-client/libs/zustaendige-stelle-shared/src/lib/externe-fachstelle/externe-fachstelle.service.ts
index 6c9493c8266927d9a99517855ee5f1568ae129ed..50e3c315d376590df9cf2c20be7e9b68fa29213a 100644
--- a/alfa-client/libs/zustaendige-stelle-shared/src/lib/externe-fachstelle/externe-fachstelle.service.ts
+++ b/alfa-client/libs/zustaendige-stelle-shared/src/lib/externe-fachstelle/externe-fachstelle.service.ts
@@ -21,7 +21,7 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-import { EMPTY_ARRAY, getEmbeddedResources, StateResource } from '@alfa-client/tech-shared';
+import { getEmbeddedResources, StateResource } from '@alfa-client/tech-shared';
 import { Injectable } from '@angular/core';
 import { InstantSearchResult } from '@ods/system';
 import { isNull } from 'lodash-es';
@@ -60,7 +60,7 @@ export class ExterneFachstelleService implements ZustaendigeStelleService<Extern
       externeFachstelleStateListResource,
       ExterneFachstelleListLinkRel.EXTERNE_FACHSTELLE_LIST,
     );
-    return isNull(resources) ? EMPTY_ARRAY : resources;
+    return isNull(resources) ? [] : resources;
   }
 
   mapToInstantSearchResult(externeFachstelle: ExterneFachstelleResource): InstantSearchResult<ExterneFachstelleResource> {
diff --git a/alfa-client/libs/zustaendige-stelle-shared/src/lib/organisations-einheit/organisations-einheit.service.spec.ts b/alfa-client/libs/zustaendige-stelle-shared/src/lib/organisations-einheit/organisations-einheit.service.spec.ts
index 87e9bbd0b160907d93887c58f48af63d576c0fd5..6c994b351bfe3c6dc4212a5b52f807c5ff536e47 100644
--- a/alfa-client/libs/zustaendige-stelle-shared/src/lib/organisations-einheit/organisations-einheit.service.spec.ts
+++ b/alfa-client/libs/zustaendige-stelle-shared/src/lib/organisations-einheit/organisations-einheit.service.spec.ts
@@ -21,7 +21,7 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-import { EMPTY_ARRAY, ResourceSearchService, StateResource, createStateResource } from '@alfa-client/tech-shared';
+import { ResourceSearchService, StateResource, createStateResource } from '@alfa-client/tech-shared';
 import { Mock, mock, useFromMock } from '@alfa-client/test-utils';
 import { faker } from '@faker-js/faker';
 import { Resource } from '@ngxp/rest';
@@ -109,7 +109,7 @@ describe('OrganisationsEinheitService', () => {
         createStateResource(createEmptyListResource<OrganisationsEinheitListResource>()),
       );
 
-      expect(result).toEqual(EMPTY_ARRAY);
+      expect(result).toEqual([]);
     });
   });
 
diff --git a/alfa-client/libs/zustaendige-stelle-shared/src/lib/organisations-einheit/organisations-einheit.service.ts b/alfa-client/libs/zustaendige-stelle-shared/src/lib/organisations-einheit/organisations-einheit.service.ts
index 578a5ad04f1a4800ac0d2133c2403818d23acb5b..b3c4fe94f7b2e14a9c69cfb8ecf550579e33bc5c 100644
--- a/alfa-client/libs/zustaendige-stelle-shared/src/lib/organisations-einheit/organisations-einheit.service.ts
+++ b/alfa-client/libs/zustaendige-stelle-shared/src/lib/organisations-einheit/organisations-einheit.service.ts
@@ -21,7 +21,7 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-import { EMPTY_ARRAY, getEmbeddedResources, ResourceSearchService, StateResource } from '@alfa-client/tech-shared';
+import { getEmbeddedResources, ResourceSearchService, StateResource } from '@alfa-client/tech-shared';
 import { Resource } from '@ngxp/rest';
 import { InstantSearchResult } from '@ods/system';
 import { isNull } from 'lodash-es';
@@ -64,7 +64,7 @@ export class OrganisationsEinheitService implements ZustaendigeStelleService<Org
       organisationsEinheitStateListResource,
       OrganisationsEinheitListLinkRel.ORGANISATIONS_EINHEIT_HEADER_LIST,
     );
-    return isNull(resources) ? EMPTY_ARRAY : resources;
+    return isNull(resources) ? [] : resources;
   }
 
   mapToInstantSearchResult(zustaendigeStelle: OrganisationsEinheitResource): InstantSearchResult<OrganisationsEinheitResource> {
diff --git a/alfa-client/package.json b/alfa-client/package.json
index 56791618d048e514e34de89a49233389e0a988c4..d6a7bffddc6984305f4bc77149fa653d2083dfd3 100644
--- a/alfa-client/package.json
+++ b/alfa-client/package.json
@@ -175,4 +175,4 @@
     "@rollup/rollup-linux-x64-gnu": "*"
   },
   "packageManager": "pnpm@9.15.0"
-}
\ No newline at end of file
+}
diff --git a/alfa-client/pnpm-lock.yaml b/alfa-client/pnpm-lock.yaml
index f875d36ba7bae2db40b66c5570722a489edb5300..c447ee766cd2cdc982a9fcdb64d528ddd73d27e5 100644
--- a/alfa-client/pnpm-lock.yaml
+++ b/alfa-client/pnpm-lock.yaml
@@ -4016,6 +4016,10 @@ packages:
     resolution: {integrity: sha512-XsGWww0odcUT0gJoBZ1DeulY1+jkaHUciUq4jKNv4cpInbvvrtDoyBH9rE/n2V29wQJPk8iCH1wipra9BhmiMA==}
     engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
 
+  '@typescript-eslint/scope-manager@8.24.0':
+    resolution: {integrity: sha512-HZIX0UByphEtdVBKaQBgTDdn9z16l4aTUz8e8zPQnyxwHBtf5vtl1L+OhH+m1FGV9DrRmoDuYKqzVrvWDcDozw==}
+    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
   '@typescript-eslint/type-utils@7.18.0':
     resolution: {integrity: sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==}
     engines: {node: ^18.18.0 || >=20.0.0}
@@ -4043,6 +4047,10 @@ packages:
     resolution: {integrity: sha512-4cyFErJetFLckcThRUFdReWJjVsPCqyBlJTi6IDEpc1GWCIIZRFxVppjWLIMcQhNGhdWJJRYFHpHoDWvMlDzng==}
     engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
 
+  '@typescript-eslint/types@8.24.0':
+    resolution: {integrity: sha512-VacJCBTyje7HGAw7xp11q439A+zeGG0p0/p2zsZwpnMzjPB5WteaWqt4g2iysgGFafrqvyLWqq6ZPZAOCoefCw==}
+    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
   '@typescript-eslint/typescript-estree@7.18.0':
     resolution: {integrity: sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==}
     engines: {node: ^18.18.0 || >=20.0.0}
@@ -4061,6 +4069,12 @@ packages:
       typescript:
         optional: true
 
+  '@typescript-eslint/typescript-estree@8.24.0':
+    resolution: {integrity: sha512-ITjYcP0+8kbsvT9bysygfIfb+hBj6koDsu37JZG7xrCiy3fPJyNmfVtaGsgTUSEuTzcvME5YI5uyL5LD1EV5ZQ==}
+    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+    peerDependencies:
+      typescript: '>=4.8.4 <5.8.0'
+
   '@typescript-eslint/utils@7.18.0':
     resolution: {integrity: sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==}
     engines: {node: ^18.18.0 || >=20.0.0}
@@ -4073,6 +4087,13 @@ packages:
     peerDependencies:
       eslint: ^8.57.0 || ^9.0.0
 
+  '@typescript-eslint/utils@8.24.0':
+    resolution: {integrity: sha512-07rLuUBElvvEb1ICnafYWr4hk8/U7X9RDCOqd9JcAMtjh/9oRmcfN4yGzbPVirgMR0+HLVHehmu19CWeh7fsmQ==}
+    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+    peerDependencies:
+      eslint: ^8.57.0 || ^9.0.0
+      typescript: '>=4.8.4 <5.8.0'
+
   '@typescript-eslint/visitor-keys@7.18.0':
     resolution: {integrity: sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==}
     engines: {node: ^18.18.0 || >=20.0.0}
@@ -4081,8 +4102,12 @@ packages:
     resolution: {integrity: sha512-7N/+lztJqH4Mrf0lb10R/CbI1EaAMMGyF5y0oJvFoAhafwgiRA7TXyd8TFn8FC8k5y2dTsYogg238qavRGNnlw==}
     engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
 
-  '@ungap/structured-clone@1.2.1':
-    resolution: {integrity: sha512-fEzPV3hSkSMltkw152tJKNARhOupqbH96MZWyRjNaYZOMIzbrTeQDG+MTc6Mr2pgzFQzFxAfmhGDNP5QK++2ZA==}
+  '@typescript-eslint/visitor-keys@8.24.0':
+    resolution: {integrity: sha512-kArLq83QxGLbuHrTMoOEWO+l2MwsNS2TGISEdx8xgqpkbytB07XmlQyQdNDrCc1ecSqx0cnmhGvpX+VBwqqSkg==}
+    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+  '@ungap/structured-clone@1.3.0':
+    resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==}
 
   '@vitejs/plugin-basic-ssl@1.1.0':
     resolution: {integrity: sha512-wO4Dk/rm8u7RNhOf95ZzcEmC9rYOncYgvq4z3duaJrCgjN8BxAnDVyndanfcJZ0O6XZzHz6Q0hTimxTg8Y9g/A==}
@@ -5855,6 +5880,10 @@ packages:
     resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
 
+  eslint-visitor-keys@4.2.0:
+    resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==}
+    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
   eslint@8.57.0:
     resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -9690,6 +9719,12 @@ packages:
     peerDependencies:
       typescript: '>=4.2.0'
 
+  ts-api-utils@2.0.1:
+    resolution: {integrity: sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w==}
+    engines: {node: '>=18.12'}
+    peerDependencies:
+      typescript: '>=4.8.4'
+
   ts-dedent@2.2.0:
     resolution: {integrity: sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==}
     engines: {node: '>=6.10'}
@@ -14290,7 +14325,7 @@ snapshots:
       '@nx/js': 19.8.8(@babel/traverse@7.25.9)(@swc-node/register@1.9.2(@swc/core@1.5.29(@swc/helpers@0.5.13))(@swc/types@0.1.17)(typescript@5.5.4))(@swc/core@1.5.29(@swc/helpers@0.5.13))(@types/node@20.17.6)(nx@19.8.8(@swc-node/register@1.9.2(@swc/core@1.5.29(@swc/helpers@0.5.13))(@swc/types@0.1.17)(typescript@5.5.4))(@swc/core@1.5.29(@swc/helpers@0.5.13)))(typescript@5.5.4)
       '@typescript-eslint/parser': 7.18.0(eslint@8.57.0)(typescript@5.5.4)
       '@typescript-eslint/type-utils': 8.13.0(eslint@8.57.0)(typescript@5.5.4)
-      '@typescript-eslint/utils': 8.13.0(eslint@8.57.0)(typescript@5.5.4)
+      '@typescript-eslint/utils': 8.24.0(eslint@8.57.0)(typescript@5.5.4)
       chalk: 4.1.2
       confusing-browser-globals: 1.0.11
       globals: 15.12.0
@@ -15946,6 +15981,11 @@ snapshots:
       '@typescript-eslint/types': 8.13.0
       '@typescript-eslint/visitor-keys': 8.13.0
 
+  '@typescript-eslint/scope-manager@8.24.0':
+    dependencies:
+      '@typescript-eslint/types': 8.24.0
+      '@typescript-eslint/visitor-keys': 8.24.0
+
   '@typescript-eslint/type-utils@7.18.0(eslint@8.57.0)(typescript@5.5.4)':
     dependencies:
       '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.5.4)
@@ -15974,6 +16014,8 @@ snapshots:
 
   '@typescript-eslint/types@8.13.0': {}
 
+  '@typescript-eslint/types@8.24.0': {}
+
   '@typescript-eslint/typescript-estree@7.18.0(typescript@5.5.4)':
     dependencies:
       '@typescript-eslint/types': 7.18.0
@@ -16004,6 +16046,20 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
+  '@typescript-eslint/typescript-estree@8.24.0(typescript@5.5.4)':
+    dependencies:
+      '@typescript-eslint/types': 8.24.0
+      '@typescript-eslint/visitor-keys': 8.24.0
+      debug: 4.3.7(supports-color@8.1.1)
+      fast-glob: 3.3.2
+      is-glob: 4.0.3
+      minimatch: 9.0.5
+      semver: 7.6.3
+      ts-api-utils: 2.0.1(typescript@5.5.4)
+      typescript: 5.5.4
+    transitivePeerDependencies:
+      - supports-color
+
   '@typescript-eslint/utils@7.18.0(eslint@8.57.0)(typescript@5.5.4)':
     dependencies:
       '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.0)
@@ -16026,6 +16082,17 @@ snapshots:
       - supports-color
       - typescript
 
+  '@typescript-eslint/utils@8.24.0(eslint@8.57.0)(typescript@5.5.4)':
+    dependencies:
+      '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.0)
+      '@typescript-eslint/scope-manager': 8.24.0
+      '@typescript-eslint/types': 8.24.0
+      '@typescript-eslint/typescript-estree': 8.24.0(typescript@5.5.4)
+      eslint: 8.57.0
+      typescript: 5.5.4
+    transitivePeerDependencies:
+      - supports-color
+
   '@typescript-eslint/visitor-keys@7.18.0':
     dependencies:
       '@typescript-eslint/types': 7.18.0
@@ -16036,7 +16103,12 @@ snapshots:
       '@typescript-eslint/types': 8.13.0
       eslint-visitor-keys: 3.4.3
 
-  '@ungap/structured-clone@1.2.1': {}
+  '@typescript-eslint/visitor-keys@8.24.0':
+    dependencies:
+      '@typescript-eslint/types': 8.24.0
+      eslint-visitor-keys: 4.2.0
+
+  '@ungap/structured-clone@1.3.0': {}
 
   '@vitejs/plugin-basic-ssl@1.1.0(vite@5.4.6(@types/node@20.17.6)(less@4.2.0)(sass@1.77.6)(stylus@0.59.0)(terser@5.31.6))':
     dependencies:
@@ -18141,6 +18213,8 @@ snapshots:
 
   eslint-visitor-keys@3.4.3: {}
 
+  eslint-visitor-keys@4.2.0: {}
+
   eslint@8.57.0:
     dependencies:
       '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.0)
@@ -18150,7 +18224,7 @@ snapshots:
       '@humanwhocodes/config-array': 0.11.14
       '@humanwhocodes/module-importer': 1.0.1
       '@nodelib/fs.walk': 1.2.8
-      '@ungap/structured-clone': 1.2.1
+      '@ungap/structured-clone': 1.3.0
       ajv: 6.12.6
       chalk: 4.1.2
       cross-spawn: 7.0.6
@@ -22722,6 +22796,10 @@ snapshots:
     dependencies:
       typescript: 5.5.4
 
+  ts-api-utils@2.0.1(typescript@5.5.4):
+    dependencies:
+      typescript: 5.5.4
+
   ts-dedent@2.2.0: {}
 
   ts-interface-checker@0.1.13: {}