diff --git a/alfa-client/apps/admin/src/app/app.module.ts b/alfa-client/apps/admin/src/app/app.module.ts
index 089a1851424f1c2eca17a73b15d0b0ad3f132588..4de0f0c0ab18a43a6295d9dbb7b6a141161a8b72 100644
--- a/alfa-client/apps/admin/src/app/app.module.ts
+++ b/alfa-client/apps/admin/src/app/app.module.ts
@@ -41,10 +41,11 @@ import { appRoutes } from './app.routes';
     HttpClientModule,
     ApiRootModule,
     EnvironmentModule,
-    environment.production ? [] : StoreDevtoolsModule.instrument(),
+    TechSharedModule,
     StoreModule.forRoot({}),
     EffectsModule.forRoot(),
     StoreRouterConnectingModule.forRoot(),
+    environment.production ? [] : StoreDevtoolsModule.instrument(),
     FormsModule,
     ReactiveFormsModule,
     AdminSettingsModule,
@@ -53,7 +54,6 @@ import { appRoutes } from './app.routes';
         sendAccessToken: true,
       },
     }),
-    TechSharedModule,
   ],
   providers: [
     {
diff --git a/alfa-client/libs/admin-settings/src/lib/admin-settings-resource.service.ts b/alfa-client/libs/admin-settings/src/lib/admin-settings-resource.service.ts
index 67ded869c2c64e15d7a382d8ede37ee6e3eb458b..011b3bab8ada5b5ee5456caeb9c6e46151cc7590 100644
--- a/alfa-client/libs/admin-settings/src/lib/admin-settings-resource.service.ts
+++ b/alfa-client/libs/admin-settings/src/lib/admin-settings-resource.service.ts
@@ -28,7 +28,7 @@ function buildConfig(
   return {
     baseResource: configurationService.get(),
     createLinkRel: SettingListLinkRel.CREATE,
-    listLinkRel: ConfigurationLinkRel.SETTING,
+    getLinkRel: ConfigurationLinkRel.SETTING,
     listResourceListLinkRel: SettingListLinkRel.LIST,
   };
 }
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 99b04e136805e4fec867cfe801aa82ab6ded3936..6aa7743d3314ea8df91d15448eba4db58ba28b15 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
@@ -1,17 +1,20 @@
 import { ApiRootService } from '@alfa-client/api-root-shared';
 import { Environment, ENVIRONMENT_CONFIG } from '@alfa-client/environment-shared';
-import { ResourceRepository, TechSharedModule } from '@alfa-client/tech-shared';
+import { ResourceRepository, StateService, TechSharedModule } from '@alfa-client/tech-shared';
 import { CommonModule } from '@angular/common';
 import { NgModule } from '@angular/core';
 import { ReactiveFormsModule } from '@angular/forms';
 import { RouterModule } from '@angular/router';
 import KcAdminClient from '@keycloak/keycloak-admin-client';
+import { StoreModule } from '@ngrx/store';
 import {
   createSettingListResourceService,
   SettingListResourceService,
 } from './admin-settings-resource.service';
 import { SettingsService } from './admin-settings.service';
 import {
+  CONFIGURATION_FEATURE_KEY,
+  configurationReducer,
   ConfigurationResourceService,
   createConfigurationResourceService,
 } from './configuration/configuration-resource.service';
@@ -26,6 +29,8 @@ import { PostfachFormComponent } from './postfach/postfach-container/postfach-fo
 import { PostfachNavigationItemComponent } from './postfach/postfach-navigation-item/postfach-navigation-item.component';
 import {
   createPostfachResourceService,
+  POSTFACH_FEATURE_KEY,
+  postfachReducer,
   PostfachResourceService,
 } from './postfach/postfach-resource.service';
 import { PostfachService } from './postfach/postfach.service';
@@ -55,7 +60,14 @@ import { TextFieldComponent } from './shared/text-field/text-field.component';
     MoreItemButtonComponent,
     SpinnerComponent,
   ],
-  imports: [CommonModule, TechSharedModule, RouterModule, ReactiveFormsModule],
+  imports: [
+    CommonModule,
+    TechSharedModule,
+    RouterModule,
+    ReactiveFormsModule,
+    StoreModule.forFeature(CONFIGURATION_FEATURE_KEY, configurationReducer),
+    StoreModule.forFeature(POSTFACH_FEATURE_KEY, postfachReducer),
+  ],
   exports: [
     PostfachContainerComponent,
     OrganisationseinheitContainerComponent,
@@ -75,21 +87,21 @@ import { TextFieldComponent } from './shared/text-field/text-field.component';
         }),
       deps: [ENVIRONMENT_CONFIG],
     },
-    {
-      provide: PostfachResourceService,
-      useFactory: createPostfachResourceService,
-      deps: [ResourceRepository, SettingsService],
-    },
     {
       provide: ConfigurationResourceService,
       useFactory: createConfigurationResourceService,
-      deps: [ResourceRepository, ApiRootService],
+      deps: [ResourceRepository, ApiRootService, StateService],
     },
     {
       provide: SettingListResourceService,
       useFactory: createSettingListResourceService,
       deps: [ResourceRepository, ConfigurationService],
     },
+    {
+      provide: PostfachResourceService,
+      useFactory: createPostfachResourceService,
+      deps: [ResourceRepository, SettingsService, StateService],
+    },
   ],
 })
 export class AdminSettingsModule {}
diff --git a/alfa-client/libs/admin-settings/src/lib/configuration/configuration-resource.service.ts b/alfa-client/libs/admin-settings/src/lib/configuration/configuration-resource.service.ts
index f73458583b348631669fe5479cbcc597f0cf5c61..1e70b5a06edc9137428c2d301326388353dd31c4 100644
--- a/alfa-client/libs/admin-settings/src/lib/configuration/configuration-resource.service.ts
+++ b/alfa-client/libs/admin-settings/src/lib/configuration/configuration-resource.service.ts
@@ -3,9 +3,17 @@ import {
   ApiResourceService,
   ResourceRepository,
   ResourceServiceConfig,
+  SingleResourceReducer,
+  StateService,
+  createSingleResourceActions,
 } from '@alfa-client/tech-shared';
+import { Action, ActionReducerMap } from '@ngrx/store';
 import { ConfigurationResource } from './configuration.model';
 
+export const CONFIGURATION_FEATURE_KEY = 'ConfigurationState';
+
+export const CONFIGURATION_PATH = 'configuration';
+
 export class ConfigurationResourceService extends ApiResourceService<
   ApiRootResource,
   ConfigurationResource
@@ -14,13 +22,26 @@ export class ConfigurationResourceService extends ApiResourceService<
 export function createConfigurationResourceService(
   repository: ResourceRepository,
   apiRootService: ApiRootService,
+  stateService: StateService,
 ) {
-  return new ApiResourceService(buildConfig(apiRootService), repository);
+  return new ApiResourceService(buildConfig(apiRootService), stateService, repository);
 }
 
 function buildConfig(apiRootService: ApiRootService): ResourceServiceConfig<ApiRootResource> {
   return {
-    resource: apiRootService.getApiRoot(),
+    stateInfo: { name: CONFIGURATION_FEATURE_KEY, path: CONFIGURATION_PATH },
+    baseResource: apiRootService.getApiRoot(),
     getLinkRel: ApiRootLinkRel.CONFIGURATION,
   };
 }
+
+function configurationResourceReducer(state: any, action: Action) {
+  const resourceReducer: SingleResourceReducer = new SingleResourceReducer(
+    createSingleResourceActions({ name: CONFIGURATION_FEATURE_KEY, path: CONFIGURATION_PATH }),
+  );
+  return resourceReducer.reducer(state, action);
+}
+
+export const configurationReducer: ActionReducerMap<any> = {
+  [CONFIGURATION_PATH]: configurationResourceReducer,
+};
diff --git a/alfa-client/libs/admin-settings/src/lib/postfach/postfach-resource.service.ts b/alfa-client/libs/admin-settings/src/lib/postfach/postfach-resource.service.ts
index 07f664fc2293fa9b9e5418d0ffc4a5cfe847a084..456685a75a08e35669939e597bf3d83232a17e07 100644
--- a/alfa-client/libs/admin-settings/src/lib/postfach/postfach-resource.service.ts
+++ b/alfa-client/libs/admin-settings/src/lib/postfach/postfach-resource.service.ts
@@ -2,11 +2,20 @@ import {
   ApiResourceService,
   ResourceRepository,
   ResourceServiceConfig,
+  SingleResourceReducer,
+  StateService,
+  createSingleResourceActions,
 } from '@alfa-client/tech-shared';
+import { Action, ActionReducerMap } from '@ngrx/store';
+import { SingleResourceState } from 'libs/tech-shared/src/lib/ngrx/state.model';
 import { SettingsService } from '../admin-settings.service';
 import { PostfachLinkRel } from './postfach.linkrel';
 import { PostfachResource } from './postfach.model';
 
+export const POSTFACH_FEATURE_KEY = 'PostfachState';
+
+export const POSTFACH_PATH = 'postfach';
+
 export class PostfachResourceService extends ApiResourceService<
   PostfachResource,
   PostfachResource
@@ -15,14 +24,26 @@ export class PostfachResourceService extends ApiResourceService<
 export function createPostfachResourceService(
   repository: ResourceRepository,
   settingService: SettingsService,
+  stateService: StateService,
 ) {
-  return new ApiResourceService(buildConfig(settingService), repository);
+  return new ApiResourceService(buildConfig(settingService), stateService, repository);
 }
 
 function buildConfig(settingService: SettingsService): ResourceServiceConfig<PostfachResource> {
   return {
-    resource: settingService.getPostfach(),
+    stateInfo: { name: POSTFACH_FEATURE_KEY, path: POSTFACH_PATH },
+    baseResource: settingService.getPostfach(),
     getLinkRel: PostfachLinkRel.SELF,
     edit: { linkRel: PostfachLinkRel.SELF },
   };
 }
+
+export function postfachResourceReducer(state: SingleResourceState, action: Action) {
+  const resourceReducer: SingleResourceReducer = new SingleResourceReducer(
+    createSingleResourceActions({ name: POSTFACH_FEATURE_KEY, path: POSTFACH_PATH }),
+  );
+  return resourceReducer.reducer(state, action);
+}
+export const postfachReducer: ActionReducerMap<any> = {
+  [POSTFACH_PATH]: postfachResourceReducer,
+};
diff --git a/alfa-client/libs/bescheid-shared/src/lib/+state/bescheid.reducer.ts b/alfa-client/libs/bescheid-shared/src/lib/+state/bescheid.reducer.ts
index 77d5d488988eb02164f9aab52f09c6b5a3553131..f8ff50bcb84c5325e570123c96385846e18377ab 100644
--- a/alfa-client/libs/bescheid-shared/src/lib/+state/bescheid.reducer.ts
+++ b/alfa-client/libs/bescheid-shared/src/lib/+state/bescheid.reducer.ts
@@ -6,21 +6,32 @@ import {
 } from '@alfa-client/command-shared';
 import {
   ApiError,
+  SingleResourceReducer,
   StateResource,
   createEmptyStateResource,
   createErrorStateResource,
+  createSingleResourceActions,
   createStateResource,
 } from '@alfa-client/tech-shared';
 import { HttpErrorResponse } from '@angular/common/http';
-import { Action, ActionReducer, createReducer, on } from '@ngrx/store';
+import { Action, ActionReducer, ActionReducerMap, createReducer, on } from '@ngrx/store';
+import { SingleResourceState } from 'libs/tech-shared/src/lib/ngrx/state.model';
 import { isCreateBescheidCommand } from '../bescheid.util';
 
 import * as CommandActions from '../../../../command-shared/src/lib/+state/command.actions';
 
 export const BESCHEID_FEATURE_KEY = 'BescheidState';
 
