diff --git a/alfa-client/apps/admin/src/app/app.component.html b/alfa-client/apps/admin/src/app/app.component.html
index aec8d53fbb5c0848c05817014a197e6fbec5ccdf..69e4b50b55c887010dbdea890b1f62c3b275478f 100644
--- a/alfa-client/apps/admin/src/app/app.component.html
+++ b/alfa-client/apps/admin/src/app/app.component.html
@@ -21,6 +21,10 @@
         <!--        <ods-nav-item caption="Organisationseinheiten" to="/organisationseinheiten">-->
         <!--          <ods-orga-unit-icon icon />-->
         <!--        </ods-nav-item>-->
+        <ods-nav-item caption="Benutzer & Rollen" to="/benutzer_und_rollen">
+          <ods-users-icon class="stroke-text" icon />
+        </ods-nav-item>
+        <hr />
         <ods-nav-item caption="Postfach" to="/postfach">
           <ods-mailbox-icon icon />
         </ods-nav-item>
diff --git a/alfa-client/apps/admin/src/app/app.component.spec.ts b/alfa-client/apps/admin/src/app/app.component.spec.ts
index d10cfd74e6f7e55e727bf6779c494f0f5311f8b7..fbf5f0baf5ba16a4c33e3140833521efb6e7a367 100644
--- a/alfa-client/apps/admin/src/app/app.component.spec.ts
+++ b/alfa-client/apps/admin/src/app/app.component.spec.ts
@@ -20,9 +20,9 @@ import {
   NavItemComponent,
   NavbarComponent,
   OrgaUnitIconComponent,
+  UsersIconComponent,
 } from '@ods/system';
 import { AuthenticationService } from 'authentication';
-import { NavigationComponent } from 'libs/admin/settings/src/lib/navigation/navigation.component';
 import { createApiRootResource } from 'libs/api-root-shared/test/api-root';
 import { getDataTestIdOf } from 'libs/tech-shared/test/data-test';
 import { MockComponent, MockDirective } from 'ng-mocks';
