diff --git a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-status-text/vorgang-status-text.component.html b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-status-text/vorgang-status-text.component.html
index f6a1ebd55e0db35ad39e55888ecca1d511452bc1..696169f3474d0aacf9feb45c554a25d291b979fd 100644
--- a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-status-text/vorgang-status-text.component.html
+++ b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-status-text/vorgang-status-text.component.html
@@ -24,5 +24,5 @@
 
 -->
 <div class="status-name text-sm" data-test-id="vorgang-status-text">
-  {{ status }}
+  {{ status | enumToLabel: vorgangStatusLabel }}
 </div>
diff --git a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-status-text/vorgang-status-text.component.spec.ts b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-status-text/vorgang-status-text.component.spec.ts
index 15774e62da602caa5cf4f474762e6464a245dfb9..31b6f8e0de9bc3cfa18c45e1ad5860f747589982 100644
--- a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-status-text/vorgang-status-text.component.spec.ts
+++ b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-status-text/vorgang-status-text.component.spec.ts
@@ -21,19 +21,23 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
+import { EnumToLabelPipe } from '@alfa-client/tech-shared';
+import { VorgangResource, VorgangStatusLabel } from '@alfa-client/vorgang-shared';
 import { ComponentFixture, TestBed } from '@angular/core/testing';
 import { getDataTestIdOf } from 'libs/tech-shared/test/data-test';
+import { createVorgangResource } from 'libs/vorgang-shared/test/vorgang';
 import { VorgangStatusTextComponent } from './vorgang-status-text.component';
 
 describe('VorgangStatusTextComponent', () => {
   let component: VorgangStatusTextComponent;
   let fixture: ComponentFixture<VorgangStatusTextComponent>;
 
+  const vorgang: VorgangResource = createVorgangResource();
   const statusTextTestId: string = getDataTestIdOf('vorgang-status-text');
 
   beforeEach(async () => {
     await TestBed.configureTestingModule({
-      declarations: [VorgangStatusTextComponent],
+      declarations: [EnumToLabelPipe, VorgangStatusTextComponent],
     }).compileComponents();
   });
 
@@ -48,11 +52,12 @@ describe('VorgangStatusTextComponent', () => {
   });
 
   it('should show status text', () => {
-    component.status = 'Neu';
+    component.status = vorgang.status;
+    const statusText: string = VorgangStatusLabel[vorgang.status];
 
     fixture.detectChanges();
     const statusTextElement: HTMLElement = fixture.nativeElement.querySelector(statusTextTestId);
 
-    expect(statusTextElement.innerHTML).toContain('Neu');
+    expect(statusTextElement.innerHTML).toContain(statusText);
   });
 });
diff --git a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-status-text/vorgang-status-text.component.ts b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-status-text/vorgang-status-text.component.ts
index de4e772d0b94942199e6bdd381077201de758b46..a1c90fd8afdb3114a17086f359b36ee5110a4f42 100644
--- a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-status-text/vorgang-status-text.component.ts
+++ b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-status-text/vorgang-status-text.component.ts
@@ -21,6 +21,7 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
+import { VorgangStatus, VorgangStatusLabel } from '@alfa-client/vorgang-shared';
 import { Component, Input } from '@angular/core';
 
 @Component({
@@ -29,5 +30,6 @@ import { Component, Input } from '@angular/core';
   styleUrls: ['./vorgang-status-text.component.scss'],
 })
 export class VorgangStatusTextComponent {
-  @Input() status: string;
+  @Input() status: VorgangStatus;
+  readonly vorgangStatusLabel = VorgangStatusLabel;
 }
diff --git a/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-list-item.component.html b/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-list-item.component.html
index d7faafb103e54a0b4abc767e586bec558d2a5982..228c9808d45c6f5b81e47b178e21cfe28e4fe01c 100644
--- a/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-list-item.component.html
+++ b/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-list-item.component.html
@@ -38,7 +38,7 @@
         data-test-class="status-dot"
       ></alfa-vorgang-status-dot>
       <alfa-vorgang-status-text
-        [status]="status"
+        [status]="vorgang.status"
         data-test-class="status-text"
         class="status-text"
       ></alfa-vorgang-status-text>