+export const BESCHEID_PATH = 'bescheid';
+export const BESCHEID_DRAFT_PATH = 'bescheidDraft';
+
 export interface BescheidPartialState {
-  readonly [BESCHEID_FEATURE_KEY]: BescheidState;
+  readonly [BESCHEID_FEATURE_KEY]: BescheidParentState;
+}
+
+export interface BescheidParentState {
+  bescheid: BescheidState;
+  [BESCHEID_DRAFT_PATH]?: SingleResourceState;
 }
 
 export interface BescheidState {
@@ -31,7 +42,7 @@ export const initialState: BescheidState = {
   bescheidCommand: createEmptyStateResource(),
 };
 
-const bescheidReducer: ActionReducer<BescheidState, Action> = createReducer(
+export const reducer: ActionReducer<BescheidState, Action> = createReducer(
   initialState,
   on(
     CommandActions.createCommand,
@@ -64,6 +75,17 @@ const bescheidReducer: ActionReducer<BescheidState, Action> = createReducer(
   ),
 );
 
-export function reducer(state: BescheidState, action: Action): BescheidState {
-  return bescheidReducer(state, action);
+export const bescheidReducer: ActionReducerMap<BescheidParentState> = {
+  [BESCHEID_PATH]: reducer,
+  [BESCHEID_DRAFT_PATH]: bescheidDraftResourceReducer,
+};
+
+function bescheidDraftResourceReducer(
+  state: SingleResourceState,
+  action: Action,
+): SingleResourceState {
+  const resourceReducer: SingleResourceReducer = new SingleResourceReducer(
+    createSingleResourceActions({ name: BESCHEID_FEATURE_KEY, path: BESCHEID_DRAFT_PATH }),
+  );
+  return resourceReducer.reducer(state, action);
 }
diff --git a/alfa-client/libs/bescheid-shared/src/lib/+state/bescheid.selectors.spec.ts b/alfa-client/libs/bescheid-shared/src/lib/+state/bescheid.selectors.spec.ts
index 04f7dfd10e8da45695ae20069e5d11713af0e6b0..d9e495c4069edb5f23830aa297913d0dc0d121e1 100644
--- a/alfa-client/libs/bescheid-shared/src/lib/+state/bescheid.selectors.spec.ts
+++ b/alfa-client/libs/bescheid-shared/src/lib/+state/bescheid.selectors.spec.ts
@@ -14,8 +14,10 @@ describe('Bescheid Selectors', () => {
   beforeEach(() => {
     state = {
       BescheidState: {
-        ...initialState,
-        bescheidCommand,
+        bescheid: {
+          ...initialState,
+          bescheidCommand,
+        },
       },
     };
   });
diff --git a/alfa-client/libs/bescheid-shared/src/lib/+state/bescheid.selectors.ts b/alfa-client/libs/bescheid-shared/src/lib/+state/bescheid.selectors.ts
index 78facfef40dad11ac7ae2cb68ce9679e41301e5b..cec1f1f96bb6c05eb333bbd160425c170c50a47e 100644
--- a/alfa-client/libs/bescheid-shared/src/lib/+state/bescheid.selectors.ts
+++ b/alfa-client/libs/bescheid-shared/src/lib/+state/bescheid.selectors.ts
@@ -1,12 +1,15 @@
 import { CommandResource } from '@alfa-client/command-shared';
 import { StateResource } from '@alfa-client/tech-shared';
 import { createFeatureSelector, createSelector, MemoizedSelector } from '@ngrx/store';
-import { BESCHEID_FEATURE_KEY, BescheidState } from './bescheid.reducer';
+import { BESCHEID_FEATURE_KEY, BescheidParentState, BescheidState } from './bescheid.reducer';
 
-export const getBescheidState: MemoizedSelector<object, BescheidState> =
-  createFeatureSelector<BescheidState>(BESCHEID_FEATURE_KEY);
+export const getBescheidState: MemoizedSelector<object, BescheidParentState> =
+  createFeatureSelector<BescheidParentState>(BESCHEID_FEATURE_KEY);
 
 export const bescheidCommand: MemoizedSelector<
   BescheidState,
   StateResource<CommandResource>
-> = createSelector(getBescheidState, (state: BescheidState) => state.bescheidCommand);
+> = createSelector(
+  getBescheidState,
+  (state: BescheidParentState) => state.bescheid.bescheidCommand,
+);
diff --git a/alfa-client/libs/bescheid-shared/src/lib/bescheid-shared.module.ts b/alfa-client/libs/bescheid-shared/src/lib/bescheid-shared.module.ts
index 9d1ae76fdae87d4475e12e7acc14eea3e518dc0f..9470079ed300804cf7edce1100d4047f06ed724c 100644
--- a/alfa-client/libs/bescheid-shared/src/lib/bescheid-shared.module.ts
+++ b/alfa-client/libs/bescheid-shared/src/lib/bescheid-shared.module.ts
@@ -1,9 +1,9 @@
 import { CommonModule } from '@angular/common';
 import { NgModule } from '@angular/core';
 import { StoreModule } from '@ngrx/store';
-import { BESCHEID_FEATURE_KEY, reducer } from './+state/bescheid.reducer';
+import { BESCHEID_FEATURE_KEY, bescheidReducer } from './+state/bescheid.reducer';
 
 @NgModule({
-  imports: [CommonModule, StoreModule.forFeature(BESCHEID_FEATURE_KEY, reducer)],
+  imports: [CommonModule, StoreModule.forFeature(BESCHEID_FEATURE_KEY, bescheidReducer)],
 })
 export class BescheidSharedModule {}
diff --git a/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.spec.ts b/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.spec.ts
index 66e7b66d411ac06720663d67414a8d3d93291642..62606384a666a79170e710f66297eae5ea191b8a 100644
--- a/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.spec.ts
+++ b/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.spec.ts
@@ -11,9 +11,9 @@ import {
 } from '@alfa-client/command-shared';
 import {
   ApiError,
-  EMPTY_STRING,
   HttpError,
   StateResource,
+  StateService,
   createEmptyStateResource,
   createErrorStateResource,
   createStateResource,
@@ -45,7 +45,7 @@ import {
 } from '../../../command-shared/test/command';
 import { ResourceRepository } from '../../../tech-shared/src/lib/resource/resource.repository';
 import { createFile } from '../../../tech-shared/test/file';
-import { singleCold, singleColdCompleted } from '../../../tech-shared/test/marbles';
+import { CLOSED_FRAME, singleCold, singleColdCompleted } from '../../../tech-shared/test/marbles';
 import {
   createBescheid,
   createBescheidListResource,
@@ -79,6 +79,7 @@ describe('BescheidService', () => {
   let commandService: Mock<CommandService>;
   let vorgangCommandService: Mock<VorgangCommandService>;
   let binaryFileService: Mock<BinaryFileService>;
+  let stateService: Mock<StateService>;
 
   const vorgangWithEingangStateResource: StateResource<VorgangWithEingangResource> =
     createStateResource(createVorgangWithEingangResource());
@@ -88,6 +89,7 @@ describe('BescheidService', () => {
     resourceRepository = mock(ResourceRepository);
     commandService = mock(CommandService);
     vorgangCommandService = mock(VorgangCommandService);
+    stateService = mock(StateService);
 
     vorgangService = mock(VorgangService);
     vorgangService.getVorgangWithEingang.mockReturnValue(of(vorgangWithEingangStateResource));
@@ -101,6 +103,7 @@ describe('BescheidService', () => {
       useFromMock(vorgangCommandService),
       useFromMock(binaryFileService),
       useFromMock(resourceRepository),
+      useFromMock(stateService),
     );
   });
 
@@ -215,7 +218,7 @@ describe('BescheidService', () => {
         const command$: Observable<StateResource<CommandResource>> =
           service.bescheidErstellungUeberspringen(vorgangWithEingangResource);
 
-        expect(command$).toBeObservable(cold('(a|)', { a: commandStateResource }));
+        expect(command$).toBeObservable(singleCold(commandStateResource, CLOSED_FRAME));
       });
     });
 
@@ -243,7 +246,7 @@ describe('BescheidService', () => {
         const command$: Observable<StateResource<CommandResource>> =
           service.bescheidErstellungUeberspringen(vorgangWithEingangResource);
 
-        expect(command$).toBeObservable(cold('(a|)', { a: commandStateResource }));
+        expect(command$).toBeObservable(singleCold(commandStateResource, CLOSED_FRAME));
       });
     });
   });
@@ -343,7 +346,9 @@ describe('BescheidService', () => {
           bescheidResource,
         );
 
-      expect(command$).toBeObservable(cold('(a|)', { a: vorgangAbschliessenCommandStateResource }));
+      expect(command$).toBeObservable(
+        singleCold(vorgangAbschliessenCommandStateResource, CLOSED_FRAME),
+      );
     });
   });
 
@@ -372,103 +377,71 @@ describe('BescheidService', () => {
         vorgangWithEingangResource,
       );
 
-      expect(command$).toBeObservable(cold('(a|)', { a: commandStateResource }));
+      expect(command$).toBeObservable(singleCold(commandStateResource, CLOSED_FRAME));
     });
   });
 
   describe('delete bescheid', () => {
+    const commandStateResource: StateResource<CommandResource> = createEmptyStateResource();
     const bescheidResource: BescheidResource = createBescheidResource();
 
-    it('should create command', () => {
+    beforeEach(() => {
+      service.bescheidDraftService.delete = jest.fn().mockReturnValue(of(commandStateResource));
+    });
+
+    it('should call bescheid draft service', () => {
       service.deleteBescheid(bescheidResource);
 
-      const expectedProps: CreateCommandProps = {
-        resource: bescheidResource,
-        linkRel: BescheidLinkRel.DELETE,
-        command: {
-          order: CommandOrder.DELETE_BESCHEID,
-          body: null,
-        },
-        snackBarMessage: EMPTY_STRING,
-      };
-      expect(commandService.createCommandByProps).toHaveBeenCalledWith(expectedProps);
+      expect(service.bescheidDraftService.delete).toHaveBeenCalled();
     });
 
     it('should return command', () => {
-      const commandStateResource: StateResource<CommandResource> = createEmptyStateResource();
-      commandService.createCommandByProps.mockReturnValue(commandStateResource);
-
-      const createdCommand: Observable<StateResource<CommandResource>> =
+      const deleteCommand$: Observable<StateResource<CommandResource>> =
         service.deleteBescheid(bescheidResource);
 
-      expect(createdCommand).toEqual(commandStateResource);
+      expect(deleteCommand$).toBeObservable(singleCold(commandStateResource, CLOSED_FRAME));
     });
   });
 
   describe('update bescheid', () => {
-    const bescheidResource: BescheidResource = createBescheidResource();
     const bescheid: Bescheid = createBescheid();
     const commandResource: CommandResource = createCommandResource([
       CommandLinkRel.EFFECTED_RESOURCE,
     ]);
     const commandStateResource: StateResource<CommandResource> =
       createStateResource(commandResource);
-    const createCommandProps: CreateCommandProps = createCreateCommandProps();
-    let buildUpdateBescheidCommandPropsSpy: jest.SpyInstance;
 
     beforeEach(() => {
-      buildUpdateBescheidCommandPropsSpy = jest
-        .spyOn(BescheidUtil, 'buildUpdateBescheidCommandProps')
-        .mockReturnValue(createCommandProps);
-      service.bescheidDraftService.stateResource.next(createStateResource(bescheidResource));
-      commandService.createCommandByProps.mockReturnValue(of(commandStateResource));
-      service.bescheidDraftService.loadByResourceUri = jest.fn();
-      service.getResource = jest.fn().mockReturnValue(createBescheidResource());
-    });
-
-    it('should build update bescheid command props', () => {
-      service.updateBescheid(bescheid);
-
-      expect(buildUpdateBescheidCommandPropsSpy).toHaveBeenCalledWith(
-        service.getResource(),
-        bescheid,
-      );
+      service.bescheidDraftService.save = jest.fn().mockReturnValue(of(commandStateResource));
     });
 
-    it('should create command', () => {
-      service.updateBescheid(bescheid);
+    it('should call draft service save', () => {
+      service.updateBescheid(bescheid).pipe(first()).subscribe();
 
-      expect(commandService.createCommandByProps).toHaveBeenCalledWith(createCommandProps);
+      expect(service.bescheidDraftService.save).toHaveBeenCalledWith(bescheid);
     });
 
     it('should return command', () => {
       const updateBescheid$: Observable<StateResource<CommandResource>> =
         service.updateBescheid(bescheid);
 
-      expect(updateBescheid$).toBeObservable(cold('(a|)', { a: commandStateResource }));
+      expect(updateBescheid$).toBeObservable(singleCold(commandStateResource, CLOSED_FRAME));
     });
 
-    it('should set resource by uri', (done) => {
+    it('should clear create bescheid document in progress', (done) => {
+      service.createBescheidDocumentInProgress$.next(createCommandStateResource());
+
       service
         .updateBescheid(bescheid)
         .pipe(first())
-        .subscribe((commandStateResource: StateResource<CommandResource>) => {
-          expect(service.bescheidDraftService.loadByResourceUri).toHaveBeenCalledWith(
-            getUrl(commandStateResource.resource, CommandLinkRel.EFFECTED_RESOURCE),
+        .subscribe(() => {
+          expect(service.createBescheidDocumentInProgress$.value).toEqual(
+            createEmptyStateResource(),
           );
           done();
         });
     });
 
-    it('should clear create bescheid document in progress', (done) => {
-      service.createBescheidDocumentInProgress$.next(createCommandStateResource());
-
-      service.updateBescheid(bescheid).subscribe(() => {
-        expect(service.createBescheidDocumentInProgress$.value).toEqual(createEmptyStateResource());
-        done();
-      });
-    });
-
     it('should clear upload bescheid document in progress', (done) => {
       service.uploadBescheidDocumentInProgress$.next(createUploadFileInProgress());
 
@@ -523,7 +496,7 @@ describe('BescheidService', () => {
         linkRel,
       );
 
-      expect(command$).toBeObservable(cold('(a|)', { a: commandStateResource }));
+      expect(command$).toBeObservable(singleCold(commandStateResource, CLOSED_FRAME));
     });
   });
 
@@ -577,34 +550,6 @@ describe('BescheidService', () => {
     });
   });
 
-  describe('do update bescheid', () => {
-    const bescheid: Bescheid = createBescheid();
-    const bescheidResource: BescheidResource = createBescheidResource();
-
-    const createCommandProps: CreateCommandProps = createCreateCommandProps();
-    let buildUpdateBescheidCommandPropsSpy: jest.SpyInstance;
-
-    beforeEach(() => {
-      buildUpdateBescheidCommandPropsSpy = jest
-        .spyOn(BescheidUtil, 'buildUpdateBescheidCommandProps')
-        .mockReturnValue(createCommandProps);
-      commandService.createCommandByProps.mockClear();
-      commandService.createCommandByProps.mockReturnValue(of(createCommandStateResource()));
-    });
-
-    it('should build update bescheid command props', () => {
-      service.doUpdateBescheid(bescheidResource, bescheid);
-
-      expect(buildUpdateBescheidCommandPropsSpy).toHaveBeenCalledWith(bescheidResource, bescheid);
-    });
-
-    it('should call command service', () => {
-      service.doUpdateBescheid(bescheidResource, bescheid).subscribe();
-
-      expect(commandService.createCommandByProps).toHaveBeenCalledWith(createCommandProps);
-    });
-  });
-
   describe('getAttachments', () => {
     let bescheidResource: BescheidResource;
     let binaryFileListResource: BinaryFileListResource;
diff --git a/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.ts b/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.ts
index 12e091a11c8e665039db2b52c00d535af90921a5..c3bb3fd12e66403ad28cb9e452a37c4fff051334 100644
--- a/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.ts
+++ b/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.ts
@@ -16,6 +16,7 @@ import {
   HttpError,
   ResourceListService,
   StateResource,
+  StateService,
   createEmptyStateResource,
   createStateResource,
   filterIsLoadedOrHasError,
@@ -51,8 +52,8 @@ import {
   ResourceServiceConfig,
 } from '../../../tech-shared/src/lib/resource/resource.model';
 import { ResourceRepository } from '../../../tech-shared/src/lib/resource/resource.repository';
-import { ResourceService } from '../../../tech-shared/src/lib/resource/resource.service';
 import { BescheidFacade } from './+state/bescheid.facade';
+import { BESCHEID_DRAFT_PATH, BESCHEID_FEATURE_KEY } from './+state/bescheid.reducer';
 import { BescheidLinkRel, BescheidListLinkRel } from './bescheid.linkrel';
 import {
   Bescheid,
@@ -65,16 +66,14 @@ import {
   buildCreateBescheidCommand,
   buildCreateBescheidDocumentCommandProps,
   buildCreateBescheidDocumentFromFileProps,
-  buildDeleteBescheidCommandProps,
   buildSendBescheidCommandProps,
-  buildUpdateBescheidCommandProps,
 } from './bescheid.util';
 import { DocumentLinkRel } from './document.linkrel';
 import { DocumentResource } from './document.model';
 
 @Injectable({ providedIn: 'root' })
 export class BescheidService {
-  bescheidDraftService: ResourceService<VorgangWithEingangResource, BescheidResource>;
+  bescheidDraftService: CommandResourceService<VorgangWithEingangResource, BescheidResource>;
   bescheidListService: ResourceListService<
     VorgangWithEingangResource,
     BescheidListResource,
@@ -116,10 +115,11 @@ export class BescheidService {
     private readonly vorgangCommandService: VorgangCommandService,
     private readonly binaryFileService: BinaryFileService,
     private readonly repository: ResourceRepository,
+    private readonly stateService: StateService,
   ) {
     this.bescheidDraftService = new CommandResourceService(
       this.buildBescheidDraftServiceConfig(),
-      repository,
+      this.stateService,
       this.commandService,
     );
     this.bescheidListService = new ResourceListService(
@@ -130,7 +130,8 @@ export class BescheidService {
 
   buildBescheidDraftServiceConfig(): ResourceServiceConfig<VorgangWithEingangResource> {
     return {
-      resource: this.vorgangService.getVorgangWithEingang(),
+      stateInfo: { name: BESCHEID_FEATURE_KEY, path: BESCHEID_DRAFT_PATH },
+      baseResource: this.vorgangService.getVorgangWithEingang(),
       getLinkRel: VorgangWithEingangLinkRel.BESCHEID_DRAFT,
       delete: { linkRel: BescheidLinkRel.DELETE, order: CommandOrder.DELETE_BESCHEID },
       edit: { linkRel: BescheidLinkRel.UPDATE, order: CommandOrder.UPDATE_BESCHEID },
@@ -140,17 +141,12 @@ export class BescheidService {
   buildBescheidListServiceConfig(): ListResourceServiceConfig<VorgangWithEingangResource> {
     return {
       baseResource: this.vorgangService.getVorgangWithEingang(),
-      listLinkRel: VorgangWithEingangLinkRel.BESCHEIDE,
+      getLinkRel: VorgangWithEingangLinkRel.BESCHEIDE,
       listResourceListLinkRel: BescheidListLinkRel.BESCHEID_LIST,
     };
   }
 
   public init(): void {
-    this.bescheidDraftService = new CommandResourceService(
-      this.buildBescheidDraftServiceConfig(),
-      this.repository,
-      this.commandService,
-    );
     this.bescheidDocumentFile$.next(createEmptyStateResource());
     this.bescheidDocumentUri$.next(null);
     this.uploadBescheidDocumentInProgress$.next({ loading: false });
@@ -224,9 +220,8 @@ export class BescheidService {
   }
 
   public updateBescheid(bescheid: Bescheid): Observable<StateResource<CommandResource>> {
-    return this.doUpdateBescheid(this.getResource(), bescheid).pipe(
-      tapOnCommandSuccessfullyDone((commandStateResource: StateResource<CommandResource>) => {
-        this.updateBescheidDraft(commandStateResource.resource);
+    return this.bescheidDraftService.save(bescheid).pipe(
+      tapOnCommandSuccessfullyDone(() => {
         this.clearCreateBescheidDocumentInProgress();
         this.clearUploadBescheidDocumentInProgress();
       }),
@@ -259,15 +254,6 @@ export class BescheidService {
     );
   }
 
-  doUpdateBescheid(
-    bescheidResource: BescheidResource,
-    bescheid: Bescheid,
-  ): Observable<StateResource<CommandResource>> {
-    return this.commandService.createCommandByProps(
-      buildUpdateBescheidCommandProps(bescheidResource, bescheid),
-    );
-  }
-
   private updateBescheidDraft(command: CommandResource): void {
     this.bescheidDraftService.loadByResourceUri(getEffectedResourceUrl(command));
   }
@@ -472,7 +458,7 @@ export class BescheidService {
   }
 
   deleteBescheid(bescheid: BescheidResource): Observable<StateResource<CommandResource>> {
-    return this.commandService.createCommandByProps(buildDeleteBescheidCommandProps(bescheid));
+    return this.bescheidDraftService.delete();
   }
 
   /**
diff --git a/alfa-client/libs/command-shared/src/lib/command-resource.service.spec.ts b/alfa-client/libs/command-shared/src/lib/command-resource.service.spec.ts
index 01af08536ee53c2b081a2da1a34d0823958d5e5c..8232b15b5fe17211a9b4cac1977aee035b51142d 100644
--- a/alfa-client/libs/command-shared/src/lib/command-resource.service.spec.ts
+++ b/alfa-client/libs/command-shared/src/lib/command-resource.service.spec.ts
@@ -1,50 +1,71 @@
 import {
   EMPTY_STRING,
   LinkRelationName,
-  ResourceRepository,
   ResourceServiceConfig,
+  SingleResourceStateService,
   StateResource,
+  StateService,
+  createEmptyStateResource,
   createStateResource,
 } from '@alfa-client/tech-shared';
 import { Mock, mock, useFromMock } from '@alfa-client/test-utils';
 import { Resource } from '@ngxp/rest';
-import { Observable, of } from 'rxjs';
-import { createCommandResource } from '../../../command-shared/test/command';
-import { singleCold, singleHot } from '../../../tech-shared/test/marbles';
+import { Observable, of, take } from 'rxjs';
+import {
+  createCommandResource,
+  createCreateCommandProps,
+} from '../../../command-shared/test/command';
+import { SECOND_FRAME, multiCold, singleCold } from '../../../tech-shared/test/marbles';
 import { createDummyResource } from '../../../tech-shared/test/resource';
 import { CommandResourceService } from './command-resource.service';
-import { CommandResource } from './command.model';
+import { CommandLinkRel } from './command.linkrel';
+import {
+  CommandResource,
+  CreateCommandProps,
+  DeleteCommandProps,
+  SaveCommandProps,
+} from './command.model';
 import { CommandService } from './command.service';
+import { getEffectedResourceUrl } from './command.util';
 
 describe('CommandResourceService', () => {
   let service: CommandResourceService<Resource, Resource>;
   let config: ResourceServiceConfig<Resource>;
-  let repository: Mock<ResourceRepository>;
+  let stateService: Mock<StateService>;
   let commandService: Mock<CommandService>;
 
-  const configResource: Resource = createDummyResource();
-  const configStateResource: StateResource<Resource> = createStateResource(configResource);
-  const configStateResource$: Observable<StateResource<Resource>> = of(configStateResource);
+  const getLinkRel: LinkRelationName = 'dummyGetLinkRel';
 
   const editLinkRel: string = 'dummyEditLinkRel';
-  const getLinkRel: LinkRelationName = 'dummyGetLinkRel';
+  const editOrder: string = 'dummyEditOrder';
 
   const deleteOrder: string = 'dummyDeleteOrder';
   const deleteLinkRel: string = 'dummyDeleteLinkRel';
 
+  const dummyResource: Resource = createDummyResource();
+  const dummyStateResource: StateResource<Resource> = createStateResource(dummyResource);
+
+  const configResource: Resource = createDummyResource([getLinkRel, editLinkRel]);
+  const configStateResource: StateResource<Resource> = createStateResource(configResource);
+  const configStateResource$: Observable<StateResource<Resource>> = of(configStateResource);
+
   beforeEach(() => {
     config = {
-      resource: configStateResource$,
+      stateInfo: { name: 'dummyStateName', path: 'dummyStatePath' },
+      baseResource: configStateResource$,
       getLinkRel,
-      edit: { linkRel: editLinkRel },
+      edit: { order: editOrder, linkRel: editLinkRel },
       delete: { order: deleteOrder, linkRel: deleteLinkRel },
     };
-    repository = mock(ResourceRepository);
+    stateService = mock(StateService);
+    stateService.createSingleResourceService = jest
+      .fn()
+      .mockReturnValue(mock(SingleResourceStateService));
     commandService = mock(CommandService);
 
     service = new CommandResourceService(
       config,
-      useFromMock(repository),
+      useFromMock(stateService),
       useFromMock(commandService),
     );
   });
@@ -53,37 +74,259 @@ describe('CommandResourceService', () => {
     expect(service).toBeTruthy();
   });
 
-  describe('delete', () => {
-    const resourceWithDeleteLinkRel: Resource = createDummyResource([deleteLinkRel]);
-    const stateResourceWithDeleteLink: StateResource<Resource> =
-      createStateResource(resourceWithDeleteLinkRel);
+  it('should be create resource state service', () => {
+    expect(service.resourceStateService).toBeTruthy();
+  });
+
+  describe('save', () => {
+    const dummyToSave: unknown = {};
+
+    const commandResource: CommandResource = createCommandResource([
+      CommandLinkRel.EFFECTED_RESOURCE,
+    ]);
+    const commandStateResource: StateResource<CommandResource> =
+      createStateResource(commandResource);
 
     beforeEach(() => {
-      commandService.createCommandByProps.mockReturnValue(
-        of(createStateResource(createCommandResource())),
+      service.doSave = jest.fn().mockReturnValue(of(commandStateResource));
+      service.resourceStateService.selectResource = jest
+        .fn()
+        .mockReturnValue(of(dummyStateResource));
+      service.loadByResourceUri = jest.fn();
+    });
+
+    it('should do save', () => {
+      service.save(dummyToSave).pipe(take(2)).subscribe();
+
+      expect(service.doSave).toHaveBeenCalledWith(dummyResource, dummyToSave, {
+        snackBarMessage: EMPTY_STRING,
+      });
+    });
+
+    it('should loadByResourceUri on sucessfully done command', () => {
+      service.save(dummyToSave).pipe(take(2)).subscribe();
+
+      expect(service.loadByResourceUri).toHaveBeenCalledWith(
+        getEffectedResourceUrl(commandResource),
       );
-      service.stateResource.next(stateResourceWithDeleteLink);
+    });
+
+    it('should return initial value', () => {
+      service.doSave = jest.fn().mockReturnValue(singleCold(commandStateResource, SECOND_FRAME));
+
+      const initialResponse$: Observable<StateResource<CommandResource>> =
+        service.save(dummyToSave);
+
+      expect(initialResponse$).toBeObservable(
+        multiCold({ a: createEmptyStateResource(true), b: commandStateResource }),
+      );
+    });
+  });
+
+  describe('do save', () => {
+    const dummyToSave: unknown = {};
+    const dummy: Resource = createDummyResource();
+    const saveCommandProps: SaveCommandProps = { snackBarMessage: EMPTY_STRING };
+    const createCommandProps: CreateCommandProps = createCreateCommandProps();
+
+    let buildSaveBescheidCommandPropsSpy: jest.SpyInstance;
+
+    beforeEach(() => {
+      buildSaveBescheidCommandPropsSpy = service.buildSaveBescheidCommandProps = jest
+        .fn()
+        .mockReturnValue(createCommandProps);
     });
 
     it('should call command service', () => {
-      service.delete();
+      service.doSave(dummy, dummyToSave, saveCommandProps);
+
+      expect(commandService.createCommandByProps).toHaveBeenCalledWith(createCommandProps);
+    });
+
+    it('should build command', () => {
+      service.doSave(dummy, dummyToSave, saveCommandProps);
+
+      expect(buildSaveBescheidCommandPropsSpy).toHaveBeenCalledWith(
+        dummy,
+        dummyToSave,
+        saveCommandProps,
+      );
+    });
+  });
+
+  describe('build save bescheid command props', () => {
+    const resource: Resource = createDummyResource();
+    const dummyToSave: unknown = {};
+    const saveCommandProps: SaveCommandProps = { snackBarMessage: EMPTY_STRING };
+
+    it('should have resource', () => {
+      const props: CreateCommandProps = service.buildSaveBescheidCommandProps(
+        resource,
+        dummyToSave,
+        saveCommandProps,
+      );
+
+      expect(props.resource).toBe(resource);
+    });
+
+    it('should have linkRel', () => {
+      const props: CreateCommandProps = service.buildSaveBescheidCommandProps(
+        resource,
+        dummyToSave,
+        saveCommandProps,
+      );
+
+      expect(props.linkRel).toBe(editLinkRel);
+    });
+
+    describe('command', () => {
+      it('should have order', () => {
+        const props: CreateCommandProps = service.buildSaveBescheidCommandProps(
+          resource,
+          dummyToSave,
+          saveCommandProps,
+        );
+
+        expect(props.command.order).toBe(editOrder);
+      });
+
+      it('should have body', () => {
+        const props: CreateCommandProps = service.buildSaveBescheidCommandProps(
+          resource,
+          dummyToSave,
+          saveCommandProps,
+        );
 
-      expect(commandService.createCommandByProps).toHaveBeenCalledWith({
-        resource: resourceWithDeleteLinkRel,
-        linkRel: deleteLinkRel,
-        command: { order: deleteOrder, body: null },
+        expect(props.command.body).toBe(dummyToSave);
+      });
+    });
+
+    it('should have snackBarMessage', () => {
+      const props: CreateCommandProps = service.buildSaveBescheidCommandProps(
+        resource,
+        dummyToSave,
+        saveCommandProps,
+      );
+
+      expect(props.snackBarMessage).toBe(saveCommandProps.snackBarMessage);
+    });
+  });
+
+  describe('delete', () => {
+    const commandResource: CommandResource = createCommandResource([
+      CommandLinkRel.EFFECTED_RESOURCE,
+    ]);
+    const commandStateResource: StateResource<CommandResource> =
+      createStateResource(commandResource);
+
+    beforeEach(() => {
+      service.doDelete = jest.fn().mockReturnValue(of(commandStateResource));
+      service.resourceStateService.selectResource = jest
+        .fn()
+        .mockReturnValue(of(dummyStateResource));
+      service.clearResource = jest.fn();
+    });
+
+    it('should do delete', () => {
+      service.delete().pipe(take(2)).subscribe();
+
+      expect(service.doDelete).toHaveBeenCalledWith(dummyResource, {
         snackBarMessage: EMPTY_STRING,
       });
     });
 
-    it('should return value', () => {
-      const deleteResource: Resource = createDummyResource();
-      const deleteStateResource: StateResource<Resource> = createStateResource(deleteResource);
-      commandService.createCommandByProps.mockReturnValue(singleHot(deleteStateResource));
+    it('should loadByResourceUri on sucessfully done command', () => {
+      service.delete().pipe(take(2)).subscribe();
+
+      expect(service.clearResource).toHaveBeenCalled();
+    });
+
+    it('should return initial value', () => {
+      service.doDelete = jest.fn().mockReturnValue(singleCold(commandStateResource, SECOND_FRAME));
+
+      const initialResponse$: Observable<StateResource<CommandResource>> = service.delete();
+
+      expect(initialResponse$).toBeObservable(
+        multiCold({ a: createEmptyStateResource(true), b: commandStateResource }),
+      );
+    });
+  });
+
+  describe('do delete', () => {
+    const dummy: Resource = createDummyResource();
+    const deleteCommandProps: DeleteCommandProps = { snackBarMessage: EMPTY_STRING };
+    const createCommandProps: CreateCommandProps = createCreateCommandProps();
+
+    let buildDeleteCommandPropsSpy: jest.SpyInstance;
+
+    beforeEach(() => {
+      buildDeleteCommandPropsSpy = service.buildDeleteCommandProps = jest
+        .fn()
+        .mockReturnValue(createCommandProps);
+    });
+
+    it('should call command service', () => {
+      service.doDelete(dummy, deleteCommandProps);
+
+      expect(commandService.createCommandByProps).toHaveBeenCalledWith(createCommandProps);
+    });
+
+    it('should build command', () => {
+      service.doDelete(dummy, deleteCommandProps);
+
+      expect(buildDeleteCommandPropsSpy).toHaveBeenCalledWith(dummy, deleteCommandProps);
+    });
+  });
+
+  describe('build delete bescheid command props', () => {
+    const resource: Resource = createDummyResource();
+    const deleteCommandProps: SaveCommandProps = { snackBarMessage: EMPTY_STRING };
+
+    it('should have resource', () => {
+      const props: CreateCommandProps = service.buildDeleteCommandProps(
+        resource,
+        deleteCommandProps,
+      );
+
+      expect(props.resource).toBe(resource);
+    });
+
+    it('should have linkRel', () => {
+      const props: CreateCommandProps = service.buildDeleteCommandProps(
+        resource,
+        deleteCommandProps,
+      );
 
-      const deletedResource: Observable<StateResource<CommandResource>> = service.delete();
+      expect(props.linkRel).toBe(deleteLinkRel);
+    });
+
+    describe('command', () => {
+      it('should have order', () => {
+        const props: CreateCommandProps = service.buildDeleteCommandProps(
+          resource,
+          deleteCommandProps,
+        );
+
+        expect(props.command.order).toBe(deleteOrder);
+      });
+
+      it('should have body', () => {
+        const props: CreateCommandProps = service.buildDeleteCommandProps(
+          resource,
+          deleteCommandProps,
+        );
+
+        expect(props.command.body).toBeNull();
+      });
+    });
+
+    it('should have snackBarMessage', () => {
+      const props: CreateCommandProps = service.buildDeleteCommandProps(
+        resource,
+        deleteCommandProps,
+      );
 
-      expect(deletedResource).toBeObservable(singleCold(deleteStateResource));
+      expect(props.snackBarMessage).toBe(deleteCommandProps.snackBarMessage);
     });
   });
 });
diff --git a/alfa-client/libs/command-shared/src/lib/command-resource.service.ts b/alfa-client/libs/command-shared/src/lib/command-resource.service.ts
index 9a564442fd23862a0c85f645a6a93573ddca3612..cd2b14471e15e1765d9a0b69a5f5aacc2daef349 100644
--- a/alfa-client/libs/command-shared/src/lib/command-resource.service.ts
+++ b/alfa-client/libs/command-shared/src/lib/command-resource.service.ts
@@ -1,46 +1,112 @@
 import {
   EMPTY_STRING,
-  ResourceRepository,
   ResourceService,
   ResourceServiceConfig,
   StateResource,
+  StateService,
   createEmptyStateResource,
+  isStateResoureStable,
 } from '@alfa-client/tech-shared';
 import { Resource } from '@ngxp/rest';
-import { BehaviorSubject, Observable } from 'rxjs';
-import { CommandResource, CreateCommandProps } from './command.model';
+import { Observable, filter, startWith, switchMap } from 'rxjs';
+import {
+  CommandResource,
+  CreateCommandProps,
+  DeleteCommandProps,
+  SaveCommandProps,
+} from './command.model';
+import { tapOnCommandSuccessfullyDone } from './command.rxjs.operator';
 import { CommandService } from './command.service';
+import { getEffectedResourceUrl } from './command.util';
 
 export class CommandResourceService<B extends Resource, T extends Resource> extends ResourceService<
   B,
   T
 > {
-  deleteStateCommandResource: BehaviorSubject<StateResource<CommandResource>> = new BehaviorSubject<
-    StateResource<CommandResource>
-  >(createEmptyStateResource());
-
   constructor(
     protected config: ResourceServiceConfig<B>,
-    protected repository: ResourceRepository,
+    protected stateService: StateService,
     private commandService: CommandService,
   ) {
-    super(config, repository);
+    super(config, stateService);
+  }
+
+  public save(
+    toSave: unknown,
+    saveCommandProps: SaveCommandProps = { snackBarMessage: EMPTY_STRING },
+  ): Observable<StateResource<CommandResource>> {
+    return this.selectResource().pipe(
+      switchMap((stateResource: StateResource<T>) =>
+        this.doSave(stateResource.resource, toSave, saveCommandProps),
+      ),
+      tapOnCommandSuccessfullyDone((commandStateResource: StateResource<CommandResource>) =>
+        this.loadByResourceUri(getEffectedResourceUrl(commandStateResource.resource)),
+      ),
+      filter(isStateResoureStable),
+      startWith(createEmptyStateResource<CommandResource>(true)),
+    );
+  }
+
+  doSave(
+    resource: T,
+    toSave: unknown,
+    saveCommandProps: SaveCommandProps,
+  ): Observable<StateResource<CommandResource>> {
+    return this.commandService.createCommandByProps(
+      this.buildSaveBescheidCommandProps<T>(resource, toSave, saveCommandProps),
+    );
+  }
+
+  buildSaveBescheidCommandProps<T extends Resource>(
+    resource: T,
+    toSave: unknown,
+    saveCommandProps: SaveCommandProps,
+  ): CreateCommandProps {
+    return {
+      resource,
+      linkRel: this.config.edit.linkRel,
+      command: {
+        order: this.config.edit.order,
+        body: toSave,
+      },
+      snackBarMessage: saveCommandProps.snackBarMessage,
+    };
   }
 
-  doSave(resource: T, toSave: unknown): Observable<T> {
-    throw new Error('Method not implemented.');
+  public delete(
+    deleteCommandProps: DeleteCommandProps = { snackBarMessage: EMPTY_STRING },
+  ): Observable<StateResource<CommandResource>> {
+    return this.selectResource().pipe(
+      switchMap((stateResource: StateResource<T>) =>
+        this.doDelete(stateResource.resource, deleteCommandProps),
+      ),
+      tapOnCommandSuccessfullyDone(() => this.clearResource()),
+      filter(isStateResoureStable),
+      startWith(createEmptyStateResource<CommandResource>(true)),
+    );
   }
 
-  public delete(): Observable<StateResource<CommandResource>> {
-    return this.commandService.createCommandByProps(this.buildDeleteCommandProps());
+  doDelete(
+    resource: T,
+    deleteCommandProps: DeleteCommandProps,
+  ): Observable<StateResource<CommandResource>> {
+    return this.commandService.createCommandByProps(
+      this.buildDeleteCommandProps(resource, deleteCommandProps),
+    );
   }
 
-  private buildDeleteCommandProps(): CreateCommandProps {
+  buildDeleteCommandProps<T extends Resource>(
+    resource: T,
+    deleteCommandProps: DeleteCommandProps,
+  ): CreateCommandProps {
     return {
-      resource: this.stateResource.value.resource,
+      resource,
       linkRel: this.config.delete.linkRel,
-      command: { order: this.config.delete.order, body: null },
-      snackBarMessage: EMPTY_STRING,
+      command: {
+        order: this.config.delete.order,
+        body: null,
+      },
+      snackBarMessage: deleteCommandProps.snackBarMessage,
     };
   }
 }
diff --git a/alfa-client/libs/command-shared/src/lib/command.model.ts b/alfa-client/libs/command-shared/src/lib/command.model.ts
index 947b7251c473ceec77e0438c299eca6c799a0752..49fa06eef50a1273187099e6d2f604d14a80df07 100644
--- a/alfa-client/libs/command-shared/src/lib/command.model.ts
+++ b/alfa-client/libs/command-shared/src/lib/command.model.ts
@@ -88,6 +88,7 @@ export enum CommandOrder {
   SEND_BESCHEID = 'SEND_BESCHEID',
 }
 
+//TODO rename CreateCommandProps -> CreateCommandActionProps
 export interface CreateCommandProps {
   resource: Resource;
   linkRel: string;
@@ -96,3 +97,11 @@ export interface CreateCommandProps {
   snackBarMessage?: string;
   snackBarErrorMessage?: string;
 }
+
+export interface SaveCommandProps {
+  snackBarMessage: string;
+}
+
+export interface DeleteCommandProps {
+  snackBarMessage: string;
+}
diff --git a/alfa-client/libs/tech-shared/src/index.ts b/alfa-client/libs/tech-shared/src/index.ts
index 64e34b9ffcb66244bb7687070f685ed6090b4950..7f8a805b1726ef9f0f36aa3b4b749e843d9805cd 100644
--- a/alfa-client/libs/tech-shared/src/index.ts
+++ b/alfa-client/libs/tech-shared/src/index.ts
@@ -31,6 +31,8 @@ export * from './lib/form.util';
 export * from './lib/http.util';
 export * from './lib/message-code';
 export * from './lib/ngrx/actions';
+export * from './lib/ngrx/resource.reducer';
+export * from './lib/ngrx/state.service';
 export * from './lib/pipe/convert-api-error-to-error-messages.pipe';
 export * from './lib/pipe/convert-for-data-test.pipe';
 export * from './lib/pipe/convert-to-boolean.pipe';
diff --git a/alfa-client/libs/tech-shared/src/lib/decorator/skip-error-interceptor.decorator.spec.ts b/alfa-client/libs/tech-shared/src/lib/decorator/skip-error-interceptor.decorator.spec.ts
index d2096fdd1f39ae8c44dd8d7807a44a0ae81026b2..b24febea161d32ce63d2ed81c0bee5aa140e3a0a 100644
--- a/alfa-client/libs/tech-shared/src/lib/decorator/skip-error-interceptor.decorator.spec.ts
+++ b/alfa-client/libs/tech-shared/src/lib/decorator/skip-error-interceptor.decorator.spec.ts
@@ -21,17 +21,16 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-import { Mock, mock } from '@alfa-client/test-utils';
-import { HttpErrorHandler } from '../error/error.handler';
+import { SkipInterceptor } from './skip-error-interceptor.decorator';
 
 describe('SkipInterceptor Decorator', () => {
-  let httpErrorHandler: Mock<HttpErrorHandler>;
+  let interceptor: MethodDecorator;
 
   beforeEach(() => {
-    httpErrorHandler = mock(HttpErrorHandler);
+    interceptor = SkipInterceptor();
   });
 
-  it.skip('should be created', () => {
-    //expect(SkipInterceptor()).toBeTruthy();
+  it('should be created', () => {
+    expect(interceptor).toBeTruthy();
   });
 });
diff --git a/alfa-client/libs/tech-shared/src/lib/ngrx/actions.ts b/alfa-client/libs/tech-shared/src/lib/ngrx/actions.ts
index 907ccaf7749c9f9cb7438addf98a0da8b56de6dc..331f65845f7cbcd5fae4f014cdd7aca56c7ae665 100644
--- a/alfa-client/libs/tech-shared/src/lib/ngrx/actions.ts
+++ b/alfa-client/libs/tech-shared/src/lib/ngrx/actions.ts
@@ -21,10 +21,11 @@
  * Die sprachspezifischen Genehmigungen und Beschränkungen
  * unter der Lizenz sind dem Lizenztext zu entnehmen.
  */
-import { Action, ActionCreator } from '@ngrx/store';
+import { Action, ActionCreator, createAction, props } from '@ngrx/store';
 import { TypedAction } from '@ngrx/store/src/models';
-import { ResourceUri } from '@ngxp/rest';
-import { ApiError } from '../tech.model';
+import { Resource, ResourceUri } from '@ngxp/rest';
+import { StateInfo } from '../resource/resource.model';
+import { ApiError, HttpError } from '../tech.model';
 
 export const EMPTY_ACTION: Action = {} as Action;
 
@@ -40,3 +41,64 @@ export interface ApiErrorAction {
 export interface ResourceUriProps {
   resourceUri: ResourceUri;
 }
+
+export interface LoadResourceSuccessProps {
+  resource: Resource;
+}
+
+export interface LoadResourceFailureProps {
+  error: HttpError;
+}
+export interface ResourceActions {
+  loadAction: TypedActionCreatorWithProps<ResourceUriProps>;
+  loadFailureAction: TypedActionCreatorWithProps<LoadResourceFailureProps>;
+  clearAction: TypedActionCreator;
+  reloadAction: TypedActionCreator;
+}
+
+export interface SingleResourceLoadActions extends ResourceActions {
+  loadSuccessAction: TypedActionCreatorWithProps<LoadResourceSuccessProps>;
+}
+
+export function createSingleResourceActions(stateInfo: StateInfo): SingleResourceLoadActions {
+  const actions: ResourceActions = createResourceActions(
+    stateInfo.name,
+    `${stateInfo.path} Resource`,
+  );
+  return { ...actions, loadSuccessAction: createLoadSuccessAction(stateInfo) };
+}
+
+export interface SingleResourceLoadActions extends ResourceActions {
+  loadSuccessAction: TypedActionCreatorWithProps<LoadResourceSuccessProps>;
+}
+
+function createLoadSuccessAction(
+  stateInfo: StateInfo,
+): TypedActionCreatorWithProps<LoadResourceSuccessProps> {
+  return createAction(
+    createActionType(stateInfo.name, `Load ${stateInfo.path} Resource Success`),
+    props<LoadResourceSuccessProps>(),
+  );
+}
+
+function createResourceActions(stateName: string, message: string): ResourceActions {
+  const loadAction: TypedActionCreatorWithProps<ResourceUriProps> = createAction(
+    createActionType(stateName, `Load ${message}`),
+    props<ResourceUriProps>(),
+  );
+  const loadFailureAction: TypedActionCreatorWithProps<LoadResourceFailureProps> = createAction(
+    createActionType(stateName, `Load ${message} Failure`),
+    props<LoadResourceFailureProps>(),
+  );
+  const clearAction: TypedActionCreator = createAction(
+    createActionType(stateName, `Clear ${message}`),
+  );
+  const reloadAction: TypedActionCreator = createAction(
+    createActionType(stateName, `Reload ${message}`),
+  );
+  return { loadAction, loadFailureAction, clearAction, reloadAction };
+}
+
+function createActionType(stateName: string, message: string): string {
+  return `[${stateName}] ${message}`;
+}
diff --git a/alfa-client/libs/tech-shared/src/lib/ngrx/effects.service.spec.ts b/alfa-client/libs/tech-shared/src/lib/ngrx/effects.service.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..84ddd441009d1dbfda1116bbcf80708bc1552c51
--- /dev/null
+++ b/alfa-client/libs/tech-shared/src/lib/ngrx/effects.service.spec.ts
@@ -0,0 +1,31 @@
+import { Mock, mock, useFromMock } from '@alfa-client/test-utils';
+import { Actions, EffectSources } from '@ngrx/effects';
+import { of } from 'rxjs';
+import { ResourceRepository } from '../resource/resource.repository';
+import { SingleResourceLoadActions } from './actions';
+import { EffectService } from './effects.service';
+
+describe('EffectService', () => {
+  let service: EffectService;
+  let actions: Actions;
+  let effectSources: Mock<EffectSources>;
+  let repository: Mock<ResourceRepository>;
+
+  const resourceActions: Mock<SingleResourceLoadActions> = <any>{};
+
+  beforeEach(() => {
+    actions = of();
+    effectSources = mock(EffectSources);
+    repository = mock(ResourceRepository);
+
+    service = new EffectService(actions, useFromMock(effectSources), useFromMock(repository));
+  });
+
+  describe('add single resource effect', () => {
+    it('should call effect sources to add effect', () => {
+      service.addSingleResourceEffects(useFromMock(resourceActions));
+
+      expect(effectSources.addEffects).toHaveBeenCalled();
+    });
+  });
+});
diff --git a/alfa-client/libs/tech-shared/src/lib/ngrx/effects.service.ts b/alfa-client/libs/tech-shared/src/lib/ngrx/effects.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..cba87ff7d15b3897c545f50e2dac2b9f6f8eea60
--- /dev/null
+++ b/alfa-client/libs/tech-shared/src/lib/ngrx/effects.service.ts
@@ -0,0 +1,20 @@
+import { Injectable } from '@angular/core';
+import { Actions, EffectSources } from '@ngrx/effects';
+import { ResourceRepository } from '../resource/resource.repository';
+import { SingleResourceLoadActions } from './actions';
+import { ResourceEffects } from './resource.effects';
+
+@Injectable()
+export class EffectService {
+  constructor(
+    private actions$: Actions,
+    private effectSources: EffectSources,
+    private repository: ResourceRepository,
+  ) {}
+
+  public addSingleResourceEffects(resourceActions: SingleResourceLoadActions): void {
+    this.effectSources.addEffects({
+      ...new ResourceEffects(this.actions$, this.repository, resourceActions),
+    });
+  }
+}
diff --git a/alfa-client/libs/tech-shared/src/lib/ngrx/resource.effects.spec.ts b/alfa-client/libs/tech-shared/src/lib/ngrx/resource.effects.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5eeb93862c13d746400e24a4d6953b289d5b5cd1
--- /dev/null
+++ b/alfa-client/libs/tech-shared/src/lib/ngrx/resource.effects.spec.ts
@@ -0,0 +1,118 @@
+import {
+  ApiError,
+  LoadResourceFailureProps,
+  LoadResourceSuccessProps,
+  ResourceRepository,
+  ResourceUriProps,
+  SingleResourceLoadActions,
+  TypedActionCreator,
+  TypedActionCreatorWithProps,
+} from '@alfa-client/tech-shared';
+import { Mock, mock } from '@alfa-client/test-utils';
+import { TestBed } from '@angular/core/testing';
+import { Actions } from '@ngrx/effects';
+import { provideMockActions } from '@ngrx/effects/testing';
+import { Action, createAction, props } from '@ngrx/store';
+import { provideMockStore } from '@ngrx/store/testing';
+import { Resource, ResourceUri } from '@ngxp/rest';
+import { ObservableWithSubscriptions, cold, hot } from 'jest-marbles';
+import { createApiError } from 'libs/tech-shared/test/error';
+import { createDummyResource } from 'libs/tech-shared/test/resource';
+import { Observable, of } from 'rxjs';
+import { ResourceEffects } from './resource.effects';
+
+describe('ResourceEffects', () => {
+  let effects: ResourceEffects<Resource>;
+
+  let actions: Observable<Action>;
+  let repository: Mock<ResourceRepository> = mock(ResourceRepository);
+
+  const loadAction: TypedActionCreatorWithProps<ResourceUriProps> = createAction(
+    'DummyLoadAction',
+    props<ResourceUriProps>(),
+  );
+
+  const loadSuccessAction: TypedActionCreatorWithProps<LoadResourceSuccessProps> = createAction(
+    'DummyLoadSuccessAction',
+    props<LoadResourceSuccessProps>(),
+  );
+
+  const loadFailureAction: TypedActionCreatorWithProps<LoadResourceFailureProps> = createAction(
+    'DummyLoadFailureAction',
+    props<LoadResourceFailureProps>(),
+  );
+
+  const clearAction: TypedActionCreator = createAction('DummyClearAction');
+
+  const reloadAction: TypedActionCreator = createAction('DummyReloadAction');
+
+  const resourceActions: SingleResourceLoadActions = {
+    loadAction,
+    loadSuccessAction,
+    loadFailureAction,
+    clearAction,
+    reloadAction,
+  };
+
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [
+        provideMockActions(() => actions),
+        provideMockStore(),
+        {
+          provide: ResourceRepository,
+          useValue: repository,
+        },
+        {
+          provide: ResourceEffects,
+          useFactory: (actions$: Actions, repository: ResourceRepository) =>
+            new ResourceEffects<Resource>(actions$, repository, resourceActions),
+          deps: [Actions, ResourceRepository],
+        },
+      ],
+    });
+
+    effects = TestBed.inject(ResourceEffects);
+  });
+
+  describe('loadVorgangList', () => {
+    const resourceUri: ResourceUri = 'dummyResourceUri';
+    const dummyResource: Resource = createDummyResource();
+
+    beforeEach(() => {
+      repository.getResource.mockReturnValue(of(dummyResource));
+    });
+
+    it('should call repository', (done) => {
+      actions = of(loadAction({ resourceUri }));
+
+      effects.loadByUri$.subscribe(() => {
+        expect(repository.getResource).toHaveBeenCalledWith(resourceUri);
+        done();
+      });
+    });
+
+    it('should dispatch loadSuccessAction action', () => {
+      actions = hot('-a-|', { a: loadAction({ resourceUri }) });
+
+      const expected: ObservableWithSubscriptions = hot('-a-|', {
+        a: resourceActions.loadSuccessAction({ resource: dummyResource }),
+      });
+
+      expect(effects.loadByUri$).toBeObservable(expected);
+    });
+
+    it('should dispatch loadFailureAction action', () => {
+      const apiError: ApiError = createApiError();
+      const errorResponse: ObservableWithSubscriptions = cold('-#', {}, apiError);
+      repository.getResource = jest.fn(() => errorResponse);
+
+      actions = hot('-a', { a: loadAction({ resourceUri }) });
+
+      const expected: ObservableWithSubscriptions = cold('--b', {
+        b: resourceActions.loadFailureAction({ error: apiError }),
+      });
+      expect(effects.loadByUri$).toBeObservable(expected);
+    });
+  });
+});
diff --git a/alfa-client/libs/tech-shared/src/lib/ngrx/resource.effects.ts b/alfa-client/libs/tech-shared/src/lib/ngrx/resource.effects.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ca5100d16f7fce7054fb5c607f2aa32230c95088
--- /dev/null
+++ b/alfa-client/libs/tech-shared/src/lib/ngrx/resource.effects.ts
@@ -0,0 +1,26 @@
+import { Actions, createEffect, ofType } from '@ngrx/effects';
+import { Resource } from '@ngxp/rest';
+import { of } from 'rxjs';
+import { catchError, map, switchMap } from 'rxjs/operators';
+import { ResourceRepository } from '../resource/resource.repository';
+import { ResourceUriProps, SingleResourceLoadActions } from './actions';
+
+export class ResourceEffects<T extends Resource> {
+  constructor(
+    private actions$: Actions,
+    private repository: ResourceRepository,
+    private resourceActions: SingleResourceLoadActions,
+  ) {}
+
+  loadByUri$ = createEffect(() =>
+    this.actions$.pipe(
+      ofType(this.resourceActions.loadAction),
+      switchMap((props: ResourceUriProps) => {
+        return this.repository.getResource<T>(props.resourceUri).pipe(
+          map((resource: T) => this.resourceActions.loadSuccessAction({ resource })),
+          catchError((error) => of(this.resourceActions.loadFailureAction({ error }))),
+        );
+      }),
+    ),
+  );
+}
diff --git a/alfa-client/libs/tech-shared/src/lib/ngrx/resource.redicer.spec.ts b/alfa-client/libs/tech-shared/src/lib/ngrx/resource.redicer.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..dd51a4cdaf28a7f170c3d06663d59e9eee16a586
--- /dev/null
+++ b/alfa-client/libs/tech-shared/src/lib/ngrx/resource.redicer.spec.ts
@@ -0,0 +1,99 @@
+import faker from '@faker-js/faker';
+import { Action } from '@ngrx/store';
+import { TypedAction } from '@ngrx/store/src/models';
+import { Resource, ResourceUri } from '@ngxp/rest';
+import { createApiError } from 'libs/tech-shared/test/error';
+import { singleResourceActions } from 'libs/tech-shared/test/ngrx';
+import { createDummyResource } from 'libs/tech-shared/test/resource';
+import { createEmptyStateResource, createStateResource } from '../resource/resource.util';
+import { ApiError } from '../tech.model';
+import {
+  LoadResourceFailureProps,
+  LoadResourceSuccessProps,
+  SingleResourceLoadActions,
+} from './actions';
+import { SingleResourceReducer } from './resource.reducer';
+import { SingleResourceState, initialResourceState } from './state.model';
+
+describe('SingleResourceReducer', () => {
+  const resourceActions: SingleResourceLoadActions = singleResourceActions;
+
+  const reducer = new SingleResourceReducer(resourceActions);
+
+  describe('unknown action', () => {
+    it('should return current state', () => {
+      const action = {} as Action;
+
+      const result = reducer.reducer(initialResourceState, action);
+
+      expect(result).toBe(initialResourceState);
+    });
+  });
+  describe('on load action', () => {
+    const resourceUri: ResourceUri = faker.internet.url();
+
+    it('should set loading to true', () => {
+      const action = resourceActions.loadAction({ resourceUri });
+
+      const state: SingleResourceState = reducer.reducer(initialResourceState, action);
+
+      expect(state.resource.loading).toBeTruthy();
+    });
+  });
+
+  describe('on load success action', () => {
+    const resource: Resource = createDummyResource();
+    const action: LoadResourceSuccessProps & TypedAction<string> =
+      resourceActions.loadSuccessAction({ resource });
+
+    it('should set resource', () => {
+      const state: SingleResourceState = reducer.reducer(initialResourceState, action);
+
+      expect(state.resource.resource).toStrictEqual(resource);
+    });
+  });
+
+  describe('on load failure action', () => {
+    const apiError: ApiError = createApiError();
+    const action: LoadResourceFailureProps & TypedAction<string> =
+      resourceActions.loadFailureAction({
+        error: apiError,
+      });
+
+    it('should set apiError', () => {
+      const state: SingleResourceState = reducer.reducer(initialResourceState, action);
+
+      expect(state.resource.error).toStrictEqual(apiError);
+    });
+  });
+
+  describe('on clear action', () => {
+    const action: TypedAction<string> = resourceActions.clearAction();
+
+    it('should clear stateresource', () => {
+      const initialState: SingleResourceState = {
+        ...initialResourceState,
+        resource: createStateResource(createDummyResource()),
+      };
+
+      const state: SingleResourceState = reducer.reducer(initialState, action);
+
+      expect(state.resource).toEqual(createEmptyStateResource());
+    });
+  });
+
+  describe('on reload action', () => {
+    const action: TypedAction<string> = resourceActions.reloadAction();
+
+    it('should mark stateresource as reload', () => {
+      const initialState: SingleResourceState = {
+        ...initialResourceState,
+        resource: createEmptyStateResource(),
+      };
+
+      const state: SingleResourceState = reducer.reducer(initialState, action);
+
+      expect(state.resource.reload).toBeTruthy();
+    });
+  });
+});
diff --git a/alfa-client/libs/tech-shared/src/lib/ngrx/resource.reducer.ts b/alfa-client/libs/tech-shared/src/lib/ngrx/resource.reducer.ts
new file mode 100644
index 0000000000000000000000000000000000000000..96ed418280bd62c755cba690d74f286e731a8df2
--- /dev/null
+++ b/alfa-client/libs/tech-shared/src/lib/ngrx/resource.reducer.ts
@@ -0,0 +1,62 @@
+import { Action, ActionReducer, createReducer, on } from '@ngrx/store';
+import {
+  createEmptyStateResource,
+  createErrorStateResource,
+  createStateResource,
+} from '../resource/resource.util';
+import {
+  LoadResourceFailureProps,
+  LoadResourceSuccessProps,
+  SingleResourceLoadActions,
+} from './actions';
+import { SingleResourceState, initialResourceState } from './state.model';
+
+export class SingleResourceReducer {
+  public reducer: ActionReducer<SingleResourceState, Action>;
+
+  constructor(private actions: SingleResourceLoadActions) {
+    this.initReducer();
+  }
+
+  initReducer(): void {
+    this.reducer = createReducer(
+      initialResourceState,
+      on(this.actions.loadAction, (state: SingleResourceState): SingleResourceState => {
+        return {
+          ...state,
+          resource: { ...state.resource, loading: true },
+        };
+      }),
+      on(
+        this.actions.loadSuccessAction,
+        (state: SingleResourceState, props: LoadResourceSuccessProps): SingleResourceState => {
+          return {
+            ...state,
+            resource: createStateResource(props.resource),
+          };
+        },
+      ),
+      on(
+        this.actions.loadFailureAction,
+        (state: SingleResourceState, props: LoadResourceFailureProps): SingleResourceState => ({
+          ...state,
+          resource: createErrorStateResource(props.error),
+        }),
+      ),
+      on(
+        this.actions.clearAction,
+        (state: SingleResourceState): SingleResourceState => ({
+          ...state,
+          resource: createEmptyStateResource(),
+        }),
+      ),
+      on(
+        this.actions.reloadAction,
+        (state: SingleResourceState): SingleResourceState => ({
+          ...state,
+          resource: { ...state.resource, reload: true },
+        }),
+      ),
+    );
+  }
+}
diff --git a/alfa-client/libs/tech-shared/src/lib/ngrx/selector.spec.ts b/alfa-client/libs/tech-shared/src/lib/ngrx/selector.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..a3e56a459e8dd094e0d0221f837ab719de53694c
--- /dev/null
+++ b/alfa-client/libs/tech-shared/src/lib/ngrx/selector.spec.ts
@@ -0,0 +1,48 @@
+import { Resource } from '@ngxp/rest';
+import {
+  FUNCTIONAL_FEATURE_PATH_KEY,
+  SingleResourceParentState,
+  StateInfoTestFactory,
+} from 'libs/tech-shared/test/ngrx';
+import { createDummyResource } from 'libs/tech-shared/test/resource';
+import { StateResource, createStateResource } from '../resource/resource.util';
+import { initialResourceState } from './state.model';
+
+import * as Selectors from './selector';
+
+describe('Selector', () => {
+  let state: SingleResourceParentState;
+
+  const stateResource: StateResource<Resource> = createStateResource(createDummyResource());
+
+  beforeEach(() => {
+    state = {
+      FunctionalState: {
+        FunctionalResourcePath: {
+          ...initialResourceState,
+          resource: stateResource,
+        },
+      },
+    };
+  });
+
+  it('should return resource from state', () => {
+    const result: StateResource<Resource> = <any>(
+      Selectors.selectResource(StateInfoTestFactory.create()).projector(
+        state.FunctionalState[FUNCTIONAL_FEATURE_PATH_KEY],
+      )
+    );
+
+    expect(result).toBe(stateResource);
+  });
+
+  it('should check resource in state exists', () => {
+    const result: StateResource<Resource> = <any>(
+      Selectors.selectResource(StateInfoTestFactory.create()).projector(
+        state.FunctionalState[FUNCTIONAL_FEATURE_PATH_KEY],
+      )
+    );
+
+    expect(result).toBeTruthy();
+  });
+});
diff --git a/alfa-client/libs/tech-shared/src/lib/ngrx/selector.ts b/alfa-client/libs/tech-shared/src/lib/ngrx/selector.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c7c2c27cacef25486909ed0dfcfb01a348daded0
--- /dev/null
+++ b/alfa-client/libs/tech-shared/src/lib/ngrx/selector.ts
@@ -0,0 +1,21 @@
+import { createFeatureSelector, createSelector } from '@ngrx/store';
+import { StateInfo } from '../resource/resource.model';
+import { SingleResourceState } from './state.model';
+
+export const selectResource = <T>(stateInfo: StateInfo) =>
+  createSelector(
+    createFeatureSelector<SingleResourceState>(stateInfo.name),
+    (state: SingleResourceState) =>
+      <T>getFeatureState<SingleResourceState>(stateInfo, state).resource,
+  );
+
+export const existResource = <T>(stateInfo: StateInfo) =>
+  createSelector(
+    createFeatureSelector<SingleResourceState>(stateInfo.name),
+    (state: SingleResourceState) =>
+      <T>getFeatureState<SingleResourceState>(stateInfo, state).resource.loaded,
+  );
+
+function getFeatureState<T>(stateInfo: StateInfo, state: any): T {
+  return <T>state.hasOwnProperty(stateInfo.path) ? state[stateInfo.path] : state;
+}
diff --git a/alfa-client/libs/tech-shared/src/lib/ngrx/state.model.ts b/alfa-client/libs/tech-shared/src/lib/ngrx/state.model.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b9c0728a3d795a2da96dfdf14af240fbea23189e
--- /dev/null
+++ b/alfa-client/libs/tech-shared/src/lib/ngrx/state.model.ts
@@ -0,0 +1,10 @@
+import { Resource } from '@ngxp/rest';
+import { StateResource, createEmptyStateResource } from '../resource/resource.util';
+
+export interface SingleResourceState {
+  resource: StateResource<Resource>;
+}
+
+export const initialResourceState: SingleResourceState = {
+  resource: createEmptyStateResource<Resource>(),
+};
diff --git a/alfa-client/libs/tech-shared/src/lib/ngrx/state.service.spec.ts b/alfa-client/libs/tech-shared/src/lib/ngrx/state.service.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b2667c5aa70a87ec8691a7534daacf5660199e75
--- /dev/null
+++ b/alfa-client/libs/tech-shared/src/lib/ngrx/state.service.spec.ts
@@ -0,0 +1,172 @@
+import { Mock, mock, useFromMock } from '@alfa-client/test-utils';
+import faker from '@faker-js/faker';
+import { MemoizedSelector, Store } from '@ngrx/store';
+import { Resource, ResourceUri } from '@ngxp/rest';
+import { singleCold } from 'libs/tech-shared/test/marbles';
+import { createDummyResource } from 'libs/tech-shared/test/resource';
+import { Observable, of } from 'rxjs';
+import { StateInfoTestFactory, dummySelector } from '../../../test/ngrx';
+import { StateInfo } from '../resource/resource.model';
+import { StateResource, createStateResource } from '../resource/resource.util';
+import { SingleResourceLoadActions, createSingleResourceActions } from './actions';
+import { EffectService } from './effects.service';
+import { SingleResourceState } from './state.model';
+import { ResourceStateService, SingleResourceStateService } from './state.service';
+
+import * as ResourceSelectors from './selector';
+
+describe('StateService', () => {
+  let store: Mock<Store>;
+  let effectService: Mock<EffectService>;
+
+  const stateInfo: StateInfo = StateInfoTestFactory.create();
+
+  beforeEach(() => {
+    store = mock(Store);
+    effectService = mock(EffectService);
+  });
+
+  describe('Resource State Service', () => {
+    let service: DummyResoureStateService<Resource>;
+
+    beforeEach(() => {
+      service = new DummyResoureStateService<Resource>(
+        stateInfo,
+        useFromMock(store),
+        useFromMock(effectService),
+      );
+    });
+
+    it('should clear resource', () => {
+      service.clearResource();
+
+      expect(store.dispatch).toHaveBeenCalledWith(service.actions.clearAction());
+    });
+
+    it('should load resource', () => {
+      const resourceUri: ResourceUri = faker.random.word();
+
+      service.loadResource(resourceUri);
+
+      expect(store.dispatch).toHaveBeenCalledWith(service.actions.loadAction({ resourceUri }));
+    });
+
+    it('should reload resource', () => {
+      service.reloadResource();
+
+      expect(store.dispatch).toHaveBeenCalledWith(service.actions.reloadAction());
+    });
+  });
+
+  describe('Single Resource State Service', () => {
+    let service: SingleResourceStateService<Resource>;
+
+    beforeEach(() => {
+      service = new SingleResourceStateService<Resource>(
+        stateInfo,
+        useFromMock(store),
+        useFromMock(effectService),
+      );
+    });
+
+    it('should init actions', () => {
+      service.actions = undefined;
+
+      service.init();
+
+      expect(service.actions).not.toBeUndefined();
+    });
+
+    it('should add effects', () => {
+      service.init();
+
+      expect(effectService.addSingleResourceEffects).toHaveBeenCalledWith(service.actions);
+    });
+
+    describe('select resource', () => {
+      const stateValue: MemoizedSelector<object, unknown, (s1: SingleResourceState) => unknown> =
+        dummySelector;
+      const dummyStateResource: StateResource<Resource> =
+        createStateResource(createDummyResource());
+
+      let selectResourceSpy: jest.SpyInstance;
+
+      beforeEach(() => {
+        store.select.mockReturnValue(of(dummyStateResource));
+        selectResourceSpy = jest
+          .spyOn(ResourceSelectors, 'selectResource')
+          .mockReturnValue(stateValue);
+      });
+
+      it('should call selector', () => {
+        service.selectResource();
+
+        expect(selectResourceSpy).toHaveBeenCalledWith(stateInfo);
+      });
+
+      it('should call store', () => {
+        service.selectResource();
+
+        expect(store.select).toHaveBeenCalledWith(stateValue);
+      });
+
+      it('should return from store selected value', () => {
+        store.select.mockReturnValue(singleCold(dummyStateResource));
+
+        const selectedResource$: Observable<StateResource<Resource>> = service.selectResource();
+
+        expect(selectedResource$).toBeObservable(singleCold(dummyStateResource));
+      });
+    });
+
+    describe('exists resource', () => {
+      const stateValue: MemoizedSelector<object, unknown, (s1: SingleResourceState) => unknown> =
+        dummySelector;
+      const dummyStateResource: StateResource<Resource> =
+        createStateResource(createDummyResource());
+
+      let existsResourceSpy: jest.SpyInstance;
+
+      beforeEach(() => {
+        store.select.mockReturnValue(of(dummyStateResource));
+        existsResourceSpy = jest
+          .spyOn(ResourceSelectors, 'existResource')
+          .mockReturnValue(stateValue);
+      });
+
+      it('should call selector', () => {
+        service.existsResource();
+
+        expect(existsResourceSpy).toHaveBeenCalledWith(stateInfo);
+      });
+
+      it('should call store', () => {
+        service.existsResource();
+
+        expect(store.select).toHaveBeenCalledWith(stateValue);
+      });
+
+      it('should return from store selected value', () => {
+        store.select.mockReturnValue(singleCold(true));
+
+        const exists$: Observable<boolean> = service.existsResource();
+
+        expect(exists$).toBeObservable(singleCold(true));
+      });
+    });
+  });
+});
+
+class DummyResoureStateService<Resource> extends ResourceStateService<Resource> {
+  actions: SingleResourceLoadActions;
+
+  protected initActions(): void {
+    this.actions = createSingleResourceActions(this.stateInfo);
+  }
+  protected initEffects(): void {
+    this.effectService.addSingleResourceEffects(this.actions);
+  }
+  public selectResource(): Observable<StateResource<Resource>> {
+    throw new Error('Method not implemented.');
+  }
+}
diff --git a/alfa-client/libs/tech-shared/src/lib/ngrx/state.service.ts b/alfa-client/libs/tech-shared/src/lib/ngrx/state.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..9ac8339252c62390a61910e0d7d63d681496b51f
--- /dev/null
+++ b/alfa-client/libs/tech-shared/src/lib/ngrx/state.service.ts
@@ -0,0 +1,85 @@
+import { Injectable } from '@angular/core';
+import { Store } from '@ngrx/store';
+import { ResourceUri } from '@ngxp/rest';
+import { Observable } from 'rxjs';
+import { StateInfo } from '../resource/resource.model';
+import { StateResource } from '../resource/resource.util';
+import { ResourceActions, SingleResourceLoadActions, createSingleResourceActions } from './actions';
+import { EffectService } from './effects.service';
+
+import * as ResourceSelectors from './selector';
+
+@Injectable()
+export class StateService {
+  constructor(
+    private store: Store,
+    private effectService: EffectService,
+  ) {}
+
+  public createSingleResourceService<T>(stateInfo: StateInfo): SingleResourceStateService<T> {
+    return new SingleResourceStateService(stateInfo, this.store, this.effectService);
+  }
+}
+
+export abstract class ResourceStateService<T> {
+  actions: ResourceActions;
+
+  constructor(
+    protected stateInfo: StateInfo,
+    protected store: Store,
+    protected effectService: EffectService,
+  ) {
+    this.init();
+  }
+
+  public init(): void {
+    this.initActions();
+    this.initEffects();
+  }
+
+  protected abstract initActions(): void;
+
+  protected abstract initEffects(): void;
+
+  public clearResource(): void {
+    this.store.dispatch(this.actions.clearAction());
+  }
+
+  public loadResource(resourceUri: ResourceUri): void {
+    this.store.dispatch(this.actions.loadAction({ resourceUri }));
+  }
+
+  public reloadResource(): void {
+    this.store.dispatch(this.actions.reloadAction());
+  }
+
+  public abstract selectResource(): Observable<StateResource<T>>;
+}
+
+export class SingleResourceStateService<T> extends ResourceStateService<T> {
+  actions: SingleResourceLoadActions;
+
+  constructor(
+    protected stateInfo: StateInfo,
+    protected store: Store,
+    protected effectService: EffectService,
+  ) {
+    super(stateInfo, store, effectService);
+  }
+
+  protected initActions(): void {
+    this.actions = createSingleResourceActions(this.stateInfo);
+  }
+
+  protected initEffects(): void {
+    this.effectService.addSingleResourceEffects(this.actions);
+  }
+
+  public selectResource(): Observable<StateResource<T>> {
+    return this.store.select(ResourceSelectors.selectResource(this.stateInfo));
+  }
+
+  public existsResource(): Observable<boolean> {
+    return this.store.select(ResourceSelectors.existResource(this.stateInfo));
+  }
+}
diff --git a/alfa-client/libs/tech-shared/src/lib/resource/api-resource.service.spec.ts b/alfa-client/libs/tech-shared/src/lib/resource/api-resource.service.spec.ts
index 8b559b8b81e03d6f4f1a56f56ac6e1e67e14cf64..cb5d71b89a2f08863ca1f8a39cb50971ed416c8d 100644
--- a/alfa-client/libs/tech-shared/src/lib/resource/api-resource.service.spec.ts
+++ b/alfa-client/libs/tech-shared/src/lib/resource/api-resource.service.spec.ts
@@ -2,19 +2,21 @@ import { Mock, mock, useFromMock } from '@alfa-client/test-utils';
 import { fakeAsync, tick } from '@angular/core/testing';
 import { Resource } from '@ngxp/rest';
 import { Observable, of, throwError } from 'rxjs';
-import { singleCold, singleHot } from '../../../test//marbles';
+import { SECOND_FRAME, multiCold, singleCold } from '../../../test//marbles';
 import { createProblemDetail } from '../../../test/error';
 import { createDummyResource } from '../../../test/resource';
+import { SingleResourceStateService, StateService } from '../ngrx/state.service';
 import { HttpError, ProblemDetail } from '../tech.model';
 import { ApiResourceService } from './api-resource.service';
 import { LinkRelationName, ResourceServiceConfig, SaveResourceData } from './resource.model';
 import { ResourceRepository } from './resource.repository';
-import { StateResource, createStateResource } from './resource.util';
+import { StateResource, createEmptyStateResource, createStateResource } from './resource.util';
 
 describe('ApiResourceService', () => {
   let service: ApiResourceService<Resource, Resource>;
   let config: ResourceServiceConfig<Resource>;
   let repository: Mock<ResourceRepository>;
+  let stateService: Mock<StateService>;
 
   const configResource: Resource = createDummyResource();
   const configStateResource: StateResource<Resource> = createStateResource(configResource);
@@ -26,28 +28,43 @@ describe('ApiResourceService', () => {
 
   beforeEach(() => {
     config = {
-      resource: configStateResource$,
+      stateInfo: { name: 'dummyStateName', path: 'dummyStatePath' },
+      baseResource: configStateResource$,
       getLinkRel,
       edit: { linkRel: editLinkRel },
       delete: { linkRel: deleteLinkRel },
     };
     repository = mock(ResourceRepository);
+    stateService = mock(StateService);
+    stateService.createSingleResourceService = jest
+      .fn()
+      .mockReturnValue(mock(SingleResourceStateService));
 
-    service = new ApiResourceService(config, useFromMock(repository));
+    service = new ApiResourceService(config, useFromMock(stateService), useFromMock(repository));
   });
 
   it('should be created', () => {
     expect(service).toBeTruthy();
   });
 
+  it('should be create resource state service', () => {
+    expect(service.resourceStateService).toBeTruthy();
+  });
+
   describe('save', () => {
     const dummyToSave: unknown = {};
     const loadedResource: Resource = createDummyResource();
 
     const resourceWithEditLinkRel: Resource = createDummyResource([editLinkRel]);
 
+    beforeEach(() => {
+      service.selectResource = jest
+        .fn()
+        .mockReturnValue(of(createStateResource(resourceWithEditLinkRel)));
+      service.resourceStateService.reloadResource = jest.fn();
+    });
+
     it('should call repository', fakeAsync(() => {
-      service.stateResource.next(createStateResource(resourceWithEditLinkRel));
       repository.save.mockReturnValue(of(loadedResource));
 
       service.save(dummyToSave).subscribe();
@@ -62,16 +79,16 @@ describe('ApiResourceService', () => {
     }));
 
     it('should return saved object', () => {
-      service.stateResource.next(createStateResource(resourceWithEditLinkRel));
-      repository.save.mockReturnValue(singleHot(loadedResource));
+      repository.save.mockReturnValue(singleCold(loadedResource, SECOND_FRAME));
 
-      const saved: Observable<StateResource<Resource | HttpError>> = service.save(dummyToSave);
+      const saved$: Observable<StateResource<Resource | HttpError>> = service.save(dummyToSave);
 
-      expect(saved).toBeObservable(singleCold(createStateResource(loadedResource)));
+      expect(saved$).toBeObservable(
+        multiCold({ a: createEmptyStateResource(true), b: createStateResource(loadedResource) }),
+      );
     });
 
     it('should call handleError', () => {
-      service.stateResource.next(createStateResource(createDummyResource([config.edit.linkRel])));
       const errorResponse: ProblemDetail = createProblemDetail();
       repository.save.mockReturnValue(throwError(() => errorResponse));
       service.handleError = jest.fn();
@@ -82,13 +99,13 @@ describe('ApiResourceService', () => {
     });
 
     it('should update state resource subject', fakeAsync(() => {
-      service.stateResource.next(createStateResource(resourceWithEditLinkRel));
+      service.resourceStateService.reloadResource = jest.fn();
       repository.save.mockReturnValue(of(loadedResource));
 
       service.save(dummyToSave).subscribe();
       tick();
 
-      expect(service.stateResource.value).toEqual(createStateResource(loadedResource));
+      expect(service.resourceStateService.reloadResource).toHaveBeenCalled();
     }));
   });
 });
diff --git a/alfa-client/libs/tech-shared/src/lib/resource/api-resource.service.ts b/alfa-client/libs/tech-shared/src/lib/resource/api-resource.service.ts
index d19c4a6fdc52813b270661c560bf76bed7f3ba24..a5232c272a4bdd2a8450029159bd6e047d71e1ce 100644
--- a/alfa-client/libs/tech-shared/src/lib/resource/api-resource.service.ts
+++ b/alfa-client/libs/tech-shared/src/lib/resource/api-resource.service.ts
@@ -1,8 +1,18 @@
+import { HttpErrorResponse } from '@angular/common/http';
 import { Resource } from '@ngxp/rest';
-import { Observable } from 'rxjs';
+import { Observable, catchError, map, of, startWith, switchMap, tap, throwError } from 'rxjs';
+import { isUnprocessableEntity } from '../http.util';
+import { StateService } from '../ngrx/state.service';
+import { HttpError } from '../tech.model';
 import { ResourceServiceConfig } from './resource.model';
 import { ResourceRepository } from './resource.repository';
 import { ResourceService } from './resource.service';
+import {
+  StateResource,
+  createEmptyStateResource,
+  createErrorStateResource,
+  createStateResource,
+} from './resource.util';
 
 export class ApiResourceService<B extends Resource, T extends Resource> extends ResourceService<
   B,
@@ -10,16 +20,37 @@ export class ApiResourceService<B extends Resource, T extends Resource> extends
 > {
   constructor(
     protected config: ResourceServiceConfig<B>,
+    protected stateService: StateService,
     protected repository: ResourceRepository,
   ) {
-    super(config, repository);
+    super(config, stateService);
+  }
+
+  public save(toSave: unknown): Observable<StateResource<T | HttpError>> {
+    return this.selectResource().pipe(
+      switchMap((stateResource: StateResource<T>) =>
+        this.doSave(stateResource.resource, toSave).pipe(
+          tap(() => this.reloadResource()),
+          map((value: T) => createStateResource<T>(value)),
+          catchError((errorResponse: HttpErrorResponse) => this.handleError(errorResponse)),
+        ),
+      ),
+      startWith(createEmptyStateResource<T | HttpError>(true)),
+    );
   }
 
   doSave(resource: T, toSave: unknown): Observable<T> {
-    return <Observable<T>>this.repository.save({
+    return this.repository.save<T>({
       resource,
       linkRel: this.config.edit.linkRel,
       toSave,
     });
   }
+
+  handleError(errorResponse: HttpErrorResponse): Observable<StateResource<HttpError>> {
+    if (isUnprocessableEntity(errorResponse.status)) {
+      return of(createErrorStateResource((<any>errorResponse) as HttpError));
+    }
+    return throwError(() => errorResponse);
+  }
 }
diff --git a/alfa-client/libs/tech-shared/src/lib/resource/list-resource.service.itcase.spec.ts b/alfa-client/libs/tech-shared/src/lib/resource/list-resource.service.itcase.spec.ts
deleted file mode 100644
index 9e8d68e04cac794472b2a4142bf9d8888c31a452..0000000000000000000000000000000000000000
--- a/alfa-client/libs/tech-shared/src/lib/resource/list-resource.service.itcase.spec.ts
+++ /dev/null
@@ -1,154 +0,0 @@
-import { Mock, mock, useFromMock } from '@alfa-client/test-utils';
-import { fakeAsync, tick } from '@angular/core/testing';
-import { Resource } from '@ngxp/rest';
-import { DummyLinkRel, DummyListLinkRel } from 'libs/tech-shared/test/dummy';
-import { createDummyListResource, createDummyResource } from 'libs/tech-shared/test/resource';
-import { BehaviorSubject, of, skip } from 'rxjs';
-import { ResourceListService } from './list-resource.service';
-import { ListResourceServiceConfig } from './resource.model';
-import { ResourceRepository } from './resource.repository';
-import {
-  ListResource,
-  StateResource,
-  createEmptyStateResource,
-  createStateResource,
-} from './resource.util';
-
-//Der Test muss nochmal ueberarbeitet werden - siehe resource.service.itcase.spec.ts
-describe.skip('ResourceListService ITCase', () => {
-  let service: ResourceListService<Resource, ListResource, Resource>;
-  let config: ListResourceServiceConfig<Resource>;
-  let resourceRepository: Mock<ResourceRepository>;
-
-  const listLinkRel: string = DummyListLinkRel.LIST;
-  const listResourceListLinkRel: string = DummyListLinkRel.LIST;
-  const createLinkRel: string = DummyLinkRel.DUMMY;
-
-  const baseResource: StateResource<Resource> = createStateResource(createDummyResource());
-
-  const loadedListResource: ListResource = createDummyListResource();
-
-  describe('getList', () => {
-    const loadedListResource: ListResource = createDummyListResource();
-    // *  - GIVEN listResource=leer, baseResource=leer WHEN baseResource neuer Eintrag THEN load ausführen AND wenn fertig listResource liefert Wert
-    describe('with empty listResource and empty baseResource', () => {
-      const baseResourceSubj: BehaviorSubject<StateResource<Resource>> = new BehaviorSubject<
-        StateResource<Resource>
-      >(createEmptyStateResource());
-
-      beforeEach(() => {
-        config = createConfigWithBaseResource(baseResourceSubj);
-        initServiceAndMocksWithBaseResourceSubj(config);
-
-        resourceRepository.getListResource.mockReturnValue(of(loadedListResource));
-      });
-
-      it('should load and return listResource on baseResource change', (done) => {
-        let emitted: number = 0;
-        service.getList().subscribe((listStateResource) => {
-          emitted++;
-          if (emitted == 1) {
-            expect(listStateResource).toEqual(createEmptyStateResource());
-          }
-          if (emitted == 2) {
-            expect(listStateResource.loading).toBeTruthy();
-            expect(resourceRepository.getListResource).toHaveBeenCalled();
-          }
-          if (emitted === 3) {
-            expect(listStateResource).toEqual(createStateResource(loadedListResource));
-            done();
-          }
-        });
-        baseResourceSubj.next(createStateResource(createDummyResource()));
-      });
-    });
-    // *  - GIVEN listResource=befüllt, baseResource=befüllt WHEN subscribe THEN nicht laden, listResource liefert Wert
-    describe('with filled listResource and filled baseResource', () => {
-      const listStateResource: StateResource<ListResource> =
-        createStateResource(createDummyListResource());
-
-      const baseResourceSubj: BehaviorSubject<StateResource<Resource>> = new BehaviorSubject<
-        StateResource<Resource>
-      >(baseResource);
-
-      beforeEach(() => {
-        config = createConfigWithBaseResource(baseResourceSubj);
-        initServiceAndMocksWithBaseResourceSubj(config);
-
-        service.listResource.next(listStateResource);
-      });
-
-      it('should return listResource', (done) => {
-        service.getList().subscribe((response) => {
-          expect(response).toBe(listStateResource);
-          done();
-        });
-      });
-
-      it('should not call repository', fakeAsync(() => {
-        service.getList().subscribe();
-        tick();
-
-        expect(resourceRepository.getListResource).not.toHaveBeenCalled();
-      }));
-
-      // *  - GIVEN listResource=befüllt, baseResource=befüllt WHEN baseResource wird leer THEN listResource leer
-      describe('on baseResource changed to null', () => {
-        it('should return empty state resource', (done) => {
-          service
-            .getList()
-            .pipe(skip(1))
-            .subscribe((listStateResource) => {
-              expect(listStateResource).toEqual(createEmptyStateResource());
-              done();
-            });
-
-          baseResourceSubj.next(createEmptyStateResource());
-        });
-      });
-
-      // *  - GIVEN listResource=befüllt, baseResource=befüllt WHEN baseResource wechselt Wert THEN load ausführen AND wenn fertig listResource liefert neuen Wert
-      describe('on baseResource changed', () => {
-        it('should reloaded value', (done) => {
-          let emitted: number = 0;
-          service.getList().subscribe((response) => {
-            emitted++;
-            if (emitted === 1) {
-              expect(response).toEqual(listStateResource);
-            }
-            if (emitted === 2) {
-              expect(response.loading).toBeTruthy();
-              expect(resourceRepository.getListResource).toHaveBeenCalled();
-            }
-            if (emitted === 3) {
-              done();
-            }
-          });
-
-          baseResourceSubj.next(createStateResource(createDummyResource()));
-        });
-      });
-    });
-  });
-
-  function createConfigWithBaseResource(baseResource: BehaviorSubject<StateResource<Resource>>) {
-    return {
-      baseResource,
-      listLinkRel,
-      listResourceListLinkRel,
-      createLinkRel,
-    };
-  }
-
-  function initServiceAndMocksWithBaseResourceSubj(
-    config: ListResourceServiceConfig<Resource>,
-  ): void {
-    resourceRepository = mock(ResourceRepository);
-    service = new ResourceListService<Resource, ListResource, Resource>(
-      config,
-      useFromMock(resourceRepository),
-    );
-
-    resourceRepository.getListResource.mockReturnValue(of(loadedListResource));
-  }
-});
diff --git a/alfa-client/libs/tech-shared/src/lib/resource/list-resource.service.spec.ts b/alfa-client/libs/tech-shared/src/lib/resource/list-resource.service.spec.ts
index 9983f8acf61e11a6c642761e7b0d6e8e3351c253..931dac12de04544bec86596a778b20656075c34b 100644
--- a/alfa-client/libs/tech-shared/src/lib/resource/list-resource.service.spec.ts
+++ b/alfa-client/libs/tech-shared/src/lib/resource/list-resource.service.spec.ts
@@ -35,10 +35,10 @@ describe('ListResourceService', () => {
   let config: ListResourceServiceConfig<Resource>;
   let resourceRepository: Mock<ResourceRepository>;
 
-  const listLinkRel: LinkRelationName = DummyListLinkRel.LIST;
+  const getLinkRel: LinkRelationName = DummyListLinkRel.LIST;
   const createLinkRel: LinkRelationName = DummyLinkRel.DUMMY;
   const listResourceListLinkRel: LinkRelationName = DummyListLinkRel.LIST;
-  const listResource: ListResource = createDummyListResource([listLinkRel, createLinkRel]);
+  const listResource: ListResource = createDummyListResource([getLinkRel, createLinkRel]);
 
   const baseResource: Resource = createDummyResource();
   const baseStateResource: StateResource<Resource> = createStateResource(baseResource);
@@ -49,7 +49,7 @@ describe('ListResourceService', () => {
   beforeEach(() => {
     config = {
       baseResource: baseResourceSubj,
-      listLinkRel,
+      getLinkRel,
       listResourceListLinkRel,
       createLinkRel,
     };
@@ -148,7 +148,7 @@ describe('ListResourceService', () => {
 
         service.handleChanges(listStateResource, baseResource);
 
-        expect(service.loadListResource).toHaveBeenCalledWith(baseResource, listLinkRel);
+        expect(service.loadListResource).toHaveBeenCalledWith(baseResource, getLinkRel);
       });
 
       it('should NOT load resource on shouldLoadResource false', () => {
@@ -177,18 +177,18 @@ describe('ListResourceService', () => {
       it('should load list on stable state resource', () => {
         service.loadListResource = jest.fn();
         service.listResource.next(createStateResource(createDummyListResource()));
-        const configResuorce: Resource = createDummyListResource([listLinkRel]);
+        const configResuorce: Resource = createDummyListResource([getLinkRel]);
 
         service.handleConfigResourceChanges(configResuorce);
 
-        expect(service.loadListResource).toHaveBeenCalledWith(service.baseResource, listLinkRel);
+        expect(service.loadListResource).toHaveBeenCalledWith(service.baseResource, getLinkRel);
       });
 
       it('should NOT load list on stable unstable resource', () => {
         jest.spyOn(ResourceUtil, 'isStateResoureStable').mockReturnValue(false);
         service.loadListResource = jest.fn();
         service.listResource.next(createStateResource(createDummyListResource()));
-        const configResuorce: Resource = createDummyListResource([listLinkRel]);
+        const configResuorce: Resource = createDummyListResource([getLinkRel]);
 
         service.handleConfigResourceChanges(configResuorce);
 
diff --git a/alfa-client/libs/tech-shared/src/lib/resource/list-resource.service.ts b/alfa-client/libs/tech-shared/src/lib/resource/list-resource.service.ts
index 631e1c685eba0e9f96e5a4e1d97e1314a1cb7e9f..830d1ff58ec54181a8470bbe87fa8e171066e2c7 100644
--- a/alfa-client/libs/tech-shared/src/lib/resource/list-resource.service.ts
+++ b/alfa-client/libs/tech-shared/src/lib/resource/list-resource.service.ts
@@ -72,21 +72,21 @@ export class ResourceListService<
     if (!isEqual(this.baseResource, configResource)) {
       this.handleConfigResourceChanges(configResource);
     } else if (this.shouldLoadResource(stateResource, configResource)) {
-      this.loadListResource(configResource, this.config.listLinkRel);
+      this.loadListResource(configResource, this.config.getLinkRel);
     }
   }
 
   handleConfigResourceChanges(newConfigResource: B): void {
     this.baseResource = newConfigResource;
     if (this.hasListLinkRel() && isStateResoureStable(this.listResource.value)) {
-      this.loadListResource(this.baseResource, this.config.listLinkRel);
+      this.loadListResource(this.baseResource, this.config.getLinkRel);
     } else if (!this.hasListLinkRel() && isStateResoureStable(this.listResource.value)) {
       this.clearCurrentListResource();
     }
   }
 
   private hasListLinkRel(): boolean {
-    return hasLink(this.baseResource, this.config.listLinkRel);
+    return hasLink(this.baseResource, this.config.getLinkRel);
   }
 
   shouldLoadResource(stateResource: StateResource<T>, configResource: B): boolean {
@@ -158,7 +158,7 @@ export class ResourceListService<
   existsUriInList(uri: ResourceUri): boolean {
     const listResources: Resource[] = getEmbeddedResources(
       this.listResource.value,
-      this.config.listLinkRel,
+      this.config.getLinkRel,
     );
 
     return isNotUndefined(listResources.find((resource) => getUrl(resource) === uri));
diff --git a/alfa-client/libs/tech-shared/src/lib/resource/resource.loader.spec.ts b/alfa-client/libs/tech-shared/src/lib/resource/resource.loader.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1226221c0935c1e0bca2825ac8b6a3fd5865587b
--- /dev/null
+++ b/alfa-client/libs/tech-shared/src/lib/resource/resource.loader.spec.ts
@@ -0,0 +1,316 @@
+import { mock, useFromMock } from '@alfa-client/test-utils';
+import { fakeAsync, tick } from '@angular/core/testing';
+import { Resource, getUrl } from '@ngxp/rest';
+import { CLOSED_FRAME, singleCold } from 'libs/tech-shared/test/marbles';
+import { Observable, of } from 'rxjs';
+import { createDummyResource } from '../../../test/resource';
+import { SingleResourceStateService } from '../ngrx/state.service';
+import { ResourceLoader } from './resource.loader';
+import { LinkRelationName, ResourceServiceConfig } from './resource.model';
+import { StateResource, createEmptyStateResource, createStateResource } from './resource.util';
+
+import * as ResourceUtil from './resource.util';
+
+describe('ResourceLoader', () => {
+  let service: ResourceLoader<Resource, Resource>;
+  let config: ResourceServiceConfig<Resource>;
+  let resourceStateService: SingleResourceStateService<Resource>;
+
+  const editLinkRel: string = 'dummyEditLinkRel';
+  const getLinkRel: LinkRelationName = 'dummyGetLinkRel';
+  const deleteLinkRel: LinkRelationName = 'dummyDeleteLinkRel';
+
+  const configResource: Resource = createDummyResource([getLinkRel]);
+  const configStateResource: StateResource<Resource> = createStateResource(configResource);
+  const configStateResource$: Observable<StateResource<Resource>> = of(configStateResource);
+
+  const dummyResource: Resource = createDummyResource();
+  const dummyStateResource: StateResource<Resource> = createStateResource(dummyResource);
+
+  beforeEach(() => {
+    config = {
+      baseResource: configStateResource$,
+      getLinkRel,
+      edit: { linkRel: editLinkRel },
+      delete: { linkRel: deleteLinkRel },
+    };
+    resourceStateService = <any>mock(SingleResourceStateService);
+
+    service = new ResourceLoader(config, useFromMock(<any>resourceStateService));
+  });
+
+  it('should be created', () => {
+    expect(service).toBeTruthy();
+  });
+
+  describe('get', () => {
+    let isInvalidResourceCombinationSpy: jest.SpyInstance;
+
+    beforeEach(() => {
+      resourceStateService.selectResource = jest.fn().mockReturnValue(of(dummyStateResource));
+
+      service.handleResourceChanges = jest.fn();
+      isInvalidResourceCombinationSpy = jest
+        .spyOn(ResourceUtil, 'isInvalidResourceCombination')
+        .mockReturnValue(true);
+    });
+
+    it('should handle config resource changed', fakeAsync(() => {
+      service.get().subscribe();
+      tick();
+
+      expect(service.handleResourceChanges).toHaveBeenCalledWith(
+        dummyStateResource,
+        configResource,
+      );
+    }));
+
+    it('should call isInvalidResourceCombinationSpy', fakeAsync(() => {
+      service.get().subscribe();
+      tick();
+
+      expect(isInvalidResourceCombinationSpy).toHaveBeenCalled();
+    }));
+
+    it('should return initial value', () => {
+      const apiRootStateResource$: Observable<StateResource<Resource>> = service.get();
+
+      expect(apiRootStateResource$).toBeObservable(
+        singleCold(createEmptyStateResource(true), CLOSED_FRAME),
+      );
+    });
+  });
+
+  describe('handle resource changes', () => {
+    const stateResource: StateResource<Resource> = createStateResource(createDummyResource());
+    const changedConfigResource: Resource = createDummyResource();
+
+    describe('on different config resource', () => {
+      beforeEach(() => {
+        service.handleConfigResourceChanges = jest.fn();
+      });
+
+      it('should update state resource by config resource', () => {
+        service.configResource = createDummyResource();
+
+        service.handleResourceChanges(stateResource, changedConfigResource);
+
+        expect(service.handleConfigResourceChanges).toHaveBeenCalled();
+      });
+    });
+
+    describe('on same config resource', () => {
+      const stateResource: StateResource<Resource> = createStateResource(createDummyResource());
+
+      beforeEach(() => {
+        service.configResource = configResource;
+      });
+
+      it('should call shouldLoadResource', () => {
+        service.shouldLoadResource = jest.fn();
+
+        service.handleResourceChanges(stateResource, configResource);
+
+        expect(service.shouldLoadResource).toHaveBeenCalledWith(stateResource, configResource);
+      });
+
+      it('should load resource', () => {
+        service.shouldLoadResource = jest.fn().mockReturnValue(true);
+        service.loadResource = jest.fn();
+
+        service.handleResourceChanges(stateResource, configResource);
+
+        expect(service.loadResource).toHaveBeenCalledWith(configResource);
+      });
+
+      it('should NOT load resource', () => {
+        service.loadResource = jest.fn();
+        service.shouldLoadResource = jest.fn().mockReturnValue(false);
+
+        service.handleResourceChanges(stateResource, configResource);
+
+        expect(service.loadResource).not.toHaveBeenCalled();
+      });
+    });
+  });
+
+  describe('handle config resource changes', () => {
+    const stateResource: StateResource<Resource> = createStateResource(createDummyResource());
+
+    beforeEach(() => {
+      service.updateStateResourceByConfigResource = jest.fn();
+    });
+
+    it('should update configresource', () => {
+      service.configResource = createDummyResource();
+
+      service.handleConfigResourceChanges(stateResource, configResource);
+
+      expect(service.configResource).toBe(configResource);
+    });
+
+    describe('on stable stateresource', () => {
+      beforeEach(() => {
+        jest.spyOn(ResourceUtil, 'isStateResoureStable').mockReturnValue(true);
+        service.updateStateResourceByConfigResource = jest.fn();
+      });
+
+      it('should update stateresource by configresource', () => {
+        service.handleConfigResourceChanges(stateResource, configResource);
+
+        expect(service.updateStateResourceByConfigResource).toHaveBeenCalledWith(
+          stateResource,
+          configResource,
+        );
+      });
+    });
+
+    describe('on instable stateresource', () => {
+      beforeEach(() => {
+        jest.spyOn(ResourceUtil, 'isStateResoureStable').mockReturnValue(false);
+      });
+
+      it('should NOT update stateresource by configresource', () => {
+        service.updateStateResourceByConfigResource = jest.fn();
+
+        service.handleConfigResourceChanges(stateResource, configResource);
+
+        expect(service.updateStateResourceByConfigResource).not.toHaveBeenCalled();
+      });
+    });
+  });
+
+  describe('update stateresource by configresource', () => {
+    it('should check if should clear stateresource', () => {
+      resourceStateService.clearResource = jest.fn();
+      service.shouldClearStateResource = jest.fn().mockRejectedValue(true);
+
+      service.updateStateResourceByConfigResource(dummyStateResource, configResource);
+
+      expect(service.shouldClearStateResource).toHaveBeenCalled();
+    });
+
+    it('should clear resource if should', () => {
+      resourceStateService.clearResource = jest.fn();
+      resourceStateService.selectResource = jest
+        .fn()
+        .mockReturnValue(of(createStateResource(createDummyResource())));
+      service.shouldClearStateResource = jest.fn().mockReturnValue(true);
+
+      service.updateStateResourceByConfigResource(dummyStateResource, configResource);
+
+      expect(resourceStateService.clearResource).toHaveBeenCalled();
+    });
+
+    describe('on NOT clearing stateresource', () => {
+      beforeEach(() => {
+        service.shouldClearStateResource = jest.fn().mockReturnValue(false);
+      });
+
+      it('should check if get link exists', () => {
+        service.hasGetLink = jest.fn();
+
+        service.updateStateResourceByConfigResource(dummyStateResource, configResource);
+
+        expect(service.hasGetLink).toHaveBeenCalledWith(configResource);
+      });
+
+      it('should load resource on existing get link', () => {
+        service.hasGetLink = jest.fn().mockReturnValue(true);
+        service.loadResource = jest.fn();
+
+        service.updateStateResourceByConfigResource(dummyStateResource, configResource);
+
+        expect(service.loadResource).toHaveBeenCalledWith(configResource);
+      });
+    });
+  });
+
+  describe('should clear stateresource', () => {
+    describe('on existing stateresource', () => {
+      beforeEach(() => {
+        resourceStateService.selectResource = jest.fn().mockReturnValue(of(dummyStateResource));
+      });
+
+      it('should return true if configresource is null', () => {
+        const shouldClear: boolean = service.shouldClearStateResource(dummyStateResource, null);
+
+        expect(shouldClear).toBeTruthy();
+      });
+
+      it('should return true if configresource has no get link', () => {
+        const shouldClear: boolean = service.shouldClearStateResource(
+          dummyStateResource,
+          createDummyResource(),
+        );
+
+        expect(shouldClear).toBeTruthy();
+      });
+    });
+
+    describe('on empty stateresource', () => {
+      it('should return false', () => {
+        const shouldClear: boolean = service.shouldClearStateResource(
+          ResourceUtil.createEmptyStateResource(),
+          null,
+        );
+
+        expect(shouldClear).toBeFalsy();
+      });
+
+      it('should return false if configresource has no get link', () => {
+        const shouldClear: boolean = service.shouldClearStateResource(
+          ResourceUtil.createEmptyStateResource(),
+          createDummyResource(),
+        );
+
+        expect(shouldClear).toBeFalsy();
+      });
+    });
+  });
+
+  describe('should load resource', () => {
+    const resource: Resource = createDummyResource();
+    const stateResource: StateResource<Resource> = createStateResource(resource);
+
+    let isLoadingRequiredSpy: jest.SpyInstance<boolean>;
+
+    beforeEach(() => {
+      isLoadingRequiredSpy = jest.spyOn(ResourceUtil, 'isLoadingRequired');
+    });
+
+    it('should return true on existing configresource and loading is required', () => {
+      isLoadingRequiredSpy.mockReturnValue(true);
+
+      const shouldLoad: boolean = service.shouldLoadResource(stateResource, configResource);
+
+      expect(shouldLoad).toBeTruthy();
+    });
+
+    it('should call isLoadingRequired', () => {
+      service.shouldLoadResource(stateResource, configResource);
+
+      expect(isLoadingRequiredSpy).toBeCalledWith(stateResource);
+    });
+
+    it('should return false if configresource exists but loading is NOT required', () => {
+      isLoadingRequiredSpy.mockReturnValue(false);
+
+      const shouldLoad: boolean = service.shouldLoadResource(stateResource, configResource);
+
+      expect(shouldLoad).toBeFalsy();
+    });
+  });
+
+  describe('load resource', () => {
+    it('should call resource state service load resource', () => {
+      resourceStateService.loadResource = jest.fn();
+
+      service.loadResource(configResource);
+
+      expect(resourceStateService.loadResource).toHaveBeenCalledWith(
+        getUrl(configResource, getLinkRel),
+      );
+    });
+  });
+});
diff --git a/alfa-client/libs/tech-shared/src/lib/resource/resource.loader.ts b/alfa-client/libs/tech-shared/src/lib/resource/resource.loader.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5c38968831a043ebffeab3de3bc78f1136757321
--- /dev/null
+++ b/alfa-client/libs/tech-shared/src/lib/resource/resource.loader.ts
@@ -0,0 +1,102 @@
+import { Resource, getUrl, hasLink } from '@ngxp/rest';
+import { isEqual, isNull } from 'lodash-es';
+import { Observable, combineLatest, filter, startWith, tap } from 'rxjs';
+import { ResourceStateService } from '../ngrx/state.service';
+import { isNotNull } from '../tech.util';
+import { ServiceConfig } from './resource.model';
+import { mapToFirst, mapToResource } from './resource.rxjs.operator';
+import {
+  StateResource,
+  createEmptyStateResource,
+  isInvalidResourceCombination,
+  isLoadingRequired,
+  isStateResoureStable,
+} from './resource.util';
+
+export class ResourceLoader<B extends Resource, T extends Resource> {
+  configResource: B = null;
+
+  constructor(
+    private config: ServiceConfig<B>,
+    private resourceStateService: ResourceStateService<T>,
+  ) {}
+
+  public get(): Observable<StateResource<T>> {
+    return combineLatest([
+      this.resourceStateService.selectResource(),
+      this.getConfigResource(),
+    ]).pipe(
+      tap(([stateResource, configResource]) =>
+        this.handleResourceChanges(stateResource, configResource),
+      ),
+      filter(
+        ([stateResource, configResource]) =>
+          !isInvalidResourceCombination(stateResource, configResource),
+      ),
+      mapToFirst<T, B>(),
+      startWith(createEmptyStateResource<T>(true)),
+    );
+  }
+
+  private getConfigResource(): Observable<B> {
+    return this.config.baseResource.pipe(filter(isStateResoureStable), mapToResource<B>());
+  }
+
+  handleResourceChanges(stateResource: StateResource<T>, configResource: B): void {
+    if (!isEqual(this.configResource, configResource)) {
+      this.handleConfigResourceChanges(stateResource, configResource);
+    } else if (this.shouldLoadResource(stateResource, configResource)) {
+      this.loadResource(configResource);
+    }
+  }
+
+  handleConfigResourceChanges(stateResource: StateResource<T>, configResource: B) {
+    this.configResource = configResource;
+    if (isStateResoureStable(stateResource)) {
+      this.updateStateResourceByConfigResource(stateResource, configResource);
+    }
+  }
+
+  updateStateResourceByConfigResource(stateResource: StateResource<T>, configResource: B): void {
+    if (this.shouldClearStateResource(stateResource, configResource)) {
+      this.resourceStateService.clearResource();
+    } else if (this.hasGetLink(configResource)) {
+      this.loadResource(configResource);
+    }
+  }
+
+  shouldClearStateResource(stateResource: StateResource<T>, configResource: B): boolean {
+    return (
+      (isNull(configResource) || this.hasNotGetLink(configResource)) &&
+      !this.isStateResourceEmpty(stateResource)
+    );
+  }
+
+  private hasNotGetLink(configResource: B) {
+    return !this.hasGetLink(configResource);
+  }
+
+  hasGetLink(configResource: B): boolean {
+    return isNotNull(configResource) && hasLink(configResource, this.config.getLinkRel);
+  }
+
+  private isStateResourceEmpty(stateResource: StateResource<T>): boolean {
+    return isEqual(stateResource, createEmptyStateResource());
+  }
+
+  shouldLoadResource(stateResource: StateResource<T>, configResource: B): boolean {
+    return (
+      isNotNull(configResource) &&
+      hasLink(configResource, this.config.getLinkRel) &&
+      isLoadingRequired(stateResource)
+    );
+  }
+
+  loadResource(configResource: B): void {
+    this.resourceStateService.loadResource(this.getGetUrl(configResource));
+  }
+
+  private getGetUrl(configResource: B): string {
+    return getUrl(configResource, this.config.getLinkRel);
+  }
+}
diff --git a/alfa-client/libs/tech-shared/src/lib/resource/resource.model.ts b/alfa-client/libs/tech-shared/src/lib/resource/resource.model.ts
index 5fa5264f32b11a057af8755641f61d02b001fc46..f08c137d763e1557b6596bc91c0e49c92e214f8f 100644
--- a/alfa-client/libs/tech-shared/src/lib/resource/resource.model.ts
+++ b/alfa-client/libs/tech-shared/src/lib/resource/resource.model.ts
@@ -2,9 +2,18 @@ import { Resource } from '@ngxp/rest';
 import { Observable } from 'rxjs';
 import { StateResource } from './resource.util';
 
-export interface ListResourceServiceConfig<B> {
+export interface StateInfo {
+  name: string;
+  path: string;
+}
+
+export interface ServiceConfig<B> {
+  stateInfo?: StateInfo;
   baseResource: Observable<StateResource<B>>;
-  listLinkRel: LinkRelationName;
+  getLinkRel: LinkRelationName;
+}
+
+export interface ListResourceServiceConfig<B> extends ServiceConfig<B> {
   listResourceListLinkRel: LinkRelationName;
   createLinkRel?: LinkRelationName;
 }
@@ -24,9 +33,12 @@ export interface SaveResourceData<T> {
 export interface ListItemResource extends Resource {}
 export declare type LinkRelationName = string;
 
-export interface ResourceServiceConfig<B> {
-  resource: Observable<StateResource<B>>;
-  getLinkRel: LinkRelationName;
-  delete?: { linkRel: LinkRelationName; order?: string };
-  edit?: { linkRel: LinkRelationName; order?: string };
+export interface ResourceServiceConfig<B> extends ServiceConfig<B> {
+  delete?: ConfigAction;
+  edit?: ConfigAction;
+}
+
+interface ConfigAction {
+  linkRel: LinkRelationName;
+  order?: string;
 }
diff --git a/alfa-client/libs/tech-shared/src/lib/resource/resource.repository.ts b/alfa-client/libs/tech-shared/src/lib/resource/resource.repository.ts
index 386819910fd1aa3b9fd58349e7a9034f72530982..2328613ee2ab9f1d74b2fcb1e42ba5a527b2f5c8 100644
--- a/alfa-client/libs/tech-shared/src/lib/resource/resource.repository.ts
+++ b/alfa-client/libs/tech-shared/src/lib/resource/resource.repository.ts
@@ -30,7 +30,7 @@ export class ResourceRepository {
     return this.resourceFactory.fromId(uri).get();
   }
 
-  public save(saveResourceData: SaveResourceData<Resource>): Observable<Resource> {
+  public save<T>(saveResourceData: SaveResourceData<Resource>): Observable<T> {
     return this.resourceFactory
       .from(saveResourceData.resource)
       .put(saveResourceData.linkRel, saveResourceData.toSave);
diff --git a/alfa-client/libs/tech-shared/src/lib/resource/resource.service.itcase.spec.ts b/alfa-client/libs/tech-shared/src/lib/resource/resource.service.itcase.spec.ts
deleted file mode 100644
index cff64cc4e17979a6d14e59a8f017e1b7cd2c9076..0000000000000000000000000000000000000000
--- a/alfa-client/libs/tech-shared/src/lib/resource/resource.service.itcase.spec.ts
+++ /dev/null
@@ -1,238 +0,0 @@
-import { Mock, mock, useFromMock } from '@alfa-client/test-utils';
-import { fakeAsync, tick } from '@angular/core/testing';
-import faker from '@faker-js/faker';
-import { Resource, getUrl } from '@ngxp/rest';
-import { BehaviorSubject, of } from 'rxjs';
-import { createDummyResource } from '../../../test/resource';
-import { LinkRelationName, ResourceServiceConfig } from './resource.model';
-import { ResourceRepository } from './resource.repository';
-import { DummyResourceService } from './resource.service.spec';
-import { StateResource, createEmptyStateResource, createStateResource } from './resource.util';
-
-describe.skip('FIXME: mocking.ts issue due to module test | ResourceService ITCase', () => {
-  let service: DummyResourceService<Resource, Resource>;
-  let config: ResourceServiceConfig<Resource>;
-  let repository: Mock<ResourceRepository>;
-
-  const getLinkRel: LinkRelationName = faker.random.word();
-  const editLinkRel: LinkRelationName = faker.random.word();
-  const deleteLinkRel: LinkRelationName = faker.random.word();
-
-  const configResource: Resource = createDummyResource([getLinkRel, editLinkRel]);
-  const configStateResource: StateResource<Resource> = createStateResource(configResource);
-  const configResourceSubj: BehaviorSubject<StateResource<Resource>> = new BehaviorSubject<
-    StateResource<Resource>
-  >(configStateResource);
-
-  const loadedResource: Resource = createDummyResource([getLinkRel, editLinkRel]);
-
-  const EXPECTED_EMITTED_TIMES_FOR_GET: number = 3;
-
-  beforeEach(() => {
-    config = {
-      resource: configResourceSubj,
-      getLinkRel,
-      edit: { linkRel: editLinkRel },
-      delete: { linkRel: deleteLinkRel },
-    };
-    repository = mock(ResourceRepository);
-
-    service = new DummyResourceService<Resource, Resource>(config, useFromMock(repository));
-
-    repository.getResource.mockReturnValueOnce(of(loadedResource));
-    service.stateResource.next(createEmptyStateResource());
-  });
-
-  describe('get', () => {
-    it('should emit initially loading stateResource', (done) => {
-      let emittedTimes: number = 0;
-      service.get().subscribe((response: StateResource<Resource>) => {
-        emittedTimes++;
-        if (emittedTimes === 1) {
-          console.info('RESPONSE 1: ', response);
-          expect(response.loading).toBeTruthy();
-          expect(response.resource).toBeNull();
-          done();
-        }
-      });
-    });
-
-    it('should emit loading stateResource', (done) => {
-      let emittedTimes: number = 0;
-      service.get().subscribe((response: StateResource<Resource>) => {
-        emittedTimes++;
-        if (emittedTimes === 2) {
-          expect(response.loading).toBeTruthy();
-          expect(response.resource).toBeNull();
-          done();
-        }
-      });
-    });
-
-    it('should emit loaded stateResource', (done) => {
-      let emittedTimes: number = 0;
-      service.get().subscribe((response: StateResource<Resource>) => {
-        emittedTimes++;
-        if (emittedTimes === EXPECTED_EMITTED_TIMES_FOR_GET) {
-          expect(repository.getResource).toHaveBeenCalledWith(getUrl(configResource, getLinkRel));
-          expect(response.resource).toBe(loadedResource);
-          expect(response.loading).toBeFalsy();
-          done();
-        }
-      });
-    });
-
-    it('should emit 3 times', async () => {
-      let emittedTimes: number = 0;
-
-      service.get().subscribe((response) => {
-        emittedTimes++;
-        console.info('RESPONSE ON GET: ', response);
-      });
-      console.info('EMITTED TIMES: ', emittedTimes);
-      expect(emittedTimes).toBe(EXPECTED_EMITTED_TIMES_FOR_GET);
-    });
-  });
-
-  describe('get - change configResource', () => {
-    const reloadedResource: Resource = createDummyResource();
-
-    const EXPECTED_EMITTED_TIMES: number = EXPECTED_EMITTED_TIMES_FOR_GET + 2;
-
-    const newConfigResource: Resource = createDummyResource([deleteLinkRel, getLinkRel]);
-    const newConfigStateResource: StateResource<Resource> = createStateResource(newConfigResource);
-
-    beforeEach(() => {
-      repository.getResource.mockReturnValueOnce(of(reloadedResource));
-    });
-
-    it('should emit loading stateResource', (done) => {
-      let emittedTimes: number = 0;
-      service.get().subscribe((response: StateResource<Resource>) => {
-        emittedTimes++;
-        doAfterGetIsDone(emittedTimes, () => configResourceSubj.next(newConfigStateResource));
-        if (emittedTimes === 4) {
-          expect(response.loading).toBeTruthy();
-          expect(response.resource).toBeNull();
-          done();
-        }
-      });
-    });
-
-    it.skip('should emit reloaded stateResource', (done) => {
-      let emittedTimes: number = 0;
-      service.get().subscribe((response: StateResource<Resource>) => {
-        emittedTimes++;
-        doAfterGetIsDone(emittedTimes, () => configResourceSubj.next(newConfigStateResource));
-        if (emittedTimes === EXPECTED_EMITTED_TIMES) {
-          expect(repository.getResource).toHaveBeenCalledTimes(2);
-          expect(repository.getResource).toHaveBeenCalledWith(getUrl(configResource, getLinkRel));
-          expect(repository.getResource).toHaveBeenCalledWith(
-            getUrl(newConfigResource, getLinkRel),
-          );
-          expect(response.resource).toBe(reloadedResource);
-          expect(response.loading).toBeFalsy();
-          done();
-        }
-      });
-    });
-
-    it.skip('should emit 5 times', fakeAsync(async () => {
-      let emittedTimes: number = 0;
-      service.get().subscribe((response) => {
-        emittedTimes++;
-        console.info('RESPONSE ON GET: ', response);
-        doAfterGetIsDone(emittedTimes, () => configResourceSubj.next(newConfigStateResource));
-      });
-      tick();
-
-      console.info('EMITTED TIMES: ', emittedTimes);
-      expect(emittedTimes).toBe(EXPECTED_EMITTED_TIMES);
-    }));
-  });
-
-  describe('get - change configResource to null', () => {
-    const EXPECTED_EMITTED_TIMES_FOR_GET: number = 3;
-    const EXPECTED_EMITTED_TIMES: number = EXPECTED_EMITTED_TIMES_FOR_GET + 1;
-
-    const emptyConfigStateResource: StateResource<Resource> = createEmptyStateResource();
-
-    it('should emit empty stateResource', (done) => {
-      let emittedTimes: number = 0;
-      service.get().subscribe((response: StateResource<Resource>) => {
-        emittedTimes++;
-        doAfterGetIsDone(emittedTimes, () => configResourceSubj.next(emptyConfigStateResource));
-        if (emittedTimes === EXPECTED_EMITTED_TIMES) {
-          expect(response.loading).toBeFalsy();
-          expect(response.resource).toBeNull();
-          done();
-        }
-      });
-    });
-
-    it('should emit 4 times', fakeAsync(async () => {
-      let emittedTimes: number = 0;
-      service.get().subscribe(() => {
-        emittedTimes++;
-        doAfterGetIsDone(emittedTimes, () => configResourceSubj.next(emptyConfigStateResource));
-      });
-      tick();
-
-      expect(emittedTimes).toBe(EXPECTED_EMITTED_TIMES);
-    }));
-  });
-
-  describe.skip('FIXME (Funktioniert nicht mit den anderen Tests zusammen) refresh', () => {
-    const reloadedResource: Resource = createDummyResource();
-
-    const EXPECTED_EMITTED_TIMES_FOR_GET: number = 3;
-    const EXPECTED_EMITTED_TIMES: number = EXPECTED_EMITTED_TIMES_FOR_GET + 2;
-
-    beforeEach(() => {
-      repository.getResource.mockReturnValueOnce(of(reloadedResource));
-    });
-
-    it('should return loading stateResource', (done) => {
-      let emittedTimes: number = 0;
-      service.get().subscribe((response: StateResource<Resource>) => {
-        emittedTimes++;
-        doAfterGetIsDone(emittedTimes, () => service.refresh());
-        if (emittedTimes === 4) {
-          expect(repository.getResource).toHaveBeenCalledWith(getUrl(configResource, getLinkRel));
-          expect(response.loading).toBeTruthy();
-          done();
-        }
-      });
-    });
-
-    it('should return reloaded stateResource', (done) => {
-      let emittedTimes: number = 0;
-      service.get().subscribe((response: StateResource<Resource>) => {
-        emittedTimes++;
-        doAfterGetIsDone(emittedTimes, () => service.refresh());
-        if (emittedTimes === EXPECTED_EMITTED_TIMES) {
-          expect(response.resource).toBe(reloadedResource);
-          expect(response.loading).toBeFalsy();
-          done();
-        }
-      });
-    });
-
-    it('should emit 5 times', fakeAsync(async () => {
-      let emittedTimes: number = 0;
-      service.get().subscribe(() => {
-        emittedTimes++;
-        doAfterGetIsDone(emittedTimes, () => service.refresh());
-      });
-      tick();
-
-      expect(emittedTimes).toBe(EXPECTED_EMITTED_TIMES);
-    }));
-  });
-
-  function doAfterGetIsDone(emittedTimes: number, runnable: () => void): void {
-    if (emittedTimes === EXPECTED_EMITTED_TIMES_FOR_GET) {
-      runnable();
-    }
-  }
-});
diff --git a/alfa-client/libs/tech-shared/src/lib/resource/resource.service.spec.ts b/alfa-client/libs/tech-shared/src/lib/resource/resource.service.spec.ts
index 1a15c29a582000a5be2378c1163f3a487cfd6d1c..64ba2376bfcc9f26dcc7bf606aa79dc2818f7e64 100644
--- a/alfa-client/libs/tech-shared/src/lib/resource/resource.service.spec.ts
+++ b/alfa-client/libs/tech-shared/src/lib/resource/resource.service.spec.ts
@@ -1,31 +1,18 @@
 import { Mock, mock, useFromMock } from '@alfa-client/test-utils';
-import { HttpErrorResponse } from '@angular/common/http';
-import { fakeAsync, tick } from '@angular/core/testing';
-import { faker } from '@faker-js/faker';
-import { Resource, ResourceUri, getUrl } from '@ngxp/rest';
-import { cold } from 'jest-marbles';
-import { Observable, lastValueFrom, of, throwError } from 'rxjs';
-import { createProblemDetail } from '../../../test//error';
-import { singleCold, singleHot } from '../../../test/marbles';
+import faker from '@faker-js/faker';
+import { Resource } from '@ngxp/rest';
+import { CLOSED_FRAME, singleCold } from 'libs/tech-shared/test/marbles';
+import { Observable, of } from 'rxjs';
 import { createDummyResource } from '../../../test/resource';
-import { HttpError, ProblemDetail } from '../tech.model';
+import { SingleResourceStateService, StateService } from '../ngrx/state.service';
 import { LinkRelationName, ResourceServiceConfig } from './resource.model';
-import { ResourceRepository } from './resource.repository';
 import { ResourceService } from './resource.service';
-import {
-  StateResource,
-  createEmptyStateResource,
-  createErrorStateResource,
-  createStateResource,
-} from './resource.util';
-
-import * as ResourceUtil from './resource.util';
+import { StateResource, createStateResource } from './resource.util';
 
 describe('ResourceService', () => {
   let service: DummyResourceService<Resource, Resource>;
   let config: ResourceServiceConfig<Resource>;
-
-  let repository: Mock<ResourceRepository>;
+  let stateService: Mock<StateService>;
 
   const configResource: Resource = createDummyResource();
   const configStateResource: StateResource<Resource> = createStateResource(configResource);
@@ -40,465 +27,117 @@ describe('ResourceService', () => {
 
   beforeEach(() => {
     config = {
-      resource: configStateResource$,
+      stateInfo: { name: 'dummyFeatureState', path: 'dummyPath' },
+      baseResource: configStateResource$,
       getLinkRel,
       edit: { linkRel: editLinkRel },
       delete: { linkRel: deleteLinkRel },
     };
-    repository = mock(ResourceRepository);
+    stateService = mock(StateService);
+    stateService.createSingleResourceService = jest
+      .fn()
+      .mockReturnValue(mock(SingleResourceStateService));
 
-    service = new DummyResourceService(config, useFromMock(repository));
+    service = new DummyResourceService(config, useFromMock(stateService));
   });
 
   it('should be created', () => {
     expect(service).toBeTruthy();
   });
 
-  describe('get', () => {
-    const stateResource: StateResource<Resource> = createStateResource(configResource);
-    let isInvalidResourceCombinationSpy: jest.SpyInstance;
-
-    beforeEach(() => {
-      service.stateResource.next(stateResource);
-
-      service.handleResourceChanges = jest.fn();
-      isInvalidResourceCombinationSpy = jest
-        .spyOn(ResourceUtil, 'isInvalidResourceCombination')
-        .mockReturnValue(true);
-    });
-
-    it('should handle config resource changed', fakeAsync(() => {
-      service.get().subscribe();
-      tick();
-
-      expect(service.handleResourceChanges).toHaveBeenCalledWith(stateResource, configResource);
-    }));
-
-    it('should call isInvalidResourceCombinationSpy', fakeAsync(() => {
-      service.get().subscribe();
-      tick();
-
-      expect(isInvalidResourceCombinationSpy).toHaveBeenCalled();
-    }));
-
-    it('should return initial value', () => {
-      service.stateResource.asObservable = jest
-        .fn()
-        .mockReturnValue(singleHot(stateResource, '-a'));
-
-      const apiRootStateResource$: Observable<StateResource<Resource>> = service.get();
-
-      expect(apiRootStateResource$).toBeObservable(
-        cold('a', { a: createEmptyStateResource(true) }),
-      );
-    });
+  it('should create state service', () => {
+    expect(service.resourceStateService).toBeTruthy();
   });
 
-  describe('handle resource changes', () => {
-    const stateResource: StateResource<Resource> = createStateResource(createDummyResource());
-    const changedConfigResource: Resource = createDummyResource();
-
-    describe('on different config resource', () => {
-      beforeEach(() => {
-        service.handleConfigResourceChanges = jest.fn();
-      });
-
-      it('should update state resource by config resource', () => {
-        service.configResource = createDummyResource();
-
-        service.handleResourceChanges(stateResource, changedConfigResource);
-
-        expect(service.handleConfigResourceChanges).toHaveBeenCalled();
-      });
-    });
-
-    describe('on same config resource', () => {
-      const stateResource: StateResource<Resource> = createStateResource(createDummyResource());
-
-      beforeEach(() => {
-        service.configResource = configResource;
-      });
-
-      it('should call shouldLoadResource', () => {
-        service.shouldLoadResource = jest.fn();
-
-        service.handleResourceChanges(stateResource, configResource);
-
-        expect(service.shouldLoadResource).toHaveBeenCalledWith(stateResource, configResource);
-      });
-
-      it('should load resource', () => {
-        service.shouldLoadResource = jest.fn().mockReturnValue(true);
-        service.loadResource = jest.fn();
-
-        service.handleResourceChanges(stateResource, configResource);
-
-        expect(service.loadResource).toHaveBeenCalledWith(configResource);
-      });
-
-      it('should NOT load resource', () => {
-        service.loadResource = jest.fn();
-        service.shouldLoadResource = jest.fn().mockReturnValue(false);
-
-        service.handleResourceChanges(stateResource, configResource);
-
-        expect(service.loadResource).not.toHaveBeenCalled();
-      });
-    });
+  it('should create resource loader', () => {
+    expect(service.resourceLoader).toBeTruthy();
   });
 
-  describe('handle config resource changes', () => {
-    const stateResource: StateResource<Resource> = createStateResource(createDummyResource());
-
-    it('should update configresource', () => {
-      service.configResource = createDummyResource();
-
-      service.handleResourceChanges(stateResource, configResource);
-
-      expect(service.configResource).toBe(configResource);
-    });
-
-    describe('on stable stateresource', () => {
-      beforeEach(() => {
-        jest.spyOn(ResourceUtil, 'isStateResoureStable').mockReturnValue(true);
-        service.updateStateResourceByConfigResource = jest.fn();
-      });
-
-      it('should update stateresource by configresource', () => {
-        service.handleResourceChanges(stateResource, configResource);
-
-        expect(service.updateStateResourceByConfigResource).toHaveBeenCalledWith(
-          stateResource,
-          configResource,
-        );
-      });
-    });
-
-    describe('on instable stateresource', () => {
-      beforeEach(() => {
-        jest.spyOn(ResourceUtil, 'isStateResoureStable').mockReturnValue(false);
-      });
-
-      it('should NOT update stateresource by configresource', () => {
-        service.updateStateResourceByConfigResource = jest.fn();
-
-        service.handleResourceChanges(stateResource, configResource);
-
-        expect(service.updateStateResourceByConfigResource).not.toHaveBeenCalled();
-      });
-    });
-  });
-
-  describe('update stateresource by configresource', () => {
-    it('should check if should clear stateresource', () => {
-      service.shouldClearStateResource = jest.fn();
-
-      service.updateStateResourceByConfigResource(dummyStateResource, configResource);
-
-      expect(service.shouldClearStateResource).toHaveBeenCalled();
-    });
-
-    it('should clear resource if should', () => {
-      service.stateResource.next(createStateResource(createDummyResource()));
-      service.shouldClearStateResource = jest.fn().mockReturnValue(true);
-
-      service.updateStateResourceByConfigResource(dummyStateResource, configResource);
-
-      expect(service.stateResource.value).toEqual(createEmptyStateResource());
-    });
-
-    describe('on NOT clearing stateresource', () => {
-      beforeEach(() => {
-        service.shouldClearStateResource = jest.fn().mockReturnValue(false);
-      });
-
-      it('should load resource if link exists', () => {
-        service.hasGetLink = jest.fn();
-
-        service.updateStateResourceByConfigResource(dummyStateResource, configResource);
-
-        expect(service.hasGetLink).toHaveBeenCalledWith(configResource);
-      });
-    });
-  });
-
-  describe('should clear stateresource', () => {
-    describe('on existing stateresource', () => {
-      beforeEach(() => {
-        service.stateResource.next(dummyStateResource);
-      });
-
-      it('should return true if configresource is null', () => {
-        const shouldClear: boolean = service.shouldClearStateResource(dummyStateResource, null);
-
-        expect(shouldClear).toBeTruthy();
-      });
-
-      it('should return true if configresource has no get link', () => {
-        const shouldClear: boolean = service.shouldClearStateResource(
-          dummyStateResource,
-          createDummyResource(),
-        );
-
-        expect(shouldClear).toBeTruthy();
-      });
-    });
-
-    describe('on empty stateresource', () => {
-      it('should return false', () => {
-        const shouldClear: boolean = service.shouldClearStateResource(
-          createEmptyStateResource(),
-          null,
-        );
-
-        expect(shouldClear).toBeFalsy();
-      });
-
-      it('should return false if configresource has no get link', () => {
-        const shouldClear: boolean = service.shouldClearStateResource(
-          createEmptyStateResource(),
-          createDummyResource(),
-        );
-
-        expect(shouldClear).toBeFalsy();
-      });
-    });
-  });
-
-  describe('should load resource', () => {
-    const resource: Resource = createDummyResource();
-    const stateResource: StateResource<Resource> = createStateResource(resource);
-
-    let isLoadingRequiredSpy: jest.SpyInstance<boolean>;
-
+  describe('get', () => {
     beforeEach(() => {
-      isLoadingRequiredSpy = jest.spyOn(ResourceUtil, 'isLoadingRequired');
-    });
-
-    it('should return true on existing configresource and loading is required', () => {
-      isLoadingRequiredSpy.mockReturnValue(true);
-
-      const shouldLoad: boolean = service.shouldLoadResource(stateResource, configResource);
-
-      expect(shouldLoad).toBeTruthy();
-    });
-
-    it('should call isLoadingRequired', () => {
-      service.shouldLoadResource(stateResource, configResource);
-
-      expect(isLoadingRequiredSpy).toBeCalledWith(stateResource);
+      service.resourceLoader.get = jest.fn().mockReturnValue(of(dummyStateResource));
     });
 
-    it('should return false if configresource exists but loading is NOT required', () => {
-      isLoadingRequiredSpy.mockReturnValue(false);
-
-      const shouldLoad: boolean = service.shouldLoadResource(stateResource, configResource);
+    it('should call resource loader', () => {
+      service.get();
 
-      expect(shouldLoad).toBeFalsy();
+      expect(service.resourceLoader.get).toHaveBeenCalled();
     });
-  });
-
-  describe('load resource', () => {
-    const configResourceWithGetLinkRel: Resource = createDummyResource([getLinkRel]);
 
-    it('should call do load resource', () => {
-      service.doLoadResource = jest.fn();
+    it('should return from loader returned value', () => {
+      const stateResource$: Observable<StateResource<Resource>> = service.get();
 
-      service.loadResource(configResourceWithGetLinkRel);
-
-      expect(service.doLoadResource).toHaveBeenCalledWith(
-        getUrl(configResourceWithGetLinkRel, config.getLinkRel),
-      );
+      expect(stateResource$).toBeObservable(singleCold(dummyStateResource, CLOSED_FRAME));
     });
   });
 
-  describe('set state resource loading', () => {
-    it('should set loading true', () => {
-      service.stateResource.next(createStateResource(createDummyResource()));
-
-      service.setStateResourceLoading();
-
-      expect(service.stateResource.value.loading).toBeTruthy();
-    });
-
-    it('should set reload false', () => {
-      service.stateResource.next({ ...createStateResource(createDummyResource()), reload: true });
+  describe('reload resource', () => {
+    it('should call resource state service to reload resource', () => {
+      service.resourceStateService.reloadResource = jest.fn();
 
-      service.setStateResourceLoading();
+      service.reloadResource();
 
-      expect(service.stateResource.value.reload).toBeFalsy();
+      expect(service.resourceStateService.reloadResource).toHaveBeenCalled();
     });
   });
 
-  describe('do load resource', () => {
-    let resourceUri: ResourceUri;
-    let loadedResource: Resource;
-
+  describe('exist resource', () => {
     beforeEach(() => {
-      service.setStateResourceLoading = jest.fn();
-      resourceUri = faker.internet.url();
-      loadedResource = createDummyResource();
-      repository.getResource.mockReturnValue(of(loadedResource));
-    });
-
-    it('should set state resource to loading', () => {
-      service.doLoadResource(resourceUri);
-
-      expect(service.setStateResourceLoading).toHaveBeenCalled();
-    });
-
-    it('should call repository', () => {
-      service.doLoadResource(resourceUri);
-
-      expect(repository.getResource).toHaveBeenCalledWith(resourceUri);
-    });
-
-    it('should update stateresource', () => {
-      service.updateStateResource = jest.fn();
-
-      service.doLoadResource(resourceUri);
-
-      expect(service.updateStateResource).toHaveBeenCalledWith(loadedResource);
-    });
-  });
-
-  describe('loadByResourceUri', () => {
-    it('should do load resource', () => {
-      service.doLoadResource = jest.fn();
-      const resourceUri: ResourceUri = faker.internet.url();
-
-      service.loadByResourceUri(resourceUri);
-
-      expect(service.doLoadResource).toHaveBeenCalledWith(resourceUri);
+      service.resourceStateService.existsResource = jest.fn().mockReturnValue(of(true));
     });
-  });
-
-  describe('update stateresource', () => {
-    const resourceToBeSet: Resource = createDummyResource();
-
-    it('should set resource as stateresource', () => {
-      service.stateResource.next(createEmptyStateResource());
-
-      service.updateStateResource(resourceToBeSet);
-
-      expect(service.stateResource.value).toEqual(createStateResource(resourceToBeSet));
-    });
-  });
-
-  describe('save', () => {
-    const dummyToSave: unknown = {};
-    const loadedResource: Resource = createDummyResource();
-
-    const resourceWithEditLinkRel: Resource = createDummyResource([editLinkRel]);
 
-    it('should do save', fakeAsync(() => {
-      const stateResource: StateResource<Resource> = createStateResource(resourceWithEditLinkRel);
-      service.stateResource.next(stateResource);
-      const doSaveMock: jest.Mock = (service.doSave = jest.fn()).mockReturnValue(
-        of(loadedResource),
-      );
+    it('should call resource state service', () => {
+      service.existResource();
 
-      service.save(dummyToSave).subscribe();
-      tick();
-
-      expect(doSaveMock).toHaveBeenCalledWith(resourceWithEditLinkRel, dummyToSave);
-    }));
-
-    it('should return saved object', () => {
-      service.stateResource.next(createStateResource(resourceWithEditLinkRel));
-      service.doSave = jest.fn().mockReturnValue(singleHot(loadedResource));
-
-      const saved: Observable<StateResource<Resource | HttpError>> = service.save(dummyToSave);
-
-      expect(saved).toBeObservable(singleCold(createStateResource(loadedResource)));
+      expect(service.resourceStateService.existsResource).toHaveBeenCalled();
     });
 
-    it('should call handleError', () => {
-      service.stateResource.next(createStateResource(createDummyResource([config.edit.linkRel])));
-      const errorResponse: ProblemDetail = createProblemDetail();
-      service.doSave = jest.fn().mockReturnValue(throwError(() => errorResponse));
-      service.handleError = jest.fn();
-
-      service.save(<any>{}).subscribe();
+    it('should return from service returned value', () => {
+      const existsValueFromService$: Observable<boolean> = service.existResource();
 
-      expect(service.handleError).toHaveBeenCalledWith(errorResponse);
+      expect(existsValueFromService$).toBeObservable(singleCold(true, CLOSED_FRAME));
     });
-
-    it('should update state resource subject', fakeAsync(() => {
-      service.stateResource.next(createStateResource(resourceWithEditLinkRel));
-      service.doSave = jest.fn().mockReturnValue(of(loadedResource));
-
-      service.save(dummyToSave).subscribe();
-      tick();
-
-      expect(service.stateResource.value).toEqual(createStateResource(loadedResource));
-    }));
   });
 
-  describe('handleError', () => {
-    it('should return error stateresource on problem unprocessable entity', (done: jest.DoneCallback) => {
-      const error: ProblemDetail = createProblemDetail();
-
-      service
-        .handleError(<HttpErrorResponse>(<any>error))
-        .subscribe((responseError: StateResource<HttpError>) => {
-          expect(responseError).toEqual(createErrorStateResource(error));
-          done();
-        });
+  describe('select resource', () => {
+    beforeEach(() => {
+      service.resourceStateService.selectResource = jest
+        .fn()
+        .mockReturnValue(of(dummyStateResource));
     });
 
-    it('should rethrow error', () => {
-      const error: HttpErrorResponse = <HttpErrorResponse>{
-        status: 500,
-        statusText: 'Internal Server Error',
-      };
+    it('should call resource state service', () => {
+      service.selectResource();
 
-      const thrownError$: Observable<StateResource<HttpError>> = service.handleError(error);
-
-      expect.assertions(1);
-      expect(lastValueFrom(thrownError$)).rejects.toThrowError('Internal Server Error');
+      expect(service.resourceStateService.selectResource).toHaveBeenCalled();
     });
-  });
-
-  describe('refresh', () => {
-    beforeEach(() => {
-      service.loadResource = jest.fn();
-    });
-
-    it('should set reload true on statresource', () => {
-      service.stateResource.next(createStateResource(createDummyResource()));
 
-      service.refresh();
+    it('should return from service returned value', () => {
+      const resource$: Observable<StateResource<Resource>> = service.selectResource();
 
-      expect(service.stateResource.value.reload).toBeTruthy();
+      expect(resource$).toBeObservable(singleCold(dummyStateResource, CLOSED_FRAME));
     });
   });
 
-  describe('exist resource', () => {
-    it('should return true on existing resource', () => {
-      service.stateResource.next(createStateResource(createDummyResource()));
-
-      const existResource$: Observable<boolean> = service.existResource();
-
-      expect(existResource$).toBeObservable(singleCold(true));
-    });
+  describe('load by resource uri', () => {
+    const dummyUri: string = faker.random.word();
 
-    it('should return false on null resource', () => {
-      service.stateResource.next(createEmptyStateResource());
+    it('should call resource state service to clear resource', () => {
+      service.resourceStateService.loadResource = jest.fn();
 
-      const existResource$: Observable<boolean> = service.existResource();
+      service.loadByResourceUri(dummyUri);
 
-      expect(existResource$).toBeObservable(singleCold(false));
+      expect(service.resourceStateService.loadResource).toHaveBeenCalledWith(dummyUri);
     });
   });
 
-  describe('select resource', () => {
-    it('should return state resource', () => {
-      service.stateResource.next(dummyStateResource);
+  describe('clear resource', () => {
+    it('should call resource state service to clear resource', () => {
+      service.resourceStateService.clearResource = jest.fn();
 
-      const resource$: Observable<StateResource<Resource>> = service.selectResource();
+      service.clearResource();
 
-      expect(resource$).toBeObservable(singleCold(dummyStateResource));
+      expect(service.resourceStateService.clearResource).toHaveBeenCalled();
     });
   });
 });
@@ -509,12 +148,8 @@ export class DummyResourceService<B extends Resource, T extends Resource> extend
 > {
   constructor(
     protected config: ResourceServiceConfig<B>,
-    protected repository: ResourceRepository,
+    protected stateService: StateService,
   ) {
-    super(config, repository);
-  }
-
-  doSave(resource: T, toSave: unknown): Observable<T> {
-    return of(resource);
+    super(config, stateService);
   }
 }
diff --git a/alfa-client/libs/tech-shared/src/lib/resource/resource.service.ts b/alfa-client/libs/tech-shared/src/lib/resource/resource.service.ts
index a69b290c8037e6c4797ae4afc19a695568f9d1c9..8e57b59cc664167c27cc07b0d5f10600c904ad16 100644
--- a/alfa-client/libs/tech-shared/src/lib/resource/resource.service.ts
+++ b/alfa-client/libs/tech-shared/src/lib/resource/resource.service.ts
@@ -1,175 +1,57 @@
-import { HttpErrorResponse } from '@angular/common/http';
-import { getUrl, hasLink, Resource, ResourceUri } from '@ngxp/rest';
-import { isEqual, isNull } from 'lodash-es';
-import {
-  BehaviorSubject,
-  catchError,
-  combineLatest,
-  filter,
-  first,
-  map,
-  Observable,
-  of,
-  startWith,
-  tap,
-  throwError,
-} from 'rxjs';
-import { isUnprocessableEntity } from '../http.util';
-import { HttpError } from '../tech.model';
-import { isNotNull } from '../tech.util';
+import { Resource, ResourceUri } from '@ngxp/rest';
+import { Observable } from 'rxjs';
+import { SingleResourceStateService, StateService } from '../ngrx/state.service';
+import { ResourceLoader } from './resource.loader';
 import { ResourceServiceConfig } from './resource.model';
-import { ResourceRepository } from './resource.repository';
-import { mapToFirst, mapToResource } from './resource.rxjs.operator';
-import {
-  createEmptyStateResource,
-  createErrorStateResource,
-  createStateResource,
-  isInvalidResourceCombination,
-  isLoadingRequired,
-  isStateResoureStable,
-  StateResource,
-} from './resource.util';
+import { StateResource } from './resource.util';
 
 /**
  * B = Type of baseresource
  * T = Type of the resource which is working on
  */
 export abstract class ResourceService<B extends Resource, T extends Resource> {
-  readonly stateResource: BehaviorSubject<StateResource<T>> = new BehaviorSubject(
-    createEmptyStateResource(),
-  );
-
-  configResource: B = null;
+  resourceStateService: SingleResourceStateService<T>;
+  resourceLoader: ResourceLoader<B, T>;
 
   constructor(
     protected config: ResourceServiceConfig<B>,
-    protected repository: ResourceRepository,
-  ) {}
-
-  public get(): Observable<StateResource<T>> {
-    return combineLatest([this.stateResource.asObservable(), this.getConfigResource()]).pipe(
-      tap(([stateResource, configResource]) =>
-        this.handleResourceChanges(stateResource, configResource),
-      ),
-      filter(
-        ([stateResource]) => !isInvalidResourceCombination(stateResource, this.configResource),
-      ),
-      mapToFirst<T, B>(),
-      startWith(createEmptyStateResource<T>(true)),
-    );
-  }
-
-  private getConfigResource(): Observable<B> {
-    return this.config.resource.pipe(
-      filter(
-        (configStateResource: StateResource<B>) =>
-          !configStateResource.loading && !configStateResource.reload,
-      ),
-      mapToResource<B>(),
-    );
-  }
-
-  handleResourceChanges(stateResource: StateResource<T>, configResource: B): void {
-    if (!isEqual(this.configResource, configResource)) {
-      this.handleConfigResourceChanges(stateResource, configResource);
-    } else if (this.shouldLoadResource(stateResource, configResource)) {
-      this.loadResource(configResource);
-    }
+    protected stateService: StateService,
+  ) {
+    this.initStateService();
+    this.initResourceLoader();
   }
 
-  handleConfigResourceChanges(stateResource: StateResource<T>, configResource: B) {
-    this.configResource = configResource;
-    if (isStateResoureStable(stateResource)) {
-      this.updateStateResourceByConfigResource(stateResource, configResource);
-    }
-  }
-
-  updateStateResourceByConfigResource(stateResource: StateResource<T>, configResource: B): void {
-    if (this.shouldClearStateResource(stateResource, configResource)) {
-      this.clearResource();
-    } else if (this.hasGetLink(configResource)) {
-      this.loadResource(configResource);
-    }
-  }
-
-  shouldClearStateResource(stateResource: StateResource<T>, configResource: B): boolean {
-    return (
-      (isNull(configResource) || this.hasNotGetLink(configResource)) &&
-      !this.isStateResourceEmpty(stateResource)
+  private initStateService(): void {
+    this.resourceStateService = this.stateService.createSingleResourceService(
+      this.config.stateInfo,
     );
   }
 
-  private hasNotGetLink(configResource: B): boolean {
-    return !this.hasGetLink(configResource);
+  private initResourceLoader(): void {
+    this.resourceLoader = new ResourceLoader<B, T>(this.config, this.resourceStateService);
   }
 
-  private isStateResourceEmpty(stateResource: StateResource<T>): boolean {
-    return isEqual(stateResource, createEmptyStateResource());
-  }
-
-  private clearResource(): void {
-    this.stateResource.next(createEmptyStateResource());
+  public get(): Observable<StateResource<T>> {
+    return this.resourceLoader.get();
   }
 
-  hasGetLink(configResource: B): boolean {
-    return isNotNull(configResource) && hasLink(configResource, this.config.getLinkRel);
+  public reloadResource(): void {
+    this.resourceStateService.reloadResource();
   }
 
-  shouldLoadResource(stateResource: StateResource<T>, configResource: B): boolean {
-    return isNotNull(configResource) && isLoadingRequired(stateResource);
+  public existResource(): Observable<boolean> {
+    return this.resourceStateService.existsResource();
   }
 
-  loadResource(configResource: B): void {
-    this.doLoadResource(getUrl(configResource, this.config.getLinkRel));
+  public selectResource(): Observable<StateResource<T>> {
+    return this.resourceStateService.selectResource();
   }
 
   public loadByResourceUri(resourceUri: ResourceUri): void {
-    this.doLoadResource(resourceUri);
+    this.resourceStateService.loadResource(resourceUri);
   }
 
-  doLoadResource(resourceUri: ResourceUri): void {
-    this.setStateResourceLoading();
-    this.repository
-      .getResource(resourceUri)
-      .pipe(first())
-      .subscribe((loadedResource: T) => this.updateStateResource(loadedResource));
-  }
-
-  setStateResourceLoading(): void {
-    this.stateResource.next({ ...createEmptyStateResource(true), reload: false });
-  }
-
-  updateStateResource(resource: T): void {
-    this.stateResource.next(createStateResource(resource));
-  }
-
-  public save(toSave: unknown): Observable<StateResource<T | HttpError>> {
-    const previousResource: T = this.stateResource.value.resource;
-    return this.doSave(previousResource, toSave).pipe(
-      tap((loadedResource: T) => this.stateResource.next(createStateResource(loadedResource))),
-      map(() => this.stateResource.value),
-      catchError((errorResponse: HttpErrorResponse) => this.handleError(errorResponse)),
-    );
-  }
-
-  handleError(errorResponse: HttpErrorResponse): Observable<StateResource<HttpError>> {
-    if (isUnprocessableEntity(errorResponse.status)) {
-      return of(createErrorStateResource((<any>errorResponse) as HttpError));
-    }
-    return throwError(() => errorResponse);
-  }
-
-  abstract doSave(resource: T, toSave: unknown): Observable<T>;
-
-  public refresh(): void {
-    this.stateResource.next({ ...this.stateResource.value, reload: true });
-  }
-
-  public existResource(): Observable<boolean> {
-    return this.stateResource.asObservable().pipe(mapToResource<T>(), map(isNotNull));
-  }
-
-  public selectResource(): Observable<StateResource<T>> {
-    return this.stateResource.asObservable();
+  public clearResource(): void {
+    this.resourceStateService.clearResource();
   }
 }
diff --git a/alfa-client/libs/tech-shared/src/lib/tech-shared.module.ts b/alfa-client/libs/tech-shared/src/lib/tech-shared.module.ts
index ecb138d23695a7111038967cf2d80147cbac5206..7e4cdca79c9f17bf7f36e1e769d5de9ac15eb6fa 100644
--- a/alfa-client/libs/tech-shared/src/lib/tech-shared.module.ts
+++ b/alfa-client/libs/tech-shared/src/lib/tech-shared.module.ts
@@ -27,6 +27,8 @@ import { Injector, NgModule } from '@angular/core';
 import { HttpBinaryFileInterceptor } from './interceptor/http-binary-file.interceptor';
 import { HttpXsrfInterceptor } from './interceptor/http-xsrf.interceptor';
 import { XhrInterceptor } from './interceptor/xhr.interceptor';
+import { EffectService } from './ngrx/effects.service';
+import { StateService } from './ngrx/state.service';
 import { ConvertApiErrorToErrorMessagesPipe } from './pipe/convert-api-error-to-error-messages.pipe';
 import { ConvertForDataTestPipe } from './pipe/convert-for-data-test.pipe';
 import { ConvertToBooleanPipe } from './pipe/convert-to-boolean.pipe';
@@ -89,6 +91,8 @@ import { ToTrafficLightPipe } from './pipe/to-traffic-light.pipe';
     ConvertApiErrorToErrorMessagesPipe,
   ],
   providers: [
+    StateService,
+    EffectService,
     {
       provide: HTTP_INTERCEPTORS,
       useClass: XhrInterceptor,
diff --git a/alfa-client/libs/tech-shared/test/marbles.ts b/alfa-client/libs/tech-shared/test/marbles.ts
index 199c8726cb43b889816929635014861fc19d19df..2b785612e602a3133e05ca4e02b1bad63e97b5cb 100644
--- a/alfa-client/libs/tech-shared/test/marbles.ts
+++ b/alfa-client/libs/tech-shared/test/marbles.ts
@@ -1,5 +1,8 @@
 import { ObservableWithSubscriptions, cold, hot } from 'jest-marbles';
 
+export const CLOSED_FRAME: string = '(a|)';
+export const SECOND_FRAME: string = '-a';
+
 export function singleHot(object: any, frame: string = 'a'): ObservableWithSubscriptions {
   return hot(frame, { a: object });
 }
@@ -11,3 +14,7 @@ export function singleCold(object: any, frame: string = 'a'): ObservableWithSubs
 export function singleColdCompleted(object: any, frame: string = 'a'): ObservableWithSubscriptions {
   return cold(`(${frame}|)`, { a: object });
 }
+
+export function multiCold(object: any, frame: string = 'ab'): ObservableWithSubscriptions {
+  return cold(frame, object);
+}
diff --git a/alfa-client/libs/tech-shared/test/ngrx.ts b/alfa-client/libs/tech-shared/test/ngrx.ts
index 526b345e5b8d10646ef4d1f62fd72d01837a3b90..b7b17b0a3409ccb9ff5098fab83d74ac125820fe 100644
--- a/alfa-client/libs/tech-shared/test/ngrx.ts
+++ b/alfa-client/libs/tech-shared/test/ngrx.ts
@@ -1,3 +1,64 @@
+import { createAction, createFeatureSelector, createSelector, props } from '@ngrx/store';
 import { TypedAction } from '@ngrx/store/src/models';
+import {
+  LoadResourceFailureProps,
+  LoadResourceSuccessProps,
+  ResourceUriProps,
+  SingleResourceLoadActions,
+  TypedActionCreator,
+  TypedActionCreatorWithProps,
+} from '../src/lib/ngrx/actions';
+import { SingleResourceState } from '../src/lib/ngrx/state.model';
+import { StateInfo } from '../src/lib/resource/resource.model';
 
 export const DUMMY_ACTION: TypedAction<string> = { type: 'Dummy Action' };
+
+export const FUNCTIONAL_FEATURE_KEY = 'FunctionalState';
+export const FUNCTIONAL_FEATURE_PATH_KEY = 'FunctionalResourcePath';
+
+export interface SingleResourceParentState {
+  readonly [FUNCTIONAL_FEATURE_KEY]: SingleResourcePartialState;
+}
+export interface SingleResourcePartialState {
+  readonly [FUNCTIONAL_FEATURE_PATH_KEY]: SingleResourceState;
+}
+
+export class StateInfoTestFactory {
+  public static readonly STATE_INFO_NAME: string = FUNCTIONAL_FEATURE_KEY;
+  public static readonly STATE_INFO_PATH: string = FUNCTIONAL_FEATURE_PATH_KEY;
+
+  public static create(): StateInfo {
+    return {
+      name: this.STATE_INFO_NAME,
+      path: this.STATE_INFO_PATH,
+    };
+  }
+}
+
+export const dummySelector = createSelector(
+  createFeatureSelector(FUNCTIONAL_FEATURE_KEY),
+  (state: unknown) => state,
+);
+
+export const dummyLoadAction: TypedActionCreatorWithProps<ResourceUriProps> = createAction(
+  'DummyLoadAction',
+  props<ResourceUriProps>(),
+);
+
+export const dummyLoadSuccessAction: TypedActionCreatorWithProps<LoadResourceSuccessProps> =
+  createAction('DummyLoadSuccessAction', props<LoadResourceSuccessProps>());
+
+export const dummyLoadFailureAction: TypedActionCreatorWithProps<LoadResourceFailureProps> =
+  createAction('DummyLoadFailureAction', props<LoadResourceFailureProps>());
+
+export const dummyClearAction: TypedActionCreator = createAction('DummyClearAction');
+
+export const dummyReloadAction: TypedActionCreator = createAction('DummyReloadAction');
+
+export const singleResourceActions: SingleResourceLoadActions = {
+  loadAction: dummyLoadAction,
+  loadSuccessAction: dummyLoadSuccessAction,
+  loadFailureAction: dummyLoadFailureAction,
+  clearAction: dummyClearAction,
+  reloadAction: dummyReloadAction,
+};