@@ -54,9 +54,9 @@ describe('AppComponent', () => {
     await TestBed.configureTestingModule({
       declarations: [
         AppComponent,
-        MockComponent(NavigationComponent),
         MockComponent(AdminLogoIconComponent),
         MockComponent(OrgaUnitIconComponent),
+        MockComponent(UsersIconComponent),
         MockComponent(MailboxIconComponent),
         MockComponent(UserProfileButtonContainerComponent),
         MockComponent(UnavailablePageComponent),
diff --git a/alfa-client/apps/admin/src/app/app.module.ts b/alfa-client/apps/admin/src/app/app.module.ts
index 350fef2058a41e30e107d9cc3d691f98e8a5269f..7c9c63cf24edf02b34858e9a0f9f1ce98b2ffdcd 100644
--- a/alfa-client/apps/admin/src/app/app.module.ts
+++ b/alfa-client/apps/admin/src/app/app.module.ts
@@ -22,6 +22,7 @@ import {
   NavItemComponent,
   NavbarComponent,
   OrgaUnitIconComponent,
+  UsersIconComponent,
 } from '@ods/system';
 import { OAuthModule } from 'angular-oauth2-oidc';
 import { HttpUnauthorizedInterceptor } from 'libs/authentication/src/lib/http-unauthorized.interceptor';
@@ -30,6 +31,7 @@ import { environment } from '../environments/environment';
 import { OrganisationseinheitPageComponent } from '../pages/organisationseinheit/organisationseinheit-page/organisationseinheit-page.component';
 import { PostfachPageComponent } from '../pages/postfach/postfach-page/postfach-page.component';
 import { UnavailablePageComponent } from '../pages/unavailable/unavailable-page/unavailable-page.component';
+import { UserRolesPageComponent } from '../pages/users-roles/user-roles-page/user-roles-page.component';
 import { AppComponent } from './app.component';
 import { appRoutes } from './app.routes';
 
@@ -37,6 +39,7 @@ import { appRoutes } from './app.routes';
   declarations: [
     AppComponent,
     PostfachPageComponent,
+    UserRolesPageComponent,
     OrganisationseinheitPageComponent,
     UserProfileButtonContainerComponent,
     UnavailablePageComponent,
@@ -50,6 +53,7 @@ import { appRoutes } from './app.routes';
     NavbarComponent,
     OrgaUnitIconComponent,
     LogoutIconComponent,
+    UsersIconComponent,
     MailboxIconComponent,
     RouterModule.forRoot(appRoutes),
     BrowserModule,
diff --git a/alfa-client/apps/admin/src/app/app.routes.ts b/alfa-client/apps/admin/src/app/app.routes.ts
index fdff512b76c4e15d4026c8c250cce90357cf98be..9594ce3ee2736d7a990774c0b57db4f75e3a7582 100644
--- a/alfa-client/apps/admin/src/app/app.routes.ts
+++ b/alfa-client/apps/admin/src/app/app.routes.ts
@@ -1,5 +1,6 @@
 import { Route } from '@angular/router';
 import { PostfachPageComponent } from '../pages/postfach/postfach-page/postfach-page.component';
+import { UserRolesPageComponent } from '../pages/users-roles/user-roles-page/user-roles-page.component';
 
 export const appRoutes: Route[] = [
   {
@@ -12,6 +13,11 @@ export const appRoutes: Route[] = [
     component: PostfachPageComponent,
     title: 'Admin | Postfach',
   },
+  {
+    path: 'benutzer_und_rollen',
+    component: UserRolesPageComponent,
+    title: 'Admin | Benutzer & Rollen',
+  },
   // {
   //   path: 'organisationseinheiten',
   //   component: OrganisationseinheitPageComponent,
diff --git a/alfa-client/apps/admin/src/index.html b/alfa-client/apps/admin/src/index.html
index b1d42def4c92709d7794e04aaa3484164a21b4a8..e9b77e77d1493dd0f7e67f051941b5c48fff1b33 100644
--- a/alfa-client/apps/admin/src/index.html
+++ b/alfa-client/apps/admin/src/index.html
@@ -1,5 +1,5 @@
 <!doctype html>
-<html lang="en" class="h-full bg-white antialiased">
+<html lang="de" class="h-full bg-white antialiased">
   <head>
     <meta charset="utf-8" />
     <title>admin</title>
@@ -7,7 +7,9 @@
     <meta name="viewport" content="width=device-width, initial-scale=1" />
     <link rel="icon" type="image/x-icon" href="favicon.ico" />
   </head>
-  <body class="flex max-h-full min-h-full bg-white text-black dark:bg-slate-100 dark:bg-slate-900">
+  <body
+    class="flex max-h-full min-h-full overflow-hidden bg-white text-black dark:bg-slate-900 dark:text-slate-100"
+  >
     <app-root class="flex w-full flex-col"></app-root>
   </body>
 </html>
diff --git a/alfa-client/apps/admin/src/pages/users-roles/user-roles-page/user-roles-page.component.html b/alfa-client/apps/admin/src/pages/users-roles/user-roles-page/user-roles-page.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..3000e0ffbac09b63c3d12d715638ab67f610bc39
--- /dev/null
+++ b/alfa-client/apps/admin/src/pages/users-roles/user-roles-page/user-roles-page.component.html
@@ -0,0 +1 @@
+<admin-users-roles />
\ No newline at end of file
diff --git a/alfa-client/apps/admin/src/pages/users-roles/user-roles-page/user-roles-page.component.spec.ts b/alfa-client/apps/admin/src/pages/users-roles/user-roles-page/user-roles-page.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1285eda7400123a525353d217969ab1d0d681074
--- /dev/null
+++ b/alfa-client/apps/admin/src/pages/users-roles/user-roles-page/user-roles-page.component.spec.ts
@@ -0,0 +1,24 @@
+import { UsersRolesComponent } from '@admin-client/admin-settings';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { MockComponent } from 'ng-mocks';
+import { UserRolesPageComponent } from './user-roles-page.component';
+
+describe('UserRolesPageComponent', () => {
+  let component: UserRolesPageComponent;
+  let fixture: ComponentFixture<UserRolesPageComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      declarations: [UserRolesPageComponent],
+      imports: [MockComponent(UsersRolesComponent)],
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(UserRolesPageComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/alfa-client/apps/admin/src/pages/users-roles/user-roles-page/user-roles-page.component.ts b/alfa-client/apps/admin/src/pages/users-roles/user-roles-page/user-roles-page.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..6b3576a76e34d01f319b4a8b2c4f44c82c62f44f
--- /dev/null
+++ b/alfa-client/apps/admin/src/pages/users-roles/user-roles-page/user-roles-page.component.ts
@@ -0,0 +1,7 @@
+import { Component } from '@angular/core';
+
+@Component({
+  selector: 'app-user-roles-page',
+  templateUrl: './user-roles-page.component.html',
+})
+export class UserRolesPageComponent {}
diff --git a/alfa-client/libs/admin/settings/src/index.ts b/alfa-client/libs/admin/settings/src/index.ts
index 8d33b086734e167bd7ba0f3b40e56033948b02a1..c4fb8070ef7b2b2df0fcfbe70f30c84a06235327 100644
--- a/alfa-client/libs/admin/settings/src/index.ts
+++ b/alfa-client/libs/admin/settings/src/index.ts
@@ -2,3 +2,4 @@ export * from './lib/admin-settings.module';
 export * from './lib/organisationseinheit/organisationseinheit-container/organisationseinheit-container.component';
 export * from './lib/postfach/postfach-container/postfach-container.component';
 export * from './lib/shared/navigation-item/navigation-item.component';
+export * from './lib/users-roles/users-roles.component';
diff --git a/alfa-client/libs/admin/settings/src/lib/admin-settings.module.ts b/alfa-client/libs/admin/settings/src/lib/admin-settings.module.ts
index a6865423b56b2537999ce25764a3357a883fe0da..321e7c04c5850b85027d827f2bc43e971cdef1b1 100644
--- a/alfa-client/libs/admin/settings/src/lib/admin-settings.module.ts
+++ b/alfa-client/libs/admin/settings/src/lib/admin-settings.module.ts
@@ -7,30 +7,18 @@ import { ReactiveFormsModule } from '@angular/forms';
 import { RouterModule } from '@angular/router';
 import KcAdminClient from '@keycloak/keycloak-admin-client';
 import { ButtonWithSpinnerComponent, TextareaEditorComponent } from '@ods/component';
-import { TextInputComponent } from '@ods/system';
-import {
-  createSettingListResourceService,
-  SettingListResourceService,
-} from './admin-settings-resource.service';
+import { MailboxIconComponent, PersonIconComponent, TextInputComponent } from '@ods/system';
+import { createSettingListResourceService, SettingListResourceService } from './admin-settings-resource.service';
 import { SettingsService } from './admin-settings.service';
-import {
-  ConfigurationResourceService,
-  createConfigurationResourceService,
-} from './configuration/configuration-resource.service';
+import { ConfigurationResourceService, createConfigurationResourceService } from './configuration/configuration-resource.service';
 import { ConfigurationService } from './configuration/configuration.service';
-import { NavigationComponent } from './navigation/navigation.component';
 import { OrganisationseinheitContainerComponent } from './organisationseinheit/organisationseinheit-container/organisationseinheit-container.component';
 import { OrganisationseinheitFormComponent } from './organisationseinheit/organisationseinheit-container/organisationseinheit-form/organisationseinheit-form.component';
 import { OrganisationseinheitListComponent } from './organisationseinheit/organisationseinheit-container/organisationseinheit-list/organisationseinheit-list.component';
-import { OrganisationseinheitNavigationItemComponent } from './organisationseinheit/organisationseinheit-navigation-item/organisationseinheit-navigation-item.component';
 import { PostfachContainerComponent } from './postfach/postfach-container/postfach-container.component';
 import { PostfachFormComponent } from './postfach/postfach-container/postfach-form/postfach-form.component';
 import { PostfachSignaturComponent } from './postfach/postfach-container/postfach-form/postfach-signatur/postfach-signatur.component';
-import { PostfachNavigationItemComponent } from './postfach/postfach-navigation-item/postfach-navigation-item.component';
-import {
-  createPostfachResourceService,
-  PostfachResourceService,
-} from './postfach/postfach-resource.service';
+import { createPostfachResourceService, PostfachResourceService } from './postfach/postfach-resource.service';
 import { PostfachService } from './postfach/postfach.service';
 import { MoreItemButtonComponent } from './shared/more-menu/more-item-button/more-item-button.component';
 import { MoreMenuComponent } from './shared/more-menu/more-menu.component';
@@ -39,6 +27,8 @@ import { PrimaryButtonComponent } from './shared/primary-button/primary-button.c
 import { SecondaryButtonComponent } from './shared/secondary-button/secondary-button.component';
 import { SpinnerComponent } from './shared/spinner/spinner.component';
 import { TextFieldComponent } from './shared/text-field/text-field.component';
+import { ToUserNamePipe } from './user/to-user-name.pipe';
+import { UsersRolesComponent } from './users-roles/users-roles.component';
 
 @NgModule({
   declarations: [
@@ -47,17 +37,15 @@ import { TextFieldComponent } from './shared/text-field/text-field.component';
     PostfachSignaturComponent,
     NavigationItemComponent,
     TextFieldComponent,
-    PostfachNavigationItemComponent,
     OrganisationseinheitContainerComponent,
     OrganisationseinheitFormComponent,
     PrimaryButtonComponent,
-    NavigationComponent,
     SecondaryButtonComponent,
-    OrganisationseinheitNavigationItemComponent,
     OrganisationseinheitListComponent,
     MoreMenuComponent,
     MoreItemButtonComponent,
     SpinnerComponent,
+    UsersRolesComponent,
   ],
   imports: [
     CommonModule,
@@ -67,13 +55,11 @@ import { TextFieldComponent } from './shared/text-field/text-field.component';
     TextInputComponent,
     ButtonWithSpinnerComponent,
     TextareaEditorComponent,
+    MailboxIconComponent,
+    PersonIconComponent,
+    ToUserNamePipe,
   ],
-  exports: [
-    PostfachContainerComponent,
-    OrganisationseinheitContainerComponent,
-    NavigationComponent,
-    NavigationItemComponent,
-  ],
+  exports: [PostfachContainerComponent, OrganisationseinheitContainerComponent, NavigationItemComponent, UsersRolesComponent],
   providers: [
     ConfigurationService,
     SettingsService,
diff --git a/alfa-client/libs/admin/settings/src/lib/navigation/navigation.component.html b/alfa-client/libs/admin/settings/src/lib/navigation/navigation.component.html
deleted file mode 100644
index aa69f82b45426328c850c413c0653d4a074c7ac5..0000000000000000000000000000000000000000
--- a/alfa-client/libs/admin/settings/src/lib/navigation/navigation.component.html
+++ /dev/null
@@ -1,2 +0,0 @@
-<!--<admin-organisationseinheit-navigation-item></admin-organisationseinheit-navigation-item>-->
-<admin-postfach-navigation-item></admin-postfach-navigation-item>
diff --git a/alfa-client/libs/admin/settings/src/lib/navigation/navigation.component.scss b/alfa-client/libs/admin/settings/src/lib/navigation/navigation.component.scss
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/alfa-client/libs/admin/settings/src/lib/navigation/navigation.component.spec.ts b/alfa-client/libs/admin/settings/src/lib/navigation/navigation.component.spec.ts
deleted file mode 100644
index 2598e618c4eb36e2762d7f34ac87260719706a99..0000000000000000000000000000000000000000
--- a/alfa-client/libs/admin/settings/src/lib/navigation/navigation.component.spec.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-import { ComponentFixture, TestBed } from '@angular/core/testing';
-import { MockComponent } from 'ng-mocks';
-import { OrganisationseinheitNavigationItemComponent } from '../organisationseinheit/organisationseinheit-navigation-item/organisationseinheit-navigation-item.component';
-import { PostfachNavigationItemComponent } from '../postfach/postfach-navigation-item/postfach-navigation-item.component';
-import { NavigationComponent } from './navigation.component';
-
-describe('NavigationComponent', () => {
-  let component: NavigationComponent;
-  let fixture: ComponentFixture<NavigationComponent>;
-
-  beforeEach(async () => {
-    await TestBed.configureTestingModule({
-      declarations: [
-        NavigationComponent,
-        MockComponent(PostfachNavigationItemComponent),
-        MockComponent(OrganisationseinheitNavigationItemComponent),
-      ],
-    }).compileComponents();
-
-    fixture = TestBed.createComponent(NavigationComponent);
-    component = fixture.componentInstance;
-    fixture.detectChanges();
-  });
-
-  it('should create', () => {
-    expect(component).toBeTruthy();
-  });
-});
diff --git a/alfa-client/libs/admin/settings/src/lib/navigation/navigation.component.ts b/alfa-client/libs/admin/settings/src/lib/navigation/navigation.component.ts
deleted file mode 100644
index 0161a117a1692930d4335c882992892626744a6e..0000000000000000000000000000000000000000
--- a/alfa-client/libs/admin/settings/src/lib/navigation/navigation.component.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { Component } from '@angular/core';
-
-@Component({
-  selector: 'admin-navigation',
-  templateUrl: './navigation.component.html',
-  styleUrls: ['./navigation.component.scss'],
-})
-export class NavigationComponent {}
diff --git a/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-container.component.html b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-container.component.html
index d324f8d83fe91defe9b5066f4f24d230bc33eb4f..3e7af75f493ada03112994766ea980b90033e282 100644
--- a/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-container.component.html
+++ b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-container.component.html
@@ -1,24 +1,27 @@
-<h1 class="heading-1 pb-4">Organisationseinheiten</h1>
-<p id="absender-desc" class="p-1">Hinterlegen Sie Name und ID der Organisationseinheiten.</p>
+<ng-container *ngIf="organisationseinheitItems$ | async as organisationseinheitItems">
+  <h1 class="heading-1 pb-4">Organisationseinheiten</h1>
+  <p id="absender-desc" class="p-1">Hinterlegen Sie Name und ID der Organisationseinheiten.</p>
 
-<admin-organisationseinheit-form
-  data-test-id="organisationseinheit-form"
-></admin-organisationseinheit-form>
+  <admin-organisationseinheit-form
+    data-test-id="organisationseinheit-form"
+    [organisationseinheitItems]="organisationseinheitItems"
+  ></admin-organisationseinheit-form>
 
-<admin-secondary-button
-  (clickEmitter)="openDialogForNewGroup()"
-  data-test-id="organisationseinheit-open-dialog-button"
-  label="Neue Organisationseinheit anlegen"
->
-</admin-secondary-button>
-<admin-spinner
-  data-test-id="organisationseinheit-spinner"
-  *ngIf="deleteInProgress$ | async"
-></admin-spinner>
+  <admin-secondary-button
+    (clickEmitter)="openDialogForNewGroup()"
+    data-test-id="organisationseinheit-open-dialog-button"
+    label="Neue Organisationseinheit anlegen"
+  >
+  </admin-secondary-button>
+  <admin-spinner
+    data-test-id="organisationseinheit-spinner"
+    *ngIf="deleteInProgress$ | async"
+  ></admin-spinner>
 
-<admin-organisationseinheit-list
-  [organisationseinheitItems]="organisationseinheitItems$ | async"
-  (editOrganisationseinheit)="edit($event)"
-  (deleteOrganisationseinheit)="delete($event)"
-  data-test-id="organisationseinheit-list"
-></admin-organisationseinheit-list>
+  <admin-organisationseinheit-list
+    [organisationseinheitItems]="organisationseinheitItems"
+    (editOrganisationseinheit)="edit($event)"
+    (deleteOrganisationseinheit)="delete($event)"
+    data-test-id="organisationseinheit-list"
+  ></admin-organisationseinheit-list>
+</ng-container>
diff --git a/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-container.component.spec.ts b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-container.component.spec.ts
index 50aed3b14f080f41d6dd560101a3c1a358bc5b8f..1c5f9731bdfef401363bc423391cf1c7a2ed0529 100644
--- a/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-container.component.spec.ts
+++ b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-container.component.spec.ts
@@ -1,3 +1,4 @@
+import { createStateResource } from '@alfa-client/tech-shared';
 import {
   Mock,
   dispatchEventFromFixture,
@@ -11,14 +12,11 @@ import { getDataTestIdOf } from 'libs/tech-shared/test/data-test';
 import { singleCold } from 'libs/tech-shared/test/marbles';
 import { MockComponent } from 'ng-mocks';
 import { of } from 'rxjs';
-import {
-  createOrganisationseinheit,
-  createOrganisationseinheitState,
-} from '../../../../test/user/user';
+import { createOrganisationseinheit } from '../../../../test/user/user';
 import { SecondaryButtonComponent } from '../../shared/secondary-button/secondary-button.component';
 import { SpinnerComponent } from '../../shared/spinner/spinner.component';
 import { Organisationseinheit } from '../../user/user.model';
-import { UserService } from '../../user/user.service';
+import { OrganisationseinheitService } from '../organisationseinheit.service';
 import { OrganisationseinheitContainerComponent } from './organisationseinheit-container.component';
 import { OrganisationseinheitFormComponent } from './organisationseinheit-form/organisationseinheit-form.component';
 import { OrganisationseinheitListComponent } from './organisationseinheit-list/organisationseinheit-list.component';
@@ -27,11 +25,9 @@ describe('OrganisationseinheitContainerComponent', () => {
   let component: OrganisationseinheitContainerComponent;
   let fixture: ComponentFixture<OrganisationseinheitContainerComponent>;
 
-  const userService: Mock<UserService> = mock(UserService);
+  const organisationseinheitService: Mock<OrganisationseinheitService> = mock(OrganisationseinheitService);
 
-  const dialogOpenButtonSelector: string = getDataTestIdOf(
-    'organisationseinheit-open-dialog-button',
-  );
+  const dialogOpenButtonSelector: string = getDataTestIdOf('organisationseinheit-open-dialog-button');
   const spinnerSelector: string = getDataTestIdOf('organisationseinheit-spinner');
 
   const organisationseinheitItems: Organisationseinheit[] = [createOrganisationseinheit()];
@@ -48,15 +44,13 @@ describe('OrganisationseinheitContainerComponent', () => {
         MockComponent(OrganisationseinheitListComponent),
         MockComponent(SpinnerComponent),
       ],
-      providers: [{ provide: UserService, useValue: userService }],
+      providers: [{ provide: OrganisationseinheitService, useValue: organisationseinheitService }],
     }).compileComponents();
 
     fixture = TestBed.createComponent(OrganisationseinheitContainerComponent);
     component = fixture.componentInstance;
 
-    userService.getOrganisationseinheitState = jest
-      .fn()
-      .mockReturnValue(of(createOrganisationseinheitState(organisationseinheitItems)));
+    organisationseinheitService.get = jest.fn().mockReturnValue(of(createStateResource(organisationseinheitItems)));
     fixture.detectChanges();
 
     formComponent = getElementFromFixtureByType(fixture, OrganisationseinheitFormComponent);
@@ -99,13 +93,13 @@ describe('OrganisationseinheitContainerComponent', () => {
     const organisationseinheit: Organisationseinheit = organisationseinheitItems[0];
 
     beforeEach(() => {
-      userService.deleteOrganisationseinheit = jest.fn().mockReturnValue(singleCold(true));
+      organisationseinheitService.delete = jest.fn().mockReturnValue(singleCold(true));
     });
 
     it('should call service method', () => {
       component.delete(organisationseinheit);
 
-      expect(userService.deleteOrganisationseinheit).toHaveBeenCalledWith(organisationseinheit.id);
+      expect(organisationseinheitService.delete).toHaveBeenCalledWith(organisationseinheit.id);
     });
 
     it('should assign delete progress observable', () => {
diff --git a/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-container.component.ts b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-container.component.ts
index f2bc2061e143c013c4d7f9f3096c2020c8852d3a..c8dc13a8eda3ff1f0825c7282020040695df6ecd 100644
--- a/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-container.component.ts
+++ b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-container.component.ts
@@ -1,7 +1,8 @@
+import { StateResource } from '@alfa-client/tech-shared';
 import { Component, OnInit, ViewChild } from '@angular/core';
 import { Observable, of } from 'rxjs';
 import { Organisationseinheit } from '../../user/user.model';
-import { UserService } from '../../user/user.service';
+import { OrganisationseinheitService } from '../organisationseinheit.service';
 import { OrganisationseinheitFormComponent } from './organisationseinheit-form/organisationseinheit-form.component';
 
 @Component({
@@ -9,16 +10,16 @@ import { OrganisationseinheitFormComponent } from './organisationseinheit-form/o
   templateUrl: './organisationseinheit-container.component.html',
 })
 export class OrganisationseinheitContainerComponent implements OnInit {
-  organisationseinheitItems$: Observable<Organisationseinheit[]>;
+  organisationseinheitItems$: Observable<StateResource<Organisationseinheit[]>>;
   deleteInProgress$: Observable<boolean> = of(false);
 
   @ViewChild(OrganisationseinheitFormComponent)
   private form!: OrganisationseinheitFormComponent;
 
-  constructor(private userService: UserService) {}
+  constructor(private organisationseinheitService: OrganisationseinheitService) {}
 
   ngOnInit(): void {
-    this.organisationseinheitItems$ = this.userService.getOrganisationseinheitItems();
+    this.organisationseinheitItems$ = this.organisationseinheitService.get();
   }
 
   public openDialogForNewGroup(): void {
@@ -30,6 +31,6 @@ export class OrganisationseinheitContainerComponent implements OnInit {
   }
 
   public delete(organisationseinheit: Organisationseinheit): void {
-    this.deleteInProgress$ = this.userService.deleteOrganisationseinheit(organisationseinheit.id);
+    this.deleteInProgress$ = this.organisationseinheitService.delete(organisationseinheit.id);
   }
 }
diff --git a/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-form/organisationseinheit-form.component.html b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-form/organisationseinheit-form.component.html
index 8d00b44b3737090091e15a34e731f4168b12b601..3bd257438d0545a41b7b791b9574b1cf9184b009 100644
--- a/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-form/organisationseinheit-form.component.html
+++ b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-form/organisationseinheit-form.component.html
@@ -1,3 +1,4 @@
+<ng-container *ngIf="submitInProgress$ | async"></ng-container>
 <dialog #OrganisationseinheitDialog data-test-id="organisationseinheit-dialog" class="bg-gray-50">
   <button
     (click)="OrganisationseinheitDialog.close()"
@@ -21,13 +22,13 @@
       [formControlName]="OrganisationseinheitFormService.ORGANISATIONSEINHEIT_IDS_FIELD"
     ></text-field>
 
-    <admin-primary-button
+    <ods-button-with-spinner
       data-test-id="organisationseinheit-save-button"
       class="justify-self-end"
       (clickEmitter)="submit()"
-      [submitInProgress]="submitInProgress$ | async"
-      label="Speichern"
+      [stateResource]="organisationseinheitItems"
+      text="Speichern"
     >
-    </admin-primary-button>
+    </ods-button-with-spinner>
   </form>
 </dialog>
diff --git a/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-form/organisationseinheit-form.component.spec.ts b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-form/organisationseinheit-form.component.spec.ts
index 0418653a9be772a8adc99ba50aa1a7f4dfda142f..fd81569ecb52fceecb829096f4e859aeb73fad36 100644
--- a/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-form/organisationseinheit-form.component.spec.ts
+++ b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-form/organisationseinheit-form.component.spec.ts
@@ -1,3 +1,4 @@
+import { createEmptyStateResource } from '@alfa-client/tech-shared';
 import {
   dispatchEventFromFixture,
   getDebugElementFromFixtureByCss,
@@ -7,29 +8,24 @@ import {
 } from '@alfa-client/test-utils';
 import { DebugElement } from '@angular/core';
 import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
-import {
-  AbstractControl,
-  FormsModule,
-  ReactiveFormsModule,
-  UntypedFormGroup,
-} from '@angular/forms';
+import { AbstractControl, FormsModule, ReactiveFormsModule, UntypedFormGroup } from '@angular/forms';
+import { ButtonWithSpinnerComponent } from '@ods/component';
 import { getDataTestIdOf } from 'libs/tech-shared/test/data-test';
 import { MockComponent, ngMocks } from 'ng-mocks';
 import { of, throwError } from 'rxjs';
 import { createOrganisationseinheit } from '../../../../../test/user/user';
-import { PrimaryButtonComponent } from '../../../shared/primary-button/primary-button.component';
 import { TextFieldComponent } from '../../../shared/text-field/text-field.component';
 import { Organisationseinheit } from '../../../user/user.model';
-import { UserService } from '../../../user/user.service';
+import { OrganisationseinheitService } from '../../organisationseinheit.service';
 import { OrganisationseinheitFormComponent } from './organisationseinheit-form.component';
-import { OrganisationseinheitFormservice } from './organisationseinheit.formservice';
+import { OrganisationseinheitFormService } from './organisationseinheit-form.service';
 
 describe('OrganisationseinheitFormComponent', () => {
   let component: OrganisationseinheitFormComponent;
   let fixture: ComponentFixture<OrganisationseinheitFormComponent>;
   let form: UntypedFormGroup;
 
-  const userService: Mock<UserService> = mock(UserService);
+  const organisationseinheitService: Mock<OrganisationseinheitService> = mock(OrganisationseinheitService);
 
   const saveButtonSelector: string = getDataTestIdOf('organisationseinheit-save-button');
   const closeButtonSelector: string = getDataTestIdOf('organisationseinheit-close-button');
@@ -39,11 +35,11 @@ describe('OrganisationseinheitFormComponent', () => {
     await TestBed.configureTestingModule({
       declarations: [
         OrganisationseinheitFormComponent,
-        MockComponent(PrimaryButtonComponent),
         MockComponent(TextFieldComponent),
+        MockComponent(ButtonWithSpinnerComponent),
       ],
-      imports: [ReactiveFormsModule, FormsModule],
-      providers: [{ provide: UserService, useValue: userService }],
+      imports: [ReactiveFormsModule, FormsModule, ButtonWithSpinnerComponent],
+      providers: [{ provide: OrganisationseinheitService, useValue: organisationseinheitService }],
     }).compileComponents();
 
     fixture = TestBed.createComponent(OrganisationseinheitFormComponent);
@@ -61,47 +57,30 @@ describe('OrganisationseinheitFormComponent', () => {
 
   describe('form element', () => {
     const fields: string[][] = [
-      [
-        OrganisationseinheitFormservice.ORGANISATIONSEINHEIT_NAME_FIELD,
-        'Name',
-        'organisationseinheit-name',
-      ],
-      [
-        OrganisationseinheitFormservice.ORGANISATIONSEINHEIT_IDS_FIELD,
-        'OrganisationseinheitID',
-        'organisationseinheit-id',
-      ],
+      [OrganisationseinheitFormService.ORGANISATIONSEINHEIT_NAME_FIELD, 'Name', 'organisationseinheit-name'],
+      [OrganisationseinheitFormService.ORGANISATIONSEINHEIT_IDS_FIELD, 'OrganisationseinheitID', 'organisationseinheit-id'],
     ];
 
-    it.each(fields)(
-      'should have label for field "%s" with name "%s"',
-      (fieldName: string, text: string, inputId: string) => {
-        const textFieldElement = getElementFromFixture(fixture, getDataTestIdOf(inputId));
-        expect(textFieldElement.getAttribute('label')).toBe(text);
-      },
-    );
+    it.each(fields)('should have label for field "%s" with name "%s"', (fieldName: string, text: string, inputId: string) => {
+      const textFieldElement = getElementFromFixture(fixture, getDataTestIdOf(inputId));
+      expect(textFieldElement.getAttribute('label')).toBe(text);
+    });
 
     it.each(fields)('should bind form for text-field "%s"', (fieldName, text, dataTestId) => {
       const fieldValue: string = `some text-field ${text}`;
       const formControl: AbstractControl = form.get(fieldName);
 
-      const textFieldComponent: DebugElement = getDebugElementFromFixtureByCss(
-        fixture,
-        getDataTestIdOf(dataTestId),
-      );
+      const textFieldComponent: DebugElement = getDebugElementFromFixtureByCss(fixture, getDataTestIdOf(dataTestId));
       ngMocks.change(textFieldComponent, fieldValue);
       expect(formControl.value).toBe(fieldValue);
     });
   });
 
   describe('save button', () => {
-    let saveButtonComponent: PrimaryButtonComponent;
+    let saveButtonComponent: ButtonWithSpinnerComponent;
 
     beforeEach(() => {
-      saveButtonComponent = getDebugElementFromFixtureByCss(
-        fixture,
-        saveButtonSelector,
-      ).componentInstance;
+      saveButtonComponent = getDebugElementFromFixtureByCss(fixture, saveButtonSelector).componentInstance;
     });
 
     it('should call submit on click', () => {
@@ -112,20 +91,20 @@ describe('OrganisationseinheitFormComponent', () => {
       expect(component.submit).toHaveBeenCalled();
     });
 
-    it('should be disabled while in progress', () => {
-      component.submitInProgress$ = of(true);
+    it('should be disabled while stateResource in loading', () => {
+      component.organisationseinheitItems = createEmptyStateResource(true);
 
       fixture.detectChanges();
 
-      expect(saveButtonComponent.submitInProgress).toBe(true);
+      expect(saveButtonComponent.stateResource.loading).toBe(true);
     });
 
     it('should be enabled while not in progress', () => {
-      component.submitInProgress$ = of(false);
+      component.organisationseinheitItems = createEmptyStateResource(false);
 
       fixture.detectChanges();
 
-      expect(saveButtonComponent.submitInProgress).toBe(false);
+      expect(saveButtonComponent.stateResource.loading).toBe(false);
     });
   });
 
@@ -157,15 +136,16 @@ describe('OrganisationseinheitFormComponent', () => {
     }));
 
     it.each([true, false])('should use submit progress "%s"', (progress) => {
-      component.submitInProgress$ = of(progress);
+      component.organisationseinheitItems = createEmptyStateResource(progress);
 
       fixture.detectChanges();
 
-      const saveButtonComponent: PrimaryButtonComponent = getDebugElementFromFixtureByCss(
+      const saveButtonComponent: ButtonWithSpinnerComponent = getDebugElementFromFixtureByCss(
         fixture,
         saveButtonSelector,
       ).componentInstance;
-      expect(saveButtonComponent.submitInProgress).toBe(progress);
+
+      expect(saveButtonComponent.stateResource.loading).toBe(progress);
     });
   });
 
diff --git a/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-form/organisationseinheit-form.component.ts b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-form/organisationseinheit-form.component.ts
index 5224f6db0c0c1abd27fba74b2adc3067fe00a460..4f4976209bc7976af17a5ce954585efbcffaff15 100644
--- a/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-form/organisationseinheit-form.component.ts
+++ b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-form/organisationseinheit-form.component.ts
@@ -1,18 +1,21 @@
-import { AfterViewInit, Component, ElementRef, ViewChild } from '@angular/core';
+import { StateResource, createStateResource } from '@alfa-client/tech-shared';
+import { AfterViewInit, Component, ElementRef, Input, ViewChild } from '@angular/core';
 import { Observable, of, tap } from 'rxjs';
 import { Organisationseinheit } from '../../../user/user.model';
-import { OrganisationseinheitFormservice } from './organisationseinheit.formservice';
+import { OrganisationseinheitFormService } from './organisationseinheit-form.service';
 
 @Component({
   selector: 'admin-organisationseinheit-form',
   templateUrl: './organisationseinheit-form.component.html',
-  providers: [OrganisationseinheitFormservice],
+  providers: [OrganisationseinheitFormService],
 })
 export class OrganisationseinheitFormComponent implements AfterViewInit {
+  @Input() organisationseinheitItems: StateResource<Organisationseinheit[]> = createStateResource([]);
+
   static CREATE_LABEL: string = 'Neue Organisationseinheit anlegen';
   static EDIT_LABEL: string = 'Organisationseinheit bearbeiten';
 
-  protected readonly OrganisationseinheitFormService = OrganisationseinheitFormservice;
+  protected readonly OrganisationseinheitFormService = OrganisationseinheitFormService;
 
   @ViewChild('OrganisationseinheitDialog') private dialogRef: ElementRef<HTMLDialogElement>;
   dialog: HTMLDialogElement;
@@ -21,16 +24,14 @@ export class OrganisationseinheitFormComponent implements AfterViewInit {
 
   label: string;
 
-  constructor(public formService: OrganisationseinheitFormservice) {}
+  constructor(public formService: OrganisationseinheitFormService) {}
 
   ngAfterViewInit(): void {
     this.dialog = this.dialogRef.nativeElement;
   }
 
   public submit() {
-    this.submitInProgress$ = this.formService
-      .submit()
-      .pipe(tap((progress: boolean) => this.handleProgressChange(progress)));
+    this.submitInProgress$ = this.formService.submit().pipe(tap((progress: boolean) => this.handleProgressChange(progress)));
   }
 
   handleProgressChange(progress: boolean): void {
diff --git a/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-form/organisationseinheit.formservice.ts b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-form/organisationseinheit-form.service.ts
similarity index 67%
rename from alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-form/organisationseinheit.formservice.ts
rename to alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-form/organisationseinheit-form.service.ts
index 850b5f775f723f0b27073ac5de0b99d7a2c877e8..fb65fa06cc6959e5df3f029f7e2894307d140d43 100644
--- a/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-form/organisationseinheit.formservice.ts
+++ b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-form/organisationseinheit-form.service.ts
@@ -1,17 +1,15 @@
-import { isNotNil } from '@alfa-client/tech-shared';
-import { Injectable } from '@angular/core';
+import { createStateResource, isNotNil, StateResource } from '@alfa-client/tech-shared';
+import { Injectable, Input } from '@angular/core';
 import { AbstractControl, FormControl, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
-import { Observable, catchError, of } from 'rxjs';
-import {
-  Organisationseinheit,
-  OrganisationseinheitError,
-  OrganisationseinheitErrorType,
-} from '../../../user/user.model';
-import { UserService } from '../../../user/user.service';
+import { catchError, Observable, of } from 'rxjs';
+import { Organisationseinheit, OrganisationseinheitError, OrganisationseinheitErrorType } from '../../../user/user.model';
 import { getOrganisationseinheitErrorMessage } from '../../../user/user.util';
+import { OrganisationseinheitService } from '../../organisationseinheit.service';
 
 @Injectable()
-export class OrganisationseinheitFormservice {
+export class OrganisationseinheitFormService {
+  @Input() organisationseinheitItems: StateResource<Organisationseinheit[]> = createStateResource([]);
+
   public static readonly ORGANISATIONSEINHEIT_NAME_FIELD: string = 'name';
   public static readonly ORGANISATIONSEINHEIT_IDS_FIELD: string = 'organisationseinheit';
 
@@ -21,11 +19,11 @@ export class OrganisationseinheitFormservice {
 
   constructor(
     private formBuilder: UntypedFormBuilder,
-    private userService: UserService,
+    private organisationsEinheitService: OrganisationseinheitService,
   ) {
     this.form = this.formBuilder.group({
-      [OrganisationseinheitFormservice.ORGANISATIONSEINHEIT_NAME_FIELD]: new FormControl(''),
-      [OrganisationseinheitFormservice.ORGANISATIONSEINHEIT_IDS_FIELD]: new FormControl(''),
+      [OrganisationseinheitFormService.ORGANISATIONSEINHEIT_NAME_FIELD]: new FormControl(''),
+      [OrganisationseinheitFormService.ORGANISATIONSEINHEIT_IDS_FIELD]: new FormControl(''),
     });
   }
 
@@ -47,14 +45,14 @@ export class OrganisationseinheitFormservice {
   }
 
   create(): Observable<boolean> {
-    return this.userService.createOrganisationseinheit(
-      this.getName(),
-      this.getOrganisationseinheitIds(),
-    );
+    return this.organisationsEinheitService.create({
+      name: this.getName(),
+      organisationseinheitIds: this.getOrganisationseinheitIds(),
+    });
   }
 
   save(): Observable<boolean> {
-    return this.userService.saveOrganisationseinheit({
+    return this.organisationsEinheitService.save({
       ...this.source,
       name: this.getName(),
       organisationseinheitIds: this.getOrganisationseinheitIds(),
@@ -65,7 +63,7 @@ export class OrganisationseinheitFormservice {
     let valid: boolean = true;
 
     if (this.getOrganisationseinheitIds().length == 0) {
-      this.setError(OrganisationseinheitFormservice.ORGANISATIONSEINHEIT_IDS_FIELD, {
+      this.setError(OrganisationseinheitFormService.ORGANISATIONSEINHEIT_IDS_FIELD, {
         errorType: OrganisationseinheitErrorType.ID_MISSING,
         detail: '',
       });
@@ -76,14 +74,12 @@ export class OrganisationseinheitFormservice {
   }
 
   private getName(): string {
-    return this.getStringFromPotentiallyEmptyField(
-      OrganisationseinheitFormservice.ORGANISATIONSEINHEIT_NAME_FIELD,
-    );
+    return this.getStringFromPotentiallyEmptyField(OrganisationseinheitFormService.ORGANISATIONSEINHEIT_NAME_FIELD);
   }
 
   private getOrganisationseinheitIds(): string[] {
     return this.splitOrganisationseinheitIds(
-      this.form.get(OrganisationseinheitFormservice.ORGANISATIONSEINHEIT_IDS_FIELD).value ?? '',
+      this.form.get(OrganisationseinheitFormService.ORGANISATIONSEINHEIT_IDS_FIELD).value ?? '',
     );
   }
 
@@ -100,7 +96,7 @@ export class OrganisationseinheitFormservice {
       error.errorType === OrganisationseinheitErrorType.NAME_CONFLICT ||
       error.errorType === OrganisationseinheitErrorType.NAME_MISSING
     ) {
-      this.setError(OrganisationseinheitFormservice.ORGANISATIONSEINHEIT_NAME_FIELD, error);
+      this.setError(OrganisationseinheitFormService.ORGANISATIONSEINHEIT_NAME_FIELD, error);
     }
   }
 
@@ -122,9 +118,8 @@ export class OrganisationseinheitFormservice {
     this.reset();
     this.source = organisationseinheit;
     this.form.patchValue({
-      [OrganisationseinheitFormservice.ORGANISATIONSEINHEIT_NAME_FIELD]: organisationseinheit.name,
-      [OrganisationseinheitFormservice.ORGANISATIONSEINHEIT_IDS_FIELD]:
-        organisationseinheit.organisationseinheitIds.join(', '),
+      [OrganisationseinheitFormService.ORGANISATIONSEINHEIT_NAME_FIELD]: organisationseinheit.name,
+      [OrganisationseinheitFormService.ORGANISATIONSEINHEIT_IDS_FIELD]: organisationseinheit.organisationseinheitIds.join(', '),
     });
   }
 
diff --git a/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-form/organisationseinheit.formservice.spec.ts b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-form/organisationseinheit.formservice.spec.ts
index c43144f6a8730dd6c81ed73aaef73aa4f0b4b5ef..30b0562d0e2ab18a08381eb1bded287beb3dcd68 100644
--- a/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-form/organisationseinheit.formservice.spec.ts
+++ b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-form/organisationseinheit.formservice.spec.ts
@@ -1,36 +1,29 @@
 import { Mock, mock, useFromMock } from '@alfa-client/test-utils';
+import { Type } from '@angular/core';
 import { fakeAsync, tick } from '@angular/core/testing';
 import { AbstractControl, FormBuilder } from '@angular/forms';
 import { hot } from 'jest-marbles';
 import { singleCold, singleHot } from 'libs/tech-shared/test/marbles';
 import { Observable, lastValueFrom, throwError } from 'rxjs';
-import {
-  createOrganisationseinheit,
-  createOrganisationseinheitError,
-} from '../../../../../test/user/user';
-import {
-  Organisationseinheit,
-  OrganisationseinheitError,
-  OrganisationseinheitErrorType,
-} from '../../../user/user.model';
-import { UserService } from '../../../user/user.service';
+import { createOrganisationseinheit, createOrganisationseinheitError } from '../../../../../test/user/user';
+import { Organisationseinheit, OrganisationseinheitError, OrganisationseinheitErrorType } from '../../../user/user.model';
 import { getOrganisationseinheitErrorMessage } from '../../../user/user.util';
-import { OrganisationseinheitFormservice } from './organisationseinheit.formservice';
+import { OrganisationseinheitService } from '../../organisationseinheit.service';
+import { OrganisationseinheitFormService } from './organisationseinheit-form.service';
 
 describe('OrganisationseinheitFormService', () => {
-  let formService: OrganisationseinheitFormservice;
+  let formService: OrganisationseinheitFormService;
   let organisationseinheit: Organisationseinheit;
-  const userService: Mock<UserService> = mock(UserService);
+  const organisationseinheitService: Mock<OrganisationseinheitService> = mockResourceService(OrganisationseinheitService);
 
   const formBuilder: FormBuilder = new FormBuilder();
 
   beforeEach(() => {
-    formService = new OrganisationseinheitFormservice(formBuilder, useFromMock(userService));
+    formService = new OrganisationseinheitFormService(formBuilder, useFromMock(organisationseinheitService));
     organisationseinheit = createOrganisationseinheit();
     formService.form.setValue({
-      [OrganisationseinheitFormservice.ORGANISATIONSEINHEIT_NAME_FIELD]: organisationseinheit.name,
-      [OrganisationseinheitFormservice.ORGANISATIONSEINHEIT_IDS_FIELD]:
-        organisationseinheit.organisationseinheitIds.join(','),
+      [OrganisationseinheitFormService.ORGANISATIONSEINHEIT_NAME_FIELD]: organisationseinheit.name,
+      [OrganisationseinheitFormService.ORGANISATIONSEINHEIT_IDS_FIELD]: organisationseinheit.organisationseinheitIds.join(','),
     });
   });
 
@@ -93,14 +86,13 @@ describe('OrganisationseinheitFormService', () => {
     const hasIdMissingError = () =>
       formService.form.hasError(
         OrganisationseinheitErrorType.ID_MISSING,
-        OrganisationseinheitFormservice.ORGANISATIONSEINHEIT_IDS_FIELD,
+        OrganisationseinheitFormService.ORGANISATIONSEINHEIT_IDS_FIELD,
       );
     describe('without organisationeinheitIds', () => {
       beforeEach(() => {
         formService.form.setValue({
-          [OrganisationseinheitFormservice.ORGANISATIONSEINHEIT_NAME_FIELD]:
-            organisationseinheit.name,
-          [OrganisationseinheitFormservice.ORGANISATIONSEINHEIT_IDS_FIELD]: ',',
+          [OrganisationseinheitFormService.ORGANISATIONSEINHEIT_NAME_FIELD]: organisationseinheit.name,
+          [OrganisationseinheitFormService.ORGANISATIONSEINHEIT_IDS_FIELD]: ',',
         });
       });
 
@@ -171,24 +163,27 @@ describe('OrganisationseinheitFormService', () => {
     it('should call create organisationseinheit', () => {
       formService.create();
 
-      expect(userService.createOrganisationseinheit).toHaveBeenCalledWith(
-        organisationseinheit.name,
-        organisationseinheit.organisationseinheitIds,
-      );
+      expect(organisationseinheitService.create).toHaveBeenCalledWith({
+        name: organisationseinheit.name,
+        organisationseinheitIds: organisationseinheit.organisationseinheitIds,
+      });
     });
 
     it('should call create organisationseinheit with empty form', () => {
       formService.form.setValue({
-        [OrganisationseinheitFormservice.ORGANISATIONSEINHEIT_NAME_FIELD]: null,
-        [OrganisationseinheitFormservice.ORGANISATIONSEINHEIT_IDS_FIELD]: null,
+        [OrganisationseinheitFormService.ORGANISATIONSEINHEIT_NAME_FIELD]: null,
+        [OrganisationseinheitFormService.ORGANISATIONSEINHEIT_IDS_FIELD]: null,
       });
       formService.create();
 
-      expect(userService.createOrganisationseinheit).toHaveBeenCalledWith('', []);
+      expect(organisationseinheitService.create).toHaveBeenCalledWith({
+        name: '',
+        organisationseinheitIds: [],
+      });
     });
 
     it('should return progress observable', () => {
-      userService.createOrganisationseinheit.mockReturnValue(singleCold(true));
+      organisationseinheitService.create.mockReturnValue(singleCold(true));
 
       const progressObservable: Observable<boolean> = formService.create();
 
@@ -202,7 +197,7 @@ describe('OrganisationseinheitFormService', () => {
 
       formService.save();
 
-      expect(userService.saveOrganisationseinheit).toHaveBeenCalledWith({
+      expect(organisationseinheitService.save).toHaveBeenCalledWith({
         id: formService.source.id,
         name: organisationseinheit.name,
         organisationseinheitIds: organisationseinheit.organisationseinheitIds,
@@ -212,12 +207,12 @@ describe('OrganisationseinheitFormService', () => {
     it('should call save organisationseinheit with empty form', () => {
       formService.source = createOrganisationseinheit();
       formService.form.setValue({
-        [OrganisationseinheitFormservice.ORGANISATIONSEINHEIT_NAME_FIELD]: null,
-        [OrganisationseinheitFormservice.ORGANISATIONSEINHEIT_IDS_FIELD]: null,
+        [OrganisationseinheitFormService.ORGANISATIONSEINHEIT_NAME_FIELD]: null,
+        [OrganisationseinheitFormService.ORGANISATIONSEINHEIT_IDS_FIELD]: null,
       });
       formService.save();
 
-      expect(userService.saveOrganisationseinheit).toHaveBeenCalledWith({
+      expect(organisationseinheitService.save).toHaveBeenCalledWith({
         id: formService.source.id,
         name: '',
         organisationseinheitIds: [],
@@ -225,7 +220,7 @@ describe('OrganisationseinheitFormService', () => {
     });
 
     it('should return progress observable', () => {
-      userService.saveOrganisationseinheit.mockReturnValue(singleCold(true));
+      organisationseinheitService.save.mockReturnValue(singleCold(true));
 
       const progressObservable: Observable<boolean> = formService.save();
 
@@ -234,22 +229,19 @@ describe('OrganisationseinheitFormService', () => {
   });
 
   describe('handle error', () => {
-    it.each([
-      OrganisationseinheitErrorType.NAME_CONFLICT,
-      OrganisationseinheitErrorType.NAME_MISSING,
-    ])('should set error on name field on %s', (type: OrganisationseinheitErrorType) => {
-      const error: OrganisationseinheitError = {
-        ...createOrganisationseinheitError(),
-        errorType: type,
-      };
-
-      formService.handleError(error);
-      const errorMessage = formService.form.getError(
-        type,
-        OrganisationseinheitFormservice.ORGANISATIONSEINHEIT_NAME_FIELD,
-      );
-      expect(errorMessage).toEqual(getOrganisationseinheitErrorMessage(error));
-    });
+    it.each([OrganisationseinheitErrorType.NAME_CONFLICT, OrganisationseinheitErrorType.NAME_MISSING])(
+      'should set error on name field on %s',
+      (type: OrganisationseinheitErrorType) => {
+        const error: OrganisationseinheitError = {
+          ...createOrganisationseinheitError(),
+          errorType: type,
+        };
+
+        formService.handleError(error);
+        const errorMessage = formService.form.getError(type, OrganisationseinheitFormService.ORGANISATIONSEINHEIT_NAME_FIELD);
+        expect(errorMessage).toEqual(getOrganisationseinheitErrorMessage(error));
+      },
+    );
 
     it('should not set error on name field for unknown errors', () => {
       const unknownError: OrganisationseinheitError = createOrganisationseinheitError(undefined);
@@ -280,33 +272,27 @@ describe('OrganisationseinheitFormService', () => {
     it('should set name', () => {
       formService.patch(organisationseinheit);
 
-      const formControl: AbstractControl = formService.form.get(
-        OrganisationseinheitFormservice.ORGANISATIONSEINHEIT_NAME_FIELD,
-      );
+      const formControl: AbstractControl = formService.form.get(OrganisationseinheitFormService.ORGANISATIONSEINHEIT_NAME_FIELD);
       expect(formControl.value).toEqual(organisationseinheit.name);
     });
 
     it('should set organisationseinheitIds', () => {
       formService.patch(organisationseinheit);
 
-      const formControl: AbstractControl = formService.form.get(
-        OrganisationseinheitFormservice.ORGANISATIONSEINHEIT_IDS_FIELD,
-      );
+      const formControl: AbstractControl = formService.form.get(OrganisationseinheitFormService.ORGANISATIONSEINHEIT_IDS_FIELD);
       expect(formControl.value).toEqual(organisationseinheit.organisationseinheitIds.join(', '));
     });
   });
 
   describe('split organisationseinheitIds by comma', () => {
     it('should return', () => {
-      const organisationseinheitIds: string[] =
-        formService.splitOrganisationseinheitIds('123, 555 ,  666');
+      const organisationseinheitIds: string[] = formService.splitOrganisationseinheitIds('123, 555 ,  666');
 
       expect(organisationseinheitIds).toEqual(['123', '555', '666']);
     });
 
     it('should filter empty organisationseinheitIds', () => {
-      const organisationseinheitIds: string[] =
-        formService.splitOrganisationseinheitIds(',55,,66,');
+      const organisationseinheitIds: string[] = formService.splitOrganisationseinheitIds(',55,,66,');
 
       expect(organisationseinheitIds).toEqual(['55', '66']);
     });
@@ -352,3 +338,7 @@ describe('OrganisationseinheitFormService', () => {
     });
   });
 });
+
+function mockResourceService<T>(service: Type<T>): Mock<T> {
+  return <Mock<T>>{ ...mock(service), create: jest.fn(), save: jest.fn() };
+}
diff --git a/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-list/organisationseinheit-list.component.html b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-list/organisationseinheit-list.component.html
index f26e6e0c0d028d7d8bf3b224279cf662d80e5603..35f04a2f2e65d9cd6354ccc65e4ebe980c7ad8bb 100644
--- a/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-list/organisationseinheit-list.component.html
+++ b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-list/organisationseinheit-list.component.html
@@ -1,52 +1,54 @@
-<table
-  *ngIf="organisationseinheitItems.length; else emptyMessage"
-  aria-label="Keycloak-Gruppen mit OrganisationseinheitIDs"
-  class="mb-2 mt-2 table-fixed"
-  data-test-id="organisationseinheit-table"
->
-  <tr class="invisible">
-    <th scope="col">Name</th>
-    <th scope="col">Attribute</th>
-  </tr>
-  <tr *ngFor="let organisationseinheit of organisationseinheitItems" [id]="organisationseinheit.id">
-    <td
-      [attr.data-test-id]="
-        'organisationseinheit-name-' + organisationseinheit.id | convertForDataTest
-      "
-      class="w-96 border border-slate-500 p-2 font-bold"
-    >
-      {{ organisationseinheit.name }}
-    </td>
-    <td
-      [attr.data-test-id]="
-        'organisationseinheit-attr-' + organisationseinheit.id | convertForDataTest
-      "
-      class="w-96 border border-slate-500 p-2"
-    >
-      OrganisationseinheitID: {{ organisationseinheit.organisationseinheitIds.join(', ') }}
-      <admin-more-menu class="float-right">
-        <admin-more-item-button
-          (clickEmitter)="editOrganisationseinheit.emit(organisationseinheit)"
-          more-menu-item
-          [attr.data-test-id]="
-            'organisationseinheit-edit-' + organisationseinheit.id | convertForDataTest
-          "
-          label="Bearbeiten"
-        ></admin-more-item-button>
-        <admin-more-item-button
-          (clickEmitter)="deleteOrganisationseinheit.emit(organisationseinheit)"
-          more-menu-item
-          [attr.data-test-id]="
-            'organisationseinheit-delete-' + organisationseinheit.id | convertForDataTest
-          "
-          label="Löschen"
-        ></admin-more-item-button>
-      </admin-more-menu>
-    </td>
-  </tr>
-</table>
-<ng-template #emptyMessage
-  ><span data-test-id="organisationseinheit-empty-message" class="mb-2 mt-2 block italic"
-    >Keine Organisationseinheiten vorhanden.</span
+<ng-container *ngIf="organisationseinheitItems.resource">
+  <table
+    *ngIf="organisationseinheitItems.resource.length; else emptyMessage"
+    aria-label="Keycloak-Gruppen mit OrganisationseinheitIDs"
+    class="mb-2 mt-2 table-fixed"
+    data-test-id="organisationseinheit-table"
   >
-</ng-template>
+    <tr class="invisible">
+      <th scope="col">Name</th>
+      <th scope="col">Attribute</th>
+    </tr>
+    <tr *ngFor="let organisationseinheit of organisationseinheitItems.resource" [id]="organisationseinheit.id">
+      <td
+        [attr.data-test-id]="
+          'organisationseinheit-name-' + organisationseinheit.id | convertForDataTest
+        "
+        class="w-96 border border-slate-500 p-2 font-bold"
+      >
+        {{ organisationseinheit.name }}
+      </td>
+      <td
+        [attr.data-test-id]="
+          'organisationseinheit-attr-' + organisationseinheit.id | convertForDataTest
+        "
+        class="w-96 border border-slate-500 p-2"
+      >
+        OrganisationseinheitID: {{ organisationseinheit.organisationseinheitIds.join(', ') }}
+        <admin-more-menu class="float-right">
+          <admin-more-item-button
+            (clickEmitter)="editOrganisationseinheit.emit(organisationseinheit)"
+            more-menu-item
+            [attr.data-test-id]="
+              'organisationseinheit-edit-' + organisationseinheit.id | convertForDataTest
+            "
+            label="Bearbeiten"
+          ></admin-more-item-button>
+          <admin-more-item-button
+            (clickEmitter)="deleteOrganisationseinheit.emit(organisationseinheit)"
+            more-menu-item
+            [attr.data-test-id]="
+              'organisationseinheit-delete-' + organisationseinheit.id | convertForDataTest
+            "
+            label="Löschen"
+          ></admin-more-item-button>
+        </admin-more-menu>
+      </td>
+    </tr>
+  </table>
+  <ng-template #emptyMessage
+    ><span data-test-id="organisationseinheit-empty-message" class="mb-2 mt-2 block italic"
+      >Keine Organisationseinheiten vorhanden.</span
+    >
+  </ng-template>
+</ng-container>
diff --git a/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-list/organisationseinheit-list.component.spec.ts b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-list/organisationseinheit-list.component.spec.ts
index 912a82f8a93e2865f011ec5a8f0c40905a910d85..53a1347003495d3b5501794c11b04af3f60008c7 100644
--- a/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-list/organisationseinheit-list.component.spec.ts
+++ b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-list/organisationseinheit-list.component.spec.ts
@@ -1,4 +1,9 @@
-import { ConvertForDataTestPipe, convertForDataTest } from '@alfa-client/tech-shared';
+import {
+  ConvertForDataTestPipe,
+  StateResource,
+  convertForDataTest,
+  createStateResource,
+} from '@alfa-client/tech-shared';
 import {
   dispatchEventFromFixture,
   existsAsHtmlElement,
@@ -57,10 +62,10 @@ describe('OrganisationseinheitListComponent', () => {
     });
 
     describe('with organisationseinheit items', () => {
-      const organisationseinheitItems: Organisationseinheit[] = [
+      const organisationseinheitItems: StateResource<Organisationseinheit[]> = createStateResource([
         createOrganisationseinheit(),
         createOrganisationseinheit(),
-      ];
+      ]);
       beforeEach(() => {
         component.organisationseinheitItems = organisationseinheitItems;
         fixture.detectChanges();
@@ -79,13 +84,13 @@ describe('OrganisationseinheitListComponent', () => {
         const rowIds: string[] = rows.map((row) => row.id);
 
         expect(rowIds).toEqual(
-          organisationseinheitItems.map(
+          organisationseinheitItems.resource.map(
             (organisationseinheit: Organisationseinheit) => organisationseinheit.id,
           ),
         );
       });
 
-      it.each(organisationseinheitItems)(
+      it.each(organisationseinheitItems.resource)(
         'should show name of organisationseinheit %#',
         (organisationseinheit: Organisationseinheit) => {
           const nameTableCell = getElementFromFixture(
@@ -97,7 +102,7 @@ describe('OrganisationseinheitListComponent', () => {
         },
       );
 
-      it.each(organisationseinheitItems)(
+      it.each(organisationseinheitItems.resource)(
         'should show organisationseinheitId of organisationseinheit %#',
         (organisationseinheit: Organisationseinheit) => {
           const attrTableCell = getElementFromFixture(
@@ -111,7 +116,7 @@ describe('OrganisationseinheitListComponent', () => {
         },
       );
 
-      it.each(organisationseinheitItems)(
+      it.each(organisationseinheitItems.resource)(
         'should emit editOrganisationseinheit %# on edit button click ',
         (organisationseinheit: Organisationseinheit) => {
           component.editOrganisationseinheit.emit = jest.fn();
@@ -128,7 +133,7 @@ describe('OrganisationseinheitListComponent', () => {
         },
       );
 
-      it.each(organisationseinheitItems)(
+      it.each(organisationseinheitItems.resource)(
         'should emit deleteOrganisationseinheit %# on delete button click ',
         (organisationseinheit: Organisationseinheit) => {
           component.deleteOrganisationseinheit.emit = jest.fn();
diff --git a/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-list/organisationseinheit-list.component.ts b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-list/organisationseinheit-list.component.ts
index dadd2f0401682461a67e76f73e79dfc09afb54be..39b105cb05759aad5be906fb7b78e7b0b167dcb6 100644
--- a/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-list/organisationseinheit-list.component.ts
+++ b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-container/organisationseinheit-list/organisationseinheit-list.component.ts
@@ -1,3 +1,4 @@
+import { createStateResource, StateResource } from '@alfa-client/tech-shared';
 import { Component, EventEmitter, Input, Output } from '@angular/core';
 import { Organisationseinheit } from '../../../user/user.model';
 
@@ -7,7 +8,7 @@ import { Organisationseinheit } from '../../../user/user.model';
 })
 export class OrganisationseinheitListComponent {
   @Input()
-  organisationseinheitItems: Organisationseinheit[] = [];
+  organisationseinheitItems: StateResource<Organisationseinheit[]> = createStateResource([]);
 
   @Output()
   editOrganisationseinheit: EventEmitter<Organisationseinheit> = new EventEmitter();
diff --git a/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-navigation-item/organisationseinheit-navigation-item.component.html b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-navigation-item/organisationseinheit-navigation-item.component.html
deleted file mode 100644
index 2e7a09a8541daa2e00417268ec67b4a43103702b..0000000000000000000000000000000000000000
--- a/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-navigation-item/organisationseinheit-navigation-item.component.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<admin-navigation-item
-  name="Organisationseinheiten"
-  imageSrc="/assets/organisationseinheit.svg"
-  link="/organisationseinheiten"
-></admin-navigation-item>
diff --git a/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-navigation-item/organisationseinheit-navigation-item.component.spec.ts b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-navigation-item/organisationseinheit-navigation-item.component.spec.ts
deleted file mode 100644
index b855265b14e0b5ec4e03e1db4b4af27cd1528b23..0000000000000000000000000000000000000000
--- a/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-navigation-item/organisationseinheit-navigation-item.component.spec.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-import { NavigationItemComponent } from '@admin-client/admin-settings';
-import { ComponentFixture, TestBed } from '@angular/core/testing';
-import { MockComponent } from 'ng-mocks';
-import { OrganisationseinheitNavigationItemComponent } from './organisationseinheit-navigation-item.component';
-
-describe('OrganisationseinheitNavigationItemComponent', () => {
-  let component: OrganisationseinheitNavigationItemComponent;
-  let fixture: ComponentFixture<OrganisationseinheitNavigationItemComponent>;
-
-  beforeEach(async () => {
-    await TestBed.configureTestingModule({
-      declarations: [
-        OrganisationseinheitNavigationItemComponent,
-        MockComponent(NavigationItemComponent),
-      ],
-    }).compileComponents();
-  });
-
-  beforeEach(() => {
-    fixture = TestBed.createComponent(OrganisationseinheitNavigationItemComponent);
-    component = fixture.componentInstance;
-
-    fixture.detectChanges();
-  });
-
-  it('should create', () => {
-    expect(component).toBeTruthy();
-  });
-});
diff --git a/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-navigation-item/organisationseinheit-navigation-item.component.ts b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-navigation-item/organisationseinheit-navigation-item.component.ts
deleted file mode 100644
index 6e66cbe44e49519c4b169c18067059807d11216a..0000000000000000000000000000000000000000
--- a/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit-navigation-item/organisationseinheit-navigation-item.component.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import { Component } from '@angular/core';
-
-@Component({
-  selector: 'admin-organisationseinheit-navigation-item',
-  templateUrl: './organisationseinheit-navigation-item.component.html',
-})
-export class OrganisationseinheitNavigationItemComponent {}
diff --git a/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit.service.spec.ts b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit.service.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..4e16cd2a3421cac02ddcd38e472322fc5942e808
--- /dev/null
+++ b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit.service.spec.ts
@@ -0,0 +1,48 @@
+import { mock, Mock, useFromMock } from '@alfa-client/test-utils';
+import { createOrganisationseinheit } from '../../../test/user/user';
+import { UserRepository } from '../user/user.repository.service';
+import { OrganisationseinheitService } from './organisationseinheit.service';
+
+describe('OrganisationseinheitService', () => {
+  let service: OrganisationseinheitService;
+  let repository: Mock<UserRepository>;
+
+  const organisationseinheit = createOrganisationseinheit();
+
+  beforeEach(() => {
+    repository = mock(UserRepository);
+    service = new OrganisationseinheitService(useFromMock(repository));
+  });
+
+  describe('getItemsFromKeycloak', () => {
+    it('should call findOrganisationseinheitItems from userRepository', () => {
+      service.getItemsFromKeycloak();
+
+      expect(repository.findOrganisationseinheitItems).toHaveBeenCalled();
+    });
+  });
+
+  describe('saveInKeycloak', () => {
+    it('should call saveOrganisationseinheit from userRepository', () => {
+      service.saveInKeycloak(organisationseinheit);
+
+      expect(repository.saveOrganisationseinheit).toHaveBeenCalledWith(organisationseinheit);
+    });
+  });
+
+  describe('createInKeycloak', () => {
+    it('should call createOrganisationseinheit from userRepository', () => {
+      service.createInKeycloak(organisationseinheit);
+
+      expect(repository.createOrganisationseinheit).toHaveBeenCalledWith(organisationseinheit);
+    });
+  });
+
+  describe('deleteInKeycloak', () => {
+    it('should call deleteOrganisationseinheit from userRepository', () => {
+      service.deleteInKeycloak(organisationseinheit.id);
+
+      expect(repository.deleteOrganisationseinheit).toHaveBeenCalledWith(organisationseinheit.id);
+    });
+  });
+});
diff --git a/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit.service.ts b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d07d400cdb35c40955a164a99bcd66faf933b911
--- /dev/null
+++ b/alfa-client/libs/admin/settings/src/lib/organisationseinheit/organisationseinheit.service.ts
@@ -0,0 +1,30 @@
+import { Injectable } from '@angular/core';
+import { Observable } from 'rxjs';
+import { KeycloakResourceService } from '../user/keycloak.resource.service';
+import { Organisationseinheit } from '../user/user.model';
+import { UserRepository } from '../user/user.repository.service';
+
+@Injectable({
+  providedIn: 'root',
+})
+export class OrganisationseinheitService extends KeycloakResourceService<Organisationseinheit> {
+  constructor(private userRepository: UserRepository) {
+    super();
+  }
+
+  getItemsFromKeycloak(): Observable<Organisationseinheit[]> {
+    return this.userRepository.findOrganisationseinheitItems();
+  }
+
+  saveInKeycloak(organisationseinheit: Organisationseinheit): Observable<void> {
+    return this.userRepository.saveOrganisationseinheit(organisationseinheit);
+  }
+
+  createInKeycloak(organisationseinheit: { name: string; organisationseinheitIds: string[] }): Observable<Organisationseinheit> {
+    return this.userRepository.createOrganisationseinheit(organisationseinheit);
+  }
+
+  deleteInKeycloak(id: string): Observable<void> {
+    return this.userRepository.deleteOrganisationseinheit(id);
+  }
+}
diff --git a/alfa-client/libs/admin/settings/src/lib/postfach/postfach-navigation-item/postfach-navigation-item.component.html b/alfa-client/libs/admin/settings/src/lib/postfach/postfach-navigation-item/postfach-navigation-item.component.html
deleted file mode 100644
index c2dc7ea533bb1d807a8a73de12d273881e2e0053..0000000000000000000000000000000000000000
--- a/alfa-client/libs/admin/settings/src/lib/postfach/postfach-navigation-item/postfach-navigation-item.component.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<admin-navigation-item
-  name="Postfach"
-  imageSrc="/assets/mail.svg"
-  link="/postfach"
-></admin-navigation-item>
diff --git a/alfa-client/libs/admin/settings/src/lib/postfach/postfach-navigation-item/postfach-navigation-item.component.scss b/alfa-client/libs/admin/settings/src/lib/postfach/postfach-navigation-item/postfach-navigation-item.component.scss
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/alfa-client/libs/admin/settings/src/lib/postfach/postfach-navigation-item/postfach-navigation-item.component.spec.ts b/alfa-client/libs/admin/settings/src/lib/postfach/postfach-navigation-item/postfach-navigation-item.component.spec.ts
deleted file mode 100644
index 78ced8dcace6a475a7d5bda4c1f2d2be6a60171a..0000000000000000000000000000000000000000
--- a/alfa-client/libs/admin/settings/src/lib/postfach/postfach-navigation-item/postfach-navigation-item.component.spec.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-import { NavigationItemComponent } from '@admin-client/admin-settings';
-import { getMockComponent } from '@alfa-client/test-utils';
-import { ComponentFixture, TestBed } from '@angular/core/testing';
-import { MockComponent } from 'ng-mocks';
-import { SettingName } from '../../admin-settings.model';
-import { PostfachNavigationItemComponent } from './postfach-navigation-item.component';
-
-describe('PostfachNavigationItemComponent', () => {
-  let component: PostfachNavigationItemComponent;
-  let fixture: ComponentFixture<PostfachNavigationItemComponent>;
-
-  beforeEach(async () => {
-    await TestBed.configureTestingModule({
-      declarations: [PostfachNavigationItemComponent, MockComponent(NavigationItemComponent)],
-    }).compileComponents();
-
-    fixture = TestBed.createComponent(PostfachNavigationItemComponent);
-    component = fixture.componentInstance;
-    fixture.detectChanges();
-  });
-
-  it('should create', () => {
-    expect(component).toBeTruthy();
-  });
-
-  describe('navigation item component', () => {
-    let navigationItemComponent: NavigationItemComponent;
-
-    beforeEach(() => {
-      navigationItemComponent = getMockComponent(fixture, NavigationItemComponent);
-    });
-
-    it('should be called with name', () => {
-      expect(navigationItemComponent.name).toBe(SettingName.POSTFACH);
-    });
-
-    it('should be called with imageSrc', () => {
-      expect(navigationItemComponent.imageSrc).toBe('/assets/mail.svg');
-    });
-
-    it('should be called with link', () => {
-      expect(navigationItemComponent.link).toBe('/postfach');
-    });
-  });
-});
diff --git a/alfa-client/libs/admin/settings/src/lib/postfach/postfach-navigation-item/postfach-navigation-item.component.ts b/alfa-client/libs/admin/settings/src/lib/postfach/postfach-navigation-item/postfach-navigation-item.component.ts
deleted file mode 100644
index c5765cc3bf0b3170300d23383a9dead64714feb8..0000000000000000000000000000000000000000
--- a/alfa-client/libs/admin/settings/src/lib/postfach/postfach-navigation-item/postfach-navigation-item.component.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { Component } from '@angular/core';
-
-@Component({
-  selector: 'admin-postfach-navigation-item',
-  templateUrl: './postfach-navigation-item.component.html',
-  styleUrls: ['./postfach-navigation-item.component.scss'],
-})
-export class PostfachNavigationItemComponent {}
diff --git a/alfa-client/libs/admin/settings/src/lib/user/keycloak.resource.service.spec.ts b/alfa-client/libs/admin/settings/src/lib/user/keycloak.resource.service.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..421892f8c3e731bf0ba687c2468e844fb5fd460b
--- /dev/null
+++ b/alfa-client/libs/admin/settings/src/lib/user/keycloak.resource.service.spec.ts
@@ -0,0 +1,227 @@
+import { fakeAsync, tick } from '@angular/core/testing';
+import faker from '@faker-js/faker';
+import { cold } from 'jest-marbles';
+import { StateResource, createEmptyStateResource } from 'libs/tech-shared/src/lib/resource/resource.util';
+import { Dummy, createDummy } from 'libs/tech-shared/test/dummy';
+import { singleCold } from 'libs/tech-shared/test/marbles';
+import { Observable, of } from 'rxjs';
+import * as resourceUtil from '../../../../../tech-shared/src/lib/resource/resource.util';
+import { KeycloakResourceService } from './keycloak.resource.service';
+
+describe('KeycloakResourceService', () => {
+  let service: KeycloakResourceService<unknown>;
+
+  const id: string = faker.random.word();
+  const emptyStateResource: StateResource<unknown[]> = createEmptyStateResource<unknown[]>();
+  const dummyObject: Dummy = createDummy();
+  const dummyAction: Observable<Dummy> = of(dummyObject);
+
+  beforeEach(() => {
+    service = new TestResourceService();
+  });
+
+  describe('get', () => {
+    beforeEach(() => {
+      service.handleChanges = jest.fn();
+    });
+
+    it('should return stateResource as observable', (done) => {
+      service.get().subscribe((stateResource) => {
+        expect(stateResource).toBe(service.stateResource.value);
+        done();
+      });
+    });
+
+    it('should call handleChanges ', fakeAsync(() => {
+      service.get().subscribe();
+
+      expect(service.handleChanges).toHaveBeenCalled();
+    }));
+  });
+
+  describe('handleChanges', () => {
+    it('should call doIfLoadingRequired', () => {
+      const doIfLoadingRequired: jest.SpyInstance<boolean> = jest.spyOn(resourceUtil, 'doIfLoadingRequired');
+
+      service.handleChanges(emptyStateResource);
+
+      expect(doIfLoadingRequired).toHaveBeenCalled();
+    });
+  });
+
+  describe('loadResource', () => {
+    it('should call set loading', () => {
+      service.setLoading = jest.fn();
+
+      service.loadResource();
+
+      expect(service.setLoading).toHaveBeenCalled();
+    });
+
+    it('should update Resource', fakeAsync(() => {
+      const dummyItems = [createDummy(), createDummy()];
+      service.getItemsFromKeycloak = jest.fn().mockReturnValue(of(dummyItems));
+
+      service.loadResource();
+      tick();
+
+      expect(service.stateResource.value.resource).toEqual(dummyItems);
+    }));
+  });
+
+  describe('create', () => {
+    const saveObject: Dummy = createDummy();
+
+    it('should call handleLoading', () => {
+      service.handleLoading = jest.fn();
+
+      service.create(saveObject);
+
+      expect(service.handleLoading).toHaveBeenCalled();
+    });
+
+    it('should call createInKeycloak', () => {
+      service.createInKeycloak = jest.fn().mockReturnValue(of({}));
+
+      service.create(saveObject);
+
+      expect(service.createInKeycloak).toHaveBeenCalled();
+    });
+  });
+
+  describe('save', () => {
+    it('should call handleLoading', () => {
+      service.handleLoading = jest.fn();
+
+      service.save(dummyObject);
+
+      expect(service.handleLoading).toHaveBeenCalled();
+    });
+
+    it('should call createInKeycloak', () => {
+      service.saveInKeycloak = jest.fn().mockReturnValue(of({}));
+
+      service.save(dummyObject);
+
+      expect(service.saveInKeycloak).toHaveBeenCalled();
+    });
+  });
+
+  describe('delete', () => {
+    it('should call handleLoading', () => {
+      service.handleLoading = jest.fn();
+
+      service.delete(id);
+
+      expect(service.handleLoading).toHaveBeenCalled();
+    });
+
+    it('should call createInKeycloak', () => {
+      service.saveInKeycloak = jest.fn().mockReturnValue(of({}));
+
+      service.save(id);
+
+      expect(service.saveInKeycloak).toHaveBeenCalled();
+    });
+  });
+
+  describe('handleLoading', () => {
+    it('should set loading', () => {
+      service.handleLoading(dummyAction);
+
+      expect(service.stateResource.value.loading).toBe(true);
+    });
+
+    it('should call refreshAfterFirstEmit', () => {
+      service.refreshAfterFirstEmit = jest.fn().mockReturnValue(dummyAction);
+
+      service.handleLoading(dummyAction);
+
+      expect(service.refreshAfterFirstEmit).toHaveBeenCalled();
+    });
+
+    it('should call progress', () => {
+      service.progress = jest.fn().mockReturnValue(dummyAction);
+
+      service.handleLoading(dummyAction);
+
+      expect(service.progress).toHaveBeenCalled();
+    });
+  });
+
+  describe('refreshAfterFirstEmit', () => {
+    it('should call refresh after first emit', fakeAsync(() => {
+      service.refresh = jest.fn();
+
+      service.refreshAfterFirstEmit(dummyAction).subscribe();
+      tick();
+
+      expect(service.refresh).toHaveBeenCalled();
+    }));
+  });
+
+  describe('progress', () => {
+    it('should emit true at the start and false after first parameter emit', () => {
+      const result: Observable<boolean> = service.progress(cold('--x', { x: dummyObject }));
+
+      expect(result).toBeObservable(cold('a-b', { a: true, b: false }));
+    });
+  });
+
+  describe('setLoading', () => {
+    it('should set loading in state to true without parameter', () => {
+      service.setLoading();
+
+      expect(service.stateResource.value.loading).toEqual(true);
+    });
+
+    it('should set loading in state to false for parameter false', () => {
+      service.setLoading(false);
+
+      expect(service.stateResource.value.loading).toEqual(false);
+    });
+  });
+
+  describe('refresh', () => {
+    it('should set reload in state to true', () => {
+      service.refresh();
+
+      expect(service.stateResource.value.reload).toBe(true);
+    });
+
+    it('should clear resource in state', () => {
+      service.refresh();
+
+      expect(service.stateResource.value.resource).toBe(null);
+    });
+  });
+
+  describe('select resource', () => {
+    it('should return state resource', () => {
+      const stateResource = createEmptyStateResource<unknown[]>();
+      service.stateResource.next(stateResource);
+
+      const resource$: Observable<StateResource<unknown[]>> = service.selectResource();
+
+      expect(resource$).toBeObservable(singleCold(stateResource));
+    });
+  });
+});
+
+class TestResourceService extends KeycloakResourceService<unknown> {
+  getItemsFromKeycloak(): Observable<unknown[]> {
+    return of(null);
+  }
+
+  saveInKeycloak(): Observable<void> {
+    return of(null);
+  }
+
+  createInKeycloak(): Observable<void> {
+    return of(null);
+  }
+
+  deleteInKeycloak(): Observable<void> {
+    return of(null);
+  }
+}
diff --git a/alfa-client/libs/admin/settings/src/lib/user/keycloak.resource.service.ts b/alfa-client/libs/admin/settings/src/lib/user/keycloak.resource.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..bc62384b90ed390dccad35c9acb296d74ca3a1e0
--- /dev/null
+++ b/alfa-client/libs/admin/settings/src/lib/user/keycloak.resource.service.ts
@@ -0,0 +1,82 @@
+import { createEmptyStateResource, createStateResource, doIfLoadingRequired, StateResource } from '@alfa-client/tech-shared';
+import { BehaviorSubject, first, map, Observable, startWith, tap } from 'rxjs';
+
+export abstract class KeycloakResourceService<T> {
+  readonly stateResource: BehaviorSubject<StateResource<T[]>> = new BehaviorSubject(createEmptyStateResource());
+
+  public get(): Observable<StateResource<T[]>> {
+    return this.stateResource.asObservable().pipe(tap((stateResource) => this.handleChanges(stateResource)));
+  }
+
+  handleChanges(stateResource: StateResource<T[]>) {
+    doIfLoadingRequired(stateResource, () => this.loadResource());
+  }
+
+  loadResource(): void {
+    this.setLoading();
+    this.getItemsFromKeycloak()
+      .pipe(first())
+      .subscribe((items) => this.updateResource(items));
+  }
+
+  abstract getItemsFromKeycloak(): Observable<T[]>;
+
+  private updateResource(items: T[]): void {
+    this.stateResource.next(createStateResource(items));
+  }
+
+  public create(item: Partial<T>): Observable<boolean> {
+    return this.handleLoading(this.createInKeycloak(item));
+  }
+
+  abstract createInKeycloak(item: Partial<T>): Observable<T>;
+
+  public save(item: T): Observable<boolean> {
+    return this.handleLoading(this.saveInKeycloak(item));
+  }
+
+  abstract saveInKeycloak(item: T): Observable<void>;
+
+  public delete(id: string): Observable<boolean> {
+    return this.handleLoading(this.deleteInKeycloak(id));
+  }
+
+  abstract deleteInKeycloak(id: string): Observable<void>;
+
+  handleLoading(action: Observable<unknown>): Observable<boolean> {
+    this.setLoading();
+    return this.progress(this.refreshAfterFirstEmit(action));
+  }
+
+  refreshAfterFirstEmit(action: Observable<unknown>): Observable<unknown> {
+    return action.pipe(
+      first(),
+      tap(() => this.refresh()),
+    );
+  }
+
+  progress(action: Observable<unknown>): Observable<boolean> {
+    return action.pipe(
+      map(() => false),
+      startWith(true),
+    );
+  }
+
+  setLoading(loading: boolean = true): void {
+    this.stateResource.next({
+      ...this.stateResource.value,
+      loading,
+    });
+  }
+
+  refresh(): void {
+    this.stateResource.next({
+      ...createEmptyStateResource(),
+      reload: true,
+    });
+  }
+
+  public selectResource(): Observable<StateResource<T[]>> {
+    return this.stateResource.asObservable();
+  }
+}
diff --git a/alfa-client/libs/admin/settings/src/lib/user/to-user-name.pipe.spec.ts b/alfa-client/libs/admin/settings/src/lib/user/to-user-name.pipe.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..81012d2754951d89e18992d26fea0fd7b2248bf0
--- /dev/null
+++ b/alfa-client/libs/admin/settings/src/lib/user/to-user-name.pipe.spec.ts
@@ -0,0 +1,23 @@
+import { createUser } from '../../../test/user/user';
+import { ToUserNamePipe } from './to-user-name.pipe';
+import { User } from './user.model';
+
+describe('UserNamePipe', () => {
+  it('should return user name', () => {
+    const user: User = { ...createUser(), firstName: 'Max', lastName: 'Mustermann' };
+    const userNamePipe: ToUserNamePipe = new ToUserNamePipe();
+
+    const result: string = userNamePipe.transform(user);
+
+    expect(result).toBe('Max Mustermann');
+  });
+
+  it('should return username for user without firstName and lastName', () => {
+    const user: User = { ...createUser(), firstName: null, lastName: null };
+    const userNamePipe: ToUserNamePipe = new ToUserNamePipe();
+
+    const result: string = userNamePipe.transform(user);
+
+    expect(result).toBe(user.username);
+  });
+});
diff --git a/alfa-client/libs/admin/settings/src/lib/user/to-user-name.pipe.ts b/alfa-client/libs/admin/settings/src/lib/user/to-user-name.pipe.ts
new file mode 100644
index 0000000000000000000000000000000000000000..4711ff9e5d78eea721342923a296976dde6a0389
--- /dev/null
+++ b/alfa-client/libs/admin/settings/src/lib/user/to-user-name.pipe.ts
@@ -0,0 +1,13 @@
+import { Pipe, PipeTransform } from '@angular/core';
+import { User } from './user.model';
+
+@Pipe({
+  name: 'toUserName',
+  standalone: true,
+})
+export class ToUserNamePipe implements PipeTransform {
+  transform(user: User): string {
+    if (!user.firstName || !user.lastName) return user.username;
+    return `${user.firstName} ${user.lastName}`;
+  }
+}
diff --git a/alfa-client/libs/admin/settings/src/lib/user/user.model.ts b/alfa-client/libs/admin/settings/src/lib/user/user.model.ts
index 308e945aa9b0f900ccfc135eeb98f713efc7e5e7..742ca490a50a84a8f9026204e573bcf729bf3c30 100644
--- a/alfa-client/libs/admin/settings/src/lib/user/user.model.ts
+++ b/alfa-client/libs/admin/settings/src/lib/user/user.model.ts
@@ -4,12 +4,6 @@ export interface Organisationseinheit {
   organisationseinheitIds: string[];
 }
 
-export interface OrganisationseinheitState {
-  organisationseinheitItems: Organisationseinheit[];
-  loading: boolean;
-  updateRequired: boolean;
-}
-
 export enum OrganisationseinheitErrorType {
   NAME_CONFLICT = 'name-conflict',
   NAME_MISSING = 'name-missing',
@@ -20,3 +14,13 @@ export interface OrganisationseinheitError {
   errorType: OrganisationseinheitErrorType;
   detail: string;
 }
+
+export interface User {
+  id: string;
+  username: string;
+  email: string;
+  firstName: string;
+  lastName: string;
+  groups?: string[];
+  roles?: string[];
+}
diff --git a/alfa-client/libs/admin/settings/src/lib/user/user.repository.service.ts b/alfa-client/libs/admin/settings/src/lib/user/user.repository.service.ts
index 293806db24c520afa4b0907811092ee0bf023979..5415be30358d129923f64c6f837885a5d78e2fd4 100644
--- a/alfa-client/libs/admin/settings/src/lib/user/user.repository.service.ts
+++ b/alfa-client/libs/admin/settings/src/lib/user/user.repository.service.ts
@@ -2,9 +2,13 @@ import { Injectable } from '@angular/core';
 import KcAdminClient, { NetworkError } from '@keycloak/keycloak-admin-client';
 import { TokenProvider } from '@keycloak/keycloak-admin-client/lib/client';
 import GroupRepresentation from '@keycloak/keycloak-admin-client/lib/defs/groupRepresentation';
+import MappingsRepresentation from '@keycloak/keycloak-admin-client/lib/defs/mappingsRepresentation';
+import RoleRepresentation from '@keycloak/keycloak-admin-client/lib/defs/roleRepresentation';
+import UserRepresentation from '@keycloak/keycloak-admin-client/lib/defs/userRepresentation';
 import { OAuthService } from 'angular-oauth2-oidc';
-import { Observable, OperatorFunction, catchError, from, map, throwError } from 'rxjs';
-import { Organisationseinheit, OrganisationseinheitError } from './user.model';
+import { isNil } from 'lodash-es';
+import { Observable, OperatorFunction, catchError, forkJoin, from, map, mergeMap, throwError } from 'rxjs';
+import { Organisationseinheit, OrganisationseinheitError, User } from './user.model';
 import { KEYCLOAK_CREATE_GROUPS_ERROR_STATUS } from './user.util';
 
 @Injectable({
@@ -35,9 +39,7 @@ export class UserRepository {
   public findOrganisationseinheitItems(): Observable<Organisationseinheit[]> {
     return from(this.kcAdminClient.groups.find({ briefRepresentation: false })).pipe(
       map((reps: GroupRepresentation[]) =>
-        reps.map((rep: GroupRepresentation) =>
-          this.mapGroupRepresentationToOrganisationseinheit(rep),
-        ),
+        reps.map((rep: GroupRepresentation) => this.mapGroupRepresentationToOrganisationseinheit(rep)),
       ),
     );
   }
@@ -62,21 +64,20 @@ export class UserRepository {
     ).pipe(this.rethrowMappedGroupsError());
   }
 
-  public createOrganisationseinheit(
-    name: string,
-    organisationseinheitIds: string[],
-  ): Observable<Organisationseinheit> {
+  public createOrganisationseinheit(organisationseinheit: {
+    name: string;
+    organisationseinheitIds: string[];
+  }): Observable<Organisationseinheit> {
     return from(
       this.kcAdminClient.groups.create({
-        name,
-        attributes: { organisationseinheitId: organisationseinheitIds },
+        name: organisationseinheit.name,
+        attributes: { organisationseinheitId: organisationseinheit.organisationseinheitIds },
       }),
     ).pipe(
       map(
         ({ id }): Organisationseinheit => ({
+          ...organisationseinheit,
           id,
-          name,
-          organisationseinheitIds: organisationseinheitIds,
         }),
       ),
       this.rethrowMappedGroupsError(),
@@ -93,4 +94,53 @@ export class UserRepository {
       detail: error.responseData['errorMessage'] ?? '',
     };
   }
+
+  public getUsers(): Observable<User[]> {
+    return from(this.kcAdminClient.users.find()).pipe(
+      map((userReps: UserRepresentation[]) => userReps.map((userReps) => this.mapToUser(userReps))),
+      mergeMap((users) => forkJoin(users.map((users) => this.addInformationToUser(users)))),
+    );
+  }
+
+  mapToUser(userRepresentation: UserRepresentation): User {
+    return {
+      id: userRepresentation.id,
+      email: userRepresentation.email,
+      username: userRepresentation.username,
+      firstName: userRepresentation.firstName,
+      lastName: userRepresentation.lastName,
+      groups: null,
+      roles: null,
+    };
+  }
+
+  private addInformationToUser(user: User): Observable<User> {
+    return forkJoin([this.getUserGroups(user), this.getAlfaClientRoles(user)]).pipe(
+      map(([groups, roles]) => ({
+        ...user,
+        groups,
+        roles,
+      })),
+    );
+  }
+
+  private getUserGroups(user: User): Observable<string[]> {
+    return from(this.kcAdminClient.users.listGroups({ id: user.id })).pipe(
+      map((groups: GroupRepresentation[]) => groups.map((group) => group.name)),
+    );
+  }
+
+  private getAlfaClientRoles(user: User): Observable<string[]> {
+    return from(this.kcAdminClient.users.listRoleMappings({ id: user.id })).pipe(
+      map((clientMappings: MappingsRepresentation) => this.mapToAlfaClientRoleNames(clientMappings)),
+    );
+  }
+
+  private mapToAlfaClientRoleNames(roleMappings: MappingsRepresentation): string[] {
+    if (isNil(roleMappings?.clientMappings?.['alfa'])) {
+      return [];
+    }
+
+    return roleMappings.clientMappings['alfa'].mappings.map((role: RoleRepresentation) => role.name);
+  }
 }
diff --git a/alfa-client/libs/admin/settings/src/lib/user/user.repository.spec.ts b/alfa-client/libs/admin/settings/src/lib/user/user.repository.spec.ts
index 47926c8e111e9ab28bc517ef13add588011b0d1e..ef000f8630a3fd9990283d882b023b30e253a060 100644
--- a/alfa-client/libs/admin/settings/src/lib/user/user.repository.spec.ts
+++ b/alfa-client/libs/admin/settings/src/lib/user/user.repository.spec.ts
@@ -4,6 +4,7 @@ import { faker } from '@faker-js/faker';
 import KcAdminClient, { NetworkError } from '@keycloak/keycloak-admin-client';
 import { TokenProvider } from '@keycloak/keycloak-admin-client/lib/client';
 import GroupRepresentation from '@keycloak/keycloak-admin-client/lib/defs/groupRepresentation';
+import MappingsRepresentation from '@keycloak/keycloak-admin-client/lib/defs/mappingsRepresentation';
 import { Groups } from '@keycloak/keycloak-admin-client/lib/resources/groups';
 import { OAuthService } from 'angular-oauth2-oidc';
 import { Observable, OperatorFunction, catchError, firstValueFrom, of, throwError } from 'rxjs';
@@ -12,12 +13,9 @@ import {
   createNetworkError,
   createOrganisationseinheit,
   createOrganisationseinheitError,
+  createUser,
 } from '../../../test/user/user';
-import {
-  Organisationseinheit,
-  OrganisationseinheitError,
-  OrganisationseinheitErrorType,
-} from './user.model';
+import { Organisationseinheit, OrganisationseinheitError, OrganisationseinheitErrorType, User } from './user.model';
 import { UserRepository } from './user.repository.service';
 
 describe('UserRepository', () => {
@@ -62,42 +60,36 @@ describe('UserRepository', () => {
   });
 
   describe('map organisationseinheit representation', () => {
-    let expectedOrganisationseinheit: Organisationseinheit = createOrganisationseinheit();
+    const expectedOrganisationseinheit: Organisationseinheit = createOrganisationseinheit();
 
     it('should map field "id"', () => {
-      const organisationseinheit: Organisationseinheit =
-        repository.mapGroupRepresentationToOrganisationseinheit({
-          id: expectedOrganisationseinheit.id,
-        });
+      const organisationseinheit: Organisationseinheit = repository.mapGroupRepresentationToOrganisationseinheit({
+        id: expectedOrganisationseinheit.id,
+      });
 
       expect(organisationseinheit.id).toEqual(expectedOrganisationseinheit.id);
     });
 
     it('should map field "name"', () => {
-      const organisationseinheit: Organisationseinheit =
-        repository.mapGroupRepresentationToOrganisationseinheit({
-          name: expectedOrganisationseinheit.name,
-        });
+      const organisationseinheit: Organisationseinheit = repository.mapGroupRepresentationToOrganisationseinheit({
+        name: expectedOrganisationseinheit.name,
+      });
 
       expect(organisationseinheit.name).toEqual(expectedOrganisationseinheit.name);
     });
 
     it('should map field "organisationseinheitIds"', () => {
-      const organisationseinheit: Organisationseinheit =
-        repository.mapGroupRepresentationToOrganisationseinheit({
-          attributes: {
-            organisationseinheitId: expectedOrganisationseinheit.organisationseinheitIds,
-          },
-        });
+      const organisationseinheit: Organisationseinheit = repository.mapGroupRepresentationToOrganisationseinheit({
+        attributes: {
+          organisationseinheitId: expectedOrganisationseinheit.organisationseinheitIds,
+        },
+      });
 
-      expect(organisationseinheit.organisationseinheitIds).toEqual(
-        expectedOrganisationseinheit.organisationseinheitIds,
-      );
+      expect(organisationseinheit.organisationseinheitIds).toEqual(expectedOrganisationseinheit.organisationseinheitIds);
     });
 
     it('should map missing organisationseinheitIds to empty list', () => {
-      const organisationseinheit: Organisationseinheit =
-        repository.mapGroupRepresentationToOrganisationseinheit({});
+      const organisationseinheit: Organisationseinheit = repository.mapGroupRepresentationToOrganisationseinheit({});
 
       expect(organisationseinheit.organisationseinheitIds).toEqual([]);
     });
@@ -110,16 +102,13 @@ describe('UserRepository', () => {
       createOrganisationseinheit(),
     ];
 
-    const groupReps: GroupRepresentation[] =
-      organisationseinheitItems.map(createGroupRepresentation);
+    const groupReps: GroupRepresentation[] = organisationseinheitItems.map(createGroupRepresentation);
 
     it('should return mapped organisationseinheit search result', async () => {
       const findMock: jest.Mock = jest.fn().mockReturnValue(Promise.resolve(groupReps));
       mockGroupsFunc('find', findMock);
 
-      const groupsResult: Organisationseinheit[] = await firstValueFrom(
-        repository.findOrganisationseinheitItems(),
-      );
+      const groupsResult: Organisationseinheit[] = await firstValueFrom(repository.findOrganisationseinheitItems());
 
       expect(groupsResult).toEqual(groupsResult);
     });
@@ -167,9 +156,7 @@ describe('UserRepository', () => {
     it('should pipe rethrowMappedGroupsError', (done) => {
       const updateMock: jest.Mock = jest.fn(() => Promise.reject(networkError));
       mockGroupsFunc('update', updateMock);
-      repository.rethrowMappedGroupsError = jest
-        .fn()
-        .mockReturnValue(catchError(() => throwError(() => error)));
+      repository.rethrowMappedGroupsError = jest.fn().mockReturnValue(catchError(() => throwError(() => error)));
 
       repository.saveOrganisationseinheit(saveGroup).subscribe({
         error: (err) => {
@@ -188,10 +175,10 @@ describe('UserRepository', () => {
       mockGroupsFunc('create', createMock);
 
       await firstValueFrom(
-        repository.createOrganisationseinheit(
-          newOrganisationseinheit.name,
-          newOrganisationseinheit.organisationseinheitIds,
-        ),
+        repository.createOrganisationseinheit({
+          name: newOrganisationseinheit.name,
+          organisationseinheitIds: newOrganisationseinheit.organisationseinheitIds,
+        }),
       );
 
       expect(createMock).toHaveBeenCalledWith({
@@ -203,16 +190,14 @@ describe('UserRepository', () => {
     });
 
     it('should return mapped organisationseinheit result', async () => {
-      const createMock: jest.Mock = jest.fn(() =>
-        Promise.resolve({ id: newOrganisationseinheit.id }),
-      );
+      const createMock: jest.Mock = jest.fn(() => Promise.resolve({ id: newOrganisationseinheit.id }));
       mockGroupsFunc('create', createMock);
 
       const newGroupResult: Organisationseinheit = await firstValueFrom(
-        repository.createOrganisationseinheit(
-          newOrganisationseinheit.name,
-          newOrganisationseinheit.organisationseinheitIds,
-        ),
+        repository.createOrganisationseinheit({
+          name: newOrganisationseinheit.name,
+          organisationseinheitIds: newOrganisationseinheit.organisationseinheitIds,
+        }),
       );
 
       expect(newGroupResult).toEqual(newOrganisationseinheit);
@@ -221,15 +206,13 @@ describe('UserRepository', () => {
     it('should pipe rethrowMappedGroupsError', (done) => {
       const createMock: jest.Mock = jest.fn(() => Promise.reject(networkError));
       mockGroupsFunc('create', createMock);
-      repository.rethrowMappedGroupsError = jest
-        .fn()
-        .mockReturnValue(catchError(() => throwError(() => error)));
+      repository.rethrowMappedGroupsError = jest.fn().mockReturnValue(catchError(() => throwError(() => error)));
 
       repository
-        .createOrganisationseinheit(
-          newOrganisationseinheit.name,
-          newOrganisationseinheit.organisationseinheitIds,
-        )
+        .createOrganisationseinheit({
+          name: newOrganisationseinheit.name,
+          organisationseinheitIds: newOrganisationseinheit.organisationseinheitIds,
+        })
         .subscribe({
           error: (err) => {
             expect(err).toBe(error);
@@ -305,9 +288,7 @@ describe('UserRepository', () => {
     const deleteOrganisationseinheit: Organisationseinheit = createOrganisationseinheit();
 
     it('should call kcAdminClient.groups.del', async () => {
-      const delMock: jest.Mock = jest.fn(() =>
-        Promise.resolve({ id: deleteOrganisationseinheit.id }),
-      );
+      const delMock: jest.Mock = jest.fn(() => Promise.resolve({ id: deleteOrganisationseinheit.id }));
       mockGroupsFunc('del', delMock);
 
       await firstValueFrom(repository.deleteOrganisationseinheit(deleteOrganisationseinheit.id));
@@ -323,11 +304,75 @@ describe('UserRepository', () => {
         jest.fn(() => Promise.resolve(null)),
       );
 
-      const voidResult = await firstValueFrom(
-        repository.deleteOrganisationseinheit(deleteOrganisationseinheit.id),
-      );
+      const voidResult: void = await firstValueFrom(repository.deleteOrganisationseinheit(deleteOrganisationseinheit.id));
 
       expect(voidResult).toBeNull();
     });
   });
+
+  describe('getUsers', () => {
+    const userRep: User = createUser();
+    const userRepArray: User[] = [userRep, userRep, userRep];
+    const group: string = faker.random.word();
+    const role: string = faker.random.word();
+    const groupRep: GroupRepresentation[] = [{ name: group }];
+    const roleRep: MappingsRepresentation = {
+      clientMappings: { alfa: { mappings: [{ name: role }] } },
+    };
+
+    beforeEach(() => {
+      jest.clearAllMocks();
+      kcAdminClient.users = <any>{
+        find: jest.fn().mockReturnValue(Promise.resolve(userRepArray)),
+        listGroups: jest.fn().mockReturnValue(Promise.resolve(groupRep)),
+        listRoleMappings: jest.fn().mockReturnValue(Promise.resolve(roleRep)),
+      };
+    });
+
+    it('should call kcAdminClient users find', () => {
+      repository.getUsers();
+
+      expect(kcAdminClient.users['find']).toHaveBeenCalled();
+    });
+
+    it('should call mapToUser', fakeAsync(() => {
+      const mapToUser: jest.SpyInstance<User> = jest.spyOn(repository, 'mapToUser');
+
+      repository.getUsers().subscribe();
+      tick();
+
+      expect(mapToUser).toBeCalledTimes(userRepArray.length);
+    }));
+
+    it('should call kcadminClient listGroups for every user', fakeAsync(() => {
+      repository.getUsers().subscribe();
+      tick();
+
+      expect(kcAdminClient.users['listGroups']).toBeCalledTimes(userRepArray.length);
+    }));
+
+    it('should call kcadminClient listRoleMappings for every user', fakeAsync(() => {
+      repository.getUsers().subscribe();
+      tick();
+
+      expect(kcAdminClient.users['listRoleMappings']).toBeCalledTimes(userRepArray.length);
+    }));
+
+    it('should return users with groups and roles', (done) => {
+      repository.getUsers().subscribe((users: User[]) => {
+        users.forEach((user) => expect(user).toEqual({ ...userRep, groups: [group], roles: [role] }));
+        done();
+      });
+    });
+
+    it('should return users with empty groups and roles if they have none', (done) => {
+      kcAdminClient.users['listGroups'] = jest.fn().mockReturnValue(Promise.resolve([]));
+      kcAdminClient.users['listRoleMappings'] = jest.fn().mockReturnValue(Promise.resolve({}));
+
+      repository.getUsers().subscribe((users: User[]) => {
+        users.forEach((user) => expect(user).toEqual({ ...userRep, groups: [], roles: [] }));
+        done();
+      });
+    });
+  });
 });
diff --git a/alfa-client/libs/admin/settings/src/lib/user/user.service.spec.ts b/alfa-client/libs/admin/settings/src/lib/user/user.service.spec.ts
deleted file mode 100644
index 56ac9d24a8cf68804dce861d61b7a3cf551aeb54..0000000000000000000000000000000000000000
--- a/alfa-client/libs/admin/settings/src/lib/user/user.service.spec.ts
+++ /dev/null
@@ -1,321 +0,0 @@
-import { mock, Mock, useFromMock } from '@alfa-client/test-utils';
-import { fakeAsync, tick } from '@angular/core/testing';
-import { cold } from 'jest-marbles';
-import { singleCold } from 'libs/tech-shared/test/marbles';
-import { firstValueFrom, lastValueFrom, Observable, of } from 'rxjs';
-import {
-  createOrganisationseinheit,
-  createOrganisationseinheitState,
-} from '../../../test/user/user';
-import { Organisationseinheit } from './user.model';
-import { UserRepository } from './user.repository.service';
-import { UserService } from './user.service';
-
-describe('UserService', () => {
-  let service: UserService;
-  let repository: Mock<UserRepository>;
-  const sortedNames: string[] = ['BBBB', 'CCCC', 'XXXX'];
-  const sortedOrganisationseinheitItems: Organisationseinheit[] = sortedNames.map((name) => ({
-    ...createOrganisationseinheit(),
-    name,
-  }));
-  const unsortedOrganisationseinheitItems: Organisationseinheit[] = [
-    sortedOrganisationseinheitItems[2],
-    sortedOrganisationseinheitItems[0],
-    sortedOrganisationseinheitItems[1],
-  ];
-  let setOrganisationseinheitItemsSpy: jest.SpyInstance;
-  let setLoadingUntilFirstSpy: jest.SpyInstance;
-
-  beforeEach(() => {
-    repository = mock(UserRepository);
-    service = new UserService(useFromMock(repository));
-    setOrganisationseinheitItemsSpy = jest.spyOn(service, 'setOrganisationseinheit');
-    setLoadingUntilFirstSpy = jest.spyOn(service, 'setLoadingUntilFirst');
-  });
-
-  it('should be created', () => {
-    expect(service).toBeTruthy();
-  });
-
-  describe('initial state', () => {
-    it('should have empty group list', () => {
-      expect(service.organisationseinheitState$.value.organisationseinheitItems).toEqual([]);
-    });
-    it('should not be loading', () => {
-      expect(service.organisationseinheitState$.value.loading).toEqual(false);
-    });
-    it('should be requiring a reload', () => {
-      expect(service.organisationseinheitState$.value.updateRequired).toEqual(true);
-    });
-  });
-
-  describe('get group state', () => {
-    it('should update if required', async () => {
-      service.updateIfRequired = jest.fn();
-
-      await firstValueFrom(service.getOrganisationseinheitState());
-
-      expect(service.updateIfRequired).toHaveBeenCalled();
-    });
-
-    it('should call find groups', fakeAsync(() => {
-      repository.findOrganisationseinheitItems.mockReturnValue(
-        of(unsortedOrganisationseinheitItems),
-      );
-
-      service.getOrganisationseinheitState().subscribe();
-      tick();
-
-      expect(repository.findOrganisationseinheitItems).toHaveBeenCalled();
-    }));
-  });
-
-  describe('update if required', () => {
-    beforeEach(() => {
-      service.updateOrganisationseinheitItems = jest.fn(() => of([]));
-    });
-
-    it('should call update groups with initial values', () => {
-      service.updateIfRequired();
-
-      expect(service.updateOrganisationseinheitItems).toHaveBeenCalled();
-    });
-
-    it('should not call update groups if loading', () => {
-      service.setLoading();
-
-      service.updateIfRequired();
-
-      expect(service.updateOrganisationseinheitItems).not.toHaveBeenCalled();
-    });
-
-    it('should not call update groups if not requiring update', () => {
-      service.setUpdateRequired(false);
-
-      service.updateIfRequired();
-
-      expect(service.updateOrganisationseinheitItems).not.toHaveBeenCalled();
-    });
-  });
-
-  describe('update groups', () => {
-    beforeEach(() => {
-      repository.findOrganisationseinheitItems.mockReturnValue(
-        of(unsortedOrganisationseinheitItems),
-      );
-    });
-
-    it('should set loading', () => {
-      service.updateOrganisationseinheitItems();
-
-      expect(service.organisationseinheitState$.value.loading).toBeTruthy();
-    });
-
-    it('should set sorted groups', async () => {
-      await lastValueFrom(service.updateOrganisationseinheitItems());
-
-      expect(service.organisationseinheitState$.value.organisationseinheitItems).toEqual(
-        sortedOrganisationseinheitItems,
-      );
-    });
-
-    it('should not require update afterward', async () => {
-      await lastValueFrom(service.updateOrganisationseinheitItems());
-
-      expect(service.organisationseinheitState$.value.updateRequired).toBeFalsy();
-    });
-  });
-
-  describe('save organisationseinheit', () => {
-    const saveGroup: Organisationseinheit = {
-      ...createOrganisationseinheit(),
-      id: sortedOrganisationseinheitItems[0].id,
-    };
-
-    beforeEach(() => {
-      repository.saveOrganisationseinheit.mockReturnValue(of(null));
-    });
-
-    it('should use set loading until first', fakeAsync(() => {
-      service.saveOrganisationseinheit(saveGroup).subscribe();
-      tick();
-
-      expect(setLoadingUntilFirstSpy).toHaveBeenCalled();
-    }));
-
-    it('should call repository for save', fakeAsync(() => {
-      service.saveOrganisationseinheit(saveGroup).subscribe();
-      tick();
-
-      expect(repository.saveOrganisationseinheit).toHaveBeenCalledWith(saveGroup);
-    }));
-
-    it('should set organisationseinheit items with updated organisationseinheit', fakeAsync(() => {
-      service.setOrganisationseinheit(sortedOrganisationseinheitItems);
-      setOrganisationseinheitItemsSpy.mockClear();
-
-      service.saveOrganisationseinheit(saveGroup).subscribe();
-      tick();
-
-      expect(setOrganisationseinheitItemsSpy).toHaveBeenCalledWith([
-        saveGroup,
-        ...sortedOrganisationseinheitItems.slice(1),
-      ]);
-    }));
-  });
-
-  describe('create organisationseinheit', () => {
-    const organisationseinheit: Organisationseinheit = createOrganisationseinheit();
-
-    beforeEach(() => {
-      repository.createOrganisationseinheit.mockReturnValue(of(organisationseinheit));
-    });
-
-    it('should use set loading until first', () => {
-      service.createOrganisationseinheit(
-        organisationseinheit.name,
-        organisationseinheit.organisationseinheitIds,
-      );
-
-      expect(setLoadingUntilFirstSpy).toHaveBeenCalled();
-    });
-
-    it('should call repository for save', () => {
-      service.createOrganisationseinheit(
-        organisationseinheit.name,
-        organisationseinheit.organisationseinheitIds,
-      );
-
-      expect(repository.createOrganisationseinheit).toHaveBeenCalledWith(
-        organisationseinheit.name,
-        organisationseinheit.organisationseinheitIds,
-      );
-    });
-
-    it('should set organisationseinheit items with new group', fakeAsync(() => {
-      service.setOrganisationseinheit(sortedOrganisationseinheitItems);
-      setOrganisationseinheitItemsSpy.mockClear();
-
-      service
-        .createOrganisationseinheit(
-          organisationseinheit.name,
-          organisationseinheit.organisationseinheitIds,
-        )
-        .subscribe();
-      tick();
-
-      expect(setOrganisationseinheitItemsSpy).toHaveBeenCalledWith([
-        ...sortedOrganisationseinheitItems,
-        organisationseinheit,
-      ]);
-    }));
-  });
-
-  describe('set organisationseinheit items', () => {
-    it('should sort groups by name', async () => {
-      service.setOrganisationseinheit(unsortedOrganisationseinheitItems);
-
-      expect(service.organisationseinheitState$.value.organisationseinheitItems).toEqual(
-        sortedOrganisationseinheitItems,
-      );
-    });
-  });
-
-  describe('delete group', () => {
-    const deleteGroup: Organisationseinheit = unsortedOrganisationseinheitItems[1];
-
-    beforeEach(async () => {
-      repository.deleteOrganisationseinheit.mockReturnValue(of(null));
-      service.organisationseinheitState$.next({
-        ...service.organisationseinheitState$.value,
-        organisationseinheitItems: sortedOrganisationseinheitItems,
-      });
-    });
-
-    it('should use set loading until first', () => {
-      const setLoadingUntilFirstSpy: jest.SpyInstance = jest.spyOn(service, 'setLoadingUntilFirst');
-      service.deleteOrganisationseinheit(deleteGroup.id);
-
-      expect(setLoadingUntilFirstSpy).toHaveBeenCalled();
-    });
-
-    it('should call repository', () => {
-      service.deleteOrganisationseinheit(deleteGroup.id);
-
-      expect(repository.deleteOrganisationseinheit).toHaveBeenCalledWith(deleteGroup.id);
-    });
-
-    describe('which exists', () => {
-      it('should not have group in list after delete', fakeAsync(() => {
-        service.deleteOrganisationseinheit(deleteGroup.id).subscribe();
-        tick();
-
-        expect(service.organisationseinheitState$.value.organisationseinheitItems).not.toContain(
-          deleteGroup,
-        );
-      }));
-    });
-
-    describe('which does not exist', () => {
-      it('should have no effect', fakeAsync(() => {
-        service.deleteOrganisationseinheit('unknown-id').subscribe();
-        tick();
-
-        expect(service.organisationseinheitState$.value.organisationseinheitItems).toEqual(
-          sortedOrganisationseinheitItems,
-        );
-      }));
-    });
-  });
-
-  describe('set loading until first', () => {
-    it('should set loading', () => {
-      service.setLoadingUntilFirst(of(null), () => {});
-
-      expect(service.organisationseinheitState$.value.loading).toBe(true);
-    });
-
-    it('should unset loading', fakeAsync(() => {
-      service.setLoadingUntilFirst(of(null), () => {}).subscribe();
-      tick();
-
-      expect(service.organisationseinheitState$.value.loading).toBe(false);
-    }));
-
-    it('should emit loading before first and emit loading after first', () => {
-      const delayedNull = cold('-a|', { a: null });
-
-      const progressObservable = service.setLoadingUntilFirst(delayedNull, () => {});
-
-      expect(progressObservable).toBeObservable(cold('a(b|)', { a: true, b: false }));
-    });
-
-    it('should call tap function', fakeAsync(() => {
-      const tapFunction: jest.Mock = jest.fn();
-      const value: string = 'abc';
-      const delayedNull: Observable<string> = of(value);
-
-      service.setLoadingUntilFirst(delayedNull, tapFunction).subscribe();
-      tick();
-
-      expect(tapFunction).toHaveBeenCalledWith(value);
-    }));
-  });
-
-  describe('get organisationseinheit items', () => {
-    it('should return items of state', () => {
-      const organisationseinheitItems: Organisationseinheit[] = [
-        createOrganisationseinheit(),
-        createOrganisationseinheit(),
-      ];
-      service.getOrganisationseinheitState = jest
-        .fn()
-        .mockReturnValue(singleCold(createOrganisationseinheitState(organisationseinheitItems)));
-
-      const itemsObservable: Observable<Organisationseinheit[]> =
-        service.getOrganisationseinheitItems();
-      expect(itemsObservable).toBeObservable(singleCold(organisationseinheitItems));
-    });
-  });
-});
diff --git a/alfa-client/libs/admin/settings/src/lib/user/user.service.ts b/alfa-client/libs/admin/settings/src/lib/user/user.service.ts
deleted file mode 100644
index 9ec08995ed49a91e48c044690c9770f121fcf9a5..0000000000000000000000000000000000000000
--- a/alfa-client/libs/admin/settings/src/lib/user/user.service.ts
+++ /dev/null
@@ -1,143 +0,0 @@
-import { Injectable } from '@angular/core';
-import { BehaviorSubject, Observable, first, map, startWith, tap } from 'rxjs';
-import { Organisationseinheit, OrganisationseinheitState } from './user.model';
-import { UserRepository } from './user.repository.service';
-
-@Injectable({
-  providedIn: 'root',
-})
-export class UserService {
-  readonly organisationseinheitState$: BehaviorSubject<OrganisationseinheitState> =
-    new BehaviorSubject({
-      organisationseinheitItems: [],
-      loading: false,
-      updateRequired: true,
-    });
-
-  constructor(private userRepository: UserRepository) {}
-
-  public saveOrganisationseinheit(organisationseinheit: Organisationseinheit): Observable<boolean> {
-    return this.setLoadingUntilFirst(
-      this.userRepository.saveOrganisationseinheit(organisationseinheit),
-      () => {
-        this.updateExistingOrganisationseinheit(organisationseinheit);
-      },
-    );
-  }
-
-  private updateExistingOrganisationseinheit(organisationseinheit: Organisationseinheit): void {
-    this.setOrganisationseinheit([
-      organisationseinheit,
-      ...this.organisationseinheitState$.value.organisationseinheitItems.filter(
-        (otherOrganisationseinheit: Organisationseinheit) =>
-          otherOrganisationseinheit.id !== organisationseinheit.id,
-      ),
-    ]);
-  }
-
-  public createOrganisationseinheit(
-    name: string,
-    organisationseinheitIds: string[],
-  ): Observable<boolean> {
-    return this.setLoadingUntilFirst(
-      this.userRepository.createOrganisationseinheit(name, organisationseinheitIds),
-      (organisationseinheit: Organisationseinheit) => {
-        this.addOrganisationseinheit(organisationseinheit);
-      },
-    );
-  }
-
-  public deleteOrganisationseinheit(id: string): Observable<boolean> {
-    return this.setLoadingUntilFirst(this.userRepository.deleteOrganisationseinheit(id), () =>
-      this.removeOrganisationseinheit(id),
-    );
-  }
-
-  private removeOrganisationseinheit(id: string): void {
-    this.setOrganisationseinheit(
-      this.organisationseinheitState$.value.organisationseinheitItems.filter(
-        (organisationseinheit: Organisationseinheit) => organisationseinheit.id !== id,
-      ),
-    );
-  }
-
-  setLoadingUntilFirst<T>(
-    action: Observable<T>,
-    tapFunction: (value: T) => void,
-  ): Observable<boolean> {
-    this.setLoading();
-
-    return action.pipe(
-      first(),
-      tap(tapFunction),
-      tap(() => this.setLoading(false)),
-      map(() => this.organisationseinheitState$.value.loading),
-      startWith(this.organisationseinheitState$.value.loading),
-    );
-  }
-
-  private addOrganisationseinheit(organisationseinheit: Organisationseinheit): void {
-    this.setOrganisationseinheit([
-      ...this.organisationseinheitState$.value.organisationseinheitItems,
-      organisationseinheit,
-    ]);
-  }
-
-  setOrganisationseinheit(organisationseinheitItems: Organisationseinheit[]): void {
-    this.organisationseinheitState$.next({
-      ...this.organisationseinheitState$.value,
-      organisationseinheitItems: this.sortedOrganisationseinheitItems(organisationseinheitItems),
-    });
-  }
-
-  private sortedOrganisationseinheitItems(
-    organisationseinheitItems: Organisationseinheit[],
-  ): Organisationseinheit[] {
-    return [...organisationseinheitItems].sort((a, b) => a.name.localeCompare(b.name));
-  }
-
-  public getOrganisationseinheitState(): Observable<OrganisationseinheitState> {
-    return this.organisationseinheitState$.pipe(tap(() => this.updateIfRequired()));
-  }
-
-  updateIfRequired(): void {
-    if (this.isUpdateRequired(this.organisationseinheitState$.value)) {
-      this.updateOrganisationseinheitItems().pipe(first()).subscribe();
-    }
-  }
-
-  private isUpdateRequired(state: OrganisationseinheitState): boolean {
-    return state.updateRequired && !state.loading;
-  }
-
-  updateOrganisationseinheitItems(): Observable<Organisationseinheit[]> {
-    this.setLoading();
-
-    return this.userRepository.findOrganisationseinheitItems().pipe(
-      tap(() => this.setUpdateRequired(false)),
-      tap((organisationseinheitItems: Organisationseinheit[]) =>
-        this.setOrganisationseinheit(organisationseinheitItems),
-      ),
-    );
-  }
-
-  setUpdateRequired(updateRequired: boolean = true) {
-    this.organisationseinheitState$.next({
-      ...this.organisationseinheitState$.value,
-      updateRequired,
-    });
-  }
-
-  setLoading(loading: boolean = true): void {
-    this.organisationseinheitState$.next({
-      ...this.organisationseinheitState$.value,
-      loading,
-    });
-  }
-
-  public getOrganisationseinheitItems(): Observable<Organisationseinheit[]> {
-    return this.getOrganisationseinheitState().pipe(
-      map((state: OrganisationseinheitState) => state.organisationseinheitItems),
-    );
-  }
-}
diff --git a/alfa-client/libs/admin/settings/src/lib/user/user.util.spec.ts b/alfa-client/libs/admin/settings/src/lib/user/user.util.spec.ts
index 7c0a60daa8b3f7e03fc2b974ada2d7b4ae2f4d13..f4d9cc168ecb9eaca45f28cead659716ff232845 100644
--- a/alfa-client/libs/admin/settings/src/lib/user/user.util.spec.ts
+++ b/alfa-client/libs/admin/settings/src/lib/user/user.util.spec.ts
@@ -1,22 +1,43 @@
-import { createOrganisationseinheitError } from '../../../test/user/user';
-import { OrganisationseinheitError, OrganisationseinheitErrorType } from './user.model';
-import { KEYCLOAK_ERROR_MESSAGES, getOrganisationseinheitErrorMessage } from './user.util';
-
-describe('get organisationseinheit error message', () => {
-  it('should map known error message', () => {
-    const nameConflictError: OrganisationseinheitError = createOrganisationseinheitError(
-      OrganisationseinheitErrorType.NAME_CONFLICT,
-    );
-    const expectedMessage: string = KEYCLOAK_ERROR_MESSAGES[nameConflictError.errorType];
-
-    const message: string = getOrganisationseinheitErrorMessage(nameConflictError);
-    expect(message).toEqual(expectedMessage);
+import { EMPTY_STRING } from '@alfa-client/tech-shared';
+import { createOrganisationseinheitError, createUser } from '../../../test/user/user';
+import { OrganisationseinheitError, OrganisationseinheitErrorType, User } from './user.model';
+import { KEYCLOAK_ERROR_MESSAGES, getOrganisationseinheitErrorMessage, sortUsersByLastName } from './user.util';
+
+describe('user util', () => {
+  describe('get organisationseinheit error message', () => {
+    it('should map known error message', () => {
+      const nameConflictError: OrganisationseinheitError = createOrganisationseinheitError(
+        OrganisationseinheitErrorType.NAME_CONFLICT,
+      );
+      const expectedMessage: string = KEYCLOAK_ERROR_MESSAGES[nameConflictError.errorType];
+
+      const message: string = getOrganisationseinheitErrorMessage(nameConflictError);
+
+      expect(message).toEqual(expectedMessage);
+    });
+
+    it('should map unknown error message to empty string', () => {
+      const nameConflictError: OrganisationseinheitError = createOrganisationseinheitError(null);
+
+      const message: string = getOrganisationseinheitErrorMessage(nameConflictError);
+
+      expect(message).toEqual(EMPTY_STRING);
+    });
   });
 
-  it('should map unknown error message to empty string', () => {
-    const nameConflictError: OrganisationseinheitError = createOrganisationseinheitError(null);
+  describe('sort users by last name', () => {
+    const users: User[] = [
+      { ...createUser(), lastName: 'Müller' },
+      { ...createUser(), lastName: 'Schmidt' },
+      { ...createUser(), lastName: 'Anders' },
+    ];
+
+    it('shoud sort users by last name alphabetically ', () => {
+      const sortedUsers: User[] = sortUsersByLastName(users);
 
-    const message: string = getOrganisationseinheitErrorMessage(nameConflictError);
-    expect(message).toEqual('');
+      expect(sortedUsers[0].lastName).toBe('Anders');
+      expect(sortedUsers[1].lastName).toBe('Müller');
+      expect(sortedUsers[2].lastName).toBe('Schmidt');
+    });
   });
 });
diff --git a/alfa-client/libs/admin/settings/src/lib/user/user.util.ts b/alfa-client/libs/admin/settings/src/lib/user/user.util.ts
index 2a1da4ffbdac3353761518988c9c112cbc450ca1..9878f7021e501b38d8d0938228a3c2c7c1df51b9 100644
--- a/alfa-client/libs/admin/settings/src/lib/user/user.util.ts
+++ b/alfa-client/libs/admin/settings/src/lib/user/user.util.ts
@@ -1,10 +1,9 @@
-import { OrganisationseinheitError, OrganisationseinheitErrorType } from './user.model';
+import { OrganisationseinheitError, OrganisationseinheitErrorType, User } from './user.model';
 
 export const KEYCLOAK_ERROR_MESSAGES: { [type: string]: string } = {
   [OrganisationseinheitErrorType.NAME_CONFLICT]: 'Der Name exisitert bereits.',
   [OrganisationseinheitErrorType.NAME_MISSING]: 'Bitte den Namen angeben.',
-  [OrganisationseinheitErrorType.ID_MISSING]:
-    'Bitte mindestens eine Organisationseinheit ID angeben.',
+  [OrganisationseinheitErrorType.ID_MISSING]: 'Bitte mindestens eine Organisationseinheit ID angeben.',
 };
 
 export const KEYCLOAK_CREATE_GROUPS_ERROR_STATUS: {
@@ -17,3 +16,7 @@ export const KEYCLOAK_CREATE_GROUPS_ERROR_STATUS: {
 export function getOrganisationseinheitErrorMessage(error: OrganisationseinheitError): string {
   return KEYCLOAK_ERROR_MESSAGES[error.errorType] ?? '';
 }
+
+export function sortUsersByLastName(users: User[]): User[] {
+  return users.sort((a, b) => (a.lastName ?? '').localeCompare(b.lastName ?? ''));
+}
diff --git a/alfa-client/libs/admin/settings/src/lib/users-roles/user.service.spec.ts b/alfa-client/libs/admin/settings/src/lib/users-roles/user.service.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..fbc8a861f16886d2e481d220281bfca7c01b03db
--- /dev/null
+++ b/alfa-client/libs/admin/settings/src/lib/users-roles/user.service.spec.ts
@@ -0,0 +1,37 @@
+import { mock, Mock, useFromMock } from '@alfa-client/test-utils';
+import { fakeAsync, tick } from '@angular/core/testing';
+import { of } from 'rxjs';
+import { createUser } from '../../../test/user/user';
+import { User } from '../user/user.model';
+import { UserRepository } from '../user/user.repository.service';
+import * as UserUtil from '../user/user.util';
+import { UserService } from './user.service';
+
+describe('UserService', () => {
+  let service: UserService;
+  let repository: Mock<UserRepository>;
+
+  const user: User = createUser();
+
+  beforeEach(() => {
+    repository = { ...mock(UserRepository), getUsers: jest.fn().mockReturnValue(of([user])) };
+    service = new UserService(useFromMock(repository));
+  });
+
+  describe('getItemsFromKeycloak', () => {
+    it('should call getUsers from userRepository', () => {
+      service.getItemsFromKeycloak();
+
+      expect(repository.getUsers).toHaveBeenCalled();
+    });
+
+    it('should call sortUsersByLastName', fakeAsync(() => {
+      const sortUsersByLastNameSpy: jest.SpyInstance<User[]> = jest.spyOn(UserUtil, 'sortUsersByLastName');
+
+      service.getItemsFromKeycloak().subscribe();
+      tick();
+
+      expect(sortUsersByLastNameSpy).toHaveBeenCalled();
+    }));
+  });
+});
diff --git a/alfa-client/libs/admin/settings/src/lib/users-roles/user.service.ts b/alfa-client/libs/admin/settings/src/lib/users-roles/user.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..83c56cc41ce3f12ec58f542164a9a113c19b75ef
--- /dev/null
+++ b/alfa-client/libs/admin/settings/src/lib/users-roles/user.service.ts
@@ -0,0 +1,31 @@
+import { Injectable } from '@angular/core';
+import { map, Observable } from 'rxjs';
+import { KeycloakResourceService } from '../user/keycloak.resource.service';
+import { User } from '../user/user.model';
+import { UserRepository } from '../user/user.repository.service';
+import { sortUsersByLastName } from '../user/user.util';
+
+@Injectable({
+  providedIn: 'root',
+})
+export class UserService extends KeycloakResourceService<User> {
+  constructor(private userRepository: UserRepository) {
+    super();
+  }
+
+  getItemsFromKeycloak(): Observable<User[]> {
+    return this.userRepository.getUsers().pipe(map(sortUsersByLastName));
+  }
+
+  createInKeycloak(item: Partial<User>): Observable<User> {
+    throw new Error('Method not implemented.');
+  }
+
+  saveInKeycloak(item: User): Observable<void> {
+    throw new Error('Method not implemented.');
+  }
+
+  deleteInKeycloak(id: string): Observable<void> {
+    throw new Error('Method not implemented.');
+  }
+}
diff --git a/alfa-client/libs/admin/settings/src/lib/users-roles/users-roles.component.html b/alfa-client/libs/admin/settings/src/lib/users-roles/users-roles.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..2607f2a96ac2d8eb8cef3aeffa18aa709fefdaea
--- /dev/null
+++ b/alfa-client/libs/admin/settings/src/lib/users-roles/users-roles.component.html
@@ -0,0 +1,60 @@
+<h1 class="heading-1">Benutzer & Rollen</h1>
+<ods-button-with-spinner text="Benutzer hinzufügen" class="py-8" dataTestId="add-user-button" />
+<ng-container *ngIf="users$ | async as users">
+  <ul class="divide-y divide-gray-300 rounded-md bg-background-50 text-text shadow-sm ring-1 ring-gray-300 empty:hidden">
+    <li *ngFor="let user of users.resource">
+      <a
+        href="#"
+        class="flex flex-col items-start justify-between gap-6 border-primary-600/50 px-6 py-4 hover:bg-background-150 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-focus lg:flex-row"
+      >
+        <div class="flex-1 basis-1/2">
+          <div class="mb-2 flex flex-wrap items-center gap-3">
+            <h3 class="text-md font-semibold">{{ user | toUserName }}</h3>
+            <dl class="flex flex-wrap gap-2">
+              <dt class="sr-only">Rollen:</dt>
+              <dd
+                *ngFor="let role of user.roles"
+                class="inline-flex flex-shrink-0 items-center rounded-full bg-green-50 px-1.5 py-0.5 text-sm font-medium text-green-700 ring-1 ring-inset ring-green-600/20"
+              >
+                {{ role }}
+              </dd>
+            </dl>
+          </div>
+
+          <dl>
+            <div *ngIf="user.email" class="flex items-center gap-2">
+              <dt>
+                <span class="sr-only">E-Mail:</span>
+                <ods-mailbox-icon size="small" class="stroke-gray-600" />
+              </dt>
+              <dd>{{ user.email }}</dd>
+            </div>
+            <div class="flex items-center gap-2">
+              <dt>
+                <span class="sr-only">Benutzername:</span>
+                <ods-person-icon />
+              </dt>
+              <dd>{{ user.username }}</dd>
+            </div>
+          </dl>
+        </div>
+
+        <div class="flex-1 basis-1/2">
+          <h4 class="sr-only">Zuständige Stellen</h4>
+
+          <ng-container *ngIf="user.groups.length > 0; else noGroups">
+            <ul class="list-outside list-disc pl-4">
+              <ng-container *ngFor="let group of user.groups | slice: 0 : GROUPS_TO_DISPLAY">
+                <li>{{ group }}</li>
+              </ng-container>
+            </ul>
+            <p *ngIf="user.groups.length > GROUPS_TO_DISPLAY" class="pl-4 text-gray-500">
+              und {{ user.groups.length - 3 }} weitere
+            </p>
+          </ng-container>
+          <ng-template #noGroups>keine zuständige Stelle zugewiesen</ng-template>
+        </div>
+      </a>
+    </li>
+  </ul>
+</ng-container>
diff --git a/alfa-client/libs/admin/settings/src/lib/users-roles/users-roles.component.spec.ts b/alfa-client/libs/admin/settings/src/lib/users-roles/users-roles.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..49182ee84673fa793f0cbe0ee14eb694ab6f2319
--- /dev/null
+++ b/alfa-client/libs/admin/settings/src/lib/users-roles/users-roles.component.spec.ts
@@ -0,0 +1,47 @@
+import { Mock, mock } from '@alfa-client/test-utils';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ButtonWithSpinnerComponent } from '@ods/component';
+import { MailboxIconComponent, PersonIconComponent } from '@ods/system';
+import { MockComponent, MockPipe } from 'ng-mocks';
+import { ToUserNamePipe } from '../user/to-user-name.pipe';
+import { UserService } from './user.service';
+import { UsersRolesComponent } from './users-roles.component';
+
+describe('UsersRolesComponent', () => {
+  let component: UsersRolesComponent;
+  let fixture: ComponentFixture<UsersRolesComponent>;
+
+  const userService: Mock<UserService> = {
+    ...mock(UserService),
+    get: jest.fn(),
+  };
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      declarations: [UsersRolesComponent],
+      providers: [{ provide: UserService, useValue: userService }],
+      imports: [
+        MockComponent(ButtonWithSpinnerComponent),
+        MockComponent(MailboxIconComponent),
+        MockComponent(PersonIconComponent),
+        MockPipe(ToUserNamePipe),
+      ],
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(UsersRolesComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  describe('template', () => {
+    it('should create', () => {
+      expect(component).toBeTruthy();
+    });
+
+    describe('constructor', () => {
+      it('should call userService.get', () => {
+        expect(userService.get).toHaveBeenCalled();
+      });
+    });
+  });
+});
diff --git a/alfa-client/libs/admin/settings/src/lib/users-roles/users-roles.component.ts b/alfa-client/libs/admin/settings/src/lib/users-roles/users-roles.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..46003c627d6c355241eba06d875e49d4d7df0f2b
--- /dev/null
+++ b/alfa-client/libs/admin/settings/src/lib/users-roles/users-roles.component.ts
@@ -0,0 +1,18 @@
+import { StateResource } from '@alfa-client/tech-shared';
+import { Component } from '@angular/core';
+import { Observable } from 'rxjs';
+import { User } from '../user/user.model';
+import { UserService } from './user.service';
+
+@Component({
+  selector: 'admin-users-roles',
+  templateUrl: './users-roles.component.html',
+})
+export class UsersRolesComponent {
+  public users$: Observable<StateResource<User[]>>;
+  public readonly GROUPS_TO_DISPLAY = 3;
+
+  constructor(private userService: UserService) {
+    this.users$ = this.userService.get();
+  }
+}
diff --git a/alfa-client/libs/admin/settings/test/user/user.ts b/alfa-client/libs/admin/settings/test/user/user.ts
index 090c729b48a5a0bea9f37ea4ec790793bf49b1f5..8e9c06e922483b856f0b179d14e476d7b81ddc83 100644
--- a/alfa-client/libs/admin/settings/test/user/user.ts
+++ b/alfa-client/libs/admin/settings/test/user/user.ts
@@ -5,9 +5,21 @@ import {
   Organisationseinheit,
   OrganisationseinheitError,
   OrganisationseinheitErrorType,
-  OrganisationseinheitState,
+  User,
 } from '../../src/lib/user/user.model';
 
+export function createUser(): User {
+  return {
+    id: faker.random.word(),
+    username: faker.random.word(),
+    firstName: faker.name.firstName(),
+    lastName: faker.name.lastName(),
+    email: faker.internet.email(),
+    roles: null,
+    groups: null,
+  };
+}
+
 export function createOrganisationseinheit(): Organisationseinheit {
   return {
     id: faker.random.alphaNumeric(16),
@@ -28,16 +40,6 @@ export function createGroupRepresentation(
   };
 }
 
-export function createOrganisationseinheitState(
-  organisationseinheitItems: Organisationseinheit[] = [createOrganisationseinheit()],
-): OrganisationseinheitState {
-  return {
-    organisationseinheitItems: organisationseinheitItems,
-    loading: false,
-    updateRequired: false,
-  };
-}
-
 export function createOrganisationseinheitError(
   errorType: OrganisationseinheitErrorType = OrganisationseinheitErrorType.NAME_MISSING,
 ): OrganisationseinheitError {
diff --git a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-in-vorgang/collaboration-in-vorgang.component.html b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-in-vorgang/collaboration-in-vorgang.component.html
index 733601490e198e7d93d37626f597974081b8367a..f6f07ea8d41b856a7044732497a7a9ae381ef669 100644
--- a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-in-vorgang/collaboration-in-vorgang.component.html
+++ b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-in-vorgang/collaboration-in-vorgang.component.html
@@ -11,7 +11,7 @@
       dataTestId="anfrage-erstellen-button"
       (clickEmitter)="showRequestForm.emit()"
     >
-      <ods-collaboration-icon icon />
+      <ods-users-icon icon />
     </ods-button>
   </ng-template>
 
diff --git a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-in-vorgang/collaboration-in-vorgang.component.spec.ts b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-in-vorgang/collaboration-in-vorgang.component.spec.ts
index 5b17cd273cc3b503a6accb79219bb149c351041a..ab7493dc471343f302d5f6053f5dff6dc20057da 100644
--- a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-in-vorgang/collaboration-in-vorgang.component.spec.ts
+++ b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-in-vorgang/collaboration-in-vorgang.component.spec.ts
@@ -13,7 +13,7 @@ import {
   triggerEvent,
 } from '@alfa-client/test-utils';
 import { ComponentFixture, TestBed } from '@angular/core/testing';
-import { ButtonComponent, CollaborationIconComponent, OfficeIconComponent } from '@ods/system';
+import { ButtonComponent, OfficeIconComponent, UsersIconComponent } from '@ods/system';
 import {
   createCollaboration,
   createCollaborationListResource,
@@ -41,7 +41,7 @@ describe('CollaborationInVorgangComponent', () => {
         HasLinkPipe,
         MockComponent(ButtonComponent),
         MockComponent(CollaborationRequestFormComponent),
-        MockComponent(CollaborationIconComponent),
+        MockComponent(UsersIconComponent),
         MockComponent(OfficeIconComponent),
         MockComponent(OrganisationsEinheitComponent),
       ],
diff --git a/alfa-client/libs/collaboration/src/lib/collaboration.module.ts b/alfa-client/libs/collaboration/src/lib/collaboration.module.ts
index 82a66754b9da100acdf4bf900a6669832f24a4ab..bff26cb02d9a14bef2898adce7a6ec64c779106c 100644
--- a/alfa-client/libs/collaboration/src/lib/collaboration.module.ts
+++ b/alfa-client/libs/collaboration/src/lib/collaboration.module.ts
@@ -11,11 +11,11 @@ import {
 import {
   ButtonComponent,
   CloseIconComponent,
-  CollaborationIconComponent,
   InstantSearchComponent,
   OfficeIconComponent,
   SaveIconComponent,
   SearchIconComponent,
+  UsersIconComponent,
 } from '@ods/system';
 import { CollaborationInVorgangContainerComponent } from './collaboration-in-vorgang-container/collaboration-in-vorgang-container.component';
 import { CollaborationInVorgangComponent } from './collaboration-in-vorgang-container/collaboration-in-vorgang/collaboration-in-vorgang.component';
@@ -34,7 +34,7 @@ import { SearchOrganisationsEinheitFormComponent } from './search-organisations-
     CloseIconComponent,
     SearchIconComponent,
     CollaborationSharedModule,
-    CollaborationIconComponent,
+    UsersIconComponent,
     TextEditorComponent,
     TextareaEditorComponent,
     FormsModule,
diff --git a/alfa-client/libs/design-component/src/lib/button-with-spinner/button-with-spinner.component.ts b/alfa-client/libs/design-component/src/lib/button-with-spinner/button-with-spinner.component.ts
index 2489bb3d94ad7f490abf17231a075dc0050700c2..e8388104a49fcb510c88b01ba98e4ea57fa2135f 100644
--- a/alfa-client/libs/design-component/src/lib/button-with-spinner/button-with-spinner.component.ts
+++ b/alfa-client/libs/design-component/src/lib/button-with-spinner/button-with-spinner.component.ts
@@ -2,7 +2,6 @@ import { CommandResource, hasCommandError } from '@alfa-client/command-shared';
 import { StateResource, createEmptyStateResource, isLoaded } from '@alfa-client/tech-shared';
 import { CommonModule } from '@angular/common';
 import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
-import { Resource } from '@ngxp/rest';
 import { ButtonComponent, ErrorMessageComponent, buttonVariants } from '@ods/system';
 import { VariantProps } from 'class-variance-authority';
 import { isNil } from 'lodash-es';
@@ -33,7 +32,7 @@ type ButtonVariants = VariantProps<typeof buttonVariants>;
 export class ButtonWithSpinnerComponent implements OnInit {
   @Input() text: string = '';
   @Input() dataTestId: string = '';
-  @Input() stateResource: StateResource<Resource>;
+  @Input() stateResource: StateResource<unknown>;
   @Input() variant: ButtonVariants['variant'] = 'primary';
   @Input() size: ButtonVariants['size'] = 'medium';
 
@@ -43,8 +42,8 @@ export class ButtonWithSpinnerComponent implements OnInit {
     this.stateResource = this.getStateResource();
   }
 
-  getStateResource(): StateResource<Resource> {
-    return isNil(this.stateResource) ? createEmptyStateResource<Resource>() : this.stateResource;
+  getStateResource(): StateResource<unknown> {
+    return isNil(this.stateResource) ? createEmptyStateResource() : this.stateResource;
   }
 
   get isLoading(): boolean {
diff --git a/alfa-client/libs/design-system/src/index.ts b/alfa-client/libs/design-system/src/index.ts
index 9e23463ad6c6fd0d96953de7adb1b71075150ca2..9a450a885bbe052655354f1410a730ad501ea22e 100644
--- a/alfa-client/libs/design-system/src/index.ts
+++ b/alfa-client/libs/design-system/src/index.ts
@@ -19,7 +19,6 @@ export * from './lib/icons/attachment-icon/attachment-icon.component';
 export * from './lib/icons/bescheid-generate-icon/bescheid-generate-icon.component';
 export * from './lib/icons/bescheid-upload-icon/bescheid-upload-icon.component';
 export * from './lib/icons/close-icon/close-icon.component';
-export * from './lib/icons/collaboration-icon/collaboration-icon.component';
 export * from './lib/icons/exclamation-icon/exclamation-icon.component';
 export * from './lib/icons/file-icon/file-icon.component';
 export * from './lib/icons/iconVariants';
@@ -27,11 +26,13 @@ export * from './lib/icons/logout-icon/logout-icon.component';
 export * from './lib/icons/mailbox-icon/mailbox-icon.component';
 export * from './lib/icons/office-icon/office-icon.component';
 export * from './lib/icons/orga-unit-icon/orga-unit-icon.component';
+export * from './lib/icons/person-icon/person-icon.component';
 export * from './lib/icons/save-icon/save-icon.component';
 export * from './lib/icons/search-icon/search-icon.component';
 export * from './lib/icons/send-icon/send-icon.component';
 export * from './lib/icons/spinner-icon/spinner-icon.component';
 export * from './lib/icons/stamp-icon/stamp-icon.component';
+export * from './lib/icons/users-icon/users-icon.component';
 export * from './lib/instant-search/instant-search/instant-search.component';
 export * from './lib/instant-search/instant-search/instant-search.model';
 export * from './lib/navbar/nav-item/nav-item.component';
diff --git a/alfa-client/libs/design-system/src/lib/icons/collaboration-icon/collaboration-icon.component.spec.ts b/alfa-client/libs/design-system/src/lib/icons/collaboration-icon/collaboration-icon.component.spec.ts
deleted file mode 100644
index c1a2136a653c2b9dfc52bc039fb0aa1d48ce0733..0000000000000000000000000000000000000000
--- a/alfa-client/libs/design-system/src/lib/icons/collaboration-icon/collaboration-icon.component.spec.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-import { ComponentFixture, TestBed } from '@angular/core/testing';
-import { CollaborationIconComponent } from './collaboration-icon.component';
-
-describe('CollaborationIconComponent', () => {
-  let component: CollaborationIconComponent;
-  let fixture: ComponentFixture<CollaborationIconComponent>;
-
-  beforeEach(async () => {
-    await TestBed.configureTestingModule({
-      imports: [CollaborationIconComponent],
-    }).compileComponents();
-
-    fixture = TestBed.createComponent(CollaborationIconComponent);
-    component = fixture.componentInstance;
-    fixture.detectChanges();
-  });
-
-  it('should create', () => {
-    expect(component).toBeTruthy();
-  });
-});
diff --git a/alfa-client/libs/design-system/src/lib/icons/mailbox-icon/mailbox-icon.component.ts b/alfa-client/libs/design-system/src/lib/icons/mailbox-icon/mailbox-icon.component.ts
index 84f8f446e56ed21aa7d1dfd2119a673b850897e9..07b28d630504aa66112c1af5fe9c030a273f1533 100644
--- a/alfa-client/libs/design-system/src/lib/icons/mailbox-icon/mailbox-icon.component.ts
+++ b/alfa-client/libs/design-system/src/lib/icons/mailbox-icon/mailbox-icon.component.ts
@@ -15,14 +15,12 @@ import { IconVariants, iconVariants } from '../iconVariants';
   >
     <path
       d="M20 4H4C2.89543 4 2 4.89543 2 6V18C2 19.1046 2.89543 20 4 20H20C21.1046 20 22 19.1046 22 18V6C22 4.89543 21.1046 4 20 4Z"
-      stroke="black"
       stroke-width="2"
       stroke-linecap="round"
       stroke-linejoin="round"
     />
     <path
       d="M22 7L13.03 12.7C12.7213 12.8934 12.3643 12.996 12 12.996C11.6357 12.996 11.2787 12.8934 10.97 12.7L2 7"
-      stroke="black"
       stroke-width="2"
       stroke-linecap="round"
       stroke-linejoin="round"
diff --git a/alfa-client/libs/design-system/src/lib/icons/person-icon/person-icon.component.spec.ts b/alfa-client/libs/design-system/src/lib/icons/person-icon/person-icon.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..652bfa8bc67ef5656971452b96f76272c06ecbdc
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/icons/person-icon/person-icon.component.spec.ts
@@ -0,0 +1,21 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { PersonIconComponent } from './person-icon.component';
+
+describe('PersonIconComponent', () => {
+  let component: PersonIconComponent;
+  let fixture: ComponentFixture<PersonIconComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: [PersonIconComponent],
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(PersonIconComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/alfa-client/libs/design-system/src/lib/icons/person-icon/person-icon.component.ts b/alfa-client/libs/design-system/src/lib/icons/person-icon/person-icon.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..54a353e5f0ff022713350d113556d0953fdeeed3
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/icons/person-icon/person-icon.component.ts
@@ -0,0 +1,33 @@
+import { NgClass } from '@angular/common';
+import { Component, Input } from '@angular/core';
+import { twMerge } from 'tailwind-merge';
+
+import { IconVariants, iconVariants } from '../iconVariants';
+
+@Component({
+  selector: 'ods-person-icon',
+  standalone: true,
+  imports: [NgClass],
+  template: `<svg
+    xmlns="http://www.w3.org/2000/svg"
+    [ngClass]="[twMerge(iconVariants({ size }), 'stroke-gray-600', class)]"
+    aria-hidden="true"
+    viewBox="0 0 24 24"
+    fill="none"
+  >
+    <path
+      d="M20.4 22.8v-2.4a4.8 4.8 0 00-4.8-4.8H8.4a4.8 4.8 0 00-4.8 4.8v2.4m8.4-12a4.8 4.8 0 100-9.6 4.8 4.8 0 000 9.6z"
+      stroke-linecap="round"
+      stroke-linejoin="round"
+      stroke-width="2"
+      fill="none"
+    />
+  </svg>`,
+})
+export class PersonIconComponent {
+  @Input() size: IconVariants['size'] = 'small';
+  @Input() class: string = undefined;
+
+  public readonly iconVariants = iconVariants;
+  public readonly twMerge = twMerge;
+}
diff --git a/alfa-client/libs/design-system/src/lib/icons/person-icon/person-icon.stories.ts b/alfa-client/libs/design-system/src/lib/icons/person-icon/person-icon.stories.ts
new file mode 100644
index 0000000000000000000000000000000000000000..61ef6271736032c9a31a5695d62303bc77fdd373
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/icons/person-icon/person-icon.stories.ts
@@ -0,0 +1,27 @@
+import type { Meta, StoryObj } from '@storybook/angular';
+
+import { PersonIconComponent } from './person-icon.component';
+
+const meta: Meta<PersonIconComponent> = {
+  title: 'Icons/Person icon',
+  component: PersonIconComponent,
+  excludeStories: /.*Data$/,
+  tags: ['autodocs'],
+};
+
+export default meta;
+type Story = StoryObj<PersonIconComponent>;
+
+export const Default: Story = {
+  args: { size: 'large' },
+  argTypes: {
+    size: {
+      control: 'select',
+      options: ['small', 'medium', 'large', 'extra-large', 'full'],
+      description: 'Size of icon. Property "full" means 100%',
+      table: {
+        defaultValue: { summary: 'small' },
+      },
+    },
+  },
+};
diff --git a/alfa-client/libs/design-system/src/lib/icons/users-icon/users-icon.component.spec.ts b/alfa-client/libs/design-system/src/lib/icons/users-icon/users-icon.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b12f0a04fd5c34a508c040a28ff59772577af746
--- /dev/null
+++ b/alfa-client/libs/design-system/src/lib/icons/users-icon/users-icon.component.spec.ts
@@ -0,0 +1,21 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { UsersIconComponent } from './users-icon.component';
+
+describe('UsersIconComponent', () => {
+  let component: UsersIconComponent;
+  let fixture: ComponentFixture<UsersIconComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: [UsersIconComponent],
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(UsersIconComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/alfa-client/libs/design-system/src/lib/icons/collaboration-icon/collaboration-icon.component.ts b/alfa-client/libs/design-system/src/lib/icons/users-icon/users-icon.component.ts
similarity index 95%
rename from alfa-client/libs/design-system/src/lib/icons/collaboration-icon/collaboration-icon.component.ts
rename to alfa-client/libs/design-system/src/lib/icons/users-icon/users-icon.component.ts
index 8565574eac373499fcedaea5b514e7f616b344e1..d7cc5a858b275dc0e33c1caecbf3ac265c89e818 100644
--- a/alfa-client/libs/design-system/src/lib/icons/collaboration-icon/collaboration-icon.component.ts
+++ b/alfa-client/libs/design-system/src/lib/icons/users-icon/users-icon.component.ts
@@ -4,7 +4,7 @@ import { twMerge } from 'tailwind-merge';
 import { IconVariants, iconVariants } from '../iconVariants';
 
 @Component({
-  selector: 'ods-collaboration-icon',
+  selector: 'ods-users-icon',
   standalone: true,
   imports: [CommonModule],
   template: `<svg
@@ -44,7 +44,7 @@ import { IconVariants, iconVariants } from '../iconVariants';
     />
   </svg>`,
 })
-export class CollaborationIconComponent {
+export class UsersIconComponent {
   @Input() size: IconVariants['size'] = 'medium';
   @Input() class: string = undefined;
 
diff --git a/alfa-client/libs/design-system/src/lib/icons/collaboration-icon/collaboration-icon.stories.ts b/alfa-client/libs/design-system/src/lib/icons/users-icon/users-icon.stories.ts
similarity index 64%
rename from alfa-client/libs/design-system/src/lib/icons/collaboration-icon/collaboration-icon.stories.ts
rename to alfa-client/libs/design-system/src/lib/icons/users-icon/users-icon.stories.ts
index dbc1440939f920bb66062062c12ac343a347ddce..702d6b13e5e6ff34a2da6549618f3c71891f6e96 100644
--- a/alfa-client/libs/design-system/src/lib/icons/collaboration-icon/collaboration-icon.stories.ts
+++ b/alfa-client/libs/design-system/src/lib/icons/users-icon/users-icon.stories.ts
@@ -1,16 +1,16 @@
 import type { Meta, StoryObj } from '@storybook/angular';
 
-import { CollaborationIconComponent } from './collaboration-icon.component';
+import { UsersIconComponent } from './users-icon.component';
 
-const meta: Meta<CollaborationIconComponent> = {
-  title: 'Icons/Collaboration icon',
-  component: CollaborationIconComponent,
+const meta: Meta<UsersIconComponent> = {
+  title: 'Icons/Users icon',
+  component: UsersIconComponent,
   excludeStories: /.*Data$/,
   tags: ['autodocs'],
 };
 
 export default meta;
-type Story = StoryObj<CollaborationIconComponent>;
+type Story = StoryObj<UsersIconComponent>;
 
 export const Default: Story = {
   args: { size: 'medium' },
diff --git a/alfa-client/libs/design-system/src/lib/navbar/nav-item/nav-item.component.ts b/alfa-client/libs/design-system/src/lib/navbar/nav-item/nav-item.component.ts
index 14acc1a1b2c6f3c6ca800bc30710d5a7adf48cdc..df3cc837b44933211f471f15420d87d88a95985b 100644
--- a/alfa-client/libs/design-system/src/lib/navbar/nav-item/nav-item.component.ts
+++ b/alfa-client/libs/design-system/src/lib/navbar/nav-item/nav-item.component.ts
@@ -9,11 +9,9 @@ import { RouterLink, RouterLinkActive } from '@angular/router';
   template: `<a
     [routerLink]="to"
     routerLinkActive="bg-selected-light border-selected"
-    [ngClass]="[
-      'flex min-h-8 items-center gap-2 rounded-2xl px-4 py-2',
-      'border border-transparent hover:border-primary',
-      'outline-2 outline-offset-4 outline-focus focus-visible:border-background-200',
-    ]"
+    class="flex min-h-8 items-center gap-2 rounded-2xl border border-transparent
+    px-4 py-2 outline-2 outline-offset-2 outline-focus hover:border-primary
+    focus-visible:border-background-200 focus-visible:outline"
     [attr.data-test-id]="'link-to-' + to"
   >
     <ng-content select="[icon]" />
diff --git a/alfa-client/libs/tech-shared/src/lib/resource/resource.util.ts b/alfa-client/libs/tech-shared/src/lib/resource/resource.util.ts
index 17394d5b91f600d6882f82fca324a97cdb046449..4691f7998807aa6e0e35dbcea7d84a5fd4a09885 100644
--- a/alfa-client/libs/tech-shared/src/lib/resource/resource.util.ts
+++ b/alfa-client/libs/tech-shared/src/lib/resource/resource.util.ts
@@ -85,7 +85,7 @@ export function doOnValidStateResource(
   if (isValidStateResource(stateResource)) actionOnValid();
 }
 
-export function isValidStateResource(stateResource: StateResource<Resource>): boolean {
+export function isValidStateResource(stateResource: StateResource<unknown>): boolean {
   return stateResource.loaded && isNotNull(stateResource.resource);
 }
 
diff --git a/alfa-client/libs/tech-shared/test/dummy.ts b/alfa-client/libs/tech-shared/test/dummy.ts
index 33e1ab1611c9df963f722a8c340641e10e0c2d33..5eb5d3f6fb787bd42180b1b61a773079a6bcf7f4 100644
--- a/alfa-client/libs/tech-shared/test/dummy.ts
+++ b/alfa-client/libs/tech-shared/test/dummy.ts
@@ -21,7 +21,7 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-class Dummy {}
+export class Dummy {}
 
 export function createDummy(): Dummy {
   return new Dummy();