diff --git a/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-list-item.component.spec.ts b/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-list-item.component.spec.ts
index 0c9700bd02d85554970bdcad3706bd6f808c8e3b..6015354498a4860c7c4bfabd7feb57ce2f9c7a93 100644
--- a/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-list-item.component.spec.ts
+++ b/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-list-item.component.spec.ts
@@ -22,9 +22,8 @@
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
 import {
-  convertForDataTest,
   ConvertForDataTestPipe,
-  createEmptyStateResource,
+  createStateResource,
   EnumToLabelPipe,
   HasLinkPipe,
   ToResourceUriPipe,
@@ -32,7 +31,7 @@ import {
 import { getElementFromFixture, mock } from '@alfa-client/test-utils';
 import { PostfachIconComponent } from '@alfa-client/ui';
 import { UserProfileInVorgangListItemContainerComponent } from '@alfa-client/user-profile';
-import { UserProfileService } from '@alfa-client/user-profile-shared';
+import { UserProfileResource, UserProfileService } from '@alfa-client/user-profile-shared';
 import { VorgangHeaderLinkRel, VorgangStatus } from '@alfa-client/vorgang-shared';
 import {
   AktenzeichenComponent,
@@ -52,6 +51,7 @@ import { MatIconTestingModule } from '@angular/material/icon/testing';
 import { MatTooltipModule } from '@angular/material/tooltip';
 import { RouterTestingModule } from '@angular/router/testing';
 import { getDataTestClassOf, getDataTestIdOf } from 'libs/tech-shared/test/data-test';
+import { createUserProfileResource } from 'libs/user-profile-shared/test/user-profile';
 import { createVorgangResource } from 'libs/vorgang-shared/test/vorgang';
 import { MockComponent, MockModule } from 'ng-mocks';
 import { of } from 'rxjs';
@@ -72,6 +72,8 @@ describe('VorgangListItemComponent', () => {
   const postfachStatus: string = getDataTestClassOf('postfach-icon');
   const bescheidStatus: string = getDataTestIdOf('vorgang-list-item-bescheid-status');
 
+  const userProfile: UserProfileResource = createUserProfileResource();
+
   beforeEach(async () => {
     await TestBed.configureTestingModule({
       imports: [RouterTestingModule, MatIconTestingModule],
@@ -114,43 +116,47 @@ describe('VorgangListItemComponent', () => {
   });
 
   describe('ngOnInit', () => {
-    it('should set status', () => {
-      component.getStatus = jest.fn().mockReturnValue('Test');
-
-      component.ngOnInit();
-
-      expect(component.status).toBe('Test');
-    });
-
-    it('should build aria label', () => {
-      component.buildAriaLabel = jest.fn();
-
-      component.ngOnInit();
-
-      expect(component.buildAriaLabel).toHaveBeenCalled();
-    });
-
     describe('user profile', () => {
       beforeEach(() => {
+        component.buildAriaLabel = jest.fn();
         component.userProfileService.getAssignedUserProfile = jest
           .fn()
-          .mockReturnValue(of(createEmptyStateResource()));
+          .mockReturnValue(of(createStateResource(userProfile)));
       });
 
-      it('should not get profile if vorgang has no "assigned to" link', () => {
-        component.vorgang = createVorgangResource();
+      describe('vorgang has no "assigned to" link', () => {
+        beforeEach(() => {
+          component.vorgang = createVorgangResource();
+        });
+        it('should not get profile', () => {
+          component.ngOnInit();
+
+          expect(component.userProfileService.getAssignedUserProfile).not.toHaveBeenCalled();
+        });
 
-        component.ngOnInit();
+        it('should build aria label without user profile resource', () => {
+          component.ngOnInit();
 
-        expect(component.userProfileService.getAssignedUserProfile).not.toHaveBeenCalled();
+          expect(component.buildAriaLabel).toHaveBeenCalledWith();
+        });
       });
 
-      it('should get profile', () => {
-        component.vorgang = createVorgangResource([VorgangHeaderLinkRel.ASSIGNED_TO]);
+      describe('vorgang has "assigned to" link', () => {
+        beforeEach(() => {
+          component.vorgang = createVorgangResource([VorgangHeaderLinkRel.ASSIGNED_TO]);
+        });
+
+        it('should get profile', () => {
+          component.ngOnInit();
+
+          expect(component.userProfileService.getAssignedUserProfile).toHaveBeenCalled();
+        });
 
-        component.ngOnInit();
+        it('should build aria label with user profile resource', () => {
+          component.ngOnInit();
 
-        expect(component.userProfileService.getAssignedUserProfile).toHaveBeenCalled();
+          expect(component.buildAriaLabel).toHaveBeenCalledWith(userProfile);
+        });
       });
     });
   });
@@ -178,142 +184,166 @@ describe('VorgangListItemComponent', () => {
     });
   });
 
-  describe('Aria label', () => {
-    it('should contain Wiedervorlage', () => {
+  describe('mail icon', () => {
+    beforeEach(() => {
       component.vorgang = createVorgangResource([
         VorgangHeaderLinkRel.VORGANG_WITH_EINGANG,
-        VorgangHeaderLinkRel.WIEDERVORLAGEN,
+        VorgangHeaderLinkRel.POSTFACH_MAILS,
       ]);
-      const listItem: string = getDataTestIdOf(
-        `vorgang-list-item-${convertForDataTest(component.vorgang.name)}`,
-      );
-      component.ngOnInit();
+    });
+
+    it('should show mail icon if Vorgang has new Postfachnachricht', () => {
+      component.vorgang.hasPostfachNachricht = true;
       fixture.detectChanges();
 
-      const element: HTMLDivElement = fixture.nativeElement.querySelector(listItem);
-      const ariaLabel: string = element.getAttribute('aria-label');
+      const statusElement = getElementFromFixture(fixture, postfachStatus);
 
-      expect(ariaLabel).toContain('Wiedervorlage');
+      expect(statusElement).toBeInstanceOf(HTMLElement);
     });
 
-    it('should not contain Wiedervorlage if no nextFrist but LinkRel.WIEDERVORLAGEN', () => {
-      component.vorgang = {
-        ...createVorgangResource([
-          VorgangHeaderLinkRel.VORGANG_WITH_EINGANG,
-          VorgangHeaderLinkRel.WIEDERVORLAGEN,
-        ]),
-        nextFrist: null,
-      };
-      const listItem: string = getDataTestIdOf(
-        `vorgang-list-item-${convertForDataTest(component.vorgang.name)}`,
-      );
-      component.ngOnInit();
+    it('should not show mail icon if Vorgang has no new Postfachnachricht', () => {
+      component.vorgang.hasPostfachNachricht = false;
       fixture.detectChanges();
 
-      const element: HTMLDivElement = fixture.nativeElement.querySelector(listItem);
-      const ariaLabel: string = element.getAttribute('aria-label');
+      const statusElement = getElementFromFixture(fixture, postfachStatus);
 
-      expect(ariaLabel).not.toContain('Wiedervorlage');
+      expect(statusElement).not.toBeInstanceOf(HTMLElement);
     });
+  });
 
-    it('should not contain Wiedervorlage if no LinkRel.WIEDERVORLAGEN', () => {
-      component.vorgang = createVorgangResource([VorgangHeaderLinkRel.VORGANG_WITH_EINGANG]);
-      const listItem: string = getDataTestIdOf(
-        `vorgang-list-item-${convertForDataTest(component.vorgang.name)}`,
-      );
-      component.ngOnInit();
+  describe('Bescheid-Status', () => {
+    it('should show bescheid status if Vorgang has antragBewilligt true', () => {
+      component.vorgang.antragBewilligt = true;
       fixture.detectChanges();
 
-      const element: HTMLDivElement = fixture.nativeElement.querySelector(listItem);
-      const ariaLabel: string = element.getAttribute('aria-label');
+      const element = getElementFromFixture(fixture, bescheidStatus);
 
-      expect(ariaLabel).not.toContain('Wiedervorlage');
+      expect(element).toBeInstanceOf(HTMLElement);
     });
 
-    it('should contain hasPostfachnachricht text if vorgang has Postfachnachricht', () => {
-      component.vorgang.hasPostfachNachricht = true;
-      component.vorgang.hasNewPostfachNachricht = false;
-      const listItem: string = getDataTestIdOf(
-        `vorgang-list-item-${convertForDataTest(component.vorgang.name)}`,
-      );
-      component.ngOnInit();
+    it('should show bescheid status if Vorgang has antragBewilligt false', () => {
+      component.vorgang.antragBewilligt = false;
       fixture.detectChanges();
 
-      const element: HTMLDivElement = fixture.nativeElement.querySelector(listItem);
-      const ariaLabel: string = element.getAttribute('aria-label');
+      const element = getElementFromFixture(fixture, bescheidStatus);
 
-      expect(ariaLabel).toContain('enthält Postfachnachrichten');
+      expect(element).toBeInstanceOf(HTMLElement);
     });
 
-    it('should contain hasNewPostfachnachricht text if vorgang has new Postfachnachricht', () => {
-      component.vorgang.hasPostfachNachricht = true;
-      component.vorgang.hasNewPostfachNachricht = true;
-      const listItem: string = getDataTestIdOf(
-        `vorgang-list-item-${convertForDataTest(component.vorgang.name)}`,
-      );
-      component.ngOnInit();
+    it('should not show bescheid status if Vorgang has no antragBewilligt', () => {
+      component.vorgang.antragBewilligt = null;
       fixture.detectChanges();
 
-      const element: HTMLDivElement = fixture.nativeElement.querySelector(listItem);
-      const ariaLabel: string = element.getAttribute('aria-label');
+      const element = getElementFromFixture(fixture, bescheidStatus);
 
-      expect(ariaLabel).toContain('enthält neue Postfachnachrichten');
+      expect(element).not.toBeInstanceOf(HTMLElement);
     });
   });
 
-  describe('mail icon', () => {
+  describe('buildAriaLabel', () => {
     beforeEach(() => {
+      component.getWiedervorlageText = jest.fn();
+      component.getPostfachNachricht = jest.fn();
+    });
+    it('should get status', () => {
+      component.getStatus = jest.fn();
+
+      component.buildAriaLabel();
+
+      expect(component.getStatus).toHaveBeenCalled();
+    });
+
+    it('should get approval text', () => {
+      component.getApprovalText = jest.fn();
+
+      component.buildAriaLabel();
+
+      expect(component.getApprovalText).toHaveBeenCalled();
+    });
+
+    it('should get user text', () => {
+      component.getUserText = jest.fn();
+
+      component.buildAriaLabel(userProfile);
+
+      expect(component.getUserText).toHaveBeenCalledWith(userProfile);
+    });
+
+    it('should get Wiedervorlage', () => {
       component.vorgang = createVorgangResource([
         VorgangHeaderLinkRel.VORGANG_WITH_EINGANG,
-        VorgangHeaderLinkRel.POSTFACH_MAILS,
+        VorgangHeaderLinkRel.WIEDERVORLAGEN,
       ]);
+
+      component.buildAriaLabel();
+
+      expect(component.getWiedervorlageText).toHaveBeenCalled();
     });
 
-    it('should show mail icon if Vorgang has new Postfachnachricht', () => {
+    it('should not get Wiedervorlage if no nextFrist but LinkRel.WIEDERVORLAGEN', () => {
+      component.vorgang = {
+        ...createVorgangResource([
+          VorgangHeaderLinkRel.VORGANG_WITH_EINGANG,
+          VorgangHeaderLinkRel.WIEDERVORLAGEN,
+        ]),
+        nextFrist: null,
+      };
+
+      component.buildAriaLabel();
+
+      expect(component.getWiedervorlageText).not.toHaveBeenCalled();
+    });
+
+    it('should not get Wiedervorlage if no LinkRel.WIEDERVORLAGEN', () => {
+      component.vorgang = createVorgangResource([VorgangHeaderLinkRel.VORGANG_WITH_EINGANG]);
+
+      component.buildAriaLabel();
+
+      expect(component.getWiedervorlageText).not.toHaveBeenCalled();
+    });
+
+    it('should get message text if vorgang has message', () => {
       component.vorgang.hasPostfachNachricht = true;
-      fixture.detectChanges();
 
-      const statusElement = getElementFromFixture(fixture, postfachStatus);
+      component.buildAriaLabel();
 
-      expect(statusElement).toBeInstanceOf(HTMLElement);
+      expect(component.getPostfachNachricht).toHaveBeenCalled();
     });
 
-    it('should not show mail icon if Vorgang has no new Postfachnachricht', () => {
+    it('should not get message text if vorgang has no messages', () => {
       component.vorgang.hasPostfachNachricht = false;
-      fixture.detectChanges();
 
-      const statusElement = getElementFromFixture(fixture, postfachStatus);
+      component.buildAriaLabel();
 
-      expect(statusElement).not.toBeInstanceOf(HTMLElement);
+      expect(component.getPostfachNachricht).not.toHaveBeenCalled();
     });
   });
 
-  describe('Bescheid-Status', () => {
-    it('should show bescheid status if Vorgang has antragBewilligt true', () => {
-      component.vorgang.antragBewilligt = true;
-      fixture.detectChanges();
+  describe('getWiedervorlageText', () => {
+    it('should return text for next resubmission', () => {
+      component.vorgang.nextFrist = new Date('07.02.1977');
 
-      const element = getElementFromFixture(fixture, bescheidStatus);
+      const result: string = component.getWiedervorlageText();
 
-      expect(element).toBeInstanceOf(HTMLElement);
+      expect(result).toBe(', Nächste Wiedervorlage am 02.07.1977');
     });
+  });
 
-    it('should show bescheid status if Vorgang has antragBewilligt false', () => {
-      component.vorgang.antragBewilligt = false;
-      fixture.detectChanges();
+  describe('getPostfachNachricht', () => {
+    it('should return "contains new messages"', () => {
+      component.vorgang.hasNewPostfachNachricht = true;
 
-      const element = getElementFromFixture(fixture, bescheidStatus);
+      const result: string = component.getPostfachNachricht();
 
-      expect(element).toBeInstanceOf(HTMLElement);
+      expect(result).toBe(', enthält neue Postfachnachrichten');
     });
 
-    it('should not show bescheid status if Vorgang has no antragBewilligt', () => {
-      component.vorgang.antragBewilligt = null;
-      fixture.detectChanges();
+    it('should return "contains messages"', () => {
+      component.vorgang.hasNewPostfachNachricht = false;
 
-      const element = getElementFromFixture(fixture, bescheidStatus);
+      const result: string = component.getPostfachNachricht();
 
-      expect(element).not.toBeInstanceOf(HTMLElement);
+      expect(result).toBe(', enthält Postfachnachrichten');
     });
   });
 
@@ -352,4 +382,20 @@ describe('VorgangListItemComponent', () => {
       expect(result).toBe('abgelehnt');
     });
   });
+
+  describe('getUserText', () => {
+    it('should return no assigned user text', () => {
+      const result: string = component.getUserText(undefined);
+
+      expect(result).toBe('Kein Bearbeiter zugewiesen');
+    });
+
+    it('should return assigned user text', () => {
+      const result: string = component.getUserText(userProfile);
+
+      expect(result).toBe(
+        `Aktuell zugewiesener Nutzer: ${userProfile.firstName} ${userProfile.lastName}`,
+      );
+    });
+  });
 });
diff --git a/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-list-item.component.ts b/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-list-item.component.ts
index b695b0b3740025faa936742b5e531aa68997b44d..b8cbab9cabd6479cc85550faf03fd35dc9550a9c 100644
--- a/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-list-item.component.ts
+++ b/alfa-client/libs/vorgang/src/lib/vorgang-list-container/vorgang-list/vorgang-list-item/vorgang-list-item.component.ts
@@ -22,7 +22,6 @@
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
 import {
-  createEmptyStateResource,
   EnumToLabelPipe,
   formatFullDateWithTimeWithoutSeconds,
   formatToPrettyDate,
@@ -53,10 +52,8 @@ export class VorgangListItemComponent implements OnInit {
   @Input() vorgang: VorgangResource;
 
   readonly vorgangLinkRel = VorgangHeaderLinkRel;
-  userProfile: StateResource<UserProfileResource> = createEmptyStateResource<UserProfileResource>();
 
   public ariaLabel: string = '';
-  public status: string = '';
 
   constructor(public userProfileService: UserProfileService) {}
 
@@ -64,23 +61,27 @@ export class VorgangListItemComponent implements OnInit {
     if (hasLink(this.vorgang, VorgangHeaderLinkRel.ASSIGNED_TO)) {
       this.userProfileService
         .getAssignedUserProfile(this.vorgang, VorgangHeaderLinkRel.ASSIGNED_TO)
-        .pipe(first(isNotNull))
+        .pipe(
+          first((userProfile: StateResource<UserProfileResource>) =>
+            isNotNull(userProfile.resource),
+          ),
+        )
         .subscribe((userProfileStateResource: StateResource<UserProfileResource>) => {
-          this.userProfile = userProfileStateResource;
+          this.buildAriaLabel(userProfileStateResource.resource);
         });
-    }
-    this.status = this.getStatus();
-    this.buildAriaLabel();
+    } else this.buildAriaLabel();
   }
 
-  buildAriaLabel() {
+  buildAriaLabel(userProfileResource: UserProfileResource = undefined) {
     const name: string = this.vorgang.name;
     const aktenzeichen: string = getAktenzeichenText(this.vorgang);
     const nummer: string = this.vorgang.nummer;
+    const status: string = this.getStatus();
     const approvalStatus: string = this.getApprovalText();
     const createdAt: string = formatFullDateWithTimeWithoutSeconds(this.vorgang.createdAt);
+    const userText: string = this.getUserText(userProfileResource);
 
-    this.ariaLabel = `Vorgang: ${name}, Aktenzeichen: ${aktenzeichen}, Nummer: ${nummer} Status: ${this.status} ${approvalStatus}, Eingang: ${createdAt}, Aktuell zugewiesener Nutzer: ${getUserName(this.userProfile.resource)}`;
+    this.ariaLabel = `Vorgang: ${name}, Aktenzeichen: ${aktenzeichen}, Nummer: ${nummer} Status: ${status} ${approvalStatus}, Eingang: ${createdAt}, ${userText}`;
 
     if (
       hasLink(this.vorgang, VorgangHeaderLinkRel.WIEDERVORLAGEN) &&
@@ -117,4 +118,10 @@ export class VorgangListItemComponent implements OnInit {
 
     return this.vorgang.antragBewilligt ? 'bewilligt' : 'abgelehnt';
   }
+
+  getUserText(userProfileResource: UserProfileResource): string {
+    return userProfileResource ?
+        `Aktuell zugewiesener Nutzer: ${getUserName(userProfileResource)}`
+      : 'Kein Bearbeiter zugewiesen';
+  }
 }
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/resource/OzgcloudResource.java b/alfa-service/src/main/java/de/ozgcloud/alfa/resource/OzgcloudResource.java
new file mode 100644
index 0000000000000000000000000000000000000000..3a5d37676d95578418ebba3385ddb8f5f7287e99
--- /dev/null
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/resource/OzgcloudResource.java
@@ -0,0 +1,8 @@
+package de.ozgcloud.alfa.resource;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+
+@JsonIgnoreProperties(ignoreUnknown=true)
+public class OzgcloudResource {
+
+}
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/resource/OzgcloudResourceController.java b/alfa-service/src/main/java/de/ozgcloud/alfa/resource/OzgcloudResourceController.java
new file mode 100644
index 0000000000000000000000000000000000000000..a0ccfcd416ac66767589bc373197b2238d4e99c5
--- /dev/null
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/resource/OzgcloudResourceController.java
@@ -0,0 +1,47 @@
+package de.ozgcloud.alfa.resource;
+
+import java.util.Collection;
+import java.util.Optional;
+
+import org.springframework.hateoas.EntityModel;
+import org.springframework.hateoas.Link;
+import org.springframework.hateoas.RepresentationModel;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import de.ozgcloud.alfa.common.errorhandling.ResourceNotFoundException;
+import de.ozgcloud.common.errorhandling.TechnicalException;
+import jakarta.validation.constraints.NotBlank;
+import lombok.RequiredArgsConstructor;
+
+@RestController
+@RequestMapping(OzgcloudResourceController.PATH)
+@RequiredArgsConstructor
+public class OzgcloudResourceController {
+
+	static final String PATH = "/api/resources";
+	static final String PARAM_URI = "uri";
+
+	private final Collection<OzgcloudResourceURIResolver> resolvers;
+	private final OzgcloudResourceModelAssembler assembler;
+
+	@GetMapping(params = PARAM_URI)
+	public RepresentationModel<EntityModel<OzgcloudResource>> getOzgcloudResource(@RequestParam @NotBlank String uri) {
+		var resourceLink = resolveUri(uri);
+		if (resourceLink.isEmpty()) {
+			throw new ResourceNotFoundException(OzgcloudResource.class, uri);
+		}
+		return assembler.toModel(new OzgcloudResourceURIResolveResult(uri, resourceLink.get()));
+	}
+
+	private Optional<Link> resolveUri(String uri) {
+		return resolvers.stream()
+				.map(resolver -> resolver.resolve(uri))
+				.flatMap(Optional::stream)
+				.reduce((r1, r2) -> {
+					throw new TechnicalException("Multiple resolvers accepted uri " + uri);
+				});
+	}
+}
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/resource/OzgcloudResourceModelAssembler.java b/alfa-service/src/main/java/de/ozgcloud/alfa/resource/OzgcloudResourceModelAssembler.java
new file mode 100644
index 0000000000000000000000000000000000000000..e3e83cf3a97ba6615974c72667fb32b976b6a733
--- /dev/null
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/resource/OzgcloudResourceModelAssembler.java
@@ -0,0 +1,24 @@
+package de.ozgcloud.alfa.resource;
+
+import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*;
+
+import org.springframework.hateoas.EntityModel;
+import org.springframework.hateoas.Link;
+import org.springframework.hateoas.server.RepresentationModelAssembler;
+import org.springframework.stereotype.Component;
+
+import lombok.RequiredArgsConstructor;
+
+@Component
+@RequiredArgsConstructor
+class OzgcloudResourceModelAssembler implements RepresentationModelAssembler<OzgcloudResourceURIResolveResult, EntityModel<OzgcloudResource>> {
+
+	@Override
+	public EntityModel<OzgcloudResource> toModel(OzgcloudResourceURIResolveResult uriResolveResult) {
+		return EntityModel.of(new OzgcloudResource()).add(getSelfLink(uriResolveResult.getResourceURI())).add(uriResolveResult.getResourceLink());
+	}
+
+	private Link getSelfLink(String uri) {
+		return linkTo(methodOn(OzgcloudResourceController.class).getOzgcloudResource(uri)).withSelfRel();
+	}
+}
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/resource/OzgcloudResourceRootProcessor.java b/alfa-service/src/main/java/de/ozgcloud/alfa/resource/OzgcloudResourceRootProcessor.java
new file mode 100644
index 0000000000000000000000000000000000000000..ebe46beb467ae69720dafe31da6121fcd4b4a956
--- /dev/null
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/resource/OzgcloudResourceRootProcessor.java
@@ -0,0 +1,20 @@
+package de.ozgcloud.alfa.resource;
+
+import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*;
+
+import org.springframework.hateoas.EntityModel;
+import org.springframework.hateoas.server.RepresentationModelProcessor;
+import org.springframework.stereotype.Component;
+
+import de.ozgcloud.alfa.Root;
+
+@Component
+class OzgcloudResourceRootProcessor implements RepresentationModelProcessor<EntityModel<Root>> {
+
+	static final String REL_RESOURCE = "resource";
+
+	@Override
+	public EntityModel<Root> process(EntityModel<Root> model) {
+		return model.add(linkTo(methodOn(OzgcloudResourceController.class).getOzgcloudResource(null)).withRel(REL_RESOURCE));
+	}
+}
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/resource/OzgcloudResourceURIResolveResult.java b/alfa-service/src/main/java/de/ozgcloud/alfa/resource/OzgcloudResourceURIResolveResult.java
new file mode 100644
index 0000000000000000000000000000000000000000..edcbd9ef072905e7a30930396e1afa0d68a90aa3
--- /dev/null
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/resource/OzgcloudResourceURIResolveResult.java
@@ -0,0 +1,15 @@
+package de.ozgcloud.alfa.resource;
+
+import org.springframework.hateoas.Link;
+
+import lombok.Builder;
+import lombok.Getter;
+import lombok.ToString;
+
+@Builder
+@Getter
+@ToString
+public class OzgcloudResourceURIResolveResult {
+	private final String resourceURI;
+	private final Link resourceLink;
+}
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/resource/OzgcloudResourceURIResolver.java b/alfa-service/src/main/java/de/ozgcloud/alfa/resource/OzgcloudResourceURIResolver.java
new file mode 100644
index 0000000000000000000000000000000000000000..de38d882ecb8d41c198915eafc20b830798f4fbc
--- /dev/null
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/resource/OzgcloudResourceURIResolver.java
@@ -0,0 +1,10 @@
+package de.ozgcloud.alfa.resource;
+
+import java.util.Optional;
+
+import org.springframework.hateoas.Link;
+
+public interface OzgcloudResourceURIResolver {
+
+	Optional<Link> resolve(String uri);
+}
diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/vorgang/VorgangURIResolver.java b/alfa-service/src/main/java/de/ozgcloud/alfa/vorgang/VorgangURIResolver.java
new file mode 100644
index 0000000000000000000000000000000000000000..c3b6a185dce5c3e3189fabe78e6301c23ccce5a0
--- /dev/null
+++ b/alfa-service/src/main/java/de/ozgcloud/alfa/vorgang/VorgangURIResolver.java
@@ -0,0 +1,29 @@
+package de.ozgcloud.alfa.vorgang;
+
+import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*;
+
+import java.util.Optional;
+import java.util.regex.Pattern;
+
+import org.springframework.hateoas.Link;
+import org.springframework.stereotype.Component;
+
+import de.ozgcloud.alfa.resource.OzgcloudResourceURIResolver;
+
+@Component
+class VorgangURIResolver implements OzgcloudResourceURIResolver {
+
+	static final String REL_NAME = "vorgang";
+
+	private final Pattern pattern = Pattern.compile("ozgcloud://[^/]+/vorgangs/([0-9a-fA-F]+)");
+
+	@Override
+	public Optional<Link> resolve(String uri) {
+		var matcher = pattern.matcher(uri);
+		if (!matcher.matches()) {
+			return Optional.empty();
+		}
+		var vorgangId = matcher.group(1);
+		return Optional.of(linkTo(VorgangController.class).slash(vorgangId).withRel(REL_NAME));
+	}
+}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/RootControllerITCase.java b/alfa-service/src/test/java/de/ozgcloud/alfa/RootControllerITCase.java
new file mode 100644
index 0000000000000000000000000000000000000000..c4bc47bb1aba700a268c32f282fb569ecb3f909e
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/RootControllerITCase.java
@@ -0,0 +1,52 @@
+package de.ozgcloud.alfa;
+
+import static org.mockito.Mockito.*;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
+
+import org.hamcrest.core.StringEndsWith;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.security.test.context.support.WithMockUser;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.ResultActions;
+
+import de.ozgcloud.alfa.common.user.CurrentUserService;
+import de.ozgcloud.alfa.common.user.UserProfileTestFactory;
+
+@AutoConfigureMockMvc
+@SpringBootTest
+@WithMockUser
+class RootControllerITCase {
+
+	@MockBean
+	private CurrentUserService currentUserService;
+
+	@Autowired
+	private MockMvc mockMvc;
+
+	@BeforeEach
+	void init() {
+		when(currentUserService.getUser()).thenReturn(UserProfileTestFactory.create());
+	}
+
+	@Nested
+	class TestProcess {
+
+		@Test
+		void shouldAddResourceLink() throws Exception {
+			var response = doRequest();
+
+			response.andExpect(jsonPath("$._links.resource.href").value(StringEndsWith.endsWith("/api/resources?uri={uri}")));
+		}
+	}
+
+	private ResultActions doRequest() throws Exception {
+		return mockMvc.perform(get(RootController.PATH)).andExpect(status().isOk());
+	}
+}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/resource/OzgcloudResourceControllerITCase.java b/alfa-service/src/test/java/de/ozgcloud/alfa/resource/OzgcloudResourceControllerITCase.java
new file mode 100644
index 0000000000000000000000000000000000000000..a545d2ee05325037544e883b529b7c39d4d9c991
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/resource/OzgcloudResourceControllerITCase.java
@@ -0,0 +1,90 @@
+package de.ozgcloud.alfa.resource;
+
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
+
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+
+import org.hamcrest.core.StringEndsWith;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.security.test.context.support.WithMockUser;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.ResultActions;
+
+import de.ozgcloud.alfa.common.AlfaTestUtils;
+import lombok.SneakyThrows;
+
+@AutoConfigureMockMvc
+@SpringBootTest
+@WithMockUser
+class OzgcloudResourceControllerITCase {
+
+	@Autowired
+	private MockMvc mockMvc;
+
+	@Nested
+	class TestGetOzgcloudResource {
+
+		private static final String VORGANG_ID = AlfaTestUtils.createMongoDbObjectId();
+
+		@Test
+		void shouldReturnStatusOk() throws Exception {
+			var response = doRequest("ozgcloud://test.de/vorgangs/" + VORGANG_ID);
+
+			response.andExpect(status().isOk());
+		}
+
+		@Test
+		void shouldHaveVorgangLink() throws Exception {
+			var response = doRequest("ozgcloud://test.de/vorgangs/" + VORGANG_ID);
+
+			response.andExpect(jsonPath("$._links.vorgang.href").value(StringEndsWith.endsWith("/api/vorgangs/" + VORGANG_ID)));
+		}
+
+		@Test
+		void shouldHaveSelfLink() throws Exception {
+			var uri = "ozgcloud://test.de/vorgangs/" + VORGANG_ID;
+			var encodedUri = URLEncoder.encode(uri, StandardCharsets.UTF_8);
+
+			var response = doRequest(uri);
+
+			response.andExpect(jsonPath("$._links.self.href").value(StringEndsWith.endsWith(OzgcloudResourceController.PATH + "?uri=" + encodedUri)));
+		}
+
+		@Test
+		void shouldReturnStatusNotFound() throws Exception {
+			var response = doRequest("dummy://test.de");
+
+			response.andExpect(status().isNotFound());
+		}
+
+		@Test
+		void shouldReturnBadRequestOnNoRequestParam() throws Exception {
+			var response = doRequestWithQueryString("");
+
+			response.andExpect(status().isBadRequest());
+		}
+
+		@Test
+		void shouldReturnBadRequestOnEmptyUri() throws Exception {
+			var response = doRequestWithQueryString("?uri=");
+
+			response.andExpect(status().isBadRequest());
+		}
+
+		@SneakyThrows
+		private ResultActions doRequest(String uri) {
+			return doRequestWithQueryString("?uri=" + uri);
+		}
+
+		@SneakyThrows
+		private ResultActions doRequestWithQueryString(String queryString) {
+			return mockMvc.perform(get(OzgcloudResourceController.PATH + queryString));
+		}
+	}
+}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/resource/OzgcloudResourceControllerTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/resource/OzgcloudResourceControllerTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..9ea5e3d62933188bc4a839a69b7b3cb4d2c63cb1
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/resource/OzgcloudResourceControllerTest.java
@@ -0,0 +1,130 @@
+package de.ozgcloud.alfa.resource;
+
+import static org.assertj.core.api.Assertions.*;
+import static org.mockito.Mockito.*;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Optional;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentMatcher;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Spy;
+import org.springframework.hateoas.EntityModel;
+import org.springframework.hateoas.RepresentationModel;
+
+import de.ozgcloud.alfa.common.errorhandling.ResourceNotFoundException;
+import de.ozgcloud.common.errorhandling.TechnicalException;
+import lombok.SneakyThrows;
+
+class OzgcloudResourceControllerTest {
+
+	@Mock
+	private OzgcloudResourceURIResolver resourceAResolver;
+	@Mock
+	private OzgcloudResourceURIResolver resourceBResolver;
+	@Spy
+	private Collection<OzgcloudResourceURIResolver> resourceResolvers = new ArrayList<>();
+	@Mock
+	private OzgcloudResourceModelAssembler assembler;
+	@InjectMocks
+	private OzgcloudResourceController controller;
+
+	@BeforeEach
+	void init() {
+		resourceResolvers.add(resourceAResolver);
+		resourceResolvers.add(resourceBResolver);
+	}
+
+	@Nested
+	class TestGetOzgcloudResource {
+
+		@Nested
+		class OnUriCouldBeResolved {
+
+			private final ArgumentMatcher<OzgcloudResourceURIResolveResult> HAS_MATCHING_RESOURCE_URI = mapping -> mapping.getResourceURI().equals(
+					OzgcloudResourceURIResolveResultTestFactory.RESOURCE_URI);
+			private final ArgumentMatcher<OzgcloudResourceURIResolveResult> HAS_MATCHING_RESOURCE_LINK = mapping -> mapping.getResourceLink().equals(
+					OzgcloudResourceURIResolveResultTestFactory.RESOURCE_LINK);
+
+			@BeforeEach
+			void init() {
+				when(resourceBResolver.resolve(OzgcloudResourceURIResolveResultTestFactory.RESOURCE_URI)).thenReturn(Optional.of(
+						OzgcloudResourceURIResolveResultTestFactory.RESOURCE_LINK));
+			}
+
+			@Test
+			void shouldCallResolver() {
+				callController();
+
+				verify(resourceBResolver).resolve(OzgcloudResourceURIResolveResultTestFactory.RESOURCE_URI);
+			}
+
+			@Test
+			void shouldCallAssemblerWithUri() {
+				callController();
+
+				verify(assembler).toModel(argThat(HAS_MATCHING_RESOURCE_URI));
+			}
+
+			@Test
+			void shouldCallAssemblerWithResourceLink() {
+				callController();
+
+				verify(assembler).toModel(argThat(HAS_MATCHING_RESOURCE_LINK));
+			}
+
+			@Test
+			void shouldReturnModelFromAssembler() {
+				EntityModel<OzgcloudResource> modelFromAssembler = EntityModel.of(new OzgcloudResource());
+				when(assembler.toModel(argThat(mapping -> HAS_MATCHING_RESOURCE_URI.matches(mapping) && HAS_MATCHING_RESOURCE_LINK.matches(mapping))))
+						.thenReturn(modelFromAssembler);
+
+				var model = callController();
+
+				assertThat(model).isEqualTo(modelFromAssembler);
+			}
+		}
+
+		@Nested
+		class OnUriCouldNotBeResolved {
+
+			@BeforeEach
+			void init() {
+				when(resourceAResolver.resolve(OzgcloudResourceURIResolveResultTestFactory.RESOURCE_URI)).thenReturn(Optional.empty());
+				when(resourceBResolver.resolve(OzgcloudResourceURIResolveResultTestFactory.RESOURCE_URI)).thenReturn(Optional.empty());
+			}
+
+			@Test
+			void shouldThrowResourceNotFoundException() {
+				assertThatThrownBy(TestGetOzgcloudResource.this::callController).isInstanceOf(ResourceNotFoundException.class);
+			}
+		}
+
+		@Nested
+		class OnMultipleResolveResults {
+
+			@BeforeEach
+			void init() {
+				when(resourceAResolver.resolve(OzgcloudResourceURIResolveResultTestFactory.RESOURCE_URI)).thenReturn(Optional.of(
+						OzgcloudResourceURIResolveResultTestFactory.RESOURCE_LINK));
+				when(resourceBResolver.resolve(OzgcloudResourceURIResolveResultTestFactory.RESOURCE_URI)).thenReturn(Optional.of(
+						OzgcloudResourceURIResolveResultTestFactory.RESOURCE_LINK));
+			}
+
+			@Test
+			void shouldThrowTechnicalException() {
+				assertThatThrownBy(TestGetOzgcloudResource.this::callController).isInstanceOf(TechnicalException.class);
+			}
+		}
+
+		@SneakyThrows
+		private RepresentationModel<EntityModel<OzgcloudResource>> callController() {
+			return controller.getOzgcloudResource(OzgcloudResourceURIResolveResultTestFactory.RESOURCE_URI);
+		}
+	}
+}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/resource/OzgcloudResourceModelAssemblerTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/resource/OzgcloudResourceModelAssemblerTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..ed144040a39978e418d2248ca496007c4c4f05ac
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/resource/OzgcloudResourceModelAssemblerTest.java
@@ -0,0 +1,43 @@
+package de.ozgcloud.alfa.resource;
+
+import static de.ozgcloud.alfa.resource.OzgcloudResourceController.*;
+import static org.assertj.core.api.Assertions.*;
+
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.mockito.InjectMocks;
+import org.springframework.hateoas.EntityModel;
+import org.springframework.hateoas.IanaLinkRelations;
+import org.springframework.hateoas.Link;
+
+class OzgcloudResourceModelAssemblerTest {
+
+	@InjectMocks
+	private OzgcloudResourceModelAssembler assembler;
+
+	@Nested
+	class TestToModel {
+
+		private final OzgcloudResourceURIResolveResult uriResolveResult = OzgcloudResourceURIResolveResultTestFactory.create();
+
+		@Test
+		void shouldHaveSelfLink() {
+			var model = callAssembler();
+
+			assertThat(model.getLink(IanaLinkRelations.SELF_VALUE)).isPresent().get().extracting(Link::getHref)
+					.isEqualTo(OzgcloudResourceController.PATH + "?" + PARAM_URI + "=" + OzgcloudResourceURIResolveResultTestFactory.ENCODED_RESOURCE_URI);
+		}
+
+		@Test
+		void shouldHaveResourceLink() {
+			var model = callAssembler();
+
+			assertThat(model.getLink(OzgcloudResourceURIResolveResultTestFactory.RESOURCE_LINK.getRel())).isPresent().get().isEqualTo(
+					OzgcloudResourceURIResolveResultTestFactory.RESOURCE_LINK);
+		}
+
+		private EntityModel<OzgcloudResource> callAssembler() {
+			return assembler.toModel(uriResolveResult);
+		}
+	}
+}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/resource/OzgcloudResourceRootProcessorTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/resource/OzgcloudResourceRootProcessorTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..71d60de1e746dd5f801b5d0a4f87b0d93493bcc7
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/resource/OzgcloudResourceRootProcessorTest.java
@@ -0,0 +1,39 @@
+package de.ozgcloud.alfa.resource;
+
+import static org.assertj.core.api.Assertions.*;
+
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.springframework.hateoas.EntityModel;
+import org.springframework.hateoas.Link;
+
+import de.ozgcloud.alfa.Root;
+import de.ozgcloud.alfa.RootTestFactory;
+
+class OzgcloudResourceRootProcessorTest {
+
+	private final OzgcloudResourceRootProcessor processor = new OzgcloudResourceRootProcessor();
+
+	@Nested
+	class TestProcess {
+
+		private final EntityModel<Root> model = EntityModel.of(RootTestFactory.create());
+
+		@Test
+		void shouldReturnOriginalModel() {
+			var result = processor.process(model);
+
+			assertThat(result).isEqualTo(model);
+		}
+
+		@Test
+		void shouldAddResourceLink() {
+			processor.process(model);
+
+			assertThat(model.getLink(OzgcloudResourceRootProcessor.REL_RESOURCE)).isPresent().get().extracting(Link::getHref)
+					.isEqualTo(OzgcloudResourceController.PATH + "?uri={uri}");
+		}
+	}
+}
+
+
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/resource/OzgcloudResourceURIResolveResultTestFactory.java b/alfa-service/src/test/java/de/ozgcloud/alfa/resource/OzgcloudResourceURIResolveResultTestFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..dd0ea565f584133ece1265c2c2a9782135a65a74
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/resource/OzgcloudResourceURIResolveResultTestFactory.java
@@ -0,0 +1,23 @@
+package de.ozgcloud.alfa.resource;
+
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+
+import org.springframework.hateoas.Link;
+
+import com.thedeanda.lorem.LoremIpsum;
+
+class OzgcloudResourceURIResolveResultTestFactory {
+
+	public static final String RESOURCE_URI = String.format("%s://%s.%s/%s", (Object[]) LoremIpsum.getInstance().getWords(4).split("\\s"));
+	public static final String ENCODED_RESOURCE_URI = URLEncoder.encode(RESOURCE_URI, StandardCharsets.UTF_8);
+	public static final Link RESOURCE_LINK = Link.of(LoremIpsum.getInstance().getUrl()).withRel(LoremIpsum.getInstance().getWords(1));
+
+	public static OzgcloudResourceURIResolveResult create() {
+		return createBuilder().build();
+	}
+
+	public static OzgcloudResourceURIResolveResult.OzgcloudResourceURIResolveResultBuilder createBuilder() {
+		return OzgcloudResourceURIResolveResult.builder().resourceURI(RESOURCE_URI).resourceLink(RESOURCE_LINK);
+	}
+}
diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/VorgangURIResolverTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/VorgangURIResolverTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..1d691c621cc7e42d207861ccb6503bd04026a74c
--- /dev/null
+++ b/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/VorgangURIResolverTest.java
@@ -0,0 +1,61 @@
+package de.ozgcloud.alfa.vorgang;
+
+import static org.assertj.core.api.Assertions.*;
+
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+import org.springframework.hateoas.Link;
+import org.springframework.hateoas.LinkRelation;
+
+import de.ozgcloud.alfa.common.AlfaTestUtils;
+
+class VorgangURIResolverTest {
+
+	private VorgangURIResolver resolver = new VorgangURIResolver();
+
+	@Nested
+	class TestResolve {
+
+		private final String VORGANG_ID = AlfaTestUtils.createMongoDbObjectId();
+		private final String VORGANG_URI = "ozgcloud://dummy.de/vorgangs/" + VORGANG_ID;
+
+		@ParameterizedTest
+		@ValueSource(strings = {
+				"http://dummy.de/vorgangs/123",
+				"ozgcloud://dummy.de/res-a/123",
+				"ozgcloud://dummy.de/xyz/vorgangs/123",
+				"ozgcloud://dummy.de/vorgangs/xyz/123" })
+		void shouldReturnEmptyIfUriIsNotRecognized(String uri) {
+			var result = resolver.resolve(uri);
+
+			assertThat(result).isEmpty();
+		}
+
+		@Test
+		void shouldReturnLink() {
+			var result = resolver.resolve(VORGANG_URI);
+
+			assertThat(result).isPresent();
+		}
+
+		@Nested
+		class TestVorgangLink {
+
+			@Test
+			void shouldHaveCorrectRelValue() {
+				var result = resolver.resolve(VORGANG_URI);
+
+				assertThat(result).get().extracting(Link::getRel).extracting(LinkRelation::value).isEqualTo(VorgangURIResolver.REL_NAME);
+			}
+
+			@Test
+			void shouldHaveHrefOfVorgang() {
+				var result = resolver.resolve(VORGANG_URI);
+
+				assertThat(result).get().extracting(Link::getHref).isEqualTo("/api/vorgangs/" + VORGANG_ID);
+			}
+		}
+	}
+}