diff --git a/.dbeaver/credentials-config.json b/.dbeaver/credentials-config.json
deleted file mode 100644
index d814bdfcf..000000000
--- a/.dbeaver/credentials-config.json
+++ /dev/null
@@ -1,3 +0,0 @@
-�4�k���1�,��f�b�A�qĬc��#������#s�8-�1�&�;���"����7�d�jM?�bljfB��q�=
-��my��
-v���V�
\ No newline at end of file
diff --git a/.dbeaver/data-sources.json b/.dbeaver/data-sources.json
deleted file mode 100644
index 096f0d57e..000000000
--- a/.dbeaver/data-sources.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
-	"folders": {},
-	"connections": {
-		"mariaDB-1813fbbc7bc-107c0b3aeaeb91ab": {
-			"provider": "mysql",
-			"driver": "mariaDB",
-			"name": "gradido",
-			"save-password": true,
-			"read-only": false,
-			"configuration": {
-				"host": "localhost",
-				"port": "3306",
-				"url": "jdbc:mariadb://localhost:3306/",
-				"home": "mysql_client",
-				"type": "dev",
-				"auth-model": "native",
-				"handlers": {}
-			}
-		}
-	},
-	"connection-types": {
-		"dev": {
-			"name": "Development",
-			"color": "255,255,255",
-			"description": "Regular development database",
-			"auto-commit": true,
-			"confirm-execute": false,
-			"confirm-data-change": false,
-			"auto-close-transactions": false
-		}
-	}
-}
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index ced6746aa..1a111760f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,5 @@
+.dbeaver
+.project
 *.log
 *.bak
 /node_modules/*
diff --git a/.project b/.project
deleted file mode 100644
index 5d9663f32..000000000
--- a/.project
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
-	<name>Gradido</name>
-	<comment></comment>
-	<projects>
-	</projects>
-	<buildSpec>
-		<buildCommand>
-			<name>org.eclipse.wst.validation.validationbuilder</name>
-			<arguments>
-			</arguments>
-		</buildCommand>
-	</buildSpec>
-	<natures>
-		<nature>org.jkiss.dbeaver.DBeaverNature</nature>
-		<nature>org.eclipse.wst.jsdt.core.jsNature</nature>
-	</natures>
-</projectDescription>
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 53aa4a9e1..63b0c2c90 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,8 +4,88 @@ All notable changes to this project will be documented in this file. Dates are d
 
 Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
 
+#### [1.11.0](https://github.com/gradido/gradido/compare/1.10.1...1.11.0)
+
+- Fix navbar community item [`#2102`](https://github.com/gradido/gradido/pull/2102)
+- Add validation date info to copied text after transaction link creation [`#2101`](https://github.com/gradido/gradido/pull/2101)
+- Remove member area from menu (desktop and mobile), when user has no elopage account [`#2099`](https://github.com/gradido/gradido/pull/2099)
+- fix: Use Inner Join for Contribution and User [`#2100`](https://github.com/gradido/gradido/pull/2100)
+- Enable copying the link, username, amount, and memo text after transaction link creation [`#2098`](https://github.com/gradido/gradido/pull/2098)
+- feat: Insert Missing Contributions Migration [`#2053`](https://github.com/gradido/gradido/pull/2053)
+- [Bug] Wallet improvments for Contributions [`#2090`](https://github.com/gradido/gradido/pull/2090)
+- [Fix] Add createdAt & contributionDate to ContributionListItems [`#2093`](https://github.com/gradido/gradido/pull/2093)
+- fix: 🍰 Reset Amount In Contribution Form And Write A Test [`#2086`](https://github.com/gradido/gradido/pull/2086)
+- [Feat] Replace logic to validation-provider. [`#2088`](https://github.com/gradido/gradido/pull/2088)
+- fix: Add Confirm Dialog on Delete Contribution [`#2087`](https://github.com/gradido/gradido/pull/2087)
+- fix: Admin Cannot Edit User  Contribution [`#2085`](https://github.com/gradido/gradido/pull/2085)
+- fix: Update contribution_date when Moved by Seed [`#2083`](https://github.com/gradido/gradido/pull/2083)
+- chore: 🍰 Provide Volume For Backend Log-Files In Docker [`#2067`](https://github.com/gradido/gradido/pull/2067)
+- feat: 🍰 Community Contribution Site And Form [`#2042`](https://github.com/gradido/gradido/pull/2042)
+- [Refactor] Move MEMO_MIN_CHARS and MEMO_MAX_CHARS to const file [`#2082`](https://github.com/gradido/gradido/pull/2082)
+- Fix: Test memo length on createContribution & updateContribution [`#2080`](https://github.com/gradido/gradido/pull/2080)
+-  chore: 🍰 Change `image` Entries In Docker Compose Files And Get Apple M1 Running [`#2050`](https://github.com/gradido/gradido/pull/2050)
+- fix: Windows 0D 0A Linebreaks to Unix 0A [`#2064`](https://github.com/gradido/gradido/pull/2064)
+- Add contributionDate to the Contribution object. [`#2066`](https://github.com/gradido/gradido/pull/2066)
+- fix: Add Contributions to User [`#2062`](https://github.com/gradido/gradido/pull/2062)
+- Feat: ContributionResolver - delete mutation [`#2035`](https://github.com/gradido/gradido/pull/2035)
+- Fix: Add count to list contributions [`#2061`](https://github.com/gradido/gradido/pull/2061)
+- docu: Explain how `.env` Files are Working [`#2022`](https://github.com/gradido/gradido/pull/2022)
+- [WIP] 1794 feature event protocol 1 implement the basics of the business event protocol [`#1997`](https://github.com/gradido/gradido/pull/1997)
+- docs: 🍰 Document The Setup Of The GraphQL Playground [`#2060`](https://github.com/gradido/gradido/pull/2060)
+- Feat: List all contribution [`#2057`](https://github.com/gradido/gradido/pull/2057)
+- feat: Do not log IntrospectionQuery from Query Browser [`#2059`](https://github.com/gradido/gradido/pull/2059)
+- Feat: Add confirmedBy and confirmedAt for the contribution query. [`#2052`](https://github.com/gradido/gradido/pull/2052)
+- Add open creations to webapp [`#2048`](https://github.com/gradido/gradido/pull/2048)
+- Prevent session expiration modal from displaying negative seconds, when session is expired for more than 0 seconds [`#2054`](https://github.com/gradido/gradido/pull/2054)
+- feat: mutation contribution update [`#2032`](https://github.com/gradido/gradido/pull/2032)
+- feat: Login Returns Open Creations for User [`#2046`](https://github.com/gradido/gradido/pull/2046)
+- Migrate transaction to valid dataset for gradido node [`#2029`](https://github.com/gradido/gradido/pull/2029)
+- feat: implement contribution list query [`#2031`](https://github.com/gradido/gradido/pull/2031)
+- add code for moving user creation date if transaction before exist [`#2034`](https://github.com/gradido/gradido/pull/2034)
+- change text from page [`#2037`](https://github.com/gradido/gradido/pull/2037)
+- Transaction link: copy link, text and more [`#2030`](https://github.com/gradido/gradido/pull/2030)
+- change welcome in community text [`#2025`](https://github.com/gradido/gradido/pull/2025)
+- changed link color in navbar and language switch [`#2024`](https://github.com/gradido/gradido/pull/2024)
+- feat: ContributionResolver - createContribution [`#2009`](https://github.com/gradido/gradido/pull/2009)
+
+#### [1.10.1](https://github.com/gradido/gradido/compare/1.10.0...1.10.1)
+
+> 30 June 2022
+
+- release: 1.10.1 [`#2021`](https://github.com/gradido/gradido/pull/2021)
+- automatic session logout with info modal [`#2001`](https://github.com/gradido/gradido/pull/2001)
+- 1910 separate text for the slideshow images.  [`#1998`](https://github.com/gradido/gradido/pull/1998)
+- Origin/1921 additional parameter checks for createContributionLinks [`#1996`](https://github.com/gradido/gradido/pull/1996)
+- add missing locales [`#1999`](https://github.com/gradido/gradido/pull/1999)
+- 1906 feature concept for gdd creation per linkqr code [`#1907`](https://github.com/gradido/gradido/pull/1907)
+- refactor: 🍰 Not Throwing An Error When Register With Existing Email [`#1962`](https://github.com/gradido/gradido/pull/1962)
+-  feat: 🍰 Set Role In Admin Interface [`#1974`](https://github.com/gradido/gradido/pull/1974)
+- refactor mobile style step 1 [`#1977`](https://github.com/gradido/gradido/pull/1977)
+- changed mobil stage picture [`#1995`](https://github.com/gradido/gradido/pull/1995)
+
+#### [1.10.0](https://github.com/gradido/gradido/compare/1.9.0...1.10.0)
+
+> 17 June 2022
+
+- release: v1.10.0 [`#1993`](https://github.com/gradido/gradido/pull/1993)
+- frontend redeem contribution link [`#1988`](https://github.com/gradido/gradido/pull/1988)
+- change new start picture [`#1990`](https://github.com/gradido/gradido/pull/1990)
+- feat: Redeem Contribution Link [`#1987`](https://github.com/gradido/gradido/pull/1987)
+- fix: Max Amount on Slider for Edit Contribution [`#1986`](https://github.com/gradido/gradido/pull/1986)
+- CRUD contribution link admin interface [`#1981`](https://github.com/gradido/gradido/pull/1981)
+- fix: `.env` log level for apollo and backend category [`#1967`](https://github.com/gradido/gradido/pull/1967)
+- refactor: Admin Pending Creations Table to Contributions Table [`#1949`](https://github.com/gradido/gradido/pull/1949)
+- devops: Update Browser List for Unit Tests as Recomended [`#1984`](https://github.com/gradido/gradido/pull/1984)
+- feat: CRUD for Contribution Links in Admin Resolver [`#1979`](https://github.com/gradido/gradido/pull/1979)
+- 1920 feature create contribution link table [`#1957`](https://github.com/gradido/gradido/pull/1957)
+- refactor: 🍰 Delete `user_setting` Table From DB [`#1960`](https://github.com/gradido/gradido/pull/1960)
+- locales link german, english navbar [`#1969`](https://github.com/gradido/gradido/pull/1969)
+
 #### [1.9.0](https://github.com/gradido/gradido/compare/1.8.3...1.9.0)
 
+> 2 June 2022
+
+- devops: Release Version 1.9.0 [`#1968`](https://github.com/gradido/gradido/pull/1968)
 - refactor: 🍰 Refactor To `filters` Object And Rename Filters Properties [`#1914`](https://github.com/gradido/gradido/pull/1914)
 - refactor register button position [`#1964`](https://github.com/gradido/gradido/pull/1964)
 - fixed redeem link is mobile start false [`#1958`](https://github.com/gradido/gradido/pull/1958)
diff --git a/DOCKER_MORE_CLOSELY.md b/DOCKER_MORE_CLOSELY.md
new file mode 100644
index 000000000..f2aae81c7
--- /dev/null
+++ b/DOCKER_MORE_CLOSELY.md
@@ -0,0 +1,44 @@
+# Docker More Closely
+
+## Apple M1 Platform
+
+***Attention:** For using Docker commands in Apple M1 environments!*
+
+### Enviroment Variable For Apple M1 Platform
+
+To set the Docker platform environment variable in your terminal tab, run:
+
+```bash
+# set env variable for your shell
+$ export DOCKER_DEFAULT_PLATFORM=linux/amd64
+```
+
+### Docker Compose Override File For Apple M1 Platform
+
+For Docker compose `up` or `build` commands, you can use our Apple M1 override file that specifies the M1 platform:
+
+```bash
+# in main folder
+
+# for development
+$ docker compose -f docker-compose.yml -f docker-compose.override.yml -f docker-compose.apple-m1.override.yml up
+
+# for production
+$ docker compose -f docker-compose.yml -f docker-compose.apple-m1.override.yml up
+```
+
+## Analysing Docker Builds
+
+To analyze a Docker build, there is a wonderful tool called [dive](https://github.com/wagoodman/dive). Please sponsor if you're using it!
+
+The `dive build` command is exactly the right one to fulfill what we are looking for.
+We can use it just like the `docker build` command and get an analysis afterwards.
+
+So, in our main folder, we use it in the following way:
+
+```bash
+# in main folder
+$ dive build --target <layer-name> -t "gradido/<app-name>:local-<layer-name>" <app-folder-name-or-dot>/
+```
+
+For the specific applications, see our [publish.yml](.github/workflows/publish.yml).
diff --git a/README.md b/README.md
index 289a39109..3d086018e 100644
--- a/README.md
+++ b/README.md
@@ -121,6 +121,19 @@ After generating a new version you should commit the changes. This will be the C
 
 Note: The Changelog will be regenerated with all tags on release on the external builder tool, but will not be checked in there. The Changelog on the github release will therefore always be correct, on the repo it might be incorrect due to missing tags when executing the `yarn release` command.
 
+## How the different .env work on deploy
+
+Each component (frontend, admin, backend and database) has its own `.env` file. When running in development with docker and nginx you usually do not have to care about the `.env`. The defaults are set by the respective config file, found in the `src/config/` folder of each component. But if you have a local `.env`, the defaults set in the config are overwritten by the `.env`. If you do not use docker, you need the `.env` in the frontend and admin interface because nginx is not running in order to find the backend. 
+
+Each component has a `.env.dist` file. This file contains all environment variables used by the component and can be used as pattern. If you want to use a local `.env`, copy the `.env.dist` and adjust the variables accordingly.
+
+Each component has a `.env.template` file. These files are very important on deploy.
+
+There is one `.env.dist` in the `deployment/bare_metal/` folder. This `.env.dist` contains all variables used by the components, e.g. unites all `.env.dist` from the components. On deploy, we copy this `.env.dist` to `.env` and set all variables in this new file. The deploy script loads this variables and provides them by the `.env.templates` of each component, creating an `.env` for each component (see in `deployment/bare_metal/start.sh` the `envsubst`).
+
+To avoid forgetting to update an existing `.env` in the `deployment/bare_metal/` folder when deploying, we have an environment version variable inside the codebase of each component. You should update this version, when environment variables must be changed or added on deploy. The code checks, that the environement version provided by the `.env` is the one expected by the codebase.
+
+
 ## Troubleshooting
 
 | Problem                                          | Issue                                                | Solution                                                                      | Description                                                                 |
diff --git a/admin/jest.config.js b/admin/jest.config.js
index b7226bd8f..9b9842bad 100644
--- a/admin/jest.config.js
+++ b/admin/jest.config.js
@@ -22,7 +22,7 @@ module.exports = {
     '^.+\\.(js|jsx)?$': 'babel-jest',
     '<rootDir>/node_modules/vee-validate/dist/rules': 'babel-jest',
   },
-  setupFiles: ['<rootDir>/test/testSetup.js'],
+  setupFiles: ['<rootDir>/test/testSetup.js', 'jest-canvas-mock'],
   testMatch: ['**/?(*.)+(spec|test).js?(x)'],
   // snapshotSerializers: ['jest-serializer-vue'],
   transformIgnorePatterns: ['<rootDir>/node_modules/(?!vee-validate/dist/rules)'],
diff --git a/admin/package.json b/admin/package.json
index e36308fd9..5da80bd1f 100644
--- a/admin/package.json
+++ b/admin/package.json
@@ -3,7 +3,7 @@
   "description": "Administraion Interface for Gradido",
   "main": "index.js",
   "author": "Moriz Wahl",
-  "version": "1.9.0",
+  "version": "1.11.0",
   "license": "Apache-2.0",
   "private": false,
   "scripts": {
@@ -38,7 +38,9 @@
     "graphql": "^15.6.1",
     "identity-obj-proxy": "^3.0.0",
     "jest": "26.6.3",
+    "jest-canvas-mock": "^2.3.1",
     "portal-vue": "^2.1.7",
+    "qrcanvas-vue": "2.1.1",
     "regenerator-runtime": "^0.13.9",
     "stats-webpack-plugin": "^0.7.0",
     "vue": "^2.6.11",
diff --git a/admin/public/img/gdd-coin.png b/admin/public/img/gdd-coin.png
new file mode 100644
index 000000000..32cb8b2b2
Binary files /dev/null and b/admin/public/img/gdd-coin.png differ
diff --git a/admin/src/components/ChangeUserRoleFormular.spec.js b/admin/src/components/ChangeUserRoleFormular.spec.js
new file mode 100644
index 000000000..8bcd4d8e5
--- /dev/null
+++ b/admin/src/components/ChangeUserRoleFormular.spec.js
@@ -0,0 +1,254 @@
+import { mount } from '@vue/test-utils'
+import ChangeUserRoleFormular from './ChangeUserRoleFormular.vue'
+import { setUserRole } from '../graphql/setUserRole'
+import { toastSuccessSpy, toastErrorSpy } from '../../test/testSetup'
+
+const localVue = global.localVue
+
+const apolloMutateMock = jest.fn().mockResolvedValue({
+  data: {
+    setUserRole: null,
+  },
+})
+
+const mocks = {
+  $t: jest.fn((t) => t),
+  $apollo: {
+    mutate: apolloMutateMock,
+  },
+  $store: {
+    state: {
+      moderator: {
+        id: 0,
+        name: 'test moderator',
+      },
+    },
+  },
+}
+
+let propsData
+let wrapper
+
+describe('ChangeUserRoleFormular', () => {
+  const Wrapper = () => {
+    return mount(ChangeUserRoleFormular, { localVue, mocks, propsData })
+  }
+
+  describe('mount', () => {
+    beforeEach(() => {
+      jest.clearAllMocks()
+    })
+
+    describe('DOM has', () => {
+      beforeEach(() => {
+        propsData = {
+          item: {
+            userId: 1,
+            isAdmin: null,
+          },
+        }
+        wrapper = Wrapper()
+      })
+
+      it('has a DIV element with the class.delete-user-formular', () => {
+        expect(wrapper.find('.change-user-role-formular').exists()).toBe(true)
+      })
+    })
+
+    describe('change own role', () => {
+      beforeEach(() => {
+        propsData = {
+          item: {
+            userId: 0,
+            isAdmin: null,
+          },
+        }
+        wrapper = Wrapper()
+      })
+
+      it('has the text that you cannot change own role', () => {
+        expect(wrapper.text()).toContain('userRole.notChangeYourSelf')
+      })
+
+      it('has role select disabled', () => {
+        expect(wrapper.find('select[disabled="disabled"]').exists()).toBe(true)
+      })
+    })
+
+    describe('change others role', () => {
+      let rolesToSelect
+
+      describe('general', () => {
+        beforeEach(() => {
+          propsData = {
+            item: {
+              userId: 1,
+              isAdmin: null,
+            },
+          }
+          wrapper = Wrapper()
+          rolesToSelect = wrapper.find('select.role-select').findAll('option')
+        })
+
+        it('has no text that you cannot change own role', () => {
+          expect(wrapper.text()).not.toContain('userRole.notChangeYourSelf')
+        })
+
+        it('has the select label', () => {
+          expect(wrapper.text()).toContain('userRole.selectLabel')
+        })
+
+        it('has a select', () => {
+          expect(wrapper.find('select.role-select').exists()).toBe(true)
+        })
+
+        it('has role select enabled', () => {
+          expect(wrapper.find('select.role-select[disabled="disabled"]').exists()).toBe(false)
+        })
+
+        describe('on API error', () => {
+          beforeEach(() => {
+            apolloMutateMock.mockRejectedValue({ message: 'Oh no!' })
+            rolesToSelect.at(1).setSelected()
+          })
+
+          it('toasts an error message', () => {
+            expect(toastErrorSpy).toBeCalledWith('Oh no!')
+          })
+        })
+      })
+
+      describe('user is usual user', () => {
+        beforeEach(() => {
+          apolloMutateMock.mockResolvedValue({
+            data: {
+              setUserRole: new Date(),
+            },
+          })
+          propsData = {
+            item: {
+              userId: 1,
+              isAdmin: null,
+            },
+          }
+          wrapper = Wrapper()
+          rolesToSelect = wrapper.find('select.role-select').findAll('option')
+        })
+
+        it('has selected option set to "usual user"', () => {
+          expect(wrapper.find('select.role-select').element.value).toBe('user')
+        })
+
+        describe('change select to', () => {
+          describe('same role', () => {
+            it('does not call the API', () => {
+              rolesToSelect.at(0).setSelected()
+              expect(apolloMutateMock).not.toHaveBeenCalled()
+            })
+          })
+
+          describe('new role', () => {
+            beforeEach(() => {
+              rolesToSelect.at(1).setSelected()
+            })
+
+            it('calls the API', () => {
+              expect(apolloMutateMock).toBeCalledWith(
+                expect.objectContaining({
+                  mutation: setUserRole,
+                  variables: {
+                    userId: 1,
+                    isAdmin: true,
+                  },
+                }),
+              )
+            })
+
+            it('emits "updateIsAdmin"', () => {
+              expect(wrapper.emitted('updateIsAdmin')).toEqual(
+                expect.arrayContaining([
+                  expect.arrayContaining([
+                    {
+                      userId: 1,
+                      isAdmin: expect.any(Date),
+                    },
+                  ]),
+                ]),
+              )
+            })
+
+            it('toasts success message', () => {
+              expect(toastSuccessSpy).toBeCalledWith('userRole.successfullyChangedTo')
+            })
+          })
+        })
+      })
+
+      describe('user is admin', () => {
+        beforeEach(() => {
+          apolloMutateMock.mockResolvedValue({
+            data: {
+              setUserRole: null,
+            },
+          })
+          propsData = {
+            item: {
+              userId: 1,
+              isAdmin: new Date(),
+            },
+          }
+          wrapper = Wrapper()
+          rolesToSelect = wrapper.find('select.role-select').findAll('option')
+        })
+
+        it('has selected option set to "admin"', () => {
+          expect(wrapper.find('select.role-select').element.value).toBe('admin')
+        })
+
+        describe('change select to', () => {
+          describe('same role', () => {
+            it('does not call the API', () => {
+              rolesToSelect.at(1).setSelected()
+              expect(apolloMutateMock).not.toHaveBeenCalled()
+            })
+          })
+
+          describe('new role', () => {
+            beforeEach(() => {
+              rolesToSelect.at(0).setSelected()
+            })
+
+            it('calls the API', () => {
+              expect(apolloMutateMock).toBeCalledWith(
+                expect.objectContaining({
+                  mutation: setUserRole,
+                  variables: {
+                    userId: 1,
+                    isAdmin: false,
+                  },
+                }),
+              )
+            })
+
+            it('emits "updateIsAdmin"', () => {
+              expect(wrapper.emitted('updateIsAdmin')).toEqual(
+                expect.arrayContaining([
+                  expect.arrayContaining([
+                    {
+                      userId: 1,
+                      isAdmin: null,
+                    },
+                  ]),
+                ]),
+              )
+            })
+
+            it('toasts success message', () => {
+              expect(toastSuccessSpy).toBeCalledWith('userRole.successfullyChangedTo')
+            })
+          })
+        })
+      })
+    })
+  })
+})
diff --git a/admin/src/components/ChangeUserRoleFormular.vue b/admin/src/components/ChangeUserRoleFormular.vue
new file mode 100644
index 000000000..1217ce7f0
--- /dev/null
+++ b/admin/src/components/ChangeUserRoleFormular.vue
@@ -0,0 +1,89 @@
+<template>
+  <div class="change-user-role-formular">
+    <div class="shadow p-3 mb-5 bg-white rounded">
+      <div v-if="item.userId === $store.state.moderator.id" class="m-3 mb-4">
+        {{ $t('userRole.notChangeYourSelf') }}
+      </div>
+      <div class="m-3">
+        <label for="role" class="mr-3">{{ $t('userRole.selectLabel') }}</label>
+        <b-form-select
+          class="role-select"
+          v-model="roleSelected"
+          :options="roles"
+          :disabled="item.userId === $store.state.moderator.id"
+        />
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { setUserRole } from '../graphql/setUserRole'
+
+const rolesValues = {
+  admin: 'admin',
+  user: 'user',
+}
+
+export default {
+  name: 'ChangeUserRoleFormular',
+  props: {
+    item: {
+      type: Object,
+      required: true,
+    },
+  },
+  data() {
+    return {
+      roleSelected: this.item.isAdmin ? rolesValues.admin : rolesValues.user,
+      roles: [
+        { value: rolesValues.user, text: this.$t('userRole.selectRoles.user') },
+        { value: rolesValues.admin, text: this.$t('userRole.selectRoles.admin') },
+      ],
+    }
+  },
+  watch: {
+    roleSelected(newRole, oldRole) {
+      if (newRole !== oldRole) {
+        this.setUserRole(newRole, oldRole)
+      }
+    },
+  },
+  methods: {
+    setUserRole(newRole, oldRole) {
+      this.$apollo
+        .mutate({
+          mutation: setUserRole,
+          variables: {
+            userId: this.item.userId,
+            isAdmin: newRole === rolesValues.admin,
+          },
+        })
+        .then((result) => {
+          this.$emit('updateIsAdmin', {
+            userId: this.item.userId,
+            isAdmin: result.data.setUserRole,
+          })
+          this.toastSuccess(
+            this.$t('userRole.successfullyChangedTo', {
+              role:
+                result.data.setUserRole !== null
+                  ? this.$t('userRole.selectRoles.admin')
+                  : this.$t('userRole.selectRoles.user'),
+            }),
+          )
+        })
+        .catch((error) => {
+          this.roleSelected = oldRole
+          this.toastError(error.message)
+        })
+    },
+  },
+}
+</script>
+
+<style>
+.role-select {
+  width: 300pt;
+}
+</style>
diff --git a/admin/src/components/ContributionLink.spec.js b/admin/src/components/ContributionLink.spec.js
new file mode 100644
index 000000000..f1b9cfb97
--- /dev/null
+++ b/admin/src/components/ContributionLink.spec.js
@@ -0,0 +1,49 @@
+import { mount } from '@vue/test-utils'
+import ContributionLink from './ContributionLink.vue'
+
+const localVue = global.localVue
+
+const mocks = {
+  $t: jest.fn((t) => t),
+}
+
+const propsData = {
+  items: [
+    {
+      id: 1,
+      name: 'Meditation',
+      memo: 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut l',
+      amount: '200',
+      validFrom: '2022-04-01',
+      validTo: '2022-08-01',
+      cycle: 'täglich',
+      maxPerCycle: '3',
+      maxAmountPerMonth: 0,
+      link: 'https://localhost/redeem/CL-1a2345678',
+    },
+  ],
+  count: 1,
+}
+
+describe('ContributionLink', () => {
+  let wrapper
+
+  const Wrapper = () => {
+    return mount(ContributionLink, { localVue, mocks, propsData })
+  }
+
+  describe('mount', () => {
+    beforeEach(() => {
+      wrapper = Wrapper()
+    })
+
+    it('renders the Div Element ".contribution-link"', () => {
+      expect(wrapper.find('div.contribution-link').exists()).toBe(true)
+    })
+
+    it('emits toggle::collapse new Contribution', async () => {
+      wrapper.vm.editContributionLinkData()
+      expect(wrapper.vm.$root.$emit('bv::toggle::collapse', 'newContribution')).toBeTruthy()
+    })
+  })
+})
diff --git a/admin/src/components/ContributionLink.vue b/admin/src/components/ContributionLink.vue
new file mode 100644
index 000000000..893e202f4
--- /dev/null
+++ b/admin/src/components/ContributionLink.vue
@@ -0,0 +1,66 @@
+<template>
+  <div class="contribution-link">
+    <b-card
+      border-variant="success"
+      :header="$t('contributionLink.contributionLinks')"
+      header-bg-variant="success"
+      header-text-variant="white"
+      header-class="text-center"
+      class="mt-5"
+    >
+      <b-button v-b-toggle.newContribution class="my-3 d-flex justify-content-left">
+        {{ $t('math.plus') }} {{ $t('contributionLink.newContributionLink') }}
+      </b-button>
+
+      <b-collapse v-model="visible" id="newContribution" class="mt-2">
+        <b-card>
+          <p class="h2 ml-5">{{ $t('contributionLink.contributionLinks') }}</p>
+          <contribution-link-form :contributionLinkData="contributionLinkData" />
+        </b-card>
+      </b-collapse>
+
+      <b-card-text>
+        <contribution-link-list
+          v-if="count > 0"
+          :items="items"
+          @editContributionLinkData="editContributionLinkData"
+        />
+        <div v-else>{{ $t('contributionLink.noContributionLinks') }}</div>
+      </b-card-text>
+    </b-card>
+  </div>
+</template>
+<script>
+import ContributionLinkForm from './ContributionLinkForm.vue'
+import ContributionLinkList from './ContributionLinkList.vue'
+
+export default {
+  name: 'ContributionLink',
+  components: {
+    ContributionLinkForm,
+    ContributionLinkList,
+  },
+  props: {
+    items: {
+      type: Array,
+      required: true,
+    },
+    count: {
+      type: Number,
+      required: true,
+    },
+  },
+  data: function () {
+    return {
+      visible: false,
+      contributionLinkData: {},
+    }
+  },
+  methods: {
+    editContributionLinkData(data) {
+      if (!this.visible) this.$root.$emit('bv::toggle::collapse', 'newContribution')
+      this.contributionLinkData = data
+    },
+  },
+}
+</script>
diff --git a/admin/src/components/ContributionLinkForm.spec.js b/admin/src/components/ContributionLinkForm.spec.js
new file mode 100644
index 000000000..9c7c33c52
--- /dev/null
+++ b/admin/src/components/ContributionLinkForm.spec.js
@@ -0,0 +1,102 @@
+import { mount } from '@vue/test-utils'
+import ContributionLinkForm from './ContributionLinkForm.vue'
+
+const localVue = global.localVue
+
+global.alert = jest.fn()
+
+const propsData = {
+  contributionLinkData: {},
+}
+
+const mocks = {
+  $t: jest.fn((t) => t),
+}
+
+// const mockAPIcall = jest.fn()
+
+describe('ContributionLinkForm', () => {
+  let wrapper
+
+  const Wrapper = () => {
+    return mount(ContributionLinkForm, { localVue, mocks, propsData })
+  }
+
+  describe('mount', () => {
+    beforeEach(() => {
+      wrapper = Wrapper()
+    })
+
+    it('renders the Div Element ".contribution-link-form"', () => {
+      expect(wrapper.find('div.contribution-link-form').exists()).toBe(true)
+    })
+
+    describe('call onReset', () => {
+      it('form has the set data', () => {
+        beforeEach(() => {
+          wrapper.setData({
+            form: {
+              name: 'name',
+              memo: 'memo',
+              amount: 100,
+              validFrom: 'validFrom',
+              validTo: 'validTo',
+              cycle: 'ONCE',
+              maxPerCycle: 1,
+              maxAmountPerMonth: 100,
+            },
+          })
+          wrapper.vm.onReset()
+        })
+        expect(wrapper.vm.form).toEqual({
+          amount: null,
+          cycle: 'ONCE',
+          validTo: null,
+          maxAmountPerMonth: '0',
+          memo: null,
+          name: null,
+          maxPerCycle: 1,
+          validFrom: null,
+        })
+      })
+    })
+
+    describe('call onSubmit', () => {
+      it('response with the contribution link url', () => {
+        wrapper.vm.onSubmit()
+      })
+    })
+
+    // describe('successfull submit', () => {
+    //   beforeEach(async () => {
+    //     mockAPIcall.mockResolvedValue({
+    //       data: {
+    //         createContributionLink: {
+    //           link: 'https://localhost/redeem/CL-1a2345678',
+    //         },
+    //       },
+    //     })
+    //     await wrapper.find('input.test-validFrom').setValue('2022-6-18')
+    //     await wrapper.find('input.test-validTo').setValue('2022-7-18')
+    //     await wrapper.find('input.test-name').setValue('test name')
+    //     await wrapper.find('input.test-memo').setValue('test memo')
+    //     await wrapper.find('input.test-amount').setValue('100')
+    //     await wrapper.find('form').trigger('submit')
+    //   })
+
+    //   it('calls the API', () => {
+    //     expect(mockAPIcall).toHaveBeenCalledWith(
+    //       expect.objectContaining({
+    //         variables: {
+    //           link: 'https://localhost/redeem/CL-1a2345678',
+    //         },
+    //       }),
+    //     )
+    //   })
+
+    //   it('displays the new username', () => {
+    //     expect(wrapper.find('div.display-username').text()).toEqual('@username')
+    //   })
+    // })
+  })
+})
diff --git a/admin/src/components/ContributionLinkForm.vue b/admin/src/components/ContributionLinkForm.vue
new file mode 100644
index 000000000..a159d33d3
--- /dev/null
+++ b/admin/src/components/ContributionLinkForm.vue
@@ -0,0 +1,218 @@
+<template>
+  <div class="contribution-link-form">
+    <div v-if="updateData" class="text-light bg-info p-3">
+      {{ updateData }}
+    </div>
+    <b-form class="m-5" @submit.prevent="onSubmit" ref="contributionLinkForm">
+      <!-- Date -->
+      <b-row>
+        <b-col>
+          <b-form-group :label="$t('contributionLink.validFrom')">
+            <b-form-datepicker
+              v-model="form.validFrom"
+              size="lg"
+              :min="min"
+              class="mb-4 test-validFrom"
+              reset-value=""
+              :label-no-date-selected="$t('contributionLink.noDateSelected')"
+              required
+            ></b-form-datepicker>
+          </b-form-group>
+        </b-col>
+        <b-col>
+          <b-form-group :label="$t('contributionLink.validTo')">
+            <b-form-datepicker
+              v-model="form.validTo"
+              size="lg"
+              :min="form.validFrom ? form.validFrom : min"
+              class="mb-4 test-validTo"
+              reset-value=""
+              :label-no-date-selected="$t('contributionLink.noDateSelected')"
+              required
+            ></b-form-datepicker>
+          </b-form-group>
+        </b-col>
+      </b-row>
+
+      <!-- Name -->
+      <b-form-group :label="$t('contributionLink.name')">
+        <b-form-input
+          v-model="form.name"
+          size="lg"
+          type="text"
+          placeholder="Name"
+          required
+          maxlength="100"
+          class="test-name"
+        ></b-form-input>
+      </b-form-group>
+      <!-- Desc -->
+      <b-form-group :label="$t('contributionLink.memo')">
+        <b-form-textarea
+          v-model="form.memo"
+          size="lg"
+          :placeholder="$t('contributionLink.memo')"
+          required
+          maxlength="255"
+          class="test-memo"
+        ></b-form-textarea>
+      </b-form-group>
+      <!-- Amount -->
+      <b-form-group :label="$t('contributionLink.amount')">
+        <b-form-input
+          v-model="form.amount"
+          size="lg"
+          type="number"
+          placeholder="0"
+          required
+          class="test-amount"
+        ></b-form-input>
+      </b-form-group>
+      <b-collapse id="collapse-2">
+        <b-jumbotron>
+          <b-row class="mb-4">
+            <b-col>
+              <!-- Cycle -->
+              <label for="cycle">{{ $t('contributionLink.cycle') }}</label>
+              <b-form-select
+                v-model="form.cycle"
+                :options="cycle"
+                :disabled="disabled"
+                class="mb-3"
+                size="lg"
+              ></b-form-select>
+            </b-col>
+            <b-col>
+              <!-- maxPerCycle -->
+              <label for="maxPerCycle">{{ $t('contributionLink.maxPerCycle') }}</label>
+              <b-form-select
+                v-model="form.maxPerCycle"
+                :options="maxPerCycle"
+                :disabled="disabled"
+                class="mb-3"
+                size="lg"
+              ></b-form-select>
+            </b-col>
+          </b-row>
+
+          <!-- Max amount -->
+          <b-form-group :label="$t('contributionLink.maximumAmount')">
+            <b-form-input
+              v-model="form.maxAmountPerMonth"
+              size="lg"
+              :disabled="disabled"
+              type="number"
+              placeholder="0"
+            ></b-form-input>
+          </b-form-group>
+        </b-jumbotron>
+      </b-collapse>
+      <div class="mt-6">
+        <b-button type="submit" variant="primary">{{ $t('contributionLink.create') }}</b-button>
+        <b-button type="reset" variant="danger" @click.prevent="onReset">
+          {{ $t('contributionLink.clear') }}
+        </b-button>
+      </div>
+    </b-form>
+  </div>
+</template>
+<script>
+import { createContributionLink } from '@/graphql/createContributionLink.js'
+export default {
+  name: 'ContributionLinkForm',
+  props: {
+    contributionLinkData: {
+      type: Object,
+      default() {
+        return {}
+      },
+    },
+  },
+  data() {
+    return {
+      form: {
+        name: null,
+        memo: null,
+        amount: null,
+        validFrom: null,
+        validTo: null,
+        cycle: 'ONCE',
+        maxPerCycle: 1,
+        maxAmountPerMonth: '0',
+      },
+      min: new Date(),
+      cycle: [
+        { value: 'ONCE', text: this.$t('contributionLink.options.cycle.once') },
+        { value: 'hourly', text: this.$t('contributionLink.options.cycle.hourly') },
+        { value: 'daily', text: this.$t('contributionLink.options.cycle.daily') },
+        { value: 'weekly', text: this.$t('contributionLink.options.cycle.weekly') },
+        { value: 'monthly', text: this.$t('contributionLink.options.cycle.monthly') },
+        { value: 'yearly', text: this.$t('contributionLink.options.cycle.yearly') },
+      ],
+      maxPerCycle: [
+        { value: '1', text: '1 x' },
+        { value: '2', text: '2 x' },
+        { value: '3', text: '3 x' },
+        { value: '4', text: '4 x' },
+        { value: '5', text: '5 x' },
+      ],
+    }
+  },
+  methods: {
+    onSubmit() {
+      if (this.form.validFrom === null)
+        return this.toastError(this.$t('contributionLink.noStartDate'))
+      if (this.form.validTo === null) return this.toastError(this.$t('contributionLink.noEndDate'))
+      // alert(JSON.stringify(this.form))
+      this.$apollo
+        .mutate({
+          mutation: createContributionLink,
+          variables: {
+            validFrom: this.form.validFrom,
+            validTo: this.form.validTo,
+            name: this.form.name,
+            amount: this.form.amount,
+            memo: this.form.memo,
+            cycle: this.form.cycle,
+            maxPerCycle: this.form.maxPerCycle,
+            maxAmountPerMonth: this.form.maxAmountPerMonth,
+          },
+        })
+        .then((result) => {
+          this.link = result.data.createContributionLink.link
+          this.toastSuccess(this.link)
+          this.onReset()
+        })
+        .catch((error) => {
+          this.toastError(error.message)
+        })
+    },
+    onReset() {
+      this.$refs.contributionLinkForm.reset()
+      this.form.validFrom = null
+      this.form.validTo = null
+    },
+  },
+  computed: {
+    updateData() {
+      return this.contributionLinkData
+    },
+    disabled() {
+      if (this.form.cycle === 'ONCE') return true
+      return false
+    },
+  },
+  watch: {
+    contributionLinkData() {
+      this.form.name = this.contributionLinkData.name
+      this.form.memo = this.contributionLinkData.memo
+      this.form.amount = this.contributionLinkData.amount
+      this.form.validFrom = this.contributionLinkData.validFrom
+      this.form.validTo = this.contributionLinkData.validTo
+      this.form.cycle = this.contributionLinkData.cycle
+      this.form.maxPerCycle = this.contributionLinkData.maxPerCycle
+      this.form.maxAmountPerMonth = this.contributionLinkData.maxAmountPerMonth
+    },
+  },
+}
+</script>
diff --git a/admin/src/components/ContributionLinkList.spec.js b/admin/src/components/ContributionLinkList.spec.js
new file mode 100644
index 000000000..0b9d131bd
--- /dev/null
+++ b/admin/src/components/ContributionLinkList.spec.js
@@ -0,0 +1,147 @@
+import { mount } from '@vue/test-utils'
+import ContributionLinkList from './ContributionLinkList.vue'
+import { toastSuccessSpy, toastErrorSpy } from '../../test/testSetup'
+// import { deleteContributionLink } from '../graphql/deleteContributionLink'
+
+const localVue = global.localVue
+
+const mockAPIcall = jest.fn()
+
+const mocks = {
+  $t: jest.fn((t) => t),
+  $apollo: {
+    mutate: mockAPIcall,
+  },
+}
+
+const propsData = {
+  items: [
+    {
+      id: 1,
+      name: 'Meditation',
+      memo: 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut l',
+      amount: '200',
+      validFrom: '2022-04-01',
+      validTo: '2022-08-01',
+      cycle: 'täglich',
+      maxPerCycle: '3',
+      maxAmountPerMonth: 0,
+      link: 'https://localhost/redeem/CL-1a2345678',
+    },
+  ],
+}
+
+describe('ContributionLinkList', () => {
+  let wrapper
+
+  const Wrapper = () => {
+    return mount(ContributionLinkList, { localVue, mocks, propsData })
+  }
+
+  describe('mount', () => {
+    beforeEach(() => {
+      wrapper = Wrapper()
+    })
+
+    it('renders the Div Element ".contribution-link-list"', () => {
+      expect(wrapper.find('div.contribution-link-list').exists()).toBe(true)
+    })
+
+    it('renders table with contribution link', () => {
+      expect(wrapper.findAll('table').at(0).findAll('tbody > tr').at(0).text()).toContain(
+        'Meditation',
+      )
+    })
+
+    describe('edit contribution link', () => {
+      beforeEach(() => {
+        wrapper.vm.editContributionLink()
+      })
+
+      it('emits editContributionLinkData', async () => {
+        expect(wrapper.vm.$emit('editContributionLinkData')).toBeTruthy()
+      })
+    })
+
+    describe('delete contribution link', () => {
+      let spy
+
+      beforeEach(async () => {
+        jest.clearAllMocks()
+        wrapper.vm.deleteContributionLink()
+      })
+
+      describe('with success', () => {
+        beforeEach(async () => {
+          spy = jest.spyOn(wrapper.vm.$bvModal, 'msgBoxConfirm')
+          spy.mockImplementation(() => Promise.resolve('some value'))
+          mockAPIcall.mockResolvedValue()
+          await wrapper.find('.test-delete-link').trigger('click')
+        })
+
+        it('opens the modal ', () => {
+          expect(spy).toBeCalled()
+        })
+
+        it.skip('calls the API', () => {
+          // expect(mockAPIcall).toBeCalledWith(
+          //   expect.objectContaining({
+          //     mutation: deleteContributionLink,
+          //     variables: {
+          //       id: 1,
+          //     },
+          //   }),
+          // )
+        })
+
+        it('toasts a success message', () => {
+          expect(toastSuccessSpy).toBeCalledWith('TODO: request message deleted ')
+        })
+      })
+
+      describe('with error', () => {
+        beforeEach(async () => {
+          spy = jest.spyOn(wrapper.vm.$bvModal, 'msgBoxConfirm')
+          spy.mockImplementation(() => Promise.resolve('some value'))
+          mockAPIcall.mockRejectedValue({ message: 'Something went wrong :(' })
+          await wrapper.find('.test-delete-link').trigger('click')
+        })
+
+        it('toasts an error message', () => {
+          expect(toastErrorSpy).toBeCalledWith('Something went wrong :(')
+        })
+      })
+
+      describe('cancel delete', () => {
+        beforeEach(async () => {
+          spy = jest.spyOn(wrapper.vm.$bvModal, 'msgBoxConfirm')
+          spy.mockImplementation(() => Promise.resolve(false))
+          mockAPIcall.mockResolvedValue()
+          await wrapper.find('.test-delete-link').trigger('click')
+        })
+
+        it('does not call the API', () => {
+          expect(mockAPIcall).not.toBeCalled()
+        })
+      })
+    })
+
+    describe('onClick showButton', () => {
+      it('modelData contains contribution link', () => {
+        wrapper.find('button.test-show').trigger('click')
+        expect(wrapper.vm.modalData).toEqual({
+          amount: '200',
+          cycle: 'täglich',
+          id: 1,
+          link: 'https://localhost/redeem/CL-1a2345678',
+          maxAmountPerMonth: 0,
+          maxPerCycle: '3',
+          memo: 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut l',
+          name: 'Meditation',
+          validFrom: '2022-04-01',
+          validTo: '2022-08-01',
+        })
+      })
+    })
+  })
+})
diff --git a/admin/src/components/ContributionLinkList.vue b/admin/src/components/ContributionLinkList.vue
new file mode 100644
index 000000000..518d7d57e
--- /dev/null
+++ b/admin/src/components/ContributionLinkList.vue
@@ -0,0 +1,106 @@
+<template>
+  <div class="contribution-link-list">
+    <b-table striped hover :items="items" :fields="fields">
+      <template #cell(delete)>
+        <b-button
+          variant="danger"
+          size="md"
+          class="mr-2 test-delete-link"
+          @click="deleteContributionLink"
+        >
+          <b-icon icon="trash" variant="light"></b-icon>
+        </b-button>
+      </template>
+      <template #cell(edit)="data">
+        <b-button variant="success" size="md" class="mr-2" @click="editContributionLink(data.item)">
+          <b-icon icon="pencil" variant="light"></b-icon>
+        </b-button>
+      </template>
+      <template #cell(show)="data">
+        <b-button
+          variant="info"
+          size="md"
+          class="mr-2 test-show"
+          @click="showContributionLink(data.item)"
+        >
+          <b-icon icon="eye" variant="light"></b-icon>
+        </b-button>
+      </template>
+    </b-table>
+
+    <b-modal ref="my-modal" ok-only hide-header-close>
+      <b-card header-tag="header" footer-tag="footer">
+        <template #header>
+          <h6 class="mb-0">{{ modalData ? modalData.name : '' }}</h6>
+        </template>
+        <b-card-text>
+          {{ modalData }}
+          <figure-qr-code :link="modalData ? modalData.link : ''" />
+        </b-card-text>
+        <template #footer>
+          <em>{{ modalData ? modalData.link : '' }}</em>
+        </template>
+      </b-card>
+    </b-modal>
+  </div>
+</template>
+<script>
+import { deleteContributionLink } from '@/graphql/deleteContributionLink.js'
+import FigureQrCode from './FigureQrCode.vue'
+
+export default {
+  name: 'ContributionLinkList',
+  components: {
+    FigureQrCode,
+  },
+  props: {
+    items: { type: Array, required: true },
+  },
+  data() {
+    return {
+      fields: [
+        'name',
+        'memo',
+        'amount',
+        { key: 'cycle', label: this.$t('contributionLink.cycle') },
+        { key: 'maxPerCycle', label: this.$t('contributionLink.maxPerCycle') },
+        { key: 'validFrom', label: this.$t('contributionLink.validFrom') },
+        { key: 'validTo', label: this.$t('contributionLink.validTo') },
+        'delete',
+        'edit',
+        'show',
+      ],
+      modalData: null,
+      modalDataLink: null,
+    }
+  },
+  methods: {
+    deleteContributionLink() {
+      this.$bvModal.msgBoxConfirm(this.$t('contributionLink.deleteNow')).then(async (value) => {
+        if (value)
+          await this.$apollo
+            .mutate({
+              mutation: deleteContributionLink,
+              variables: {
+                id: this.id,
+              },
+            })
+            .then(() => {
+              this.toastSuccess('TODO: request message deleted ')
+            })
+            .catch((err) => {
+              this.toastError(err.message)
+            })
+      })
+    },
+    editContributionLink(row) {
+      this.$emit('editContributionLinkData', row)
+    },
+
+    showContributionLink(row) {
+      this.modalData = row
+      this.$refs['my-modal'].show()
+    },
+  },
+}
+</script>
diff --git a/admin/src/components/CreationFormular.spec.js b/admin/src/components/CreationFormular.spec.js
index 08ec71bdc..6e4c1dc6e 100644
--- a/admin/src/components/CreationFormular.spec.js
+++ b/admin/src/components/CreationFormular.spec.js
@@ -1,14 +1,14 @@
 import { mount } from '@vue/test-utils'
 import CreationFormular from './CreationFormular.vue'
-import { createPendingCreation } from '../graphql/createPendingCreation'
-import { createPendingCreations } from '../graphql/createPendingCreations'
+import { adminCreateContribution } from '../graphql/adminCreateContribution'
+import { adminCreateContributions } from '../graphql/adminCreateContributions'
 import { toastErrorSpy, toastSuccessSpy } from '../../test/testSetup'
 
 const localVue = global.localVue
 
 const apolloMutateMock = jest.fn().mockResolvedValue({
   data: {
-    createPendingCreation: [0, 0, 0],
+    adminCreateContribution: [0, 0, 0],
   },
 })
 const stateCommitMock = jest.fn()
@@ -110,7 +110,7 @@ describe('CreationFormular', () => {
             it('sends ... to apollo', () => {
               expect(apolloMutateMock).toBeCalledWith(
                 expect.objectContaining({
-                  mutation: createPendingCreation,
+                  mutation: adminCreateContribution,
                   variables: {
                     email: 'benjamin@bluemchen.de',
                     creationDate: getCreationDate(2),
@@ -334,10 +334,10 @@ describe('CreationFormular', () => {
           jest.clearAllMocks()
           apolloMutateMock.mockResolvedValue({
             data: {
-              createPendingCreations: {
+              adminCreateContributions: {
                 success: true,
-                successfulCreation: ['bob@baumeister.de', 'bibi@bloxberg.de'],
-                failedCreation: [],
+                successfulContribution: ['bob@baumeister.de', 'bibi@bloxberg.de'],
+                failedContribution: [],
               },
             },
           })
@@ -355,7 +355,7 @@ describe('CreationFormular', () => {
         it('calls the API', () => {
           expect(apolloMutateMock).toBeCalledWith(
             expect.objectContaining({
-              mutation: createPendingCreations,
+              mutation: adminCreateContributions,
               variables: {
                 pendingCreations: [
                   {
@@ -390,10 +390,10 @@ describe('CreationFormular', () => {
           jest.clearAllMocks()
           apolloMutateMock.mockResolvedValue({
             data: {
-              createPendingCreations: {
+              adminCreateContributions: {
                 success: true,
-                successfulCreation: [],
-                failedCreation: ['bob@baumeister.de', 'bibi@bloxberg.de'],
+                successfulContribution: [],
+                failedContribution: ['bob@baumeister.de', 'bibi@bloxberg.de'],
               },
             },
           })
diff --git a/admin/src/components/CreationFormular.vue b/admin/src/components/CreationFormular.vue
index cdcd6ef1d..2201838de 100644
--- a/admin/src/components/CreationFormular.vue
+++ b/admin/src/components/CreationFormular.vue
@@ -85,8 +85,8 @@
   </div>
 </template>
 <script>
-import { createPendingCreation } from '../graphql/createPendingCreation'
-import { createPendingCreations } from '../graphql/createPendingCreations'
+import { adminCreateContribution } from '../graphql/adminCreateContribution'
+import { adminCreateContributions } from '../graphql/adminCreateContributions'
 import { creationMonths } from '../mixins/creationMonths'
 export default {
   name: 'CreationFormular',
@@ -158,25 +158,25 @@ export default {
         })
         this.$apollo
           .mutate({
-            mutation: createPendingCreations,
+            mutation: adminCreateContributions,
             variables: {
               pendingCreations: submitObj,
             },
             fetchPolicy: 'no-cache',
           })
           .then((result) => {
-            const failedCreations = []
+            const failedContributions = []
             this.$store.commit(
               'openCreationsPlus',
-              result.data.createPendingCreations.successfulCreation.length,
+              result.data.adminCreateContributions.successfulContribution.length,
             )
-            if (result.data.createPendingCreations.failedCreation.length > 0) {
-              result.data.createPendingCreations.failedCreation.forEach((email) => {
-                failedCreations.push(email)
+            if (result.data.adminCreateContributions.failedContribution.length > 0) {
+              result.data.adminCreateContributions.failedContribution.forEach((email) => {
+                failedContributions.push(email)
               })
             }
             this.$emit('remove-all-bookmark')
-            this.$emit('toast-failed-creations', failedCreations)
+            this.$emit('toast-failed-creations', failedContributions)
           })
           .catch((error) => {
             this.toastError(error.message)
@@ -190,11 +190,11 @@ export default {
         }
         this.$apollo
           .mutate({
-            mutation: createPendingCreation,
+            mutation: adminCreateContribution,
             variables: submitObj,
           })
           .then((result) => {
-            this.$emit('update-user-data', this.item, result.data.createPendingCreation)
+            this.$emit('update-user-data', this.item, result.data.adminCreateContribution)
             this.$store.commit('openCreationsPlus', 1)
             this.toastSuccess(
               this.$t('creation_form.toasted', {
diff --git a/admin/src/components/DeletedUserFormular.spec.js b/admin/src/components/DeletedUserFormular.spec.js
index 5c41831e5..e6a2c94a6 100644
--- a/admin/src/components/DeletedUserFormular.spec.js
+++ b/admin/src/components/DeletedUserFormular.spec.js
@@ -47,200 +47,200 @@ describe('DeletedUserFormular', () => {
     })
 
     it('has a DIV element with the class.delete-user-formular', () => {
-      expect(wrapper.find('.deleted-user-formular').exists()).toBeTruthy()
-    })
-  })
-
-  describe('delete self', () => {
-    beforeEach(() => {
-      wrapper.setProps({
-        item: {
-          userId: 0,
-        },
-      })
+      expect(wrapper.find('.deleted-user-formular').exists()).toBe(true)
     })
 
-    it('shows a text that you cannot delete yourself', () => {
-      expect(wrapper.text()).toBe('removeNotSelf')
-    })
-  })
-
-  describe('delete other user', () => {
-    beforeEach(() => {
-      wrapper.setProps({
-        item: {
-          userId: 1,
-          deletedAt: null,
-        },
-      })
-    })
-
-    it('has a checkbox', () => {
-      expect(wrapper.find('input[type="checkbox"]').exists()).toBeTruthy()
-    })
-
-    it('shows the text "delete_user"', () => {
-      expect(wrapper.text()).toBe('delete_user')
-    })
-
-    describe('click on checkbox', () => {
-      beforeEach(async () => {
-        await wrapper.find('input[type="checkbox"]').setChecked()
-      })
-
-      it('has a confirmation button', () => {
-        expect(wrapper.find('button').exists()).toBeTruthy()
-      })
-
-      it('has the button text "delete_user"', () => {
-        expect(wrapper.find('button').text()).toBe('delete_user')
-      })
-
-      describe('confirm delete with success', () => {
-        beforeEach(async () => {
-          await wrapper.find('button').trigger('click')
-        })
-
-        it('calls the API', () => {
-          expect(apolloMutateMock).toBeCalledWith(
-            expect.objectContaining({
-              mutation: deleteUser,
-              variables: {
-                userId: 1,
-              },
-            }),
-          )
-        })
-
-        it('emits update deleted At', () => {
-          expect(wrapper.emitted('updateDeletedAt')).toEqual(
-            expect.arrayContaining([
-              expect.arrayContaining([
-                {
-                  userId: 1,
-                  deletedAt: date,
-                },
-              ]),
-            ]),
-          )
-        })
-
-        it('unchecks the checkbox', () => {
-          expect(wrapper.find('input').attributes('checked')).toBe(undefined)
-        })
-      })
-
-      describe('confirm delete with error', () => {
-        beforeEach(async () => {
-          apolloMutateMock.mockRejectedValue({ message: 'Oh no!' })
-          await wrapper.find('button').trigger('click')
-        })
-
-        it('toasts an error message', () => {
-          expect(toastErrorSpy).toBeCalledWith('Oh no!')
-        })
-      })
-
-      describe('click on checkbox again', () => {
-        beforeEach(async () => {
-          await wrapper.find('input[type="checkbox"]').setChecked(false)
-        })
-
-        it('has no confirmation button anymore', () => {
-          expect(wrapper.find('button').exists()).toBeFalsy()
-        })
-      })
-    })
-  })
-
-  describe('recover user', () => {
-    beforeEach(() => {
-      wrapper.setProps({
-        item: {
-          userId: 1,
-          deletedAt: date,
-        },
-      })
-    })
-
-    it('has a checkbox', () => {
-      expect(wrapper.find('input[type="checkbox"]').exists()).toBeTruthy()
-    })
-
-    it('shows the text "undelete_user"', () => {
-      expect(wrapper.text()).toBe('undelete_user')
-    })
-
-    describe('click on checkbox', () => {
-      beforeEach(async () => {
-        apolloMutateMock.mockResolvedValue({
-          data: {
-            unDeleteUser: null,
+    describe('delete self', () => {
+      beforeEach(() => {
+        wrapper.setProps({
+          item: {
+            userId: 0,
           },
         })
-        await wrapper.find('input[type="checkbox"]').setChecked()
       })
 
-      it('has a confirmation button', () => {
-        expect(wrapper.find('button').exists()).toBeTruthy()
+      it('shows a text that you cannot delete yourself', () => {
+        expect(wrapper.text()).toBe('removeNotSelf')
+      })
+    })
+
+    describe('delete other user', () => {
+      beforeEach(() => {
+        wrapper.setProps({
+          item: {
+            userId: 1,
+            deletedAt: null,
+          },
+        })
       })
 
-      it('has the button text "undelete_user"', () => {
-        expect(wrapper.find('button').text()).toBe('undelete_user')
+      it('has a checkbox', () => {
+        expect(wrapper.find('input[type="checkbox"]').exists()).toBe(true)
       })
 
-      describe('confirm recover with success', () => {
+      it('shows the text "delete_user"', () => {
+        expect(wrapper.text()).toBe('delete_user')
+      })
+
+      describe('click on checkbox', () => {
         beforeEach(async () => {
-          await wrapper.find('button').trigger('click')
+          await wrapper.find('input[type="checkbox"]').setChecked()
         })
 
-        it('calls the API', () => {
-          expect(apolloMutateMock).toBeCalledWith(
-            expect.objectContaining({
-              mutation: unDeleteUser,
-              variables: {
-                userId: 1,
-              },
-            }),
-          )
+        it('has a confirmation button', () => {
+          expect(wrapper.find('button').exists()).toBe(true)
         })
 
-        it('emits update deleted At', () => {
-          expect(wrapper.emitted('updateDeletedAt')).toEqual(
-            expect.arrayContaining([
-              expect.arrayContaining([
-                {
+        it('has the button text "delete_user"', () => {
+          expect(wrapper.find('button').text()).toBe('delete_user')
+        })
+
+        describe('confirm delete with success', () => {
+          beforeEach(async () => {
+            await wrapper.find('button').trigger('click')
+          })
+
+          it('calls the API', () => {
+            expect(apolloMutateMock).toBeCalledWith(
+              expect.objectContaining({
+                mutation: deleteUser,
+                variables: {
                   userId: 1,
-                  deletedAt: null,
                 },
+              }),
+            )
+          })
+
+          it('emits update deleted At', () => {
+            expect(wrapper.emitted('updateDeletedAt')).toEqual(
+              expect.arrayContaining([
+                expect.arrayContaining([
+                  {
+                    userId: 1,
+                    deletedAt: date,
+                  },
+                ]),
               ]),
-            ]),
-          )
+            )
+          })
+
+          it('unchecks the checkbox', () => {
+            expect(wrapper.find('input').attributes('checked')).toBe(undefined)
+          })
         })
 
-        it('unchecks the checkbox', () => {
-          expect(wrapper.find('input').attributes('checked')).toBe(undefined)
+        describe('confirm delete with error', () => {
+          beforeEach(async () => {
+            apolloMutateMock.mockRejectedValue({ message: 'Oh no!' })
+            await wrapper.find('button').trigger('click')
+          })
+
+          it('toasts an error message', () => {
+            expect(toastErrorSpy).toBeCalledWith('Oh no!')
+          })
+        })
+
+        describe('click on checkbox again', () => {
+          beforeEach(async () => {
+            await wrapper.find('input[type="checkbox"]').setChecked(false)
+          })
+
+          it('has no confirmation button anymore', () => {
+            expect(wrapper.find('button').exists()).toBe(false)
+          })
+        })
+      })
+    })
+
+    describe('recover user', () => {
+      beforeEach(() => {
+        wrapper.setProps({
+          item: {
+            userId: 1,
+            deletedAt: date,
+          },
         })
       })
 
-      describe('confirm recover with error', () => {
-        beforeEach(async () => {
-          apolloMutateMock.mockRejectedValue({ message: 'Oh no!' })
-          await wrapper.find('button').trigger('click')
-        })
-
-        it('toasts an error message', () => {
-          expect(toastErrorSpy).toBeCalledWith('Oh no!')
-        })
+      it('has a checkbox', () => {
+        expect(wrapper.find('input[type="checkbox"]').exists()).toBe(true)
       })
 
-      describe('click on checkbox again', () => {
+      it('shows the text "undelete_user"', () => {
+        expect(wrapper.text()).toBe('undelete_user')
+      })
+
+      describe('click on checkbox', () => {
         beforeEach(async () => {
-          await wrapper.find('input[type="checkbox"]').setChecked(false)
+          apolloMutateMock.mockResolvedValue({
+            data: {
+              unDeleteUser: null,
+            },
+          })
+          await wrapper.find('input[type="checkbox"]').setChecked()
         })
 
-        it('has no confirmation button anymore', () => {
-          expect(wrapper.find('button').exists()).toBeFalsy()
+        it('has a confirmation button', () => {
+          expect(wrapper.find('button').exists()).toBe(true)
+        })
+
+        it('has the button text "undelete_user"', () => {
+          expect(wrapper.find('button').text()).toBe('undelete_user')
+        })
+
+        describe('confirm recover with success', () => {
+          beforeEach(async () => {
+            await wrapper.find('button').trigger('click')
+          })
+
+          it('calls the API', () => {
+            expect(apolloMutateMock).toBeCalledWith(
+              expect.objectContaining({
+                mutation: unDeleteUser,
+                variables: {
+                  userId: 1,
+                },
+              }),
+            )
+          })
+
+          it('emits update deleted At', () => {
+            expect(wrapper.emitted('updateDeletedAt')).toEqual(
+              expect.arrayContaining([
+                expect.arrayContaining([
+                  {
+                    userId: 1,
+                    deletedAt: null,
+                  },
+                ]),
+              ]),
+            )
+          })
+
+          it('unchecks the checkbox', () => {
+            expect(wrapper.find('input').attributes('checked')).toBe(undefined)
+          })
+        })
+
+        describe('confirm recover with error', () => {
+          beforeEach(async () => {
+            apolloMutateMock.mockRejectedValue({ message: 'Oh no!' })
+            await wrapper.find('button').trigger('click')
+          })
+
+          it('toasts an error message', () => {
+            expect(toastErrorSpy).toBeCalledWith('Oh no!')
+          })
+        })
+
+        describe('click on checkbox again', () => {
+          beforeEach(async () => {
+            await wrapper.find('input[type="checkbox"]').setChecked(false)
+          })
+
+          it('has no confirmation button anymore', () => {
+            expect(wrapper.find('button').exists()).toBe(false)
+          })
         })
       })
     })
diff --git a/admin/src/components/DeletedUserFormular.vue b/admin/src/components/DeletedUserFormular.vue
index 03359d9f9..43a353ef4 100644
--- a/admin/src/components/DeletedUserFormular.vue
+++ b/admin/src/components/DeletedUserFormular.vue
@@ -28,6 +28,7 @@ export default {
   props: {
     item: {
       type: Object,
+      required: true,
     },
   },
   data() {
diff --git a/admin/src/components/EditCreationFormular.spec.js b/admin/src/components/EditCreationFormular.spec.js
index f39edad52..2ed3baa3b 100644
--- a/admin/src/components/EditCreationFormular.spec.js
+++ b/admin/src/components/EditCreationFormular.spec.js
@@ -6,7 +6,7 @@ const localVue = global.localVue
 
 const apolloMutateMock = jest.fn().mockResolvedValue({
   data: {
-    updatePendingCreation: {
+    adminUpdateContribution: {
       creation: [0, 0, 0],
       amount: 500,
       date: new Date(),
diff --git a/admin/src/components/EditCreationFormular.vue b/admin/src/components/EditCreationFormular.vue
index fb30f2b77..0e887ad3d 100644
--- a/admin/src/components/EditCreationFormular.vue
+++ b/admin/src/components/EditCreationFormular.vue
@@ -73,7 +73,7 @@
   </div>
 </template>
 <script>
-import { updatePendingCreation } from '../graphql/updatePendingCreation'
+import { adminUpdateContribution } from '../graphql/adminUpdateContribution'
 import { creationMonths } from '../mixins/creationMonths'
 
 export default {
@@ -103,7 +103,7 @@ export default {
   data() {
     return {
       text: !this.creationUserData.memo ? '' : this.creationUserData.memo,
-      value: !this.creationUserData.amount ? 0 : this.creationUserData.amount,
+      value: !this.creationUserData.amount ? 0 : Number(this.creationUserData.amount),
       rangeMin: 0,
       rangeMax: 1000,
       selected: '',
@@ -113,7 +113,7 @@ export default {
     submitCreation() {
       this.$apollo
         .mutate({
-          mutation: updatePendingCreation,
+          mutation: adminUpdateContribution,
           variables: {
             id: this.item.id,
             email: this.item.email,
@@ -123,11 +123,11 @@ export default {
           },
         })
         .then((result) => {
-          this.$emit('update-user-data', this.item, result.data.updatePendingCreation.creation)
+          this.$emit('update-user-data', this.item, result.data.adminUpdateContribution.creation)
           this.$emit('update-creation-data', {
-            amount: Number(result.data.updatePendingCreation.amount),
-            date: result.data.updatePendingCreation.date,
-            memo: result.data.updatePendingCreation.memo,
+            amount: Number(result.data.adminUpdateContribution.amount),
+            date: result.data.adminUpdateContribution.date,
+            memo: result.data.adminUpdateContribution.memo,
             row: this.row,
           })
           this.toastSuccess(
@@ -155,7 +155,7 @@ export default {
       const month = this.$d(new Date(this.creationUserData.date), 'month')
       const index = this.radioOptions.findIndex((obj) => obj.item.short === month)
       this.selected = this.radioOptions[index].item
-      this.rangeMax = this.creation[index] + this.creationUserData.amount
+      this.rangeMax = Number(this.creation[index]) + Number(this.creationUserData.amount)
     }
   },
 }
diff --git a/admin/src/components/FigureQrCode.spec.js b/admin/src/components/FigureQrCode.spec.js
new file mode 100644
index 000000000..2c18a31a1
--- /dev/null
+++ b/admin/src/components/FigureQrCode.spec.js
@@ -0,0 +1,30 @@
+import { mount } from '@vue/test-utils'
+import FigureQrCode from './FigureQrCode.vue'
+
+const localVue = global.localVue
+
+const propsData = {
+  link: '',
+}
+
+describe('FigureQrCode', () => {
+  let wrapper
+
+  const Wrapper = () => {
+    return mount(FigureQrCode, { localVue, propsData })
+  }
+
+  describe('mount', () => {
+    beforeEach(() => {
+      wrapper = Wrapper()
+    })
+
+    it('renders the Div Element ".figure-qr-code"', () => {
+      expect(wrapper.find('div.figure-qr-code').exists()).toBe(true)
+    })
+
+    it('renders the QRCanvas Element ".canvas"', () => {
+      expect(wrapper.find('.canvas').exists()).toBe(true)
+    })
+  })
+})
diff --git a/admin/src/components/FigureQrCode.vue b/admin/src/components/FigureQrCode.vue
new file mode 100644
index 000000000..11a11d98c
--- /dev/null
+++ b/admin/src/components/FigureQrCode.vue
@@ -0,0 +1,56 @@
+<template>
+  <div class="figure-qr-code">
+    <div class="qrbox">
+      <q-r-canvas :options="options" class="canvas" />
+    </div>
+  </div>
+</template>
+<script>
+import { QRCanvas } from 'qrcanvas-vue'
+
+export default {
+  name: 'FigureQrCode',
+  components: {
+    QRCanvas,
+  },
+  props: {
+    link: { type: String, required: true },
+  },
+  data() {
+    return {
+      options: {
+        cellSize: 8,
+        correctLevel: 'H',
+        data: this.link,
+        logo: {
+          image: null,
+        },
+      },
+    }
+  },
+  created() {
+    const image = new Image()
+    image.src = 'img/gdd-coin.png'
+    image.onload = () => {
+      this.options = {
+        ...this.options,
+        logo: {
+          image,
+        },
+      }
+    }
+  },
+}
+</script>
+<style scoped>
+.qrbox {
+  padding: 20px;
+  background-color: rgb(255, 255, 255);
+}
+.canvas {
+  width: 90%;
+  max-width: 300px;
+  padding: 5px;
+  background-color: rgb(255, 255, 255);
+}
+</style>
diff --git a/admin/src/components/Tables/OpenCreationsTable.spec.js b/admin/src/components/Tables/OpenCreationsTable.spec.js
index 9ff348562..2eb149e4f 100644
--- a/admin/src/components/Tables/OpenCreationsTable.spec.js
+++ b/admin/src/components/Tables/OpenCreationsTable.spec.js
@@ -28,7 +28,7 @@ const propsData = {
       amount: 210,
       memo: 'Aktives Grundeinkommen für Januar 2022',
       date: '2022-01-01T00:00:00.000Z',
-      moderator: 1,
+      moderator: null,
       creation: [790, 1000, 1000],
       __typename: 'PendingCreation',
     },
@@ -66,9 +66,10 @@ const propsData = {
       },
     },
     { key: 'moderator', label: 'moderator' },
-    { key: 'edit_creation', label: 'edit' },
+    { key: 'editCreation', label: 'edit' },
     { key: 'confirm', label: 'save' },
   ],
+  toggleDetails: false,
 }
 
 const mocks = {
@@ -101,7 +102,7 @@ describe('OpenCreationsTable', () => {
     })
 
     it('has a DIV element with the class .open-creations-table', () => {
-      expect(wrapper.find('div.open-creations-table').exists()).toBeTruthy()
+      expect(wrapper.find('div.open-creations-table').exists()).toBe(true)
     })
 
     it('has a table with three rows', () => {
@@ -109,7 +110,11 @@ describe('OpenCreationsTable', () => {
     })
 
     it('find first button.bi-pencil-square for open EditCreationFormular ', () => {
-      expect(wrapper.findAll('tr').at(1).find('.bi-pencil-square').exists()).toBeTruthy()
+      expect(wrapper.findAll('tr').at(1).find('.bi-pencil-square').exists()).toBe(true)
+    })
+
+    it('has no button.bi-pencil-square for user contribution ', () => {
+      expect(wrapper.findAll('tr').at(2).find('.bi-pencil-square').exists()).toBe(false)
     })
 
     describe('show edit details', () => {
@@ -122,7 +127,15 @@ describe('OpenCreationsTable', () => {
       })
 
       it.skip('renders the component component-edit-creation-formular', () => {
-        expect(wrapper.find('div.component-edit-creation-formular').exists()).toBeTruthy()
+        expect(wrapper.find('div.component-edit-creation-formular').exists()).toBe(true)
+      })
+    })
+
+    describe('call updateUserData', () => {
+      it('user creations has updated data', async () => {
+        wrapper.vm.updateUserData(propsData.items[0], [444, 555, 666])
+        await wrapper.vm.$nextTick()
+        expect(wrapper.vm.items[0].creation).toEqual([444, 555, 666])
       })
     })
   })
diff --git a/admin/src/components/Tables/OpenCreationsTable.vue b/admin/src/components/Tables/OpenCreationsTable.vue
index d2e9669e6..3ebc81fba 100644
--- a/admin/src/components/Tables/OpenCreationsTable.vue
+++ b/admin/src/components/Tables/OpenCreationsTable.vue
@@ -11,8 +11,14 @@
           <b-icon icon="x" variant="light"></b-icon>
         </b-button>
       </template>
-      <template #cell(edit_creation)="row">
-        <b-button variant="info" size="md" @click="rowToggleDetails(row, 0)" class="mr-2">
+      <template #cell(editCreation)="row">
+        <b-button
+          v-if="row.item.moderator"
+          variant="info"
+          size="md"
+          @click="rowToggleDetails(row, 0)"
+          class="mr-2"
+        >
           <b-icon :icon="row.detailsShowing ? 'x' : 'pencil-square'" aria-label="Help"></b-icon>
         </b-button>
       </template>
@@ -70,12 +76,23 @@ export default {
       required: true,
     },
   },
+  data() {
+    return {
+      creationUserData: {
+        amount: null,
+        date: null,
+        memo: null,
+        moderator: null,
+      },
+    }
+  },
   methods: {
     updateCreationData(data) {
-      this.creationUserData.amount = data.amount
-      this.creationUserData.date = data.date
-      this.creationUserData.memo = data.memo
-      this.creationUserData.moderator = data.moderator
+      this.creationUserData = data
+      // this.creationUserData.amount = data.amount
+      // this.creationUserData.date = data.date
+      // this.creationUserData.memo = data.memo
+      // this.creationUserData.moderator = data.moderator
       data.row.toggleDetails()
     },
     updateUserData(rowItem, newCreation) {
diff --git a/admin/src/components/Tables/SearchUserTable.spec.js b/admin/src/components/Tables/SearchUserTable.spec.js
index eb87357cc..e9072e54b 100644
--- a/admin/src/components/Tables/SearchUserTable.spec.js
+++ b/admin/src/components/Tables/SearchUserTable.spec.js
@@ -1,8 +1,6 @@
 import { mount } from '@vue/test-utils'
 import SearchUserTable from './SearchUserTable.vue'
 
-const date = new Date()
-
 const localVue = global.localVue
 
 const apolloMutateMock = jest.fn().mockResolvedValue({})
@@ -96,16 +94,29 @@ describe('SearchUserTable', () => {
         await wrapper.findAll('tbody > tr').at(1).trigger('click')
       })
 
+      describe('isAdmin', () => {
+        beforeEach(async () => {
+          await wrapper.find('div.change-user-role-formular').vm.$emit('updateIsAdmin', {
+            userId: 1,
+            isAdmin: new Date(),
+          })
+        })
+
+        it('emits updateIsAdmin', () => {
+          expect(wrapper.emitted('updateIsAdmin')).toEqual([[1, expect.any(Date)]])
+        })
+      })
+
       describe('deleted at', () => {
         beforeEach(async () => {
           await wrapper.find('div.deleted-user-formular').vm.$emit('updateDeletedAt', {
             userId: 1,
-            deletedAt: date,
+            deletedAt: new Date(),
           })
         })
 
         it('emits updateDeletedAt', () => {
-          expect(wrapper.emitted('updateDeletedAt')).toEqual([[1, date]])
+          expect(wrapper.emitted('updateDeletedAt')).toEqual([[1, expect.any(Date)]])
         })
       })
 
diff --git a/admin/src/components/Tables/SearchUserTable.vue b/admin/src/components/Tables/SearchUserTable.vue
index 0be24a099..772160202 100644
--- a/admin/src/components/Tables/SearchUserTable.vue
+++ b/admin/src/components/Tables/SearchUserTable.vue
@@ -18,7 +18,7 @@
 
       <template #cell(status)="row">
         <div class="text-right">
-          <b-avatar v-if="row.item.deletedAt" class="mr-3" variant="light">
+          <b-avatar v-if="row.item.deletedAt" class="mr-3 test-deleted-icon" variant="light">
             <b-iconstack font-scale="2">
               <b-icon stacked icon="person" variant="info" scale="0.75"></b-icon>
               <b-icon stacked icon="slash-circle" variant="danger"></b-icon>
@@ -79,6 +79,9 @@
             <b-tab :title="$t('transactionlink.name')" :disabled="row.item.deletedAt !== null">
               <transaction-link-list v-if="!row.item.deletedAt" :userId="row.item.userId" />
             </b-tab>
+            <b-tab :title="$t('userRole.tabTitle')">
+              <change-user-role-formular :item="row.item" @updateIsAdmin="updateIsAdmin" />
+            </b-tab>
             <b-tab :title="$t('delete_user')">
               <deleted-user-formular :item="row.item" @updateDeletedAt="updateDeletedAt" />
             </b-tab>
@@ -93,6 +96,7 @@ import CreationFormular from '../CreationFormular.vue'
 import ConfirmRegisterMailFormular from '../ConfirmRegisterMailFormular.vue'
 import CreationTransactionList from '../CreationTransactionList.vue'
 import TransactionLinkList from '../TransactionLinkList.vue'
+import ChangeUserRoleFormular from '../ChangeUserRoleFormular.vue'
 import DeletedUserFormular from '../DeletedUserFormular.vue'
 
 export default {
@@ -102,6 +106,7 @@ export default {
     ConfirmRegisterMailFormular,
     CreationTransactionList,
     TransactionLinkList,
+    ChangeUserRoleFormular,
     DeletedUserFormular,
   },
   props: {
@@ -123,6 +128,9 @@ export default {
     updateUserData(rowItem, newCreation) {
       rowItem.creation = newCreation
     },
+    updateIsAdmin({ userId, isAdmin }) {
+      this.$emit('updateIsAdmin', userId, isAdmin)
+    },
     updateDeletedAt({ userId, deletedAt }) {
       this.$emit('updateDeletedAt', userId, deletedAt)
     },
diff --git a/admin/src/components/TransactionLinkList.vue b/admin/src/components/TransactionLinkList.vue
index 0289792a2..d850083cc 100644
--- a/admin/src/components/TransactionLinkList.vue
+++ b/admin/src/components/TransactionLinkList.vue
@@ -11,6 +11,7 @@
       :per-page="perPage"
       :total-rows="rows"
       align="center"
+      :hide-ellipsis="true"
     ></b-pagination>
   </div>
 </template>
diff --git a/admin/src/graphql/adminCreateContribution.js b/admin/src/graphql/adminCreateContribution.js
new file mode 100644
index 000000000..5ee409c67
--- /dev/null
+++ b/admin/src/graphql/adminCreateContribution.js
@@ -0,0 +1,12 @@
+import gql from 'graphql-tag'
+
+export const adminCreateContribution = gql`
+  mutation ($email: String!, $amount: Decimal!, $memo: String!, $creationDate: String!) {
+    adminCreateContribution(
+      email: $email
+      amount: $amount
+      memo: $memo
+      creationDate: $creationDate
+    )
+  }
+`
diff --git a/admin/src/graphql/adminCreateContributions.js b/admin/src/graphql/adminCreateContributions.js
new file mode 100644
index 000000000..20831975c
--- /dev/null
+++ b/admin/src/graphql/adminCreateContributions.js
@@ -0,0 +1,11 @@
+import gql from 'graphql-tag'
+
+export const adminCreateContributions = gql`
+  mutation ($pendingCreations: [AdminCreateContributionArgs!]!) {
+    adminCreateContributions(pendingCreations: $pendingCreations) {
+      success
+      successfulContribution
+      failedContribution
+    }
+  }
+`
diff --git a/admin/src/graphql/adminDeleteContribution.js b/admin/src/graphql/adminDeleteContribution.js
new file mode 100644
index 000000000..0aed494e1
--- /dev/null
+++ b/admin/src/graphql/adminDeleteContribution.js
@@ -0,0 +1,7 @@
+import gql from 'graphql-tag'
+
+export const adminDeleteContribution = gql`
+  mutation ($id: Int!) {
+    adminDeleteContribution(id: $id)
+  }
+`
diff --git a/admin/src/graphql/updatePendingCreation.js b/admin/src/graphql/adminUpdateContribution.js
similarity index 80%
rename from admin/src/graphql/updatePendingCreation.js
rename to admin/src/graphql/adminUpdateContribution.js
index f0775e68b..b7c834109 100644
--- a/admin/src/graphql/updatePendingCreation.js
+++ b/admin/src/graphql/adminUpdateContribution.js
@@ -1,8 +1,8 @@
 import gql from 'graphql-tag'
 
-export const updatePendingCreation = gql`
+export const adminUpdateContribution = gql`
   mutation ($id: Int!, $email: String!, $amount: Decimal!, $memo: String!, $creationDate: String!) {
-    updatePendingCreation(
+    adminUpdateContribution(
       id: $id
       email: $email
       amount: $amount
diff --git a/admin/src/graphql/confirmContribution.js b/admin/src/graphql/confirmContribution.js
new file mode 100644
index 000000000..7b5aa58cc
--- /dev/null
+++ b/admin/src/graphql/confirmContribution.js
@@ -0,0 +1,7 @@
+import gql from 'graphql-tag'
+
+export const confirmContribution = gql`
+  mutation ($id: Int!) {
+    confirmContribution(id: $id)
+  }
+`
diff --git a/admin/src/graphql/confirmPendingCreation.js b/admin/src/graphql/confirmPendingCreation.js
deleted file mode 100644
index df72cc04d..000000000
--- a/admin/src/graphql/confirmPendingCreation.js
+++ /dev/null
@@ -1,7 +0,0 @@
-import gql from 'graphql-tag'
-
-export const confirmPendingCreation = gql`
-  mutation ($id: Int!) {
-    confirmPendingCreation(id: $id)
-  }
-`
diff --git a/admin/src/graphql/createContributionLink.js b/admin/src/graphql/createContributionLink.js
new file mode 100644
index 000000000..fb6728243
--- /dev/null
+++ b/admin/src/graphql/createContributionLink.js
@@ -0,0 +1,27 @@
+import gql from 'graphql-tag'
+
+export const createContributionLink = gql`
+  mutation (
+    $validFrom: String!
+    $validTo: String!
+    $name: String!
+    $amount: Decimal!
+    $memo: String!
+    $cycle: String!
+    $maxPerCycle: Int! = 1
+    $maxAmountPerMonth: Decimal
+  ) {
+    createContributionLink(
+      validFrom: $validFrom
+      validTo: $validTo
+      name: $name
+      amount: $amount
+      memo: $memo
+      cycle: $cycle
+      maxPerCycle: $maxPerCycle
+      maxAmountPerMonth: $maxAmountPerMonth
+    ) {
+      link
+    }
+  }
+`
diff --git a/admin/src/graphql/createPendingCreation.js b/admin/src/graphql/createPendingCreation.js
deleted file mode 100644
index 9301ea489..000000000
--- a/admin/src/graphql/createPendingCreation.js
+++ /dev/null
@@ -1,7 +0,0 @@
-import gql from 'graphql-tag'
-
-export const createPendingCreation = gql`
-  mutation ($email: String!, $amount: Decimal!, $memo: String!, $creationDate: String!) {
-    createPendingCreation(email: $email, amount: $amount, memo: $memo, creationDate: $creationDate)
-  }
-`
diff --git a/admin/src/graphql/createPendingCreations.js b/admin/src/graphql/createPendingCreations.js
deleted file mode 100644
index 95d60bc9a..000000000
--- a/admin/src/graphql/createPendingCreations.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import gql from 'graphql-tag'
-
-export const createPendingCreations = gql`
-  mutation ($pendingCreations: [CreatePendingCreationArgs!]!) {
-    createPendingCreations(pendingCreations: $pendingCreations) {
-      success
-      successfulCreation
-      failedCreation
-    }
-  }
-`
diff --git a/admin/src/graphql/deleteContributionLink.js b/admin/src/graphql/deleteContributionLink.js
new file mode 100644
index 000000000..d0a938627
--- /dev/null
+++ b/admin/src/graphql/deleteContributionLink.js
@@ -0,0 +1,7 @@
+import gql from 'graphql-tag'
+
+export const deleteContributionLink = gql`
+  mutation ($id: Int!) {
+    deleteContributionLink(id: $id)
+  }
+`
diff --git a/admin/src/graphql/deletePendingCreation.js b/admin/src/graphql/deletePendingCreation.js
deleted file mode 100644
index edf45fe74..000000000
--- a/admin/src/graphql/deletePendingCreation.js
+++ /dev/null
@@ -1,7 +0,0 @@
-import gql from 'graphql-tag'
-
-export const deletePendingCreation = gql`
-  mutation ($id: Int!) {
-    deletePendingCreation(id: $id)
-  }
-`
diff --git a/admin/src/graphql/listContributionLinks.js b/admin/src/graphql/listContributionLinks.js
new file mode 100644
index 000000000..7ce4b04e6
--- /dev/null
+++ b/admin/src/graphql/listContributionLinks.js
@@ -0,0 +1,23 @@
+import gql from 'graphql-tag'
+
+export const listContributionLinks = gql`
+  query ($currentPage: Int = 1, $pageSize: Int = 25, $order: Order = DESC) {
+    listContributionLinks(currentPage: $currentPage, pageSize: $pageSize, order: $order) {
+      links {
+        id
+        amount
+        name
+        memo
+        code
+        link
+        createdAt
+        validFrom
+        validTo
+        maxAmountPerMonth
+        cycle
+        maxPerCycle
+      }
+      count
+    }
+  }
+`
diff --git a/admin/src/graphql/getPendingCreations.js b/admin/src/graphql/listUnconfirmedContributions.js
similarity index 67%
rename from admin/src/graphql/getPendingCreations.js
rename to admin/src/graphql/listUnconfirmedContributions.js
index 86b1965c8..c31347468 100644
--- a/admin/src/graphql/getPendingCreations.js
+++ b/admin/src/graphql/listUnconfirmedContributions.js
@@ -1,8 +1,8 @@
 import gql from 'graphql-tag'
 
-export const getPendingCreations = gql`
+export const listUnconfirmedContributions = gql`
   query {
-    getPendingCreations {
+    listUnconfirmedContributions {
       id
       firstName
       lastName
diff --git a/admin/src/graphql/searchUsers.js b/admin/src/graphql/searchUsers.js
index cc7f83b1c..3e33fe96b 100644
--- a/admin/src/graphql/searchUsers.js
+++ b/admin/src/graphql/searchUsers.js
@@ -19,6 +19,7 @@ export const searchUsers = gql`
         hasElopage
         emailConfirmationSend
         deletedAt
+        isAdmin
       }
     }
   }
diff --git a/admin/src/graphql/setUserRole.js b/admin/src/graphql/setUserRole.js
new file mode 100644
index 000000000..8cdcab396
--- /dev/null
+++ b/admin/src/graphql/setUserRole.js
@@ -0,0 +1,7 @@
+import gql from 'graphql-tag'
+
+export const setUserRole = gql`
+  mutation ($userId: Int!, $isAdmin: Boolean!) {
+    setUserRole(userId: $userId, isAdmin: $isAdmin)
+  }
+`
diff --git a/admin/src/graphql/showContributionLink.js b/admin/src/graphql/showContributionLink.js
new file mode 100644
index 000000000..8042db6b5
--- /dev/null
+++ b/admin/src/graphql/showContributionLink.js
@@ -0,0 +1,18 @@
+import gql from 'graphql-tag'
+
+export const showContributionLink = gql`
+  query ($id: Int!) {
+    showContributionLink {
+      id
+      validFrom
+      validTo
+      name
+      memo
+      amount
+      cycle
+      maxPerCycle
+      maxAmountPerMonth
+      code
+    }
+  }
+`
diff --git a/admin/src/locales/de.json b/admin/src/locales/de.json
index b667a1ada..3d88e0257 100644
--- a/admin/src/locales/de.json
+++ b/admin/src/locales/de.json
@@ -1,11 +1,41 @@
 {
   "all_emails": "Alle Nutzer",
   "back": "zurück",
+  "contributionLink": {
+    "amount": "Betrag",
+    "clear": "Löschen",
+    "contributionLinks": "Beitragslinks",
+    "create": "Anlegen",
+    "cycle": "Zyklus",
+    "deleteNow": "Automatische Creations wirklich löschen?",
+    "maximumAmount": "maximaler Betrag",
+    "maxPerCycle": "Wiederholungen",
+    "memo": "Nachricht",
+    "name": "Name",
+    "newContributionLink": "Neuer Beitragslink",
+    "noContributionLinks": "Es sind keine Beitragslinks angelegt.",
+    "noDateSelected": "Kein Datum ausgewählt",
+    "noEndDate": "Kein Enddatum gewählt.",
+    "noStartDate": "Kein Startdatum gewählt.",
+    "options": {
+      "cycle": {
+        "daily": "täglich",
+        "hourly": "stündlich",
+        "monthly": "monatlich",
+        "once": "einmalig",
+        "weekly": "wöchentlich",
+        "yearly": "jährlich"
+      }
+    },
+    "validFrom": "Startdatum",
+    "validTo": "Enddatum"
+  },
   "creation": "Schöpfung",
   "creationList": "Schöpfungsliste",
   "creation_form": {
     "creation_failed": "Ausstehende Schöpfung für {email} konnte nicht erzeugt werden.",
     "creation_for": "Aktives Grundeinkommen für",
+    "deleteNow": "Möchtest du diesen Beitrag zur Gemeinschaft wirklich löschen?",
     "enter_text": "Text eintragen",
     "form": "Schöpfungsformular",
     "min_characters": "Mindestens 10 Zeichen eingeben",
@@ -44,7 +74,8 @@
   "lastname": "Nachname",
   "math": {
     "exclaim": "!",
-    "pipe": "|"
+    "pipe": "|",
+    "plus": "+"
   },
   "moderator": "Moderator",
   "multiple_creation_text": "Bitte wähle ein oder mehrere Mitglieder aus für die du Schöpfen möchtest.",
@@ -71,7 +102,7 @@
   },
   "redeemed": "eingelöst",
   "remove": "Entfernen",
-  "removeNotSelf": "Als Admin / Moderator kannst du dich nicht selber löschen.",
+  "removeNotSelf": "Als Admin/Moderator kannst du dich nicht selber löschen.",
   "remove_all": "alle Nutzer entfernen",
   "save": "Speichern",
   "status": "Status",
@@ -101,6 +132,16 @@
     "text_false": " Die letzte Email wurde am {date} Uhr an das Mitglied ({email}) gesendet.",
     "text_true": " Die Email wurde bestätigt."
   },
+  "userRole": {
+    "notChangeYourSelf": "Als Admin/Moderator kannst du nicht selber deine Rolle ändern.",
+    "selectLabel": "Rolle:",
+    "selectRoles": {
+      "admin": "Administrator",
+      "user": "einfacher Nutzer"
+    },
+    "successfullyChangedTo": "Nutzer ist jetzt „{role}“.",
+    "tabTitle": "Nutzer-Rolle"
+  },
   "user_deleted": "Nutzer ist gelöscht.",
   "user_recovered": "Nutzer ist wiederhergestellt.",
   "user_search": "Nutzer-Suche"
diff --git a/admin/src/locales/en.json b/admin/src/locales/en.json
index 982c42d92..f23c61e21 100644
--- a/admin/src/locales/en.json
+++ b/admin/src/locales/en.json
@@ -1,11 +1,41 @@
 {
   "all_emails": "All users",
   "back": "back",
+  "contributionLink": {
+    "amount": "Amount",
+    "clear": "Clear",
+    "contributionLinks": "Contribution Links",
+    "create": "Create",
+    "cycle": "Cycle",
+    "deleteNow": "Do you really delete automatic creations?",
+    "maximumAmount": "Maximum amount",
+    "maxPerCycle": "Repetition",
+    "memo": "Memo",
+    "name": "Name",
+    "newContributionLink": "New contribution link",
+    "noContributionLinks": "No contribution link has been created.",
+    "noDateSelected": "No date selected",
+    "noEndDate": "No end-date",
+    "noStartDate": "No start-date",
+    "options": {
+      "cycle": {
+        "daily": "daily",
+        "hourly": "hourly",
+        "monthly": "monthly",
+        "once": "once",
+        "weekly": "weekly",
+        "yearly": "yearly"
+      }
+    },
+    "validFrom": "Start-date",
+    "validTo": "End-Date"
+  },
   "creation": "Creation",
   "creationList": "Creation list",
   "creation_form": {
     "creation_failed": "Could not create pending creation for {email}",
     "creation_for": "Active Basic Income for",
+    "deleteNow": "Do you really want to delete this contribution to the community?",
     "enter_text": "Enter text",
     "form": "Creation form",
     "min_characters": "Enter at least 10 characters",
@@ -44,7 +74,8 @@
   "lastname": "Lastname",
   "math": {
     "exclaim": "!",
-    "pipe": "|"
+    "pipe": "|",
+    "plus": "+"
   },
   "moderator": "Moderator",
   "multiple_creation_text": "Please select one or more members for which you would like to perform creations.",
@@ -71,7 +102,7 @@
   },
   "redeemed": "redeemed",
   "remove": "Remove",
-  "removeNotSelf": "As admin / moderator you cannot delete yourself.",
+  "removeNotSelf": "As an admin/moderator, you cannot delete yourself.",
   "remove_all": "Remove all users",
   "save": "Speichern",
   "status": "Status",
@@ -101,6 +132,16 @@
     "text_false": "The last email was sent to the member ({email}) on {date}.",
     "text_true": "The email was confirmed."
   },
+  "userRole": {
+    "notChangeYourSelf": "As an admin/moderator, you cannot change your own role.",
+    "selectLabel": "Role:",
+    "selectRoles": {
+      "admin": "administrator",
+      "user": "usual user"
+    },
+    "successfullyChangedTo": "User is now \"{role}\".",
+    "tabTitle": "User Role"
+  },
   "user_deleted": "User is deleted.",
   "user_recovered": "User is recovered.",
   "user_search": "User search"
diff --git a/admin/src/pages/Creation.vue b/admin/src/pages/Creation.vue
index 9e554ff92..26d44fd3e 100644
--- a/admin/src/pages/Creation.vue
+++ b/admin/src/pages/Creation.vue
@@ -29,6 +29,7 @@
           per-page="perPage"
           :total-rows="rows"
           align="center"
+          :hide-ellipsis="true"
         ></b-pagination>
       </b-col>
       <b-col cols="12" lg="6" class="shadow p-3 mb-5 rounded bg-info">
diff --git a/admin/src/pages/CreationConfirm.spec.js b/admin/src/pages/CreationConfirm.spec.js
index 6df60378c..352eba809 100644
--- a/admin/src/pages/CreationConfirm.spec.js
+++ b/admin/src/pages/CreationConfirm.spec.js
@@ -1,7 +1,7 @@
 import { mount } from '@vue/test-utils'
 import CreationConfirm from './CreationConfirm.vue'
-import { deletePendingCreation } from '../graphql/deletePendingCreation'
-import { confirmPendingCreation } from '../graphql/confirmPendingCreation'
+import { adminDeleteContribution } from '../graphql/adminDeleteContribution'
+import { confirmContribution } from '../graphql/confirmContribution'
 import { toastErrorSpy, toastSuccessSpy } from '../../test/testSetup'
 
 const localVue = global.localVue
@@ -9,7 +9,7 @@ const localVue = global.localVue
 const storeCommitMock = jest.fn()
 const apolloQueryMock = jest.fn().mockResolvedValue({
   data: {
-    getPendingCreations: [
+    listUnconfirmedContributions: [
       {
         id: 1,
         firstName: 'Bibi',
@@ -18,7 +18,7 @@ const apolloQueryMock = jest.fn().mockResolvedValue({
         amount: 500,
         memo: 'Danke für alles',
         date: new Date(),
-        moderator: 0,
+        moderator: 2,
       },
       {
         id: 2,
@@ -28,7 +28,7 @@ const apolloQueryMock = jest.fn().mockResolvedValue({
         amount: 1000000,
         memo: 'Gut Ergattert',
         date: new Date(),
-        moderator: 0,
+        moderator: 2,
       },
     ],
   },
@@ -80,28 +80,54 @@ describe('CreationConfirm', () => {
     })
 
     describe('remove creation with success', () => {
-      beforeEach(async () => {
-        await wrapper.findAll('tr').at(1).findAll('button').at(0).trigger('click')
-      })
+      let spy
 
-      it('calls the deletePendingCreation mutation', () => {
-        expect(apolloMutateMock).toBeCalledWith({
-          mutation: deletePendingCreation,
-          variables: { id: 1 },
+      describe('admin confirms deletion', () => {
+        beforeEach(async () => {
+          spy = jest.spyOn(wrapper.vm.$bvModal, 'msgBoxConfirm')
+          spy.mockImplementation(() => Promise.resolve('some value'))
+          await wrapper.findAll('tr').at(1).findAll('button').at(0).trigger('click')
+        })
+
+        it('opens a modal', () => {
+          expect(spy).toBeCalled()
+        })
+
+        it('calls the adminDeleteContribution mutation', () => {
+          expect(apolloMutateMock).toBeCalledWith({
+            mutation: adminDeleteContribution,
+            variables: { id: 1 },
+          })
+        })
+
+        it('commits openCreationsMinus to store', () => {
+          expect(storeCommitMock).toBeCalledWith('openCreationsMinus', 1)
+        })
+
+        it('toasts a success message', () => {
+          expect(toastSuccessSpy).toBeCalledWith('creation_form.toasted_delete')
         })
       })
 
-      it('commits openCreationsMinus to store', () => {
-        expect(storeCommitMock).toBeCalledWith('openCreationsMinus', 1)
-      })
+      describe('admin cancels deletion', () => {
+        beforeEach(async () => {
+          spy = jest.spyOn(wrapper.vm.$bvModal, 'msgBoxConfirm')
+          spy.mockImplementation(() => Promise.resolve(false))
+          await wrapper.findAll('tr').at(1).findAll('button').at(0).trigger('click')
+        })
 
-      it('toasts a success message', () => {
-        expect(toastSuccessSpy).toBeCalledWith('creation_form.toasted_delete')
+        it('does not call the adminDeleteContribution mutation', () => {
+          expect(apolloMutateMock).not.toBeCalled()
+        })
       })
     })
 
     describe('remove creation with error', () => {
+      let spy
+
       beforeEach(async () => {
+        spy = jest.spyOn(wrapper.vm.$bvModal, 'msgBoxConfirm')
+        spy.mockImplementation(() => Promise.resolve('some value'))
         apolloMutateMock.mockRejectedValue({ message: 'Ouchhh!' })
         await wrapper.findAll('tr').at(1).findAll('button').at(0).trigger('click')
       })
@@ -141,9 +167,9 @@ describe('CreationConfirm', () => {
             await wrapper.find('#overlay').findAll('button').at(1).trigger('click')
           })
 
-          it('calls the confirmPendingCreation mutation', () => {
+          it('calls the confirmContribution mutation', () => {
             expect(apolloMutateMock).toBeCalledWith({
-              mutation: confirmPendingCreation,
+              mutation: confirmContribution,
               variables: { id: 2 },
             })
           })
diff --git a/admin/src/pages/CreationConfirm.vue b/admin/src/pages/CreationConfirm.vue
index 26928fb67..c07e6b351 100644
--- a/admin/src/pages/CreationConfirm.vue
+++ b/admin/src/pages/CreationConfirm.vue
@@ -15,9 +15,9 @@
 <script>
 import Overlay from '../components/Overlay.vue'
 import OpenCreationsTable from '../components/Tables/OpenCreationsTable.vue'
-import { getPendingCreations } from '../graphql/getPendingCreations'
-import { deletePendingCreation } from '../graphql/deletePendingCreation'
-import { confirmPendingCreation } from '../graphql/confirmPendingCreation'
+import { listUnconfirmedContributions } from '../graphql/listUnconfirmedContributions'
+import { adminDeleteContribution } from '../graphql/adminDeleteContribution'
+import { confirmContribution } from '../graphql/confirmContribution'
 
 export default {
   name: 'CreationConfirm',
@@ -34,25 +34,28 @@ export default {
   },
   methods: {
     removeCreation(item) {
-      this.$apollo
-        .mutate({
-          mutation: deletePendingCreation,
-          variables: {
-            id: item.id,
-          },
-        })
-        .then((result) => {
-          this.updatePendingCreations(item.id)
-          this.toastSuccess(this.$t('creation_form.toasted_delete'))
-        })
-        .catch((error) => {
-          this.toastError(error.message)
-        })
+      this.$bvModal.msgBoxConfirm(this.$t('creation_form.deleteNow')).then(async (value) => {
+        if (value)
+          await this.$apollo
+            .mutate({
+              mutation: adminDeleteContribution,
+              variables: {
+                id: item.id,
+              },
+            })
+            .then((result) => {
+              this.updatePendingCreations(item.id)
+              this.toastSuccess(this.$t('creation_form.toasted_delete'))
+            })
+            .catch((error) => {
+              this.toastError(error.message)
+            })
+      })
     },
     confirmCreation() {
       this.$apollo
         .mutate({
-          mutation: confirmPendingCreation,
+          mutation: confirmContribution,
           variables: {
             id: this.item.id,
           },
@@ -70,13 +73,13 @@ export default {
     getPendingCreations() {
       this.$apollo
         .query({
-          query: getPendingCreations,
+          query: listUnconfirmedContributions,
           fetchPolicy: 'network-only',
         })
         .then((result) => {
           this.$store.commit('resetOpenCreations')
-          this.pendingCreations = result.data.getPendingCreations
-          this.$store.commit('setOpenCreations', result.data.getPendingCreations.length)
+          this.pendingCreations = result.data.listUnconfirmedContributions
+          this.$store.commit('setOpenCreations', result.data.listUnconfirmedContributions.length)
         })
         .catch((error) => {
           this.toastError(error.message)
@@ -114,7 +117,7 @@ export default {
           },
         },
         { key: 'moderator', label: this.$t('moderator') },
-        { key: 'edit_creation', label: this.$t('edit') },
+        { key: 'editCreation', label: this.$t('edit') },
         { key: 'confirm', label: this.$t('save') },
       ]
     },
diff --git a/admin/src/pages/Overview.spec.js b/admin/src/pages/Overview.spec.js
index b3d720d5c..cc5a0c3a5 100644
--- a/admin/src/pages/Overview.spec.js
+++ b/admin/src/pages/Overview.spec.js
@@ -5,7 +5,7 @@ const localVue = global.localVue
 
 const apolloQueryMock = jest.fn().mockResolvedValue({
   data: {
-    getPendingCreations: [
+    listUnconfirmedContributions: [
       {
         pending: true,
       },
@@ -46,7 +46,7 @@ describe('Overview', () => {
       wrapper = Wrapper()
     })
 
-    it('calls getPendingCreations', () => {
+    it('calls listUnconfirmedContributions', () => {
       expect(apolloQueryMock).toBeCalled()
     })
 
diff --git a/admin/src/pages/Overview.vue b/admin/src/pages/Overview.vue
index ed7ac8ad7..69aa15c1a 100644
--- a/admin/src/pages/Overview.vue
+++ b/admin/src/pages/Overview.vue
@@ -28,27 +28,54 @@
         </b-link>
       </b-card-text>
     </b-card>
+    <contribution-link :items="items" :count="count" />
   </div>
 </template>
 <script>
-import { getPendingCreations } from '../graphql/getPendingCreations'
+import { listContributionLinks } from '@/graphql/listContributionLinks.js'
+import ContributionLink from '../components/ContributionLink.vue'
+import { listUnconfirmedContributions } from '../graphql/listUnconfirmedContributions'
 
 export default {
   name: 'overview',
+  components: {
+    ContributionLink,
+  },
+  data() {
+    return {
+      items: [],
+      count: 0,
+    }
+  },
   methods: {
     async getPendingCreations() {
       this.$apollo
         .query({
-          query: getPendingCreations,
+          query: listUnconfirmedContributions,
           fetchPolicy: 'network-only',
         })
         .then((result) => {
-          this.$store.commit('setOpenCreations', result.data.getPendingCreations.length)
+          this.$store.commit('setOpenCreations', result.data.listUnconfirmedContributions.length)
+        })
+    },
+    async getContributionLinks() {
+      this.$apollo
+        .query({
+          query: listContributionLinks,
+          fetchPolicy: 'network-only',
+        })
+        .then((result) => {
+          this.count = result.data.listContributionLinks.count
+          this.items = result.data.listContributionLinks.links
+        })
+        .catch(() => {
+          this.toastError('listContributionLinks has no result, use default data')
         })
     },
   },
   created() {
     this.getPendingCreations()
+    this.getContributionLinks()
   },
 }
 </script>
diff --git a/admin/src/pages/UserSearch.spec.js b/admin/src/pages/UserSearch.spec.js
index 7d8be648f..1020d2b00 100644
--- a/admin/src/pages/UserSearch.spec.js
+++ b/admin/src/pages/UserSearch.spec.js
@@ -199,14 +199,43 @@ describe('UserSearch', () => {
       })
     })
 
+    describe('change user role', () => {
+      const userId = 4
+
+      describe('to admin', () => {
+        it('updates user role to admin', async () => {
+          await wrapper
+            .findComponent({ name: 'SearchUserTable' })
+            .vm.$emit('updateIsAdmin', userId, new Date())
+          expect(wrapper.vm.searchResult.find((obj) => obj.userId === userId).isAdmin).toEqual(
+            expect.any(Date),
+          )
+        })
+      })
+
+      describe('to usual user', () => {
+        it('updates user role to usual user', async () => {
+          await wrapper
+            .findComponent({ name: 'SearchUserTable' })
+            .vm.$emit('updateIsAdmin', userId, null)
+          expect(wrapper.vm.searchResult.find((obj) => obj.userId === userId).isAdmin).toEqual(null)
+        })
+      })
+    })
+
     describe('delete user', () => {
-      const now = new Date()
-      beforeEach(async () => {
-        wrapper.findComponent({ name: 'SearchUserTable' }).vm.$emit('updateDeletedAt', 4, now)
+      const userId = 4
+      beforeEach(() => {
+        wrapper
+          .findComponent({ name: 'SearchUserTable' })
+          .vm.$emit('updateDeletedAt', userId, new Date())
       })
 
       it('marks the user as deleted', () => {
-        expect(wrapper.vm.searchResult.find((obj) => obj.userId === 4).deletedAt).toEqual(now)
+        expect(wrapper.vm.searchResult.find((obj) => obj.userId === userId).deletedAt).toEqual(
+          expect.any(Date),
+        )
+        expect(wrapper.find('.test-deleted-icon').exists()).toBe(true)
       })
 
       it('toasts a success message', () => {
diff --git a/admin/src/pages/UserSearch.vue b/admin/src/pages/UserSearch.vue
index f1ca31d14..df49526d7 100644
--- a/admin/src/pages/UserSearch.vue
+++ b/admin/src/pages/UserSearch.vue
@@ -42,6 +42,7 @@
       type="PageUserSearch"
       :items="searchResult"
       :fields="fields"
+      @updateIsAdmin="updateIsAdmin"
       @updateDeletedAt="updateDeletedAt"
     />
     <b-pagination
@@ -51,6 +52,7 @@
       per-page="perPage"
       :total-rows="rows"
       align="center"
+      :hide-ellipsis="true"
     ></b-pagination>
     <div></div>
   </div>
@@ -111,6 +113,9 @@ export default {
           this.toastError(error.message)
         })
     },
+    updateIsAdmin(userId, isAdmin) {
+      this.searchResult.find((obj) => obj.userId === userId).isAdmin = isAdmin
+    },
     updateDeletedAt(userId, deletedAt) {
       this.searchResult.find((obj) => obj.userId === userId).deletedAt = deletedAt
       this.toastSuccess(deletedAt ? this.$t('user_deleted') : this.$t('user_recovered'))
diff --git a/admin/yarn.lock b/admin/yarn.lock
index af1d18fa6..09b543354 100644
--- a/admin/yarn.lock
+++ b/admin/yarn.lock
@@ -932,6 +932,13 @@
   dependencies:
     regenerator-runtime "^0.13.4"
 
+"@babel/runtime@^7.11.2", "@babel/runtime@^7.16.0":
+  version "7.18.3"
+  resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.3.tgz#c7b654b57f6f63cf7f8b418ac9ca04408c4579f4"
+  integrity sha512-38Y8f7YUhce/K7RMwTp7m0uCumpv9hZkitCbBClqQIow1qSbCvGkcegKOXpEWCQLfWmevgRiWokZ1GkpfhbZug==
+  dependencies:
+    regenerator-runtime "^0.13.4"
+
 "@babel/runtime@^7.14.0":
   version "7.17.7"
   resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.7.tgz#a5f3328dc41ff39d803f311cfe17703418cf9825"
@@ -4082,9 +4089,9 @@ caniuse-api@^3.0.0:
     lodash.uniq "^4.5.0"
 
 caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000844, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001271:
-  version "1.0.30001271"
-  resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001271.tgz#0dda0c9bcae2cf5407cd34cac304186616cc83e8"
-  integrity sha512-BBruZFWmt3HFdVPS8kceTBIguKxu4f99n5JNp06OlPD/luoAMIaIK5ieV5YjnBLH3Nysai9sxj9rpJj4ZisXOA==
+  version "1.0.30001354"
+  resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001354.tgz"
+  integrity sha512-mImKeCkyGDAHNywYFA4bqnLAzTUvVkqPvhY4DV47X+Gl2c5Z8c3KNETnXp14GQt11LvxE8AwjzGxJ+rsikiOzg==
 
 capture-exit@^2.0.0:
   version "2.0.0"
@@ -4397,7 +4404,7 @@ color-name@1.1.3:
   resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
   integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
 
-color-name@^1.0.0, color-name@~1.1.4:
+color-name@^1.0.0, color-name@^1.1.4, color-name@~1.1.4:
   version "1.1.4"
   resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
   integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
@@ -4845,6 +4852,11 @@ cssesc@^3.0.0:
   resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
   integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==
 
+cssfontparser@^1.2.1:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/cssfontparser/-/cssfontparser-1.2.1.tgz#f4022fc8f9700c68029d542084afbaf425a3f3e3"
+  integrity sha512-6tun4LoZnj7VN6YeegOVb67KBX/7JJsqvj+pv3ZA7F878/eN33AbGa5b/S/wXxS/tcp8nc40xRUrsPlxIyNUPg==
+
 cssnano-preset-default@^4.0.0, cssnano-preset-default@^4.0.8:
   version "4.0.8"
   resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-4.0.8.tgz#920622b1fc1e95a34e8838203f1397a504f2d3ff"
@@ -7821,6 +7833,14 @@ javascript-stringify@^2.0.1:
   resolved "https://registry.yarnpkg.com/javascript-stringify/-/javascript-stringify-2.1.0.tgz#27c76539be14d8bd128219a2d731b09337904e79"
   integrity sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg==
 
+jest-canvas-mock@^2.3.1:
+  version "2.4.0"
+  resolved "https://registry.yarnpkg.com/jest-canvas-mock/-/jest-canvas-mock-2.4.0.tgz#947b71442d7719f8e055decaecdb334809465341"
+  integrity sha512-mmMpZzpmLzn5vepIaHk5HoH3Ka4WykbSoLuG/EKoJd0x0ID/t+INo1l8ByfcUJuDM+RIsL4QDg/gDnBbrj2/IQ==
+  dependencies:
+    cssfontparser "^1.2.1"
+    moo-color "^1.0.2"
+
 jest-changed-files@^24.9.0:
   version "24.9.0"
   resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-24.9.0.tgz#08d8c15eb79a7fa3fc98269bc14b451ee82f8039"
@@ -9478,6 +9498,13 @@ mkdirp@0.x, mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@^0.5.5, mkdirp@~0.5.1:
   dependencies:
     minimist "^1.2.5"
 
+moo-color@^1.0.2:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/moo-color/-/moo-color-1.0.3.tgz#d56435f8359c8284d83ac58016df7427febece74"
+  integrity sha512-i/+ZKXMDf6aqYtBhuOcej71YSlbjT3wCO/4H1j8rPvxDJEifdwgg5MaFyu6iYAT8GBZJg2z0dkgK4YMzvURALQ==
+  dependencies:
+    color-name "^1.1.4"
+
 move-concurrently@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92"
@@ -10959,6 +10986,27 @@ q@^1.1.2:
   resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
   integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=
 
+qrcanvas-vue@2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/qrcanvas-vue/-/qrcanvas-vue-2.1.1.tgz#27b449f99eaf46f324b300215469bfdf8ef77d88"
+  integrity sha512-86NMjOJ5XJGrrqrD2t+zmZxZKNuW1Is7o88UOiM8qFxDBjuTyfq9VJE9/2rN5XxThsjBuY4bRrQqL9blVwnI9w==
+  dependencies:
+    "@babel/runtime" "^7.16.0"
+    qrcanvas "^3.1.2"
+
+qrcanvas@^3.1.2:
+  version "3.1.2"
+  resolved "https://registry.yarnpkg.com/qrcanvas/-/qrcanvas-3.1.2.tgz#81a25e91b2c27e9ace91da95591cbfb100d68702"
+  integrity sha512-lNcAyCHN0Eno/mJ5eBc7lHV/5ejAJxII0UELthG3bNnlLR+u8hCc7CR+hXBawbYUf96kNIosXfG2cJzx92ZWKg==
+  dependencies:
+    "@babel/runtime" "^7.11.2"
+    qrcode-generator "^1.4.4"
+
+qrcode-generator@^1.4.4:
+  version "1.4.4"
+  resolved "https://registry.yarnpkg.com/qrcode-generator/-/qrcode-generator-1.4.4.tgz#63f771224854759329a99048806a53ed278740e7"
+  integrity sha512-HM7yY8O2ilqhmULxGMpcHSF1EhJJ9yBj8gvDEuZ6M+KGJ0YY2hKpnXvRD+hZPLrDVck3ExIGhmPtSdcjC+guuw==
+
 qs@6.7.0:
   version "6.7.0"
   resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
diff --git a/backend/.env.dist b/backend/.env.dist
index 62b786456..69b1d6a46 100644
--- a/backend/.env.dist
+++ b/backend/.env.dist
@@ -1,9 +1,9 @@
-CONFIG_VERSION=v6.2022-04-21
+CONFIG_VERSION=v9.2022-07-07
 
 # Server
 PORT=4000
 JWT_SECRET=secret123
-JWT_EXPIRES_IN=30m
+JWT_EXPIRES_IN=10m
 GRAPHIQL=false
 GDT_API_URL=https://gdt.gradido.net
 
@@ -28,6 +28,7 @@ COMMUNITY_NAME=Gradido Entwicklung
 COMMUNITY_URL=http://localhost/
 COMMUNITY_REGISTER_URL=http://localhost/register
 COMMUNITY_REDEEM_URL=http://localhost/redeem/{code}
+COMMUNITY_REDEEM_CONTRIBUTION_URL=http://localhost/redeem/CL-{code}
 COMMUNITY_DESCRIPTION=Die lokale Entwicklungsumgebung von Gradido.
 
 # Login Server
@@ -51,6 +52,9 @@ EMAIL_CODE_REQUEST_TIME=10
 # Webhook
 WEBHOOK_ELOPAGE_SECRET=secret
 
+# EventProtocol
+EVENT_PROTOCOL_DISABLED=false
+
 # SET LOG LEVEL AS NEEDED IN YOUR .ENV
 # POSSIBLE VALUES: all | trace | debug | info | warn | error | fatal
 # LOG_LEVEL=info
diff --git a/backend/.env.template b/backend/.env.template
index 140ec67e9..beaa256ef 100644
--- a/backend/.env.template
+++ b/backend/.env.template
@@ -27,6 +27,7 @@ COMMUNITY_NAME=$COMMUNITY_NAME
 COMMUNITY_URL=$COMMUNITY_URL
 COMMUNITY_REGISTER_URL=$COMMUNITY_REGISTER_URL
 COMMUNITY_REDEEM_URL=$COMMUNITY_REDEEM_URL
+COMMUNITY_REDEEM_CONTRIBUTION_URL=$COMMUNITY_REDEEM_CONTRIBUTION_URL
 COMMUNITY_DESCRIPTION=$COMMUNITY_DESCRIPTION
 
 # Login Server
@@ -42,9 +43,13 @@ EMAIL_SMTP_URL=$EMAIL_SMTP_URL
 EMAIL_SMTP_PORT=587
 EMAIL_LINK_VERIFICATION=$EMAIL_LINK_VERIFICATION
 EMAIL_LINK_SETPASSWORD=$EMAIL_LINK_SETPASSWORD
+EMAIL_LINK_FORGOTPASSWORD=$EMAIL_LINK_FORGOTPASSWORD
 EMAIL_LINK_OVERVIEW=$EMAIL_LINK_OVERVIEW
 EMAIL_CODE_VALID_TIME=$EMAIL_CODE_VALID_TIME
 EMAIL_CODE_REQUEST_TIME=$EMAIL_CODE_REQUEST_TIME
 
 # Webhook
 WEBHOOK_ELOPAGE_SECRET=$WEBHOOK_ELOPAGE_SECRET
+
+# EventProtocol
+EVENT_PROTOCOL_DISABLED=$EVENT_PROTOCOL_DISABLED
diff --git a/backend/README.md b/backend/README.md
index e74750c46..b27ab16d9 100644
--- a/backend/README.md
+++ b/backend/README.md
@@ -1,16 +1,18 @@
 # backend
 
 ## Project setup
-```
+
+```bash
 yarn install
 ```
 
 ## Seed DB
-```
+
+```bash
 yarn seed
 ```
-Deletes all data in database. Then seeds data in database.
 
+Deletes all data in database. Then seeds data in database.
 
 ## Seeded Users
 
@@ -22,3 +24,47 @@ Deletes all data in database. Then seeds data in database.
 | bob@baumeister.de      | `Aa12345_` | `false` | `true`        | `false` |
 | garrick@ollivander.com |            | `false` | `false`       | `false` |
 | stephen@hawking.uk     | `Aa12345_` | `false` | `true`        | `true`  |
+
+## Setup GraphQL Playground
+
+### Setup In The Code
+
+Setting up the GraphQL Playground in our code requires the following steps:
+
+- Create an empty `.env` file in the `backend` folder and set "GRAPHIQL=true" there.
+- Start or restart Docker Compose.
+- For verification, Docker should display `GraphQL available at http://localhost:4000` in the terminal.
+- If you open "http://localhost:4000/" in your browser, you should see the GraphQL Playground.
+
+### Authentication
+
+You need to authenticate yourself in GraphQL Playground to be able to send queries and mutations, to do so follow the steps below:
+
+- in Firefox go to "Network Analysis" and delete all entries
+- enter and send the login query:
+
+```gql
+{
+  login(email: "bibi@bloxberg.de", password:"Aa12345_") {
+    id
+    publisherId
+    email
+    firstName
+    lastName
+    emailChecked
+    language
+    hasElopage
+  }
+}
+```
+
+- search in Firefox under „Network Analysis" for the smallest size of a header and copy the value of the token
+- open the header section in GraphQL Playground and set your current token by filling in and replacing `XXX`:
+
+```qgl
+{
+  "Authorization": "XXX"
+}
+```
+
+Now you can open a new tap in the Playground and enter your query or mutation there.
diff --git a/backend/package.json b/backend/package.json
index bd5388632..c56c8e960 100644
--- a/backend/package.json
+++ b/backend/package.json
@@ -1,6 +1,6 @@
 {
   "name": "gradido-backend",
-  "version": "1.9.0",
+  "version": "1.11.0",
   "description": "Gradido unified backend providing an API-Service for Gradido Transactions",
   "main": "src/index.ts",
   "repository": "https://github.com/gradido/gradido/backend",
diff --git a/backend/src/auth/RIGHTS.ts b/backend/src/auth/RIGHTS.ts
index 8188b3daa..d5e2cc7ce 100644
--- a/backend/src/auth/RIGHTS.ts
+++ b/backend/src/auth/RIGHTS.ts
@@ -25,16 +25,27 @@ export enum RIGHTS {
   REDEEM_TRANSACTION_LINK = 'REDEEM_TRANSACTION_LINK',
   LIST_TRANSACTION_LINKS = 'LIST_TRANSACTION_LINKS',
   GDT_BALANCE = 'GDT_BALANCE',
+  CREATE_CONTRIBUTION = 'CREATE_CONTRIBUTION',
+  DELETE_CONTRIBUTION = 'DELETE_CONTRIBUTION',
+  LIST_CONTRIBUTIONS = 'LIST_CONTRIBUTIONS',
+  LIST_ALL_CONTRIBUTIONS = 'LIST_ALL_CONTRIBUTIONS',
+  UPDATE_CONTRIBUTION = 'UPDATE_CONTRIBUTION',
   // Admin
   SEARCH_USERS = 'SEARCH_USERS',
-  CREATE_PENDING_CREATION = 'CREATE_PENDING_CREATION',
-  UPDATE_PENDING_CREATION = 'UPDATE_PENDING_CREATION',
-  SEARCH_PENDING_CREATION = 'SEARCH_PENDING_CREATION',
-  DELETE_PENDING_CREATION = 'DELETE_PENDING_CREATION',
-  CONFIRM_PENDING_CREATION = 'CONFIRM_PENDING_CREATION',
-  SEND_ACTIVATION_EMAIL = 'SEND_ACTIVATION_EMAIL',
+  SET_USER_ROLE = 'SET_USER_ROLE',
   DELETE_USER = 'DELETE_USER',
   UNDELETE_USER = 'UNDELETE_USER',
+  ADMIN_CREATE_CONTRIBUTION = 'ADMIN_CREATE_CONTRIBUTION',
+  ADMIN_CREATE_CONTRIBUTIONS = 'ADMIN_CREATE_CONTRIBUTIONS',
+  ADMIN_UPDATE_CONTRIBUTION = 'ADMIN_UPDATE_CONTRIBUTION',
+  ADMIN_DELETE_CONTRIBUTION = 'ADMIN_DELETE_CONTRIBUTION',
+  LIST_UNCONFIRMED_CONTRIBUTIONS = 'LIST_UNCONFIRMED_CONTRIBUTIONS',
+  CONFIRM_CONTRIBUTION = 'CONFIRM_CONTRIBUTION',
+  SEND_ACTIVATION_EMAIL = 'SEND_ACTIVATION_EMAIL',
   CREATION_TRANSACTION_LIST = 'CREATION_TRANSACTION_LIST',
   LIST_TRANSACTION_LINKS_ADMIN = 'LIST_TRANSACTION_LINKS_ADMIN',
+  CREATE_CONTRIBUTION_LINK = 'CREATE_CONTRIBUTION_LINK',
+  LIST_CONTRIBUTION_LINKS = 'LIST_CONTRIBUTION_LINKS',
+  DELETE_CONTRIBUTION_LINK = 'DELETE_CONTRIBUTION_LINK',
+  UPDATE_CONTRIBUTION_LINK = 'UPDATE_CONTRIBUTION_LINK',
 }
diff --git a/backend/src/auth/ROLES.ts b/backend/src/auth/ROLES.ts
index 891fe1844..9dcba0a4b 100644
--- a/backend/src/auth/ROLES.ts
+++ b/backend/src/auth/ROLES.ts
@@ -23,6 +23,11 @@ export const ROLE_USER = new Role('user', [
   RIGHTS.REDEEM_TRANSACTION_LINK,
   RIGHTS.LIST_TRANSACTION_LINKS,
   RIGHTS.GDT_BALANCE,
+  RIGHTS.CREATE_CONTRIBUTION,
+  RIGHTS.DELETE_CONTRIBUTION,
+  RIGHTS.LIST_CONTRIBUTIONS,
+  RIGHTS.LIST_ALL_CONTRIBUTIONS,
+  RIGHTS.UPDATE_CONTRIBUTION,
 ])
 export const ROLE_ADMIN = new Role('admin', Object.values(RIGHTS)) // all rights
 
diff --git a/backend/src/config/index.ts b/backend/src/config/index.ts
index 5736e6d8a..f44aa584c 100644
--- a/backend/src/config/index.ts
+++ b/backend/src/config/index.ts
@@ -10,14 +10,14 @@ Decimal.set({
 })
 
 const constants = {
-  DB_VERSION: '0038-add_contribution_links_table',
+  DB_VERSION: '0044-insert_missing_contributions',
   DECAY_START_TIME: new Date('2021-05-13 17:46:31-0000'), // GMT+0
   LOG4JS_CONFIG: 'log4js-config.json',
   // default log level on production should be info
   LOG_LEVEL: process.env.LOG_LEVEL || 'info',
   CONFIG_VERSION: {
     DEFAULT: 'DEFAULT',
-    EXPECTED: 'v6.2022-04-21',
+    EXPECTED: 'v9.2022-07-07',
     CURRENT: '',
   },
 }
@@ -25,7 +25,7 @@ const constants = {
 const server = {
   PORT: process.env.PORT || 4000,
   JWT_SECRET: process.env.JWT_SECRET || 'secret123',
-  JWT_EXPIRES_IN: process.env.JWT_EXPIRES_IN || '30m',
+  JWT_EXPIRES_IN: process.env.JWT_EXPIRES_IN || '10m',
   GRAPHIQL: process.env.GRAPHIQL === 'true' || false,
   GDT_API_URL: process.env.GDT_API_URL || 'https://gdt.gradido.net',
   PRODUCTION: process.env.NODE_ENV === 'production' || false,
@@ -54,6 +54,8 @@ const community = {
   COMMUNITY_URL: process.env.COMMUNITY_URL || 'http://localhost/',
   COMMUNITY_REGISTER_URL: process.env.COMMUNITY_REGISTER_URL || 'http://localhost/register',
   COMMUNITY_REDEEM_URL: process.env.COMMUNITY_REDEEM_URL || 'http://localhost/redeem/{code}',
+  COMMUNITY_REDEEM_CONTRIBUTION_URL:
+    process.env.COMMUNITY_REDEEM_CONTRIBUTION_URL || 'http://localhost/redeem/CL-{code}',
   COMMUNITY_DESCRIPTION:
     process.env.COMMUNITY_DESCRIPTION || 'Die lokale Entwicklungsumgebung von Gradido.',
 }
@@ -92,6 +94,11 @@ const webhook = {
   WEBHOOK_ELOPAGE_SECRET: process.env.WEBHOOK_ELOPAGE_SECRET || 'secret',
 }
 
+const eventProtocol = {
+  // global switch to enable writing of EventProtocol-Entries
+  EVENT_PROTOCOL_DISABLED: process.env.EVENT_PROTOCOL_DISABLED === 'true' || false,
+}
+
 // This is needed by graphql-directive-auth
 process.env.APP_SECRET = server.JWT_SECRET
 
@@ -116,6 +123,7 @@ const CONFIG = {
   ...email,
   ...loginServer,
   ...webhook,
+  ...eventProtocol,
 }
 
 export default CONFIG
diff --git a/backend/src/event/Event.ts b/backend/src/event/Event.ts
new file mode 100644
index 000000000..6f07661f1
--- /dev/null
+++ b/backend/src/event/Event.ts
@@ -0,0 +1,301 @@
+import { EventProtocol } from '@entity/EventProtocol'
+import decimal from 'decimal.js-light'
+import { EventProtocolType } from './EventProtocolType'
+
+export class EventBasic {
+  type: string
+  createdAt: Date
+}
+export class EventBasicUserId extends EventBasic {
+  userId: number
+}
+
+export class EventBasicTx extends EventBasicUserId {
+  xUserId: number
+  xCommunityId: number
+  transactionId: number
+  amount: decimal
+}
+
+export class EventBasicCt extends EventBasicUserId {
+  contributionId: number
+  amount: decimal
+}
+
+export class EventBasicRedeem extends EventBasicUserId {
+  transactionId?: number
+  contributionId?: number
+}
+
+export class EventVisitGradido extends EventBasic {}
+export class EventRegister extends EventBasicUserId {}
+export class EventRedeemRegister extends EventBasicRedeem {}
+export class EventInactiveAccount extends EventBasicUserId {}
+export class EventSendConfirmationEmail extends EventBasicUserId {}
+export class EventConfirmationEmail extends EventBasicUserId {}
+export class EventRegisterEmailKlicktipp extends EventBasicUserId {}
+export class EventLogin extends EventBasicUserId {}
+export class EventRedeemLogin extends EventBasicRedeem {}
+export class EventActivateAccount extends EventBasicUserId {}
+export class EventPasswordChange extends EventBasicUserId {}
+export class EventTransactionSend extends EventBasicTx {}
+export class EventTransactionSendRedeem extends EventBasicTx {}
+export class EventTransactionRepeateRedeem extends EventBasicTx {}
+export class EventTransactionCreation extends EventBasicUserId {
+  transactionId: number
+  amount: decimal
+}
+export class EventTransactionReceive extends EventBasicTx {}
+export class EventTransactionReceiveRedeem extends EventBasicTx {}
+export class EventContributionCreate extends EventBasicCt {}
+export class EventContributionConfirm extends EventBasicCt {
+  xUserId: number
+  xCommunityId: number
+}
+export class EventContributionLinkDefine extends EventBasicCt {}
+export class EventContributionLinkActivateRedeem extends EventBasicCt {}
+
+export class Event {
+  constructor()
+  constructor(event?: EventProtocol) {
+    if (event) {
+      this.id = event.id
+      this.type = event.type
+      this.createdAt = event.createdAt
+      this.userId = event.userId
+      this.xUserId = event.xUserId
+      this.xCommunityId = event.xCommunityId
+      this.transactionId = event.transactionId
+      this.contributionId = event.contributionId
+      this.amount = event.amount
+    }
+  }
+
+  public setEventBasic(): Event {
+    this.type = EventProtocolType.BASIC
+    this.createdAt = new Date()
+
+    return this
+  }
+
+  public setEventVisitGradido(): Event {
+    this.setEventBasic()
+    this.type = EventProtocolType.VISIT_GRADIDO
+
+    return this
+  }
+
+  public setEventRegister(ev: EventRegister): Event {
+    this.setByBasicUser(ev.userId)
+    this.type = EventProtocolType.REGISTER
+
+    return this
+  }
+
+  public setEventRedeemRegister(ev: EventRedeemRegister): Event {
+    this.setByBasicRedeem(ev.userId, ev.transactionId, ev.contributionId)
+    this.type = EventProtocolType.REDEEM_REGISTER
+
+    return this
+  }
+
+  public setEventInactiveAccount(ev: EventInactiveAccount): Event {
+    this.setByBasicUser(ev.userId)
+    this.type = EventProtocolType.INACTIVE_ACCOUNT
+
+    return this
+  }
+
+  public setEventSendConfirmationEmail(ev: EventSendConfirmationEmail): Event {
+    this.setByBasicUser(ev.userId)
+    this.type = EventProtocolType.SEND_CONFIRMATION_EMAIL
+
+    return this
+  }
+
+  public setEventConfirmationEmail(ev: EventConfirmationEmail): Event {
+    this.setByBasicUser(ev.userId)
+    this.type = EventProtocolType.CONFIRM_EMAIL
+
+    return this
+  }
+
+  public setEventRegisterEmailKlicktipp(ev: EventRegisterEmailKlicktipp): Event {
+    this.setByBasicUser(ev.userId)
+    this.type = EventProtocolType.REGISTER_EMAIL_KLICKTIPP
+
+    return this
+  }
+
+  public setEventLogin(ev: EventLogin): Event {
+    this.setByBasicUser(ev.userId)
+    this.type = EventProtocolType.LOGIN
+
+    return this
+  }
+
+  public setEventRedeemLogin(ev: EventRedeemLogin): Event {
+    this.setByBasicRedeem(ev.userId, ev.transactionId, ev.contributionId)
+    this.type = EventProtocolType.REDEEM_LOGIN
+
+    return this
+  }
+
+  public setEventActivateAccount(ev: EventActivateAccount): Event {
+    this.setByBasicUser(ev.userId)
+    this.type = EventProtocolType.ACTIVATE_ACCOUNT
+
+    return this
+  }
+
+  public setEventPasswordChange(ev: EventPasswordChange): Event {
+    this.setByBasicUser(ev.userId)
+    this.type = EventProtocolType.PASSWORD_CHANGE
+
+    return this
+  }
+
+  public setEventTransactionSend(ev: EventTransactionSend): Event {
+    this.setByBasicTx(ev.userId, ev.xUserId, ev.xCommunityId, ev.transactionId, ev.amount)
+    this.type = EventProtocolType.TRANSACTION_SEND
+
+    return this
+  }
+
+  public setEventTransactionSendRedeem(ev: EventTransactionSendRedeem): Event {
+    this.setByBasicTx(ev.userId, ev.xUserId, ev.xCommunityId, ev.transactionId, ev.amount)
+    this.type = EventProtocolType.TRANSACTION_SEND_REDEEM
+
+    return this
+  }
+
+  public setEventTransactionRepeateRedeem(ev: EventTransactionRepeateRedeem): Event {
+    this.setByBasicTx(ev.userId, ev.xUserId, ev.xCommunityId, ev.transactionId, ev.amount)
+    this.type = EventProtocolType.TRANSACTION_REPEATE_REDEEM
+
+    return this
+  }
+
+  public setEventTransactionCreation(ev: EventTransactionCreation): Event {
+    this.setByBasicUser(ev.userId)
+    if (ev.transactionId) this.transactionId = ev.transactionId
+    if (ev.amount) this.amount = ev.amount
+    this.type = EventProtocolType.TRANSACTION_CREATION
+
+    return this
+  }
+
+  public setEventTransactionReceive(ev: EventTransactionReceive): Event {
+    this.setByBasicTx(ev.userId, ev.xUserId, ev.xCommunityId, ev.transactionId, ev.amount)
+    this.type = EventProtocolType.TRANSACTION_RECEIVE
+
+    return this
+  }
+
+  public setEventTransactionReceiveRedeem(ev: EventTransactionReceiveRedeem): Event {
+    this.setByBasicTx(ev.userId, ev.xUserId, ev.xCommunityId, ev.transactionId, ev.amount)
+    this.type = EventProtocolType.TRANSACTION_RECEIVE_REDEEM
+
+    return this
+  }
+
+  public setEventContributionCreate(ev: EventContributionCreate): Event {
+    this.setByBasicCt(ev.userId, ev.contributionId, ev.amount)
+    this.type = EventProtocolType.CONTRIBUTION_CREATE
+
+    return this
+  }
+
+  public setEventContributionConfirm(ev: EventContributionConfirm): Event {
+    this.setByBasicCt(ev.userId, ev.contributionId, ev.amount)
+    if (ev.xUserId) this.xUserId = ev.xUserId
+    if (ev.xCommunityId) this.xCommunityId = ev.xCommunityId
+    this.type = EventProtocolType.CONTRIBUTION_CONFIRM
+
+    return this
+  }
+
+  public setEventContributionLinkDefine(ev: EventContributionLinkDefine): Event {
+    this.setByBasicCt(ev.userId, ev.contributionId, ev.amount)
+    this.type = EventProtocolType.CONTRIBUTION_LINK_DEFINE
+
+    return this
+  }
+
+  public setEventContributionLinkActivateRedeem(ev: EventContributionLinkActivateRedeem): Event {
+    this.setByBasicCt(ev.userId, ev.contributionId, ev.amount)
+    this.type = EventProtocolType.CONTRIBUTION_LINK_ACTIVATE_REDEEM
+
+    return this
+  }
+
+  setByBasicUser(userId: number): Event {
+    this.setEventBasic()
+    this.userId = userId
+
+    return this
+  }
+
+  setByBasicTx(
+    userId: number,
+    xUserId?: number,
+    xCommunityId?: number,
+    transactionId?: number,
+    amount?: decimal,
+  ): Event {
+    this.setByBasicUser(userId)
+    if (xUserId) this.xUserId = xUserId
+    if (xCommunityId) this.xCommunityId = xCommunityId
+    if (transactionId) this.transactionId = transactionId
+    if (amount) this.amount = amount
+
+    return this
+  }
+
+  setByBasicCt(userId: number, contributionId: number, amount?: decimal): Event {
+    this.setByBasicUser(userId)
+    if (contributionId) this.contributionId = contributionId
+    if (amount) this.amount = amount
+
+    return this
+  }
+
+  setByBasicRedeem(userId: number, transactionId?: number, contributionId?: number): Event {
+    this.setByBasicUser(userId)
+    if (transactionId) this.transactionId = transactionId
+    if (contributionId) this.contributionId = contributionId
+
+    return this
+  }
+
+  setByEventTransactionCreation(event: EventTransactionCreation): Event {
+    this.type = event.type
+    this.createdAt = event.createdAt
+    this.userId = event.userId
+    this.transactionId = event.transactionId
+    this.amount = event.amount
+
+    return this
+  }
+
+  setByEventContributionConfirm(event: EventContributionConfirm): Event {
+    this.type = event.type
+    this.createdAt = event.createdAt
+    this.userId = event.userId
+    this.xUserId = event.xUserId
+    this.xCommunityId = event.xCommunityId
+    this.amount = event.amount
+
+    return this
+  }
+
+  id: number
+  type: string
+  createdAt: Date
+  userId: number
+  xUserId?: number
+  xCommunityId?: number
+  transactionId?: number
+  contributionId?: number
+  amount?: decimal
+}
diff --git a/backend/src/event/EventProtocolEmitter.ts b/backend/src/event/EventProtocolEmitter.ts
new file mode 100644
index 000000000..6dea99810
--- /dev/null
+++ b/backend/src/event/EventProtocolEmitter.ts
@@ -0,0 +1,39 @@
+import { Event } from '@/event/Event'
+import { backendLogger as logger } from '@/server/logger'
+import { EventProtocol } from '@entity/EventProtocol'
+import CONFIG from '@/config'
+
+class EventProtocolEmitter {
+  /* }extends EventEmitter { */
+  private events: Event[]
+
+  public addEvent(event: Event) {
+    this.events.push(event)
+  }
+
+  public getEvents(): Event[] {
+    return this.events
+  }
+
+  public isDisabled() {
+    logger.info(`EventProtocol - isDisabled=${CONFIG.EVENT_PROTOCOL_DISABLED}`)
+    return CONFIG.EVENT_PROTOCOL_DISABLED === true
+  }
+
+  public async writeEvent(event: Event): Promise<void> {
+    if (!eventProtocol.isDisabled()) {
+      logger.info(`writeEvent(${JSON.stringify(event)})`)
+      const dbEvent = new EventProtocol()
+      dbEvent.type = event.type
+      dbEvent.createdAt = event.createdAt
+      dbEvent.userId = event.userId
+      if (event.xUserId) dbEvent.xUserId = event.xUserId
+      if (event.xCommunityId) dbEvent.xCommunityId = event.xCommunityId
+      if (event.contributionId) dbEvent.contributionId = event.contributionId
+      if (event.transactionId) dbEvent.transactionId = event.transactionId
+      if (event.amount) dbEvent.amount = event.amount
+      await dbEvent.save()
+    }
+  }
+}
+export const eventProtocol = new EventProtocolEmitter()
diff --git a/backend/src/event/EventProtocolType.ts b/backend/src/event/EventProtocolType.ts
new file mode 100644
index 000000000..0f61f787a
--- /dev/null
+++ b/backend/src/event/EventProtocolType.ts
@@ -0,0 +1,24 @@
+export enum EventProtocolType {
+  BASIC = 'BASIC',
+  VISIT_GRADIDO = 'VISIT_GRADIDO',
+  REGISTER = 'REGISTER',
+  REDEEM_REGISTER = 'REDEEM_REGISTER',
+  INACTIVE_ACCOUNT = 'INACTIVE_ACCOUNT',
+  SEND_CONFIRMATION_EMAIL = 'SEND_CONFIRMATION_EMAIL',
+  CONFIRM_EMAIL = 'CONFIRM_EMAIL',
+  REGISTER_EMAIL_KLICKTIPP = 'REGISTER_EMAIL_KLICKTIPP',
+  LOGIN = 'LOGIN',
+  REDEEM_LOGIN = 'REDEEM_LOGIN',
+  ACTIVATE_ACCOUNT = 'ACTIVATE_ACCOUNT',
+  PASSWORD_CHANGE = 'PASSWORD_CHANGE',
+  TRANSACTION_SEND = 'TRANSACTION_SEND',
+  TRANSACTION_SEND_REDEEM = 'TRANSACTION_SEND_REDEEM',
+  TRANSACTION_REPEATE_REDEEM = 'TRANSACTION_REPEATE_REDEEM',
+  TRANSACTION_CREATION = 'TRANSACTION_CREATION',
+  TRANSACTION_RECEIVE = 'TRANSACTION_RECEIVE',
+  TRANSACTION_RECEIVE_REDEEM = 'TRANSACTION_RECEIVE_REDEEM',
+  CONTRIBUTION_CREATE = 'CONTRIBUTION_CREATE',
+  CONTRIBUTION_CONFIRM = 'CONTRIBUTION_CONFIRM',
+  CONTRIBUTION_LINK_DEFINE = 'CONTRIBUTION_LINK_DEFINE',
+  CONTRIBUTION_LINK_ACTIVATE_REDEEM = 'CONTRIBUTION_LINK_ACTIVATE_REDEEM',
+}
diff --git a/backend/src/graphql/arg/CreatePendingCreationArgs.ts b/backend/src/graphql/arg/AdminCreateContributionArgs.ts
similarity index 85%
rename from backend/src/graphql/arg/CreatePendingCreationArgs.ts
rename to backend/src/graphql/arg/AdminCreateContributionArgs.ts
index 11c345465..b09edea32 100644
--- a/backend/src/graphql/arg/CreatePendingCreationArgs.ts
+++ b/backend/src/graphql/arg/AdminCreateContributionArgs.ts
@@ -3,7 +3,7 @@ import Decimal from 'decimal.js-light'
 
 @InputType()
 @ArgsType()
-export default class CreatePendingCreationArgs {
+export default class AdminCreateContributionArgs {
   @Field(() => String)
   email: string
 
diff --git a/backend/src/graphql/arg/UpdatePendingCreationArgs.ts b/backend/src/graphql/arg/AdminUpdateContributionArgs.ts
similarity index 85%
rename from backend/src/graphql/arg/UpdatePendingCreationArgs.ts
rename to backend/src/graphql/arg/AdminUpdateContributionArgs.ts
index 691d73154..392365b38 100644
--- a/backend/src/graphql/arg/UpdatePendingCreationArgs.ts
+++ b/backend/src/graphql/arg/AdminUpdateContributionArgs.ts
@@ -2,7 +2,7 @@ import { ArgsType, Field, Int } from 'type-graphql'
 import Decimal from 'decimal.js-light'
 
 @ArgsType()
-export default class UpdatePendingCreationArgs {
+export default class AdminUpdateContributionArgs {
   @Field(() => Int)
   id: number
 
diff --git a/backend/src/graphql/arg/ContributionArgs.ts b/backend/src/graphql/arg/ContributionArgs.ts
new file mode 100644
index 000000000..2fa1c5ced
--- /dev/null
+++ b/backend/src/graphql/arg/ContributionArgs.ts
@@ -0,0 +1,15 @@
+import { ArgsType, Field, InputType } from 'type-graphql'
+import Decimal from 'decimal.js-light'
+
+@InputType()
+@ArgsType()
+export default class ContributionArgs {
+  @Field(() => Decimal)
+  amount: Decimal
+
+  @Field(() => String)
+  memo: string
+
+  @Field(() => String)
+  creationDate: string
+}
diff --git a/backend/src/graphql/arg/ContributionLinkArgs.ts b/backend/src/graphql/arg/ContributionLinkArgs.ts
new file mode 100644
index 000000000..7344a28ff
--- /dev/null
+++ b/backend/src/graphql/arg/ContributionLinkArgs.ts
@@ -0,0 +1,29 @@
+import { ArgsType, Field, Int } from 'type-graphql'
+import Decimal from 'decimal.js-light'
+
+@ArgsType()
+export default class ContributionLinkArgs {
+  @Field(() => Decimal)
+  amount: Decimal
+
+  @Field(() => String)
+  name: string
+
+  @Field(() => String)
+  memo: string
+
+  @Field(() => String)
+  cycle: string
+
+  @Field(() => String, { nullable: true })
+  validFrom?: string | null
+
+  @Field(() => String, { nullable: true })
+  validTo?: string | null
+
+  @Field(() => Decimal, { nullable: true })
+  maxAmountPerMonth: Decimal | null
+
+  @Field(() => Int)
+  maxPerCycle: number
+}
diff --git a/backend/src/graphql/enum/ContributionCycleType.ts b/backend/src/graphql/enum/ContributionCycleType.ts
new file mode 100644
index 000000000..5fe494a02
--- /dev/null
+++ b/backend/src/graphql/enum/ContributionCycleType.ts
@@ -0,0 +1,28 @@
+import { registerEnumType } from 'type-graphql'
+
+export enum ContributionCycleType {
+  ONCE = 'once',
+  HOUR = 'hour',
+  TWO_HOURS = 'two_hours',
+  FOUR_HOURS = 'four_hours',
+  EIGHT_HOURS = 'eight_hours',
+  HALF_DAY = 'half_day',
+  DAY = 'day',
+  TWO_DAYS = 'two_days',
+  THREE_DAYS = 'three_days',
+  FOUR_DAYS = 'four_days',
+  FIVE_DAYS = 'five_days',
+  SIX_DAYS = 'six_days',
+  WEEK = 'week',
+  TWO_WEEKS = 'two_weeks',
+  MONTH = 'month',
+  TWO_MONTH = 'two_month',
+  QUARTER = 'quarter',
+  HALF_YEAR = 'half_year',
+  YEAR = 'year',
+}
+
+registerEnumType(ContributionCycleType, {
+  name: 'ContributionCycleType', // this one is mandatory
+  description: 'Name of the Type of the ContributionCycle', // this one is optional
+})
diff --git a/backend/src/graphql/model/CreatePendingCreations.ts b/backend/src/graphql/model/AdminCreateContributions.ts
similarity index 54%
rename from backend/src/graphql/model/CreatePendingCreations.ts
rename to backend/src/graphql/model/AdminCreateContributions.ts
index 8d5bcef2c..aa402733a 100644
--- a/backend/src/graphql/model/CreatePendingCreations.ts
+++ b/backend/src/graphql/model/AdminCreateContributions.ts
@@ -1,19 +1,19 @@
 import { ObjectType, Field } from 'type-graphql'
 
 @ObjectType()
-export class CreatePendingCreations {
+export class AdminCreateContributions {
   constructor() {
     this.success = false
-    this.successfulCreation = []
-    this.failedCreation = []
+    this.successfulContribution = []
+    this.failedContribution = []
   }
 
   @Field(() => Boolean)
   success: boolean
 
   @Field(() => [String])
-  successfulCreation: string[]
+  successfulContribution: string[]
 
   @Field(() => [String])
-  failedCreation: string[]
+  failedContribution: string[]
 }
diff --git a/backend/src/graphql/model/UpdatePendingCreation.ts b/backend/src/graphql/model/AdminUpdateContribution.ts
similarity index 87%
rename from backend/src/graphql/model/UpdatePendingCreation.ts
rename to backend/src/graphql/model/AdminUpdateContribution.ts
index e19e1e064..e824975a4 100644
--- a/backend/src/graphql/model/UpdatePendingCreation.ts
+++ b/backend/src/graphql/model/AdminUpdateContribution.ts
@@ -2,7 +2,7 @@ import { ObjectType, Field } from 'type-graphql'
 import Decimal from 'decimal.js-light'
 
 @ObjectType()
-export class UpdatePendingCreation {
+export class AdminUpdateContribution {
   @Field(() => Date)
   date: Date
 
diff --git a/backend/src/graphql/model/Contribution.ts b/backend/src/graphql/model/Contribution.ts
new file mode 100644
index 000000000..aa878990c
--- /dev/null
+++ b/backend/src/graphql/model/Contribution.ts
@@ -0,0 +1,64 @@
+import { ObjectType, Field, Int } from 'type-graphql'
+import Decimal from 'decimal.js-light'
+import { Contribution as dbContribution } from '@entity/Contribution'
+import { User } from './User'
+
+@ObjectType()
+export class Contribution {
+  constructor(contribution: dbContribution, user: User) {
+    this.id = contribution.id
+    this.firstName = user ? user.firstName : null
+    this.lastName = user ? user.lastName : null
+    this.amount = contribution.amount
+    this.memo = contribution.memo
+    this.createdAt = contribution.createdAt
+    this.deletedAt = contribution.deletedAt
+    this.confirmedAt = contribution.confirmedAt
+    this.confirmedBy = contribution.confirmedBy
+    this.contributionDate = contribution.contributionDate
+  }
+
+  @Field(() => Number)
+  id: number
+
+  @Field(() => String, { nullable: true })
+  firstName: string | null
+
+  @Field(() => String, { nullable: true })
+  lastName: string | null
+
+  @Field(() => Decimal)
+  amount: Decimal
+
+  @Field(() => String)
+  memo: string
+
+  @Field(() => Date)
+  createdAt: Date
+
+  @Field(() => Date, { nullable: true })
+  deletedAt: Date | null
+
+  @Field(() => Date, { nullable: true })
+  confirmedAt: Date | null
+
+  @Field(() => Number, { nullable: true })
+  confirmedBy: number | null
+
+  @Field(() => Date)
+  contributionDate: Date
+}
+
+@ObjectType()
+export class ContributionListResult {
+  constructor(count: number, list: Contribution[]) {
+    this.contributionCount = count
+    this.contributionList = list
+  }
+
+  @Field(() => Int)
+  contributionCount: number
+
+  @Field(() => [Contribution])
+  contributionList: Contribution[]
+}
diff --git a/backend/src/graphql/model/ContributionLink.ts b/backend/src/graphql/model/ContributionLink.ts
new file mode 100644
index 000000000..9fe9eccd6
--- /dev/null
+++ b/backend/src/graphql/model/ContributionLink.ts
@@ -0,0 +1,62 @@
+import { ObjectType, Field, Int } from 'type-graphql'
+import Decimal from 'decimal.js-light'
+import { ContributionLink as dbContributionLink } from '@entity/ContributionLink'
+import CONFIG from '@/config'
+
+@ObjectType()
+export class ContributionLink {
+  constructor(contributionLink: dbContributionLink) {
+    this.id = contributionLink.id
+    this.amount = contributionLink.amount
+    this.name = contributionLink.name
+    this.memo = contributionLink.memo
+    this.createdAt = contributionLink.createdAt
+    this.deletedAt = contributionLink.deletedAt
+    this.validFrom = contributionLink.validFrom
+    this.validTo = contributionLink.validTo
+    this.maxAmountPerMonth = contributionLink.maxAmountPerMonth
+    this.cycle = contributionLink.cycle
+    this.maxPerCycle = contributionLink.maxPerCycle
+    this.code = contributionLink.code
+    this.link = CONFIG.COMMUNITY_REDEEM_CONTRIBUTION_URL.replace(/{code}/g, this.code)
+  }
+
+  @Field(() => Number)
+  id: number
+
+  @Field(() => Decimal)
+  amount: Decimal
+
+  @Field(() => String)
+  name: string
+
+  @Field(() => String)
+  memo: string
+
+  @Field(() => String)
+  code: string
+
+  @Field(() => String)
+  link: string
+
+  @Field(() => Date)
+  createdAt: Date
+
+  @Field(() => Date, { nullable: true })
+  deletedAt: Date | null
+
+  @Field(() => Date, { nullable: true })
+  validFrom: Date | null
+
+  @Field(() => Date, { nullable: true })
+  validTo: Date | null
+
+  @Field(() => Decimal, { nullable: true })
+  maxAmountPerMonth: Decimal | null
+
+  @Field(() => String)
+  cycle: string
+
+  @Field(() => Int)
+  maxPerCycle: number
+}
diff --git a/backend/src/graphql/model/ContributionLinkList.ts b/backend/src/graphql/model/ContributionLinkList.ts
new file mode 100644
index 000000000..412d0bf7b
--- /dev/null
+++ b/backend/src/graphql/model/ContributionLinkList.ts
@@ -0,0 +1,11 @@
+import { ObjectType, Field } from 'type-graphql'
+import { ContributionLink } from '@model/ContributionLink'
+
+@ObjectType()
+export class ContributionLinkList {
+  @Field(() => [ContributionLink])
+  links: ContributionLink[]
+
+  @Field(() => Number)
+  count: number
+}
diff --git a/backend/src/graphql/model/PendingCreation.ts b/backend/src/graphql/model/PendingCreation.ts
deleted file mode 100644
index 500ba6f6b..000000000
--- a/backend/src/graphql/model/PendingCreation.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import { ObjectType, Field, Int } from 'type-graphql'
-import Decimal from 'decimal.js-light'
-
-@ObjectType()
-export class PendingCreation {
-  @Field(() => String)
-  firstName: string
-
-  @Field(() => Int)
-  id?: number
-
-  @Field(() => String)
-  lastName: string
-
-  @Field(() => Number)
-  userId: number
-
-  @Field(() => String)
-  email: string
-
-  @Field(() => Date)
-  date: Date
-
-  @Field(() => String)
-  memo: string
-
-  @Field(() => Decimal)
-  amount: Decimal
-
-  @Field(() => Number)
-  moderator: number
-
-  @Field(() => [Decimal])
-  creation: Decimal[]
-}
diff --git a/backend/src/graphql/model/UnconfirmedContribution.ts b/backend/src/graphql/model/UnconfirmedContribution.ts
new file mode 100644
index 000000000..1d697a971
--- /dev/null
+++ b/backend/src/graphql/model/UnconfirmedContribution.ts
@@ -0,0 +1,49 @@
+import { ObjectType, Field, Int } from 'type-graphql'
+import Decimal from 'decimal.js-light'
+import { Contribution } from '@entity/Contribution'
+import { User } from '@entity/User'
+
+@ObjectType()
+export class UnconfirmedContribution {
+  constructor(contribution: Contribution, user: User, creations: Decimal[]) {
+    this.id = contribution.id
+    this.userId = contribution.userId
+    this.amount = contribution.amount
+    this.memo = contribution.memo
+    this.date = contribution.contributionDate
+    this.firstName = user ? user.firstName : ''
+    this.lastName = user ? user.lastName : ''
+    this.email = user ? user.email : ''
+    this.creation = creations
+  }
+
+  @Field(() => String)
+  firstName: string
+
+  @Field(() => Int)
+  id?: number
+
+  @Field(() => String)
+  lastName: string
+
+  @Field(() => Number)
+  userId: number
+
+  @Field(() => String)
+  email: string
+
+  @Field(() => Date)
+  date: Date
+
+  @Field(() => String)
+  memo: string
+
+  @Field(() => Decimal)
+  amount: Decimal
+
+  @Field(() => Number, { nullable: true })
+  moderator: number | null
+
+  @Field(() => [Decimal])
+  creation: Decimal[]
+}
diff --git a/backend/src/graphql/model/User.ts b/backend/src/graphql/model/User.ts
index 86c56312f..0642be630 100644
--- a/backend/src/graphql/model/User.ts
+++ b/backend/src/graphql/model/User.ts
@@ -1,10 +1,12 @@
 import { ObjectType, Field } from 'type-graphql'
 import { KlickTipp } from './KlickTipp'
 import { User as dbUser } from '@entity/User'
+import Decimal from 'decimal.js-light'
+import { FULL_CREATION_AVAILABLE } from '../resolver/const/const'
 
 @ObjectType()
 export class User {
-  constructor(user: dbUser) {
+  constructor(user: dbUser, creation: Decimal[] = FULL_CREATION_AVAILABLE) {
     this.id = user.id
     this.email = user.email
     this.firstName = user.firstName
@@ -17,6 +19,7 @@ export class User {
     this.isAdmin = user.isAdmin
     this.klickTipp = null
     this.hasElopage = null
+    this.creation = creation
   }
 
   @Field(() => Number)
@@ -64,4 +67,7 @@ export class User {
 
   @Field(() => Boolean, { nullable: true })
   hasElopage: boolean | null
+
+  @Field(() => [Decimal])
+  creation: Decimal[]
 }
diff --git a/backend/src/graphql/model/UserAdmin.ts b/backend/src/graphql/model/UserAdmin.ts
index 8a1459c0f..cf3663e70 100644
--- a/backend/src/graphql/model/UserAdmin.ts
+++ b/backend/src/graphql/model/UserAdmin.ts
@@ -14,6 +14,7 @@ export class UserAdmin {
     this.hasElopage = hasElopage
     this.deletedAt = user.deletedAt
     this.emailConfirmationSend = emailConfirmationSend
+    this.isAdmin = user.isAdmin
   }
 
   @Field(() => Number)
@@ -42,6 +43,9 @@ export class UserAdmin {
 
   @Field(() => String, { nullable: true })
   emailConfirmationSend?: string
+
+  @Field(() => Date, { nullable: true })
+  isAdmin: Date | null
 }
 
 @ObjectType()
diff --git a/backend/src/graphql/resolver/AdminResolver.test.ts b/backend/src/graphql/resolver/AdminResolver.test.ts
index acf880efb..7b1c6ffcd 100644
--- a/backend/src/graphql/resolver/AdminResolver.test.ts
+++ b/backend/src/graphql/resolver/AdminResolver.test.ts
@@ -13,27 +13,33 @@ import { peterLustig } from '@/seeds/users/peter-lustig'
 import { stephenHawking } from '@/seeds/users/stephen-hawking'
 import { garrickOllivander } from '@/seeds/users/garrick-ollivander'
 import {
+  setUserRole,
   deleteUser,
   unDeleteUser,
-  createPendingCreation,
-  createPendingCreations,
-  updatePendingCreation,
-  deletePendingCreation,
-  confirmPendingCreation,
+  adminCreateContribution,
+  adminCreateContributions,
+  adminUpdateContribution,
+  adminDeleteContribution,
+  confirmContribution,
+  createContributionLink,
+  deleteContributionLink,
+  updateContributionLink,
 } from '@/seeds/graphql/mutations'
 import {
-  getPendingCreations,
+  listUnconfirmedContributions,
   login,
   searchUsers,
   listTransactionLinksAdmin,
+  listContributionLinks,
 } from '@/seeds/graphql/queries'
 import { GraphQLError } from 'graphql'
 import { User } from '@entity/User'
 /* eslint-disable-next-line @typescript-eslint/no-unused-vars */
 import { sendAccountActivationEmail } from '@/mailer/sendAccountActivationEmail'
 import Decimal from 'decimal.js-light'
-import { AdminPendingCreation } from '@entity/AdminPendingCreation'
+import { Contribution } from '@entity/Contribution'
 import { Transaction as DbTransaction } from '@entity/Transaction'
+import { ContributionLink as DbContributionLink } from '@entity/ContributionLink'
 
 // mock account activation email to avoid console spam
 jest.mock('@/mailer/sendAccountActivationEmail', () => {
@@ -61,9 +67,164 @@ afterAll(async () => {
 
 let admin: User
 let user: User
-let creation: AdminPendingCreation | void
+let creation: Contribution | void
 
 describe('AdminResolver', () => {
+  describe('set user role', () => {
+    describe('unauthenticated', () => {
+      it('returns an error', async () => {
+        await expect(
+          mutate({ mutation: setUserRole, variables: { userId: 1, isAdmin: true } }),
+        ).resolves.toEqual(
+          expect.objectContaining({
+            errors: [new GraphQLError('401 Unauthorized')],
+          }),
+        )
+      })
+    })
+
+    describe('authenticated', () => {
+      describe('without admin rights', () => {
+        beforeAll(async () => {
+          user = await userFactory(testEnv, bibiBloxberg)
+          await query({
+            query: login,
+            variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
+          })
+        })
+
+        afterAll(async () => {
+          await cleanDB()
+          resetToken()
+        })
+
+        it('returns an error', async () => {
+          await expect(
+            mutate({ mutation: setUserRole, variables: { userId: user.id + 1, isAdmin: true } }),
+          ).resolves.toEqual(
+            expect.objectContaining({
+              errors: [new GraphQLError('401 Unauthorized')],
+            }),
+          )
+        })
+      })
+
+      describe('with admin rights', () => {
+        beforeAll(async () => {
+          admin = await userFactory(testEnv, peterLustig)
+          await query({
+            query: login,
+            variables: { email: 'peter@lustig.de', password: 'Aa12345_' },
+          })
+        })
+
+        afterAll(async () => {
+          await cleanDB()
+          resetToken()
+        })
+
+        describe('user to get a new role does not exist', () => {
+          it('throws an error', async () => {
+            await expect(
+              mutate({ mutation: setUserRole, variables: { userId: admin.id + 1, isAdmin: true } }),
+            ).resolves.toEqual(
+              expect.objectContaining({
+                errors: [new GraphQLError(`Could not find user with userId: ${admin.id + 1}`)],
+              }),
+            )
+          })
+        })
+
+        describe('change role with success', () => {
+          beforeAll(async () => {
+            user = await userFactory(testEnv, bibiBloxberg)
+          })
+
+          describe('user gets new role', () => {
+            describe('to admin', () => {
+              it('returns date string', async () => {
+                const result = await mutate({
+                  mutation: setUserRole,
+                  variables: { userId: user.id, isAdmin: true },
+                })
+                expect(result).toEqual(
+                  expect.objectContaining({
+                    data: {
+                      setUserRole: expect.any(String),
+                    },
+                  }),
+                )
+                expect(new Date(result.data.setUserRole)).toEqual(expect.any(Date))
+              })
+            })
+
+            describe('to usual user', () => {
+              it('returns null', async () => {
+                await expect(
+                  mutate({ mutation: setUserRole, variables: { userId: user.id, isAdmin: false } }),
+                ).resolves.toEqual(
+                  expect.objectContaining({
+                    data: {
+                      setUserRole: null,
+                    },
+                  }),
+                )
+              })
+            })
+          })
+        })
+
+        describe('change role with error', () => {
+          describe('is own role', () => {
+            it('throws an error', async () => {
+              await expect(
+                mutate({ mutation: setUserRole, variables: { userId: admin.id, isAdmin: false } }),
+              ).resolves.toEqual(
+                expect.objectContaining({
+                  errors: [new GraphQLError('Administrator can not change his own role!')],
+                }),
+              )
+            })
+          })
+
+          describe('user has already role to be set', () => {
+            describe('to admin', () => {
+              it('throws an error', async () => {
+                await mutate({
+                  mutation: setUserRole,
+                  variables: { userId: user.id, isAdmin: true },
+                })
+                await expect(
+                  mutate({ mutation: setUserRole, variables: { userId: user.id, isAdmin: true } }),
+                ).resolves.toEqual(
+                  expect.objectContaining({
+                    errors: [new GraphQLError('User is already admin!')],
+                  }),
+                )
+              })
+            })
+
+            describe('to usual user', () => {
+              it('throws an error', async () => {
+                await mutate({
+                  mutation: setUserRole,
+                  variables: { userId: user.id, isAdmin: false },
+                })
+                await expect(
+                  mutate({ mutation: setUserRole, variables: { userId: user.id, isAdmin: false } }),
+                ).resolves.toEqual(
+                  expect.objectContaining({
+                    errors: [new GraphQLError('User is already a usual user!')],
+                  }),
+                )
+              })
+            })
+          })
+        })
+      })
+    })
+  })
+
   describe('delete user', () => {
     describe('unauthenticated', () => {
       it('returns an error', async () => {
@@ -497,9 +658,9 @@ describe('AdminResolver', () => {
     }
 
     describe('unauthenticated', () => {
-      describe('createPendingCreation', () => {
+      describe('adminCreateContribution', () => {
         it('returns an error', async () => {
-          await expect(mutate({ mutation: createPendingCreation, variables })).resolves.toEqual(
+          await expect(mutate({ mutation: adminCreateContribution, variables })).resolves.toEqual(
             expect.objectContaining({
               errors: [new GraphQLError('401 Unauthorized')],
             }),
@@ -507,11 +668,11 @@ describe('AdminResolver', () => {
         })
       })
 
-      describe('createPendingCreations', () => {
+      describe('adminCreateContributions', () => {
         it('returns an error', async () => {
           await expect(
             mutate({
-              mutation: createPendingCreations,
+              mutation: adminCreateContributions,
               variables: { pendingCreations: [variables] },
             }),
           ).resolves.toEqual(
@@ -522,11 +683,11 @@ describe('AdminResolver', () => {
         })
       })
 
-      describe('updatePendingCreation', () => {
+      describe('adminUpdateContribution', () => {
         it('returns an error', async () => {
           await expect(
             mutate({
-              mutation: updatePendingCreation,
+              mutation: adminUpdateContribution,
               variables: {
                 id: 1,
                 email: 'bibi@bloxberg.de',
@@ -543,11 +704,11 @@ describe('AdminResolver', () => {
         })
       })
 
-      describe('getPendingCreations', () => {
+      describe('listUnconfirmedContributions', () => {
         it('returns an error', async () => {
           await expect(
             query({
-              query: getPendingCreations,
+              query: listUnconfirmedContributions,
             }),
           ).resolves.toEqual(
             expect.objectContaining({
@@ -557,11 +718,11 @@ describe('AdminResolver', () => {
         })
       })
 
-      describe('deletePendingCreation', () => {
+      describe('adminDeleteContribution', () => {
         it('returns an error', async () => {
           await expect(
             mutate({
-              mutation: deletePendingCreation,
+              mutation: adminDeleteContribution,
               variables: {
                 id: 1,
               },
@@ -574,11 +735,11 @@ describe('AdminResolver', () => {
         })
       })
 
-      describe('confirmPendingCreation', () => {
+      describe('confirmContribution', () => {
         it('returns an error', async () => {
           await expect(
             mutate({
-              mutation: confirmPendingCreation,
+              mutation: confirmContribution,
               variables: {
                 id: 1,
               },
@@ -607,9 +768,9 @@ describe('AdminResolver', () => {
           resetToken()
         })
 
-        describe('createPendingCreation', () => {
+        describe('adminCreateContribution', () => {
           it('returns an error', async () => {
-            await expect(mutate({ mutation: createPendingCreation, variables })).resolves.toEqual(
+            await expect(mutate({ mutation: adminCreateContribution, variables })).resolves.toEqual(
               expect.objectContaining({
                 errors: [new GraphQLError('401 Unauthorized')],
               }),
@@ -617,11 +778,11 @@ describe('AdminResolver', () => {
           })
         })
 
-        describe('createPendingCreations', () => {
+        describe('adminCreateContributions', () => {
           it('returns an error', async () => {
             await expect(
               mutate({
-                mutation: createPendingCreations,
+                mutation: adminCreateContributions,
                 variables: { pendingCreations: [variables] },
               }),
             ).resolves.toEqual(
@@ -632,11 +793,11 @@ describe('AdminResolver', () => {
           })
         })
 
-        describe('updatePendingCreation', () => {
+        describe('adminUpdateContribution', () => {
           it('returns an error', async () => {
             await expect(
               mutate({
-                mutation: updatePendingCreation,
+                mutation: adminUpdateContribution,
                 variables: {
                   id: 1,
                   email: 'bibi@bloxberg.de',
@@ -653,11 +814,11 @@ describe('AdminResolver', () => {
           })
         })
 
-        describe('getPendingCreations', () => {
+        describe('listUnconfirmedContributions', () => {
           it('returns an error', async () => {
             await expect(
               query({
-                query: getPendingCreations,
+                query: listUnconfirmedContributions,
               }),
             ).resolves.toEqual(
               expect.objectContaining({
@@ -667,11 +828,11 @@ describe('AdminResolver', () => {
           })
         })
 
-        describe('deletePendingCreation', () => {
+        describe('adminDeleteContribution', () => {
           it('returns an error', async () => {
             await expect(
               mutate({
-                mutation: deletePendingCreation,
+                mutation: adminDeleteContribution,
                 variables: {
                   id: 1,
                 },
@@ -684,11 +845,11 @@ describe('AdminResolver', () => {
           })
         })
 
-        describe('confirmPendingCreation', () => {
+        describe('confirmContribution', () => {
           it('returns an error', async () => {
             await expect(
               mutate({
-                mutation: confirmPendingCreation,
+                mutation: confirmContribution,
                 variables: {
                   id: 1,
                 },
@@ -716,7 +877,7 @@ describe('AdminResolver', () => {
           resetToken()
         })
 
-        describe('createPendingCreation', () => {
+        describe('adminCreateContribution', () => {
           beforeAll(async () => {
             const now = new Date()
             creation = await creationFactory(testEnv, {
@@ -729,7 +890,9 @@ describe('AdminResolver', () => {
 
           describe('user to create for does not exist', () => {
             it('throws an error', async () => {
-              await expect(mutate({ mutation: createPendingCreation, variables })).resolves.toEqual(
+              await expect(
+                mutate({ mutation: adminCreateContribution, variables }),
+              ).resolves.toEqual(
                 expect.objectContaining({
                   errors: [new GraphQLError('Could not find user with email: bibi@bloxberg.de')],
                 }),
@@ -744,9 +907,13 @@ describe('AdminResolver', () => {
             })
 
             it('throws an error', async () => {
-              await expect(mutate({ mutation: createPendingCreation, variables })).resolves.toEqual(
+              await expect(
+                mutate({ mutation: adminCreateContribution, variables }),
+              ).resolves.toEqual(
                 expect.objectContaining({
-                  errors: [new GraphQLError('This user was deleted. Cannot make a creation.')],
+                  errors: [
+                    new GraphQLError('This user was deleted. Cannot create a contribution.'),
+                  ],
                 }),
               )
             })
@@ -759,9 +926,13 @@ describe('AdminResolver', () => {
             })
 
             it('throws an error', async () => {
-              await expect(mutate({ mutation: createPendingCreation, variables })).resolves.toEqual(
+              await expect(
+                mutate({ mutation: adminCreateContribution, variables }),
+              ).resolves.toEqual(
                 expect.objectContaining({
-                  errors: [new GraphQLError('Creation could not be saved, Email is not activated')],
+                  errors: [
+                    new GraphQLError('Contribution could not be saved, Email is not activated'),
+                  ],
                 }),
               )
             })
@@ -776,7 +947,7 @@ describe('AdminResolver', () => {
             describe('date of creation is not a date string', () => {
               it('throws an error', async () => {
                 await expect(
-                  mutate({ mutation: createPendingCreation, variables }),
+                  mutate({ mutation: adminCreateContribution, variables }),
                 ).resolves.toEqual(
                   expect.objectContaining({
                     errors: [
@@ -796,7 +967,7 @@ describe('AdminResolver', () => {
                   1,
                 ).toString()
                 await expect(
-                  mutate({ mutation: createPendingCreation, variables }),
+                  mutate({ mutation: adminCreateContribution, variables }),
                 ).resolves.toEqual(
                   expect.objectContaining({
                     errors: [
@@ -816,7 +987,7 @@ describe('AdminResolver', () => {
                   1,
                 ).toString()
                 await expect(
-                  mutate({ mutation: createPendingCreation, variables }),
+                  mutate({ mutation: adminCreateContribution, variables }),
                 ).resolves.toEqual(
                   expect.objectContaining({
                     errors: [
@@ -831,7 +1002,7 @@ describe('AdminResolver', () => {
               it('throws an error', async () => {
                 variables.creationDate = new Date().toString()
                 await expect(
-                  mutate({ mutation: createPendingCreation, variables }),
+                  mutate({ mutation: adminCreateContribution, variables }),
                 ).resolves.toEqual(
                   expect.objectContaining({
                     errors: [
@@ -848,11 +1019,11 @@ describe('AdminResolver', () => {
               it('returns an array of the open creations for the last three months', async () => {
                 variables.amount = new Decimal(200)
                 await expect(
-                  mutate({ mutation: createPendingCreation, variables }),
+                  mutate({ mutation: adminCreateContribution, variables }),
                 ).resolves.toEqual(
                   expect.objectContaining({
                     data: {
-                      createPendingCreation: [1000, 1000, 800],
+                      adminCreateContribution: [1000, 1000, 800],
                     },
                   }),
                 )
@@ -863,7 +1034,7 @@ describe('AdminResolver', () => {
               it('returns an array of the open creations for the last three months', async () => {
                 variables.amount = new Decimal(1000)
                 await expect(
-                  mutate({ mutation: createPendingCreation, variables }),
+                  mutate({ mutation: adminCreateContribution, variables }),
                 ).resolves.toEqual(
                   expect.objectContaining({
                     errors: [
@@ -878,7 +1049,7 @@ describe('AdminResolver', () => {
           })
         })
 
-        describe('createPendingCreations', () => {
+        describe('adminCreateContributions', () => {
           // at this point we have this data in DB:
           // bibi@bloxberg.de: [1000, 1000, 800]
           // peter@lustig.de: [1000, 600, 1000]
@@ -903,16 +1074,16 @@ describe('AdminResolver', () => {
           it('returns success, two successful creation and three failed creations', async () => {
             await expect(
               mutate({
-                mutation: createPendingCreations,
+                mutation: adminCreateContributions,
                 variables: { pendingCreations: massCreationVariables },
               }),
             ).resolves.toEqual(
               expect.objectContaining({
                 data: {
-                  createPendingCreations: {
+                  adminCreateContributions: {
                     success: true,
-                    successfulCreation: ['bibi@bloxberg.de', 'peter@lustig.de'],
-                    failedCreation: [
+                    successfulContribution: ['bibi@bloxberg.de', 'peter@lustig.de'],
+                    failedContribution: [
                       'stephen@hawking.uk',
                       'garrick@ollivander.com',
                       'bob@baumeister.de',
@@ -924,7 +1095,7 @@ describe('AdminResolver', () => {
           })
         })
 
-        describe('updatePendingCreation', () => {
+        describe('adminUpdateContribution', () => {
           // at this I expect to have this data in DB:
           // bibi@bloxberg.de: [1000, 1000, 300]
           // peter@lustig.de: [1000, 600, 500]
@@ -935,7 +1106,7 @@ describe('AdminResolver', () => {
             it('throws an error', async () => {
               await expect(
                 mutate({
-                  mutation: updatePendingCreation,
+                  mutation: adminUpdateContribution,
                   variables: {
                     id: 1,
                     email: 'bob@baumeister.de',
@@ -956,7 +1127,7 @@ describe('AdminResolver', () => {
             it('throws an error', async () => {
               await expect(
                 mutate({
-                  mutation: updatePendingCreation,
+                  mutation: adminUpdateContribution,
                   variables: {
                     id: 1,
                     email: 'stephen@hawking.uk',
@@ -977,7 +1148,7 @@ describe('AdminResolver', () => {
             it('throws an error', async () => {
               await expect(
                 mutate({
-                  mutation: updatePendingCreation,
+                  mutation: adminUpdateContribution,
                   variables: {
                     id: -1,
                     email: 'bibi@bloxberg.de',
@@ -988,7 +1159,7 @@ describe('AdminResolver', () => {
                 }),
               ).resolves.toEqual(
                 expect.objectContaining({
-                  errors: [new GraphQLError('No creation found to given id.')],
+                  errors: [new GraphQLError('No contribution found to given id.')],
                 }),
               )
             })
@@ -998,7 +1169,7 @@ describe('AdminResolver', () => {
             it('throws an error', async () => {
               await expect(
                 mutate({
-                  mutation: updatePendingCreation,
+                  mutation: adminUpdateContribution,
                   variables: {
                     id: creation ? creation.id : -1,
                     email: 'bibi@bloxberg.de',
@@ -1011,7 +1182,7 @@ describe('AdminResolver', () => {
                 expect.objectContaining({
                   errors: [
                     new GraphQLError(
-                      'user of the pending creation and send user does not correspond',
+                      'user of the pending contribution and send user does not correspond',
                     ),
                   ],
                 }),
@@ -1023,7 +1194,7 @@ describe('AdminResolver', () => {
             it('throws an error', async () => {
               await expect(
                 mutate({
-                  mutation: updatePendingCreation,
+                  mutation: adminUpdateContribution,
                   variables: {
                     id: creation ? creation.id : -1,
                     email: 'peter@lustig.de',
@@ -1048,7 +1219,7 @@ describe('AdminResolver', () => {
             it('returns update creation object', async () => {
               await expect(
                 mutate({
-                  mutation: updatePendingCreation,
+                  mutation: adminUpdateContribution,
                   variables: {
                     id: creation ? creation.id : -1,
                     email: 'peter@lustig.de',
@@ -1060,7 +1231,7 @@ describe('AdminResolver', () => {
               ).resolves.toEqual(
                 expect.objectContaining({
                   data: {
-                    updatePendingCreation: {
+                    adminUpdateContribution: {
                       date: expect.any(String),
                       memo: 'Danke Peter!',
                       amount: '300',
@@ -1076,7 +1247,7 @@ describe('AdminResolver', () => {
             it('returns update creation object', async () => {
               await expect(
                 mutate({
-                  mutation: updatePendingCreation,
+                  mutation: adminUpdateContribution,
                   variables: {
                     id: creation ? creation.id : -1,
                     email: 'peter@lustig.de',
@@ -1088,7 +1259,7 @@ describe('AdminResolver', () => {
               ).resolves.toEqual(
                 expect.objectContaining({
                   data: {
-                    updatePendingCreation: {
+                    adminUpdateContribution: {
                       date: expect.any(String),
                       memo: 'Das war leider zu Viel!',
                       amount: '200',
@@ -1101,16 +1272,16 @@ describe('AdminResolver', () => {
           })
         })
 
-        describe('getPendingCreations', () => {
+        describe('listUnconfirmedContributions', () => {
           it('returns four pending creations', async () => {
             await expect(
               query({
-                query: getPendingCreations,
+                query: listUnconfirmedContributions,
               }),
             ).resolves.toEqual(
               expect.objectContaining({
                 data: {
-                  getPendingCreations: expect.arrayContaining([
+                  listUnconfirmedContributions: expect.arrayContaining([
                     {
                       id: expect.any(Number),
                       firstName: 'Peter',
@@ -1162,19 +1333,19 @@ describe('AdminResolver', () => {
           })
         })
 
-        describe('deletePendingCreation', () => {
+        describe('adminDeleteContribution', () => {
           describe('creation id does not exist', () => {
             it('throws an error', async () => {
               await expect(
                 mutate({
-                  mutation: deletePendingCreation,
+                  mutation: adminDeleteContribution,
                   variables: {
                     id: -1,
                   },
                 }),
               ).resolves.toEqual(
                 expect.objectContaining({
-                  errors: [new GraphQLError('Creation not found for given id.')],
+                  errors: [new GraphQLError('Contribution not found for given id.')],
                 }),
               )
             })
@@ -1184,33 +1355,33 @@ describe('AdminResolver', () => {
             it('returns true', async () => {
               await expect(
                 mutate({
-                  mutation: deletePendingCreation,
+                  mutation: adminDeleteContribution,
                   variables: {
                     id: creation ? creation.id : -1,
                   },
                 }),
               ).resolves.toEqual(
                 expect.objectContaining({
-                  data: { deletePendingCreation: true },
+                  data: { adminDeleteContribution: true },
                 }),
               )
             })
           })
         })
 
-        describe('confirmPendingCreation', () => {
+        describe('confirmContribution', () => {
           describe('creation does not exits', () => {
             it('throws an error', async () => {
               await expect(
                 mutate({
-                  mutation: confirmPendingCreation,
+                  mutation: confirmContribution,
                   variables: {
                     id: -1,
                   },
                 }),
               ).resolves.toEqual(
                 expect.objectContaining({
-                  errors: [new GraphQLError('Creation not found to given id.')],
+                  errors: [new GraphQLError('Contribution not found to given id.')],
                 }),
               )
             })
@@ -1230,14 +1401,14 @@ describe('AdminResolver', () => {
             it('thows an error', async () => {
               await expect(
                 mutate({
-                  mutation: confirmPendingCreation,
+                  mutation: confirmContribution,
                   variables: {
                     id: creation ? creation.id : -1,
                   },
                 }),
               ).resolves.toEqual(
                 expect.objectContaining({
-                  errors: [new GraphQLError('Moderator can not confirm own pending creation')],
+                  errors: [new GraphQLError('Moderator can not confirm own contribution')],
                 }),
               )
             })
@@ -1257,14 +1428,14 @@ describe('AdminResolver', () => {
             it('returns true', async () => {
               await expect(
                 mutate({
-                  mutation: confirmPendingCreation,
+                  mutation: confirmContribution,
                   variables: {
                     id: creation ? creation.id : -1,
                   },
                 }),
               ).resolves.toEqual(
                 expect.objectContaining({
-                  data: { confirmPendingCreation: true },
+                  data: { confirmContribution: true },
                 }),
               )
             })
@@ -1282,8 +1453,8 @@ describe('AdminResolver', () => {
           })
 
           describe('confirm two creations one after the other quickly', () => {
-            let c1: AdminPendingCreation | void
-            let c2: AdminPendingCreation | void
+            let c1: Contribution | void
+            let c2: Contribution | void
 
             beforeAll(async () => {
               const now = new Date()
@@ -1304,25 +1475,25 @@ describe('AdminResolver', () => {
             // In the futrue this should not throw anymore
             it('throws an error for the second confirmation', async () => {
               const r1 = mutate({
-                mutation: confirmPendingCreation,
+                mutation: confirmContribution,
                 variables: {
                   id: c1 ? c1.id : -1,
                 },
               })
               const r2 = mutate({
-                mutation: confirmPendingCreation,
+                mutation: confirmContribution,
                 variables: {
                   id: c2 ? c2.id : -1,
                 },
               })
               await expect(r1).resolves.toEqual(
                 expect.objectContaining({
-                  data: { confirmPendingCreation: true },
+                  data: { confirmContribution: true },
                 }),
               )
               await expect(r2).resolves.toEqual(
                 expect.objectContaining({
-                  errors: [new GraphQLError('Unable to confirm creation.')],
+                  errors: [new GraphQLError('Creation was not successful.')],
                 }),
               )
             })
@@ -1593,4 +1764,544 @@ describe('AdminResolver', () => {
       })
     })
   })
+
+  describe('Contribution Links', () => {
+    const variables = {
+      amount: new Decimal(200),
+      name: 'Dokumenta 2022',
+      memo: 'Danke für deine Teilnahme an der Dokumenta 2022',
+      cycle: 'once',
+      validFrom: new Date(2022, 5, 18).toISOString(),
+      validTo: new Date(2022, 7, 14).toISOString(),
+      maxAmountPerMonth: new Decimal(200),
+      maxPerCycle: 1,
+    }
+
+    describe('unauthenticated', () => {
+      describe('createContributionLink', () => {
+        it('returns an error', async () => {
+          await expect(mutate({ mutation: createContributionLink, variables })).resolves.toEqual(
+            expect.objectContaining({
+              errors: [new GraphQLError('401 Unauthorized')],
+            }),
+          )
+        })
+      })
+
+      describe('listContributionLinks', () => {
+        it('returns an error', async () => {
+          await expect(query({ query: listContributionLinks })).resolves.toEqual(
+            expect.objectContaining({
+              errors: [new GraphQLError('401 Unauthorized')],
+            }),
+          )
+        })
+      })
+
+      describe('updateContributionLink', () => {
+        it('returns an error', async () => {
+          await expect(
+            mutate({
+              mutation: updateContributionLink,
+              variables: {
+                ...variables,
+                id: -1,
+                amount: new Decimal(400),
+                name: 'Dokumenta 2023',
+                memo: 'Danke für deine Teilnahme an der Dokumenta 2023',
+              },
+            }),
+          ).resolves.toEqual(
+            expect.objectContaining({
+              errors: [new GraphQLError('401 Unauthorized')],
+            }),
+          )
+        })
+      })
+
+      describe('deleteContributionLink', () => {
+        it('returns an error', async () => {
+          await expect(
+            mutate({ mutation: deleteContributionLink, variables: { id: -1 } }),
+          ).resolves.toEqual(
+            expect.objectContaining({
+              errors: [new GraphQLError('401 Unauthorized')],
+            }),
+          )
+        })
+      })
+    })
+
+    describe('authenticated', () => {
+      describe('without admin rights', () => {
+        beforeAll(async () => {
+          user = await userFactory(testEnv, bibiBloxberg)
+          await query({
+            query: login,
+            variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
+          })
+        })
+
+        afterAll(async () => {
+          await cleanDB()
+          resetToken()
+        })
+
+        describe('createContributionLink', () => {
+          it('returns an error', async () => {
+            await expect(mutate({ mutation: createContributionLink, variables })).resolves.toEqual(
+              expect.objectContaining({
+                errors: [new GraphQLError('401 Unauthorized')],
+              }),
+            )
+          })
+        })
+
+        describe('listContributionLinks', () => {
+          it('returns an error', async () => {
+            await expect(query({ query: listContributionLinks })).resolves.toEqual(
+              expect.objectContaining({
+                errors: [new GraphQLError('401 Unauthorized')],
+              }),
+            )
+          })
+        })
+
+        describe('updateContributionLink', () => {
+          it('returns an error', async () => {
+            await expect(
+              mutate({
+                mutation: updateContributionLink,
+                variables: {
+                  ...variables,
+                  id: -1,
+                  amount: new Decimal(400),
+                  name: 'Dokumenta 2023',
+                  memo: 'Danke für deine Teilnahme an der Dokumenta 2023',
+                },
+              }),
+            ).resolves.toEqual(
+              expect.objectContaining({
+                errors: [new GraphQLError('401 Unauthorized')],
+              }),
+            )
+          })
+        })
+
+        describe('deleteContributionLink', () => {
+          it('returns an error', async () => {
+            await expect(
+              mutate({ mutation: deleteContributionLink, variables: { id: -1 } }),
+            ).resolves.toEqual(
+              expect.objectContaining({
+                errors: [new GraphQLError('401 Unauthorized')],
+              }),
+            )
+          })
+        })
+      })
+
+      describe('with admin rights', () => {
+        beforeAll(async () => {
+          user = await userFactory(testEnv, peterLustig)
+          await query({
+            query: login,
+            variables: { email: 'peter@lustig.de', password: 'Aa12345_' },
+          })
+        })
+
+        afterAll(async () => {
+          await cleanDB()
+          resetToken()
+        })
+
+        describe('createContributionLink', () => {
+          it('returns a contribution link object', async () => {
+            await expect(mutate({ mutation: createContributionLink, variables })).resolves.toEqual(
+              expect.objectContaining({
+                data: {
+                  createContributionLink: expect.objectContaining({
+                    id: expect.any(Number),
+                    amount: '200',
+                    code: expect.stringMatching(/^[0-9a-f]{24,24}$/),
+                    link: expect.stringMatching(/^.*?\/CL-[0-9a-f]{24,24}$/),
+                    createdAt: expect.any(String),
+                    name: 'Dokumenta 2022',
+                    memo: 'Danke für deine Teilnahme an der Dokumenta 2022',
+                    validFrom: expect.any(String),
+                    validTo: expect.any(String),
+                    maxAmountPerMonth: '200',
+                    cycle: 'once',
+                    maxPerCycle: 1,
+                  }),
+                },
+              }),
+            )
+          })
+
+          it('has a contribution link stored in db', async () => {
+            const cls = await DbContributionLink.find()
+            expect(cls).toHaveLength(1)
+            expect(cls[0]).toEqual(
+              expect.objectContaining({
+                id: expect.any(Number),
+                name: 'Dokumenta 2022',
+                memo: 'Danke für deine Teilnahme an der Dokumenta 2022',
+                validFrom: new Date('2022-06-18T00:00:00.000Z'),
+                validTo: new Date('2022-08-14T00:00:00.000Z'),
+                cycle: 'once',
+                maxPerCycle: 1,
+                totalMaxCountOfContribution: null,
+                maxAccountBalance: null,
+                minGapHours: null,
+                createdAt: expect.any(Date),
+                deletedAt: null,
+                code: expect.stringMatching(/^[0-9a-f]{24,24}$/),
+                linkEnabled: true,
+                // amount: '200',
+                // maxAmountPerMonth: '200',
+              }),
+            )
+          })
+
+          it('returns an error if missing startDate', async () => {
+            await expect(
+              mutate({
+                mutation: createContributionLink,
+                variables: {
+                  ...variables,
+                  validFrom: null,
+                },
+              }),
+            ).resolves.toEqual(
+              expect.objectContaining({
+                errors: [
+                  new GraphQLError('Start-Date is not initialized. A Start-Date must be set!'),
+                ],
+              }),
+            )
+          })
+
+          it('returns an error if missing endDate', async () => {
+            await expect(
+              mutate({
+                mutation: createContributionLink,
+                variables: {
+                  ...variables,
+                  validTo: null,
+                },
+              }),
+            ).resolves.toEqual(
+              expect.objectContaining({
+                errors: [new GraphQLError('End-Date is not initialized. An End-Date must be set!')],
+              }),
+            )
+          })
+
+          it('returns an error if endDate is before startDate', async () => {
+            await expect(
+              mutate({
+                mutation: createContributionLink,
+                variables: {
+                  ...variables,
+                  validFrom: new Date('2022-06-18T00:00:00.001Z').toISOString(),
+                  validTo: new Date('2022-06-18T00:00:00.000Z').toISOString(),
+                },
+              }),
+            ).resolves.toEqual(
+              expect.objectContaining({
+                errors: [
+                  new GraphQLError(`The value of validFrom must before or equals the validTo!`),
+                ],
+              }),
+            )
+          })
+
+          it('returns an error if name is an empty string', async () => {
+            await expect(
+              mutate({
+                mutation: createContributionLink,
+                variables: {
+                  ...variables,
+                  name: '',
+                },
+              }),
+            ).resolves.toEqual(
+              expect.objectContaining({
+                errors: [new GraphQLError('The name must be initialized!')],
+              }),
+            )
+          })
+
+          it('returns an error if name is shorter than 5 characters', async () => {
+            await expect(
+              mutate({
+                mutation: createContributionLink,
+                variables: {
+                  ...variables,
+                  name: '123',
+                },
+              }),
+            ).resolves.toEqual(
+              expect.objectContaining({
+                errors: [
+                  new GraphQLError(
+                    `The value of 'name' with a length of 3 did not fulfill the requested bounderies min=5 and max=100`,
+                  ),
+                ],
+              }),
+            )
+          })
+
+          it('returns an error if name is longer than 100 characters', async () => {
+            await expect(
+              mutate({
+                mutation: createContributionLink,
+                variables: {
+                  ...variables,
+                  name: '12345678901234567892123456789312345678941234567895123456789612345678971234567898123456789912345678901',
+                },
+              }),
+            ).resolves.toEqual(
+              expect.objectContaining({
+                errors: [
+                  new GraphQLError(
+                    `The value of 'name' with a length of 101 did not fulfill the requested bounderies min=5 and max=100`,
+                  ),
+                ],
+              }),
+            )
+          })
+
+          it('returns an error if memo is an empty string', async () => {
+            await expect(
+              mutate({
+                mutation: createContributionLink,
+                variables: {
+                  ...variables,
+                  memo: '',
+                },
+              }),
+            ).resolves.toEqual(
+              expect.objectContaining({
+                errors: [new GraphQLError('The memo must be initialized!')],
+              }),
+            )
+          })
+
+          it('returns an error if memo is shorter than 5 characters', async () => {
+            await expect(
+              mutate({
+                mutation: createContributionLink,
+                variables: {
+                  ...variables,
+                  memo: '123',
+                },
+              }),
+            ).resolves.toEqual(
+              expect.objectContaining({
+                errors: [
+                  new GraphQLError(
+                    `The value of 'memo' with a length of 3 did not fulfill the requested bounderies min=5 and max=255`,
+                  ),
+                ],
+              }),
+            )
+          })
+
+          it('returns an error if memo is longer than 255 characters', async () => {
+            await expect(
+              mutate({
+                mutation: createContributionLink,
+                variables: {
+                  ...variables,
+                  memo: '1234567890123456789212345678931234567894123456789512345678961234567897123456789812345678991234567890123456789012345678921234567893123456789412345678951234567896123456789712345678981234567899123456789012345678901234567892123456789312345678941234567895123456',
+                },
+              }),
+            ).resolves.toEqual(
+              expect.objectContaining({
+                errors: [
+                  new GraphQLError(
+                    `The value of 'memo' with a length of 256 did not fulfill the requested bounderies min=5 and max=255`,
+                  ),
+                ],
+              }),
+            )
+          })
+
+          it('returns an error if amount is not positive', async () => {
+            await expect(
+              mutate({
+                mutation: createContributionLink,
+                variables: {
+                  ...variables,
+                  amount: new Decimal(0),
+                },
+              }),
+            ).resolves.toEqual(
+              expect.objectContaining({
+                errors: [
+                  new GraphQLError('The amount=0 must be initialized with a positiv value!'),
+                ],
+              }),
+            )
+          })
+        })
+
+        describe('listContributionLinks', () => {
+          describe('one link in DB', () => {
+            it('returns the link and count 1', async () => {
+              await expect(query({ query: listContributionLinks })).resolves.toEqual(
+                expect.objectContaining({
+                  data: {
+                    listContributionLinks: {
+                      links: expect.arrayContaining([
+                        expect.objectContaining({
+                          amount: '200',
+                          code: expect.stringMatching(/^[0-9a-f]{24,24}$/),
+                          link: expect.stringMatching(/^.*?\/CL-[0-9a-f]{24,24}$/),
+                          createdAt: expect.any(String),
+                          name: 'Dokumenta 2022',
+                          memo: 'Danke für deine Teilnahme an der Dokumenta 2022',
+                          validFrom: expect.any(String),
+                          validTo: expect.any(String),
+                          maxAmountPerMonth: '200',
+                          cycle: 'once',
+                          maxPerCycle: 1,
+                        }),
+                      ]),
+                      count: 1,
+                    },
+                  },
+                }),
+              )
+            })
+          })
+        })
+
+        describe('updateContributionLink', () => {
+          describe('no valid id', () => {
+            it('returns an error', async () => {
+              await expect(
+                mutate({
+                  mutation: updateContributionLink,
+                  variables: {
+                    ...variables,
+                    id: -1,
+                    amount: new Decimal(400),
+                    name: 'Dokumenta 2023',
+                    memo: 'Danke für deine Teilnahme an der Dokumenta 2023',
+                  },
+                }),
+              ).resolves.toEqual(
+                expect.objectContaining({
+                  errors: [new GraphQLError('Contribution Link not found to given id.')],
+                }),
+              )
+            })
+          })
+
+          describe('valid id', () => {
+            let linkId: number
+            beforeAll(async () => {
+              const links = await query({ query: listContributionLinks })
+              linkId = links.data.listContributionLinks.links[0].id
+            })
+
+            it('returns updated contribution link object', async () => {
+              await expect(
+                mutate({
+                  mutation: updateContributionLink,
+                  variables: {
+                    ...variables,
+                    id: linkId,
+                    amount: new Decimal(400),
+                    name: 'Dokumenta 2023',
+                    memo: 'Danke für deine Teilnahme an der Dokumenta 2023',
+                  },
+                }),
+              ).resolves.toEqual(
+                expect.objectContaining({
+                  data: {
+                    updateContributionLink: {
+                      id: linkId,
+                      amount: '400',
+                      code: expect.stringMatching(/^[0-9a-f]{24,24}$/),
+                      link: expect.stringMatching(/^.*?\/CL-[0-9a-f]{24,24}$/),
+                      createdAt: expect.any(String),
+                      name: 'Dokumenta 2023',
+                      memo: 'Danke für deine Teilnahme an der Dokumenta 2023',
+                      validFrom: expect.any(String),
+                      validTo: expect.any(String),
+                      maxAmountPerMonth: '200',
+                      cycle: 'once',
+                      maxPerCycle: 1,
+                    },
+                  },
+                }),
+              )
+            })
+
+            it('updated the DB record', async () => {
+              await expect(DbContributionLink.findOne(linkId)).resolves.toEqual(
+                expect.objectContaining({
+                  id: linkId,
+                  name: 'Dokumenta 2023',
+                  memo: 'Danke für deine Teilnahme an der Dokumenta 2023',
+                  // amount: '400',
+                }),
+              )
+            })
+          })
+        })
+
+        describe('deleteContributionLink', () => {
+          describe('no valid id', () => {
+            it('returns an error', async () => {
+              await expect(
+                mutate({ mutation: deleteContributionLink, variables: { id: -1 } }),
+              ).resolves.toEqual(
+                expect.objectContaining({
+                  errors: [new GraphQLError('Contribution Link not found to given id.')],
+                }),
+              )
+            })
+          })
+
+          describe('valid id', () => {
+            let linkId: number
+            beforeAll(async () => {
+              const links = await query({ query: listContributionLinks })
+              linkId = links.data.listContributionLinks.links[0].id
+            })
+
+            it('returns a date string', async () => {
+              await expect(
+                mutate({ mutation: deleteContributionLink, variables: { id: linkId } }),
+              ).resolves.toEqual(
+                expect.objectContaining({
+                  data: {
+                    deleteContributionLink: expect.any(String),
+                  },
+                }),
+              )
+            })
+
+            it('does not list this contribution link anymore', async () => {
+              await expect(query({ query: listContributionLinks })).resolves.toEqual(
+                expect.objectContaining({
+                  data: {
+                    listContributionLinks: {
+                      links: [],
+                      count: 0,
+                    },
+                  },
+                }),
+              )
+            })
+          })
+        })
+      })
+    })
+  })
 })
diff --git a/backend/src/graphql/resolver/AdminResolver.ts b/backend/src/graphql/resolver/AdminResolver.ts
index 4c94e48c8..84ae09cf8 100644
--- a/backend/src/graphql/resolver/AdminResolver.ts
+++ b/backend/src/graphql/resolver/AdminResolver.ts
@@ -1,4 +1,5 @@
 import { Context, getUser } from '@/server/context'
+import { backendLogger as logger } from '@/server/logger'
 import { Resolver, Query, Arg, Args, Authorized, Mutation, Ctx, Int } from 'type-graphql'
 import {
   getCustomRepository,
@@ -11,21 +12,25 @@ import {
   FindOperator,
 } from '@dbTools/typeorm'
 import { UserAdmin, SearchUsersResult } from '@model/UserAdmin'
-import { PendingCreation } from '@model/PendingCreation'
-import { CreatePendingCreations } from '@model/CreatePendingCreations'
-import { UpdatePendingCreation } from '@model/UpdatePendingCreation'
+import { UnconfirmedContribution } from '@model/UnconfirmedContribution'
+import { AdminCreateContributions } from '@model/AdminCreateContributions'
+import { AdminUpdateContribution } from '@model/AdminUpdateContribution'
+import { ContributionLink } from '@model/ContributionLink'
+import { ContributionLinkList } from '@model/ContributionLinkList'
 import { RIGHTS } from '@/auth/RIGHTS'
 import { UserRepository } from '@repository/User'
-import CreatePendingCreationArgs from '@arg/CreatePendingCreationArgs'
-import UpdatePendingCreationArgs from '@arg/UpdatePendingCreationArgs'
+import AdminCreateContributionArgs from '@arg/AdminCreateContributionArgs'
+import AdminUpdateContributionArgs from '@arg/AdminUpdateContributionArgs'
 import SearchUsersArgs from '@arg/SearchUsersArgs'
+import ContributionLinkArgs from '@arg/ContributionLinkArgs'
 import { Transaction as DbTransaction } from '@entity/Transaction'
+import { ContributionLink as DbContributionLink } from '@entity/ContributionLink'
 import { Transaction } from '@model/Transaction'
 import { TransactionLink, TransactionLinkResult } from '@model/TransactionLink'
 import { TransactionLink as dbTransactionLink } from '@entity/TransactionLink'
 import { TransactionRepository } from '@repository/Transaction'
 import { calculateDecay } from '@/util/decay'
-import { AdminPendingCreation } from '@entity/AdminPendingCreation'
+import { Contribution } from '@entity/Contribution'
 import { hasElopageBuys } from '@/util/hasElopageBuys'
 import { LoginEmailOptIn } from '@entity/LoginEmailOptIn'
 import { User as dbUser } from '@entity/User'
@@ -39,12 +44,25 @@ import { Order } from '@enum/Order'
 import { communityUser } from '@/util/communityUser'
 import { checkOptInCode, activationLink, printTimeDuration } from './UserResolver'
 import { sendAccountActivationEmail } from '@/mailer/sendAccountActivationEmail'
+import { transactionLinkCode as contributionLinkCode } from './TransactionLinkResolver'
 import CONFIG from '@/config'
+import {
+  getUserCreation,
+  getUserCreations,
+  validateContribution,
+  isStartEndDateValid,
+  updateCreations,
+} from './util/creations'
+import {
+  CONTRIBUTIONLINK_NAME_MAX_CHARS,
+  CONTRIBUTIONLINK_NAME_MIN_CHARS,
+  FULL_CREATION_AVAILABLE,
+  MEMO_MAX_CHARS,
+  MEMO_MIN_CHARS,
+} from './const/const'
 
 // const EMAIL_OPT_IN_REGISTER = 1
 // const EMAIL_OPT_UNKNOWN = 3 // elopage?
-const MAX_CREATION_AMOUNT = new Decimal(1000)
-const FULL_CREATION_AVAILABLE = [MAX_CREATION_AMOUNT, MAX_CREATION_AMOUNT, MAX_CREATION_AMOUNT]
 
 @Resolver()
 export class AdminResolver {
@@ -67,7 +85,15 @@ export class AdminResolver {
       }
     }
 
-    const userFields = ['id', 'firstName', 'lastName', 'email', 'emailChecked', 'deletedAt']
+    const userFields = [
+      'id',
+      'firstName',
+      'lastName',
+      'email',
+      'emailChecked',
+      'deletedAt',
+      'isAdmin',
+    ]
     const [users, count] = await userRepository.findBySearchCriteriaPagedFiltered(
       userFields.map((fieldName) => {
         return 'user.' + fieldName
@@ -127,6 +153,48 @@ export class AdminResolver {
     }
   }
 
+  @Authorized([RIGHTS.SET_USER_ROLE])
+  @Mutation(() => Date, { nullable: true })
+  async setUserRole(
+    @Arg('userId', () => Int)
+    userId: number,
+    @Arg('isAdmin', () => Boolean)
+    isAdmin: boolean,
+    @Ctx()
+    context: Context,
+  ): Promise<Date | null> {
+    const user = await dbUser.findOne({ id: userId })
+    // user exists ?
+    if (!user) {
+      throw new Error(`Could not find user with userId: ${userId}`)
+    }
+    // administrator user changes own role?
+    const moderatorUser = getUser(context)
+    if (moderatorUser.id === userId) {
+      throw new Error('Administrator can not change his own role!')
+    }
+    // change isAdmin
+    switch (user.isAdmin) {
+      case null:
+        if (isAdmin === true) {
+          user.isAdmin = new Date()
+        } else {
+          throw new Error('User is already a usual user!')
+        }
+        break
+      default:
+        if (isAdmin === false) {
+          user.isAdmin = null
+        } else {
+          throw new Error('User is already admin!')
+        }
+        break
+    }
+    await user.save()
+    const newUser = await dbUser.findOne({ id: userId })
+    return newUser ? newUser.isAdmin : null
+  }
+
   @Authorized([RIGHTS.DELETE_USER])
   @Mutation(() => Date, { nullable: true })
   async deleteUser(
@@ -163,10 +231,10 @@ export class AdminResolver {
     return null
   }
 
-  @Authorized([RIGHTS.CREATE_PENDING_CREATION])
+  @Authorized([RIGHTS.ADMIN_CREATE_CONTRIBUTION])
   @Mutation(() => [Number])
-  async createPendingCreation(
-    @Args() { email, amount, memo, creationDate }: CreatePendingCreationArgs,
+  async adminCreateContribution(
+    @Args() { email, amount, memo, creationDate }: AdminCreateContributionArgs,
     @Ctx() context: Context,
   ): Promise<Decimal[]> {
     const user = await dbUser.findOne({ email }, { withDeleted: true })
@@ -174,61 +242,63 @@ export class AdminResolver {
       throw new Error(`Could not find user with email: ${email}`)
     }
     if (user.deletedAt) {
-      throw new Error('This user was deleted. Cannot make a creation.')
+      throw new Error('This user was deleted. Cannot create a contribution.')
     }
     if (!user.emailChecked) {
-      throw new Error('Creation could not be saved, Email is not activated')
+      throw new Error('Contribution could not be saved, Email is not activated')
     }
     const moderator = getUser(context)
+    logger.trace('moderator: ', moderator.id)
     const creations = await getUserCreation(user.id)
+    logger.trace('creations', creations)
     const creationDateObj = new Date(creationDate)
-    if (isCreationValid(creations, amount, creationDateObj)) {
-      const adminPendingCreation = AdminPendingCreation.create()
-      adminPendingCreation.userId = user.id
-      adminPendingCreation.amount = amount
-      adminPendingCreation.created = new Date()
-      adminPendingCreation.date = creationDateObj
-      adminPendingCreation.memo = memo
-      adminPendingCreation.moderator = moderator.id
+    validateContribution(creations, amount, creationDateObj)
+    const contribution = Contribution.create()
+    contribution.userId = user.id
+    contribution.amount = amount
+    contribution.createdAt = new Date()
+    contribution.contributionDate = creationDateObj
+    contribution.memo = memo
+    contribution.moderatorId = moderator.id
 
-      await AdminPendingCreation.save(adminPendingCreation)
-    }
+    logger.trace('contribution to save', contribution)
+    await Contribution.save(contribution)
     return getUserCreation(user.id)
   }
 
-  @Authorized([RIGHTS.CREATE_PENDING_CREATION])
-  @Mutation(() => CreatePendingCreations)
-  async createPendingCreations(
-    @Arg('pendingCreations', () => [CreatePendingCreationArgs])
-    pendingCreations: CreatePendingCreationArgs[],
+  @Authorized([RIGHTS.ADMIN_CREATE_CONTRIBUTIONS])
+  @Mutation(() => AdminCreateContributions)
+  async adminCreateContributions(
+    @Arg('pendingCreations', () => [AdminCreateContributionArgs])
+    contributions: AdminCreateContributionArgs[],
     @Ctx() context: Context,
-  ): Promise<CreatePendingCreations> {
+  ): Promise<AdminCreateContributions> {
     let success = false
-    const successfulCreation: string[] = []
-    const failedCreation: string[] = []
-    for (const pendingCreation of pendingCreations) {
-      await this.createPendingCreation(pendingCreation, context)
+    const successfulContribution: string[] = []
+    const failedContribution: string[] = []
+    for (const contribution of contributions) {
+      await this.adminCreateContribution(contribution, context)
         .then(() => {
-          successfulCreation.push(pendingCreation.email)
+          successfulContribution.push(contribution.email)
           success = true
         })
         .catch(() => {
-          failedCreation.push(pendingCreation.email)
+          failedContribution.push(contribution.email)
         })
     }
     return {
       success,
-      successfulCreation,
-      failedCreation,
+      successfulContribution,
+      failedContribution,
     }
   }
 
-  @Authorized([RIGHTS.UPDATE_PENDING_CREATION])
-  @Mutation(() => UpdatePendingCreation)
-  async updatePendingCreation(
-    @Args() { id, email, amount, memo, creationDate }: UpdatePendingCreationArgs,
+  @Authorized([RIGHTS.ADMIN_UPDATE_CONTRIBUTION])
+  @Mutation(() => AdminUpdateContribution)
+  async adminUpdateContribution(
+    @Args() { id, email, amount, memo, creationDate }: AdminUpdateContributionArgs,
     @Ctx() context: Context,
-  ): Promise<UpdatePendingCreation> {
+  ): Promise<AdminUpdateContribution> {
     const user = await dbUser.findOne({ email }, { withDeleted: true })
     if (!user) {
       throw new Error(`Could not find user with email: ${email}`)
@@ -239,59 +309,69 @@ export class AdminResolver {
 
     const moderator = getUser(context)
 
-    const pendingCreationToUpdate = await AdminPendingCreation.findOne({ id })
+    const contributionToUpdate = await Contribution.findOne({
+      where: { id, confirmedAt: IsNull() },
+    })
 
-    if (!pendingCreationToUpdate) {
-      throw new Error('No creation found to given id.')
+    if (!contributionToUpdate) {
+      throw new Error('No contribution found to given id.')
     }
 
-    if (pendingCreationToUpdate.userId !== user.id) {
-      throw new Error('user of the pending creation and send user does not correspond')
+    if (contributionToUpdate.userId !== user.id) {
+      throw new Error('user of the pending contribution and send user does not correspond')
+    }
+
+    if (contributionToUpdate.moderatorId === null) {
+      throw new Error('An admin is not allowed to update a user contribution.')
     }
 
     const creationDateObj = new Date(creationDate)
     let creations = await getUserCreation(user.id)
-    if (pendingCreationToUpdate.date.getMonth() === creationDateObj.getMonth()) {
-      creations = updateCreations(creations, pendingCreationToUpdate)
+    if (contributionToUpdate.contributionDate.getMonth() === creationDateObj.getMonth()) {
+      creations = updateCreations(creations, contributionToUpdate)
     }
 
     // all possible cases not to be true are thrown in this function
-    isCreationValid(creations, amount, creationDateObj)
-    pendingCreationToUpdate.amount = amount
-    pendingCreationToUpdate.memo = memo
-    pendingCreationToUpdate.date = new Date(creationDate)
-    pendingCreationToUpdate.moderator = moderator.id
+    validateContribution(creations, amount, creationDateObj)
+    contributionToUpdate.amount = amount
+    contributionToUpdate.memo = memo
+    contributionToUpdate.contributionDate = new Date(creationDate)
+    contributionToUpdate.moderatorId = moderator.id
 
-    await AdminPendingCreation.save(pendingCreationToUpdate)
-    const result = new UpdatePendingCreation()
+    await Contribution.save(contributionToUpdate)
+    const result = new AdminUpdateContribution()
     result.amount = amount
-    result.memo = pendingCreationToUpdate.memo
-    result.date = pendingCreationToUpdate.date
+    result.memo = contributionToUpdate.memo
+    result.date = contributionToUpdate.contributionDate
 
     result.creation = await getUserCreation(user.id)
 
     return result
   }
 
-  @Authorized([RIGHTS.SEARCH_PENDING_CREATION])
-  @Query(() => [PendingCreation])
-  async getPendingCreations(): Promise<PendingCreation[]> {
-    const pendingCreations = await AdminPendingCreation.find()
-    if (pendingCreations.length === 0) {
+  @Authorized([RIGHTS.LIST_UNCONFIRMED_CONTRIBUTIONS])
+  @Query(() => [UnconfirmedContribution])
+  async listUnconfirmedContributions(): Promise<UnconfirmedContribution[]> {
+    const contributions = await Contribution.find({ where: { confirmedAt: IsNull() } })
+    if (contributions.length === 0) {
       return []
     }
 
-    const userIds = pendingCreations.map((p) => p.userId)
+    const userIds = contributions.map((p) => p.userId)
     const userCreations = await getUserCreations(userIds)
     const users = await dbUser.find({ where: { id: In(userIds) }, withDeleted: true })
 
-    return pendingCreations.map((pendingCreation) => {
-      const user = users.find((u) => u.id === pendingCreation.userId)
-      const creation = userCreations.find((c) => c.id === pendingCreation.userId)
+    return contributions.map((contribution) => {
+      const user = users.find((u) => u.id === contribution.userId)
+      const creation = userCreations.find((c) => c.id === contribution.userId)
 
       return {
-        ...pendingCreation,
-        amount: pendingCreation.amount,
+        id: contribution.id,
+        userId: contribution.userId,
+        date: contribution.contributionDate,
+        memo: contribution.memo,
+        amount: contribution.amount,
+        moderator: contribution.moderatorId,
         firstName: user ? user.firstName : '',
         lastName: user ? user.lastName : '',
         email: user ? user.email : '',
@@ -300,69 +380,91 @@ export class AdminResolver {
     })
   }
 
-  @Authorized([RIGHTS.DELETE_PENDING_CREATION])
+  @Authorized([RIGHTS.ADMIN_DELETE_CONTRIBUTION])
   @Mutation(() => Boolean)
-  async deletePendingCreation(@Arg('id', () => Int) id: number): Promise<boolean> {
-    const pendingCreation = await AdminPendingCreation.findOne(id)
-    if (!pendingCreation) {
-      throw new Error('Creation not found for given id.')
+  async adminDeleteContribution(@Arg('id', () => Int) id: number): Promise<boolean> {
+    const contribution = await Contribution.findOne(id)
+    if (!contribution) {
+      throw new Error('Contribution not found for given id.')
     }
-    const res = await AdminPendingCreation.delete(pendingCreation)
+    const res = await contribution.softRemove()
     return !!res
   }
 
-  @Authorized([RIGHTS.CONFIRM_PENDING_CREATION])
+  @Authorized([RIGHTS.CONFIRM_CONTRIBUTION])
   @Mutation(() => Boolean)
-  async confirmPendingCreation(
+  async confirmContribution(
     @Arg('id', () => Int) id: number,
     @Ctx() context: Context,
   ): Promise<boolean> {
-    const pendingCreation = await AdminPendingCreation.findOne(id)
-    if (!pendingCreation) {
-      throw new Error('Creation not found to given id.')
+    const contribution = await Contribution.findOne(id)
+    if (!contribution) {
+      throw new Error('Contribution not found to given id.')
     }
     const moderatorUser = getUser(context)
-    if (moderatorUser.id === pendingCreation.userId)
-      throw new Error('Moderator can not confirm own pending creation')
+    if (moderatorUser.id === contribution.userId)
+      throw new Error('Moderator can not confirm own contribution')
 
-    const user = await dbUser.findOneOrFail({ id: pendingCreation.userId }, { withDeleted: true })
-    if (user.deletedAt) throw new Error('This user was deleted. Cannot confirm a creation.')
+    const user = await dbUser.findOneOrFail({ id: contribution.userId }, { withDeleted: true })
+    if (user.deletedAt) throw new Error('This user was deleted. Cannot confirm a contribution.')
 
-    const creations = await getUserCreation(pendingCreation.userId, false)
-    if (!isCreationValid(creations, pendingCreation.amount, pendingCreation.date)) {
-      throw new Error('Creation is not valid!!')
-    }
+    const creations = await getUserCreation(contribution.userId, false)
+    validateContribution(creations, contribution.amount, contribution.contributionDate)
 
     const receivedCallDate = new Date()
 
-    const transactionRepository = getCustomRepository(TransactionRepository)
-    const lastTransaction = await transactionRepository.findLastForUser(pendingCreation.userId)
+    const queryRunner = getConnection().createQueryRunner()
+    await queryRunner.connect()
+    await queryRunner.startTransaction('READ UNCOMMITTED')
+    try {
+      const lastTransaction = await queryRunner.manager
+        .createQueryBuilder()
+        .select('transaction')
+        .from(DbTransaction, 'transaction')
+        .where('transaction.userId = :id', { id: contribution.userId })
+        .orderBy('transaction.balanceDate', 'DESC')
+        .getOne()
+      logger.info('lastTransaction ID', lastTransaction ? lastTransaction.id : 'undefined')
 
-    let newBalance = new Decimal(0)
-    let decay: Decay | null = null
-    if (lastTransaction) {
-      decay = calculateDecay(lastTransaction.balance, lastTransaction.balanceDate, receivedCallDate)
-      newBalance = decay.balance
+      let newBalance = new Decimal(0)
+      let decay: Decay | null = null
+      if (lastTransaction) {
+        decay = calculateDecay(
+          lastTransaction.balance,
+          lastTransaction.balanceDate,
+          receivedCallDate,
+        )
+        newBalance = decay.balance
+      }
+      newBalance = newBalance.add(contribution.amount.toString())
+
+      const transaction = new DbTransaction()
+      transaction.typeId = TransactionTypeId.CREATION
+      transaction.memo = contribution.memo
+      transaction.userId = contribution.userId
+      transaction.previous = lastTransaction ? lastTransaction.id : null
+      transaction.amount = contribution.amount
+      transaction.creationDate = contribution.contributionDate
+      transaction.balance = newBalance
+      transaction.balanceDate = receivedCallDate
+      transaction.decay = decay ? decay.decay : new Decimal(0)
+      transaction.decayStart = decay ? decay.start : null
+      await queryRunner.manager.insert(DbTransaction, transaction)
+
+      contribution.confirmedAt = receivedCallDate
+      contribution.confirmedBy = moderatorUser.id
+      contribution.transactionId = transaction.id
+      await queryRunner.manager.update(Contribution, { id: contribution.id }, contribution)
+
+      await queryRunner.commitTransaction()
+      logger.info('creation commited successfuly.')
+    } catch (e) {
+      await queryRunner.rollbackTransaction()
+      logger.error(`Creation was not successful: ${e}`)
+      throw new Error(`Creation was not successful.`)
+    } finally {
+      await queryRunner.release()
     }
-    newBalance = newBalance.add(pendingCreation.amount.toString())
-
-    const transaction = new DbTransaction()
-    transaction.typeId = TransactionTypeId.CREATION
-    transaction.memo = pendingCreation.memo
-    transaction.userId = pendingCreation.userId
-    transaction.previous = lastTransaction ? lastTransaction.id : null
-    transaction.amount = pendingCreation.amount
-    transaction.creationDate = pendingCreation.date
-    transaction.balance = newBalance
-    transaction.balanceDate = receivedCallDate
-    transaction.decay = decay ? decay.decay : new Decimal(0)
-    transaction.decayStart = decay ? decay.start : null
-    await transaction.save().catch(() => {
-      throw new Error('Unable to confirm creation.')
-    })
-
-    await AdminPendingCreation.delete(pendingCreation)
-
     return true
   }
 
@@ -460,96 +562,130 @@ export class AdminResolver {
       linkList: transactionLinks.map((tl) => new TransactionLink(tl, new User(user))),
     }
   }
-}
 
-interface CreationMap {
-  id: number
-  creations: Decimal[]
-}
-
-async function getUserCreation(id: number, includePending = true): Promise<Decimal[]> {
-  const creations = await getUserCreations([id], includePending)
-  return creations[0] ? creations[0].creations : FULL_CREATION_AVAILABLE
-}
-
-async function getUserCreations(ids: number[], includePending = true): Promise<CreationMap[]> {
-  const months = getCreationMonths()
-
-  const queryRunner = getConnection().createQueryRunner()
-  await queryRunner.connect()
-
-  const dateFilter = 'last_day(curdate() - interval 3 month) + interval 1 day'
-
-  const unionString = includePending
-    ? `
-    UNION
-      SELECT date AS date, amount AS amount, userId AS userId FROM admin_pending_creations
-        WHERE userId IN (${ids.toString()})
-        AND date >= ${dateFilter}`
-    : ''
-
-  const unionQuery = await queryRunner.manager.query(`
-    SELECT MONTH(date) AS month, sum(amount) AS sum, userId AS id FROM
-      (SELECT creation_date AS date, amount AS amount, user_id AS userId FROM transactions
-        WHERE user_id IN (${ids.toString()})
-        AND type_id = ${TransactionTypeId.CREATION}
-        AND creation_date >= ${dateFilter}
-      ${unionString}) AS result
-    GROUP BY month, userId
-    ORDER BY date DESC
-  `)
-
-  await queryRunner.release()
-
-  return ids.map((id) => {
-    return {
-      id,
-      creations: months.map((month) => {
-        const creation = unionQuery.find(
-          (raw: { month: string; id: string; creation: number[] }) =>
-            parseInt(raw.month) === month && parseInt(raw.id) === id,
-        )
-        return MAX_CREATION_AMOUNT.minus(creation ? creation.sum : 0)
-      }),
+  @Authorized([RIGHTS.CREATE_CONTRIBUTION_LINK])
+  @Mutation(() => ContributionLink)
+  async createContributionLink(
+    @Args()
+    {
+      amount,
+      name,
+      memo,
+      cycle,
+      validFrom,
+      validTo,
+      maxAmountPerMonth,
+      maxPerCycle,
+    }: ContributionLinkArgs,
+  ): Promise<ContributionLink> {
+    isStartEndDateValid(validFrom, validTo)
+    if (!name) {
+      logger.error(`The name must be initialized!`)
+      throw new Error(`The name must be initialized!`)
     }
-  })
-}
-
-function updateCreations(creations: Decimal[], pendingCreation: AdminPendingCreation): Decimal[] {
-  const index = getCreationIndex(pendingCreation.date.getMonth())
-
-  if (index < 0) {
-    throw new Error('You cannot create GDD for a month older than the last three months.')
-  }
-  creations[index] = creations[index].plus(pendingCreation.amount.toString())
-  return creations
-}
-
-function isCreationValid(creations: Decimal[], amount: Decimal, creationDate: Date) {
-  const index = getCreationIndex(creationDate.getMonth())
-
-  if (index < 0) {
-    throw new Error('No information for available creations for the given date')
+    if (
+      name.length < CONTRIBUTIONLINK_NAME_MIN_CHARS ||
+      name.length > CONTRIBUTIONLINK_NAME_MAX_CHARS
+    ) {
+      const msg = `The value of 'name' with a length of ${name.length} did not fulfill the requested bounderies min=${CONTRIBUTIONLINK_NAME_MIN_CHARS} and max=${CONTRIBUTIONLINK_NAME_MAX_CHARS}`
+      logger.error(`${msg}`)
+      throw new Error(`${msg}`)
+    }
+    if (!memo) {
+      logger.error(`The memo must be initialized!`)
+      throw new Error(`The memo must be initialized!`)
+    }
+    if (memo.length < MEMO_MIN_CHARS || memo.length > MEMO_MAX_CHARS) {
+      const msg = `The value of 'memo' with a length of ${memo.length} did not fulfill the requested bounderies min=${MEMO_MIN_CHARS} and max=${MEMO_MAX_CHARS}`
+      logger.error(`${msg}`)
+      throw new Error(`${msg}`)
+    }
+    if (!amount) {
+      logger.error(`The amount must be initialized!`)
+      throw new Error('The amount must be initialized!')
+    }
+    if (!new Decimal(amount).isPositive()) {
+      logger.error(`The amount=${amount} must be initialized with a positiv value!`)
+      throw new Error(`The amount=${amount} must be initialized with a positiv value!`)
+    }
+    const dbContributionLink = new DbContributionLink()
+    dbContributionLink.amount = amount
+    dbContributionLink.name = name
+    dbContributionLink.memo = memo
+    dbContributionLink.createdAt = new Date()
+    dbContributionLink.code = contributionLinkCode(dbContributionLink.createdAt)
+    dbContributionLink.cycle = cycle
+    if (validFrom) dbContributionLink.validFrom = new Date(validFrom)
+    if (validTo) dbContributionLink.validTo = new Date(validTo)
+    dbContributionLink.maxAmountPerMonth = maxAmountPerMonth
+    dbContributionLink.maxPerCycle = maxPerCycle
+    await dbContributionLink.save()
+    logger.debug(`createContributionLink successful!`)
+    return new ContributionLink(dbContributionLink)
   }
 
-  if (amount.greaterThan(creations[index].toString())) {
-    throw new Error(
-      `The amount (${amount} GDD) to be created exceeds the amount (${creations[index]} GDD) still available for this month.`,
-    )
+  @Authorized([RIGHTS.LIST_CONTRIBUTION_LINKS])
+  @Query(() => ContributionLinkList)
+  async listContributionLinks(
+    @Args()
+    { currentPage = 1, pageSize = 5, order = Order.DESC }: Paginated,
+  ): Promise<ContributionLinkList> {
+    const [links, count] = await DbContributionLink.findAndCount({
+      order: { createdAt: order },
+      skip: (currentPage - 1) * pageSize,
+      take: pageSize,
+    })
+    return {
+      links: links.map((link: DbContributionLink) => new ContributionLink(link)),
+      count,
+    }
   }
 
-  return true
-}
+  @Authorized([RIGHTS.DELETE_CONTRIBUTION_LINK])
+  @Mutation(() => Date, { nullable: true })
+  async deleteContributionLink(@Arg('id', () => Int) id: number): Promise<Date | null> {
+    const contributionLink = await DbContributionLink.findOne(id)
+    if (!contributionLink) {
+      logger.error(`Contribution Link not found to given id: ${id}`)
+      throw new Error('Contribution Link not found to given id.')
+    }
+    await contributionLink.softRemove()
+    logger.debug(`deleteContributionLink successful!`)
+    const newContributionLink = await DbContributionLink.findOne({ id }, { withDeleted: true })
+    return newContributionLink ? newContributionLink.deletedAt : null
+  }
 
-const getCreationMonths = (): number[] => {
-  const now = new Date(Date.now())
-  return [
-    now.getMonth() + 1,
-    new Date(now.getFullYear(), now.getMonth() - 1, 1).getMonth() + 1,
-    new Date(now.getFullYear(), now.getMonth() - 2, 1).getMonth() + 1,
-  ].reverse()
-}
-
-const getCreationIndex = (month: number): number => {
-  return getCreationMonths().findIndex((el) => el === month + 1)
+  @Authorized([RIGHTS.UPDATE_CONTRIBUTION_LINK])
+  @Mutation(() => ContributionLink)
+  async updateContributionLink(
+    @Args()
+    {
+      amount,
+      name,
+      memo,
+      cycle,
+      validFrom,
+      validTo,
+      maxAmountPerMonth,
+      maxPerCycle,
+    }: ContributionLinkArgs,
+    @Arg('id', () => Int) id: number,
+  ): Promise<ContributionLink> {
+    const dbContributionLink = await DbContributionLink.findOne(id)
+    if (!dbContributionLink) {
+      logger.error(`Contribution Link not found to given id: ${id}`)
+      throw new Error('Contribution Link not found to given id.')
+    }
+    dbContributionLink.amount = amount
+    dbContributionLink.name = name
+    dbContributionLink.memo = memo
+    dbContributionLink.cycle = cycle
+    if (validFrom) dbContributionLink.validFrom = new Date(validFrom)
+    if (validTo) dbContributionLink.validTo = new Date(validTo)
+    dbContributionLink.maxAmountPerMonth = maxAmountPerMonth
+    dbContributionLink.maxPerCycle = maxPerCycle
+    await dbContributionLink.save()
+    logger.debug(`updateContributionLink successful!`)
+    return new ContributionLink(dbContributionLink)
+  }
 }
diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts
new file mode 100644
index 000000000..20f11ff9a
--- /dev/null
+++ b/backend/src/graphql/resolver/ContributionResolver.test.ts
@@ -0,0 +1,735 @@
+/* eslint-disable @typescript-eslint/no-explicit-any */
+/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
+
+import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg'
+import {
+  adminUpdateContribution,
+  confirmContribution,
+  createContribution,
+  deleteContribution,
+  updateContribution,
+} from '@/seeds/graphql/mutations'
+import { listAllContributions, listContributions, login } from '@/seeds/graphql/queries'
+import { cleanDB, resetToken, testEnvironment } from '@test/helpers'
+import { GraphQLError } from 'graphql'
+import { userFactory } from '@/seeds/factory/user'
+import { creationFactory } from '@/seeds/factory/creation'
+import { creations } from '@/seeds/creation/index'
+import { peterLustig } from '@/seeds/users/peter-lustig'
+
+let mutate: any, query: any, con: any
+let testEnv: any
+let result: any
+
+beforeAll(async () => {
+  testEnv = await testEnvironment()
+  mutate = testEnv.mutate
+  query = testEnv.query
+  con = testEnv.con
+  await cleanDB()
+})
+
+afterAll(async () => {
+  await cleanDB()
+  await con.close()
+})
+
+describe('ContributionResolver', () => {
+  describe('createContribution', () => {
+    describe('unauthenticated', () => {
+      it('returns an error', async () => {
+        await expect(
+          mutate({
+            mutation: createContribution,
+            variables: { amount: 100.0, memo: 'Test Contribution', creationDate: 'not-valid' },
+          }),
+        ).resolves.toEqual(
+          expect.objectContaining({
+            errors: [new GraphQLError('401 Unauthorized')],
+          }),
+        )
+      })
+    })
+
+    describe('authenticated with valid user', () => {
+      beforeAll(async () => {
+        await userFactory(testEnv, bibiBloxberg)
+        await query({
+          query: login,
+          variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
+        })
+      })
+
+      afterAll(async () => {
+        await cleanDB()
+        resetToken()
+      })
+
+      describe('input not valid', () => {
+        it('throws error when memo length smaller than 5 chars', async () => {
+          const date = new Date()
+          await expect(
+            mutate({
+              mutation: createContribution,
+              variables: {
+                amount: 100.0,
+                memo: 'Test',
+                creationDate: date.toString(),
+              },
+            }),
+          ).resolves.toEqual(
+            expect.objectContaining({
+              errors: [new GraphQLError('memo text is too short (5 characters minimum)')],
+            }),
+          )
+        })
+
+        it('throws error when memo length greater than 255 chars', async () => {
+          const date = new Date()
+          await expect(
+            mutate({
+              mutation: createContribution,
+              variables: {
+                amount: 100.0,
+                memo: 'Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test',
+                creationDate: date.toString(),
+              },
+            }),
+          ).resolves.toEqual(
+            expect.objectContaining({
+              errors: [new GraphQLError('memo text is too long (255 characters maximum)')],
+            }),
+          )
+        })
+
+        it('throws error when creationDate not-valid', async () => {
+          await expect(
+            mutate({
+              mutation: createContribution,
+              variables: {
+                amount: 100.0,
+                memo: 'Test env contribution',
+                creationDate: 'not-valid',
+              },
+            }),
+          ).resolves.toEqual(
+            expect.objectContaining({
+              errors: [
+                new GraphQLError('No information for available creations for the given date'),
+              ],
+            }),
+          )
+        })
+
+        it('throws error when creationDate 3 month behind', async () => {
+          const date = new Date()
+          await expect(
+            mutate({
+              mutation: createContribution,
+              variables: {
+                amount: 100.0,
+                memo: 'Test env contribution',
+                creationDate: date.setMonth(date.getMonth() - 3).toString(),
+              },
+            }),
+          ).resolves.toEqual(
+            expect.objectContaining({
+              errors: [
+                new GraphQLError('No information for available creations for the given date'),
+              ],
+            }),
+          )
+        })
+      })
+
+      describe('valid input', () => {
+        it('creates contribution', async () => {
+          await expect(
+            mutate({
+              mutation: createContribution,
+              variables: {
+                amount: 100.0,
+                memo: 'Test env contribution',
+                creationDate: new Date().toString(),
+              },
+            }),
+          ).resolves.toEqual(
+            expect.objectContaining({
+              data: {
+                createContribution: {
+                  id: expect.any(Number),
+                  amount: '100',
+                  memo: 'Test env contribution',
+                },
+              },
+            }),
+          )
+        })
+      })
+    })
+  })
+
+  describe('listContributions', () => {
+    describe('unauthenticated', () => {
+      it('returns an error', async () => {
+        await expect(
+          query({
+            query: listContributions,
+            variables: {
+              currentPage: 1,
+              pageSize: 25,
+              order: 'DESC',
+              filterConfirmed: false,
+            },
+          }),
+        ).resolves.toEqual(
+          expect.objectContaining({
+            errors: [new GraphQLError('401 Unauthorized')],
+          }),
+        )
+      })
+    })
+
+    describe('authenticated', () => {
+      beforeAll(async () => {
+        await userFactory(testEnv, bibiBloxberg)
+        await userFactory(testEnv, peterLustig)
+        const bibisCreation = creations.find((creation) => creation.email === 'bibi@bloxberg.de')
+        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+        await creationFactory(testEnv, bibisCreation!)
+        await query({
+          query: login,
+          variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
+        })
+        await mutate({
+          mutation: createContribution,
+          variables: {
+            amount: 100.0,
+            memo: 'Test env contribution',
+            creationDate: new Date().toString(),
+          },
+        })
+      })
+
+      afterAll(async () => {
+        await cleanDB()
+        resetToken()
+      })
+
+      describe('filter confirmed is false', () => {
+        it('returns creations', async () => {
+          await expect(
+            query({
+              query: listContributions,
+              variables: {
+                currentPage: 1,
+                pageSize: 25,
+                order: 'DESC',
+                filterConfirmed: false,
+              },
+            }),
+          ).resolves.toEqual(
+            expect.objectContaining({
+              data: {
+                listContributions: {
+                  contributionCount: 2,
+                  contributionList: expect.arrayContaining([
+                    expect.objectContaining({
+                      id: expect.any(Number),
+                      memo: 'Herzlich Willkommen bei Gradido!',
+                      amount: '1000',
+                    }),
+                    expect.objectContaining({
+                      id: expect.any(Number),
+                      memo: 'Test env contribution',
+                      amount: '100',
+                    }),
+                  ]),
+                },
+              },
+            }),
+          )
+        })
+      })
+
+      describe('filter confirmed is true', () => {
+        it('returns only unconfirmed creations', async () => {
+          await expect(
+            query({
+              query: listContributions,
+              variables: {
+                currentPage: 1,
+                pageSize: 25,
+                order: 'DESC',
+                filterConfirmed: true,
+              },
+            }),
+          ).resolves.toEqual(
+            expect.objectContaining({
+              data: {
+                listContributions: {
+                  contributionCount: 1,
+                  contributionList: expect.arrayContaining([
+                    expect.objectContaining({
+                      id: expect.any(Number),
+                      memo: 'Test env contribution',
+                      amount: '100',
+                    }),
+                  ]),
+                },
+              },
+            }),
+          )
+        })
+      })
+    })
+  })
+
+  describe('updateContribution', () => {
+    describe('unauthenticated', () => {
+      it('returns an error', async () => {
+        await expect(
+          mutate({
+            mutation: updateContribution,
+            variables: {
+              contributionId: 1,
+              amount: 100.0,
+              memo: 'Test Contribution',
+              creationDate: 'not-valid',
+            },
+          }),
+        ).resolves.toEqual(
+          expect.objectContaining({
+            errors: [new GraphQLError('401 Unauthorized')],
+          }),
+        )
+      })
+    })
+
+    describe('authenticated', () => {
+      beforeAll(async () => {
+        await userFactory(testEnv, peterLustig)
+        await userFactory(testEnv, bibiBloxberg)
+        await query({
+          query: login,
+          variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
+        })
+        result = await mutate({
+          mutation: createContribution,
+          variables: {
+            amount: 100.0,
+            memo: 'Test env contribution',
+            creationDate: new Date().toString(),
+          },
+        })
+      })
+
+      afterAll(async () => {
+        await cleanDB()
+        resetToken()
+      })
+
+      describe('wrong contribution id', () => {
+        it('throws an error', async () => {
+          await expect(
+            mutate({
+              mutation: updateContribution,
+              variables: {
+                contributionId: -1,
+                amount: 100.0,
+                memo: 'Test env contribution',
+                creationDate: new Date().toString(),
+              },
+            }),
+          ).resolves.toEqual(
+            expect.objectContaining({
+              errors: [new GraphQLError('No contribution found to given id.')],
+            }),
+          )
+        })
+      })
+
+      describe('Memo length smaller than 5 chars', () => {
+        it('throws error', async () => {
+          const date = new Date()
+          await expect(
+            mutate({
+              mutation: updateContribution,
+              variables: {
+                contributionId: result.data.createContribution.id,
+                amount: 100.0,
+                memo: 'Test',
+                creationDate: date.toString(),
+              },
+            }),
+          ).resolves.toEqual(
+            expect.objectContaining({
+              errors: [new GraphQLError('memo text is too short (5 characters minimum)')],
+            }),
+          )
+        })
+      })
+
+      describe('Memo length greater than 255 chars', () => {
+        it('throws error', async () => {
+          const date = new Date()
+          await expect(
+            mutate({
+              mutation: updateContribution,
+              variables: {
+                contributionId: result.data.createContribution.id,
+                amount: 100.0,
+                memo: 'Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test Test',
+                creationDate: date.toString(),
+              },
+            }),
+          ).resolves.toEqual(
+            expect.objectContaining({
+              errors: [new GraphQLError('memo text is too long (255 characters maximum)')],
+            }),
+          )
+        })
+      })
+
+      describe('wrong user tries to update the contribution', () => {
+        beforeAll(async () => {
+          await query({
+            query: login,
+            variables: { email: 'peter@lustig.de', password: 'Aa12345_' },
+          })
+        })
+
+        it('throws an error', async () => {
+          await expect(
+            mutate({
+              mutation: updateContribution,
+              variables: {
+                contributionId: result.data.createContribution.id,
+                amount: 10.0,
+                memo: 'Test env contribution',
+                creationDate: new Date().toString(),
+              },
+            }),
+          ).resolves.toEqual(
+            expect.objectContaining({
+              errors: [
+                new GraphQLError(
+                  'user of the pending contribution and send user does not correspond',
+                ),
+              ],
+            }),
+          )
+        })
+      })
+
+      describe('admin tries to update a user contribution', () => {
+        it('throws an error', async () => {
+          await expect(
+            mutate({
+              mutation: adminUpdateContribution,
+              variables: {
+                id: result.data.createContribution.id,
+                email: 'bibi@bloxberg.de',
+                amount: 10.0,
+                memo: 'Test env contribution',
+                creationDate: new Date().toString(),
+              },
+            }),
+          ).resolves.toEqual(
+            expect.objectContaining({
+              errors: [new GraphQLError('An admin is not allowed to update a user contribution.')],
+            }),
+          )
+        })
+      })
+
+      describe('update too much so that the limit is exceeded', () => {
+        beforeAll(async () => {
+          await query({
+            query: login,
+            variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
+          })
+        })
+
+        it('throws an error', async () => {
+          await expect(
+            mutate({
+              mutation: updateContribution,
+              variables: {
+                contributionId: result.data.createContribution.id,
+                amount: 1019.0,
+                memo: 'Test env contribution',
+                creationDate: new Date().toString(),
+              },
+            }),
+          ).resolves.toEqual(
+            expect.objectContaining({
+              errors: [
+                new GraphQLError(
+                  'The amount (1019 GDD) to be created exceeds the amount (1000 GDD) still available for this month.',
+                ),
+              ],
+            }),
+          )
+        })
+      })
+
+      describe('update creation to a date that is older than 3 months', () => {
+        it('throws an error', async () => {
+          const date = new Date()
+          await expect(
+            mutate({
+              mutation: updateContribution,
+              variables: {
+                contributionId: result.data.createContribution.id,
+                amount: 10.0,
+                memo: 'Test env contribution',
+                creationDate: date.setMonth(date.getMonth() - 3).toString(),
+              },
+            }),
+          ).resolves.toEqual(
+            expect.objectContaining({
+              errors: [
+                new GraphQLError('No information for available creations for the given date'),
+              ],
+            }),
+          )
+        })
+      })
+
+      describe('valid input', () => {
+        it('updates contribution', async () => {
+          await expect(
+            mutate({
+              mutation: updateContribution,
+              variables: {
+                contributionId: result.data.createContribution.id,
+                amount: 10.0,
+                memo: 'Test contribution',
+                creationDate: new Date().toString(),
+              },
+            }),
+          ).resolves.toEqual(
+            expect.objectContaining({
+              data: {
+                updateContribution: {
+                  id: result.data.createContribution.id,
+                  amount: '10',
+                  memo: 'Test contribution',
+                },
+              },
+            }),
+          )
+        })
+      })
+    })
+  })
+
+  describe('listAllContribution', () => {
+    describe('unauthenticated', () => {
+      it('returns an error', async () => {
+        await expect(
+          query({
+            query: listAllContributions,
+            variables: {
+              currentPage: 1,
+              pageSize: 25,
+              order: 'DESC',
+              filterConfirmed: false,
+            },
+          }),
+        ).resolves.toEqual(
+          expect.objectContaining({
+            errors: [new GraphQLError('401 Unauthorized')],
+          }),
+        )
+      })
+    })
+
+    describe('authenticated', () => {
+      beforeAll(async () => {
+        await userFactory(testEnv, bibiBloxberg)
+        await userFactory(testEnv, peterLustig)
+        const bibisCreation = creations.find((creation) => creation.email === 'bibi@bloxberg.de')
+        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+        await creationFactory(testEnv, bibisCreation!)
+        await query({
+          query: login,
+          variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
+        })
+        await mutate({
+          mutation: createContribution,
+          variables: {
+            amount: 100.0,
+            memo: 'Test env contribution',
+            creationDate: new Date().toString(),
+          },
+        })
+      })
+
+      afterAll(async () => {
+        await cleanDB()
+        resetToken()
+      })
+
+      it('returns allCreation', async () => {
+        await expect(
+          query({
+            query: listAllContributions,
+            variables: {
+              currentPage: 1,
+              pageSize: 25,
+              order: 'DESC',
+              filterConfirmed: false,
+            },
+          }),
+        ).resolves.toEqual(
+          expect.objectContaining({
+            data: {
+              listAllContributions: {
+                contributionCount: 2,
+                contributionList: expect.arrayContaining([
+                  expect.objectContaining({
+                    id: expect.any(Number),
+                    memo: 'Herzlich Willkommen bei Gradido!',
+                    amount: '1000',
+                  }),
+                  expect.objectContaining({
+                    id: expect.any(Number),
+                    memo: 'Test env contribution',
+                    amount: '100',
+                  }),
+                ]),
+              },
+            },
+          }),
+        )
+      })
+    })
+  })
+
+  describe('deleteContribution', () => {
+    describe('unauthenticated', () => {
+      it('returns an error', async () => {
+        await expect(
+          query({
+            query: deleteContribution,
+            variables: {
+              id: -1,
+            },
+          }),
+        ).resolves.toEqual(
+          expect.objectContaining({
+            errors: [new GraphQLError('401 Unauthorized')],
+          }),
+        )
+      })
+    })
+
+    describe('authenticated', () => {
+      beforeAll(async () => {
+        await userFactory(testEnv, bibiBloxberg)
+        await userFactory(testEnv, peterLustig)
+        await query({
+          query: login,
+          variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
+        })
+        result = await mutate({
+          mutation: createContribution,
+          variables: {
+            amount: 100.0,
+            memo: 'Test env contribution',
+            creationDate: new Date().toString(),
+          },
+        })
+      })
+
+      afterAll(async () => {
+        await cleanDB()
+        resetToken()
+      })
+
+      describe('wrong contribution id', () => {
+        it('returns an error', async () => {
+          await expect(
+            mutate({
+              mutation: deleteContribution,
+              variables: {
+                id: -1,
+              },
+            }),
+          ).resolves.toEqual(
+            expect.objectContaining({
+              errors: [new GraphQLError('Contribution not found for given id.')],
+            }),
+          )
+        })
+      })
+
+      describe('other user sends a deleteContribtuion', () => {
+        it('returns an error', async () => {
+          await query({
+            query: login,
+            variables: { email: 'peter@lustig.de', password: 'Aa12345_' },
+          })
+          await expect(
+            mutate({
+              mutation: deleteContribution,
+              variables: {
+                id: result.data.createContribution.id,
+              },
+            }),
+          ).resolves.toEqual(
+            expect.objectContaining({
+              errors: [new GraphQLError('Can not delete contribution of another user')],
+            }),
+          )
+        })
+      })
+
+      describe('User deletes own contribution', () => {
+        it('deletes successfully', async () => {
+          await expect(
+            mutate({
+              mutation: deleteContribution,
+              variables: {
+                id: result.data.createContribution.id,
+              },
+            }),
+          ).resolves.toBeTruthy()
+        })
+      })
+
+      describe('User deletes already confirmed contribution', () => {
+        it('throws an error', async () => {
+          await query({
+            query: login,
+            variables: { email: 'peter@lustig.de', password: 'Aa12345_' },
+          })
+          await mutate({
+            mutation: confirmContribution,
+            variables: {
+              id: result.data.createContribution.id,
+            },
+          })
+          await query({
+            query: login,
+            variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
+          })
+          await expect(
+            mutate({
+              mutation: deleteContribution,
+              variables: {
+                id: result.data.createContribution.id,
+              },
+            }),
+          ).resolves.toEqual(
+            expect.objectContaining({
+              errors: [new GraphQLError('A confirmed contribution can not be deleted')],
+            }),
+          )
+        })
+      })
+    })
+  })
+})
diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts
new file mode 100644
index 000000000..3307252e4
--- /dev/null
+++ b/backend/src/graphql/resolver/ContributionResolver.ts
@@ -0,0 +1,171 @@
+import { RIGHTS } from '@/auth/RIGHTS'
+import { Context, getUser } from '@/server/context'
+import { backendLogger as logger } from '@/server/logger'
+import { Contribution as dbContribution } from '@entity/Contribution'
+import { Arg, Args, Authorized, Ctx, Int, Mutation, Query, Resolver } from 'type-graphql'
+import { FindOperator, IsNull, getConnection } from '@dbTools/typeorm'
+import ContributionArgs from '@arg/ContributionArgs'
+import Paginated from '@arg/Paginated'
+import { Order } from '@enum/Order'
+import { Contribution, ContributionListResult } from '@model/Contribution'
+import { UnconfirmedContribution } from '@model/UnconfirmedContribution'
+import { User } from '@model/User'
+import { validateContribution, getUserCreation, updateCreations } from './util/creations'
+import { MEMO_MAX_CHARS, MEMO_MIN_CHARS } from './const/const'
+
+@Resolver()
+export class ContributionResolver {
+  @Authorized([RIGHTS.CREATE_CONTRIBUTION])
+  @Mutation(() => UnconfirmedContribution)
+  async createContribution(
+    @Args() { amount, memo, creationDate }: ContributionArgs,
+    @Ctx() context: Context,
+  ): Promise<UnconfirmedContribution> {
+    if (memo.length > MEMO_MAX_CHARS) {
+      logger.error(`memo text is too long: memo.length=${memo.length} > (${MEMO_MAX_CHARS}`)
+      throw new Error(`memo text is too long (${MEMO_MAX_CHARS} characters maximum)`)
+    }
+
+    if (memo.length < MEMO_MIN_CHARS) {
+      logger.error(`memo text is too short: memo.length=${memo.length} < (${MEMO_MIN_CHARS}`)
+      throw new Error(`memo text is too short (${MEMO_MIN_CHARS} characters minimum)`)
+    }
+
+    const user = getUser(context)
+    const creations = await getUserCreation(user.id)
+    logger.trace('creations', creations)
+    const creationDateObj = new Date(creationDate)
+    validateContribution(creations, amount, creationDateObj)
+
+    const contribution = dbContribution.create()
+    contribution.userId = user.id
+    contribution.amount = amount
+    contribution.createdAt = new Date()
+    contribution.contributionDate = creationDateObj
+    contribution.memo = memo
+
+    logger.trace('contribution to save', contribution)
+    await dbContribution.save(contribution)
+    return new UnconfirmedContribution(contribution, user, creations)
+  }
+
+  @Authorized([RIGHTS.DELETE_CONTRIBUTION])
+  @Mutation(() => Boolean)
+  async deleteContribution(
+    @Arg('id', () => Int) id: number,
+    @Ctx() context: Context,
+  ): Promise<boolean> {
+    const user = getUser(context)
+    const contribution = await dbContribution.findOne(id)
+    if (!contribution) {
+      throw new Error('Contribution not found for given id.')
+    }
+    if (contribution.userId !== user.id) {
+      throw new Error('Can not delete contribution of another user')
+    }
+    if (contribution.confirmedAt) {
+      throw new Error('A confirmed contribution can not be deleted')
+    }
+    const res = await contribution.softRemove()
+    return !!res
+  }
+
+  @Authorized([RIGHTS.LIST_CONTRIBUTIONS])
+  @Query(() => ContributionListResult)
+  async listContributions(
+    @Args()
+    { currentPage = 1, pageSize = 5, order = Order.DESC }: Paginated,
+    @Arg('filterConfirmed', () => Boolean)
+    filterConfirmed: boolean | null,
+    @Ctx() context: Context,
+  ): Promise<ContributionListResult> {
+    const user = getUser(context)
+    const where: {
+      userId: number
+      confirmedBy?: FindOperator<number> | null
+    } = { userId: user.id }
+    if (filterConfirmed) where.confirmedBy = IsNull()
+    const [contributions, count] = await dbContribution.findAndCount({
+      where,
+      order: {
+        createdAt: order,
+      },
+      withDeleted: true,
+      skip: (currentPage - 1) * pageSize,
+      take: pageSize,
+    })
+    return new ContributionListResult(
+      count,
+      contributions.map((contribution) => new Contribution(contribution, new User(user))),
+    )
+  }
+
+  @Authorized([RIGHTS.LIST_ALL_CONTRIBUTIONS])
+  @Query(() => ContributionListResult)
+  async listAllContributions(
+    @Args()
+    { currentPage = 1, pageSize = 5, order = Order.DESC }: Paginated,
+  ): Promise<ContributionListResult> {
+    const [dbContributions, count] = await getConnection()
+      .createQueryBuilder()
+      .select('c')
+      .from(dbContribution, 'c')
+      .innerJoinAndSelect('c.user', 'u')
+      .orderBy('c.createdAt', order)
+      .limit(pageSize)
+      .offset((currentPage - 1) * pageSize)
+      .getManyAndCount()
+    return new ContributionListResult(
+      count,
+      dbContributions.map(
+        (contribution) => new Contribution(contribution, new User(contribution.user)),
+      ),
+    )
+  }
+
+  @Authorized([RIGHTS.UPDATE_CONTRIBUTION])
+  @Mutation(() => UnconfirmedContribution)
+  async updateContribution(
+    @Arg('contributionId', () => Int)
+    contributionId: number,
+    @Args() { amount, memo, creationDate }: ContributionArgs,
+    @Ctx() context: Context,
+  ): Promise<UnconfirmedContribution> {
+    if (memo.length > MEMO_MAX_CHARS) {
+      logger.error(`memo text is too long: memo.length=${memo.length} > (${MEMO_MAX_CHARS}`)
+      throw new Error(`memo text is too long (${MEMO_MAX_CHARS} characters maximum)`)
+    }
+
+    if (memo.length < MEMO_MIN_CHARS) {
+      logger.error(`memo text is too short: memo.length=${memo.length} < (${MEMO_MIN_CHARS}`)
+      throw new Error(`memo text is too short (${MEMO_MIN_CHARS} characters minimum)`)
+    }
+
+    const user = getUser(context)
+
+    const contributionToUpdate = await dbContribution.findOne({
+      where: { id: contributionId, confirmedAt: IsNull() },
+    })
+    if (!contributionToUpdate) {
+      throw new Error('No contribution found to given id.')
+    }
+    if (contributionToUpdate.userId !== user.id) {
+      throw new Error('user of the pending contribution and send user does not correspond')
+    }
+
+    const creationDateObj = new Date(creationDate)
+    let creations = await getUserCreation(user.id)
+    if (contributionToUpdate.contributionDate.getMonth() === creationDateObj.getMonth()) {
+      creations = updateCreations(creations, contributionToUpdate)
+    }
+
+    // all possible cases not to be true are thrown in this function
+    validateContribution(creations, amount, creationDateObj)
+    contributionToUpdate.amount = amount
+    contributionToUpdate.memo = memo
+    contributionToUpdate.contributionDate = new Date(creationDate)
+    dbContribution.save(contributionToUpdate)
+
+    return new UnconfirmedContribution(contributionToUpdate, user, creations)
+  }
+}
diff --git a/backend/src/graphql/resolver/TransactionLinkResolver.ts b/backend/src/graphql/resolver/TransactionLinkResolver.ts
index 733f1db28..8696065ed 100644
--- a/backend/src/graphql/resolver/TransactionLinkResolver.ts
+++ b/backend/src/graphql/resolver/TransactionLinkResolver.ts
@@ -1,7 +1,21 @@
+import { backendLogger as logger } from '@/server/logger'
 import { Context, getUser } from '@/server/context'
-import { Resolver, Args, Arg, Authorized, Ctx, Mutation, Query, Int } from 'type-graphql'
+import { getConnection } from '@dbTools/typeorm'
+import {
+  Resolver,
+  Args,
+  Arg,
+  Authorized,
+  Ctx,
+  Mutation,
+  Query,
+  Int,
+  createUnionType,
+} from 'type-graphql'
 import { TransactionLink } from '@model/TransactionLink'
+import { ContributionLink } from '@model/ContributionLink'
 import { TransactionLink as dbTransactionLink } from '@entity/TransactionLink'
+import { Transaction as DbTransaction } from '@entity/Transaction'
 import { User as dbUser } from '@entity/User'
 import TransactionLinkArgs from '@arg/TransactionLinkArgs'
 import Paginated from '@arg/Paginated'
@@ -12,6 +26,17 @@ import { User } from '@model/User'
 import { calculateDecay } from '@/util/decay'
 import { executeTransaction } from './TransactionResolver'
 import { Order } from '@enum/Order'
+import { Contribution as DbContribution } from '@entity/Contribution'
+import { ContributionLink as DbContributionLink } from '@entity/ContributionLink'
+import { getUserCreation, validateContribution } from './util/creations'
+import { Decay } from '@model/Decay'
+import Decimal from 'decimal.js-light'
+import { TransactionTypeId } from '@enum/TransactionTypeId'
+
+const QueryLinkResult = createUnionType({
+  name: 'QueryLinkResult', // the name of the GraphQL union
+  types: () => [TransactionLink, ContributionLink] as const, // function that returns tuple of object types classes
+})
 
 // TODO: do not export, test it inside the resolver
 export const transactionLinkCode = (date: Date): string => {
@@ -95,15 +120,23 @@ export class TransactionLinkResolver {
   }
 
   @Authorized([RIGHTS.QUERY_TRANSACTION_LINK])
-  @Query(() => TransactionLink)
-  async queryTransactionLink(@Arg('code') code: string): Promise<TransactionLink> {
-    const transactionLink = await dbTransactionLink.findOneOrFail({ code }, { withDeleted: true })
-    const user = await dbUser.findOneOrFail({ id: transactionLink.userId })
-    let redeemedBy: User | null = null
-    if (transactionLink && transactionLink.redeemedBy) {
-      redeemedBy = new User(await dbUser.findOneOrFail({ id: transactionLink.redeemedBy }))
+  @Query(() => QueryLinkResult)
+  async queryTransactionLink(@Arg('code') code: string): Promise<typeof QueryLinkResult> {
+    if (code.match(/^CL-/)) {
+      const contributionLink = await DbContributionLink.findOneOrFail(
+        { code: code.replace('CL-', '') },
+        { withDeleted: true },
+      )
+      return new ContributionLink(contributionLink)
+    } else {
+      const transactionLink = await dbTransactionLink.findOneOrFail({ code }, { withDeleted: true })
+      const user = await dbUser.findOneOrFail({ id: transactionLink.userId })
+      let redeemedBy: User | null = null
+      if (transactionLink && transactionLink.redeemedBy) {
+        redeemedBy = new User(await dbUser.findOneOrFail({ id: transactionLink.redeemedBy }))
+      }
+      return new TransactionLink(transactionLink, new User(user), redeemedBy)
     }
-    return new TransactionLink(transactionLink, new User(user), redeemedBy)
   }
 
   @Authorized([RIGHTS.LIST_TRANSACTION_LINKS])
@@ -137,31 +170,137 @@ export class TransactionLinkResolver {
     @Ctx() context: Context,
   ): Promise<boolean> {
     const user = getUser(context)
-    const transactionLink = await dbTransactionLink.findOneOrFail({ code })
-    const linkedUser = await dbUser.findOneOrFail({ id: transactionLink.userId })
-
     const now = new Date()
 
-    if (user.id === linkedUser.id) {
-      throw new Error('Cannot redeem own transaction link.')
+    if (code.match(/^CL-/)) {
+      logger.info('redeem contribution link...')
+      const queryRunner = getConnection().createQueryRunner()
+      await queryRunner.connect()
+      await queryRunner.startTransaction('SERIALIZABLE')
+      try {
+        const contributionLink = await queryRunner.manager
+          .createQueryBuilder()
+          .select('contributionLink')
+          .from(DbContributionLink, 'contributionLink')
+          .where('contributionLink.code = :code', { code: code.replace('CL-', '') })
+          .getOne()
+        if (!contributionLink) {
+          logger.error('no contribution link found to given code:', code)
+          throw new Error('No contribution link found')
+        }
+        logger.info('...contribution link found with id', contributionLink.id)
+        if (new Date(contributionLink.validFrom).getTime() > now.getTime()) {
+          logger.error(
+            'contribution link is not valid yet. Valid from: ',
+            contributionLink.validFrom,
+          )
+          throw new Error('Contribution link not valid yet')
+        }
+        if (contributionLink.validTo) {
+          if (new Date(contributionLink.validTo).setHours(23, 59, 59) < now.getTime()) {
+            logger.error('contribution link is depricated. Valid to: ', contributionLink.validTo)
+            throw new Error('Contribution link is depricated')
+          }
+        }
+        if (contributionLink.cycle !== 'ONCE') {
+          logger.error('contribution link has unknown cycle', contributionLink.cycle)
+          throw new Error('Contribution link has unknown cycle')
+        }
+        // Test ONCE rule
+        const alreadyRedeemed = await queryRunner.manager
+          .createQueryBuilder()
+          .select('contribution')
+          .from(DbContribution, 'contribution')
+          .where('contribution.contributionLinkId = :linkId AND contribution.userId = :id', {
+            linkId: contributionLink.id,
+            id: user.id,
+          })
+          .getOne()
+        if (alreadyRedeemed) {
+          logger.error('contribution link with rule ONCE already redeemed by user with id', user.id)
+          throw new Error('Contribution link already redeemed')
+        }
+
+        const creations = await getUserCreation(user.id, false)
+        logger.info('open creations', creations)
+        validateContribution(creations, contributionLink.amount, now)
+        const contribution = new DbContribution()
+        contribution.userId = user.id
+        contribution.createdAt = now
+        contribution.contributionDate = now
+        contribution.memo = contributionLink.memo
+        contribution.amount = contributionLink.amount
+        contribution.contributionLinkId = contributionLink.id
+        await queryRunner.manager.insert(DbContribution, contribution)
+
+        const lastTransaction = await queryRunner.manager
+          .createQueryBuilder()
+          .select('transaction')
+          .from(DbTransaction, 'transaction')
+          .where('transaction.userId = :id', { id: user.id })
+          .orderBy('transaction.balanceDate', 'DESC')
+          .getOne()
+        let newBalance = new Decimal(0)
+
+        let decay: Decay | null = null
+        if (lastTransaction) {
+          decay = calculateDecay(lastTransaction.balance, lastTransaction.balanceDate, now)
+          newBalance = decay.balance
+        }
+        newBalance = newBalance.add(contributionLink.amount.toString())
+
+        const transaction = new DbTransaction()
+        transaction.typeId = TransactionTypeId.CREATION
+        transaction.memo = contribution.memo
+        transaction.userId = contribution.userId
+        transaction.previous = lastTransaction ? lastTransaction.id : null
+        transaction.amount = contribution.amount
+        transaction.creationDate = contribution.contributionDate
+        transaction.balance = newBalance
+        transaction.balanceDate = now
+        transaction.decay = decay ? decay.decay : new Decimal(0)
+        transaction.decayStart = decay ? decay.start : null
+        await queryRunner.manager.insert(DbTransaction, transaction)
+
+        contribution.confirmedAt = now
+        contribution.transactionId = transaction.id
+        await queryRunner.manager.update(DbContribution, { id: contribution.id }, contribution)
+
+        await queryRunner.commitTransaction()
+        logger.info('creation from contribution link commited successfuly.')
+      } catch (e) {
+        await queryRunner.rollbackTransaction()
+        logger.error(`Creation from contribution link was not successful: ${e}`)
+        throw new Error(`Creation from contribution link was not successful. ${e}`)
+      } finally {
+        await queryRunner.release()
+      }
+      return true
+    } else {
+      const transactionLink = await dbTransactionLink.findOneOrFail({ code })
+      const linkedUser = await dbUser.findOneOrFail({ id: transactionLink.userId })
+
+      if (user.id === linkedUser.id) {
+        throw new Error('Cannot redeem own transaction link.')
+      }
+
+      if (transactionLink.validUntil.getTime() < now.getTime()) {
+        throw new Error('Transaction Link is not valid anymore.')
+      }
+
+      if (transactionLink.redeemedBy) {
+        throw new Error('Transaction Link already redeemed.')
+      }
+
+      await executeTransaction(
+        transactionLink.amount,
+        transactionLink.memo,
+        linkedUser,
+        user,
+        transactionLink,
+      )
+
+      return true
     }
-
-    if (transactionLink.validUntil.getTime() < now.getTime()) {
-      throw new Error('Transaction Link is not valid anymore.')
-    }
-
-    if (transactionLink.redeemedBy) {
-      throw new Error('Transaction Link already redeemed.')
-    }
-
-    await executeTransaction(
-      transactionLink.amount,
-      transactionLink.memo,
-      linkedUser,
-      user,
-      transactionLink,
-    )
-
-    return true
   }
 }
diff --git a/backend/src/graphql/resolver/TransactionResolver.ts b/backend/src/graphql/resolver/TransactionResolver.ts
index 023e5b2ff..bc062a1f4 100644
--- a/backend/src/graphql/resolver/TransactionResolver.ts
+++ b/backend/src/graphql/resolver/TransactionResolver.ts
@@ -34,9 +34,7 @@ import { virtualLinkTransaction, virtualDecayTransaction } from '@/util/virtualT
 import Decimal from 'decimal.js-light'
 
 import { BalanceResolver } from './BalanceResolver'
-
-const MEMO_MAX_CHARS = 255
-const MEMO_MIN_CHARS = 5
+import { MEMO_MAX_CHARS, MEMO_MIN_CHARS } from './const/const'
 
 export const executeTransaction = async (
   amount: Decimal,
diff --git a/backend/src/graphql/resolver/UserResolver.test.ts b/backend/src/graphql/resolver/UserResolver.test.ts
index 78b630834..a2a499224 100644
--- a/backend/src/graphql/resolver/UserResolver.test.ts
+++ b/backend/src/graphql/resolver/UserResolver.test.ts
@@ -11,8 +11,13 @@ import { LoginEmailOptIn } from '@entity/LoginEmailOptIn'
 import { User } from '@entity/User'
 import CONFIG from '@/config'
 import { sendAccountActivationEmail } from '@/mailer/sendAccountActivationEmail'
+import { sendAccountMultiRegistrationEmail } from '@/mailer/sendAccountMultiRegistrationEmail'
 import { sendResetPasswordEmail } from '@/mailer/sendResetPasswordEmail'
 import { printTimeDuration, activationLink } from './UserResolver'
+import { contributionLinkFactory } from '@/seeds/factory/contributionLink'
+// import { transactionLinkFactory } from '@/seeds/factory/transactionLink'
+import { ContributionLink } from '@model/ContributionLink'
+// import { TransactionLink } from '@entity/TransactionLink'
 
 import { logger } from '@test/testSetup'
 
@@ -25,6 +30,13 @@ jest.mock('@/mailer/sendAccountActivationEmail', () => {
   }
 })
 
+jest.mock('@/mailer/sendAccountMultiRegistrationEmail', () => {
+  return {
+    __esModule: true,
+    sendAccountMultiRegistrationEmail: jest.fn(),
+  }
+})
+
 jest.mock('@/mailer/sendResetPasswordEmail', () => {
   return {
     __esModule: true,
@@ -69,6 +81,7 @@ describe('UserResolver', () => {
 
     let result: any
     let emailOptIn: string
+    let user: User[]
 
     beforeAll(async () => {
       jest.clearAllMocks()
@@ -86,7 +99,6 @@ describe('UserResolver', () => {
     })
 
     describe('valid input data', () => {
-      let user: User[]
       let loginEmailOptIn: LoginEmailOptIn[]
       beforeAll(async () => {
         user = await User.find()
@@ -114,6 +126,7 @@ describe('UserResolver', () => {
               deletedAt: null,
               publisherId: 1234,
               referrerId: null,
+              contributionLinkId: null,
             },
           ])
         })
@@ -151,14 +164,33 @@ describe('UserResolver', () => {
     })
 
     describe('email already exists', () => {
-      it('throws and logs an error', async () => {
-        const mutation = await mutate({ mutation: createUser, variables })
+      let mutation: User
+      beforeAll(async () => {
+        mutation = await mutate({ mutation: createUser, variables })
+      })
+
+      it('logs an info', async () => {
+        expect(logger.info).toBeCalledWith('User already exists with this email=peter@lustig.de')
+      })
+
+      it('sends an account multi registration email', () => {
+        expect(sendAccountMultiRegistrationEmail).toBeCalledWith({
+          firstName: 'Peter',
+          lastName: 'Lustig',
+          email: 'peter@lustig.de',
+        })
+      })
+
+      it('results with partly faked user with random "id"', async () => {
         expect(mutation).toEqual(
           expect.objectContaining({
-            errors: [new GraphQLError('User already exists.')],
+            data: {
+              createUser: {
+                id: expect.any(Number),
+              },
+            },
           }),
         )
-        expect(logger.error).toBeCalledWith('User already exists with this email=peter@lustig.de')
       })
     })
 
@@ -195,6 +227,72 @@ describe('UserResolver', () => {
         )
       })
     })
+
+    describe('redeem codes', () => {
+      describe('contribution link', () => {
+        let link: ContributionLink
+        beforeAll(async () => {
+          // activate account of admin Peter Lustig
+          await mutate({
+            mutation: setPassword,
+            variables: { code: emailOptIn, password: 'Aa12345_' },
+          })
+          // make Peter Lustig Admin
+          const peter = await User.findOneOrFail({ id: user[0].id })
+          peter.isAdmin = new Date()
+          await peter.save()
+          // factory logs in as Peter Lustig
+          link = await contributionLinkFactory(testEnv, {
+            name: 'Dokumenta 2022',
+            memo: 'Vielen Dank für deinen Besuch bei der Dokumenta 2022',
+            amount: 200,
+            validFrom: new Date(2022, 5, 18),
+            validTo: new Date(2022, 8, 25),
+          })
+          resetToken()
+          await mutate({
+            mutation: createUser,
+            variables: { ...variables, email: 'ein@besucher.de', redeemCode: 'CL-' + link.code },
+          })
+        })
+
+        it('sets the contribution link id', async () => {
+          await expect(User.findOne({ email: 'ein@besucher.de' })).resolves.toEqual(
+            expect.objectContaining({
+              contributionLinkId: link.id,
+            }),
+          )
+        })
+      })
+
+      /* A transaction link requires GDD on account
+      describe('transaction link', () => {
+        let code: string
+        beforeAll(async () => {
+          // factory logs in as Peter Lustig
+          await transactionLinkFactory(testEnv, {
+            email: 'peter@lustig.de',
+            amount: 19.99,
+            memo: `Kein Trick, keine Zauberrei,
+bei Gradidio sei dabei!`,
+          })
+          const transactionLink = await TransactionLink.findOneOrFail()
+          resetToken()
+          await mutate({
+            mutation: createUser,
+            variables: { ...variables, email: 'neuer@user.de', redeemCode: transactionLink.code },
+          })          
+        })
+
+        it('sets the referrer id to Peter Lustigs id', async () => {
+          await expect(User.findOne({ email: 'neuer@user.de' })).resolves.toEqual(expect.objectContaining({
+            referrerId: user[0].id,
+          }))
+        })
+      })
+
+      */
+    })
   })
 
   describe('setPassword', () => {
diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts
index 9b42d76b5..a89a8cb0b 100644
--- a/backend/src/graphql/resolver/UserResolver.ts
+++ b/backend/src/graphql/resolver/UserResolver.ts
@@ -7,7 +7,9 @@ import { getConnection } from '@dbTools/typeorm'
 import CONFIG from '@/config'
 import { User } from '@model/User'
 import { User as DbUser } from '@entity/User'
+import { communityDbUser } from '@/util/communityUser'
 import { TransactionLink as dbTransactionLink } from '@entity/TransactionLink'
+import { ContributionLink as dbContributionLink } from '@entity/ContributionLink'
 import { encode } from '@/auth/JWT'
 import CreateUserArgs from '@arg/CreateUserArgs'
 import UnsecureLoginArgs from '@arg/UnsecureLoginArgs'
@@ -17,9 +19,19 @@ import { OptInType } from '@enum/OptInType'
 import { LoginEmailOptIn } from '@entity/LoginEmailOptIn'
 import { sendResetPasswordEmail as sendResetPasswordEmailMailer } from '@/mailer/sendResetPasswordEmail'
 import { sendAccountActivationEmail } from '@/mailer/sendAccountActivationEmail'
+import { sendAccountMultiRegistrationEmail } from '@/mailer/sendAccountMultiRegistrationEmail'
 import { klicktippSignIn } from '@/apis/KlicktippController'
 import { RIGHTS } from '@/auth/RIGHTS'
 import { hasElopageBuys } from '@/util/hasElopageBuys'
+import { eventProtocol } from '@/event/EventProtocolEmitter'
+import {
+  Event,
+  EventLogin,
+  EventRedeemRegister,
+  EventRegister,
+  EventSendConfirmationEmail,
+} from '@/event/Event'
+import { getUserCreation } from './util/creations'
 
 // eslint-disable-next-line @typescript-eslint/no-var-requires
 const sodium = require('sodium-native')
@@ -221,7 +233,7 @@ export class UserResolver {
     logger.info('verifyLogin...')
     // TODO refactor and do not have duplicate code with login(see below)
     const userEntity = getUser(context)
-    const user = new User(userEntity)
+    const user = new User(userEntity, await getUserCreation(userEntity.id))
     // user.pubkey = userEntity.pubKey.toString('hex')
     // Elopage Status & Stored PublisherId
     user.hasElopage = await this.hasElopage(context)
@@ -271,7 +283,7 @@ export class UserResolver {
     logger.addContext('user', dbUser.id)
     logger.debug('login credentials valid...')
 
-    const user = new User(dbUser)
+    const user = new User(dbUser, await getUserCreation(dbUser.id))
     logger.debug('user=' + user)
 
     // Elopage Status & Stored PublisherId
@@ -287,6 +299,9 @@ export class UserResolver {
       key: 'token',
       value: encode(dbUser.pubKey),
     })
+    const ev = new EventLogin()
+    ev.userId = user.id
+    eventProtocol.writeEvent(new Event().setEventLogin(ev))
     logger.info('successful Login:' + user)
     return user
   }
@@ -327,10 +342,35 @@ export class UserResolver {
     // TODO we cannot use repository.count(), since it does not allow to specify if you want to include the soft deletes
     const userFound = await DbUser.findOne({ email }, { withDeleted: true })
     logger.info(`DbUser.findOne(email=${email}) = ${userFound}`)
+
     if (userFound) {
-      logger.error('User already exists with this email=' + email)
+      logger.info('User already exists with this email=' + email)
       // TODO: this is unsecure, but the current implementation of the login server. This way it can be queried if the user with given EMail is existent.
-      throw new Error(`User already exists.`)
+
+      const user = new User(communityDbUser)
+      user.id = sodium.randombytes_random() % (2048 * 16) // TODO: for a better faking derive id from email so that it will be always the same id when the same email comes in?
+      user.email = email
+      user.firstName = firstName
+      user.lastName = lastName
+      user.language = language
+      user.publisherId = publisherId
+      logger.debug('partly faked user=' + user)
+
+      // eslint-disable-next-line @typescript-eslint/no-unused-vars
+      const emailSent = await sendAccountMultiRegistrationEmail({
+        firstName,
+        lastName,
+        email,
+      })
+      logger.info(`sendAccountMultiRegistrationEmail of ${firstName}.${lastName} to ${email}`)
+      /* uncomment this, when you need the activation link on the console */
+      // In case EMails are disabled log the activation link for the user
+      if (!emailSent) {
+        logger.debug(`Email not send!`)
+      }
+      logger.info('createUser() faked and send multi registration mail...')
+
+      return user
     }
 
     const passphrase = PassphraseGenerate()
@@ -339,6 +379,9 @@ export class UserResolver {
     // const encryptedPrivkey = SecretKeyCryptographyEncrypt(keyPair[1], passwordHash[1])
     const emailHash = getEmailHash(email)
 
+    const eventRegister = new EventRegister()
+    const eventRedeemRegister = new EventRedeemRegister()
+    const eventSendConfirmEmail = new EventSendConfirmationEmail()
     const dbUser = new DbUser()
     dbUser.email = email
     dbUser.firstName = firstName
@@ -349,10 +392,22 @@ export class UserResolver {
     dbUser.passphrase = passphrase.join(' ')
     logger.debug('new dbUser=' + dbUser)
     if (redeemCode) {
-      const transactionLink = await dbTransactionLink.findOne({ code: redeemCode })
-      logger.info('redeemCode found transactionLink=' + transactionLink)
-      if (transactionLink) {
-        dbUser.referrerId = transactionLink.userId
+      if (redeemCode.match(/^CL-/)) {
+        const contributionLink = await dbContributionLink.findOne({
+          code: redeemCode.replace('CL-', ''),
+        })
+        logger.info('redeemCode found contributionLink=' + contributionLink)
+        if (contributionLink) {
+          dbUser.contributionLinkId = contributionLink.id
+          eventRedeemRegister.contributionId = contributionLink.id
+        }
+      } else {
+        const transactionLink = await dbTransactionLink.findOne({ code: redeemCode })
+        logger.info('redeemCode found transactionLink=' + transactionLink)
+        if (transactionLink) {
+          dbUser.referrerId = transactionLink.userId
+          eventRedeemRegister.transactionId = transactionLink.id
+        }
       }
     }
     // TODO this field has no null allowed unlike the loginServer table
@@ -362,6 +417,7 @@ export class UserResolver {
     // loginUser.pubKey = keyPair[0]
     // loginUser.privKey = encryptedPrivkey
 
+    const event = new Event()
     const queryRunner = getConnection().createQueryRunner()
     await queryRunner.connect()
     await queryRunner.startTransaction('READ UNCOMMITTED')
@@ -391,6 +447,9 @@ export class UserResolver {
         duration: printTimeDuration(CONFIG.EMAIL_CODE_VALID_TIME),
       })
       logger.info(`sendAccountActivationEmail of ${firstName}.${lastName} to ${email}`)
+      eventSendConfirmEmail.userId = dbUser.id
+      eventProtocol.writeEvent(event.setEventSendConfirmationEmail(eventSendConfirmEmail))
+
       /* uncomment this, when you need the activation link on the console */
       // In case EMails are disabled log the activation link for the user
       if (!emailSent) {
@@ -406,6 +465,15 @@ export class UserResolver {
       await queryRunner.release()
     }
     logger.info('createUser() successful...')
+
+    if (redeemCode) {
+      eventRedeemRegister.userId = dbUser.id
+      eventProtocol.writeEvent(event.setEventRedeemRegister(eventRedeemRegister))
+    } else {
+      eventRegister.userId = dbUser.id
+      eventProtocol.writeEvent(event.setEventRegister(eventRegister))
+    }
+
     return new User(dbUser)
   }
 
diff --git a/backend/src/graphql/resolver/const/const.ts b/backend/src/graphql/resolver/const/const.ts
new file mode 100644
index 000000000..e4eb9a13b
--- /dev/null
+++ b/backend/src/graphql/resolver/const/const.ts
@@ -0,0 +1,12 @@
+import Decimal from 'decimal.js-light'
+
+export const MAX_CREATION_AMOUNT = new Decimal(1000)
+export const FULL_CREATION_AVAILABLE = [
+  MAX_CREATION_AMOUNT,
+  MAX_CREATION_AMOUNT,
+  MAX_CREATION_AMOUNT,
+]
+export const CONTRIBUTIONLINK_NAME_MAX_CHARS = 100
+export const CONTRIBUTIONLINK_NAME_MIN_CHARS = 5
+export const MEMO_MAX_CHARS = 255
+export const MEMO_MIN_CHARS = 5
diff --git a/backend/src/graphql/resolver/util/creations.ts b/backend/src/graphql/resolver/util/creations.ts
new file mode 100644
index 000000000..ad15ebec6
--- /dev/null
+++ b/backend/src/graphql/resolver/util/creations.ts
@@ -0,0 +1,130 @@
+import { TransactionTypeId } from '@/graphql/enum/TransactionTypeId'
+import { backendLogger as logger } from '@/server/logger'
+import { getConnection } from '@dbTools/typeorm'
+import { Contribution } from '@entity/Contribution'
+import Decimal from 'decimal.js-light'
+import { FULL_CREATION_AVAILABLE, MAX_CREATION_AMOUNT } from '../const/const'
+
+interface CreationMap {
+  id: number
+  creations: Decimal[]
+}
+
+export const validateContribution = (
+  creations: Decimal[],
+  amount: Decimal,
+  creationDate: Date,
+): void => {
+  logger.trace('isContributionValid', creations, amount, creationDate)
+  const index = getCreationIndex(creationDate.getMonth())
+
+  if (index < 0) {
+    throw new Error('No information for available creations for the given date')
+  }
+
+  if (amount.greaterThan(creations[index].toString())) {
+    throw new Error(
+      `The amount (${amount} GDD) to be created exceeds the amount (${creations[index]} GDD) still available for this month.`,
+    )
+  }
+}
+
+export const getUserCreations = async (
+  ids: number[],
+  includePending = true,
+): Promise<CreationMap[]> => {
+  logger.trace('getUserCreations:', ids, includePending)
+  const months = getCreationMonths()
+  logger.trace('getUserCreations months', months)
+
+  const queryRunner = getConnection().createQueryRunner()
+  await queryRunner.connect()
+
+  const dateFilter = 'last_day(curdate() - interval 3 month) + interval 1 day'
+  logger.trace('getUserCreations dateFilter', dateFilter)
+
+  const unionString = includePending
+    ? `
+    UNION
+      SELECT contribution_date AS date, amount AS amount, user_id AS userId FROM contributions
+        WHERE user_id IN (${ids.toString()})
+        AND contribution_date >= ${dateFilter}
+        AND confirmed_at IS NULL AND deleted_at IS NULL`
+    : ''
+
+  const unionQuery = await queryRunner.manager.query(`
+    SELECT MONTH(date) AS month, sum(amount) AS sum, userId AS id FROM
+      (SELECT creation_date AS date, amount AS amount, user_id AS userId FROM transactions
+        WHERE user_id IN (${ids.toString()})
+        AND type_id = ${TransactionTypeId.CREATION}
+        AND creation_date >= ${dateFilter}
+      ${unionString}) AS result
+    GROUP BY month, userId
+    ORDER BY date DESC
+  `)
+
+  await queryRunner.release()
+
+  return ids.map((id) => {
+    return {
+      id,
+      creations: months.map((month) => {
+        const creation = unionQuery.find(
+          (raw: { month: string; id: string; creation: number[] }) =>
+            parseInt(raw.month) === month && parseInt(raw.id) === id,
+        )
+        return MAX_CREATION_AMOUNT.minus(creation ? creation.sum : 0)
+      }),
+    }
+  })
+}
+
+export const getUserCreation = async (id: number, includePending = true): Promise<Decimal[]> => {
+  logger.trace('getUserCreation', id, includePending)
+  const creations = await getUserCreations([id], includePending)
+  return creations[0] ? creations[0].creations : FULL_CREATION_AVAILABLE
+}
+
+export const getCreationMonths = (): number[] => {
+  const now = new Date(Date.now())
+  return [
+    now.getMonth() + 1,
+    new Date(now.getFullYear(), now.getMonth() - 1, 1).getMonth() + 1,
+    new Date(now.getFullYear(), now.getMonth() - 2, 1).getMonth() + 1,
+  ].reverse()
+}
+
+export const getCreationIndex = (month: number): number => {
+  return getCreationMonths().findIndex((el) => el === month + 1)
+}
+
+export const isStartEndDateValid = (
+  startDate: string | null | undefined,
+  endDate: string | null | undefined,
+): void => {
+  if (!startDate) {
+    logger.error('Start-Date is not initialized. A Start-Date must be set!')
+    throw new Error('Start-Date is not initialized. A Start-Date must be set!')
+  }
+
+  if (!endDate) {
+    logger.error('End-Date is not initialized. An End-Date must be set!')
+    throw new Error('End-Date is not initialized. An End-Date must be set!')
+  }
+
+  // check if endDate is before startDate
+  if (new Date(endDate).getTime() - new Date(startDate).getTime() < 0) {
+    logger.error(`The value of validFrom must before or equals the validTo!`)
+    throw new Error(`The value of validFrom must before or equals the validTo!`)
+  }
+}
+
+export const updateCreations = (creations: Decimal[], contribution: Contribution): Decimal[] => {
+  const index = getCreationIndex(contribution.contributionDate.getMonth())
+
+  if (index < 0) {
+    throw new Error('You cannot create GDD for a month older than the last three months.')
+  }
+  creations[index] = creations[index].plus(contribution.amount.toString())
+  return creations
+}
diff --git a/backend/src/mailer/sendAccountMultiRegistrationEmail.test.ts b/backend/src/mailer/sendAccountMultiRegistrationEmail.test.ts
new file mode 100644
index 000000000..bb37a196e
--- /dev/null
+++ b/backend/src/mailer/sendAccountMultiRegistrationEmail.test.ts
@@ -0,0 +1,31 @@
+import CONFIG from '@/config'
+import { sendAccountMultiRegistrationEmail } from './sendAccountMultiRegistrationEmail'
+import { sendEMail } from './sendEMail'
+
+jest.mock('./sendEMail', () => {
+  return {
+    __esModule: true,
+    sendEMail: jest.fn(),
+  }
+})
+
+describe('sendAccountMultiRegistrationEmail', () => {
+  beforeEach(async () => {
+    await sendAccountMultiRegistrationEmail({
+      firstName: 'Peter',
+      lastName: 'Lustig',
+      email: 'peter@lustig.de',
+    })
+  })
+
+  it('calls sendEMail', () => {
+    expect(sendEMail).toBeCalledWith({
+      to: `Peter Lustig <peter@lustig.de>`,
+      subject: 'Gradido: Erneuter Registrierungsversuch mit deiner E-Mail',
+      text:
+        expect.stringContaining('Hallo Peter Lustig') &&
+        expect.stringContaining(CONFIG.EMAIL_LINK_FORGOTPASSWORD) &&
+        expect.stringContaining('https://gradido.net/de/contact/'),
+    })
+  })
+})
diff --git a/backend/src/mailer/sendAccountMultiRegistrationEmail.ts b/backend/src/mailer/sendAccountMultiRegistrationEmail.ts
new file mode 100644
index 000000000..18928770b
--- /dev/null
+++ b/backend/src/mailer/sendAccountMultiRegistrationEmail.ts
@@ -0,0 +1,18 @@
+import { sendEMail } from './sendEMail'
+import { accountMultiRegistration } from './text/accountMultiRegistration'
+import CONFIG from '@/config'
+
+export const sendAccountMultiRegistrationEmail = (data: {
+  firstName: string
+  lastName: string
+  email: string
+}): Promise<boolean> => {
+  return sendEMail({
+    to: `${data.firstName} ${data.lastName} <${data.email}>`,
+    subject: accountMultiRegistration.de.subject,
+    text: accountMultiRegistration.de.text({
+      ...data,
+      resendLink: CONFIG.EMAIL_LINK_FORGOTPASSWORD,
+    }),
+  })
+}
diff --git a/backend/src/mailer/sendEMail.test.ts b/backend/src/mailer/sendEMail.test.ts
index 8a13c027d..5746f1ead 100644
--- a/backend/src/mailer/sendEMail.test.ts
+++ b/backend/src/mailer/sendEMail.test.ts
@@ -31,6 +31,7 @@ describe('sendEMail', () => {
     beforeEach(async () => {
       result = await sendEMail({
         to: 'receiver@mail.org',
+        cc: 'support@gradido.net',
         subject: 'Subject',
         text: 'Text text text',
       })
@@ -50,6 +51,7 @@ describe('sendEMail', () => {
       CONFIG.EMAIL = true
       result = await sendEMail({
         to: 'receiver@mail.org',
+        cc: 'support@gradido.net',
         subject: 'Subject',
         text: 'Text text text',
       })
@@ -72,6 +74,7 @@ describe('sendEMail', () => {
       expect((createTransport as jest.Mock).mock.results[0].value.sendMail).toBeCalledWith({
         from: `Gradido (nicht antworten) <${CONFIG.EMAIL_SENDER}>`,
         to: 'receiver@mail.org',
+        cc: 'support@gradido.net',
         subject: 'Subject',
         text: 'Text text text',
       })
diff --git a/backend/src/mailer/sendEMail.ts b/backend/src/mailer/sendEMail.ts
index 640dd7f4c..746daa810 100644
--- a/backend/src/mailer/sendEMail.ts
+++ b/backend/src/mailer/sendEMail.ts
@@ -5,10 +5,15 @@ import CONFIG from '@/config'
 
 export const sendEMail = async (emailDef: {
   to: string
+  cc?: string
   subject: string
   text: string
 }): Promise<boolean> => {
-  logger.info(`send Email: to=${emailDef.to}, subject=${emailDef.subject}, text=${emailDef.text}`)
+  logger.info(
+    `send Email: to=${emailDef.to}` +
+      (emailDef.cc ? `, cc=${emailDef.cc}` : '') +
+      `, subject=${emailDef.subject}, text=${emailDef.text}`,
+  )
 
   if (!CONFIG.EMAIL) {
     logger.info(`Emails are disabled via config...`)
diff --git a/backend/src/mailer/text/accountMultiRegistration.ts b/backend/src/mailer/text/accountMultiRegistration.ts
new file mode 100644
index 000000000..c5b55bac5
--- /dev/null
+++ b/backend/src/mailer/text/accountMultiRegistration.ts
@@ -0,0 +1,25 @@
+export const accountMultiRegistration = {
+  de: {
+    subject: 'Gradido: Erneuter Registrierungsversuch mit deiner E-Mail',
+    text: (data: {
+      firstName: string
+      lastName: string
+      email: string
+      resendLink: string
+    }): string =>
+      `Hallo ${data.firstName} ${data.lastName},
+
+Deine E-Mail-Adresse wurde soeben erneut benutzt, um bei Gradido ein Konto zu registrieren.
+Es existiert jedoch zu deiner E-Mail-Adresse schon ein Konto.
+
+Klicke bitte auf den folgenden Link, falls du dein Passwort vergessen haben solltest:
+${data.resendLink}
+oder kopiere den obigen Link in dein Browserfenster.
+
+Wenn du nicht derjenige bist, der sich versucht hat erneut zu registrieren, wende dich bitte an unseren support:
+https://gradido.net/de/contact/
+
+Mit freundlichen Grüßen,
+dein Gradido-Team`,
+  },
+}
diff --git a/backend/src/seeds/contributionLink/ContributionLinkInterface.ts b/backend/src/seeds/contributionLink/ContributionLinkInterface.ts
new file mode 100644
index 000000000..15ba4b72d
--- /dev/null
+++ b/backend/src/seeds/contributionLink/ContributionLinkInterface.ts
@@ -0,0 +1,7 @@
+export interface ContributionLinkInterface {
+  amount: number
+  name: string
+  memo: string
+  validFrom?: Date
+  validTo?: Date
+}
diff --git a/backend/src/seeds/contributionLink/index.ts b/backend/src/seeds/contributionLink/index.ts
new file mode 100644
index 000000000..41d28eb60
--- /dev/null
+++ b/backend/src/seeds/contributionLink/index.ts
@@ -0,0 +1,18 @@
+import { ContributionLinkInterface } from './ContributionLinkInterface'
+
+export const contributionLinks: ContributionLinkInterface[] = [
+  {
+    name: 'Dokumenta 2017',
+    memo: 'Vielen Dank für deinen Besuch bei der Dokumenta 2017',
+    amount: 200,
+    validFrom: new Date(2017, 3, 8),
+    validTo: new Date(2017, 6, 16),
+  },
+  {
+    name: 'Dokumenta 2022',
+    memo: 'Vielen Dank für deinen Besuch bei der Dokumenta 2022',
+    amount: 200,
+    validFrom: new Date(2022, 5, 18),
+    validTo: new Date(2022, 8, 25),
+  },
+]
diff --git a/backend/src/seeds/factory/contributionLink.ts b/backend/src/seeds/factory/contributionLink.ts
new file mode 100644
index 000000000..5c83b6ad3
--- /dev/null
+++ b/backend/src/seeds/factory/contributionLink.ts
@@ -0,0 +1,29 @@
+import { ApolloServerTestClient } from 'apollo-server-testing'
+import { createContributionLink } from '@/seeds/graphql/mutations'
+import { login } from '@/seeds/graphql/queries'
+import { ContributionLink } from '@model/ContributionLink'
+import { ContributionLinkInterface } from '@/seeds/contributionLink/ContributionLinkInterface'
+
+export const contributionLinkFactory = async (
+  client: ApolloServerTestClient,
+  contributionLink: ContributionLinkInterface,
+): Promise<ContributionLink> => {
+  const { mutate, query } = client
+
+  // login as admin
+  await query({ query: login, variables: { email: 'peter@lustig.de', password: 'Aa12345_' } })
+
+  const variables = {
+    amount: contributionLink.amount,
+    memo: contributionLink.memo,
+    name: contributionLink.name,
+    cycle: 'ONCE',
+    maxPerCycle: 1,
+    maxAmountPerMonth: 200,
+    validFrom: contributionLink.validFrom ? contributionLink.validFrom.toISOString() : undefined,
+    validTo: contributionLink.validTo ? contributionLink.validTo.toISOString() : undefined,
+  }
+
+  const result = await mutate({ mutation: createContributionLink, variables })
+  return result.data.createContributionLink
+}
diff --git a/backend/src/seeds/factory/creation.ts b/backend/src/seeds/factory/creation.ts
index e49be3758..d3f0f78ca 100644
--- a/backend/src/seeds/factory/creation.ts
+++ b/backend/src/seeds/factory/creation.ts
@@ -1,13 +1,13 @@
 /* eslint-disable @typescript-eslint/no-explicit-any */
 /* eslint-disable @typescript-eslint/explicit-module-boundary-types */
 
-import { createPendingCreation, confirmPendingCreation } from '@/seeds/graphql/mutations'
+import { adminCreateContribution, confirmContribution } from '@/seeds/graphql/mutations'
 import { login } from '@/seeds/graphql/queries'
 import { CreationInterface } from '@/seeds/creation/CreationInterface'
 import { ApolloServerTestClient } from 'apollo-server-testing'
 import { User } from '@entity/User'
 import { Transaction } from '@entity/Transaction'
-import { AdminPendingCreation } from '@entity/AdminPendingCreation'
+import { Contribution } from '@entity/Contribution'
 // import CONFIG from '@/config/index'
 
 export const nMonthsBefore = (date: Date, months = 1): string => {
@@ -17,23 +17,25 @@ export const nMonthsBefore = (date: Date, months = 1): string => {
 export const creationFactory = async (
   client: ApolloServerTestClient,
   creation: CreationInterface,
-): Promise<AdminPendingCreation | void> => {
+): Promise<Contribution | void> => {
   const { mutate, query } = client
 
   await query({ query: login, variables: { email: 'peter@lustig.de', password: 'Aa12345_' } })
 
   // TODO it would be nice to have this mutation return the id
-  await mutate({ mutation: createPendingCreation, variables: { ...creation } })
+  await mutate({ mutation: adminCreateContribution, variables: { ...creation } })
 
   const user = await User.findOneOrFail({ where: { email: creation.email } })
 
-  const pendingCreation = await AdminPendingCreation.findOneOrFail({
+  const pendingCreation = await Contribution.findOneOrFail({
     where: { userId: user.id, amount: creation.amount },
-    order: { created: 'DESC' },
+    order: { createdAt: 'DESC' },
   })
 
   if (creation.confirmed) {
-    await mutate({ mutation: confirmPendingCreation, variables: { id: pendingCreation.id } })
+    await mutate({ mutation: confirmContribution, variables: { id: pendingCreation.id } })
+
+    const confirmedCreation = await Contribution.findOneOrFail({ id: pendingCreation.id })
 
     if (creation.moveCreationDate) {
       const transaction = await Transaction.findOneOrFail({
@@ -41,6 +43,9 @@ export const creationFactory = async (
         order: { balanceDate: 'DESC' },
       })
       if (transaction.decay.equals(0) && transaction.creationDate) {
+        confirmedCreation.contributionDate = new Date(
+          nMonthsBefore(transaction.creationDate, creation.moveCreationDate),
+        )
         transaction.creationDate = new Date(
           nMonthsBefore(transaction.creationDate, creation.moveCreationDate),
         )
@@ -48,6 +53,7 @@ export const creationFactory = async (
           nMonthsBefore(transaction.balanceDate, creation.moveCreationDate),
         )
         await transaction.save()
+        await confirmedCreation.save()
       }
     }
   } else {
diff --git a/backend/src/seeds/graphql/mutations.ts b/backend/src/seeds/graphql/mutations.ts
index e66827566..bf898bd7d 100644
--- a/backend/src/seeds/graphql/mutations.ts
+++ b/backend/src/seeds/graphql/mutations.ts
@@ -81,15 +81,26 @@ export const createTransactionLink = gql`
 
 // from admin interface
 
-export const createPendingCreation = gql`
+export const adminCreateContribution = gql`
   mutation ($email: String!, $amount: Decimal!, $memo: String!, $creationDate: String!) {
-    createPendingCreation(email: $email, amount: $amount, memo: $memo, creationDate: $creationDate)
+    adminCreateContribution(
+      email: $email
+      amount: $amount
+      memo: $memo
+      creationDate: $creationDate
+    )
   }
 `
 
-export const confirmPendingCreation = gql`
+export const confirmContribution = gql`
   mutation ($id: Int!) {
-    confirmPendingCreation(id: $id)
+    confirmContribution(id: $id)
+  }
+`
+
+export const setUserRole = gql`
+  mutation ($userId: Int!, $isAdmin: Boolean!) {
+    setUserRole(userId: $userId, isAdmin: $isAdmin)
   }
 `
 
@@ -105,19 +116,19 @@ export const unDeleteUser = gql`
   }
 `
 
-export const createPendingCreations = gql`
-  mutation ($pendingCreations: [CreatePendingCreationArgs!]!) {
-    createPendingCreations(pendingCreations: $pendingCreations) {
+export const adminCreateContributions = gql`
+  mutation ($pendingCreations: [AdminCreateContributionArgs!]!) {
+    adminCreateContributions(pendingCreations: $pendingCreations) {
       success
-      successfulCreation
-      failedCreation
+      successfulContribution
+      failedContribution
     }
   }
 `
 
-export const updatePendingCreation = gql`
+export const adminUpdateContribution = gql`
   mutation ($id: Int!, $email: String!, $amount: Decimal!, $memo: String!, $creationDate: String!) {
-    updatePendingCreation(
+    adminUpdateContribution(
       id: $id
       email: $email
       amount: $amount
@@ -132,8 +143,121 @@ export const updatePendingCreation = gql`
   }
 `
 
-export const deletePendingCreation = gql`
+export const adminDeleteContribution = gql`
   mutation ($id: Int!) {
-    deletePendingCreation(id: $id)
+    adminDeleteContribution(id: $id)
+  }
+`
+
+export const createContributionLink = gql`
+  mutation (
+    $amount: Decimal!
+    $name: String!
+    $memo: String!
+    $cycle: String!
+    $validFrom: String
+    $validTo: String
+    $maxAmountPerMonth: Decimal
+    $maxPerCycle: Int! = 1
+  ) {
+    createContributionLink(
+      amount: $amount
+      name: $name
+      memo: $memo
+      cycle: $cycle
+      validFrom: $validFrom
+      validTo: $validTo
+      maxAmountPerMonth: $maxAmountPerMonth
+      maxPerCycle: $maxPerCycle
+    ) {
+      id
+      amount
+      name
+      memo
+      code
+      link
+      createdAt
+      validFrom
+      validTo
+      maxAmountPerMonth
+      cycle
+      maxPerCycle
+    }
+  }
+`
+
+export const updateContributionLink = gql`
+  mutation (
+    $amount: Decimal!
+    $name: String!
+    $memo: String!
+    $cycle: String!
+    $validFrom: String
+    $validTo: String
+    $maxAmountPerMonth: Decimal
+    $maxPerCycle: Int! = 1
+    $id: Int!
+  ) {
+    updateContributionLink(
+      amount: $amount
+      name: $name
+      memo: $memo
+      cycle: $cycle
+      validFrom: $validFrom
+      validTo: $validTo
+      maxAmountPerMonth: $maxAmountPerMonth
+      maxPerCycle: $maxPerCycle
+      id: $id
+    ) {
+      id
+      amount
+      name
+      memo
+      code
+      link
+      createdAt
+      validFrom
+      validTo
+      maxAmountPerMonth
+      cycle
+      maxPerCycle
+    }
+  }
+`
+
+export const deleteContributionLink = gql`
+  mutation ($id: Int!) {
+    deleteContributionLink(id: $id)
+  }
+`
+
+export const createContribution = gql`
+  mutation ($amount: Decimal!, $memo: String!, $creationDate: String!) {
+    createContribution(amount: $amount, memo: $memo, creationDate: $creationDate) {
+      id
+      amount
+      memo
+    }
+  }
+`
+
+export const updateContribution = gql`
+  mutation ($contributionId: Int!, $amount: Decimal!, $memo: String!, $creationDate: String!) {
+    updateContribution(
+      contributionId: $contributionId
+      amount: $amount
+      memo: $memo
+      creationDate: $creationDate
+    ) {
+      id
+      amount
+      memo
+    }
+  }
+`
+
+export const deleteContribution = gql`
+  mutation ($id: Int!) {
+    deleteContribution(id: $id)
   }
 `
diff --git a/backend/src/seeds/graphql/queries.ts b/backend/src/seeds/graphql/queries.ts
index 03ee3b53e..9f7a02e70 100644
--- a/backend/src/seeds/graphql/queries.ts
+++ b/backend/src/seeds/graphql/queries.ts
@@ -110,6 +110,7 @@ export const searchUsers = gql`
         hasElopage
         emailConfirmationSend
         deletedAt
+        isAdmin
       }
     }
   }
@@ -171,11 +172,51 @@ export const queryTransactionLink = gql`
   }
 `
 
+export const listContributions = gql`
+  query (
+    $currentPage: Int = 1
+    $pageSize: Int = 5
+    $order: Order
+    $filterConfirmed: Boolean = false
+  ) {
+    listContributions(
+      currentPage: $currentPage
+      pageSize: $pageSize
+      order: $order
+      filterConfirmed: $filterConfirmed
+    ) {
+      contributionCount
+      contributionList {
+        id
+        amount
+        memo
+      }
+    }
+  }
+`
+
+export const listAllContributions = `
+query ($currentPage: Int = 1, $pageSize: Int = 5, $order: Order = DESC) {
+  listAllContributions(currentPage: $currentPage, pageSize: $pageSize, order: $order) {
+  	contributionCount
+    contributionList {
+      id
+      firstName
+      lastName
+      amount
+      memo
+      createdAt
+      confirmedAt
+      confirmedBy
+    }
+	}
+}
+`
 // from admin interface
 
-export const getPendingCreations = gql`
+export const listUnconfirmedContributions = gql`
   query {
-    getPendingCreations {
+    listUnconfirmedContributions {
       id
       firstName
       lastName
@@ -217,3 +258,25 @@ export const listTransactionLinksAdmin = gql`
     }
   }
 `
+
+export const listContributionLinks = gql`
+  query ($pageSize: Int = 25, $currentPage: Int = 1, $order: Order) {
+    listContributionLinks(pageSize: $pageSize, currentPage: $currentPage, order: $order) {
+      links {
+        id
+        amount
+        name
+        memo
+        code
+        link
+        createdAt
+        validFrom
+        validTo
+        maxAmountPerMonth
+        cycle
+        maxPerCycle
+      }
+      count
+    }
+  }
+`
diff --git a/backend/src/seeds/index.ts b/backend/src/seeds/index.ts
index 710f255ee..8e9a4e2d8 100644
--- a/backend/src/seeds/index.ts
+++ b/backend/src/seeds/index.ts
@@ -9,9 +9,11 @@ import { name, internet, datatype } from 'faker'
 import { users } from './users/index'
 import { creations } from './creation/index'
 import { transactionLinks } from './transactionLink/index'
+import { contributionLinks } from './contributionLink/index'
 import { userFactory } from './factory/user'
 import { creationFactory } from './factory/creation'
 import { transactionLinkFactory } from './factory/transactionLink'
+import { contributionLinkFactory } from './factory/contributionLink'
 import { entities } from '@entity/index'
 import CONFIG from '@/config'
 
@@ -77,6 +79,11 @@ const run = async () => {
     await transactionLinkFactory(seedClient, transactionLinks[i])
   }
 
+  // create Contribution Links
+  for (let i = 0; i < contributionLinks.length; i++) {
+    await contributionLinkFactory(seedClient, contributionLinks[i])
+  }
+
   await con.close()
 }
 
diff --git a/backend/src/server/logger.ts b/backend/src/server/logger.ts
index 27d0cf75b..cbc8c9b9b 100644
--- a/backend/src/server/logger.ts
+++ b/backend/src/server/logger.ts
@@ -5,7 +5,8 @@ import { readFileSync } from 'fs'
 
 const options = JSON.parse(readFileSync(CONFIG.LOG4JS_CONFIG, 'utf-8'))
 
-options.categories.default.level = CONFIG.LOG_LEVEL
+options.categories.backend.level = CONFIG.LOG_LEVEL
+options.categories.apollo.level = CONFIG.LOG_LEVEL
 
 log4js.configure(options)
 
diff --git a/backend/src/server/plugins.ts b/backend/src/server/plugins.ts
index 134ca1bb9..24df45baa 100644
--- a/backend/src/server/plugins.ts
+++ b/backend/src/server/plugins.ts
@@ -31,18 +31,24 @@ const filterVariables = (variables: any) => {
 const logPlugin = {
   requestDidStart(requestContext: any) {
     const { logger } = requestContext
-    const { query, mutation, variables } = requestContext.request
-    logger.info(`Request:
+    const { query, mutation, variables, operationName } = requestContext.request
+    if (operationName !== 'IntrospectionQuery') {
+      logger.info(`Request:
 ${mutation || query}variables: ${JSON.stringify(filterVariables(variables), null, 2)}`)
+    }
     return {
       willSendResponse(requestContext: any) {
-        if (requestContext.context.user) logger.info(`User ID: ${requestContext.context.user.id}`)
-        if (requestContext.response.data)
-          logger.info(`Response-Data:
+        if (operationName !== 'IntrospectionQuery') {
+          if (requestContext.context.user) logger.info(`User ID: ${requestContext.context.user.id}`)
+          if (requestContext.response.data) {
+            logger.info('Response Success!')
+            logger.trace(`Response-Data:
 ${JSON.stringify(requestContext.response.data, null, 2)}`)
-        if (requestContext.response.errors)
-          logger.error(`Response-Errors:
+          }
+          if (requestContext.response.errors)
+            logger.error(`Response-Errors:
 ${JSON.stringify(requestContext.response.errors, null, 2)}`)
+        }
         return requestContext
       },
     }
diff --git a/database/entity/0039-contributions_table/Contribution.ts b/database/entity/0039-contributions_table/Contribution.ts
new file mode 100644
index 000000000..b5e6ac0e0
--- /dev/null
+++ b/database/entity/0039-contributions_table/Contribution.ts
@@ -0,0 +1,61 @@
+import Decimal from 'decimal.js-light'
+import {
+  BaseEntity,
+  Column,
+  Entity,
+  PrimaryGeneratedColumn,
+  DeleteDateColumn,
+  JoinColumn,
+  ManyToOne,
+} from 'typeorm'
+import { DecimalTransformer } from '../../src/typeorm/DecimalTransformer'
+import { User } from '../User'
+
+@Entity('contributions')
+export class Contribution extends BaseEntity {
+  @PrimaryGeneratedColumn('increment', { unsigned: true })
+  id: number
+
+  @Column({ unsigned: true, nullable: false, name: 'user_id' })
+  userId: number
+
+  @ManyToOne(() => User, (user) => user.contributions)
+  @JoinColumn({ name: 'user_id' })
+  user: User
+
+  @Column({ type: 'datetime', default: () => 'CURRENT_TIMESTAMP', name: 'created_at' })
+  createdAt: Date
+
+  @Column({ type: 'datetime', nullable: false, name: 'contribution_date' })
+  contributionDate: Date
+
+  @Column({ length: 255, nullable: false, collation: 'utf8mb4_unicode_ci' })
+  memo: string
+
+  @Column({
+    type: 'decimal',
+    precision: 40,
+    scale: 20,
+    nullable: false,
+    transformer: DecimalTransformer,
+  })
+  amount: Decimal
+
+  @Column({ unsigned: true, nullable: true, name: 'moderator_id' })
+  moderatorId: number
+
+  @Column({ unsigned: true, nullable: true, name: 'contribution_link_id' })
+  contributionLinkId: number
+
+  @Column({ unsigned: true, nullable: true, name: 'confirmed_by' })
+  confirmedBy: number
+
+  @Column({ nullable: true, name: 'confirmed_at' })
+  confirmedAt: Date
+
+  @Column({ unsigned: true, nullable: true, name: 'transaction_id' })
+  transactionId: number
+
+  @DeleteDateColumn({ name: 'deleted_at' })
+  deletedAt: Date | null
+}
diff --git a/database/entity/0039-contributions_table/User.ts b/database/entity/0039-contributions_table/User.ts
new file mode 100644
index 000000000..147ae6f6f
--- /dev/null
+++ b/database/entity/0039-contributions_table/User.ts
@@ -0,0 +1,83 @@
+import {
+  BaseEntity,
+  Entity,
+  PrimaryGeneratedColumn,
+  Column,
+  DeleteDateColumn,
+  OneToMany,
+  JoinColumn,
+} from 'typeorm'
+import { Contribution } from '../Contribution'
+
+@Entity('users', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' })
+export class User extends BaseEntity {
+  @PrimaryGeneratedColumn('increment', { unsigned: true })
+  id: number
+
+  @Column({ name: 'public_key', type: 'binary', length: 32, default: null, nullable: true })
+  pubKey: Buffer
+
+  @Column({ name: 'privkey', type: 'binary', length: 80, default: null, nullable: true })
+  privKey: Buffer
+
+  @Column({ length: 255, unique: true, nullable: false, collation: 'utf8mb4_unicode_ci' })
+  email: string
+
+  @Column({
+    name: 'first_name',
+    length: 255,
+    nullable: true,
+    default: null,
+    collation: 'utf8mb4_unicode_ci',
+  })
+  firstName: string
+
+  @Column({
+    name: 'last_name',
+    length: 255,
+    nullable: true,
+    default: null,
+    collation: 'utf8mb4_unicode_ci',
+  })
+  lastName: string
+
+  @DeleteDateColumn()
+  deletedAt: Date | null
+
+  @Column({ type: 'bigint', default: 0, unsigned: true })
+  password: BigInt
+
+  @Column({ name: 'email_hash', type: 'binary', length: 32, default: null, nullable: true })
+  emailHash: Buffer
+
+  @Column({ name: 'created', default: () => 'CURRENT_TIMESTAMP', nullable: false })
+  createdAt: Date
+
+  @Column({ name: 'email_checked', type: 'bool', nullable: false, default: false })
+  emailChecked: boolean
+
+  @Column({ length: 4, default: 'de', collation: 'utf8mb4_unicode_ci', nullable: false })
+  language: string
+
+  @Column({ name: 'is_admin', type: 'datetime', nullable: true, default: null })
+  isAdmin: Date | null
+
+  @Column({ name: 'referrer_id', type: 'int', unsigned: true, nullable: true, default: null })
+  referrerId?: number | null
+
+  @Column({ name: 'publisher_id', default: 0 })
+  publisherId: number
+
+  @Column({
+    type: 'text',
+    name: 'passphrase',
+    collation: 'utf8mb4_unicode_ci',
+    nullable: true,
+    default: null,
+  })
+  passphrase: string
+
+  @OneToMany(() => Contribution, (contribution) => contribution.user)
+  @JoinColumn({ name: 'user_id' })
+  contributions?: Contribution[]
+}
diff --git a/database/entity/0040-add_contribution_link_id_to_user/User.ts b/database/entity/0040-add_contribution_link_id_to_user/User.ts
new file mode 100644
index 000000000..56047345a
--- /dev/null
+++ b/database/entity/0040-add_contribution_link_id_to_user/User.ts
@@ -0,0 +1,92 @@
+import {
+  BaseEntity,
+  Entity,
+  PrimaryGeneratedColumn,
+  Column,
+  DeleteDateColumn,
+  OneToMany,
+  JoinColumn,
+} from 'typeorm'
+import { Contribution } from '../Contribution'
+
+@Entity('users', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' })
+export class User extends BaseEntity {
+  @PrimaryGeneratedColumn('increment', { unsigned: true })
+  id: number
+
+  @Column({ name: 'public_key', type: 'binary', length: 32, default: null, nullable: true })
+  pubKey: Buffer
+
+  @Column({ name: 'privkey', type: 'binary', length: 80, default: null, nullable: true })
+  privKey: Buffer
+
+  @Column({ length: 255, unique: true, nullable: false, collation: 'utf8mb4_unicode_ci' })
+  email: string
+
+  @Column({
+    name: 'first_name',
+    length: 255,
+    nullable: true,
+    default: null,
+    collation: 'utf8mb4_unicode_ci',
+  })
+  firstName: string
+
+  @Column({
+    name: 'last_name',
+    length: 255,
+    nullable: true,
+    default: null,
+    collation: 'utf8mb4_unicode_ci',
+  })
+  lastName: string
+
+  @DeleteDateColumn()
+  deletedAt: Date | null
+
+  @Column({ type: 'bigint', default: 0, unsigned: true })
+  password: BigInt
+
+  @Column({ name: 'email_hash', type: 'binary', length: 32, default: null, nullable: true })
+  emailHash: Buffer
+
+  @Column({ name: 'created', default: () => 'CURRENT_TIMESTAMP', nullable: false })
+  createdAt: Date
+
+  @Column({ name: 'email_checked', type: 'bool', nullable: false, default: false })
+  emailChecked: boolean
+
+  @Column({ length: 4, default: 'de', collation: 'utf8mb4_unicode_ci', nullable: false })
+  language: string
+
+  @Column({ name: 'is_admin', type: 'datetime', nullable: true, default: null })
+  isAdmin: Date | null
+
+  @Column({ name: 'referrer_id', type: 'int', unsigned: true, nullable: true, default: null })
+  referrerId?: number | null
+
+  @Column({
+    name: 'contribution_link_id',
+    type: 'int',
+    unsigned: true,
+    nullable: true,
+    default: null,
+  })
+  contributionLinkId?: number | null
+
+  @Column({ name: 'publisher_id', default: 0 })
+  publisherId: number
+
+  @Column({
+    type: 'text',
+    name: 'passphrase',
+    collation: 'utf8mb4_unicode_ci',
+    nullable: true,
+    default: null,
+  })
+  passphrase: string
+
+  @OneToMany(() => Contribution, (contribution) => contribution.user)
+  @JoinColumn({ name: 'user_id' })
+  contributions?: Contribution[]
+}
diff --git a/database/entity/0043-add_event_protocol_table/EventProtocol.ts b/database/entity/0043-add_event_protocol_table/EventProtocol.ts
new file mode 100644
index 000000000..72470d2ed
--- /dev/null
+++ b/database/entity/0043-add_event_protocol_table/EventProtocol.ts
@@ -0,0 +1,39 @@
+import Decimal from 'decimal.js-light'
+import { BaseEntity, Entity, PrimaryGeneratedColumn, Column } from 'typeorm'
+import { DecimalTransformer } from '../../src/typeorm/DecimalTransformer'
+
+@Entity('event_protocol')
+export class EventProtocol extends BaseEntity {
+  @PrimaryGeneratedColumn('increment', { unsigned: true })
+  id: number
+
+  @Column({ length: 100, nullable: false, collation: 'utf8mb4_unicode_ci' })
+  type: string
+
+  @Column({ name: 'created_at', type: 'datetime', default: () => 'CURRENT_TIMESTAMP' })
+  createdAt: Date
+
+  @Column({ name: 'user_id', unsigned: true, nullable: false })
+  userId: number
+
+  @Column({ name: 'x_user_id', unsigned: true, nullable: true })
+  xUserId: number
+
+  @Column({ name: 'x_community_id', unsigned: true, nullable: true })
+  xCommunityId: number
+
+  @Column({ name: 'transaction_id', unsigned: true, nullable: true })
+  transactionId: number
+
+  @Column({ name: 'contribution_id', unsigned: true, nullable: true })
+  contributionId: number
+
+  @Column({
+    type: 'decimal',
+    precision: 40,
+    scale: 20,
+    nullable: true,
+    transformer: DecimalTransformer,
+  })
+  amount: Decimal
+}
diff --git a/database/entity/Contribution.ts b/database/entity/Contribution.ts
new file mode 100644
index 000000000..82dd6478c
--- /dev/null
+++ b/database/entity/Contribution.ts
@@ -0,0 +1 @@
+export { Contribution } from './0039-contributions_table/Contribution'
diff --git a/database/entity/EventProtocol.ts b/database/entity/EventProtocol.ts
new file mode 100644
index 000000000..4a73f146c
--- /dev/null
+++ b/database/entity/EventProtocol.ts
@@ -0,0 +1 @@
+export { EventProtocol } from './0043-add_event_protocol_table/EventProtocol'
diff --git a/database/entity/User.ts b/database/entity/User.ts
index 2d434799e..99b8c8ca9 100644
--- a/database/entity/User.ts
+++ b/database/entity/User.ts
@@ -1 +1 @@
-export { User } from './0037-drop_user_setting_table/User'
+export { User } from './0040-add_contribution_link_id_to_user/User'
diff --git a/database/entity/index.ts b/database/entity/index.ts
index 991e482e9..733c99a3a 100644
--- a/database/entity/index.ts
+++ b/database/entity/index.ts
@@ -5,10 +5,11 @@ import { Migration } from './Migration'
 import { Transaction } from './Transaction'
 import { TransactionLink } from './TransactionLink'
 import { User } from './User'
-import { AdminPendingCreation } from './AdminPendingCreation'
+import { Contribution } from './Contribution'
+import { EventProtocol } from './EventProtocol'
 
 export const entities = [
-  AdminPendingCreation,
+  Contribution,
   ContributionLink,
   LoginElopageBuys,
   LoginEmailOptIn,
@@ -16,4 +17,5 @@ export const entities = [
   Transaction,
   TransactionLink,
   User,
+  EventProtocol,
 ]
diff --git a/database/migrations/0039-contributions_table.ts b/database/migrations/0039-contributions_table.ts
new file mode 100644
index 000000000..50b147448
--- /dev/null
+++ b/database/migrations/0039-contributions_table.ts
@@ -0,0 +1,59 @@
+/* MIGRATION to rename ADMIN_PENDING_CREATION table and add columns
+ */
+
+/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
+/* eslint-disable @typescript-eslint/no-explicit-any */
+
+export async function upgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
+  await queryFn('RENAME TABLE `admin_pending_creations` TO `contributions`;')
+
+  await queryFn('ALTER TABLE `contributions` CHANGE COLUMN `userId` `user_id` int(10);')
+
+  await queryFn('ALTER TABLE `contributions` CHANGE COLUMN `created` `created_at` datetime;')
+
+  await queryFn('ALTER TABLE `contributions` CHANGE COLUMN `date` `contribution_date` datetime;')
+
+  await queryFn('ALTER TABLE `contributions` CHANGE COLUMN `moderator` `moderator_id` int(10);')
+
+  await queryFn(
+    'ALTER TABLE `contributions` ADD COLUMN `contribution_link_id` int(10) unsigned DEFAULT NULL AFTER `moderator_id`;',
+  )
+
+  await queryFn(
+    'ALTER TABLE `contributions` ADD COLUMN `confirmed_by` int(10) unsigned DEFAULT NULL AFTER `contribution_link_id`;',
+  )
+
+  await queryFn(
+    'ALTER TABLE `contributions` ADD COLUMN `confirmed_at` datetime DEFAULT NULL AFTER `confirmed_by`;',
+  )
+
+  await queryFn(
+    'ALTER TABLE `contributions` ADD COLUMN `transaction_id` int(10) unsigned DEFAULT NULL AFTER `confirmed_at`;',
+  )
+
+  await queryFn(
+    'ALTER TABLE `contributions` ADD COLUMN `deleted_at` datetime DEFAULT NULL AFTER `confirmed_at`;',
+  )
+}
+
+export async function downgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
+  await queryFn('ALTER TABLE `contributions` DROP COLUMN IF EXISTS `deleted_at`;')
+
+  await queryFn('ALTER TABLE `contributions` DROP COLUMN IF EXISTS `transaction_id`;')
+
+  await queryFn('ALTER TABLE `contributions` DROP COLUMN IF EXISTS `confirmed_at`;')
+
+  await queryFn('ALTER TABLE `contributions` DROP COLUMN IF EXISTS `confirmed_by`;')
+
+  await queryFn('ALTER TABLE `contributions` DROP COLUMN IF EXISTS `contribution_link_id`;')
+
+  await queryFn('ALTER TABLE `contributions` CHANGE COLUMN `moderator_id` `moderator` int(10);')
+
+  await queryFn('ALTER TABLE `contributions` CHANGE COLUMN `created_at` `created` datetime;')
+
+  await queryFn('ALTER TABLE `contributions` CHANGE COLUMN `contribution_date` `date` datetime;')
+
+  await queryFn('ALTER TABLE `contributions` CHANGE COLUMN `user_id` `userId` int(10);')
+
+  await queryFn('RENAME TABLE `contributions` TO `admin_pending_creations`;')
+}
diff --git a/database/migrations/0040-add_contribution_link_id_to_user.ts b/database/migrations/0040-add_contribution_link_id_to_user.ts
new file mode 100644
index 000000000..ebe7896df
--- /dev/null
+++ b/database/migrations/0040-add_contribution_link_id_to_user.ts
@@ -0,0 +1,14 @@
+/* MIGRATION TO ADD contribution_link_id FIELD TO users */
+
+/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
+/* eslint-disable @typescript-eslint/no-explicit-any */
+
+export async function upgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
+  await queryFn(
+    'ALTER TABLE `users` ADD COLUMN `contribution_link_id` int UNSIGNED DEFAULT NULL AFTER `referrer_id`;',
+  )
+}
+
+export async function downgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
+  await queryFn('ALTER TABLE `users` DROP COLUMN `contribution_link_id`;')
+}
diff --git a/database/migrations/0041-move_users_creation_date.ts b/database/migrations/0041-move_users_creation_date.ts
new file mode 100644
index 000000000..27353a5b4
--- /dev/null
+++ b/database/migrations/0041-move_users_creation_date.ts
@@ -0,0 +1,130 @@
+/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
+/* eslint-disable @typescript-eslint/no-explicit-any */
+
+/* 
+Move forward the creation date of the users by 1 or 2 hours, 
+for which there are transactions created before their account creation. 
+
+Because of a error by importing data from old db format into new, all older transactions balance_date
+are 1 or 2 hours off
+
+*/
+
+export async function upgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
+  /* generate raw mysql queries 
+    const usersToMove = await queryFn(
+      `
+       SELECT u.id, u.created, t.balance_date 
+       FROM \`users\` as u 
+       LEFT JOIN \`transactions\` as t 
+       ON t.user_id = u.id where t.balance_date < u.created
+       order by id
+       `
+    )
+    let downgradeQueries = ''
+    for(const id in usersToMove) {
+        const user = usersToMove[id]
+        const diff = (user.created - user.balance_date) / 1000
+        const correcture = diff < 3600 ? 1: 2
+        const correctedDate = new Date(user.created)
+        correctedDate.setHours(correctedDate.getHours() - correcture)
+        //console.log("%d, %s, %s, %s, %d", user.id, user.created, user.balance_date, diff, correcture)
+        console.log('await queryFn(`UPDATE \\`users\\` SET \\`created\\` = \'%s\' WHERE \\`id\\` = %d`)',
+            correctedDate.toISOString().slice(0, 19).replace('T', ' '),
+            user.id
+        )
+        downgradeQueries += 'await queryFn(`UPDATE \\`users\\` SET \\`created\\` = \''
+        downgradeQueries += user.created.toISOString().slice(0, 19).replace('T', ' ')
+        downgradeQueries += '\' WHERE \\`id\\` = ' 
+        downgradeQueries += user.id
+        downgradeQueries += '`)\n'
+    }
+    console.log('downgrade: \n%s', downgradeQueries)
+    */
+
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2020-01-25 08:01:52' WHERE \`id\` = 179`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2020-05-26 10:21:57' WHERE \`id\` = 443`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2020-06-08 17:04:41' WHERE \`id\` = 490`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2020-06-12 20:07:17' WHERE \`id\` = 508`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2020-07-17 19:20:36' WHERE \`id\` = 621`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2020-11-22 16:31:48' WHERE \`id\` = 788`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2020-12-17 20:09:16' WHERE \`id\` = 825`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-01-26 13:09:35' WHERE \`id\` = 949`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-03-20 16:55:46' WHERE \`id\` = 1057`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-05-13 15:59:30' WHERE \`id\` = 1228`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-05-13 17:38:47' WHERE \`id\` = 1229`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-05-13 17:38:47' WHERE \`id\` = 1229`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-05-13 17:38:47' WHERE \`id\` = 1229`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-05-13 17:58:15' WHERE \`id\` = 1230`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-05-13 17:58:15' WHERE \`id\` = 1230`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-05-14 14:27:49' WHERE \`id\` = 1231`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-05-14 14:27:49' WHERE \`id\` = 1231`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-05-14 14:27:49' WHERE \`id\` = 1231`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-05-14 14:27:49' WHERE \`id\` = 1231`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-05-17 22:51:19' WHERE \`id\` = 1239`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-06-03 07:23:28' WHERE \`id\` = 1273`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-06-09 06:16:18' WHERE \`id\` = 1287`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-06-17 11:26:41' WHERE \`id\` = 1298`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-06-30 15:56:27' WHERE \`id\` = 1315`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-06-30 15:56:27' WHERE \`id\` = 1315`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-06-30 15:56:27' WHERE \`id\` = 1315`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-07-08 07:24:57' WHERE \`id\` = 1326`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-07-08 07:24:57' WHERE \`id\` = 1326`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-07-13 12:07:29' WHERE \`id\` = 1342`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-07-16 15:32:48' WHERE \`id\` = 1348`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-09-30 14:06:40' WHERE \`id\` = 1470`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-10-15 14:35:37' WHERE \`id\` = 1490`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-10-16 06:42:00' WHERE \`id\` = 1492`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-10-16 06:42:00' WHERE \`id\` = 1492`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-11-22 09:45:15' WHERE \`id\` = 1576`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-11-23 13:55:37' WHERE \`id\` = 1582`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2022-01-11 14:58:12' WHERE \`id\` = 1729`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2022-01-11 18:03:10' WHERE \`id\` = 1732`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2022-01-19 15:00:38' WHERE \`id\` = 1756`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2022-01-19 20:01:58' WHERE \`id\` = 1757`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2022-01-21 15:58:48' WHERE \`id\` = 1762`)
+}
+
+export async function downgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2020-01-25 09:01:52' WHERE \`id\` = 179`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2020-05-26 11:21:57' WHERE \`id\` = 443`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2020-06-08 19:04:41' WHERE \`id\` = 490`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2020-06-12 22:07:17' WHERE \`id\` = 508`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2020-07-17 21:20:36' WHERE \`id\` = 621`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2020-11-22 17:31:48' WHERE \`id\` = 788`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2020-12-17 21:09:16' WHERE \`id\` = 825`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-01-26 14:09:35' WHERE \`id\` = 949`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-03-20 17:55:46' WHERE \`id\` = 1057`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-05-13 17:59:30' WHERE \`id\` = 1228`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-05-13 19:38:47' WHERE \`id\` = 1229`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-05-13 19:38:47' WHERE \`id\` = 1229`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-05-13 19:38:47' WHERE \`id\` = 1229`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-05-13 19:58:15' WHERE \`id\` = 1230`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-05-13 19:58:15' WHERE \`id\` = 1230`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-05-14 16:27:49' WHERE \`id\` = 1231`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-05-14 16:27:49' WHERE \`id\` = 1231`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-05-14 16:27:49' WHERE \`id\` = 1231`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-05-14 16:27:49' WHERE \`id\` = 1231`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-05-18 00:51:19' WHERE \`id\` = 1239`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-06-03 09:23:28' WHERE \`id\` = 1273`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-06-09 08:16:18' WHERE \`id\` = 1287`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-06-17 13:26:41' WHERE \`id\` = 1298`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-06-30 17:56:27' WHERE \`id\` = 1315`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-06-30 17:56:27' WHERE \`id\` = 1315`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-06-30 17:56:27' WHERE \`id\` = 1315`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-07-08 09:24:57' WHERE \`id\` = 1326`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-07-08 09:24:57' WHERE \`id\` = 1326`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-07-13 14:07:29' WHERE \`id\` = 1342`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-07-16 16:32:48' WHERE \`id\` = 1348`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-09-30 16:06:40' WHERE \`id\` = 1470`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-10-15 16:35:37' WHERE \`id\` = 1490`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-10-16 08:42:00' WHERE \`id\` = 1492`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-10-16 08:42:00' WHERE \`id\` = 1492`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-11-22 10:45:15' WHERE \`id\` = 1576`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2021-11-23 14:55:37' WHERE \`id\` = 1582`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2022-01-11 15:58:12' WHERE \`id\` = 1729`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2022-01-11 19:03:10' WHERE \`id\` = 1732`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2022-01-19 16:00:38' WHERE \`id\` = 1756`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2022-01-19 21:01:58' WHERE \`id\` = 1757`)
+  await queryFn(`UPDATE \`users\` SET \`created\` = '2022-01-21 16:58:48' WHERE \`id\` = 1762`)
+}
diff --git a/database/migrations/0042-update_transactions_for_blockchain.ts b/database/migrations/0042-update_transactions_for_blockchain.ts
new file mode 100644
index 000000000..d7b26abbd
--- /dev/null
+++ b/database/migrations/0042-update_transactions_for_blockchain.ts
@@ -0,0 +1,1917 @@
+/* MIGRATION for updating transactions from the past to follow the blockchain rules */
+/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
+/* eslint-disable @typescript-eslint/no-explicit-any */
+
+export async function upgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
+  // split creation transaction with 3000 GDD created in one transaction what isn't allowed
+  const transactionMemos: string[] = [
+    'Aktives Grundeinkommen für GL. Dez',
+    'Aktives Grundeinkommen für GL. Jan',
+    'Aktives Grundeinkommen für GL. Feb',
+  ]
+  const creationDate = new Date('2020-03-30 06:59:55')
+
+  await queryFn(
+    `UPDATE \`transactions\` set \`amount\` = 1000, \`balance\` = 1000, \`memo\` = ? WHERE \`id\` = 150`,
+    [transactionMemos[0]],
+  )
+
+  // [ RowDataPacket { 'MAX(`id`)': 6828 } ]
+  const lastTransactionId = (await queryFn(`SELECT MAX(\`id\`) as max_id from \`transactions\``))[0]
+    .max_id
+  // dummy id to insert two transactions before this (previous has an index on it)
+  await queryFn(`UPDATE \`transactions\` set \`previous\` = ? WHERE \`id\` = 278`, [
+    lastTransactionId + 30,
+  ])
+
+  await queryFn(
+    `INSERT INTO \`transactions\`(
+            \`user_id\`, \`previous\`, \`type_id\`, \`amount\`, \`balance\`,
+            \`balance_date\`, \`decay\`, \`memo\`, \`creation_date\`
+          ) VALUES(
+            275, 150, 1, 1000, 2000,
+            ?, 0, ?, ?
+          )`,
+    [
+      creationDate,
+      transactionMemos[1],
+      new Date(creationDate.getFullYear(), creationDate.getMonth() - 1, 1),
+    ],
+  )
+  await queryFn(
+    `INSERT INTO \`transactions\`(
+            \`user_id\`, \`previous\`, \`type_id\`, \`amount\`, \`balance\`,
+            \`balance_date\`, \`decay\`, \`memo\`, \`creation_date\`
+          ) VALUES(
+            275, LAST_INSERT_ID(), 1, 1000, 3000,
+            ?, 0, ?, ?
+          )`,
+    [
+      creationDate,
+      transactionMemos[2],
+      new Date(creationDate.getFullYear(), creationDate.getMonth() - 2, 1),
+    ],
+  )
+  await queryFn(`UPDATE \`transactions\` set \`previous\` = LAST_INSERT_ID() WHERE \`id\` = 278`)
+
+  // ----------------------------------------------------------------------------------------------
+  // update creation_date for transactions with creation_date == balance_date
+  /* js code for generating mysql raw queries
+  // print mysql raw querys
+  interface ReplaceSet {
+    monthName: RegExp
+    monthValue: number
+  }
+  // js month starting with 0 for Jan
+  const replaceSets: ReplaceSet[] = [
+    { monthName: new RegExp('.*Dez.*'), monthValue: -1},
+    { monthName: new RegExp('.*Jan.*'), monthValue: 0 },
+    { monthName: new RegExp('.*Feb.*'), monthValue: 1 },
+    { monthName: new RegExp('.*M.rz.*'), monthValue: 2 },
+    { monthName: new RegExp('.*April.*'), monthValue: 3 },
+  ]
+  const transaction_ids = await queryFn(`
+    SELECT id, balance_date, creation_date, memo 
+    FROM \`transactions\` 
+    WHERE \`balance_date\` = \`creation_date\`
+    AND \`type_id\` = 1
+  `)
+  let downgradeQueries = ''
+  for(let id in transaction_ids) {
+    const transaction = transaction_ids[id]
+    let updatedCreationDate: Date | null = null
+    // determine correct creation date
+    for(const replaceSet of replaceSets) {
+      // check if target creation can be determine which help of the memo
+      if(transaction.memo.match(replaceSet.monthName)) {
+        const oldCreationDate = transaction.creation_date        
+        updatedCreationDate = new Date(oldCreationDate)
+        updatedCreationDate.setMonth(replaceSet.monthValue)
+        break
+      }
+    }
+    // couldn't find info in memo, simply set date 1 month back
+    if(updatedCreationDate === null) {
+      //date.setMonth(date.getMonth() - numOfMonths);
+      updatedCreationDate = new Date(transaction.creation_date)
+      updatedCreationDate.setMonth(transaction.creation_date.getMonth() - 1)
+    }
+    if(updatedCreationDate.getMonth() == 1) {
+      // only 28 februars exist so let us fix it
+      if(updatedCreationDate.getDate() > 28) {
+        updatedCreationDate.setDate(28)
+      }
+    }
+    console.log('// %s, original creation date: %s\nawait queryFn(`UPDATE \\`transactions\\` SET creation_date = \'%s\' WHERE \\`id\\` = %d`)\n', 
+        transaction.memo, 
+        transaction.creation_date.toISOString().slice(0, 19).replace('T', ' '),
+        updatedCreationDate.toISOString().slice(0, 19).replace('T', ' '), 
+        transaction.id
+    )
+    downgradeQueries += 'await queryFn(`UPDATE \\`transactions\\` SET creation_date = \''
+    downgradeQueries += transaction.creation_date.toISOString().slice(0, 19).replace('T', ' ')
+    downgradeQueries += '\' WHERE \\`id\\` = '
+    downgradeQueries += transaction.id
+    downgradeQueries += '`)\n'
+  }
+  console.log("downgrade: \n%s", downgradeQueries)
+  console.log("transactions count: %d", transaction_ids.length) // 224
+*/
+
+  // Erste Schöpfung, viel Spaß damit ;), original creation date: 2019-12-17 13:06:13
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-11-17 13:06:13' WHERE \`id\` = 1`,
+  )
+
+  // Erste Schöpfung, viel Spaß damit ;), original creation date: 2019-12-17 13:06:16
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-11-17 13:06:16' WHERE \`id\` = 2`,
+  )
+
+  // Erste Schöpfung, viel Spaß damit ;), original creation date: 2019-12-17 13:06:19
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-11-17 13:06:19' WHERE \`id\` = 3`,
+  )
+
+  // Erste Schöpfung, viel Spaß damit ;), original creation date: 2019-12-17 13:06:21
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-11-17 13:06:21' WHERE \`id\` = 4`,
+  )
+
+  // Test1 , original creation date: 2019-12-17 13:07:01
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-11-17 13:07:01' WHERE \`id\` = 5`,
+  )
+
+  // EIn bisschen Nachschub für dich ;), original creation date: 2019-12-19 17:35:16
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-11-19 17:35:16' WHERE \`id\` = 6`,
+  )
+
+  // AGE Dezember 2019, original creation date: 2020-01-08 10:34:40
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-12-08 10:34:40' WHERE \`id\` = 7`,
+  )
+
+  // AGE Dezember 2019, original creation date: 2020-01-08 11:02:41
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-12-08 11:02:41' WHERE \`id\` = 8`,
+  )
+
+  // AGE Dezember 2019, original creation date: 2020-01-08 11:06:42
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-12-08 11:06:42' WHERE \`id\` = 9`,
+  )
+
+  // AGE Dezember 2019, original creation date: 2020-01-08 11:16:11
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-12-08 11:16:11' WHERE \`id\` = 10`,
+  )
+
+  // AGE Dezember 2019, original creation date: 2020-01-08 11:16:15
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-12-08 11:16:15' WHERE \`id\` = 11`,
+  )
+
+  // Für deine tolle Arbeit ;), original creation date: 2020-01-08 13:24:29
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-12-08 13:24:29' WHERE \`id\` = 12`,
+  )
+
+  // AGE Dezember 2019, original creation date: 2020-01-09 12:02:48
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-12-09 12:02:48' WHERE \`id\` = 13`,
+  )
+
+  // AGE Dezember 2019, original creation date: 2020-01-09 12:02:52
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-12-09 12:02:52' WHERE \`id\` = 14`,
+  )
+
+  // AGE Dezember 2019, original creation date: 2020-01-09 12:02:54
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-12-09 12:02:54' WHERE \`id\` = 15`,
+  )
+
+  // AGE Dezember 2019, original creation date: 2020-01-09 12:09:08
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-12-09 12:09:08' WHERE \`id\` = 16`,
+  )
+
+  // AGE Dezember 2019, original creation date: 2020-01-11 11:10:55
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-12-11 11:10:55' WHERE \`id\` = 17`,
+  )
+
+  // AGE Dezember 2019, original creation date: 2020-01-11 11:11:24
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-12-11 11:11:24' WHERE \`id\` = 18`,
+  )
+
+  // AGE Dezember 2019, original creation date: 2020-01-11 11:12:09
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-12-11 11:12:09' WHERE \`id\` = 19`,
+  )
+
+  // AGE Dezember 2019, original creation date: 2020-01-11 11:31:20
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-12-11 11:31:20' WHERE \`id\` = 20`,
+  )
+
+  // AGE Dezember 2019, original creation date: 2020-01-11 11:37:13
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-12-11 11:37:13' WHERE \`id\` = 21`,
+  )
+
+  // AGE Dezember 2019, original creation date: 2020-01-11 11:37:42
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-12-11 11:37:42' WHERE \`id\` = 22`,
+  )
+
+  // AGE Dezember 2019, original creation date: 2020-01-11 19:01:06
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-12-11 19:01:06' WHERE \`id\` = 23`,
+  )
+
+  // AGE Dezember 2019, original creation date: 2020-01-13 16:27:07
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-12-13 16:27:07' WHERE \`id\` = 24`,
+  )
+
+  // AGE Dezember 2019, original creation date: 2020-01-13 16:28:05
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-12-13 16:28:05' WHERE \`id\` = 25`,
+  )
+
+  // AGE Dezember 2019, original creation date: 2020-01-13 16:28:57
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-12-13 16:28:57' WHERE \`id\` = 26`,
+  )
+
+  // AGE Dezember 2019, original creation date: 2020-01-13 16:29:45
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-12-13 16:29:45' WHERE \`id\` = 27`,
+  )
+
+  // AGE Dezember 2019, original creation date: 2020-01-17 13:47:28
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-12-17 13:47:28' WHERE \`id\` = 28`,
+  )
+
+  // AGE Dezember 2019, original creation date: 2020-01-17 13:48:52
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-12-17 13:48:52' WHERE \`id\` = 29`,
+  )
+
+  // AGE Dezember 2019, original creation date: 2020-01-17 13:49:21
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-12-17 13:49:21' WHERE \`id\` = 30`,
+  )
+
+  // AGE Dezember 2019, original creation date: 2020-01-23 13:08:44
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-12-23 13:08:44' WHERE \`id\` = 31`,
+  )
+
+  // AGE Dezember 2019, original creation date: 2020-01-27 08:12:16
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-12-27 08:12:16' WHERE \`id\` = 32`,
+  )
+
+  // AGE Dezember 2019, original creation date: 2020-01-30 14:49:58
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-12-30 14:49:58' WHERE \`id\` = 33`,
+  )
+
+  // AGE Dezember 2019, original creation date: 2020-01-30 14:50:35
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-12-30 14:50:35' WHERE \`id\` = 34`,
+  )
+
+  // AGE Dezember 2019, original creation date: 2020-01-30 14:50:55
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-12-30 14:50:55' WHERE \`id\` = 35`,
+  )
+
+  // AGE Dezember 2019, original creation date: 2020-01-30 14:52:03
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-12-30 14:52:03' WHERE \`id\` = 36`,
+  )
+
+  // AGE Dezember 2019, original creation date: 2020-01-30 14:52:33
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-12-30 14:52:33' WHERE \`id\` = 37`,
+  )
+
+  // AGE Dezember 2019, original creation date: 2020-01-30 14:52:53
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-12-30 14:52:53' WHERE \`id\` = 38`,
+  )
+
+  // AGE Dezember 2019, original creation date: 2020-01-30 14:53:45
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-12-30 14:53:45' WHERE \`id\` = 39`,
+  )
+
+  // AGE Dezember 2019, original creation date: 2020-01-30 14:54:13
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-12-30 14:54:13' WHERE \`id\` = 40`,
+  )
+
+  // AGE Dezember 2019, original creation date: 2020-01-30 14:54:50
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-12-30 14:54:50' WHERE \`id\` = 41`,
+  )
+
+  // AGE Dezember 2019, original creation date: 2020-01-30 15:03:26
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-12-30 15:03:26' WHERE \`id\` = 42`,
+  )
+
+  // AGE Dezember 2019, original creation date: 2020-01-30 15:10:39
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-12-30 15:10:39' WHERE \`id\` = 43`,
+  )
+
+  // AGE Dezember 2019, original creation date: 2020-01-30 15:13:10
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-12-30 15:13:10' WHERE \`id\` = 44`,
+  )
+
+  // AGE Dezember 2019, original creation date: 2020-01-30 15:26:45
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-12-30 15:26:45' WHERE \`id\` = 45`,
+  )
+
+  // Grundeinkommen für Gemeinschaftsleistungen Jan. 2020, original creation date: 2020-02-19 08:54:31
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-19 08:54:31' WHERE \`id\` = 46`,
+  )
+
+  // Grundeinkommen für Gemeinschaftsleistungen Jan. 2020, original creation date: 2020-02-19 08:55:30
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-19 08:55:30' WHERE \`id\` = 47`,
+  )
+
+  // Grundeinkommen für Gemeinschaftsleistungen Jan. 2020, original creation date: 2020-02-19 08:55:33
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-19 08:55:33' WHERE \`id\` = 48`,
+  )
+
+  // Grundeinkommen für Gemeinschaftsleistungen Jan. 2020, original creation date: 2020-02-19 08:55:36
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-19 08:55:36' WHERE \`id\` = 49`,
+  )
+
+  // Grundeinkommen für Gemeinschaftsleistungen Jan. 2020, original creation date: 2020-02-19 08:55:39
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-19 08:55:39' WHERE \`id\` = 50`,
+  )
+
+  // Grundeinkommen für Gemeinschaftsleistungen Jan. 2020, original creation date: 2020-02-19 08:55:43
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-19 08:55:43' WHERE \`id\` = 51`,
+  )
+
+  // Grundeinkommen für Gemeinschaftsleistungen Jan. 2020, original creation date: 2020-02-19 08:55:46
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-19 08:55:46' WHERE \`id\` = 52`,
+  )
+
+  // Grundeinkommen für Gemeinschaftsleistungen Jan. 2020, original creation date: 2020-02-19 08:55:48
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-19 08:55:48' WHERE \`id\` = 53`,
+  )
+
+  // Grundeinkommen für Gemeinschaftsleistungen Jan. 2020, original creation date: 2020-02-19 08:55:50
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-19 08:55:50' WHERE \`id\` = 54`,
+  )
+
+  // Grundeinkommen für Gemeinschaftsleistungen Jan. 2020, original creation date: 2020-02-19 08:55:52
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-19 08:55:52' WHERE \`id\` = 55`,
+  )
+
+  // Grundeinkommen für Gemeinschaftsleistungen Jan. 2020, original creation date: 2020-02-19 08:55:54
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-19 08:55:54' WHERE \`id\` = 56`,
+  )
+
+  // Grundeinkommen für Gemeinschaftsleistungen Jan. 2020, original creation date: 2020-02-19 08:55:56
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-19 08:55:56' WHERE \`id\` = 57`,
+  )
+
+  // Grundeinkommen für Gemeinschaftsleistungen Jan. 2020, original creation date: 2020-02-19 08:55:59
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-19 08:55:59' WHERE \`id\` = 58`,
+  )
+
+  // Grundeinkommen für Gemeinschaftsleistungen Jan. 2020, original creation date: 2020-02-19 08:56:02
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-19 08:56:02' WHERE \`id\` = 59`,
+  )
+
+  // Grundeinkommen für Gemeinschaftsleistungen Jan. 2020, original creation date: 2020-02-19 08:56:05
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-19 08:56:05' WHERE \`id\` = 60`,
+  )
+
+  // Grundeinkommen für Gemeinschaftsleistungen Jan. 2020, original creation date: 2020-02-19 08:56:07
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-19 08:56:07' WHERE \`id\` = 61`,
+  )
+
+  // Grundeinkommen für Gemeinschaftsleistungen Jan. 2020, original creation date: 2020-02-19 08:56:10
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-19 08:56:10' WHERE \`id\` = 62`,
+  )
+
+  // Grundeinkommen für Gemeinschaftsleistungen Jan. 2020, original creation date: 2020-02-19 08:56:12
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-19 08:56:12' WHERE \`id\` = 63`,
+  )
+
+  // Grundeinkommen für Gemeinschaftsleistungen Jan. 2020, original creation date: 2020-02-19 08:56:14
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-19 08:56:14' WHERE \`id\` = 64`,
+  )
+
+  // Grundeinkommen für Gemeinschaftsleistungen Jan. 2020, original creation date: 2020-02-19 08:56:21
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-19 08:56:21' WHERE \`id\` = 65`,
+  )
+
+  // Grundeinkommen für Gemeinschaftsleistungen Jan. 2020, original creation date: 2020-02-19 08:56:24
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-19 08:56:24' WHERE \`id\` = 66`,
+  )
+
+  // Grundeinkommen für Gemeinschaftsleistungen Jan. 2020, original creation date: 2020-02-19 08:56:26
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-19 08:56:26' WHERE \`id\` = 67`,
+  )
+
+  // Grundeinkommen für Gemeinschaftsleistungen Jan. 2020, original creation date: 2020-02-19 08:56:28
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-19 08:56:28' WHERE \`id\` = 68`,
+  )
+
+  // Grundeinkommen für Gemeinschaftsleistungen Jan. 2020, original creation date: 2020-02-19 08:56:31
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-19 08:56:31' WHERE \`id\` = 69`,
+  )
+
+  // Grundeinkommen rückwirkend Dezember, original creation date: 2020-02-20 06:40:36
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-12-20 06:40:36' WHERE \`id\` = 70`,
+  )
+
+  // Grundeinkommen für GLJanuar 2020, original creation date: 2020-02-20 06:43:41
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-20 06:43:41' WHERE \`id\` = 71`,
+  )
+
+  // Grundeinkommen für GLJanuar 2020, original creation date: 2020-02-20 06:43:43
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-20 06:43:43' WHERE \`id\` = 72`,
+  )
+
+  // Grundeinkommen für GLJanuar 2020, original creation date: 2020-02-20 06:43:45
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-20 06:43:45' WHERE \`id\` = 73`,
+  )
+
+  // Grundeinkommen für GLJanuar 2020, original creation date: 2020-02-20 06:43:47
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-20 06:43:47' WHERE \`id\` = 74`,
+  )
+
+  // Grundeinkommen, original creation date: 2020-02-20 07:09:05
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-20 07:09:05' WHERE \`id\` = 75`,
+  )
+
+  // Grundeinkommen für GLJanuar 2020, original creation date: 2020-02-20 08:03:31
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-20 08:03:31' WHERE \`id\` = 76`,
+  )
+
+  // AGE für Gemeinschaftsleistungen Januar 2020, original creation date: 2020-02-29 16:17:24
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-29 16:17:24' WHERE \`id\` = 77`,
+  )
+
+  // AGE für Gemeinschaftsleistungen Januar 2020, original creation date: 2020-02-29 16:17:35
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-29 16:17:35' WHERE \`id\` = 78`,
+  )
+
+  // AGE für Gemeinschaftsleistungen Januar 2020, original creation date: 2020-02-29 16:17:42
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-29 16:17:42' WHERE \`id\` = 79`,
+  )
+
+  // AGE für Gemeinschaftsleistungen Januar 2020, original creation date: 2020-02-29 16:29:47
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-29 16:29:47' WHERE \`id\` = 80`,
+  )
+
+  // AGE für Gemeinschaftsleistungen Januar 2020, original creation date: 2020-02-29 16:29:48
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-29 16:29:48' WHERE \`id\` = 81`,
+  )
+
+  // AGE für Gemeinschaftsleistungen Januar 2020, original creation date: 2020-02-29 16:29:55
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-29 16:29:55' WHERE \`id\` = 82`,
+  )
+
+  // AGE rückwirkend für Januar 2020, original creation date: 2020-03-04 09:08:54
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-04 09:08:54' WHERE \`id\` = 83`,
+  )
+
+  // AGE für Gemeinschaftsleitungen Januar, original creation date: 2020-03-07 07:59:42
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-07 07:59:42' WHERE \`id\` = 84`,
+  )
+
+  // AGE für Gemeinschaftsleitungen Januar, original creation date: 2020-03-07 07:59:51
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-07 07:59:51' WHERE \`id\` = 85`,
+  )
+
+  // AGE für Gemeinschaftsleitungen Januar, original creation date: 2020-03-07 07:59:54
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-07 07:59:54' WHERE \`id\` = 86`,
+  )
+
+  // AGE für Gemeinschaftsleitungen Januar, original creation date: 2020-03-07 07:59:57
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-07 07:59:57' WHERE \`id\` = 87`,
+  )
+
+  // AGE für Gemeinschaftsleistungen Februar 2020, original creation date: 2020-03-07 08:15:48
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-07 08:15:48' WHERE \`id\` = 88`,
+  )
+
+  // AGE für Gemeinschaftsleistungen Februar 2020, original creation date: 2020-03-07 08:15:53
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-07 08:15:53' WHERE \`id\` = 89`,
+  )
+
+  // AGE für Gemeinschaftsleistungen Februar 2020, original creation date: 2020-03-07 08:15:56
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-07 08:15:56' WHERE \`id\` = 90`,
+  )
+
+  // AGE für Gemeinschaftsleistungen Februar 2020, original creation date: 2020-03-07 08:15:59
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-07 08:15:59' WHERE \`id\` = 91`,
+  )
+
+  // AGE für Gemeinschaftsleistungen Februar 2020, original creation date: 2020-03-07 08:16:01
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-07 08:16:01' WHERE \`id\` = 92`,
+  )
+
+  // AGE für Gemeinschaftsleistungen Februar 2020, original creation date: 2020-03-07 08:16:05
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-07 08:16:05' WHERE \`id\` = 93`,
+  )
+
+  // AGE für Gemeinschaftsleistungen Februar 2020, original creation date: 2020-03-07 08:16:07
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-07 08:16:07' WHERE \`id\` = 94`,
+  )
+
+  // AGE für Gemeinschaftsleistungen Februar 2020, original creation date: 2020-03-07 08:16:10
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-07 08:16:10' WHERE \`id\` = 95`,
+  )
+
+  // AGE für Gemeinschaftsleistungen Februar 2020, original creation date: 2020-03-07 08:17:00
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-07 08:17:00' WHERE \`id\` = 96`,
+  )
+
+  // AGE für Gemeinschaftsleistungen Februar 2020, original creation date: 2020-03-07 08:17:03
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-07 08:17:03' WHERE \`id\` = 97`,
+  )
+
+  // AGE für Gemeinschaftsleistungen Februar 2020, original creation date: 2020-03-07 08:17:05
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-07 08:17:05' WHERE \`id\` = 98`,
+  )
+
+  // AGE für Gemeinschaftsleistungen Februar 2020, original creation date: 2020-03-07 08:17:07
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-07 08:17:07' WHERE \`id\` = 99`,
+  )
+
+  // AGE für Gemeinschaftsleistungen Februar 2020, original creation date: 2020-03-07 08:17:09
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-07 08:17:09' WHERE \`id\` = 100`,
+  )
+
+  // AGE für Gemeinschaftsleistungen Februar 2020, original creation date: 2020-03-07 08:17:11
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-07 08:17:11' WHERE \`id\` = 101`,
+  )
+
+  // AGE für Gemeinschaftsleistungen Februar 2020, original creation date: 2020-03-07 08:17:13
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-07 08:17:13' WHERE \`id\` = 102`,
+  )
+
+  // AGE für Gemeinschaftsleistungen Februar 2020, original creation date: 2020-03-07 08:17:21
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-07 08:17:21' WHERE \`id\` = 103`,
+  )
+
+  // AGE für Gemeinschaftsleistungen Februar 2020, original creation date: 2020-03-07 08:17:25
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-07 08:17:25' WHERE \`id\` = 104`,
+  )
+
+  // AGE für Gemeinschaftsleistungen Februar 2020, original creation date: 2020-03-07 08:17:28
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-07 08:17:28' WHERE \`id\` = 105`,
+  )
+
+  // AGE für Gemeinschaftsleistungen Februar, original creation date: 2020-03-07 08:19:15
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-07 08:19:15' WHERE \`id\` = 106`,
+  )
+
+  // AGE für Gemeinschaftsleistungen Februar 2020 geschöpft und gutgeschrieben., original creation date: 2020-03-08 18:00:20
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-08 18:00:20' WHERE \`id\` = 107`,
+  )
+
+  // AGE für Februar, original creation date: 2020-03-09 11:43:30
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-09 11:43:30' WHERE \`id\` = 108`,
+  )
+
+  // AGE für Gemeinschaftsleistungen Februar 2020, original creation date: 2020-03-09 17:48:34
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-09 17:48:34' WHERE \`id\` = 109`,
+  )
+
+  // AGE für Gemeinschaftsleistungen Februar 2020, original creation date: 2020-03-09 17:48:36
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-09 17:48:36' WHERE \`id\` = 110`,
+  )
+
+  // AGE für Gemeinschaftsleistungen Februar 2020, original creation date: 2020-03-09 17:48:38
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-09 17:48:38' WHERE \`id\` = 111`,
+  )
+
+  // AGE für Gemeinschaftsleistungen Februar 2020, original creation date: 2020-03-09 17:48:40
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-09 17:48:40' WHERE \`id\` = 112`,
+  )
+
+  // AGE für Gemeinschaftsleistungen Februar 2020, original creation date: 2020-03-09 17:48:43
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-09 17:48:43' WHERE \`id\` = 113`,
+  )
+
+  // AGE für Gemeinschaftsleistungen rückwirkend für  Januar 2020 , original creation date: 2020-03-11 21:11:03
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-11 21:11:03' WHERE \`id\` = 114`,
+  )
+
+  // AGE für Gemeinschaftsleistungen Februar 2020 , original creation date: 2020-03-11 21:17:22
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-11 21:17:22' WHERE \`id\` = 115`,
+  )
+
+  // AGE für Gemeinschaftsleistungen Februar 2020 , original creation date: 2020-03-11 21:17:26
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-11 21:17:26' WHERE \`id\` = 116`,
+  )
+
+  // AGE für Gemeinschaftsleistungen rückwirkend für  Januar, original creation date: 2020-03-18 15:44:07
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-18 15:44:07' WHERE \`id\` = 117`,
+  )
+
+  // AGE für Gemeinschaftsleistungen Februar 2020 , original creation date: 2020-03-18 15:54:59
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-18 15:54:59' WHERE \`id\` = 118`,
+  )
+
+  // AGE für Gemeinschaftsleistungen Februar 2020 , original creation date: 2020-03-18 15:55:32
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-18 15:55:32' WHERE \`id\` = 119`,
+  )
+
+  // AGE für Gemeinschaftsleistungen Februar 2020 , original creation date: 2020-03-18 15:56:32
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-18 15:56:32' WHERE \`id\` = 120`,
+  )
+
+  // AGE für Gemeinschaftsleistungen Februar 2020 , original creation date: 2020-03-18 15:56:48
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-18 15:56:48' WHERE \`id\` = 121`,
+  )
+
+  // AGE für Gemeinschaftsleistungen Februar 2020 , original creation date: 2020-03-18 15:57:14
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-18 15:57:14' WHERE \`id\` = 122`,
+  )
+
+  // AGE für Gemeinschaftsleistungen Februar 2020 , original creation date: 2020-03-18 15:58:41
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-18 15:58:41' WHERE \`id\` = 123`,
+  )
+
+  // AGE für Gemeinschaftsleistungen Februar 2020 , original creation date: 2020-03-18 15:59:03
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-18 15:59:03' WHERE \`id\` = 124`,
+  )
+
+  // AGE für Gemeinschaftsleistungen Februar 2020 , original creation date: 2020-03-18 15:59:26
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-18 15:59:26' WHERE \`id\` = 125`,
+  )
+
+  // AGE für Gemeinschaftsleistungen Februar 2020 , original creation date: 2020-03-18 16:00:05
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-18 16:00:05' WHERE \`id\` = 126`,
+  )
+
+  // AGE für Gemeinschaftsleistungen Februar 2020 , original creation date: 2020-03-18 16:00:12
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-18 16:00:12' WHERE \`id\` = 127`,
+  )
+
+  // Aktives Grundeinkommen, original creation date: 2020-03-23 07:35:35
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-23 07:35:35' WHERE \`id\` = 128`,
+  )
+
+  // Aktives Grundeinkommen, original creation date: 2020-03-23 07:35:38
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-23 07:35:38' WHERE \`id\` = 129`,
+  )
+
+  // Aktives Grundeinkommen, original creation date: 2020-03-23 07:35:42
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-23 07:35:42' WHERE \`id\` = 130`,
+  )
+
+  // Aktives Grundeinkommen Januar , original creation date: 2020-03-24 17:00:05
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-24 17:00:05' WHERE \`id\` = 131`,
+  )
+
+  // Aktives Grundeinkommen Februar, original creation date: 2020-03-24 17:06:50
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-24 17:06:50' WHERE \`id\` = 132`,
+  )
+
+  // Aktives Grundeinkommen Februar, original creation date: 2020-03-24 17:06:54
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-24 17:06:54' WHERE \`id\` = 133`,
+  )
+
+  // Aktives Grundeinkommen März, original creation date: 2020-03-24 17:14:21
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-24 17:14:21' WHERE \`id\` = 134`,
+  )
+
+  // Aktives Grundeinkommen März, original creation date: 2020-03-24 17:14:27
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-24 17:14:27' WHERE \`id\` = 135`,
+  )
+
+  // Aktives Grundeinkommen März, original creation date: 2020-03-24 17:14:28
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-24 17:14:28' WHERE \`id\` = 136`,
+  )
+
+  // Aktives Grundeinkommen März, original creation date: 2020-03-24 17:14:30
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-24 17:14:30' WHERE \`id\` = 137`,
+  )
+
+  // Aktives Grundeinkommen geschöpft , original creation date: 2020-03-27 09:06:16
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-27 09:06:16' WHERE \`id\` = 138`,
+  )
+
+  // Aktives Grundeinkommen für GL Februar, original creation date: 2020-03-27 09:44:27
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-27 09:44:27' WHERE \`id\` = 139`,
+  )
+
+  // Aktives Grundeinkommen für GL Februar, original creation date: 2020-03-27 09:44:29
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-27 09:44:29' WHERE \`id\` = 140`,
+  )
+
+  // Aktives Grundeinkommen für GL Februar, original creation date: 2020-03-27 09:44:30
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-27 09:44:30' WHERE \`id\` = 141`,
+  )
+
+  // Aktives Grundeinkommen für GL Februar, original creation date: 2020-03-27 09:44:35
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-27 09:44:35' WHERE \`id\` = 142`,
+  )
+
+  // Aktives Grundeinkommen für GL Februar, original creation date: 2020-03-27 09:44:36
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-27 09:44:36' WHERE \`id\` = 143`,
+  )
+
+  // Aktives Grundeinkommen für GL Februar, original creation date: 2020-03-27 09:44:40
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-27 09:44:40' WHERE \`id\` = 144`,
+  )
+
+  // Aktives Grundeinkommen für GL Februar, original creation date: 2020-03-27 09:44:42
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-27 09:44:42' WHERE \`id\` = 145`,
+  )
+
+  // Aktives Grundeinkommen für GL. März, original creation date: 2020-03-28 09:28:24
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-28 09:28:24' WHERE \`id\` = 146`,
+  )
+
+  // Aktives Grundeinkommen für GL. März, original creation date: 2020-03-28 09:34:30
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-28 09:34:30' WHERE \`id\` = 147`,
+  )
+
+  // , original creation date: 2020-03-29 17:21:33
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-28 17:21:33' WHERE \`id\` = 148`,
+  )
+
+  // , original creation date: 2020-03-29 17:21:35
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-28 17:21:35' WHERE \`id\` = 149`,
+  )
+
+  // Aktives Grundeinkommen für GL. Dez, original creation date: 2020-03-30 06:59:55
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-12-30 06:59:55' WHERE \`id\` = 150`,
+  )
+
+  // Aktives Grundeinkommen für GL. Dez 2019, original creation date: 2020-03-30 07:05:14
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-12-30 07:05:14' WHERE \`id\` = 151`,
+  )
+
+  // Aktives Grundeinkommen für GL. Jan 2020, original creation date: 2020-03-30 07:09:52
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-30 07:09:52' WHERE \`id\` = 152`,
+  )
+
+  // Aktives Grundeinkommen für GL. Februar 2020, original creation date: 2020-03-30 07:15:43
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-01 07:15:43' WHERE \`id\` = 153`,
+  )
+
+  // Aktives Grundeinkommen für GL., original creation date: 2020-03-30 07:16:33
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-01 07:16:33' WHERE \`id\` = 154`,
+  )
+
+  // Aktives Grundeinkommen für GL. März, original creation date: 2020-03-30 07:21:07
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-30 07:21:07' WHERE \`id\` = 155`,
+  )
+
+  // Aktives Grundeinkommen für GL. Feb. 2020, original creation date: 2020-03-30 11:47:55
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-01 11:47:55' WHERE \`id\` = 156`,
+  )
+
+  // Aktives Grundeinkommen für GL. März, original creation date: 2020-04-01 06:56:20
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-01 06:56:20' WHERE \`id\` = 157`,
+  )
+
+  // Aktives Grundeinkommen für GL. März, original creation date: 2020-04-01 06:56:26
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-01 06:56:26' WHERE \`id\` = 158`,
+  )
+
+  // Aktives Grundeinkommen für GL. März, original creation date: 2020-04-01 06:56:29
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-01 06:56:29' WHERE \`id\` = 159`,
+  )
+
+  // Aktives Grundeinkommen für GL. März, original creation date: 2020-04-01 06:56:31
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-01 06:56:31' WHERE \`id\` = 160`,
+  )
+
+  // Aktives Grundeinkommen für GL. März, original creation date: 2020-04-01 06:58:10
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-01 06:58:10' WHERE \`id\` = 161`,
+  )
+
+  // Aktives Grundeinkommen für GL. März, original creation date: 2020-04-07 14:09:26
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-07 14:09:26' WHERE \`id\` = 162`,
+  )
+
+  // Aktives Grundeinkommen für GL. März, original creation date: 2020-04-07 14:09:28
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-07 14:09:28' WHERE \`id\` = 163`,
+  )
+
+  // Aktives Grundeinkommen für GL. März, original creation date: 2020-04-07 14:09:29
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-07 14:09:29' WHERE \`id\` = 164`,
+  )
+
+  // Aktives Grundeinkommen für GL. März, original creation date: 2020-04-07 14:09:32
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-07 14:09:32' WHERE \`id\` = 165`,
+  )
+
+  // Aktives Grundeinkommen für GL. März, original creation date: 2020-04-08 18:41:17
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-08 18:41:17' WHERE \`id\` = 166`,
+  )
+
+  // Aktives Grundeinkommen für GL. März, original creation date: 2020-04-08 18:41:20
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-08 18:41:20' WHERE \`id\` = 167`,
+  )
+
+  // Aktives Grundeinkommen für GL. März, original creation date: 2020-04-08 18:41:21
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-08 18:41:21' WHERE \`id\` = 168`,
+  )
+
+  // Aktives Grundeinkommen für GL. März, original creation date: 2020-04-08 18:41:23
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-08 18:41:23' WHERE \`id\` = 169`,
+  )
+
+  // Aktives Grundeinkommen für GL. März, original creation date: 2020-04-08 18:41:27
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-08 18:41:27' WHERE \`id\` = 170`,
+  )
+
+  // Aktives Grundeinkommen für GL. März, original creation date: 2020-04-08 18:58:15
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-08 18:58:15' WHERE \`id\` = 171`,
+  )
+
+  // Aktives Grundeinkommen für GL. März, original creation date: 2020-04-15 16:10:54
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-15 16:10:54' WHERE \`id\` = 172`,
+  )
+
+  // Aktives Grundeinkommen für GL. März, original creation date: 2020-04-15 16:10:56
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-15 16:10:56' WHERE \`id\` = 173`,
+  )
+
+  // Aktives Grundeinkommen für GL. März, original creation date: 2020-04-15 16:10:58
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-15 16:10:58' WHERE \`id\` = 174`,
+  )
+
+  // Aktives Grundeinkommen für GL. März, original creation date: 2020-04-15 16:11:01
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-15 16:11:01' WHERE \`id\` = 175`,
+  )
+
+  // Aktives Grundeinkommen für GL. März, original creation date: 2020-04-15 16:11:02
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-15 16:11:02' WHERE \`id\` = 176`,
+  )
+
+  // Aktives Grundeinkommen für GL. März, original creation date: 2020-04-15 16:11:04
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-15 16:11:04' WHERE \`id\` = 177`,
+  )
+
+  // Aktives Grundeinkommen für GL. März, original creation date: 2020-04-15 16:11:07
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-15 16:11:07' WHERE \`id\` = 178`,
+  )
+
+  // Aktives Grundeinkommen für GL.März 2020, original creation date: 2020-04-17 16:54:39
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-17 16:54:39' WHERE \`id\` = 179`,
+  )
+
+  // Aktives Grundeinkommen für GL.März 2020, original creation date: 2020-04-17 16:54:40
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-17 16:54:40' WHERE \`id\` = 180`,
+  )
+
+  // Aktives Grundeinkommen für GL.März 2020, original creation date: 2020-04-17 16:54:42
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-17 16:54:42' WHERE \`id\` = 181`,
+  )
+
+  // Aktives Grundeinkommen für GL.März 2020, original creation date: 2020-04-17 16:54:44
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-17 16:54:44' WHERE \`id\` = 182`,
+  )
+
+  // Aktives Grundeinkommen geschöpft und gutgeschrieben.
+  // Tausend Dank, weil Du bei uns bist und  gemeinsam mit uns das Lebensgeld der Zukunft erschaffst!, original creation date: 2020-04-18 08:58:42
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-18 08:58:42' WHERE \`id\` = 183`,
+  )
+
+  // Aktives Grundeinkommen geschöpft und gutgeschrieben.
+  // Tausend Dank, weil Du bei uns bist und  gemeinsam mit uns das Lebensgeld der Zukunft erschaffst!, original creation date: 2020-04-18 08:58:44
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-18 08:58:44' WHERE \`id\` = 184`,
+  )
+
+  // Aktives Grundeinkommen für GL.März 2020, original creation date: 2020-04-20 17:44:36
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-20 17:44:36' WHERE \`id\` = 185`,
+  )
+
+  // Aktives Grundeinkommen für GL.März 2020, original creation date: 2020-04-20 17:44:38
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-20 17:44:38' WHERE \`id\` = 186`,
+  )
+
+  // Aktives Grundeinkommen für GL.März 2020, original creation date: 2020-04-20 17:44:40
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-20 17:44:40' WHERE \`id\` = 187`,
+  )
+
+  // Aktives Grundeinkommen für GL.März 2020, original creation date: 2020-04-20 17:44:43
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-20 17:44:43' WHERE \`id\` = 188`,
+  )
+
+  // Aktives Grundeinkommen für GL März 2020, original creation date: 2020-04-25 06:30:13
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-25 06:30:13' WHERE \`id\` = 189`,
+  )
+
+  // Aktives Grundeinkommen für GL März 2020, original creation date: 2020-04-25 06:30:19
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-25 06:30:19' WHERE \`id\` = 190`,
+  )
+
+  // Aktives Grundeinkommen für GL März 2020, original creation date: 2020-04-25 06:30:21
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-25 06:30:21' WHERE \`id\` = 191`,
+  )
+
+  // Aktives Grundeinkommen für GL März 2020, original creation date: 2020-04-25 06:30:23
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-25 06:30:23' WHERE \`id\` = 192`,
+  )
+
+  // Aktives Grundeinkommen für GL März 2020, original creation date: 2020-04-25 06:30:24
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-25 06:30:24' WHERE \`id\` = 193`,
+  )
+
+  // Aktives Grundeinkommen für GL März 2020, original creation date: 2020-04-25 06:30:26
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-25 06:30:26' WHERE \`id\` = 194`,
+  )
+
+  // Aktives Grundeinkommen für G März 2020, original creation date: 2020-04-25 18:41:55
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-25 18:41:55' WHERE \`id\` = 195`,
+  )
+
+  // Aktives Grundeinkommen für G März 2020, original creation date: 2020-04-25 18:42:25
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-25 18:42:25' WHERE \`id\` = 196`,
+  )
+
+  // Aktives Grundeinkommen für März 2020, original creation date: 2020-04-25 18:46:01
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-25 18:46:01' WHERE \`id\` = 197`,
+  )
+
+  // Aktives Grundeinkommen für März 2020, original creation date: 2020-04-30 06:40:39
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-30 06:40:39' WHERE \`id\` = 198`,
+  )
+
+  // Aktives Grundeinkommen für März 2020, original creation date: 2020-04-30 06:40:41
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-30 06:40:41' WHERE \`id\` = 199`,
+  )
+
+  // Aktives Grundeinkommen für März 2020, original creation date: 2020-04-30 06:40:42
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-30 06:40:42' WHERE \`id\` = 200`,
+  )
+
+  // Aktives Grundeinkommen für März 2020, original creation date: 2020-04-30 06:40:45
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-30 06:40:45' WHERE \`id\` = 201`,
+  )
+
+  // Aktives Grundeinkommen für März 2020, original creation date: 2020-04-30 06:40:46
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-30 06:40:46' WHERE \`id\` = 202`,
+  )
+
+  // Aktives Grundeinkommen für März 2020, original creation date: 2020-04-30 06:40:50
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-30 06:40:50' WHERE \`id\` = 203`,
+  )
+
+  // Aktives Grundeinkommen für März 2020, original creation date: 2020-05-02 08:25:27
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-02 08:25:27' WHERE \`id\` = 204`,
+  )
+
+  // Aktives Grundeinkommen für März 2020, original creation date: 2020-05-02 08:25:29
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-02 08:25:29' WHERE \`id\` = 205`,
+  )
+
+  // Aktives Grundeinkommen für März 2020, original creation date: 2020-05-02 08:25:32
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-02 08:25:32' WHERE \`id\` = 206`,
+  )
+
+  // Aktives Grundeinkommen für März 2020, original creation date: 2020-05-02 08:28:14
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-02 08:28:14' WHERE \`id\` = 207`,
+  )
+
+  // Aktives Grundeinkommen für April 2020, original creation date: 2020-05-02 08:43:49
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-02 08:43:49' WHERE \`id\` = 208`,
+  )
+
+  // Aktives Grundeinkommen für April 2020, original creation date: 2020-05-02 08:43:51
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-02 08:43:51' WHERE \`id\` = 209`,
+  )
+
+  // Aktives Grundeinkommen für April 2020, original creation date: 2020-05-02 08:43:54
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-02 08:43:54' WHERE \`id\` = 210`,
+  )
+
+  // Aktives Grundeinkommen für April 2020, original creation date: 2020-05-02 08:43:56
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-02 08:43:56' WHERE \`id\` = 211`,
+  )
+
+  // Aktives Grundeinkommen für April 2020, original creation date: 2020-05-02 08:43:57
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-02 08:43:57' WHERE \`id\` = 212`,
+  )
+
+  // Aktives Grundeinkommen für April 2020, original creation date: 2020-05-02 08:43:59
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-02 08:43:59' WHERE \`id\` = 213`,
+  )
+
+  // Aktives Grundeinkommen für April 2020, original creation date: 2020-05-02 08:44:01
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-02 08:44:01' WHERE \`id\` = 214`,
+  )
+
+  // Aktives Grundeinkommen für April 2020, original creation date: 2020-05-02 08:44:02
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-02 08:44:02' WHERE \`id\` = 215`,
+  )
+
+  // Aktives Grundeinkommen für April 2020, original creation date: 2020-05-02 08:44:05
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-02 08:44:05' WHERE \`id\` = 216`,
+  )
+
+  // Aktives Grundeinkommen für April 2020, original creation date: 2020-05-02 08:44:10
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-02 08:44:10' WHERE \`id\` = 217`,
+  )
+
+  // Aktives Grundeinkommen für April 2020, original creation date: 2020-05-02 08:44:12
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-02 08:44:12' WHERE \`id\` = 218`,
+  )
+
+  // Aktives Grundeinkommen für April 2020, original creation date: 2020-05-02 08:44:14
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-02 08:44:14' WHERE \`id\` = 219`,
+  )
+
+  // Aktives Grundeinkommen für April 2020, original creation date: 2020-05-02 08:44:17
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-02 08:44:17' WHERE \`id\` = 220`,
+  )
+
+  // Aktives Grundeinkommen für April 2020, original creation date: 2020-05-03 09:00:04
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-03 09:00:04' WHERE \`id\` = 221`,
+  )
+
+  // Aktives Grundeinkommen für April 2020, original creation date: 2020-05-03 09:00:07
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-03 09:00:07' WHERE \`id\` = 222`,
+  )
+}
+
+export async function downgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
+  // reverse creation date changes
+
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-12-17 13:06:13' WHERE \`id\` = 1`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-12-17 13:06:16' WHERE \`id\` = 2`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-12-17 13:06:19' WHERE \`id\` = 3`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-12-17 13:06:21' WHERE \`id\` = 4`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-12-17 13:07:01' WHERE \`id\` = 5`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2019-12-19 17:35:16' WHERE \`id\` = 6`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-08 10:34:40' WHERE \`id\` = 7`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-08 11:02:41' WHERE \`id\` = 8`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-08 11:06:42' WHERE \`id\` = 9`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-08 11:16:11' WHERE \`id\` = 10`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-08 11:16:15' WHERE \`id\` = 11`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-08 13:24:29' WHERE \`id\` = 12`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-09 12:02:48' WHERE \`id\` = 13`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-09 12:02:52' WHERE \`id\` = 14`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-09 12:02:54' WHERE \`id\` = 15`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-09 12:09:08' WHERE \`id\` = 16`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-11 11:10:55' WHERE \`id\` = 17`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-11 11:11:24' WHERE \`id\` = 18`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-11 11:12:09' WHERE \`id\` = 19`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-11 11:31:20' WHERE \`id\` = 20`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-11 11:37:13' WHERE \`id\` = 21`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-11 11:37:42' WHERE \`id\` = 22`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-11 19:01:06' WHERE \`id\` = 23`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-13 16:27:07' WHERE \`id\` = 24`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-13 16:28:05' WHERE \`id\` = 25`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-13 16:28:57' WHERE \`id\` = 26`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-13 16:29:45' WHERE \`id\` = 27`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-17 13:47:28' WHERE \`id\` = 28`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-17 13:48:52' WHERE \`id\` = 29`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-17 13:49:21' WHERE \`id\` = 30`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-23 13:08:44' WHERE \`id\` = 31`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-27 08:12:16' WHERE \`id\` = 32`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-30 14:49:58' WHERE \`id\` = 33`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-30 14:50:35' WHERE \`id\` = 34`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-30 14:50:55' WHERE \`id\` = 35`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-30 14:52:03' WHERE \`id\` = 36`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-30 14:52:33' WHERE \`id\` = 37`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-30 14:52:53' WHERE \`id\` = 38`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-30 14:53:45' WHERE \`id\` = 39`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-30 14:54:13' WHERE \`id\` = 40`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-30 14:54:50' WHERE \`id\` = 41`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-30 15:03:26' WHERE \`id\` = 42`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-30 15:10:39' WHERE \`id\` = 43`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-30 15:13:10' WHERE \`id\` = 44`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-01-30 15:26:45' WHERE \`id\` = 45`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-19 08:54:31' WHERE \`id\` = 46`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-19 08:55:30' WHERE \`id\` = 47`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-19 08:55:33' WHERE \`id\` = 48`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-19 08:55:36' WHERE \`id\` = 49`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-19 08:55:39' WHERE \`id\` = 50`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-19 08:55:43' WHERE \`id\` = 51`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-19 08:55:46' WHERE \`id\` = 52`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-19 08:55:48' WHERE \`id\` = 53`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-19 08:55:50' WHERE \`id\` = 54`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-19 08:55:52' WHERE \`id\` = 55`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-19 08:55:54' WHERE \`id\` = 56`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-19 08:55:56' WHERE \`id\` = 57`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-19 08:55:59' WHERE \`id\` = 58`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-19 08:56:02' WHERE \`id\` = 59`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-19 08:56:05' WHERE \`id\` = 60`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-19 08:56:07' WHERE \`id\` = 61`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-19 08:56:10' WHERE \`id\` = 62`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-19 08:56:12' WHERE \`id\` = 63`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-19 08:56:14' WHERE \`id\` = 64`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-19 08:56:21' WHERE \`id\` = 65`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-19 08:56:24' WHERE \`id\` = 66`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-19 08:56:26' WHERE \`id\` = 67`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-19 08:56:28' WHERE \`id\` = 68`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-19 08:56:31' WHERE \`id\` = 69`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-20 06:40:36' WHERE \`id\` = 70`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-20 06:43:41' WHERE \`id\` = 71`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-20 06:43:43' WHERE \`id\` = 72`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-20 06:43:45' WHERE \`id\` = 73`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-20 06:43:47' WHERE \`id\` = 74`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-20 07:09:05' WHERE \`id\` = 75`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-20 08:03:31' WHERE \`id\` = 76`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-29 16:17:24' WHERE \`id\` = 77`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-29 16:17:35' WHERE \`id\` = 78`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-29 16:17:42' WHERE \`id\` = 79`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-29 16:29:47' WHERE \`id\` = 80`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-29 16:29:48' WHERE \`id\` = 81`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-02-29 16:29:55' WHERE \`id\` = 82`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-04 09:08:54' WHERE \`id\` = 83`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-07 07:59:42' WHERE \`id\` = 84`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-07 07:59:51' WHERE \`id\` = 85`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-07 07:59:54' WHERE \`id\` = 86`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-07 07:59:57' WHERE \`id\` = 87`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-07 08:15:48' WHERE \`id\` = 88`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-07 08:15:53' WHERE \`id\` = 89`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-07 08:15:56' WHERE \`id\` = 90`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-07 08:15:59' WHERE \`id\` = 91`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-07 08:16:01' WHERE \`id\` = 92`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-07 08:16:05' WHERE \`id\` = 93`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-07 08:16:07' WHERE \`id\` = 94`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-07 08:16:10' WHERE \`id\` = 95`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-07 08:17:00' WHERE \`id\` = 96`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-07 08:17:03' WHERE \`id\` = 97`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-07 08:17:05' WHERE \`id\` = 98`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-07 08:17:07' WHERE \`id\` = 99`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-07 08:17:09' WHERE \`id\` = 100`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-07 08:17:11' WHERE \`id\` = 101`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-07 08:17:13' WHERE \`id\` = 102`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-07 08:17:21' WHERE \`id\` = 103`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-07 08:17:25' WHERE \`id\` = 104`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-07 08:17:28' WHERE \`id\` = 105`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-07 08:19:15' WHERE \`id\` = 106`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-08 18:00:20' WHERE \`id\` = 107`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-09 11:43:30' WHERE \`id\` = 108`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-09 17:48:34' WHERE \`id\` = 109`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-09 17:48:36' WHERE \`id\` = 110`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-09 17:48:38' WHERE \`id\` = 111`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-09 17:48:40' WHERE \`id\` = 112`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-09 17:48:43' WHERE \`id\` = 113`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-11 21:11:03' WHERE \`id\` = 114`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-11 21:17:22' WHERE \`id\` = 115`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-11 21:17:26' WHERE \`id\` = 116`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-18 15:44:07' WHERE \`id\` = 117`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-18 15:54:59' WHERE \`id\` = 118`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-18 15:55:32' WHERE \`id\` = 119`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-18 15:56:32' WHERE \`id\` = 120`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-18 15:56:48' WHERE \`id\` = 121`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-18 15:57:14' WHERE \`id\` = 122`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-18 15:58:41' WHERE \`id\` = 123`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-18 15:59:03' WHERE \`id\` = 124`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-18 15:59:26' WHERE \`id\` = 125`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-18 16:00:05' WHERE \`id\` = 126`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-18 16:00:12' WHERE \`id\` = 127`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-23 07:35:35' WHERE \`id\` = 128`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-23 07:35:38' WHERE \`id\` = 129`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-23 07:35:42' WHERE \`id\` = 130`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-24 17:00:05' WHERE \`id\` = 131`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-24 17:06:50' WHERE \`id\` = 132`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-24 17:06:54' WHERE \`id\` = 133`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-24 17:14:21' WHERE \`id\` = 134`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-24 17:14:27' WHERE \`id\` = 135`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-24 17:14:28' WHERE \`id\` = 136`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-24 17:14:30' WHERE \`id\` = 137`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-27 09:06:16' WHERE \`id\` = 138`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-27 09:44:27' WHERE \`id\` = 139`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-27 09:44:29' WHERE \`id\` = 140`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-27 09:44:30' WHERE \`id\` = 141`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-27 09:44:35' WHERE \`id\` = 142`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-27 09:44:36' WHERE \`id\` = 143`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-27 09:44:40' WHERE \`id\` = 144`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-27 09:44:42' WHERE \`id\` = 145`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-28 09:28:24' WHERE \`id\` = 146`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-28 09:34:30' WHERE \`id\` = 147`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-29 17:21:33' WHERE \`id\` = 148`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-29 17:21:35' WHERE \`id\` = 149`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-30 06:59:55' WHERE \`id\` = 150`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-30 07:05:14' WHERE \`id\` = 151`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-30 07:09:52' WHERE \`id\` = 152`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-30 07:15:43' WHERE \`id\` = 153`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-30 07:16:33' WHERE \`id\` = 154`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-30 07:21:07' WHERE \`id\` = 155`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-03-30 11:47:55' WHERE \`id\` = 156`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-01 06:56:20' WHERE \`id\` = 157`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-01 06:56:26' WHERE \`id\` = 158`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-01 06:56:29' WHERE \`id\` = 159`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-01 06:56:31' WHERE \`id\` = 160`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-01 06:58:10' WHERE \`id\` = 161`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-07 14:09:26' WHERE \`id\` = 162`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-07 14:09:28' WHERE \`id\` = 163`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-07 14:09:29' WHERE \`id\` = 164`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-07 14:09:32' WHERE \`id\` = 165`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-08 18:41:17' WHERE \`id\` = 166`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-08 18:41:20' WHERE \`id\` = 167`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-08 18:41:21' WHERE \`id\` = 168`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-08 18:41:23' WHERE \`id\` = 169`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-08 18:41:27' WHERE \`id\` = 170`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-08 18:58:15' WHERE \`id\` = 171`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-15 16:10:54' WHERE \`id\` = 172`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-15 16:10:56' WHERE \`id\` = 173`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-15 16:10:58' WHERE \`id\` = 174`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-15 16:11:01' WHERE \`id\` = 175`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-15 16:11:02' WHERE \`id\` = 176`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-15 16:11:04' WHERE \`id\` = 177`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-15 16:11:07' WHERE \`id\` = 178`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-17 16:54:39' WHERE \`id\` = 179`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-17 16:54:40' WHERE \`id\` = 180`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-17 16:54:42' WHERE \`id\` = 181`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-17 16:54:44' WHERE \`id\` = 182`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-18 08:58:42' WHERE \`id\` = 183`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-18 08:58:44' WHERE \`id\` = 184`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-20 17:44:36' WHERE \`id\` = 185`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-20 17:44:38' WHERE \`id\` = 186`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-20 17:44:40' WHERE \`id\` = 187`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-20 17:44:43' WHERE \`id\` = 188`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-25 06:30:13' WHERE \`id\` = 189`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-25 06:30:19' WHERE \`id\` = 190`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-25 06:30:21' WHERE \`id\` = 191`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-25 06:30:23' WHERE \`id\` = 192`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-25 06:30:24' WHERE \`id\` = 193`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-25 06:30:26' WHERE \`id\` = 194`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-25 18:41:55' WHERE \`id\` = 195`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-25 18:42:25' WHERE \`id\` = 196`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-25 18:46:01' WHERE \`id\` = 197`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-30 06:40:39' WHERE \`id\` = 198`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-30 06:40:41' WHERE \`id\` = 199`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-30 06:40:42' WHERE \`id\` = 200`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-30 06:40:45' WHERE \`id\` = 201`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-30 06:40:46' WHERE \`id\` = 202`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-04-30 06:40:50' WHERE \`id\` = 203`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-05-02 08:25:27' WHERE \`id\` = 204`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-05-02 08:25:29' WHERE \`id\` = 205`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-05-02 08:25:32' WHERE \`id\` = 206`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-05-02 08:28:14' WHERE \`id\` = 207`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-05-02 08:43:49' WHERE \`id\` = 208`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-05-02 08:43:51' WHERE \`id\` = 209`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-05-02 08:43:54' WHERE \`id\` = 210`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-05-02 08:43:56' WHERE \`id\` = 211`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-05-02 08:43:57' WHERE \`id\` = 212`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-05-02 08:43:59' WHERE \`id\` = 213`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-05-02 08:44:01' WHERE \`id\` = 214`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-05-02 08:44:02' WHERE \`id\` = 215`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-05-02 08:44:05' WHERE \`id\` = 216`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-05-02 08:44:10' WHERE \`id\` = 217`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-05-02 08:44:12' WHERE \`id\` = 218`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-05-02 08:44:14' WHERE \`id\` = 219`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-05-02 08:44:17' WHERE \`id\` = 220`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-05-03 09:00:04' WHERE \`id\` = 221`,
+  )
+  await queryFn(
+    `UPDATE \`transactions\` SET creation_date = '2020-05-03 09:00:07' WHERE \`id\` = 222`,
+  )
+
+  // remove added transaction
+  await queryFn(
+    `DELETE FROM \`transactions\` 
+     WHERE \`user_id\` = 275 AND \`balance\` IN (2000, 3000) AND \`amount\` = 1000`,
+  )
+
+  // rewind transaction to split
+  await queryFn(
+    `UPDATE \`transactions\` set \`amount\` = 3000, \`memo\` = 'Aktives Grundeinkommen für GL. Dez, Jan, Feb' 
+     WHERE \`id\` = 150`,
+  )
+
+  await queryFn(`UPDATE \`transactions\` set \`previous\` = 150 WHERE \`id\` = 278`)
+}
diff --git a/database/migrations/0043-add_event_protocol_table.ts b/database/migrations/0043-add_event_protocol_table.ts
new file mode 100644
index 000000000..c3669f857
--- /dev/null
+++ b/database/migrations/0043-add_event_protocol_table.ts
@@ -0,0 +1,28 @@
+/* MIGRATION TO ADD EVENT_PROTOCOL
+ *
+ * This migration adds the table `event_protocol` in order to store all sorts of business event data
+ */
+
+/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
+/* eslint-disable @typescript-eslint/no-explicit-any */
+
+export async function upgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
+  await queryFn(`
+      CREATE TABLE IF NOT EXISTS \`event_protocol\` (
+        \`id\` int(10) unsigned NOT NULL AUTO_INCREMENT,
+        \`type\` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL,
+        \`created_at\` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
+        \`user_id\` int(10) unsigned NOT NULL,
+        \`x_user_id\` int(10) unsigned NULL DEFAULT NULL,
+        \`x_community_id\` int(10) unsigned NULL DEFAULT NULL,
+        \`transaction_id\` int(10) unsigned NULL DEFAULT NULL,
+        \`contribution_id\` int(10) unsigned NULL DEFAULT NULL,
+        \`amount\` bigint(20) NULL DEFAULT NULL,
+        PRIMARY KEY (\`id\`)
+      ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;`)
+}
+
+export async function downgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
+  // write downgrade logic as parameter of queryFn
+  await queryFn(`DROP TABLE IF EXISTS \`event_protocol\`;`)
+}
diff --git a/database/migrations/0044-insert_missing_contributions.ts b/database/migrations/0044-insert_missing_contributions.ts
new file mode 100644
index 000000000..a14141498
--- /dev/null
+++ b/database/migrations/0044-insert_missing_contributions.ts
@@ -0,0 +1,34 @@
+/* MIGRATION TO INSERT contributions for all transactions with type creation that do not have a contribution yet */
+
+/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
+/* eslint-disable @typescript-eslint/no-explicit-any */
+
+export async function upgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
+  await queryFn(
+    `INSERT INTO gradido_community.contributions
+  (user_id, created_at, contribution_date, memo, amount, moderator_id, confirmed_by, confirmed_at, transaction_id)
+SELECT 
+  user_id,
+  balance_date,
+  creation_date AS contribution_date,
+  memo,
+  amount,
+  20 AS moderator_id,
+  502 AS confirmed_by,
+  balance_date AS confirmed_at,
+  id
+FROM
+  gradido_community.transactions
+WHERE
+  type_id = 1
+  AND NOT EXISTS(
+    SELECT * FROM gradido_community.contributions
+    WHERE gradido_community.contributions.transaction_id = gradido_community.transactions.id);`,
+  )
+}
+
+export async function downgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
+  await queryFn(
+    'DELETE FROM `contributions` WHERE `contributions`.`moderator_id` = 20 AND `contributions`.`confirmed_by` = 502 AND `contributions`.`created_at` = `contributions`.`confirmed_at`;',
+  )
+}
diff --git a/database/package.json b/database/package.json
index 50e3bdd78..05e1c2ac8 100644
--- a/database/package.json
+++ b/database/package.json
@@ -1,6 +1,6 @@
 {
   "name": "gradido-database",
-  "version": "1.9.0",
+  "version": "1.11.0",
   "description": "Gradido Database Tool to execute database migrations",
   "main": "src/index.ts",
   "repository": "https://github.com/gradido/gradido/database",
diff --git a/deployment/bare_metal/.env.dist b/deployment/bare_metal/.env.dist
index a1751a859..1255104c9 100644
--- a/deployment/bare_metal/.env.dist
+++ b/deployment/bare_metal/.env.dist
@@ -22,12 +22,13 @@ COMMUNITY_NAME="Gradido Development Stage1"
 COMMUNITY_URL=https://stage1.gradido.net/
 COMMUNITY_REGISTER_URL=https://stage1.gradido.net/register
 COMMUNITY_REDEEM_URL=https://stage1.gradido.net/redeem/{code}
+COMMUNITY_REDEEM_CONTRIBUTION_URL=https://stage1.gradido.net/redeem/CL-{code}
 COMMUNITY_DESCRIPTION="Gradido Development Stage1 Test Community"
 
 # backend
-BACKEND_CONFIG_VERSION=v6.2022-04-21
+BACKEND_CONFIG_VERSION=v9.2022-07-07
 
-JWT_EXPIRES_IN=30m
+JWT_EXPIRES_IN=10m
 GDT_API_URL=https://gdt.gradido.net
 
 TYPEORM_LOGGING_RELATIVE_PATH=../deployment/bare_metal/log/typeorm.backend.log
@@ -52,6 +53,10 @@ EMAIL_CODE_REQUEST_TIME=10
 
 WEBHOOK_ELOPAGE_SECRET=secret
 
+# EventProtocol
+EVENT_PROTOCOL_DISABLED=false
+
+
 # database
 DATABASE_CONFIG_VERSION=v1.2022-03-18
 
diff --git a/docker-compose.apple-m1.override.yml b/docker-compose.apple-m1.override.yml
new file mode 100644
index 000000000..72152f9ae
--- /dev/null
+++ b/docker-compose.apple-m1.override.yml
@@ -0,0 +1,43 @@
+# This file defines the Apple M1 chip settings. It overrides docker-compose.override.yml,
+# which defines the development settings.
+# To use it it is required to explicitly define if you want to build with it:
+# > docker-compose -f docker-compose.yml -f docker-compose.override.yml -f docker-compose.apple-m1.override.yml up
+
+version: "3.4"
+
+services:
+  ########################################################
+  # FRONTEND #############################################
+  ########################################################
+  frontend:
+    platform: linux/amd64
+
+  ########################################################
+  # ADMIN INTERFACE ######################################
+  ########################################################
+  admin:
+    platform: linux/amd64
+
+  #########################################################
+  ## MARIADB ##############################################
+  #########################################################
+  mariadb:
+    platform: linux/amd64
+      
+  ########################################################
+  # BACKEND ##############################################
+  ########################################################
+  backend:
+    platform: linux/amd64
+
+  ########################################################
+  # DATABASE #############################################
+  ########################################################
+  database:
+    platform: linux/amd64
+    
+  #########################################################
+  ## NGINX ################################################
+  #########################################################
+  nginx:
+    platform: linux/amd64
diff --git a/docker-compose.override.yml b/docker-compose.override.yml
index 3d63da9e3..2af3c41ee 100644
--- a/docker-compose.override.yml
+++ b/docker-compose.override.yml
@@ -1,11 +1,13 @@
 version: "3.4"
 
 services:
+
   ########################################################
   # FRONTEND #############################################
   ########################################################
   frontend:
-    image: gradido/frontend:development
+    # name the image so that it cannot be found in a DockerHub repository, otherwise it will not be built locally from the 'dockerfile' but pulled from there
+    image: gradido/frontend:local-development
     build:
       target: development
     environment:
@@ -22,7 +24,8 @@ services:
   # ADMIN INTERFACE ######################################
   ########################################################
   admin:
-    image: gradido/admin:development
+    # name the image so that it cannot be found in a DockerHub repository, otherwise it will not be built locally from the 'dockerfile' but pulled from there
+    image: gradido/admin:local-development
     build:
       target: development
     environment:
@@ -39,7 +42,8 @@ services:
   # BACKEND ##############################################
   ########################################################
   backend:
-    image: gradido/backend:development
+    # name the image so that it cannot be found in a DockerHub repository, otherwise it will not be built locally from the 'dockerfile' but pulled from there
+    image: gradido/backend:local-development
     build:
       target: development
     networks:
@@ -62,10 +66,11 @@ services:
   ########################################################
   database:
     # we always run on production here since else the service lingers
-    # feel free to change this behaviour if it seems useful
-    # Due to problems with the volume caching the built files
-    # we changed this to test build. This keeps the service running.
-    image: gradido/database:test_up
+    #  feel free to change this behaviour if it seems useful
+    #  Due to problems with the volume caching the built files
+    #  we changed this to test build. This keeps the service running.
+    # name the image so that it cannot be found in a DockerHub repository, otherwise it will not be built locally from the 'dockerfile' but pulled from there
+    image: gradido/database:local-test_up
     build:
       target: test_up
     environment:
@@ -89,9 +94,7 @@ services:
   #########################################################
   ## NGINX ################################################
   #########################################################
-  nginx:
-    volumes: 
-      - ./logs/nginx:/var/log/nginx 
+  # nginx:
   
   #########################################################
   ## PHPMYADMIN ###########################################
diff --git a/docker-compose.test.yml b/docker-compose.test.yml
index 221ecba20..7db318176 100644
--- a/docker-compose.test.yml
+++ b/docker-compose.test.yml
@@ -6,6 +6,7 @@ services:
   # BACKEND ##############################################
   ########################################################
   backend:
+    # name the image so that it cannot be found in a DockerHub repository, otherwise it will not be built locally from the 'dockerfile' but pulled from there
     image: gradido/backend:test
     build:
       target: test
diff --git a/docker-compose.yml b/docker-compose.yml
index 213b200cd..5f0ab4dde 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -6,11 +6,13 @@
 version: "3.4"
 
 services:
+
   ########################################################
   # FRONTEND #############################################
   ########################################################
   frontend:
-    image: gradido/frontend:latest
+    # name the image so that it cannot be found in a DockerHub repository, otherwise it will not be built locally from the 'dockerfile' but pulled from there
+    image: gradido/frontend:local-production
     build:
       context: ./frontend
       target: production
@@ -35,7 +37,8 @@ services:
   # ADMIN INTERFACE ######################################
   ########################################################
   admin:
-    image: gradido/admin:latest
+    # name the image so that it cannot be found in a DockerHub repository, otherwise it will not be built locally from the 'dockerfile' but pulled from there
+    image: gradido/admin:local-production
     build:
       context: ./admin
       target: production
@@ -77,7 +80,8 @@ services:
   # BACKEND ##############################################
   ########################################################
   backend:
-    image: gradido/backend:latest
+    # name the image so that it cannot be found in a DockerHub repository, otherwise it will not be built locally from the 'dockerfile' but pulled from there
+    image: gradido/backend:local-production
     build:
       # since we have to include the entities from ./database we cannot define the context as ./backend
       # this might blow build image size to the moon ?!
@@ -103,12 +107,16 @@ services:
       # Application only envs
     #env_file:
     #  - ./frontend/.env
+    volumes:
+      # <host_machine_directy>:<container_directory> – mirror bidirectional path in local context with path in Docker container
+      - ./logs/backend:/logs/backend
 
   ########################################################
   # DATABASE #############################################
   ########################################################
   database:
-    #image: gradido/database:production_up
+    # name the image so that it cannot be found in a DockerHub repository, otherwise it will not be built locally from the 'dockerfile' but pulled from there
+    image: gradido/database:local-production_up
     build:
       context: ./database
       target: production_up
@@ -144,6 +152,8 @@ services:
       - admin 
     ports:
       - 80:80
+    volumes: 
+      - ./logs/nginx:/var/log/nginx 
   
 networks:
   external-net:
diff --git a/docu/Concepts/BusinessRequirements/UC_Send_Contribution.md b/docu/Concepts/BusinessRequirements/UC_Send_Contribution.md
new file mode 100644
index 000000000..ab04efc7f
--- /dev/null
+++ b/docu/Concepts/BusinessRequirements/UC_Send_Contribution.md
@@ -0,0 +1,173 @@
+# GDD-Creation per Link/QR-Code
+
+Die Idee besteht darin, dass ein Administrator eine Contribution mit all seinen Attributen und Regeln im System erfasst. Dabei kann er unter anderem festlegen, ob für diese ein Link oder ein QR-Code generiert und über andere Medien wie Email oder Messenger versendet werden kann. Der Empfänger kann diesen Link bzw QR-Code dann über die Gradido-Anwendung einlösen und bekommt dann den Betrag der Contribution als Schöpfung auf seinem Konto gutgeschrieben.
+
+## Logischer Ablauf
+
+Der logische Ablauf für das Szenario "Activity-Confirmation and booking of Creations " wird in der nachfolgenden Grafik dargestellt. Dabei wird links das Szenario der "interactive Confirmation and booking of Creations" und rechts "automatic Confirmation and booking of Creations" dargestellt. Ziel dieser Grafik ist neben der logischen Ablaufsübersicht auch die Gemeinsamkeiten und Unterschiede der beiden Szenarien herauszuarbeiten.
+
+![img](./image/Ablauf_manuelle_auto_Creations.png)
+
+Das Szenario der *interaktiven Aktivitäten-Bestätigung* ist derzeit noch in den zwei Systemen EloPage und Gradido enthalten - markiert als IST-Prozess - und wird zukünftig dann nur noch innerhalb Gradido ablaufen - markiert als SOLL-Prozess. Mit der Ablösung von EloPage und der vollständigen Migration nach Gradido erfolgt  gleichzeitig eine Migration der Datenbank-Tabelle "admin_pending-creations" nach "Contributions". Unterhalb der gestrichelten Linie sind die beiden Szenarien dann in der Ablauflogik vollständig gleich.
+
+## Dialoge
+
+Für die Erfassung, Suche und Anzeige der Contributions und deren Gliederung in Kategorien wird es dazu im Admin-Bereich zusätzliche Funktionen und Dialoge geben.
+
+### Übersicht - Dialog
+
+In der Admin-Übersicht wird es zusätzliche Navigations- bzw. Menüpunkte geben, über die der Admin die gewünschte Funktionalität und die zugehörigen Dialoge öffnen kann.
+
+![Admin Overview](./image/UC_Send_Contribution_Admin-Overview.png)
+
+### Contribution erfassen - Dialog
+
+Bei der Erfassung einer Contribution wird die Kategorie, ein Name, eine Beschreibung der Contribution und der Betrag eingegeben.
+
+Der Gültigkeitsstart wird als Default mit dem aktuellen Erfassungszeitpunkt vorbelegt, wobei das Gültigkeitsende leer bleibt und damit als endlos gültig definiert wird. Mit Eingabe eines Start- und/oder Endezeitpunktes kann aber ein konkreter Gültigkeitszeitraum erfasst werden.
+
+Wie häufig ein User für diese Contribution eine Schöpfung gutgeschrieben bekommen kann, wird über die Auswahl eines Zyklus - stündlich, 2-stündlich, 4-stündlich, etc. - und innerhalb dieses Zyklus eine Anzahl an Wiederholungen definiert. Voreinstellung sind 1x täglich.
+
+![Zyklus](./image/UC_Send_Contribution_Admin-new ContributionZyklus.png)
+
+Ob die Contribution über einen versendeten Link bzw. QR-Code geschöpft werden kann, wird mittels der Auswahl "Versenden möglich als" bestimmt.
+
+![send](./image/UC_Send_Contribution_Admin-new ContributionSend.png)
+
+Für die Schöpfung der Contribution können weitere Regeln definiert werden:
+
+* Gesamt - max. Anzahl Schöpfungen:   bestimmt die maximale Anzahl der möglichen Schöpfungen über alle User dieser Community. Sobald diese Anzahl an Schöpfungen erreicht ist, werden alle weiteren eingehenden Schöpfungsanfragen für diese Contribution -egal ob per Links, per QR-Code oder User-Online-Erfassung mit einer entsprechend aussagekräftigen Fehlermeldung abgelehnt.
+* pro User
+  * max schöpfbarer Betrag pro Monat:   mit diesem definierbaren Betrag kann vordefiniert werden, wieviel Gradido ein User innerhalb eines Abrechnungsmonats maximal durch diese Contribution schöpfen kann. Ist diese Summer erreicht werden weiter eingehende Schöpfungsanfragen - egal ob per Link, per QR-Code oder online - mit einer entsprechend aussagekräftigen Fehlermeldung abgelehnt.
+  * max. Kontostand vor Schöpfung:   mit diesem definierbaren Betrag kann festgelegt werden, dass bevor für diese Contribution eine Schöpfung für den user erfolgt, eine Prüfung auf den aktuellen Kontostand erfolgt. Sobald der Kontostand höher als der vorgegebene Betrag ist, wird die eingehende Schöpfungsanfrage, ob per Link, per QR-Code oder online, mit einer entsprechend aussagekräftigen Fehlermeldung abgelehnt.
+  * min. Abstand zw. erneuter Schöpfung:   es kann ein zeitlicher Abstand in Stunden definiert werden, der angibt wieviel Stunden seit der letzten erfolgten Schöpfung vergehen müssen, bevor eine erneute Schöpfungsanfrage, ob per Link, per QR-Code oder online angenommen und durchgeführt werden darf. Ist bei einer erneuten Schöpfungsanfrage der zeitliche Abstand noch nicht erreicht, dann wird mit einer entsprechend aussagekräftigen Fehlermeldung abgebrochen.
+
+![new](./image/UC_Send_Contribution_Admin-newContribution.png)
+
+### Ausbaustufe-1:
+
+Die Ausbaustufe-1 wird gezielt auf die Anforderungen der "Dokumenta" im Juni 2022 abgestimmt. 
+
+#### Contribution-Erfassungsdialog (Adminbereich)
+
+Es werden folgende Anforderungen an den Erfassungsdialog einer Contribution gestellt:
+
+| Attribut                | Beschreibung                                                                                                                                                                                                                                    |
+| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| Name                    | Name der Contribution als Bezeichnung, nach dem später auch eine Suche erfolgen kann                                                                                                                                                           |
+| Beschreibung            | Beschreibung der Contribution, die mit der Schöpfung als Memo in die Transaktion übernommen wird                                                                                                                                              |
+| Betrag                  | der Betrag, der mit Einlösen der Contribution geschöpft wird                                                                                                                                                                                  |
+| GültigVon              | - das Datum, ab wann die Contribution gültig und damit einlösbar ist<br />- es wird die Uhrzeit 00:00:00 angenommen                                                                                                                           |
+| GültigBis              | - das Datum, wie lange die Contribution gültig und damit einlösbar ist<br />- es wird die Uhrzeit 23:59:59 angenommen                                                                                                                         |
+| Zyklus                  | - Angabe wie häufig eine Contribution gutgeschrieben werden kann<br />- als Auswahlliste (Combobox) geplant, aber für diese Ausbaustufe nur mit dem Wert "kein Wiederholungszyklus" vorbelegt                                                 |
+| Wiederholungen          | - Anzahl an Wiederholungen pro Zyklus<br />- für diese Ausbaustufe wird der Wert "1" vorbelegt -> somit gilt 1 x pro User                                                                                                                      |
+| VersendenMöglich       | - hier wird "als Link / QR-Code" voreingestellt                                                                                                                                                                                                 |
+| alle weiteren Attribute | - entfallen für diese Ausbaustufe<br />- die GUI-Komponenten können optional schon im Dialog eingebaut und angezeigt werden<br />- diese GUI-Komponenten müssen wenn sichtbar disabled sein und dürfen damit keine Eingaben entgegen nehmen |
+
+
+#### Ablauflogik
+
+Für die Ausbaustufe-1 wird gemäß der Beschreibung aus dem Kapitel "Logischer Ablauf" nur die "automatic Confirmation and booking of Creations" umgesetzt. Die interaktive Variante - sprich Ablösung des EloPage Prozesses - mit "interactive Confirmation and booking of Creations" bleibt für eine spätere Ausbaustufe aussen vor.
+
+Das Regelwerk in der Businesslogik wird gemäß der reduzierten Contribution-Attribute aus dem Erfassungsdialog, den vordefinierten Initialwerten und der daraus resultierenden Variantenvielfalt vereinfacht.
+
+
+#### Kriterien "Dokumenta"
+
+* Es soll eine "Dokumenta"-Contribution im Admin-Bereich erfassbar sein und in der Datenbank als ContributionLink gespeichert werden.
+* Es wird für die Gesamtlaufzeit der "Dokumenta" genau ein Contribution benötigt
+* Die "Dokumenta"-Contribution kann von einem User maximal 1x aktiviert werden
+* Ein User kann mit diesem Link nur die Menge an GDDs schöpfen, die in der Contribution als "Betrag" festgelegt ist
+* Die "Dokumenta"-Contribution kann als Link / QR-Code erzeugt, angezeigt und in die Zwischenablage kopiert werden
+* Jeder beliebige User kann den Link / QR-Code aktivieren
+* der Link führt auf eine Gradido-Seite, wo der User sich anmelden oder registrieren kann
+* mit erfolgreichem Login bzw. Registrierung wird der automatische Bestätigungs- und Schöpfungsprozess getriggert
+* es erfolgt eine Überprüfung der definierten Contribution-Regeln für den angemeldeten User:
+  * Gültigkeit: liegt die Aktivierung im Gültigkeitszeitraum der Contribution
+  * Zyklus und WIederholungen: bei einem Zyklus-Wert = "kein Zyklus" und einem Wiederholungswert = 1 darf der User den Betrag dieser Contribution nur einmal insgesamt schöpfen
+  * max. schöpfbarer Gradido-Betrag pro Monat: wenn der Betrag der Contribution plus der Betrag, den der User in diesem Monat schon geschöpft hat den maximal schöpfbaren Betrag pro Monat von 1000 GDD übersteigt, dann wird die Schöpfung dieser Contribution abgelehnt
+* mit erfolgreich durchlaufenen Regelprüfungen wird ein "besätigter" aber "noch nicht gebuchten" Eintrag in der "Contributions"-Tabelle erzeugt
+* ein "bestätigter" aber "noch nicht gebuchter" "Contributions"-Eintrag stößt eine Schöpfungstransaktion für den User an
+* es erfolgt eine übliche Schöpfungstransaktion nach der Bestätigung der Contribution
+* die Schöpfungstransaktion schreibt den Betrag der Contribution dem Kontostand des Users gut
+
+
+## Datenbank-Modell
+
+### Ausgangsmodell
+
+Das nachfolgende Bild zeigt das Datenmodell vor der Einführung und Migration auf Contributions.
+
+![Datenbankmodell](./image/DB-Diagramm_20220518.png)
+
+### Datenbank-Änderungen
+
+Die Datenbank wird in ihrer vollständigen Ausprägung trotz Ausbaustufe-1 wie folgt beschrieben umgesetzt.
+
+#### neue Tabellen
+
+##### contribution_links - Tabelle
+
+| Name                            | Typ          | Nullable |    Default    | Kommentar                                                                                                                              |
+| ------------------------------- | ------------ | :------: | :------------: | -------------------------------------------------------------------------------------------------------------------------------------- |
+| id                              | INT UNSIGNED | NOT NULL | auto increment | PrimaryKey                                                                                                                             |
+| name                            | varchar(100) | NOT NULL |               | unique Name                                                                                                                            |
+| description                     | varchar(255) |         |               |                                                                                                                                        |
+| valid_from                      | DATETIME     | NOT NULL |      NOW      |                                                                                                                                        |
+| valid_to                        | DATETIME     |         |      NULL      |                                                                                                                                        |
+| amount                          | DECIMAL      | NOT NULL |               |                                                                                                                                        |
+| cycle                           | ENUM         | NOT NULL |      ONCE      | ONCE, HOUR, 2HOUR, 4HOUR, 8HOUR, HALFDAY, DAY, 2DAYS, 3DAYS, 4DAYS, 5DAYS, 6DAYS, WEEK, 2WEEKS, MONTH, 2MONTH, QUARTER, HALFYEAR, YEAR |
+| max_per_cycle                   | INT UNSIGNED | NOT NULL |       1       |                                                                                                                                        |
+| max_amount_per_month            | DECIMAL      |         |      NULL      |                                                                                                                                        |
+| total_max_count_of_contribution | INT UNSIGNED |         |      NULL      |                                                                                                                                        |
+| max_account_balance             | DECIMAL      |         |      NULL      |                                                                                                                                        |
+| min_gap_hours                   | INT UNSIGNED |         |      NULL      |                                                                                                                                        |
+| created_at                      | DATETIME     |         |      NOW      |                                                                                                                                        |
+| deleted_at                      | DATETIMEBOOL |         |      NULL      |                                                                                                                                        |
+| code                            | varchar(24)  |         |      NULL      |                                                                                                                                        |
+| link_enabled                    | BOOL         |         |      NULL      |                                                                                                                                        |
+
+##### contributions -Tabelle
+
+| Name                  | Typ          | Nullable | Default        | Kommentar                                                                        |
+| --------------------- | ------------ | -------- | -------------- | -------------------------------------------------------------------------------- |
+| id                    | INT UNSIGNED | NOT NULL | auto increment | PrimaryKey                                                                       |
+| name                  | varchar(100) | NOT NULL |                | short Naming of activity                                                         |
+| memo                  | varchar(255) | NOT NULL |                | full and detailed description of activities                                      |
+| amount                | DECIMAL      | NOT NULL |                | the amount of GDD for this activity                                              |
+| contribution_date     | DATETIME     |          | NULL           | the date/month, when the contribution was realized by the user                   |
+| user_id               | INT UNSIGNED | NOT NULL |                | the user, who wants to get GDD for his activity                                  |
+| created_at            | DATETIME     | NOT NULL | NOW            | the date, when this entry was captured and stored in database                    |
+| contribution_links_id | INT UNSIGNED |          | NULL           | contribution, on which this activity base on                                     |
+| moderator_id          | INT UNSIGNED |          | NULL           | userID of Moderator/Admin, who captured the contribution                         |
+| confirmed_by          | INT UNSIGNED |          | NULL           | userID of Moderator/Admin, who confirms the contribution                         |
+| confirmed_at          | DATETIME     |          | NULL           | date, when moderator has confirmed the contribution                              |
+| booked_at             | DATETIME     |          | NULL           | date, when the system has booked the amount of the activity on the users account |
+| deleted_at            | DATETIME     |          | NULL           | soft delete                                                                      |
+
+#### zu migrierende Tabellen
+
+##### Tabelle admin_pending_creations
+
+Diese Tabelle wird im Rahmen dieses UseCase migriert in die neue Tabelle contributions...
+
+| Quell-Spalte | Migration | Ziel-Spalte           | Beschreibung                                               |
+| ------------ | --------- | --------------------- | ---------------------------------------------------------- |
+| id           | keine     | id                    | auto inkrement des PK                                      |
+| user_id      | copy      | user_id               |                                                            |
+| created      | copy      | created_at            |                                                            |
+| date         | copy      | activity_date         |                                                            |
+| memo         | copy      | memo                  |                                                            |
+| amount       | copy      | amount                |                                                            |
+| moderator    | copy      | moderator_id          |                                                            |
+|              |           | name                  | neu mit ContributionsLinks                                 |
+|              |           | contribution_links_id | neu mit ContributionsLinks                                 |
+|              |           | confirmed_at          | neu mit Erfassung der Contributions von Elopage in Gradido |
+|              |           | confirmed_by          | neu mit Erfassung der Contributions von Elopage in Gradido |
+|              |           | booked_at             | neu mit Erfassung der Contributions von Elopage in Gradido |
+
+...und kann nach Übernahme der Daten in die neue Tabelle gelöscht werden oder es erfolgen die Änderungen sofort auf der Ursprungstabelle.
+
+### Zielmodell
+
+![Contributions-DB](./image/DB-Diagramm_Contributions.png)
diff --git a/docu/Concepts/BusinessRequirements/graphics/Ablauf_manuelle_auto_Creations.drawio b/docu/Concepts/BusinessRequirements/graphics/Ablauf_manuelle_auto_Creations.drawio
new file mode 100644
index 000000000..b4f1f45ea
--- /dev/null
+++ b/docu/Concepts/BusinessRequirements/graphics/Ablauf_manuelle_auto_Creations.drawio
@@ -0,0 +1,368 @@
+<mxfile host="65bd71144e">
+    <diagram id="-Bvenr9G4hMm7q4_ZwMA" name="Seite-1">
+        <mxGraphModel dx="3755" dy="1067" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="2336" pageHeight="1654" math="0" shadow="0">
+            <root>
+                <mxCell id="0"/>
+                <mxCell id="1" parent="0"/>
+                <mxCell id="6" value="EloPage" style="rounded=0;whiteSpace=wrap;html=1;fontSize=24;fillColor=#fff2cc;strokeColor=#d6b656;verticalAlign=top;align=center;" parent="1" vertex="1">
+                    <mxGeometry x="40" y="80" width="1080" height="120" as="geometry"/>
+                </mxCell>
+                <mxCell id="2" value="interactive Confirmation and booking of Creations" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=28;fontStyle=1" parent="1" vertex="1">
+                    <mxGeometry x="40" y="10" width="1080" height="30" as="geometry"/>
+                </mxCell>
+                <mxCell id="3" value="automatic Confirmation and booking of Creations" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=28;fontStyle=1" parent="1" vertex="1">
+                    <mxGeometry x="1200" y="10" width="1080" height="30" as="geometry"/>
+                </mxCell>
+                <mxCell id="4" value="" style="endArrow=none;html=1;" parent="1" edge="1">
+                    <mxGeometry width="50" height="50" relative="1" as="geometry">
+                        <mxPoint x="1160" y="1650" as="sourcePoint"/>
+                        <mxPoint x="1160" as="targetPoint"/>
+                    </mxGeometry>
+                </mxCell>
+                <mxCell id="45" value="" style="edgeStyle=none;html=1;fontSize=14;" parent="1" source="5" target="44" edge="1">
+                    <mxGeometry relative="1" as="geometry"/>
+                </mxCell>
+                <mxCell id="5" value="User erfasst Activity" style="rounded=1;whiteSpace=wrap;html=1;fontSize=20;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
+                    <mxGeometry x="80" y="140" width="240" height="40" as="geometry"/>
+                </mxCell>
+                <mxCell id="7" value="Gradido" style="rounded=0;whiteSpace=wrap;html=1;fontSize=24;fillColor=#d5e8d4;strokeColor=#82b366;verticalAlign=top;align=center;" parent="1" vertex="1">
+                    <mxGeometry x="40" y="210" width="1080" height="150" as="geometry"/>
+                </mxCell>
+                <mxCell id="21" style="edgeStyle=none;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;fontSize=24;" parent="1" source="8" target="9" edge="1">
+                    <mxGeometry relative="1" as="geometry"/>
+                </mxCell>
+                <mxCell id="8" value="Moderator überträgt&amp;nbsp; offene User-Activity aus EloPage" style="rounded=1;whiteSpace=wrap;html=1;fontSize=20;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
+                    <mxGeometry x="80" y="236" width="240" height="110" as="geometry"/>
+                </mxCell>
+                <mxCell id="9" value="admin_pending_creations" style="shape=process;whiteSpace=wrap;html=1;backgroundOutline=1;fontSize=24;size=0.05263157894736842;" parent="1" vertex="1">
+                    <mxGeometry x="400" y="261" width="380" height="60" as="geometry"/>
+                </mxCell>
+                <mxCell id="29" value="" style="edgeStyle=none;html=1;fontSize=24;" parent="1" source="10" target="9" edge="1">
+                    <mxGeometry relative="1" as="geometry"/>
+                </mxCell>
+                <mxCell id="10" value="users" style="shape=process;whiteSpace=wrap;html=1;backgroundOutline=1;fontSize=24;size=0.05263157894736842;" parent="1" vertex="1">
+                    <mxGeometry x="880" y="261" width="170" height="60" as="geometry"/>
+                </mxCell>
+                <mxCell id="12" value="" style="endArrow=none;dashed=1;html=1;fontSize=24;" parent="1" edge="1">
+                    <mxGeometry width="50" height="50" relative="1" as="geometry">
+                        <mxPoint y="440" as="sourcePoint"/>
+                        <mxPoint x="1160" y="440" as="targetPoint"/>
+                    </mxGeometry>
+                </mxCell>
+                <mxCell id="13" value="IST-Prozess" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=24;" parent="1" vertex="1">
+                    <mxGeometry y="400" width="210" height="30" as="geometry"/>
+                </mxCell>
+                <mxCell id="14" value="SOLL-Prozess" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=24;" parent="1" vertex="1">
+                    <mxGeometry y="450" width="210" height="30" as="geometry"/>
+                </mxCell>
+                <mxCell id="15" value="Gradido" style="rounded=0;whiteSpace=wrap;html=1;fontSize=24;fillColor=#d5e8d4;strokeColor=#82b366;verticalAlign=top;align=center;" parent="1" vertex="1">
+                    <mxGeometry x="40" y="520" width="1080" height="1080" as="geometry"/>
+                </mxCell>
+                <mxCell id="18" value="contributions" style="shape=process;whiteSpace=wrap;html=1;backgroundOutline=1;fontSize=24;size=0.05263157894736842;" parent="1" vertex="1">
+                    <mxGeometry x="400" y="690" width="380" height="60" as="geometry"/>
+                </mxCell>
+                <mxCell id="30" value="" style="edgeStyle=none;html=1;fontSize=24;" parent="1" source="19" target="18" edge="1">
+                    <mxGeometry relative="1" as="geometry"/>
+                </mxCell>
+                <mxCell id="19" value="users" style="shape=process;whiteSpace=wrap;html=1;backgroundOutline=1;fontSize=24;size=0.05263157894736842;" parent="1" vertex="1">
+                    <mxGeometry x="880" y="690" width="170" height="60" as="geometry"/>
+                </mxCell>
+                <mxCell id="22" value="" style="edgeStyle=none;html=1;fontSize=24;" parent="1" source="20" target="18" edge="1">
+                    <mxGeometry relative="1" as="geometry"/>
+                </mxCell>
+                <mxCell id="20" value="User erfasst seine Contribution" style="rounded=1;whiteSpace=wrap;html=1;fontSize=20;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
+                    <mxGeometry x="90" y="690" width="240" height="60" as="geometry"/>
+                </mxCell>
+                <mxCell id="36" value="" style="edgeStyle=none;html=1;fontSize=24;" parent="1" source="23" target="28" edge="1">
+                    <mxGeometry relative="1" as="geometry"/>
+                </mxCell>
+                <mxCell id="23" value="Moderator sucht unbestätigte &lt;br&gt;Contributions" style="rounded=1;whiteSpace=wrap;html=1;fontSize=20;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
+                    <mxGeometry x="90" y="790" width="240" height="110" as="geometry"/>
+                </mxCell>
+                <mxCell id="27" value="" style="edgeStyle=none;html=1;fontSize=24;" parent="1" source="25" target="23" edge="1">
+                    <mxGeometry relative="1" as="geometry"/>
+                </mxCell>
+                <mxCell id="25" value="contributions&lt;br style=&quot;font-size: 24px&quot;&gt;&lt;font style=&quot;font-size: 20px&quot;&gt;confirmed_at == NULL&lt;/font&gt;" style="shape=process;whiteSpace=wrap;html=1;backgroundOutline=1;fontSize=24;size=0.05263157894736842;" parent="1" vertex="1">
+                    <mxGeometry x="400" y="795" width="380" height="100" as="geometry"/>
+                </mxCell>
+                <mxCell id="32" value="" style="edgeStyle=none;html=1;fontSize=24;" parent="1" source="28" target="31" edge="1">
+                    <mxGeometry relative="1" as="geometry"/>
+                </mxCell>
+                <mxCell id="43" value="" style="edgeStyle=none;html=1;fontSize=14;" parent="1" source="28" target="34" edge="1">
+                    <mxGeometry relative="1" as="geometry"/>
+                </mxCell>
+                <mxCell id="28" value="Moderator bestätigt Contribution" style="rounded=1;whiteSpace=wrap;html=1;fontSize=20;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
+                    <mxGeometry x="90" y="920" width="240" height="110" as="geometry"/>
+                </mxCell>
+                <mxCell id="31" value="&lt;font style=&quot;font-size: 23px&quot;&gt;&lt;span style=&quot;font-size: 24px&quot;&gt;contributions&lt;/span&gt;&lt;br&gt;&lt;/font&gt;&lt;div style=&quot;text-align: left ; font-size: 20px&quot;&gt;&lt;font style=&quot;font-size: 20px&quot;&gt;confirmed_at = NOW&lt;/font&gt;&lt;/div&gt;&lt;span style=&quot;line-height: 0.8 ; font-size: 20px&quot;&gt;&lt;div style=&quot;text-align: left&quot;&gt;&lt;font style=&quot;font-size: 20px&quot;&gt;confirmed_by = Moderator's userID&lt;/font&gt;&lt;/div&gt;&lt;/span&gt;" style="shape=process;whiteSpace=wrap;html=1;backgroundOutline=1;fontSize=24;size=0.05263157894736842;" parent="1" vertex="1">
+                    <mxGeometry x="400" y="930" width="380" height="90" as="geometry"/>
+                </mxCell>
+                <mxCell id="49" value="" style="edgeStyle=none;html=1;startArrow=none;" parent="1" source="50" target="48" edge="1">
+                    <mxGeometry relative="1" as="geometry"/>
+                </mxCell>
+                <mxCell id="53" value="Ja" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];fontSize=16;" parent="49" vertex="1" connectable="0">
+                    <mxGeometry x="-0.3333" relative="1" as="geometry">
+                        <mxPoint as="offset"/>
+                    </mxGeometry>
+                </mxCell>
+                <mxCell id="51" value="" style="edgeStyle=none;html=1;" parent="1" source="34" target="50" edge="1">
+                    <mxGeometry relative="1" as="geometry"/>
+                </mxCell>
+                <mxCell id="34" value="&amp;nbsp;lese Transaktionen des Users zu bestätigter&lt;br&gt;Contribution" style="rounded=1;whiteSpace=wrap;html=1;fontSize=20;fillColor=#008a00;strokeColor=#005700;fontColor=#ffffff;" parent="1" vertex="1">
+                    <mxGeometry x="90" y="1090" width="240" height="100" as="geometry"/>
+                </mxCell>
+                <mxCell id="37" value="" style="edgeStyle=none;html=1;fontSize=12;exitX=0;exitY=0.5;exitDx=0;exitDy=0;" parent="1" source="35" target="34" edge="1">
+                    <mxGeometry relative="1" as="geometry"/>
+                </mxCell>
+                <mxCell id="35" value="contributions" style="shape=process;whiteSpace=wrap;html=1;backgroundOutline=1;fontSize=24;size=0.05263157894736842;" parent="1" vertex="1">
+                    <mxGeometry x="400" y="1080" width="380" height="60" as="geometry"/>
+                </mxCell>
+                <mxCell id="38" value="" style="edgeStyle=none;html=1;fontSize=24;" parent="1" source="39" edge="1">
+                    <mxGeometry relative="1" as="geometry">
+                        <mxPoint x="780" y="1110" as="targetPoint"/>
+                    </mxGeometry>
+                </mxCell>
+                <mxCell id="41" style="edgeStyle=none;html=1;entryX=1;entryY=0.5;entryDx=0;entryDy=0;fontSize=12;" parent="1" source="39" target="40" edge="1">
+                    <mxGeometry relative="1" as="geometry"/>
+                </mxCell>
+                <mxCell id="39" value="users" style="shape=process;whiteSpace=wrap;html=1;backgroundOutline=1;fontSize=24;size=0.05263157894736842;" parent="1" vertex="1">
+                    <mxGeometry x="880" y="1110" width="170" height="60" as="geometry"/>
+                </mxCell>
+                <mxCell id="42" style="edgeStyle=none;html=1;fontSize=12;" parent="1" source="40" target="34" edge="1">
+                    <mxGeometry relative="1" as="geometry"/>
+                </mxCell>
+                <mxCell id="40" value="transactions" style="shape=process;whiteSpace=wrap;html=1;backgroundOutline=1;fontSize=24;size=0.05263157894736842;" parent="1" vertex="1">
+                    <mxGeometry x="400" y="1150" width="380" height="60" as="geometry"/>
+                </mxCell>
+                <mxCell id="46" style="edgeStyle=none;html=1;entryX=0.75;entryY=0;entryDx=0;entryDy=0;fontSize=14;dashed=1;startArrow=classic;startFill=1;exitX=0;exitY=1;exitDx=0;exitDy=0;" parent="1" source="44" target="8" edge="1">
+                    <mxGeometry relative="1" as="geometry"/>
+                </mxCell>
+                <mxCell id="44" value="Aktivitäten-Liste als Chat" style="shape=process;whiteSpace=wrap;html=1;backgroundOutline=1;fontSize=24;size=0.05263157894736842;fillColor=#f5f5f5;strokeColor=#666666;gradientColor=#b3b3b3;" parent="1" vertex="1">
+                    <mxGeometry x="400" y="130" width="380" height="60" as="geometry"/>
+                </mxCell>
+                <mxCell id="47" value="" style="endArrow=none;dashed=1;html=1;fontSize=24;strokeWidth=3;" parent="1" edge="1">
+                    <mxGeometry width="50" height="50" relative="1" as="geometry">
+                        <mxPoint y="1040" as="sourcePoint"/>
+                        <mxPoint x="1160" y="1040" as="targetPoint"/>
+                    </mxGeometry>
+                </mxCell>
+                <mxCell id="57" style="edgeStyle=none;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;fontSize=16;" parent="1" source="48" target="55" edge="1">
+                    <mxGeometry relative="1" as="geometry"/>
+                </mxCell>
+                <mxCell id="60" value="" style="edgeStyle=none;html=1;fontSize=16;" parent="1" source="48" target="59" edge="1">
+                    <mxGeometry relative="1" as="geometry"/>
+                </mxCell>
+                <mxCell id="48" value="erzeuge Schöpfungstransaktion&lt;br&gt;aus Contribution" style="rounded=1;whiteSpace=wrap;html=1;fontSize=20;fillColor=#008a00;strokeColor=#005700;fontColor=#ffffff;" parent="1" vertex="1">
+                    <mxGeometry x="90" y="1330" width="240" height="80" as="geometry"/>
+                </mxCell>
+                <mxCell id="50" value="&lt;br&gt;Schöpfungsregeln&lt;br&gt;&amp;nbsp;erfüllt?" style="rhombus;whiteSpace=wrap;html=1;fontSize=16;fillColor=#008a00;strokeColor=#005700;fontColor=#ffffff;rounded=1;" parent="1" vertex="1">
+                    <mxGeometry x="110" y="1210" width="200" height="80" as="geometry"/>
+                </mxCell>
+                <mxCell id="52" value="" style="edgeStyle=none;html=1;endArrow=none;" parent="1" source="34" target="50" edge="1">
+                    <mxGeometry relative="1" as="geometry">
+                        <mxPoint x="210" y="1230" as="sourcePoint"/>
+                        <mxPoint x="210" y="1410" as="targetPoint"/>
+                    </mxGeometry>
+                </mxCell>
+                <mxCell id="55" value="transactions" style="shape=process;whiteSpace=wrap;html=1;backgroundOutline=1;fontSize=24;size=0.05263157894736842;" parent="1" vertex="1">
+                    <mxGeometry x="400" y="1340" width="380" height="60" as="geometry"/>
+                </mxCell>
+                <mxCell id="58" value="contributions&lt;br style=&quot;font-size: 24px&quot;&gt;&lt;span style=&quot;text-align: left&quot;&gt;&lt;font style=&quot;font-size: 20px&quot;&gt;booked_at = NOW&lt;/font&gt;&lt;/span&gt;" style="shape=process;whiteSpace=wrap;html=1;backgroundOutline=1;fontSize=24;size=0.05263157894736842;" parent="1" vertex="1">
+                    <mxGeometry x="400" y="1460" width="380" height="60" as="geometry"/>
+                </mxCell>
+                <mxCell id="61" value="" style="edgeStyle=none;html=1;fontSize=16;" parent="1" source="59" target="58" edge="1">
+                    <mxGeometry relative="1" as="geometry"/>
+                </mxCell>
+                <mxCell id="59" value="aktualisiere &lt;br&gt;&amp;nbsp;gebuchte Contribution" style="rounded=1;whiteSpace=wrap;html=1;fontSize=20;fillColor=#008a00;strokeColor=#005700;fontColor=#ffffff;" parent="1" vertex="1">
+                    <mxGeometry x="90" y="1450" width="240" height="80" as="geometry"/>
+                </mxCell>
+                <mxCell id="62" value="Gradido" style="rounded=0;whiteSpace=wrap;html=1;fontSize=24;fillColor=#d5e8d4;strokeColor=#82b366;verticalAlign=top;align=center;" parent="1" vertex="1">
+                    <mxGeometry x="1200" y="80" width="980" height="1520" as="geometry"/>
+                </mxCell>
+                <mxCell id="117" value="" style="edgeStyle=none;html=1;fontSize=16;" parent="1" source="63" target="67" edge="1">
+                    <mxGeometry relative="1" as="geometry"/>
+                </mxCell>
+                <mxCell id="63" value="contribution_links&lt;br style=&quot;font-size: 24px&quot;&gt;&lt;span style=&quot;font-size: 20px&quot;&gt;id = X&lt;br&gt;code = X-link&lt;br&gt;&lt;/span&gt;" style="shape=process;whiteSpace=wrap;html=1;backgroundOutline=1;fontSize=24;size=0.05263157894736842;" parent="1" vertex="1">
+                    <mxGeometry x="1560" y="670" width="380" height="100" as="geometry"/>
+                </mxCell>
+                <mxCell id="121" value="" style="edgeStyle=none;html=1;fontSize=16;" parent="1" source="65" target="71" edge="1">
+                    <mxGeometry relative="1" as="geometry"/>
+                </mxCell>
+                <mxCell id="65" value="users&lt;br style=&quot;font-size: 24px&quot;&gt;&lt;font style=&quot;font-size: 20px&quot;&gt;ID=Y&lt;/font&gt;" style="shape=process;whiteSpace=wrap;html=1;backgroundOutline=1;fontSize=24;size=0.05263157894736842;" parent="1" vertex="1">
+                    <mxGeometry x="1990" y="930" width="170" height="60" as="geometry"/>
+                </mxCell>
+                <mxCell id="128" value="" style="edgeStyle=none;html=1;fontSize=20;strokeWidth=1;" parent="1" source="67" target="127" edge="1">
+                    <mxGeometry relative="1" as="geometry"/>
+                </mxCell>
+                <mxCell id="67" value="lese Contribution zu aktiviertem Link" style="rounded=1;whiteSpace=wrap;html=1;fontSize=20;fillColor=#008a00;strokeColor=#005700;fontColor=#ffffff;" parent="1" vertex="1">
+                    <mxGeometry x="1250" y="690" width="240" height="60" as="geometry"/>
+                </mxCell>
+                <mxCell id="120" value="" style="edgeStyle=none;html=1;fontSize=16;" parent="1" source="69" target="71" edge="1">
+                    <mxGeometry relative="1" as="geometry"/>
+                </mxCell>
+                <mxCell id="122" value="" style="edgeStyle=none;html=1;fontSize=16;" parent="1" source="69" target="79" edge="1">
+                    <mxGeometry relative="1" as="geometry"/>
+                </mxCell>
+                <mxCell id="69" value="erzeuge aus ContributionLink zu angemeldetem User eine bestätigte Contribution" style="rounded=1;whiteSpace=wrap;html=1;fontSize=20;fillColor=#008a00;strokeColor=#005700;fontColor=#ffffff;" parent="1" vertex="1">
+                    <mxGeometry x="1250" y="907.5" width="240" height="110" as="geometry"/>
+                </mxCell>
+                <mxCell id="71" value="contributions&lt;br style=&quot;font-size: 24px&quot;&gt;&lt;font style=&quot;font-size: 20px&quot;&gt;confirmed_at = NOW, contribution_links_id=X, user_id=Y&lt;/font&gt;" style="shape=process;whiteSpace=wrap;html=1;backgroundOutline=1;fontSize=24;size=0.05263157894736842;" parent="1" vertex="1">
+                    <mxGeometry x="1560" y="917.5" width="380" height="90" as="geometry"/>
+                </mxCell>
+                <mxCell id="72" value="" style="edgeStyle=none;html=1;fontSize=24;" parent="1" edge="1">
+                    <mxGeometry relative="1" as="geometry">
+                        <mxPoint x="1490" y="855" as="sourcePoint"/>
+                    </mxGeometry>
+                </mxCell>
+                <mxCell id="76" value="" style="edgeStyle=none;html=1;startArrow=none;" parent="1" source="91" target="90" edge="1">
+                    <mxGeometry relative="1" as="geometry"/>
+                </mxCell>
+                <mxCell id="77" value="Ja" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];fontSize=16;" parent="76" vertex="1" connectable="0">
+                    <mxGeometry x="-0.3333" relative="1" as="geometry">
+                        <mxPoint as="offset"/>
+                    </mxGeometry>
+                </mxCell>
+                <mxCell id="78" value="" style="edgeStyle=none;html=1;" parent="1" source="79" target="91" edge="1">
+                    <mxGeometry relative="1" as="geometry"/>
+                </mxCell>
+                <mxCell id="79" value="&amp;nbsp;lese Transaktionen des Users zu bestätigter&lt;br&gt;Contribution" style="rounded=1;whiteSpace=wrap;html=1;fontSize=20;fillColor=#008a00;strokeColor=#005700;fontColor=#ffffff;" parent="1" vertex="1">
+                    <mxGeometry x="1250" y="1090" width="240" height="100" as="geometry"/>
+                </mxCell>
+                <mxCell id="80" value="" style="edgeStyle=none;html=1;fontSize=12;exitX=0;exitY=0.5;exitDx=0;exitDy=0;" parent="1" source="81" target="79" edge="1">
+                    <mxGeometry relative="1" as="geometry"/>
+                </mxCell>
+                <mxCell id="81" value="contributions" style="shape=process;whiteSpace=wrap;html=1;backgroundOutline=1;fontSize=24;size=0.05263157894736842;" parent="1" vertex="1">
+                    <mxGeometry x="1560" y="1080" width="380" height="60" as="geometry"/>
+                </mxCell>
+                <mxCell id="82" value="" style="edgeStyle=none;html=1;fontSize=24;" parent="1" source="84" edge="1">
+                    <mxGeometry relative="1" as="geometry">
+                        <mxPoint x="1940" y="1110" as="targetPoint"/>
+                    </mxGeometry>
+                </mxCell>
+                <mxCell id="83" style="edgeStyle=none;html=1;entryX=1;entryY=0.5;entryDx=0;entryDy=0;fontSize=12;" parent="1" source="84" target="86" edge="1">
+                    <mxGeometry relative="1" as="geometry"/>
+                </mxCell>
+                <mxCell id="84" value="users" style="shape=process;whiteSpace=wrap;html=1;backgroundOutline=1;fontSize=24;size=0.05263157894736842;" parent="1" vertex="1">
+                    <mxGeometry x="1990" y="1110" width="170" height="60" as="geometry"/>
+                </mxCell>
+                <mxCell id="85" style="edgeStyle=none;html=1;fontSize=12;" parent="1" source="86" target="79" edge="1">
+                    <mxGeometry relative="1" as="geometry"/>
+                </mxCell>
+                <mxCell id="86" value="transactions" style="shape=process;whiteSpace=wrap;html=1;backgroundOutline=1;fontSize=24;size=0.05263157894736842;" parent="1" vertex="1">
+                    <mxGeometry x="1560" y="1150" width="380" height="60" as="geometry"/>
+                </mxCell>
+                <mxCell id="87" value="" style="endArrow=none;dashed=1;html=1;fontSize=24;strokeWidth=3;" parent="1" edge="1">
+                    <mxGeometry width="50" height="50" relative="1" as="geometry">
+                        <mxPoint x="1160" y="1040" as="sourcePoint"/>
+                        <mxPoint x="2320" y="1040" as="targetPoint"/>
+                    </mxGeometry>
+                </mxCell>
+                <mxCell id="88" style="edgeStyle=none;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;fontSize=16;" parent="1" source="90" target="93" edge="1">
+                    <mxGeometry relative="1" as="geometry"/>
+                </mxCell>
+                <mxCell id="89" value="" style="edgeStyle=none;html=1;fontSize=16;" parent="1" source="90" target="96" edge="1">
+                    <mxGeometry relative="1" as="geometry"/>
+                </mxCell>
+                <mxCell id="90" value="erzeuge Schöpfungstransaktion&lt;br&gt;aus Contribution" style="rounded=1;whiteSpace=wrap;html=1;fontSize=20;fillColor=#008a00;strokeColor=#005700;fontColor=#ffffff;" parent="1" vertex="1">
+                    <mxGeometry x="1250" y="1330" width="240" height="80" as="geometry"/>
+                </mxCell>
+                <mxCell id="91" value="&lt;br&gt;Schöpfungsregeln&lt;br&gt;&amp;nbsp;erfüllt?" style="rhombus;whiteSpace=wrap;html=1;fontSize=16;fillColor=#008a00;strokeColor=#005700;fontColor=#ffffff;rounded=1;" parent="1" vertex="1">
+                    <mxGeometry x="1270" y="1210" width="200" height="80" as="geometry"/>
+                </mxCell>
+                <mxCell id="92" value="" style="edgeStyle=none;html=1;endArrow=none;" parent="1" source="79" target="91" edge="1">
+                    <mxGeometry relative="1" as="geometry">
+                        <mxPoint x="1370" y="1230" as="sourcePoint"/>
+                        <mxPoint x="1370" y="1410" as="targetPoint"/>
+                    </mxGeometry>
+                </mxCell>
+                <mxCell id="93" value="transactions" style="shape=process;whiteSpace=wrap;html=1;backgroundOutline=1;fontSize=24;size=0.05263157894736842;" parent="1" vertex="1">
+                    <mxGeometry x="1560" y="1340" width="380" height="60" as="geometry"/>
+                </mxCell>
+                <mxCell id="94" value="contributions&lt;br style=&quot;font-size: 24px&quot;&gt;&lt;span style=&quot;text-align: left&quot;&gt;&lt;font style=&quot;font-size: 20px&quot;&gt;booked_at = NOW&lt;/font&gt;&lt;/span&gt;" style="shape=process;whiteSpace=wrap;html=1;backgroundOutline=1;fontSize=24;size=0.05263157894736842;" parent="1" vertex="1">
+                    <mxGeometry x="1560" y="1460" width="380" height="60" as="geometry"/>
+                </mxCell>
+                <mxCell id="95" value="" style="edgeStyle=none;html=1;fontSize=16;" parent="1" source="96" target="94" edge="1">
+                    <mxGeometry relative="1" as="geometry"/>
+                </mxCell>
+                <mxCell id="96" value="aktualisiere &lt;br&gt;gebuchte Contribution" style="rounded=1;whiteSpace=wrap;html=1;fontSize=20;fillColor=#008a00;strokeColor=#005700;fontColor=#ffffff;" parent="1" vertex="1">
+                    <mxGeometry x="1250" y="1450" width="240" height="80" as="geometry"/>
+                </mxCell>
+                <mxCell id="99" value="" style="edgeStyle=none;html=1;fontSize=16;" parent="1" source="97" target="98" edge="1">
+                    <mxGeometry relative="1" as="geometry"/>
+                </mxCell>
+                <mxCell id="97" value="Moderator erfasst Contribution für &lt;br&gt;&quot;automatic Confirmation&quot;" style="rounded=1;whiteSpace=wrap;html=1;fontSize=20;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
+                    <mxGeometry x="1250" y="117.5" width="240" height="80" as="geometry"/>
+                </mxCell>
+                <mxCell id="98" value="contribution_links" style="shape=process;whiteSpace=wrap;html=1;backgroundOutline=1;fontSize=24;size=0.05263157894736842;" parent="1" vertex="1">
+                    <mxGeometry x="1560" y="127.5" width="380" height="60" as="geometry"/>
+                </mxCell>
+                <mxCell id="101" value="Moderator erzeugt Link/QR-Code aus Contribution" style="rounded=1;whiteSpace=wrap;html=1;fontSize=20;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
+                    <mxGeometry x="1250" y="213.5" width="240" height="80" as="geometry"/>
+                </mxCell>
+                <mxCell id="103" value="" style="edgeStyle=none;html=1;fontSize=16;" parent="1" source="102" target="101" edge="1">
+                    <mxGeometry relative="1" as="geometry"/>
+                </mxCell>
+                <mxCell id="102" value="contribution_links" style="shape=process;whiteSpace=wrap;html=1;backgroundOutline=1;fontSize=24;size=0.05263157894736842;" parent="1" vertex="1">
+                    <mxGeometry x="1560" y="223.5" width="380" height="60" as="geometry"/>
+                </mxCell>
+                <mxCell id="110" value="" style="edgeStyle=none;html=1;fontSize=16;" parent="1" source="104" target="109" edge="1">
+                    <mxGeometry relative="1" as="geometry"/>
+                </mxCell>
+                <mxCell id="104" value="Moderator &lt;br&gt;verbreitet / versendet&lt;br&gt;&amp;nbsp;erzeugten Link/QR-Code" style="rounded=1;whiteSpace=wrap;html=1;fontSize=20;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
+                    <mxGeometry x="1250" y="312.5" width="240" height="80" as="geometry"/>
+                </mxCell>
+                <mxCell id="112" style="edgeStyle=none;html=1;entryX=1;entryY=0.5;entryDx=0;entryDy=0;fontSize=16;" parent="1" source="109" target="111" edge="1">
+                    <mxGeometry relative="1" as="geometry">
+                        <mxPoint x="1912.7716129809019" y="520.971840668889" as="sourcePoint"/>
+                    </mxGeometry>
+                </mxCell>
+                <mxCell id="109" value="veröffentlichter &lt;br&gt;Link / QR-Code für&lt;br&gt;eine Contribution" style="ellipse;whiteSpace=wrap;html=1;fontSize=20;rounded=1;fillColor=#d0cee2;strokeColor=#56517e;" parent="1" vertex="1">
+                    <mxGeometry x="2010" y="410" width="310" height="90" as="geometry"/>
+                </mxCell>
+                <mxCell id="118" value="" style="edgeStyle=none;html=1;fontSize=16;" parent="1" target="113" edge="1">
+                    <mxGeometry relative="1" as="geometry">
+                        <mxPoint x="1370" y="570" as="sourcePoint"/>
+                    </mxGeometry>
+                </mxCell>
+                <mxCell id="111" value="User aktiviert &lt;br&gt;Link / QR-Code" style="rounded=1;whiteSpace=wrap;html=1;fontSize=20;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
+                    <mxGeometry x="1250" y="510" width="240" height="50" as="geometry"/>
+                </mxCell>
+                <mxCell id="115" style="edgeStyle=none;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;fontSize=16;" parent="1" source="113" target="114" edge="1">
+                    <mxGeometry relative="1" as="geometry"/>
+                </mxCell>
+                <mxCell id="116" style="edgeStyle=none;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=16;" parent="1" source="113" target="67" edge="1">
+                    <mxGeometry relative="1" as="geometry"/>
+                </mxCell>
+                <mxCell id="113" value="User führt &lt;br&gt;Login / Register aus" style="rounded=1;whiteSpace=wrap;html=1;fontSize=20;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
+                    <mxGeometry x="1250" y="597.5" width="240" height="50" as="geometry"/>
+                </mxCell>
+                <mxCell id="114" value="users" style="shape=process;whiteSpace=wrap;html=1;backgroundOutline=1;fontSize=24;size=0.05263157894736842;" parent="1" vertex="1">
+                    <mxGeometry x="1990" y="592.5" width="170" height="60" as="geometry"/>
+                </mxCell>
+                <mxCell id="123" style="edgeStyle=none;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;fontSize=16;" parent="1" source="124" target="125" edge="1">
+                    <mxGeometry relative="1" as="geometry"/>
+                </mxCell>
+                <mxCell id="126" value="" style="edgeStyle=none;html=1;fontSize=20;strokeWidth=1;" parent="1" source="124" target="20" edge="1">
+                    <mxGeometry relative="1" as="geometry"/>
+                </mxCell>
+                <mxCell id="124" value="User führt &lt;br&gt;Login / Register aus" style="rounded=1;whiteSpace=wrap;html=1;fontSize=20;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
+                    <mxGeometry x="90" y="597.5" width="240" height="50" as="geometry"/>
+                </mxCell>
+                <mxCell id="125" value="users" style="shape=process;whiteSpace=wrap;html=1;backgroundOutline=1;fontSize=24;size=0.05263157894736842;" parent="1" vertex="1">
+                    <mxGeometry x="880" y="592.5" width="170" height="60" as="geometry"/>
+                </mxCell>
+                <mxCell id="129" value="" style="edgeStyle=none;html=1;fontSize=20;strokeWidth=1;" parent="1" source="127" target="69" edge="1">
+                    <mxGeometry relative="1" as="geometry"/>
+                </mxCell>
+                <mxCell id="130" value="Ja" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];fontSize=20;" parent="129" vertex="1" connectable="0">
+                    <mxGeometry x="-0.3467" relative="1" as="geometry">
+                        <mxPoint as="offset"/>
+                    </mxGeometry>
+                </mxCell>
+                <mxCell id="127" value="Contribution &lt;br&gt;und Regel &lt;br&gt;valide?" style="rhombus;whiteSpace=wrap;html=1;fontSize=20;fillColor=#008a00;strokeColor=#005700;fontColor=#ffffff;rounded=1;" parent="1" vertex="1">
+                    <mxGeometry x="1250" y="770" width="240" height="100" as="geometry"/>
+                </mxCell>
+            </root>
+        </mxGraphModel>
+    </diagram>
+</mxfile>
\ No newline at end of file
diff --git a/docu/Concepts/BusinessRequirements/graphics/GradidoÜbersichtMaske.bmpr b/docu/Concepts/BusinessRequirements/graphics/GradidoÜbersichtMaske.bmpr
index d392ef12b..7921d16ce 100644
Binary files a/docu/Concepts/BusinessRequirements/graphics/GradidoÜbersichtMaske.bmpr and b/docu/Concepts/BusinessRequirements/graphics/GradidoÜbersichtMaske.bmpr differ
diff --git a/docu/Concepts/BusinessRequirements/image/Ablauf_manuelle_auto_Creations.png b/docu/Concepts/BusinessRequirements/image/Ablauf_manuelle_auto_Creations.png
new file mode 100644
index 000000000..00fe89d3e
Binary files /dev/null and b/docu/Concepts/BusinessRequirements/image/Ablauf_manuelle_auto_Creations.png differ
diff --git a/docu/Concepts/BusinessRequirements/image/DB-Diagramm_20220518.png b/docu/Concepts/BusinessRequirements/image/DB-Diagramm_20220518.png
new file mode 100644
index 000000000..84a900eaa
Binary files /dev/null and b/docu/Concepts/BusinessRequirements/image/DB-Diagramm_20220518.png differ
diff --git a/docu/Concepts/BusinessRequirements/image/DB-Diagramm_Contributions.png b/docu/Concepts/BusinessRequirements/image/DB-Diagramm_Contributions.png
new file mode 100644
index 000000000..97268e6a7
Binary files /dev/null and b/docu/Concepts/BusinessRequirements/image/DB-Diagramm_Contributions.png differ
diff --git a/docu/Concepts/BusinessRequirements/image/UC_Send_Contribution_Admin-Overview.png b/docu/Concepts/BusinessRequirements/image/UC_Send_Contribution_Admin-Overview.png
new file mode 100644
index 000000000..2ca517450
Binary files /dev/null and b/docu/Concepts/BusinessRequirements/image/UC_Send_Contribution_Admin-Overview.png differ
diff --git a/docu/Concepts/BusinessRequirements/image/UC_Send_Contribution_Admin-new ContributionSend.png b/docu/Concepts/BusinessRequirements/image/UC_Send_Contribution_Admin-new ContributionSend.png
new file mode 100644
index 000000000..2be22bc40
Binary files /dev/null and b/docu/Concepts/BusinessRequirements/image/UC_Send_Contribution_Admin-new ContributionSend.png differ
diff --git a/docu/Concepts/BusinessRequirements/image/UC_Send_Contribution_Admin-new ContributionZyklus.png b/docu/Concepts/BusinessRequirements/image/UC_Send_Contribution_Admin-new ContributionZyklus.png
new file mode 100644
index 000000000..5b2ea8395
Binary files /dev/null and b/docu/Concepts/BusinessRequirements/image/UC_Send_Contribution_Admin-new ContributionZyklus.png differ
diff --git a/docu/Concepts/BusinessRequirements/image/UC_Send_Contribution_Admin-newContribution.png b/docu/Concepts/BusinessRequirements/image/UC_Send_Contribution_Admin-newContribution.png
new file mode 100644
index 000000000..0dd13f81b
Binary files /dev/null and b/docu/Concepts/BusinessRequirements/image/UC_Send_Contribution_Admin-newContribution.png differ
diff --git a/docu/Concepts/TechnicalRequirements/BusinessEventProtocol.md b/docu/Concepts/TechnicalRequirements/BusinessEventProtocol.md
index 5a436d057..f8cf2cd03 100644
--- a/docu/Concepts/TechnicalRequirements/BusinessEventProtocol.md
+++ b/docu/Concepts/TechnicalRequirements/BusinessEventProtocol.md
@@ -6,29 +6,30 @@ With the business event protocol the gradido application will capture and persis
 
 The different event types will be defined as Enum. The following list is a first draft and will grow with further event types in the future.
 
-| EventType                   | Value | Description                                                                                          |
-| --------------------------- | ----- | ---------------------------------------------------------------------------------------------------- |
-| BasicEvent                  | 0     | the basic event is the root of all further extending event types                                     |
-| VisitGradidoEvent           | 10    | if a user visits a gradido page without login or register                                            |
-| RegisterEvent               | 20    | the user presses the register button                                                                 |
-| RedeemRegisterEvent         | 21    | the user presses the register button initiated by the redeem link                                    |
-| InActiveAccountEvent        | 22    | the systems create an inactive account during the register process                                   |
-| SendConfirmEmailEvent       | 23    | the system send a confirmation email to the user during the register process                         |
-| ConfirmEmailEvent           | 24    | the user confirms his email during the register process                                              |
-| RegisterEmailKlickTippEvent | 25    | the system registers the confirmed email at klicktipp                                                |
-| LoginEvent                  | 30    | the user presses the login button                                                                    |
-| RedeemLoginEvent            | 31    | the user presses the login button initiated by the redeem link                                       |
-| ActivateAccountEvent        | 32    | the system activates the users account during the first login process                                |
-| PasswordChangeEvent         | 33    | the user changes his password                                                                        |
-| TxSendEvent                 | 40    | the user creates a transaction and sends it online                                                   |
-| TxSendRedeemEvent           | 41    | the user creates a transaction and sends it per redeem link                                          |
-| TxRepeateRedeemEvent        | 42    | the user recreates a redeem link of a still open transaction                                         |
-| TxCreationEvent             | 50    | the user receives a creation transaction for his confirmed contribution                              |
-| TxReceiveEvent              | 51    | the user receives a transaction from an other user and posts the amount on his account               |
-| TxReceiveRedeemEvent        | 52    | the user activates the redeem link and receives the transaction and posts the amount on his account  |
-| ContribCreateEvent          | 60    | the user enters his contribution and asks for confirmation                                           |
-| ContribConfirmEvent         | 61    | the user confirms a contribution of an other user (for future multi confirmation from several users) |
-|                             |       |                                                                                                      |
+| EventType                           | Value | Description                                                                                            |
+| ----------------------------------- | ----- | ------------------------------------------------------------------------------------------------------ |
+| BasicEvent                          | 0     | the basic event is the root of all further extending event types                                       |
+| VisitGradidoEvent                   | 10    | if a user visits a gradido page without login or register                                              |
+| RegisterEvent                       | 20    | the user presses the register button                                                                   |
+| RedeemRegisterEvent                 | 21    | the user presses the register button initiated by the redeem link                                      |
+| InActiveAccountEvent                | 22    | the systems create an inactive account during the register process                                     |
+| SendConfirmEmailEvent               | 23    | the system send a confirmation email to the user during the register process                           |
+| ConfirmEmailEvent                   | 24    | the user confirms his email during the register process                                                |
+| RegisterEmailKlickTippEvent         | 25    | the system registers the confirmed email at klicktipp                                                  |
+| LoginEvent                          | 30    | the user presses the login button                                                                      |
+| RedeemLoginEvent                    | 31    | the user presses the login button initiated by the redeem link                                         |
+| ActivateAccountEvent                | 32    | the system activates the users account during the first login process                                  |
+| PasswordChangeEvent                 | 33    | the user changes his password                                                                          |
+| TransactionSendEvent                | 40    | the user creates a transaction and sends it online                                                     |
+| TransactionSendRedeemEvent          | 41    | the user creates a transaction and sends it per redeem link                                            |
+| TransactionRepeateRedeemEvent       | 42    | the user recreates a redeem link of a still open transaction                                           |
+| TransactionCreationEvent            | 50    | the user receives a creation transaction for his confirmed contribution                                |
+| TransactionReceiveEvent             | 51    | the user receives a transaction from an other user and posts the amount on his account                 |
+| TransactionReceiveRedeemEvent       | 52    | the user activates the redeem link and receives the transaction and posts the amount on his account    |
+| ContributionCreateEvent             | 60    | the user enters his contribution and asks for confirmation                                             |
+| ContributionConfirmEvent            | 61    | the user confirms a contribution of an other user (for future multi confirmation from several users)   |
+| ContributionLinkDefineEvent         | 70    | the admin user defines a contributionLink, which could be send per Link/QR-Code on an other medium     |
+| ContributionLinkActivateRedeemEvent | 71    | the user activates a received contributionLink to create a contribution entry for the contributionLink |
 
 ## EventProtocol - Entity
 
@@ -50,29 +51,30 @@ The business events will be stored in database in the new table `EventProtocol`.
 
 The following table lists for each event type the mandatory attributes, which have to be initialized at event occurence and to be written in the database event protocol table:
 
-| EventType                   | id | type | createdAt | userID | XuserID | XCommunityID | transactionID | contribID | amount |
-| :-------------------------- | :-: | :--: | :-------: | :----: | :-----: | :----------: | :-----------: | :-------: | :----: |
-| BasicEvent                  | x |  x  |     x     |       |         |             |               |           |       |
-| VisitGradidoEvent           | x |  x  |     x     |       |         |             |               |           |       |
-| RegisterEvent               | x |  x  |     x     |   x   |         |             |               |           |       |
-| RedeemRegisterEvent         | x |  x  |     x     |   x   |         |             |               |           |       |
-| InActiveAccountEvent        | x |  x  |     x     |   x   |         |             |               |           |       |
-| SendConfirmEmailEvent       | x |  x  |     x     |   x   |         |             |               |           |       |
-| ConfirmEmailEvent           | x |  x  |     x     |   x   |         |             |               |           |       |
-| RegisterEmailKlickTippEvent | x |  x  |     x     |   x   |         |             |               |           |       |
-| LoginEvent                  | x |  x  |     x     |   x   |         |             |               |           |       |
-| RedeemLoginEvent            | x |  x  |     x     |   x   |         |             |               |           |       |
-| ActivateAccountEvent        | x |  x  |     x     |   x   |         |             |               |           |       |
-| PasswordChangeEvent         | x |  x  |     x     |   x   |         |             |               |           |       |
-| TxSendEvent                 | x |  x  |     x     |   x   |    x    |      x      |       x       |           |   x   |
-| TxSendRedeemEvent           | x |  x  |     x     |   x   |    x    |      x      |       x       |           |   x   |
-| TxRepeateRedeemEvent        | x |  x  |     x     |   x   |    x    |      x      |       x       |           |   x   |
-| TxCreationEvent             | x |  x  |     x     |   x   |         |             |       x       |           |   x   |
-| TxReceiveEvent              | x |  x  |     x     |   x   |    x    |      x      |       x       |           |   x   |
-| TxReceiveRedeemEvent        | x |  x  |     x     |   x   |    x    |      x      |       x       |           |   x   |
-| ContribCreateEvent          | x |  x  |     x     |   x   |         |             |               |     x     |       |
-| ContribConfirmEvent         | x |  x  |     x     |   x   |    x    |      x      |               |     x     |       |
-|                             |   |     |           |       |         |             |               |           |       |
+| EventType                           | id | type | createdAt | userID | XuserID | XCommunityID | transactionID | contribID | amount |
+| :---------------------------------- | :-: | :--: | :-------: | :----: | :-----: | :----------: | :-----------: | :-------: | :----: |
+| BasicEvent                          | x |  x  |     x     |        |        |              |              |          |        |
+| VisitGradidoEvent                   | x |  x  |     x     |        |        |              |              |          |        |
+| RegisterEvent                       | x |  x  |     x     |   x   |        |              |              |          |        |
+| RedeemRegisterEvent                 | x |  x  |     x     |   x   |        |              |      (x)      |    (x)    |        |
+| InActiveAccountEvent                | x |  x  |     x     |   x   |        |              |              |          |        |
+| SendConfirmEmailEvent               | x |  x  |     x     |   x   |        |              |              |          |        |
+| ConfirmEmailEvent                   | x |  x  |     x     |   x   |        |              |              |          |        |
+| RegisterEmailKlickTippEvent         | x |  x  |     x     |   x   |        |              |              |          |        |
+| LoginEvent                          | x |  x  |     x     |   x   |        |              |              |          |        |
+| RedeemLoginEvent                    | x |  x  |     x     |   x   |        |              |      (x)      |    (x)    |        |
+| ActivateAccountEvent                | x |  x  |     x     |   x   |        |              |              |          |        |
+| PasswordChangeEvent                 | x |  x  |     x     |   x   |        |              |              |          |        |
+| TransactionSendEvent                | x |  x  |     x     |   x   |    x    |      x      |       x       |          |   x   |
+| TransactionSendRedeemEvent          | x |  x  |     x     |   x   |    x    |      x      |       x       |          |   x   |
+| TransactionRepeateRedeemEvent       | x |  x  |     x     |   x   |    x    |      x      |       x       |          |   x   |
+| TransactionCreationEvent            | x |  x  |     x     |   x   |        |              |       x       |          |   x   |
+| TransactionReceiveEvent             | x |  x  |     x     |   x   |    x    |      x      |       x       |          |   x   |
+| TransactionReceiveRedeemEvent       | x |  x  |     x     |   x   |    x    |      x      |       x       |          |   x   |
+| ContributionCreateEvent             | x |  x  |     x     |   x   |        |              |              |     x     |   x   |
+| ContributionConfirmEvent            | x |  x  |     x     |   x   |    x    |      x      |              |     x     |   x   |
+| ContributionLinkDefineEvent         | x |  x  |     x     |   x   |        |              |              |          |   x   |
+| ContributionLinkActivateRedeemEvent | x |  x  |     x     |   x   |        |              |              |     x     |   x   |
 
 ## Event creation
 
diff --git a/frontend/package.json b/frontend/package.json
index e59ec8140..71baf4764 100755
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -1,6 +1,6 @@
 {
   "name": "bootstrap-vue-gradido-wallet",
-  "version": "1.9.0",
+  "version": "1.11.0",
   "private": true,
   "scripts": {
     "start": "node run/server.js",
@@ -45,6 +45,7 @@
     "jest": "^26.6.3",
     "jest-canvas-mock": "^2.3.1",
     "jest-environment-jsdom-sixteen": "^2.0.0",
+    "jwt-decode": "^3.1.2",
     "portal-vue": "^2.1.7",
     "prettier": "^2.2.1",
     "qrcanvas-vue": "2.1.1",
@@ -59,6 +60,7 @@
     "vue-loading-overlay": "^3.4.2",
     "vue-moment": "^4.1.0",
     "vue-router": "^3.0.6",
+    "vue-timers": "^2.0.4",
     "vue2-transitions": "^0.2.3",
     "vuex": "^3.6.0",
     "vuex-persistedstate": "^4.0.0-beta.3"
diff --git a/frontend/public/img/template/Foto_01.jpg b/frontend/public/img/template/Foto_01.jpg
index 3e64e27a5..6238da44c 100644
Binary files a/frontend/public/img/template/Foto_01.jpg and b/frontend/public/img/template/Foto_01.jpg differ
diff --git a/frontend/public/img/template/Foto_01_2400_small.jpg b/frontend/public/img/template/Foto_01_2400_small.jpg
index 834ec73df..2e623cec0 100644
Binary files a/frontend/public/img/template/Foto_01_2400_small.jpg and b/frontend/public/img/template/Foto_01_2400_small.jpg differ
diff --git a/frontend/public/img/template/Foto_03_2400_small.jpg b/frontend/public/img/template/Foto_03_2400_small.jpg
index d81b4c3f4..2c2828928 100644
Binary files a/frontend/public/img/template/Foto_03_2400_small.jpg and b/frontend/public/img/template/Foto_03_2400_small.jpg differ
diff --git a/frontend/src/components/Auth/AuthCarousel.vue b/frontend/src/components/Auth/AuthCarousel.vue
index db3037828..a050c1554 100644
--- a/frontend/src/components/Auth/AuthCarousel.vue
+++ b/frontend/src/components/Auth/AuthCarousel.vue
@@ -1,9 +1,18 @@
 <template>
   <div>
     <b-carousel :interval="13000">
-      <b-carousel-slide img-src="/img/template/Foto_01_2400_small.jpg"></b-carousel-slide>
-      <b-carousel-slide img-src="/img/template/Foto_02_2400_small.jpg"></b-carousel-slide>
-      <b-carousel-slide img-src="/img/template/Foto_03_2400_small.jpg"></b-carousel-slide>
+      <b-carousel-slide img-src="/img/template/Foto_01_2400_small.jpg">
+        <div class="caption-first-text">{{ $t('auth.left.gratitude') }}</div>
+        <div class="caption-second-text">{{ $t('auth.left.oneGratitude') }}</div>
+      </b-carousel-slide>
+      <b-carousel-slide img-src="/img/template/Foto_02_2400_small.jpg">
+        <div class="caption-first-text">{{ $t('auth.left.dignity') }}</div>
+        <div class="caption-second-text">{{ $t('auth.left.oneDignity') }}</div>
+      </b-carousel-slide>
+      <b-carousel-slide img-src="/img/template/Foto_03_2400_small.jpg">
+        <div class="caption-first-text">{{ $t('auth.left.donation') }}</div>
+        <div class="caption-second-text">{{ $t('auth.left.oneDonation') }}</div>
+      </b-carousel-slide>
     </b-carousel>
   </div>
 </template>
@@ -15,6 +24,21 @@ export default {
 </script>
 
 <style>
+.carousel-caption {
+  color: #fff;
+  top: 317px;
+  text-shadow: 2px 2px 8px #000000;
+  font-size: xx-large;
+}
+
+.caption-first-text {
+  font-size: 150%;
+}
+
+.caption-second-text {
+  font-size: 80%;
+}
+
 .carousel {
   position: relative;
   height: 110%;
diff --git a/frontend/src/components/Auth/AuthMobileStart.vue b/frontend/src/components/Auth/AuthMobileStart.vue
index 09985dd77..690b8f895 100644
--- a/frontend/src/components/Auth/AuthMobileStart.vue
+++ b/frontend/src/components/Auth/AuthMobileStart.vue
@@ -6,7 +6,7 @@
       {{ $t('auth.left.gratitude') }}
     </div>
     <div class="position-absolute h2 text-white zindex1000 w-100 text-center mt-9">
-      {{ $t('auth.left.newCurrency') }}
+      {{ $t('auth.left.oneGratitude') }}
     </div>
     <img
       src="/img/template/Blaetter.png"
diff --git a/frontend/src/components/Auth/AuthNavbar.vue b/frontend/src/components/Auth/AuthNavbar.vue
index 8063dd330..1192d6db3 100644
--- a/frontend/src/components/Auth/AuthNavbar.vue
+++ b/frontend/src/components/Auth/AuthNavbar.vue
@@ -3,7 +3,7 @@
     <b-navbar toggleable="lg" class="pr-4">
       <b-navbar-brand>
         <b-img
-          class="imgLogo position-absolute ml--3 mt--3 p-2 zindex1000"
+          class="imgLogo position-absolute ml--3 mt-lg--2 mt-3 p-2 zindex1000"
           :src="logo"
           width="200"
           alt="..."
@@ -18,7 +18,7 @@
       <b-img class="sheet-img position-absolute d-block d-lg-none zindex1000" :src="sheet"></b-img>
       <b-navbar-toggle target="nav-collapse" class="zindex1000"></b-navbar-toggle>
 
-      <b-collapse id="nav-collapse" is-nav class="mt-5 mt-lg-0">
+      <b-collapse id="nav-collapse" is-nav class="ml-5">
         <b-navbar-nav class="ml-auto" right>
           <b-nav-item :href="`https://gradido.net/${$i18n.locale}`" target="_blank">
             {{ $t('auth.navbar.aboutGradido') }}
@@ -46,11 +46,19 @@ export default {
 
 <style lang="scss">
 .authNavbar > .nav-link {
-  color: #383838 !important;
+  color: #0e79bc !important;
+}
+
+.navbar-toggler {
+  font-size: 2.25rem;
 }
 
 .authNavbar > .router-link-exact-active {
-  color: #0e79bc !important;
+  color: #383838 !important;
+}
+
+button.navbar-toggler > span.navbar-toggler-icon {
+  background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='30' height='30' viewBox='0 0 30 30'%3e%3cpath stroke='rgba(4, 112, 6, 1)' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");
 }
 
 .auth-header {
diff --git a/frontend/src/components/ClipboardCopy.vue b/frontend/src/components/ClipboardCopy.vue
index 7a6cf0ec1..ebab31aad 100644
--- a/frontend/src/components/ClipboardCopy.vue
+++ b/frontend/src/components/ClipboardCopy.vue
@@ -3,8 +3,11 @@
     <b-input-group v-if="canCopyLink" size="lg" class="mb-3" prepend="Link">
       <b-form-input :value="link" type="text" readonly></b-form-input>
       <b-input-group-append>
-        <b-button size="sm" text="Button" variant="primary" @click="CopyLink">
-          {{ $t('gdd_per_link.copy') }}
+        <b-button size="sm" text="Button" variant="primary" @click="copyLinkWithText">
+          {{ $t('gdd_per_link.copy-link-with-text') }}
+        </b-button>
+        <b-button size="sm" text="Button" variant="primary" @click="copyLink">
+          {{ $t('gdd_per_link.copy-link') }}
         </b-button>
         <b-button variant="primary" class="text-light" @click="$emit('show-qr-code-button')">
           <b-img src="img/svg/qr-code.svg" width="19" class="svg"></b-img>
@@ -18,29 +21,10 @@
   </div>
 </template>
 <script>
+import { copyLinks } from '../mixins/copyLinks'
 export default {
   name: 'ClipboardCopy',
-  props: {
-    link: { type: String, required: true },
-  },
-  data() {
-    return {
-      canCopyLink: true,
-    }
-  },
-  methods: {
-    CopyLink() {
-      navigator.clipboard
-        .writeText(this.link)
-        .then(() => {
-          this.toastSuccess(this.$t('gdd_per_link.link-copied'))
-        })
-        .catch(() => {
-          this.canCopyLink = false
-          this.toastError(this.$t('gdd_per_link.not-copied'))
-        })
-    },
-  },
+  mixins: [copyLinks],
 }
 </script>
 <style>
diff --git a/frontend/src/components/ContentFooter.spec.js b/frontend/src/components/ContentFooter.spec.js
index f67560e44..c578d3fac 100644
--- a/frontend/src/components/ContentFooter.spec.js
+++ b/frontend/src/components/ContentFooter.spec.js
@@ -97,24 +97,14 @@ describe('ContentFooter', () => {
         )
       })
 
-      it('has a link to the members area', () => {
-        expect(wrapper.findAll('a.nav-link').at(2).text()).toEqual('navigation.members_area')
-      })
-
-      it('links to the elopage', () => {
-        expect(wrapper.findAll('a.nav-link').at(2).attributes('href')).toEqual(
-          'https://elopage.com/s/gradido/sign_in?locale=en',
-        )
-      })
-
       it('links to the whitepaper', () => {
-        expect(wrapper.findAll('a.nav-link').at(3).attributes('href')).toEqual(
+        expect(wrapper.findAll('a.nav-link').at(2).attributes('href')).toEqual(
           'https://docs.google.com/document/d/1kcX1guOi6tDgnFHD9tf7fB_MneKTx-0nHJxzdN8ygNs/edit?usp=sharing',
         )
       })
 
       it('links to the support', () => {
-        expect(wrapper.findAll('a.nav-link').at(4).attributes('href')).toEqual(
+        expect(wrapper.findAll('a.nav-link').at(3).attributes('href')).toEqual(
           'https://gradido.net/en/contact/',
         )
       })
@@ -142,20 +132,14 @@ describe('ContentFooter', () => {
           )
         })
 
-        it('links to the German elopage when locale is de', () => {
-          expect(wrapper.findAll('a.nav-link').at(2).attributes('href')).toEqual(
-            'https://elopage.com/s/gradido/sign_in?locale=de',
-          )
-        })
-
         it('links to the German whitepaper when locale is de', () => {
-          expect(wrapper.findAll('a.nav-link').at(3).attributes('href')).toEqual(
+          expect(wrapper.findAll('a.nav-link').at(2).attributes('href')).toEqual(
             'https://docs.google.com/document/d/1jZp-DiiMPI9ZPNXmjsvOQ1BtnfDFfx8BX7CDmA8KKjY/edit?usp=sharing',
           )
         })
 
         it('links to the German support-page when locale is de', () => {
-          expect(wrapper.findAll('a.nav-link').at(4).attributes('href')).toEqual(
+          expect(wrapper.findAll('a.nav-link').at(3).attributes('href')).toEqual(
             'https://gradido.net/de/contact/',
           )
         })
diff --git a/frontend/src/components/ContentFooter.vue b/frontend/src/components/ContentFooter.vue
index bdcb5b1a9..c563cc23d 100755
--- a/frontend/src/components/ContentFooter.vue
+++ b/frontend/src/components/ContentFooter.vue
@@ -34,12 +34,6 @@
           <b-nav-item :href="`https://gradido.net/${$i18n.locale}/datenschutz/`" target="_blank">
             {{ $t('footer.privacy_policy') }}
           </b-nav-item>
-          <b-nav-item
-            :href="`https://elopage.com/s/gradido/sign_in?locale=${$i18n.locale}`"
-            target="_blank"
-          >
-            {{ $t('navigation.members_area') }}
-          </b-nav-item>
           <b-nav-item
             :href="
               $i18n.locale === 'de'
diff --git a/frontend/src/components/Contributions/ContributionForm.spec.js b/frontend/src/components/Contributions/ContributionForm.spec.js
new file mode 100644
index 000000000..eb1509328
--- /dev/null
+++ b/frontend/src/components/Contributions/ContributionForm.spec.js
@@ -0,0 +1,114 @@
+import { mount } from '@vue/test-utils'
+import ContributionForm from './ContributionForm.vue'
+
+const localVue = global.localVue
+
+describe('ContributionForm', () => {
+  let wrapper
+
+  const propsData = {
+    value: {
+      id: null,
+      date: '',
+      memo: '',
+      amount: '',
+    },
+  }
+
+  const mocks = {
+    $t: jest.fn((t) => t),
+    $d: jest.fn((d) => d),
+    $store: {
+      state: {
+        creation: ['1000', '1000', '1000'],
+      },
+    },
+    $i18n: {
+      locale: 'en',
+    },
+  }
+
+  const Wrapper = () => {
+    return mount(ContributionForm, {
+      localVue,
+      mocks,
+      propsData,
+    })
+  }
+
+  describe('mount', () => {
+    beforeEach(() => {
+      wrapper = Wrapper()
+    })
+
+    it('has a DIV .contribution-form', () => {
+      expect(wrapper.find('div.contribution-form').exists()).toBe(true)
+    })
+
+    describe('empty form data', () => {
+      describe('buttons', () => {
+        it('has reset enabled', () => {
+          expect(wrapper.find('button[type="reset"]').attributes('disabled')).toBeFalsy()
+        })
+
+        it('has submit disabled', () => {
+          expect(wrapper.find('button[type="submit"]').attributes('disabled')).toBe('disabled')
+        })
+      })
+    })
+
+    describe('set contrubtion', () => {
+      describe('fill in form data', () => {
+        const now = new Date().toISOString()
+
+        beforeEach(async () => {
+          await wrapper.setData({
+            form: {
+              id: null,
+              date: now,
+              memo: 'Mein Beitrag zur Gemeinschaft für diesen Monat ...',
+              amount: '200',
+            },
+          })
+        })
+
+        describe('buttons', () => {
+          it('has reset enabled', () => {
+            expect(wrapper.find('button[type="reset"]').attributes('disabled')).toBeFalsy()
+          })
+
+          it('has submit enabled', () => {
+            expect(wrapper.find('button[type="submit"]').attributes('disabled')).toBeFalsy()
+          })
+        })
+      })
+    })
+
+    describe('update contrubtion', () => {
+      describe('fill in form data and "id"', () => {
+        const now = new Date().toISOString()
+
+        beforeEach(async () => {
+          await wrapper.setData({
+            form: {
+              id: 2,
+              date: now,
+              memo: 'Mein Beitrag zur Gemeinschaft für diesen Monat ...',
+              amount: '200',
+            },
+          })
+        })
+
+        describe('buttons', () => {
+          it('has reset enabled', () => {
+            expect(wrapper.find('button[type="reset"]').attributes('disabled')).toBeFalsy()
+          })
+
+          it('has submit enabled', () => {
+            expect(wrapper.find('button[type="submit"]').attributes('disabled')).toBeFalsy()
+          })
+        })
+      })
+    })
+  })
+})
diff --git a/frontend/src/components/Contributions/ContributionForm.vue b/frontend/src/components/Contributions/ContributionForm.vue
new file mode 100644
index 000000000..d0de061d3
--- /dev/null
+++ b/frontend/src/components/Contributions/ContributionForm.vue
@@ -0,0 +1,179 @@
+<template>
+  <div class="container contribution-form">
+    <div class="my-3">
+      <h3>{{ $t('contribution.formText.yourContribution') }}</h3>
+      {{ $t('contribution.formText.bringYourTalentsTo') }}
+      <ul class="my-3">
+        <li v-html="lastMonthObject"></li>
+        <li v-html="thisMonthObject"></li>
+      </ul>
+
+      <div class="my-3">
+        <b>{{ $t('contribution.formText.describeYourCommunity') }}</b>
+      </div>
+    </div>
+    <b-form ref="form" @submit.prevent="submit" class="border p-3">
+      <label>{{ $t('contribution.selectDate') }}</label>
+      <b-form-datepicker
+        id="contribution-date"
+        v-model="form.date"
+        size="lg"
+        :locale="$i18n.locale"
+        :max="maximalDate"
+        :min="minimalDate"
+        class="mb-4"
+        reset-value=""
+        :label-no-date-selected="$t('contribution.noDateSelected')"
+        required
+      >
+        <template #nav-prev-year><span></span></template>
+        <template #nav-next-year><span></span></template>
+      </b-form-datepicker>
+      <validation-provider
+        :rules="{
+          required: true,
+          min: minlength,
+          max: maxlength,
+        }"
+        :name="$t('form.message')"
+        v-slot="{ errors }"
+      >
+        <label class="mt-3">{{ $t('contribution.activity') }}</label>
+        <b-form-textarea
+          id="contribution-memo"
+          v-model="form.memo"
+          rows="3"
+          max-rows="6"
+          required
+        ></b-form-textarea>
+        <b-col v-if="errors">
+          <span v-for="error in errors" class="errors" :key="error">{{ error }}</span>
+        </b-col>
+      </validation-provider>
+      <label class="mt-3">{{ $t('form.amount') }}</label>
+      <b-input-group size="lg" prepend="GDD" append=".00">
+        <b-form-input
+          id="contribution-amount"
+          v-model="form.amount"
+          type="number"
+          min="1"
+          :max="isThisMonth ? maxGddThisMonth : maxGddLastMonth"
+        ></b-form-input>
+      </b-input-group>
+      <div
+        v-if="isThisMonth && parseInt(form.amount) > parseInt(maxGddThisMonth)"
+        class="text-danger text-right"
+      >
+        {{ $t('contribution.formText.maxGDDforMonth', { amount: maxGddThisMonth }) }}
+      </div>
+      <div
+        v-if="!isThisMonth && parseInt(form.amount) > parseInt(maxGddLastMonth)"
+        class="text-danger text-right"
+      >
+        {{ $t('contribution.formText.maxGDDforMonth', { amount: maxGddLastMonth }) }}
+      </div>
+      <b-row class="mt-3">
+        <b-col>
+          <b-button class="test-cancel" type="reset" variant="secondary" @click="reset">
+            {{ $t('form.cancel') }}
+          </b-button>
+        </b-col>
+        <b-col class="text-right">
+          <b-button class="test-submit" type="submit" variant="primary" :disabled="disabled">
+            {{ form.id ? $t('form.change') : $t('contribution.submit') }}
+          </b-button>
+        </b-col>
+      </b-row>
+    </b-form>
+  </div>
+</template>
+<script>
+export default {
+  name: 'ContributionForm',
+  props: {
+    value: { type: Object, required: true },
+    updateAmount: { type: String, required: false },
+  },
+  data() {
+    return {
+      minlength: 5,
+      maxlength: 255,
+      maximalDate: new Date(),
+      form: this.value, // includes 'id'
+    }
+  },
+  methods: {
+    submit() {
+      if (this.form.id) {
+        this.$emit('update-contribution', this.form)
+      } else {
+        this.$emit('set-contribution', this.form)
+      }
+      this.reset()
+    },
+    reset() {
+      this.$refs.form.reset()
+      this.form.id = null
+      this.form.date = ''
+      this.form.memo = ''
+      this.form.amount = ''
+    },
+  },
+  computed: {
+    /*
+     * minimalDate() = Sets the date to the 1st of the previous month.
+     *
+     */
+    minimalDate() {
+      return new Date(this.maximalDate.getFullYear(), this.maximalDate.getMonth() - 1, 1)
+    },
+    disabled() {
+      if (
+        this.form.date === '' ||
+        this.form.memo.length < this.minlength ||
+        this.form.amount <= 0 ||
+        this.form.amount > 1000 ||
+        (this.isThisMonth && parseInt(this.form.amount) > parseInt(this.maxGddThisMonth)) ||
+        (!this.isThisMonth && parseInt(this.form.amount) > parseInt(this.maxGddLastMonth))
+      )
+        return true
+      return false
+    },
+    lastMonthObject() {
+      // new Date().getMonth === 1 If the current month is January, then one year must be gone back in the previous month
+      const obj = {
+        monthAndYear: this.$d(new Date(this.minimalDate), 'monthAndYear'),
+        creation: this.maxGddLastMonth,
+      }
+      return this.$t('contribution.formText.openAmountForMonth', obj)
+    },
+    thisMonthObject() {
+      const obj = {
+        monthAndYear: this.$d(new Date(), 'monthAndYear'),
+        creation: this.maxGddThisMonth,
+      }
+      return this.$t('contribution.formText.openAmountForMonth', obj)
+    },
+    isThisMonth() {
+      return new Date(this.form.date).getMonth() === new Date().getMonth()
+    },
+    maxGddLastMonth() {
+      // When edited, the amount is added back on top of the amount
+      return this.form.id && !this.isThisMonth
+        ? parseInt(this.$store.state.creation[1]) + parseInt(this.updateAmount)
+        : this.$store.state.creation[1]
+    },
+    maxGddThisMonth() {
+      // When edited, the amount is added back on top of the amount
+      return this.form.id && this.isThisMonth
+        ? parseInt(this.$store.state.creation[2]) + parseInt(this.updateAmount)
+        : this.$store.state.creation[2]
+    },
+  },
+}
+</script>
+<style>
+span.errors {
+  color: red;
+}
+</style>
diff --git a/frontend/src/components/Contributions/ContributionList.spec.js b/frontend/src/components/Contributions/ContributionList.spec.js
new file mode 100644
index 000000000..a1dfc934d
--- /dev/null
+++ b/frontend/src/components/Contributions/ContributionList.spec.js
@@ -0,0 +1,120 @@
+import { mount } from '@vue/test-utils'
+import ContributionList from './ContributionList.vue'
+
+const localVue = global.localVue
+
+describe('ContributionList', () => {
+  let wrapper
+
+  const mocks = {
+    $t: jest.fn((t) => t),
+    $d: jest.fn((d) => d),
+  }
+
+  const propsData = {
+    contributionCount: 3,
+    showPagination: true,
+    pageSize: 25,
+    items: [
+      {
+        id: 0,
+        date: '07/06/2022',
+        memo: 'Ich habe 10 Stunden die Elbwiesen von Müll befreit.',
+        amount: '200',
+      },
+      {
+        id: 1,
+        date: '06/22/2022',
+        memo: 'Ich habe 30 Stunden Frau Müller beim EInkaufen und im Haushalt geholfen.',
+        amount: '600',
+      },
+      {
+        id: 2,
+        date: '05/04/2022',
+        memo:
+          'Ich habe 50 Stunden den Nachbarkindern bei ihren Hausaufgaben geholfen und Nachhilfeunterricht gegeben.',
+        amount: '1000',
+      },
+    ],
+  }
+
+  const Wrapper = () => {
+    return mount(ContributionList, {
+      localVue,
+      mocks,
+      propsData,
+    })
+  }
+
+  describe('mount', () => {
+    beforeEach(() => {
+      wrapper = Wrapper()
+    })
+
+    it('has a DIV .contribution-list', () => {
+      expect(wrapper.find('div.contribution-list').exists()).toBe(true)
+    })
+
+    describe('pagination', () => {
+      describe('list count smaller than page size', () => {
+        it('has no pagination buttons', () => {
+          expect(wrapper.find('ul.pagination').exists()).toBe(false)
+        })
+      })
+
+      describe('list count greater than page size', () => {
+        beforeEach(() => {
+          wrapper.setProps({ contributionCount: 33 })
+        })
+
+        it('has pagination buttons', () => {
+          expect(wrapper.find('ul.pagination').exists()).toBe(true)
+        })
+      })
+
+      describe('switch page', () => {
+        const scrollToMock = jest.fn()
+        window.scrollTo = scrollToMock
+
+        beforeEach(async () => {
+          await wrapper.setProps({ contributionCount: 33 })
+          wrapper.findComponent({ name: 'BPagination' }).vm.$emit('input', 2)
+        })
+
+        it('emits update contribution list', () => {
+          expect(wrapper.emitted('update-list-contributions')).toEqual([
+            [{ currentPage: 2, pageSize: 25 }],
+          ])
+        })
+
+        it('scrolls to top', () => {
+          expect(scrollToMock).toBeCalledWith(0, 0)
+        })
+      })
+    })
+
+    describe('update contribution', () => {
+      beforeEach(() => {
+        wrapper
+          .findComponent({ name: 'ContributionListItem' })
+          .vm.$emit('update-contribution-form', 'item')
+      })
+
+      it('emits update contribution form', () => {
+        expect(wrapper.emitted('update-contribution-form')).toEqual([['item']])
+      })
+    })
+
+    describe('delete contribution', () => {
+      beforeEach(() => {
+        wrapper
+          .findComponent({ name: 'ContributionListItem' })
+          .vm.$emit('delete-contribution', { id: 2 })
+      })
+
+      it('emits delete contribution', () => {
+        expect(wrapper.emitted('delete-contribution')).toEqual([[{ id: 2 }]])
+      })
+    })
+  })
+})
diff --git a/frontend/src/components/Contributions/ContributionList.vue b/frontend/src/components/Contributions/ContributionList.vue
new file mode 100644
index 000000000..cf8606e33
--- /dev/null
+++ b/frontend/src/components/Contributions/ContributionList.vue
@@ -0,0 +1,77 @@
+<template>
+  <div class="contribution-list container">
+    <div class="list-group" v-for="item in items" :key="item.id">
+      <contribution-list-item
+        v-bind="item"
+        @update-contribution-form="updateContributionForm"
+        @delete-contribution="deleteContribution"
+      />
+    </div>
+    <b-pagination
+      v-if="isPaginationVisible"
+      class="mt-3"
+      pills
+      size="lg"
+      v-model="currentPage"
+      :per-page="pageSize"
+      :total-rows="contributionCount"
+      align="center"
+      :hide-ellipsis="true"
+    ></b-pagination>
+  </div>
+</template>
+<script>
+import ContributionListItem from '@/components/Contributions/ContributionListItem.vue'
+
+export default {
+  name: 'ContributionList',
+  components: {
+    ContributionListItem,
+  },
+  props: {
+    items: {
+      type: Array,
+      required: true,
+    },
+    contributionCount: {
+      type: Number,
+      required: true,
+    },
+    showPagination: {
+      type: Boolean,
+      required: true,
+    },
+    pageSize: { type: Number, default: 25 },
+  },
+  data() {
+    return {
+      currentPage: 1,
+    }
+  },
+  methods: {
+    updateListContributions() {
+      this.$emit('update-list-contributions', {
+        currentPage: this.currentPage,
+        pageSize: this.pageSize,
+      })
+      window.scrollTo(0, 0)
+    },
+    updateContributionForm(item) {
+      this.$emit('update-contribution-form', item)
+    },
+    deleteContribution(item) {
+      this.$emit('delete-contribution', item)
+    },
+  },
+  computed: {
+    isPaginationVisible() {
+      return this.showPagination && this.pageSize < this.contributionCount
+    },
+  },
+  watch: {
+    currentPage() {
+      this.updateListContributions()
+    },
+  },
+}
+</script>
diff --git a/frontend/src/components/Contributions/ContributionListItem.spec.js b/frontend/src/components/Contributions/ContributionListItem.spec.js
new file mode 100644
index 000000000..59918e762
--- /dev/null
+++ b/frontend/src/components/Contributions/ContributionListItem.spec.js
@@ -0,0 +1,145 @@
+import { mount } from '@vue/test-utils'
+import ContributionListItem from './ContributionListItem.vue'
+
+const localVue = global.localVue
+
+describe('ContributionListItem', () => {
+  let wrapper
+
+  const mocks = {
+    $t: jest.fn((t) => t),
+    $d: jest.fn((d) => d),
+  }
+
+  const propsData = {
+    id: 1,
+    createdAt: '26/07/2022',
+    contributionDate: '07/06/2022',
+    memo: 'Ich habe 10 Stunden die Elbwiesen von Müll befreit.',
+    amount: '200',
+  }
+
+  const Wrapper = () => {
+    return mount(ContributionListItem, {
+      localVue,
+      mocks,
+      propsData,
+    })
+  }
+
+  describe('mount', () => {
+    beforeEach(() => {
+      jest.clearAllMocks()
+      wrapper = Wrapper()
+    })
+
+    it('has a DIV .contribution-list-item', () => {
+      expect(wrapper.find('div.contribution-list-item').exists()).toBe(true)
+    })
+
+    describe('contribution type', () => {
+      it('is pending by default', () => {
+        expect(wrapper.vm.type).toBe('pending')
+      })
+
+      it('is deleted when deletedAt is present', async () => {
+        await wrapper.setProps({ deletedAt: new Date().toISOString() })
+        expect(wrapper.vm.type).toBe('deleted')
+      })
+
+      it('is confirmed when confirmedAt is present', async () => {
+        await wrapper.setProps({ confirmedAt: new Date().toISOString() })
+        expect(wrapper.vm.type).toBe('confirmed')
+      })
+    })
+
+    describe('contribution icon', () => {
+      it('is bell-fill by default', () => {
+        expect(wrapper.vm.icon).toBe('bell-fill')
+      })
+
+      it('is x-circle when deletedAt is present', async () => {
+        await wrapper.setProps({ deletedAt: new Date().toISOString() })
+        expect(wrapper.vm.icon).toBe('x-circle')
+      })
+
+      it('is check when confirmedAt is present', async () => {
+        await wrapper.setProps({ confirmedAt: new Date().toISOString() })
+        expect(wrapper.vm.icon).toBe('check')
+      })
+    })
+
+    describe('contribution variant', () => {
+      it('is primary by default', () => {
+        expect(wrapper.vm.variant).toBe('primary')
+      })
+
+      it('is danger when deletedAt is present', async () => {
+        await wrapper.setProps({ deletedAt: new Date().toISOString() })
+        expect(wrapper.vm.variant).toBe('danger')
+      })
+
+      it('is success at when confirmedAt is present', async () => {
+        await wrapper.setProps({ confirmedAt: new Date().toISOString() })
+        expect(wrapper.vm.variant).toBe('success')
+      })
+    })
+
+    describe('date', () => {
+      it('is equal to createdAt', () => {
+        expect(wrapper.vm.date).toBe(wrapper.vm.createdAt)
+      })
+    })
+
+    describe('delete contribution', () => {
+      let spy
+
+      describe('edit contribution', () => {
+        beforeEach(() => {
+          wrapper.findAll('div.pointer').at(0).trigger('click')
+        })
+
+        it('emits update contribution form', () => {
+          expect(wrapper.emitted('update-contribution-form')).toEqual([
+            [
+              {
+                id: 1,
+                contributionDate: '07/06/2022',
+                memo: 'Ich habe 10 Stunden die Elbwiesen von Müll befreit.',
+                amount: '200',
+              },
+            ],
+          ])
+        })
+      })
+
+      describe('confirm deletion', () => {
+        beforeEach(() => {
+          spy = jest.spyOn(wrapper.vm.$bvModal, 'msgBoxConfirm')
+          spy.mockImplementation(() => Promise.resolve(true))
+          wrapper.findAll('div.pointer').at(1).trigger('click')
+        })
+
+        it('opens the modal', () => {
+          expect(spy).toBeCalledWith('contribution.delete')
+        })
+
+        it('emits delete contribution', () => {
+          expect(wrapper.emitted('delete-contribution')).toEqual([[{ id: 1 }]])
+        })
+      })
+
+      describe('cancel deletion', () => {
+        beforeEach(async () => {
+          spy = jest.spyOn(wrapper.vm.$bvModal, 'msgBoxConfirm')
+          spy.mockImplementation(() => Promise.resolve(false))
+          await wrapper.findAll('div.pointer').at(1).trigger('click')
+        })
+
+        it('does not emit delete contribution', () => {
+          expect(wrapper.emitted('delete-contribution')).toBeFalsy()
+        })
+      })
+    })
+  })
+})
diff --git a/frontend/src/components/Contributions/ContributionListItem.vue b/frontend/src/components/Contributions/ContributionListItem.vue
new file mode 100644
index 000000000..90e98bc4c
--- /dev/null
+++ b/frontend/src/components/Contributions/ContributionListItem.vue
@@ -0,0 +1,114 @@
+<template>
+  <div class="contribution-list-item">
+    <slot>
+      <div class="border p-3 w-100 mb-1" :class="`border-${variant}`">
+        <div class="d-inline-flex">
+          <div class="mr-2"><b-icon :icon="icon" :variant="variant" class="h2"></b-icon></div>
+          <div v-if="firstName" class="mr-3">{{ firstName }} {{ lastName }}</div>
+          <div class="mr-2" :class="type != 'deleted' ? 'font-weight-bold' : ''">
+            {{ amount | GDD }}
+          </div>
+          {{ $t('math.minus') }}
+          <div class="mx-2">{{ $d(new Date(date), 'short') }}</div>
+        </div>
+        <div class="mr-2">
+          <span>{{ $t('contribution.date') }}</span>
+          <span>
+            {{ $d(new Date(contributionDate), 'monthAndYear') }}
+          </span>
+        </div>
+        <div class="mr-2">{{ memo }}</div>
+        <div v-if="type === 'pending' && !firstName" class="d-flex flex-row-reverse">
+          <div
+            class="pointer ml-5"
+            @click="
+              $emit('update-contribution-form', {
+                id: id,
+                contributionDate: contributionDate,
+                memo: memo,
+                amount: amount,
+              })
+            "
+          >
+            <b-icon icon="pencil" class="h2"></b-icon>
+          </div>
+          <div class="pointer" @click="deleteContribution({ id })">
+            <b-icon icon="trash" class="h2"></b-icon>
+          </div>
+        </div>
+      </div>
+    </slot>
+  </div>
+</template>
+<script>
+export default {
+  name: 'ContributionListItem',
+  props: {
+    id: {
+      type: Number,
+    },
+    amount: {
+      type: String,
+    },
+    memo: {
+      type: String,
+    },
+    firstName: {
+      type: String,
+      required: false,
+    },
+    lastName: {
+      type: String,
+      required: false,
+    },
+    createdAt: {
+      type: String,
+    },
+    contributionDate: {
+      type: String,
+    },
+    deletedAt: {
+      type: String,
+      required: false,
+    },
+    confirmedBy: {
+      type: Number,
+      required: false,
+    },
+    confirmedAt: {
+      type: String,
+      required: false,
+    },
+  },
+  computed: {
+    type() {
+      if (this.deletedAt) return 'deleted'
+      if (this.confirmedAt) return 'confirmed'
+      return 'pending'
+    },
+    icon() {
+      if (this.deletedAt) return 'x-circle'
+      if (this.confirmedAt) return 'check'
+      return 'bell-fill'
+    },
+    variant() {
+      if (this.deletedAt) return 'danger'
+      if (this.confirmedAt) return 'success'
+      return 'primary'
+    },
+    date() {
+      // if (this.deletedAt) return this.deletedAt
+      // if (this.confirmedAt) return this.confirmedAt
+      // return this.contributionDate
+      return this.createdAt
+    },
+  },
+  methods: {
+    deleteContribution(item) {
+      this.$bvModal.msgBoxConfirm(this.$t('contribution.delete')).then(async (value) => {
+        if (value) this.$emit('delete-contribution', item)
+      })
+    },
+  },
+}
+</script>
diff --git a/frontend/src/components/GddSend/TransactionResultLink.vue b/frontend/src/components/GddSend/TransactionResultLink.vue
index 04445acfe..2e1e68ac0 100644
--- a/frontend/src/components/GddSend/TransactionResultLink.vue
+++ b/frontend/src/components/GddSend/TransactionResultLink.vue
@@ -3,7 +3,13 @@
     <b-col>
       <b-card class="p-0 gradido-custom-background">
         <div class="h3 mb-4">{{ $t('gdd_per_link.created') }}</div>
-        <clipboard-copy :link="link" @show-qr-code-button="showQrCodeButton" />
+        <clipboard-copy
+          :link="link"
+          :amount="amount"
+          :memo="memo"
+          :validUntil="validUntil"
+          @show-qr-code-button="showQrCodeButton"
+        ></clipboard-copy>
 
         <div class="text-center">
           <figure-qr-code v-if="showQrcode" :link="link" />
@@ -27,10 +33,10 @@ export default {
     FigureQrCode,
   },
   props: {
-    link: {
-      type: String,
-      required: true,
-    },
+    link: { type: String, required: true },
+    amount: { type: String, required: true },
+    memo: { type: String, required: true },
+    validUntil: { type: String, required: true },
   },
   data() {
     return {
diff --git a/frontend/src/components/GddTransactionList.vue b/frontend/src/components/GddTransactionList.vue
index 5becfa39e..a74be5187 100644
--- a/frontend/src/components/GddTransactionList.vue
+++ b/frontend/src/components/GddTransactionList.vue
@@ -69,6 +69,7 @@
       :per-page="pageSize"
       :total-rows="transactionCount"
       align="center"
+      :hide-ellipsis="true"
     ></b-pagination>
 
     <div v-if="transactionCount <= 0" class="mt-4 text-center">
diff --git a/frontend/src/components/GdtTransactionList.vue b/frontend/src/components/GdtTransactionList.vue
index 4934f9fce..f915cd881 100644
--- a/frontend/src/components/GdtTransactionList.vue
+++ b/frontend/src/components/GdtTransactionList.vue
@@ -36,6 +36,7 @@
       :per-page="pageSize"
       :total-rows="transactionGdtCount"
       align="center"
+      :hide-ellipsis="true"
     ></b-pagination>
   </div>
 </template>
diff --git a/frontend/src/components/LanguageSwitch2.spec.js b/frontend/src/components/LanguageSwitch2.spec.js
new file mode 100644
index 000000000..600e2513e
--- /dev/null
+++ b/frontend/src/components/LanguageSwitch2.spec.js
@@ -0,0 +1,133 @@
+import { mount } from '@vue/test-utils'
+import LanguageSwitch from './LanguageSwitch2'
+
+const localVue = global.localVue
+
+const updateUserInfosMutationMock = jest.fn().mockResolvedValue({
+  data: {
+    updateUserInfos: {
+      validValues: 1,
+    },
+  },
+})
+
+describe('LanguageSwitch', () => {
+  let wrapper
+
+  const state = {
+    email: 'he@ho.he',
+    language: null,
+  }
+
+  const mocks = {
+    $store: {
+      state,
+      commit: jest.fn(),
+    },
+    $i18n: {
+      locale: 'en',
+    },
+    $t: jest.fn((t) => t),
+    $apollo: {
+      mutate: updateUserInfosMutationMock,
+    },
+  }
+
+  const Wrapper = () => {
+    return mount(LanguageSwitch, { localVue, mocks })
+  }
+
+  describe('mount', () => {
+    beforeEach(() => {
+      wrapper = Wrapper()
+    })
+
+    it('renders the component', () => {
+      expect(wrapper.find('div.language-switch').exists()).toBe(true)
+    })
+
+    describe('with locales en and de', () => {
+      describe('empty store', () => {
+        describe('navigator language is "en-US"', () => {
+          const languageGetter = jest.spyOn(navigator, 'language', 'get')
+          it('shows English as default navigator langauge', async () => {
+            languageGetter.mockReturnValue('en-US')
+            wrapper.vm.setCurrentLanguage()
+            await wrapper.vm.$nextTick()
+            expect(wrapper.findAll('span.locales').at(0).text()).toBe('English')
+          })
+        })
+        describe('navigator language is "de-DE"', () => {
+          const languageGetter = jest.spyOn(navigator, 'language', 'get')
+          it('shows Deutsch as language ', async () => {
+            languageGetter.mockReturnValue('de-DE')
+            wrapper.vm.setCurrentLanguage()
+            await wrapper.vm.$nextTick()
+            expect(wrapper.findAll('span.locales').at(1).text()).toBe('Deutsch')
+          })
+        })
+        describe('navigator language is "es-ES" (not supported)', () => {
+          const languageGetter = jest.spyOn(navigator, 'language', 'get')
+          it('shows English as language ', async () => {
+            languageGetter.mockReturnValue('es-ES')
+            wrapper.vm.setCurrentLanguage()
+            await wrapper.vm.$nextTick()
+            expect(wrapper.findAll('span.locales').at(0).text()).toBe('English')
+          })
+        })
+        describe('no navigator langauge', () => {
+          const languageGetter = jest.spyOn(navigator, 'language', 'get')
+          it('shows English as language ', async () => {
+            languageGetter.mockReturnValue(null)
+            wrapper.vm.setCurrentLanguage()
+            await wrapper.vm.$nextTick()
+            expect(wrapper.findAll('span.locales').at(0).text()).toBe('English')
+          })
+        })
+      })
+      describe('language "de" in store', () => {
+        it('shows Deutsch as language', async () => {
+          wrapper.vm.$store.state.language = 'de'
+          wrapper.vm.setCurrentLanguage()
+          await wrapper.vm.$nextTick()
+          expect(wrapper.findAll('span.locales').at(1).text()).toBe('Deutsch')
+        })
+      })
+      describe('language menu', () => {
+        it('has English and German as languages to choose', () => {
+          expect(wrapper.findAll('span.locales')).toHaveLength(2)
+        })
+        it('has English as first language to choose', () => {
+          expect(wrapper.findAll('span.locales').at(0).text()).toBe('English')
+        })
+        it('has German as second language to choose', () => {
+          expect(wrapper.findAll('span.locales').at(1).text()).toBe('Deutsch')
+        })
+      })
+    })
+
+    describe('calls the API', () => {
+      it("with locale 'de'", () => {
+        wrapper.findAll('span.locales').at(1).trigger('click')
+        expect(updateUserInfosMutationMock).toBeCalledWith(
+          expect.objectContaining({
+            variables: {
+              locale: 'de',
+            },
+          }),
+        )
+      })
+
+      // it("with locale 'en'", () => {
+      //   wrapper.findAll('span.locales').at(0).trigger('click')
+      //   expect(updateUserInfosMutationMock).toBeCalledWith(
+      //     expect.objectContaining({
+      //       variables: {
+      //         locale: 'en',
+      //       },
+      //     }),
+      //   )
+      // })
+    })
+  })
+})
diff --git a/frontend/src/components/LanguageSwitch2.vue b/frontend/src/components/LanguageSwitch2.vue
index 317935900..e88050047 100644
--- a/frontend/src/components/LanguageSwitch2.vue
+++ b/frontend/src/components/LanguageSwitch2.vue
@@ -4,10 +4,10 @@
       v-for="(lang, index) in locales"
       @click.prevent="saveLocale(lang.code)"
       :key="lang.code"
-      class="pointer pr-3"
-      :class="$store.state.language === lang.code ? 'c-blau' : 'c-grey'"
+      class="pointer pr-2"
+      :class="$store.state.language === lang.code ? 'c-grey' : 'c-blau'"
     >
-      {{ lang.name }}
+      <span class="locales">{{ lang.name }}</span>
       <span class="ml-3">{{ locales.length - 1 > index ? $t('math.pipe') : '' }}</span>
     </span>
   </div>
diff --git a/frontend/src/components/LinkInformations/RedeemInformation.vue b/frontend/src/components/LinkInformations/RedeemInformation.vue
index bdc17db9a..d287605a4 100644
--- a/frontend/src/components/LinkInformations/RedeemInformation.vue
+++ b/frontend/src/components/LinkInformations/RedeemInformation.vue
@@ -1,8 +1,12 @@
 <template>
   <div class="redeem-information">
     <b-jumbotron bg-variant="muted" text-variant="dark" border-variant="info">
-      <h1>
-        {{ firstName }}
+      <h1 v-if="isContributionLink">
+        {{ CONFIG.COMMUNITY_NAME }}
+        {{ $t('contribution-link.thanksYouWith') }} {{ amount | GDD }}
+      </h1>
+      <h1 v-else>
+        {{ user.firstName }}
         {{ $t('transaction-link.send_you') }} {{ amount | GDD }}
       </h1>
       <b>{{ memo }}</b>
@@ -10,12 +14,20 @@
   </div>
 </template>
 <script>
+import CONFIG from '@/config'
+
 export default {
   name: 'RedeemInformation',
   props: {
-    firstName: { type: String, required: true },
+    user: { type: Object, required: false },
     amount: { type: String, required: true },
     memo: { type: String, required: true, default: '' },
+    isContributionLink: { type: Boolean, default: false },
+  },
+  data() {
+    return {
+      CONFIG,
+    }
   },
 }
 </script>
diff --git a/frontend/src/components/LinkInformations/RedeemLoggedOut.vue b/frontend/src/components/LinkInformations/RedeemLoggedOut.vue
index a5cb97955..982bfdf08 100644
--- a/frontend/src/components/LinkInformations/RedeemLoggedOut.vue
+++ b/frontend/src/components/LinkInformations/RedeemLoggedOut.vue
@@ -1,6 +1,6 @@
 <template>
   <div class="redeem-logged-out">
-    <redeem-information :firstName="user.firstName" :amount="amount" :memo="memo" />
+    <redeem-information v-bind="linkData" :isContributionLink="isContributionLink" />
 
     <b-jumbotron>
       <div class="mb-6">
@@ -32,9 +32,8 @@ export default {
     RedeemInformation,
   },
   props: {
-    user: { type: Object, required: true },
-    amount: { type: String, required: true },
-    memo: { type: String, required: true, default: '' },
+    linkData: { type: Object, required: true },
+    isContributionLink: { type: Boolean, default: false },
   },
   computed: {
     login() {
diff --git a/frontend/src/components/LinkInformations/RedeemSelfCreator.vue b/frontend/src/components/LinkInformations/RedeemSelfCreator.vue
index 9f4764c0f..10311e52b 100644
--- a/frontend/src/components/LinkInformations/RedeemSelfCreator.vue
+++ b/frontend/src/components/LinkInformations/RedeemSelfCreator.vue
@@ -1,6 +1,6 @@
 <template>
   <div class="redeem-self-creator">
-    <redeem-information :firstName="user.firstName" :amount="amount" :memo="memo" />
+    <redeem-information v-bind="linkData" :isContributionLink="isContributionLink" />
 
     <b-jumbotron>
       <div class="mb-3 text-center">
@@ -23,9 +23,8 @@ export default {
     RedeemInformation,
   },
   props: {
-    user: { type: Object, required: true },
-    amount: { type: String, required: true },
-    memo: { type: String, required: true, default: '' },
+    linkData: { type: Object, required: true },
+    isContributionLink: { type: Boolean, default: false },
   },
 }
 </script>
diff --git a/frontend/src/components/LinkInformations/RedeemValid.vue b/frontend/src/components/LinkInformations/RedeemValid.vue
index 301afad69..353fefaf8 100644
--- a/frontend/src/components/LinkInformations/RedeemValid.vue
+++ b/frontend/src/components/LinkInformations/RedeemValid.vue
@@ -1,9 +1,9 @@
 <template>
   <div class="redeem-valid">
-    <redeem-information :firstName="user.firstName" :amount="amount" :memo="memo" />
+    <redeem-information v-bind="linkData" :isContributionLink="isContributionLink" />
     <b-jumbotron>
       <div class="mb-3 text-center">
-        <b-button variant="primary" @click="$emit('redeem-link', amount)" size="lg">
+        <b-button variant="primary" @click="$emit('redeem-link', linkData.amount)" size="lg">
           {{ $t('gdd_per_link.redeem') }}
         </b-button>
       </div>
@@ -19,9 +19,8 @@ export default {
     RedeemInformation,
   },
   props: {
-    user: { type: Object, required: false },
-    amount: { type: String, required: false },
-    memo: { type: String, required: false, default: '' },
+    linkData: { type: Object, required: true },
+    isContributionLink: { type: Boolean, default: false },
   },
 }
 </script>
diff --git a/frontend/src/components/Menu/Navbar.spec.js b/frontend/src/components/Menu/Navbar.spec.js
index ebf9abba0..3f12682c0 100644
--- a/frontend/src/components/Menu/Navbar.spec.js
+++ b/frontend/src/components/Menu/Navbar.spec.js
@@ -17,7 +17,7 @@ const mocks = {
   $t: jest.fn((t) => t),
   $store: {
     state: {
-      hasElopage: false,
+      hasElopage: true,
       isAdmin: true,
     },
   },
@@ -39,15 +39,17 @@ describe('Navbar', () => {
       expect(wrapper.find('div.component-navbar').exists()).toBeTruthy()
     })
 
-    describe('navigation Navbar', () => {
+    describe('navigation Navbar (general elements)', () => {
       it('has .navbar-brand in the navbar', () => {
         expect(wrapper.find('.navbar-brand').exists()).toBeTruthy()
       })
+
       it('has b-navbar-toggle in the navbar', () => {
         expect(wrapper.find('.navbar-toggler').exists()).toBeTruthy()
       })
+
       it('has ten b-nav-item in the navbar', () => {
-        expect(wrapper.findAll('.nav-item')).toHaveLength(10)
+        expect(wrapper.findAll('.nav-item')).toHaveLength(11)
       })
 
       it('has first nav-item "amount GDD" in navbar', () => {
@@ -57,31 +59,57 @@ describe('Navbar', () => {
       it('has first nav-item "navigation.overview" in navbar', () => {
         expect(wrapper.findAll('.nav-item').at(3).text()).toEqual('navigation.overview')
       })
+
       it('has first nav-item "navigation.send" in navbar', () => {
         expect(wrapper.findAll('.nav-item').at(4).text()).toEqual('navigation.send')
       })
+
       it('has first nav-item "navigation.transactions" in navbar', () => {
         expect(wrapper.findAll('.nav-item').at(5).text()).toEqual('navigation.transactions')
       })
-      it('has first nav-item "navigation.profile" in navbar', () => {
-        expect(wrapper.findAll('.nav-item').at(6).text()).toEqual('navigation.profile')
+
+      it('has first nav-item "navigation.transactions" in navbar', () => {
+        expect(wrapper.findAll('.nav-item').at(6).text()).toEqual('navigation.community')
       })
 
+      it('has first nav-item "navigation.profile" in navbar', () => {
+        expect(wrapper.findAll('.nav-item').at(7).text()).toEqual('navigation.profile')
+      })
+    })
+
+    describe('navigation Navbar (user has an elopage account)', () => {
       it('has a link to the members area', () => {
-        expect(wrapper.findAll('.nav-item').at(7).text()).toContain('navigation.members_area')
-        expect(wrapper.findAll('.nav-item').at(7).find('a').attributes('href')).toBe(
+        expect(wrapper.findAll('.nav-item').at(8).text()).toContain('navigation.members_area')
+        expect(wrapper.findAll('.nav-item').at(8).find('a').attributes('href')).toBe(
           'https://elopage.com',
         )
       })
 
+      it('has first nav-item "navigation.admin_area" in navbar', () => {
+        expect(wrapper.findAll('.nav-item').at(9).text()).toEqual('navigation.admin_area')
+      })
+
+      it('has first nav-item "navigation.logout" in navbar', () => {
+        expect(wrapper.findAll('.nav-item').at(10).text()).toEqual('navigation.logout')
+      })
+    })
+
+    describe('navigation Navbar (user has no elopage account)', () => {
+      beforeAll(() => {
+        mocks.$store.state.hasElopage = false
+        wrapper = Wrapper()
+      })
+
       it('has first nav-item "navigation.admin_area" in navbar', () => {
         expect(wrapper.findAll('.nav-item').at(8).text()).toEqual('navigation.admin_area')
       })
+
       it('has first nav-item "navigation.logout" in navbar', () => {
         expect(wrapper.findAll('.nav-item').at(9).text()).toEqual('navigation.logout')
       })
     })
   })
+
   describe('check watch visible true', () => {
     beforeEach(async () => {
       await wrapper.setProps({ visible: true })
diff --git a/frontend/src/components/Menu/Navbar.vue b/frontend/src/components/Menu/Navbar.vue
index 2f26f381e..ef222fdb4 100644
--- a/frontend/src/components/Menu/Navbar.vue
+++ b/frontend/src/components/Menu/Navbar.vue
@@ -52,17 +52,18 @@
           <b-icon icon="layout-text-sidebar-reverse" aria-hidden="true"></b-icon>
           {{ $t('navigation.transactions') }}
         </b-nav-item>
+        <b-nav-item to="/community" class="mb-3">
+          <b-icon icon="people" aria-hidden="true"></b-icon>
+          {{ $t('navigation.community') }}
+        </b-nav-item>
         <b-nav-item to="/profile" class="mb-3">
           <b-icon icon="gear" aria-hidden="true"></b-icon>
           {{ $t('navigation.profile') }}
         </b-nav-item>
         <br />
-        <b-nav-item :href="elopageUri" class="mb-3" target="_blank">
+        <b-nav-item v-if="$store.state.hasElopage" :href="elopageUri" class="mb-3" target="_blank">
           <b-icon icon="link45deg" aria-hidden="true"></b-icon>
           {{ $t('navigation.members_area') }}
-          <b-badge v-if="!$store.state.hasElopage" pill variant="danger">
-            {{ $t('math.exclaim') }}
-          </b-badge>
         </b-nav-item>
         <b-nav-item class="mb-3" v-if="$store.state.isAdmin" @click="$emit('admin')">
           <b-icon icon="shield-check" aria-hidden="true"></b-icon>
diff --git a/frontend/src/components/Menu/Sidebar.spec.js b/frontend/src/components/Menu/Sidebar.spec.js
index 0a7856c67..bd107d40b 100644
--- a/frontend/src/components/Menu/Sidebar.spec.js
+++ b/frontend/src/components/Menu/Sidebar.spec.js
@@ -27,6 +27,7 @@ describe('Sidebar', () => {
     beforeEach(() => {
       wrapper = Wrapper()
     })
+
     it('renders the component', () => {
       expect(wrapper.find('div#component-sidebar').exists()).toBeTruthy()
     })
@@ -47,19 +48,53 @@ describe('Sidebar', () => {
       it('has first nav-item "navigation.transactions" in navbar', () => {
         expect(wrapper.findAll('.nav-item').at(2).text()).toEqual('navigation.transactions')
       })
+
+      it('has first nav-item "navigation.community" in navbar', () => {
+        expect(wrapper.findAll('.nav-item').at(3).text()).toContain('navigation.community')
+      })
+
       it('has first nav-item "navigation.profile" in navbar', () => {
-        expect(wrapper.findAll('.nav-item').at(3).text()).toEqual('navigation.profile')
+        expect(wrapper.findAll('.nav-item').at(4).text()).toEqual('navigation.profile')
       })
+    })
+
+    describe('navigation Navbar (user has an elopage account)', () => {
+      it('has eight b-nav-item in the navbar', () => {
+        expect(wrapper.findAll('.nav-item')).toHaveLength(8)
+      })
+
       it('has a link to the members area', () => {
-        expect(wrapper.findAll('.nav-item').at(4).text()).toContain('navigation.members_area')
-        expect(wrapper.findAll('.nav-item').at(4).find('a').attributes('href')).toBe('#')
+        expect(wrapper.findAll('.nav-item').at(5).text()).toEqual('navigation.members_area')
+        expect(wrapper.findAll('.nav-item').at(5).find('a').attributes('href')).toBe('#')
       })
+
+      it('has first nav-item "navigation.admin_area" in navbar', () => {
+        expect(wrapper.findAll('.nav-item').at(6).text()).toEqual('navigation.admin_area')
+      })
+
+      it('has first nav-item "navigation.logout" in navbar', () => {
+        expect(wrapper.findAll('.nav-item').at(7).text()).toEqual('navigation.logout')
+      })
+    })
+
+    describe('navigation Navbar (user has no elopage account)', () => {
+      beforeAll(() => {
+        mocks.$store.state.hasElopage = false
+        wrapper = Wrapper()
+      })
+
+      it('has seven b-nav-item in the navbar', () => {
+        expect(wrapper.findAll('.nav-item')).toHaveLength(7)
+      })
+
       it('has first nav-item "navigation.admin_area" in navbar', () => {
         expect(wrapper.findAll('.nav-item').at(5).text()).toEqual('navigation.admin_area')
       })
+
       it('has first nav-item "community.community" in navbar', () => {
         expect(wrapper.findAll('.nav-item').at(6).text()).toEqual('community.community')
       })
+      
       it('has first nav-item "navigation.logout" in navbar', () => {
         expect(wrapper.findAll('.nav-item').at(7).text()).toEqual('navigation.logout')
       })
diff --git a/frontend/src/components/Menu/Sidebar.vue b/frontend/src/components/Menu/Sidebar.vue
index 8062e5ef5..e6bb4c6d9 100644
--- a/frontend/src/components/Menu/Sidebar.vue
+++ b/frontend/src/components/Menu/Sidebar.vue
@@ -16,6 +16,10 @@
             <b-icon icon="layout-text-sidebar-reverse" aria-hidden="true"></b-icon>
             {{ $t('navigation.transactions') }}
           </b-nav-item>
+          <b-nav-item to="/community" class="mb-3">
+            <b-icon icon="people" aria-hidden="true"></b-icon>
+            {{ $t('navigation.community') }}
+          </b-nav-item>
           <b-nav-item to="/profile" class="mb-3">
             <b-icon icon="gear" aria-hidden="true"></b-icon>
             {{ $t('navigation.profile') }}
@@ -23,12 +27,14 @@
         </b-nav>
         <hr />
         <b-nav vertical class="w-100">
-          <b-nav-item class="mb-3" :href="elopageUri" target="_blank">
+          <b-nav-item
+            v-if="$store.state.hasElopage"
+            class="mb-3"
+            :href="elopageUri"
+            target="_blank"
+          >
             <b-icon icon="link45deg" aria-hidden="true"></b-icon>
             {{ $t('navigation.members_area') }}
-            <b-badge v-if="!$store.state.hasElopage" pill variant="danger">
-              {{ $t('math.exclaim') }}
-            </b-badge>
           </b-nav-item>
           <b-nav-item class="mb-3" v-if="$store.state.isAdmin" @click="$emit('admin')">
             <b-icon icon="shield-check" aria-hidden="true"></b-icon>
diff --git a/frontend/src/components/SessionLogoutTimeout.spec.js b/frontend/src/components/SessionLogoutTimeout.spec.js
new file mode 100644
index 000000000..bd6911d13
--- /dev/null
+++ b/frontend/src/components/SessionLogoutTimeout.spec.js
@@ -0,0 +1,103 @@
+import { mount } from '@vue/test-utils'
+import SessionLogoutTimeout from './SessionLogoutTimeout'
+
+const localVue = global.localVue
+
+const apolloQueryMock = jest.fn()
+
+const setTokenTime = (seconds) => {
+  const now = new Date()
+  return Math.floor(new Date(now.setSeconds(now.getSeconds() + seconds)).getTime() / 1000)
+}
+
+const mocks = {
+  $store: {
+    state: {
+      token: '1234',
+      tokenTime: setTokenTime(120),
+    },
+  },
+  $i18n: {
+    locale: 'en',
+  },
+  $t: jest.fn((t) => t),
+  $apollo: {
+    query: apolloQueryMock,
+  },
+  $route: {
+    meta: {
+      requiresAuth: true,
+    },
+  },
+}
+
+describe('SessionLogoutTimeout', () => {
+  let wrapper, spy
+
+  const Wrapper = () => {
+    return mount(SessionLogoutTimeout, { localVue, mocks })
+  }
+
+  describe('mount', () => {
+    beforeEach(() => {
+      jest.clearAllMocks()
+      wrapper = Wrapper()
+    })
+
+    it('renders the component div.session-logout-timeout', () => {
+      expect(wrapper.find('div.session-logout-timeout').exists()).toBe(true)
+    })
+
+    describe('timers', () => {
+      it('has a token expires timer', () => {
+        expect(wrapper.vm.$options.timers).toEqual({
+          tokenExpires: expect.objectContaining({
+            name: 'tokenExpires',
+            time: 15000,
+            repeat: true,
+            immediate: true,
+            autostart: true,
+            isSwitchTab: false,
+          }),
+        })
+      })
+
+      describe('token is expired for several seconds', () => {
+        beforeEach(() => {
+          mocks.$store.state.tokenTime = setTokenTime(-60)
+          wrapper = Wrapper()
+        })
+
+        it('has value for remaining seconds equal 0', () => {
+          expect(wrapper.tokenExpiresInSeconds === 0)
+        })
+
+        it('emits logout', () => {
+          expect(wrapper.emitted('logout')).toBeTruthy()
+        })
+      })
+
+      describe('token time less than 75 seconds', () => {
+        beforeEach(() => {
+          mocks.$store.state.tokenTime = setTokenTime(60)
+          jest.useFakeTimers()
+          wrapper = Wrapper()
+          spy = jest.spyOn(wrapper.vm.$bvModal, 'msgBoxConfirm')
+          spy.mockImplementation(() => Promise.resolve(true))
+        })
+
+        it('sets the timer to 1000', () => {
+          expect(wrapper.vm.timers.tokenExpires.time).toBe(1000)
+        })
+
+        it.skip('opens the modal', () => {
+          jest.advanceTimersByTime(1000)
+          jest.advanceTimersByTime(1000)
+          jest.advanceTimersByTime(1000)
+          jest.advanceTimersByTime(1000)
+          expect(spy).toBeCalled()
+        })
+      })
+    })
+  })
+})
diff --git a/frontend/src/components/SessionLogoutTimeout.vue b/frontend/src/components/SessionLogoutTimeout.vue
new file mode 100644
index 000000000..1ebff752a
--- /dev/null
+++ b/frontend/src/components/SessionLogoutTimeout.vue
@@ -0,0 +1,103 @@
+<template>
+  <div class="session-logout-timeout">
+    <b-modal
+      id="modalSessionTimeOut"
+      class="bg-variant-danger"
+      hide-header-close
+      hide-header
+      hide-footer
+      no-close-on-backdrop
+    >
+      <b-card header-tag="header" footer-tag="footer">
+        <b-card-text>
+          <div class="p-3 h2">{{ $t('session.warningText') }}</div>
+          <div class="p-3">
+            {{ $t('session.lightText') }}
+          </div>
+          <div class="p-3 h2 text-warning">
+            {{ $t('session.logoutIn') }}
+            <b>{{ tokenExpiresInSeconds }}</b>
+            {{ $t('time.seconds') }}
+          </div>
+        </b-card-text>
+        <b-row>
+          <b-col class="text-center">
+            <b-button size="lg" variant="success" @click="handleOk">
+              {{ $t('session.extend') }}
+            </b-button>
+          </b-col>
+        </b-row>
+      </b-card>
+      <template #modal-footer>
+        <b-button size="sm" variant="danger" @click="$emit('logout')">
+          {{ $t('navigation.logout') }}
+        </b-button>
+        <b-button size="lg" variant="success" @click="handleOk">
+          {{ $t('session.extend') }}
+        </b-button>
+      </template>
+    </b-modal>
+  </div>
+</template>
+<script>
+import { verifyLogin } from '@/graphql/queries'
+
+export default {
+  name: 'SessionLogoutTimeout',
+  data() {
+    return {
+      now: new Date().getTime(),
+    }
+  },
+  timers: {
+    tokenExpires: {
+      time: 15000,
+      autostart: true,
+      repeat: true,
+      immediate: true,
+    },
+  },
+  methods: {
+    tokenExpires() {
+      this.now = new Date().getTime()
+      if (this.tokenExpiresInSeconds < 75 && this.timers.tokenExpires.time !== 1000) {
+        this.timers.tokenExpires.time = 1000
+        this.$timer.restart('tokenExpires')
+        this.$bvModal.show('modalSessionTimeOut')
+      }
+      if (this.tokenExpiresInSeconds === 0) {
+        this.$timer.stop('tokenExpires')
+        this.$emit('logout')
+      }
+    },
+    handleOk(bvModalEvent) {
+      bvModalEvent.preventDefault()
+      this.$apollo
+        .query({
+          query: verifyLogin,
+          fetchPolicy: 'network-only',
+        })
+        .then((result) => {
+          this.timers.tokenExpires.time = 15000
+          this.$timer.restart('tokenExpires')
+          this.$bvModal.hide('modalSessionTimeOut')
+        })
+        .catch(() => {
+          this.$timer.stop('tokenExpires')
+          this.$emit('logout')
+        })
+    },
+  },
+  computed: {
+    tokenExpiresInSeconds() {
+      const remainingSecs = Math.floor(
+        (new Date(this.$store.state.tokenTime * 1000).getTime() - this.now) / 1000,
+      )
+      return remainingSecs <= 0 ? 0 : remainingSecs
+    },
+  },
+  beforeDestroy() {
+    this.$timer.stop('tokenExpires')
+  },
+}
+</script>
diff --git a/frontend/src/components/TransactionLinks/TransactionLink.spec.js b/frontend/src/components/TransactionLinks/TransactionLink.spec.js
index ad9e4860e..d06f0f726 100644
--- a/frontend/src/components/TransactionLinks/TransactionLink.spec.js
+++ b/frontend/src/components/TransactionLinks/TransactionLink.spec.js
@@ -9,15 +9,16 @@ const mockAPIcall = jest.fn()
 const navigatorClipboardMock = jest.fn()
 
 const mocks = {
-  $i18n: {
-    locale: 'en',
-  },
   $t: jest.fn((t) => t),
   $d: jest.fn((d) => d),
-  $tc: jest.fn((tc) => tc),
   $apollo: {
     mutate: mockAPIcall,
   },
+  $store: {
+    state: {
+      firstName: 'Testy',
+    },
+  },
 }
 
 const propsData = {
@@ -77,7 +78,7 @@ describe('TransactionLink', () => {
           navigator.clipboard = navigatorClipboard
         })
 
-        describe('copy with success', () => {
+        describe('copy link with success', () => {
           beforeEach(async () => {
             navigatorClipboardMock.mockResolvedValue()
             await wrapper.find('.test-copy-link .dropdown-item').trigger('click')
@@ -92,6 +93,47 @@ describe('TransactionLink', () => {
             expect(toastSuccessSpy).toBeCalledWith('gdd_per_link.link-copied')
           })
         })
+
+        describe('copy link and text with success', () => {
+          beforeEach(async () => {
+            navigatorClipboardMock.mockResolvedValue()
+            await wrapper.find('.test-copy-text .dropdown-item').trigger('click')
+          })
+
+          it('should call clipboard.writeText', () => {
+            expect(navigator.clipboard.writeText).toHaveBeenCalledWith(
+              'http://localhost/redeem/c00000000c000000c0000\n' +
+                'Testy transaction-link.send_you 75 Gradido.\n' +
+                '"Katzenauge, Eulenschrei, was verschwunden komm herbei!"\n' +
+                'gdd_per_link.credit-your-gradido gdd_per_link.validUntilDate',
+            )
+          })
+          it('toasts success message', () => {
+            expect(toastSuccessSpy).toBeCalledWith('gdd_per_link.link-and-text-copied')
+          })
+        })
+
+        describe('copy link with error', () => {
+          beforeEach(async () => {
+            navigatorClipboardMock.mockRejectedValue()
+            await wrapper.find('.test-copy-link .dropdown-item').trigger('click')
+          })
+
+          it('toasts an error', () => {
+            expect(toastErrorSpy).toBeCalledWith('gdd_per_link.not-copied')
+          })
+        })
+
+        describe('copy link and text with error', () => {
+          beforeEach(async () => {
+            navigatorClipboardMock.mockRejectedValue()
+            await wrapper.find('.test-copy-text .dropdown-item').trigger('click')
+          })
+
+          it('toasts an error', () => {
+            expect(toastErrorSpy).toBeCalledWith('gdd_per_link.not-copied')
+          })
+        })
       })
 
       describe('qr code modal', () => {
diff --git a/frontend/src/components/TransactionLinks/TransactionLink.vue b/frontend/src/components/TransactionLinks/TransactionLink.vue
index c7b7682ec..76f705e35 100644
--- a/frontend/src/components/TransactionLinks/TransactionLink.vue
+++ b/frontend/src/components/TransactionLinks/TransactionLink.vue
@@ -18,9 +18,17 @@
                 <b-icon icon="three-dots-vertical"></b-icon>
               </template>
 
-              <b-dropdown-item v-if="validLink" class="test-copy-link" @click="copy">
+              <b-dropdown-item v-if="validLink" class="test-copy-link" @click="copyLink">
                 <b-icon icon="clipboard"></b-icon>
-                {{ $t('gdd_per_link.copy') }}
+                {{ $t('gdd_per_link.copy-link') }}
+              </b-dropdown-item>
+              <b-dropdown-item
+                v-if="validLink"
+                class="test-copy-text pt-3"
+                @click="copyLinkWithText"
+              >
+                <b-icon icon="clipboard-plus"></b-icon>
+                {{ $t('gdd_per_link.copy-link-with-text') }}
               </b-dropdown-item>
               <b-dropdown-item
                 v-if="validLink"
@@ -68,9 +76,11 @@ import MemoRow from '../TransactionRows/MemoRow'
 import DateRow from '../TransactionRows/DateRow'
 import DecayRow from '../TransactionRows/DecayRow'
 import FigureQrCode from '@/components/QrCode/FigureQrCode.vue'
+import { copyLinks } from '../../mixins/copyLinks'
 
 export default {
   name: 'TransactionLink',
+  mixins: [copyLinks],
   components: {
     TypeIcon,
     AmountAndNameRow,
@@ -80,25 +90,10 @@ export default {
     FigureQrCode,
   },
   props: {
-    amount: { type: String, required: true },
-    link: { type: String, required: true },
     holdAvailableAmount: { type: String, required: true },
     id: { type: Number, required: true },
-    memo: { type: String, required: true },
-    validUntil: { type: String, required: true },
   },
   methods: {
-    copy() {
-      navigator.clipboard
-        .writeText(this.link)
-        .then(() => {
-          this.toastSuccess(this.$t('gdd_per_link.link-copied'))
-        })
-        .catch(() => {
-          this.$bvModal.show('modalPopoverCopyError' + this.id)
-          this.toastError(this.$t('gdd_per_link.not-copied'))
-        })
-    },
     deleteLink() {
       this.$bvModal.msgBoxConfirm(this.$t('gdd_per_link.delete-the-link')).then(async (value) => {
         if (value)
diff --git a/frontend/src/graphql/mutations.js b/frontend/src/graphql/mutations.js
index 9b035cba6..959bdefc3 100644
--- a/frontend/src/graphql/mutations.js
+++ b/frontend/src/graphql/mutations.js
@@ -74,6 +74,9 @@ export const createTransactionLink = gql`
   mutation($amount: Decimal!, $memo: String!) {
     createTransactionLink(amount: $amount, memo: $memo) {
       link
+      amount
+      memo
+      validUntil
     }
   }
 `
@@ -89,3 +92,33 @@ export const redeemTransactionLink = gql`
     redeemTransactionLink(code: $code)
   }
 `
+
+export const createContribution = gql`
+  mutation($creationDate: String!, $memo: String!, $amount: Decimal!) {
+    createContribution(creationDate: $creationDate, memo: $memo, amount: $amount) {
+      amount
+      memo
+    }
+  }
+`
+
+export const updateContribution = gql`
+  mutation($contributionId: Int!, $amount: Decimal!, $memo: String!, $creationDate: String!) {
+    updateContribution(
+      contributionId: $contributionId
+      amount: $amount
+      memo: $memo
+      creationDate: $creationDate
+    ) {
+      id
+      amount
+      memo
+    }
+  }
+`
+
+export const deleteContribution = gql`
+  mutation($id: Int!) {
+    deleteContribution(id: $id)
+  }
+`
diff --git a/frontend/src/graphql/queries.js b/frontend/src/graphql/queries.js
index c6c847868..97c51df9e 100644
--- a/frontend/src/graphql/queries.js
+++ b/frontend/src/graphql/queries.js
@@ -13,6 +13,7 @@ export const login = gql`
       hasElopage
       publisherId
       isAdmin
+      creation
     }
   }
 `
@@ -30,6 +31,7 @@ export const verifyLogin = gql`
       hasElopage
       publisherId
       isAdmin
+      creation
     }
   }
 `
@@ -114,17 +116,33 @@ export const queryOptIn = gql`
 export const queryTransactionLink = gql`
   query($code: String!) {
     queryTransactionLink(code: $code) {
-      id
-      amount
-      memo
-      createdAt
-      validUntil
-      redeemedAt
-      deletedAt
-      user {
-        firstName
-        publisherId
-        email
+      ... on TransactionLink {
+        id
+        amount
+        memo
+        createdAt
+        validUntil
+        redeemedAt
+        deletedAt
+        user {
+          firstName
+          publisherId
+          email
+        }
+      }
+      ... on ContributionLink {
+        id
+        validTo
+        validFrom
+        amount
+        name
+        memo
+        cycle
+        createdAt
+        code
+        link
+        deletedAt
+        maxAmountPerMonth
       }
     }
   }
@@ -158,4 +176,51 @@ export const listContributionLinks = gql`
       maxAmount
     }
   }
+ `
+ 
+export const listContributions = gql`
+  query(
+    $currentPage: Int = 1
+    $pageSize: Int = 25
+    $order: Order = DESC
+    $filterConfirmed: Boolean = false
+  ) {
+    listContributions(
+      currentPage: $currentPage
+      pageSize: $pageSize
+      order: $order
+      filterConfirmed: $filterConfirmed
+    ) {
+      contributionCount
+      contributionList {
+        id
+        amount
+        memo
+        createdAt
+        contributionDate
+        confirmedAt
+        confirmedBy
+        deletedAt
+      }
+    }
+  }
+`
+
+export const listAllContributions = gql`
+  query($currentPage: Int = 1, $pageSize: Int = 25, $order: Order = DESC) {
+    listAllContributions(currentPage: $currentPage, pageSize: $pageSize, order: $order) {
+      contributionCount
+      contributionList {
+        id
+        firstName
+        lastName
+        amount
+        memo
+        createdAt
+        contributionDate
+        confirmedAt
+        confirmedBy
+      }
+    }
+  }
 `
diff --git a/frontend/src/i18n.js b/frontend/src/i18n.js
index f4f969008..3136c6d80 100644
--- a/frontend/src/i18n.js
+++ b/frontend/src/i18n.js
@@ -75,6 +75,19 @@ const dateTimeFormats = {
       hour: 'numeric',
       minute: 'numeric',
     },
+    monthShort: {
+      month: 'short',
+    },
+    month: {
+      month: 'long',
+    },
+    year: {
+      year: 'numeric',
+    },
+    monthAndYear: {
+      month: 'long',
+      year: 'numeric',
+    },
   },
   de: {
     short: {
@@ -90,6 +103,19 @@ const dateTimeFormats = {
       hour: 'numeric',
       minute: 'numeric',
     },
+    monthShort: {
+      month: 'short',
+    },
+    month: {
+      month: 'long',
+    },
+    year: {
+      year: 'numeric',
+    },
+    monthAndYear: {
+      month: 'long',
+      year: 'numeric',
+    },
   },
 }
 
diff --git a/frontend/src/layouts/AuthLayout.spec.js b/frontend/src/layouts/AuthLayout.spec.js
index 2246793d5..30c858ea5 100644
--- a/frontend/src/layouts/AuthLayout.spec.js
+++ b/frontend/src/layouts/AuthLayout.spec.js
@@ -35,9 +35,10 @@ describe('AuthLayout', () => {
     beforeEach(() => {
       wrapper = Wrapper()
     })
+
     describe('Mobile Version Start', () => {
       beforeEach(() => {
-        wrapper.vm.mobileStart = true
+        wrapper.findComponent({ name: 'AuthMobileStart' }).vm.$emit('set-mobile-start', true)
       })
 
       it('has Component AuthMobileStart', () => {
diff --git a/frontend/src/layouts/AuthLayout.vue b/frontend/src/layouts/AuthLayout.vue
index c886fd7f9..46f58a4a2 100644
--- a/frontend/src/layouts/AuthLayout.vue
+++ b/frontend/src/layouts/AuthLayout.vue
@@ -13,9 +13,6 @@
           <auth-carousel class="carousel" />
         </div>
         <div class="bg-txt-box position-relative d-none d-lg-block text-center align-self-center">
-          <div class="h0 text-white">{{ $t('auth.left.gratitude') }}</div>
-          <div class="h1 text-white">{{ $t('auth.left.newCurrency') }}</div>
-          <div class="h2 text-white">{{ $t('auth.left.oneAnotherNature') }}</div>
           <b-link :href="`https://gradido.net/${$i18n.locale}`" target="_blank">
             <b-button variant="gradido">
               {{ $t('auth.left.learnMore') }}
@@ -31,10 +28,10 @@
                 <auth-navbar-small />
               </b-col>
             </b-row>
-            <b-row class="mt-5 pl-2 pl-md-0 pl-lg-0">
-              <b-col cols="9">
-                <div class="h1 mb--2">{{ $t('welcome') }}</div>
-                <div class="h1 mb-0">{{ $t('WelcomeBy', { name: communityName }) }}</div>
+            <b-row class="mt-0 mt-md-5 pl-2 pl-md-0 pl-lg-0">
+              <b-col lg="9" md="9" sm="12">
+                <div class="mb--2">{{ $t('welcome') }}</div>
+                <div class="h1 mb-0">{{ communityName }}</div>
                 <div class="mb-0">{{ $t('1000thanks') }}</div>
               </b-col>
               <b-col cols="3" class="text-right d-none d-sm-none d-md-inline">
@@ -150,20 +147,10 @@ export default {
 }
 
 .bg-txt-box {
-  margin-top: 317px;
+  margin-top: 520px;
   text-shadow: 2px 2px 8px #000000;
   max-width: 733px;
 }
-.bg-txt-box > .h0 {
-  font-size: 4em;
-  text-shadow: -2px -2px -8px #e4a907;
-}
-
-.bg-txt-box .h1,
-.bg-txt-box .h2 {
-  font-size: 1.5em;
-  text-shadow: -2px -2px -8px #e4a907;
-}
 
 .bg-img {
   border-radius: 0% 50% 70% 0% / 50% 70% 70% 50%;
diff --git a/frontend/src/layouts/DashboardLayout.vue b/frontend/src/layouts/DashboardLayout.vue
index cd8794c40..8e778ab01 100755
--- a/frontend/src/layouts/DashboardLayout.vue
+++ b/frontend/src/layouts/DashboardLayout.vue
@@ -32,6 +32,7 @@
           </fade-transition>
         </div>
         <content-footer v-if="!$route.meta.hideFooter"></content-footer>
+        <session-logout-timeout @logout="logout"></session-logout-timeout>
       </div>
     </div>
   </div>
@@ -39,6 +40,7 @@
 <script>
 import Navbar from '@/components/Menu/Navbar.vue'
 import Sidebar from '@/components/Menu/Sidebar.vue'
+import SessionLogoutTimeout from '@/components/SessionLogoutTimeout.vue'
 import { logout, transactionsQuery } from '@/graphql/queries'
 import ContentFooter from '@/components/ContentFooter.vue'
 import { FadeTransition } from 'vue2-transitions'
@@ -49,6 +51,7 @@ export default {
   components: {
     Navbar,
     Sidebar,
+    SessionLogoutTimeout,
     ContentFooter,
     FadeTransition,
   },
diff --git a/frontend/src/locales/de.json b/frontend/src/locales/de.json
index ead5cfff8..d5fb21bc9 100644
--- a/frontend/src/locales/de.json
+++ b/frontend/src/locales/de.json
@@ -6,12 +6,15 @@
   "advanced-calculation": "Vorausberechnung",
   "auth": {
     "left": {
+      "dignity": "Würde",
+      "donation": "Gabe",
       "gratitude": "Dankbarkeit",
       "hasAccount": "Du hast schon einen Account?",
       "hereLogin": "Hier Anmelden",
       "learnMore": "Erfahre mehr …",
-      "newCurrency": "Die neue Währung",
-      "oneAnotherNature": "FÜR EINANDER, FÜR ALLE, FÜR DIE NATUR"
+      "oneDignity": "Wir schenken einander und danken mit Gradido.",
+      "oneDonation": "Du bist ein Geschenk für die Gemeinschaft. 1000 Dank, weil du bei uns bist.",
+      "oneGratitude": "Für einander, für alle Menschen, für die Natur."
     },
     "navbar": {
       "aboutGradido": "Über Gradido"
@@ -29,8 +32,40 @@
     "openContributionLinkText": "Folgende automatische Schöpfungen werden zur Zeit durch die Gemeinschaft '{_name_}' bereitgestellt.",
     "other-communities": "Weitere Gemeinschaften",
     "statistic": "Statistik",
+    "myContributions": "Meine Beiträge zum Gemeinwohl",
+    "other-communities": "Weitere Gemeinschaften",
+    "submitContribution": "Beitrag einreichen",
     "switch-to-this-community": "zu dieser Gemeinschaft wechseln"
   },
+  "contribution": {
+    "activity": "Tätigkeit",
+    "alert": {
+      "communityNoteList": "Hier findest du alle eingereichten und bestätigten Beiträge von allen Mitgliedern aus dieser Gemeinschaft.",
+      "confirm": "bestätigt",
+      "myContributionNoteList": "Eingereichte Beiträge, die noch nicht bestätigt wurden, kannst du jederzeit bearbeiten oder löschen.",
+      "myContributionNoteSupport": "Es wird bald an dieser Stelle die Möglichkeit geben das ein Dialog zwischen Moderatoren und dir stattfinden kann. Solltest du jetzt Probleme haben bitte nimm Kontakt mit dem Support auf.",
+      "pending": "Eingereicht und wartet auf Bestätigung",
+      "rejected": "abgelehnt"
+    },
+    "date": "Beitrag für:",
+    "delete": "Beitrag löschen! Bist du sicher?",
+    "deleted": "Der Beitrag wurde gelöscht! Wird aber sichtbar bleiben.",
+    "formText": {
+      "bringYourTalentsTo": "Bring dich mit deinen Talenten in die Gemeinschaft ein! Dein freiwilliges Engagement honorieren wir mit 20 GDD pro Stunde bis maximal 1.000 GDD im Monat.",
+      "describeYourCommunity": "Beschreibe deine Gemeinwohl-Tätigkeit mit Angabe der Stunden und trage einen Betrag von 20 GDD pro Stunde ein! Nach Bestätigung durch einen Moderator wird der Betrag deinem Konto gutgeschrieben.",
+      "maxGDDforMonth": "Du kannst für den ausgewählten Monat nur noch maximal {amount} GDD einreichen.",
+      "openAmountForMonth": "Für <b>{monthAndYear}</b> kannst du noch <b>{creation}</b> GDD einreichen.",
+      "yourContribution": "Dein Beitrag zum Gemeinwohl"
+    },
+    "noDateSelected": "Wähle irgendein Datum im Monat",
+    "selectDate": "Wann war dein Beitrag?",
+    "submit": "Einreichen",
+    "submitted": "Der Beitrag wurde eingereicht.",
+    "updated": "Der Beitrag wurde geändert."
+  },
+  "contribution-link": {
+    "thanksYouWith": "dankt dir mit"
+  },
   "decay": {
     "before_startblock_transaction": "Diese Transaktion beinhaltet keine Vergänglichkeit.",
     "calculation_decay": "Berechnung der Vergänglichkeit",
@@ -43,7 +78,7 @@
     "Starting_block_decay": "Startblock Vergänglichkeit",
     "total": "Gesamt",
     "types": {
-      "created": "Geschöpft",
+      "creation": "Geschöpft",
       "noDecay": "Keine Vergänglichkeit",
       "receive": "Empfangen",
       "send": "Gesendet"
@@ -59,8 +94,7 @@
     "no-transactionlist": "Es gab leider einen Fehler. Es wurden keine Transaktionen vom Server übermittelt.",
     "no-user": "Kein Benutzer mit diesen Anmeldedaten.",
     "session-expired": "Die Sitzung wurde aus Sicherheitsgründen beendet.",
-    "unknown-error": "Unbekanter Fehler: ",
-    "user-already-exists": "Ein Benutzer mit diesen Daten existiert bereits."
+    "unknown-error": "Unbekannter Fehler: "
   },
   "followUs": "folge uns:",
   "footer": {
@@ -78,12 +112,12 @@
     "amount": "Betrag",
     "at": "am",
     "cancel": "Abbrechen",
+    "change": "Ändern",
     "check_now": "Jetzt prüfen",
     "close": "Schließen",
     "current_balance": "Aktueller Kontostand",
     "date": "Datum",
     "description": "Beschreibung",
-    "edit": "Bearbeiten",
     "email": "E-Mail",
     "firstname": "Vorname",
     "from": "Von",
@@ -123,8 +157,10 @@
   "GDD": "GDD",
   "gdd_per_link": {
     "choose-amount": "Wähle einen Betrag aus, welchen du per Link versenden möchtest. Du kannst auch noch eine Nachricht eintragen. Beim Klick „Jetzt generieren“ wird ein Link erstellt, den du versenden kannst.",
-    "copy": "kopieren",
+    "copy-link": "Link kopieren",
+    "copy-link-with-text": "Link und Text kopieren",
     "created": "Der Link wurde erstellt!",
+    "credit-your-gradido": "Damit die Gradido gutgeschrieben werden können, klicke auf den Link!",
     "decay-14-day": "Vergänglichkeit für 14 Tage",
     "delete-the-link": "Den Link löschen?",
     "deleted": "Der Link wurde gelöscht!",
@@ -132,6 +168,7 @@
     "has-account": "Du besitzt bereits ein Gradido Konto?",
     "header": "Gradidos versenden per Link",
     "isFree": "Gradido ist weltweit kostenfrei.",
+    "link-and-text-copied": "Der Link und deine Nachricht wurden in die Zwischenablage kopiert. Du kannst ihn jetzt in eine E-Mail oder Nachricht einfügen.",
     "link-copied": "Link wurde in die Zwischenablage kopiert. Du kannst ihn jetzt in eine E-Mail oder Nachricht einfügen.",
     "link-deleted": "Der Link wurde am {date} gelöscht.",
     "link-expired": "Der Link ist nicht mehr gültig. Die Gültigkeit ist am {date} abgelaufen.",
@@ -148,7 +185,8 @@
     "redeemed-title": "eingelöst",
     "to-login": "Log dich ein",
     "to-register": "Registriere ein neues Konto.",
-    "validUntil": "Gültig bis"
+    "validUntil": "Gültig bis",
+    "validUntilDate": "Der Link ist bis zum {date} gültig."
   },
   "gdt": {
     "calculation": "Berechnung der Gradido Transform",
@@ -173,7 +211,6 @@
   "math": {
     "aprox": "~",
     "equal": "=",
-    "exclaim": "!",
     "minus": "−",
     "pipe": "|"
   },
@@ -189,6 +226,7 @@
   },
   "navigation": {
     "admin_area": "Adminbereich",
+    "community": "Gemeinschaft",
     "logout": "Abmelden",
     "members_area": "Mitgliederbereich",
     "overview": "Übersicht",
@@ -200,6 +238,12 @@
   "qrCode": "QR Code",
   "send_gdd": "GDD versenden",
   "send_per_link": "GDD versenden per Link",
+  "session": {
+    "extend": "Angemeldet bleiben",
+    "lightText": "Wenn du länger als 10 Minuten keine Aktion getätigt hast, wirst du aus Sicherheitsgründen abgemeldet.",
+    "logoutIn": "Abmelden in ",
+    "warningText": "Bist du noch da?"
+  },
   "settings": {
     "language": {
       "changeLanguage": "Sprache ändern",
@@ -261,9 +305,10 @@
     "days": "Tage",
     "hours": "Stunden",
     "minutes": "Minuten",
+    "month": "Monat",
     "months": "Monate",
     "seconds": "Sekunden",
-    "year": "Jahre"
+    "years": "Jahr"
   },
   "transaction": {
     "gdd-text": "Gradido Transaktionen",
@@ -277,6 +322,5 @@
     "send_you": "sendet dir"
   },
   "via_link": "über einen Link",
-  "welcome": "Willkommen",
-  "WelcomeBy": "bei {name}"
+  "welcome": "Willkommen in der Gemeinschaft"
 }
diff --git a/frontend/src/locales/en.json b/frontend/src/locales/en.json
index fabd4c621..202420b32 100644
--- a/frontend/src/locales/en.json
+++ b/frontend/src/locales/en.json
@@ -6,12 +6,15 @@
   "advanced-calculation": "Advanced calculation",
   "auth": {
     "left": {
+      "dignity": "Dignity",
+      "donation": "Donation",
       "gratitude": "Gratitude",
       "hasAccount": "You already have an account?",
       "hereLogin": "Log in here",
       "learnMore": "Learn more …",
-      "newCurrency": "The new currency",
-      "oneAnotherNature": "FOR EACH OTHER, FOR ALL, FOR NATURE"
+      "oneDignity": "We gift to each other and give thanks with Gradido.",
+      "oneDonation": "You are a gift for the community. 1000 thanks because you are with us.",
+      "oneGratitude": "For each other, for all people, for nature."
     },
     "navbar": {
       "aboutGradido": "About Gradido"
@@ -29,8 +32,40 @@
     "openContributionLinkText": "The following automatic creations are currently provided by the '{_name_}' community.",
     "other-communities": "Other communities",
     "statistic": "Statistics",
+    "myContributions": "My contributions to the common good",
+    "other-communities": "Other communities",
+    "submitContribution": "Submit contribution",
     "switch-to-this-community": "Switch to this community"
   },
+  "contribution": {
+    "activity": "Activity",
+    "alert": {
+      "communityNoteList": "Here you will find all submitted and confirmed contributions from all members of this community.",
+      "confirm": "confirmed",
+      "myContributionNoteList": "You can edit or delete entries that have not yet been confirmed at any time.",
+      "myContributionNoteSupport": "Soon there will be the possibility for a dialogue between moderators and you. If you have any problems now, please contact the support.",
+      "pending": "Submitted and waiting for confirmation",
+      "rejected": "deleted"
+    },
+    "date": "Contribution for:",
+    "delete": "Delete Contribution! Are you sure?",
+    "deleted": "The contribution has been deleted! But it will remain visible.",
+    "formText": {
+      "bringYourTalentsTo": "Bring your talents to the community! Your voluntary commitment will be rewarded with 20 GDD per hour up to a maximum of 1,000 GDD per month.",
+      "describeYourCommunity": "Describe your community service activity with hours and enter an amount of 20 GDD per hour! After confirmation by a moderator, the amount will be credited to your account.",
+      "maxGDDforMonth": "You can only submit a maximum of {amount} GDD for the selected month.",
+      "openAmountForMonth": "For  <b>{monthAndYear}</b>, you can still submit <b>{creation}</b> GDD.",
+      "yourContribution": "Your contribution to the common good"
+    },
+    "noDateSelected": "Choose any date in the month",
+    "selectDate": "When was your contribution?",
+    "submit": "Submit",
+    "submitted": "The contribution was submitted.",
+    "updated": "The contribution was changed."
+  },
+  "contribution-link": {
+    "thanksYouWith": "thanks you with"
+  },
   "decay": {
     "before_startblock_transaction": "This transaction does not include decay.",
     "calculation_decay": "Calculation of Decay",
@@ -43,7 +78,7 @@
     "Starting_block_decay": "Starting Block Decay",
     "total": "Total",
     "types": {
-      "created": "Created",
+      "creation": "Created",
       "noDecay": "No Decay",
       "receive": "Received",
       "send": "Sent"
@@ -59,8 +94,7 @@
     "no-transactionlist": "Unfortunately, there was an error. No transactions have been sent from the server.",
     "no-user": "No user with this credentials.",
     "session-expired": "The session was closed for security reasons.",
-    "unknown-error": "Unknown error: ",
-    "user-already-exists": "A user with this data already exists."
+    "unknown-error": "Unknown error: "
   },
   "followUs": "follow us:",
   "footer": {
@@ -78,12 +112,12 @@
     "amount": "Amount",
     "at": "at",
     "cancel": "Cancel",
+    "change": "Change",
     "check_now": "Check now",
     "close": "Close",
     "current_balance": "Current Balance",
     "date": "Date",
     "description": "Description",
-    "edit": "Edit",
     "email": "Email",
     "firstname": "Firstname",
     "from": "from",
@@ -123,8 +157,10 @@
   "GDD": "GDD",
   "gdd_per_link": {
     "choose-amount": "Select an amount that you would like to send via link. You can also enter a message. Click 'Generate now' to create a link that you can share.",
-    "copy": "copy",
+    "copy-link": "Copy link",
+    "copy-link-with-text": "Copy link and text",
     "created": "Link was created!",
+    "credit-your-gradido": "For the Gradido to be credited, click on the link!",
     "decay-14-day": "Decay for 14 days",
     "delete-the-link": "Delete the link?",
     "deleted": "The link was deleted!",
@@ -132,6 +168,7 @@
     "has-account": "You already have a Gradido account?",
     "header": "Send Gradidos via link",
     "isFree": "Gradido is free of charge worldwide.",
+    "link-and-text-copied": "The link and your message have been copied to the clipboard. You can now include it in an email or message.",
     "link-copied": "Link has been copied to the clipboard. You can now paste it into an email or message.",
     "link-deleted": "The link was deleted on {date}.",
     "link-expired": "The link is no longer valid. The validity expired on {date}.",
@@ -148,7 +185,8 @@
     "redeemed-title": "redeemed",
     "to-login": "Log in",
     "to-register": "Register a new account.",
-    "validUntil": "Valid until"
+    "validUntil": "Valid until",
+    "validUntilDate": "The link is valid until {date}."
   },
   "gdt": {
     "calculation": "Calculation of Gradido Transform",
@@ -173,7 +211,6 @@
   "math": {
     "aprox": "~",
     "equal": "=",
-    "exclaim": "!",
     "minus": "−",
     "pipe": "|"
   },
@@ -189,6 +226,7 @@
   },
   "navigation": {
     "admin_area": "Admin Area",
+    "community": "Community",
     "logout": "Logout",
     "members_area": "Members area",
     "overview": "Overview",
@@ -200,6 +238,12 @@
   "qrCode": "QR Code",
   "send_gdd": "GDD send",
   "send_per_link": "GDD send via link",
+  "session": {
+    "extend": "Stay logged in",
+    "lightText": "If you have not performed any action for more than 10 minutes, you will be logged out for security reasons.",
+    "logoutIn": "Log out in ",
+    "warningText": "Are you still there?"
+  },
   "settings": {
     "language": {
       "changeLanguage": "Change language",
@@ -261,9 +305,10 @@
     "days": "Days",
     "hours": "Hours",
     "minutes": "Minutes",
+    "month": "Month",
     "months": "Months",
     "seconds": "Seconds",
-    "year": "Years"
+    "years": "Year"
   },
   "transaction": {
     "gdd-text": "Gradido Transactions",
@@ -277,6 +322,5 @@
     "send_you": "wants to send you"
   },
   "via_link": "via Link",
-  "welcome": "Welcome",
-  "WelcomeBy": "by {name}"
+  "welcome": "Welcome to the community"
 }
diff --git a/frontend/src/mixins/copyLinks.js b/frontend/src/mixins/copyLinks.js
new file mode 100644
index 000000000..415358c9b
--- /dev/null
+++ b/frontend/src/mixins/copyLinks.js
@@ -0,0 +1,44 @@
+export const copyLinks = {
+  props: {
+    link: { type: String, required: true },
+    amount: { type: String, required: true },
+    memo: { type: String, required: true },
+    validUntil: { type: String, required: true },
+  },
+  data() {
+    return {
+      canCopyLink: true,
+    }
+  },
+  methods: {
+    copyLink() {
+      navigator.clipboard
+        .writeText(this.link)
+        .then(() => {
+          this.toastSuccess(this.$t('gdd_per_link.link-copied'))
+        })
+        .catch(() => {
+          this.canCopyLink = false
+          this.toastError(this.$t('gdd_per_link.not-copied'))
+        })
+    },
+    copyLinkWithText() {
+      navigator.clipboard
+        .writeText(
+          `${this.link}
+${this.$store.state.firstName} ${this.$t('transaction-link.send_you')} ${this.amount} Gradido.
+"${this.memo}"
+${this.$t('gdd_per_link.credit-your-gradido')} ${this.$t('gdd_per_link.validUntilDate', {
+            date: this.$d(new Date(this.validUntil), 'short'),
+          })}`,
+        )
+        .then(() => {
+          this.toastSuccess(this.$t('gdd_per_link.link-and-text-copied'))
+        })
+        .catch(() => {
+          this.canCopyLink = false
+          this.toastError(this.$t('gdd_per_link.not-copied'))
+        })
+    },
+  },
+}
diff --git a/frontend/src/pages/Community.spec.js b/frontend/src/pages/Community.spec.js
new file mode 100644
index 000000000..b4aa43785
--- /dev/null
+++ b/frontend/src/pages/Community.spec.js
@@ -0,0 +1,408 @@
+import { mount } from '@vue/test-utils'
+import Community from './Community'
+import { toastErrorSpy, toastSuccessSpy } from '@test/testSetup'
+import { createContribution, updateContribution, deleteContribution } from '@/graphql/mutations'
+import { listContributions, listAllContributions, verifyLogin } from '@/graphql/queries'
+
+const localVue = global.localVue
+
+const mockStoreDispach = jest.fn()
+const apolloQueryMock = jest.fn()
+const apolloMutationMock = jest.fn()
+
+describe('Community', () => {
+  let wrapper
+
+  const mocks = {
+    $t: jest.fn((t) => t),
+    $d: jest.fn((d) => d),
+    $apollo: {
+      query: apolloQueryMock,
+      mutate: apolloMutationMock,
+    },
+    $store: {
+      dispatch: mockStoreDispach,
+      state: {
+        creation: ['1000', '1000', '1000'],
+      },
+    },
+    $i18n: {
+      locale: 'en',
+    },
+  }
+
+  const Wrapper = () => {
+    return mount(Community, {
+      localVue,
+      mocks,
+    })
+  }
+
+  describe('mount', () => {
+    beforeEach(() => {
+      apolloQueryMock.mockResolvedValue({
+        data: {
+          listContributions: {
+            contributionList: [
+              {
+                id: 1555,
+                amount: '200',
+                memo: 'Fleisig, fleisig am Arbeiten mein lieber Freund, 50 Zeichen sind viel',
+                createdAt: '2022-07-15T08:47:06.000Z',
+                deletedAt: null,
+                confirmedBy: null,
+                confirmedAt: null,
+              },
+            ],
+            contributionCount: 1,
+          },
+          listAllContributions: {
+            contributionList: [
+              {
+                id: 1555,
+                amount: '200',
+                memo: 'Fleisig, fleisig am Arbeiten mein lieber Freund, 50 Zeichen sind viel',
+                createdAt: '2022-07-15T08:47:06.000Z',
+                deletedAt: null,
+                confirmedBy: null,
+                confirmedAt: null,
+              },
+              {
+                id: 1556,
+                amount: '400',
+                memo: 'Ein anderer lieber Freund ist auch sehr felißig am Arbeiten!!!!',
+                createdAt: '2022-07-16T08:47:06.000Z',
+                deletedAt: null,
+                confirmedBy: null,
+                confirmedAt: null,
+              },
+            ],
+            contributionCount: 2,
+          },
+        },
+      })
+      wrapper = Wrapper()
+    })
+
+    it('has a DIV .community-page', () => {
+      expect(wrapper.find('div.community-page').exists()).toBe(true)
+    })
+
+    describe('tabs', () => {
+      it('has three tabs', () => {
+        expect(wrapper.findAll('div[role="tabpanel"]')).toHaveLength(3)
+      })
+
+      it('has first tab active by default', () => {
+        expect(wrapper.findAll('div[role="tabpanel"]').at(0).classes('active')).toBe(true)
+      })
+    })
+
+    describe('API calls after creation', () => {
+      it('emits update transactions', () => {
+        expect(wrapper.emitted('update-transactions')).toEqual([[0]])
+      })
+
+      it('queries list of own contributions', () => {
+        expect(apolloQueryMock).toBeCalledWith({
+          fetchPolicy: 'no-cache',
+          query: listContributions,
+          variables: {
+            currentPage: 1,
+            pageSize: 25,
+          },
+        })
+      })
+
+      it('queries list of all contributions', () => {
+        expect(apolloQueryMock).toBeCalledWith({
+          fetchPolicy: 'no-cache',
+          query: listAllContributions,
+          variables: {
+            currentPage: 1,
+            pageSize: 25,
+          },
+        })
+      })
+
+      describe('server response is error', () => {
+        beforeEach(() => {
+          jest.clearAllMocks()
+          apolloQueryMock.mockRejectedValue({ message: 'Ups' })
+          wrapper = Wrapper()
+        })
+
+        it('toasts two errors', () => {
+          expect(toastErrorSpy).toBeCalledTimes(2)
+          expect(toastErrorSpy).toBeCalledWith('Ups')
+        })
+      })
+    })
+
+    describe('set contrubtion', () => {
+      describe('with success', () => {
+        const now = new Date().toISOString()
+        beforeEach(async () => {
+          jest.clearAllMocks()
+          apolloMutationMock.mockResolvedValue({
+            data: {
+              createContribution: true,
+            },
+          })
+          await wrapper.setData({
+            form: {
+              id: null,
+              date: now,
+              memo: 'Mein Beitrag zur Gemeinschaft für diesen Monat ...',
+              amount: '200',
+            },
+          })
+          await wrapper.find('form').trigger('submit')
+        })
+
+        it('calls the create contribution mutation', () => {
+          expect(apolloMutationMock).toBeCalledWith({
+            fetchPolicy: 'no-cache',
+            mutation: createContribution,
+            variables: {
+              creationDate: now,
+              memo: 'Mein Beitrag zur Gemeinschaft für diesen Monat ...',
+              amount: '200',
+            },
+          })
+        })
+
+        it('toasts a success message', () => {
+          expect(toastSuccessSpy).toBeCalledWith('contribution.submitted')
+        })
+
+        it('updates the contribution list', () => {
+          expect(apolloQueryMock).toBeCalledWith({
+            fetchPolicy: 'no-cache',
+            query: listContributions,
+            variables: {
+              currentPage: 1,
+              pageSize: 25,
+            },
+          })
+        })
+
+        it('verifies the login (to get the new creations available)', () => {
+          expect(apolloQueryMock).toBeCalledWith({
+            query: verifyLogin,
+            fetchPolicy: 'network-only',
+          })
+        })
+
+        it('set all data to the default values)', () => {
+          expect(wrapper.vm.form.id).toBe(null)
+          expect(wrapper.vm.form.date).toBe('')
+          expect(wrapper.vm.form.memo).toBe('')
+          expect(wrapper.vm.form.amount).toBe('')
+        })
+      })
+
+      describe('with error', () => {
+        const now = new Date().toISOString()
+        beforeEach(async () => {
+          jest.clearAllMocks()
+          apolloMutationMock.mockRejectedValue({
+            message: 'Ouch!',
+          })
+          await wrapper.setData({
+            form: {
+              id: null,
+              date: now,
+              memo: 'Mein Beitrag zur Gemeinschaft für diesen Monat ...',
+              amount: '200',
+            },
+          })
+          await wrapper.find('form').trigger('submit')
+        })
+
+        it('toasts the error message', () => {
+          expect(toastErrorSpy).toBeCalledWith('Ouch!')
+        })
+      })
+    })
+
+    describe('update contrubtion', () => {
+      describe('with success', () => {
+        const now = new Date().toISOString()
+        beforeEach(async () => {
+          jest.clearAllMocks()
+          apolloMutationMock.mockResolvedValue({
+            data: {
+              updateContribution: true,
+            },
+          })
+          await wrapper
+            .findComponent({ name: 'ContributionForm' })
+            .vm.$emit('update-contribution', {
+              id: 2,
+              date: now,
+              memo: 'Mein Beitrag zur Gemeinschaft für diesen Monat ...',
+              amount: '400',
+            })
+        })
+
+        it('calls the update contribution mutation', () => {
+          expect(apolloMutationMock).toBeCalledWith({
+            fetchPolicy: 'no-cache',
+            mutation: updateContribution,
+            variables: {
+              contributionId: 2,
+              creationDate: now,
+              memo: 'Mein Beitrag zur Gemeinschaft für diesen Monat ...',
+              amount: '400',
+            },
+          })
+        })
+
+        it('toasts a success message', () => {
+          expect(toastSuccessSpy).toBeCalledWith('contribution.updated')
+        })
+
+        it('updates the contribution list', () => {
+          expect(apolloQueryMock).toBeCalledWith({
+            fetchPolicy: 'no-cache',
+            query: listContributions,
+            variables: {
+              currentPage: 1,
+              pageSize: 25,
+            },
+          })
+        })
+
+        it('verifies the login (to get the new creations available)', () => {
+          expect(apolloQueryMock).toBeCalledWith({
+            query: verifyLogin,
+            fetchPolicy: 'network-only',
+          })
+        })
+
+        it('set all data to the default values)', () => {
+          expect(wrapper.vm.form.id).toBe(null)
+          expect(wrapper.vm.form.date).toBe('')
+          expect(wrapper.vm.form.memo).toBe('')
+          expect(wrapper.vm.form.amount).toBe('')
+        })
+      })
+
+      describe('with error', () => {
+        const now = new Date().toISOString()
+        beforeEach(async () => {
+          jest.clearAllMocks()
+          apolloMutationMock.mockRejectedValue({
+            message: 'Oh No!',
+          })
+          await wrapper
+            .findComponent({ name: 'ContributionForm' })
+            .vm.$emit('update-contribution', {
+              id: 2,
+              date: now,
+              memo: 'Mein Beitrag zur Gemeinschaft für diesen Monat ...',
+              amount: '400',
+            })
+        })
+
+        it('toasts the error message', () => {
+          expect(toastErrorSpy).toBeCalledWith('Oh No!')
+        })
+      })
+    })
+
+    describe('delete contribution', () => {
+      let contributionListComponent
+
+      beforeEach(async () => {
+        await wrapper.setData({ tabIndex: 1 })
+        contributionListComponent = await wrapper.findComponent({ name: 'ContributionList' })
+      })
+
+      describe('with success', () => {
+        beforeEach(async () => {
+          jest.clearAllMocks()
+          apolloMutationMock.mockResolvedValue({
+            data: {
+              deleteContribution: true,
+            },
+          })
+          contributionListComponent.vm.$emit('delete-contribution', { id: 2 })
+        })
+
+        it('calls the API', () => {
+          expect(apolloMutationMock).toBeCalledWith({
+            fetchPolicy: 'no-cache',
+            mutation: deleteContribution,
+            variables: {
+              id: 2,
+            },
+          })
+        })
+
+        it('toasts a success message', () => {
+          expect(toastSuccessSpy).toBeCalledWith('contribution.deleted')
+        })
+
+        it('updates the contribution list', () => {
+          expect(apolloQueryMock).toBeCalledWith({
+            fetchPolicy: 'no-cache',
+            query: listContributions,
+            variables: {
+              currentPage: 1,
+              pageSize: 25,
+            },
+          })
+        })
+
+        it('verifies the login (to get the new creations available)', () => {
+          expect(apolloQueryMock).toBeCalledWith({
+            query: verifyLogin,
+            fetchPolicy: 'network-only',
+          })
+        })
+      })
+
+      describe('with error', () => {
+        beforeEach(async () => {
+          jest.clearAllMocks()
+          apolloMutationMock.mockRejectedValue({
+            message: 'Oh my god!',
+          })
+          contributionListComponent.vm.$emit('delete-contribution', { id: 2 })
+        })
+
+        it('toasts the error message', () => {
+          expect(toastErrorSpy).toBeCalledWith('Oh my god!')
+        })
+      })
+    })
+
+    describe('update contribution form', () => {
+      const now = new Date().toISOString()
+      beforeEach(async () => {
+        await wrapper.setData({ tabIndex: 1 })
+        await wrapper
+          .findComponent({ name: 'ContributionList' })
+          .vm.$emit('update-contribution-form', {
+            id: 2,
+            contributionDate: now,
+            memo: 'Mein Beitrag zur Gemeinschaft für diesen Monat ...',
+            amount: '400',
+          })
+      })
+
+      it('sets the form data to the new values', () => {
+        expect(wrapper.vm.form.id).toBe(2)
+        expect(wrapper.vm.form.date).toBe(now)
+        expect(wrapper.vm.form.memo).toBe('Mein Beitrag zur Gemeinschaft für diesen Monat ...')
+        expect(wrapper.vm.form.amount).toBe('400')
+      })
+
+      it('sets tab index back to 0', () => {
+        expect(wrapper.vm.tabIndex).toBe(0)
+      })
+    })
+  })
+})
diff --git a/frontend/src/pages/Community.vue b/frontend/src/pages/Community.vue
index 2ebc99381..e1c8c9683 100644
--- a/frontend/src/pages/Community.vue
+++ b/frontend/src/pages/Community.vue
@@ -54,5 +54,278 @@ export default {
       membersCount: '1203',
     }
   },
+  <div class="community-page">
+    <div>
+      <b-tabs v-model="tabIndex" content-class="mt-3" align="center">
+        <b-tab :title="$t('community.submitContribution')" active>
+          <contribution-form
+            @set-contribution="setContribution"
+            @update-contribution="updateContribution"
+            v-model="form"
+            :updateAmount="updateAmount"
+          />
+        </b-tab>
+        <b-tab :title="$t('community.myContributions')">
+          <div>
+            <b-alert show dismissible fade variant="secondary" class="text-dark">
+              <h4 class="alert-heading">{{ $t('community.myContributions') }}</h4>
+              <p>
+                {{ $t('contribution.alert.myContributionNoteList') }}
+              </p>
+              <ul class="h2">
+                <li>
+                  <b-icon icon="bell-fill" variant="primary"></b-icon>
+                  {{ $t('contribution.alert.pending') }}
+                </li>
+                <li>
+                  <b-icon icon="check" variant="success"></b-icon>
+                  {{ $t('contribution.alert.confirm') }}
+                </li>
+                <li>
+                  <b-icon icon="x-circle" variant="danger"></b-icon>
+                  {{ $t('contribution.alert.rejected') }}
+                </li>
+              </ul>
+              <hr />
+              <p class="mb-0">
+                {{ $t('contribution.alert.myContributionNoteSupport') }}
+              </p>
+            </b-alert>
+          </div>
+          <contribution-list
+            :items="items"
+            @update-list-contributions="updateListContributions"
+            @update-contribution-form="updateContributionForm"
+            @delete-contribution="deleteContribution"
+            :contributionCount="contributionCount"
+            :showPagination="true"
+            :pageSize="pageSize"
+          />
+        </b-tab>
+        <b-tab :title="$t('navigation.community')">
+          <b-alert show dismissible fade variant="secondary" class="text-dark">
+            <h4 class="alert-heading">{{ $t('navigation.community') }}</h4>
+            <p>
+              {{ $t('contribution.alert.communityNoteList') }}
+            </p>
+            <ul class="h2">
+              <li>
+                <b-icon icon="bell-fill" variant="primary"></b-icon>
+                {{ $t('contribution.alert.pending') }}
+              </li>
+              <li>
+                <b-icon icon="check" variant="success"></b-icon>
+                {{ $t('contribution.alert.confirm') }}
+              </li>
+            </ul>
+          </b-alert>
+          <contribution-list
+            :items="itemsAll"
+            @update-list-contributions="updateListAllContributions"
+            @update-contribution-form="updateContributionForm"
+            :contributionCount="contributionCountAll"
+            :showPagination="true"
+            :pageSize="pageSizeAll"
+          />
+        </b-tab>
+      </b-tabs>
+    </div>
+  </div>
+</template>
+<script>
+import ContributionForm from '@/components/Contributions/ContributionForm.vue'
+import ContributionList from '@/components/Contributions/ContributionList.vue'
+import { createContribution, updateContribution, deleteContribution } from '@/graphql/mutations'
+import { listContributions, listAllContributions, verifyLogin } from '@/graphql/queries'
+
+export default {
+  name: 'Community',
+  components: {
+    ContributionForm,
+    ContributionList,
+  },
+  data() {
+    return {
+      tabIndex: 0,
+      items: [],
+      itemsAll: [],
+      currentPage: 1,
+      pageSize: 25,
+      pageSizeAll: 25,
+      contributionCount: 0,
+      contributionCountAll: 0,
+      form: {
+        id: null,
+        date: '',
+        memo: '',
+        amount: '',
+      },
+      updateAmount: '',
+    }
+  },
+  methods: {
+    setContribution(data) {
+      this.$apollo
+        .mutate({
+          fetchPolicy: 'no-cache',
+          mutation: createContribution,
+          variables: {
+            creationDate: data.date,
+            memo: data.memo,
+            amount: data.amount,
+          },
+        })
+        .then((result) => {
+          this.toastSuccess(this.$t('contribution.submitted'))
+          this.updateListContributions({
+            currentPage: this.currentPage,
+            pageSize: this.pageSize,
+          })
+          this.updateListAllContributions({
+            currentPage: this.currentPage,
+            pageSize: this.pageSize,
+          })
+          this.verifyLogin()
+        })
+        .catch((err) => {
+          this.toastError(err.message)
+        })
+    },
+    updateContribution(data) {
+      this.$apollo
+        .mutate({
+          fetchPolicy: 'no-cache',
+          mutation: updateContribution,
+          variables: {
+            contributionId: data.id,
+            creationDate: data.date,
+            memo: data.memo,
+            amount: data.amount,
+          },
+        })
+        .then((result) => {
+          this.toastSuccess(this.$t('contribution.updated'))
+          this.updateListContributions({
+            currentPage: this.currentPage,
+            pageSize: this.pageSize,
+          })
+          this.updateListAllContributions({
+            currentPage: this.currentPage,
+            pageSize: this.pageSize,
+          })
+          this.verifyLogin()
+        })
+        .catch((err) => {
+          this.toastError(err.message)
+        })
+    },
+    deleteContribution(data) {
+      this.$apollo
+        .mutate({
+          fetchPolicy: 'no-cache',
+          mutation: deleteContribution,
+          variables: {
+            id: data.id,
+          },
+        })
+        .then((result) => {
+          this.toastSuccess(this.$t('contribution.deleted'))
+          this.updateListContributions({
+            currentPage: this.currentPage,
+            pageSize: this.pageSize,
+          })
+          this.updateListAllContributions({
+            currentPage: this.currentPage,
+            pageSize: this.pageSize,
+          })
+          this.verifyLogin()
+        })
+        .catch((err) => {
+          this.toastError(err.message)
+        })
+    },
+    updateListAllContributions(pagination) {
+      this.$apollo
+        .query({
+          fetchPolicy: 'no-cache',
+          query: listAllContributions,
+          variables: {
+            currentPage: pagination.currentPage,
+            pageSize: pagination.pageSize,
+          },
+        })
+        .then((result) => {
+          const {
+            data: { listAllContributions },
+          } = result
+          this.contributionCountAll = listAllContributions.contributionCount
+          this.itemsAll = listAllContributions.contributionList
+        })
+        .catch((err) => {
+          this.toastError(err.message)
+        })
+    },
+    updateListContributions(pagination) {
+      this.$apollo
+        .query({
+          fetchPolicy: 'no-cache',
+          query: listContributions,
+          variables: {
+            currentPage: pagination.currentPage,
+            pageSize: pagination.pageSize,
+          },
+        })
+        .then((result) => {
+          const {
+            data: { listContributions },
+          } = result
+          this.contributionCount = listContributions.contributionCount
+          this.items = listContributions.contributionList
+        })
+        .catch((err) => {
+          this.toastError(err.message)
+        })
+    },
+    verifyLogin() {
+      this.$apollo
+        .query({
+          query: verifyLogin,
+          fetchPolicy: 'network-only',
+        })
+        .then((result) => {
+          const {
+            data: { verifyLogin },
+          } = result
+          this.$store.dispatch('login', verifyLogin)
+        })
+        .catch(() => {
+          this.$emit('logout')
+        })
+    },
+    updateContributionForm(item) {
+      this.form.id = item.id
+      this.form.date = item.contributionDate
+      this.form.memo = item.memo
+      this.form.amount = item.amount
+      this.updateAmount = item.amount
+      this.tabIndex = 0
+    },
+    updateTransactions(pagination) {
+      this.$emit('update-transactions', pagination)
+    },
+  },
+  created() {
+    // verifyLogin is important at this point so that creation is updated on reload if they are deleted in a session in the admin area.
+    this.verifyLogin()
+    this.updateListContributions({
+      currentPage: this.currentPage,
+      pageSize: this.pageSize,
+    })
+    this.updateListAllContributions({
+      currentPage: this.currentPage,
+      pageSize: this.pageSize,
+    })
+    this.updateTransactions(0)
+  },
 }
 </script>
diff --git a/frontend/src/pages/Register.spec.js b/frontend/src/pages/Register.spec.js
index a9415de87..91e945c6a 100644
--- a/frontend/src/pages/Register.spec.js
+++ b/frontend/src/pages/Register.spec.js
@@ -139,24 +139,6 @@ describe('Register', () => {
           await flushPromises()
         }
 
-        describe('server sends back error "User already exists."', () => {
-          beforeEach(async () => {
-            await createError('GraphQL error: User already exists.')
-          })
-
-          it('shows no error message on the page', () => {
-            // don't show any error on the page! against boots
-            expect(wrapper.vm.showPageMessage).toBe(false)
-            expect(wrapper.find('.test-message-headline').exists()).toBe(false)
-            expect(wrapper.find('.test-message-subtitle').exists()).toBe(false)
-            expect(wrapper.find('.test-message-button').exists()).toBe(false)
-          })
-
-          it('toasts the error message', () => {
-            expect(toastErrorSpy).toBeCalledWith('error.user-already-exists')
-          })
-        })
-
         describe('server sends back error "Unknown error"', () => {
           beforeEach(async () => {
             await createError(' – Unknown error.')
diff --git a/frontend/src/pages/Register.vue b/frontend/src/pages/Register.vue
index f1bfad6d9..0ae316ae9 100755
--- a/frontend/src/pages/Register.vue
+++ b/frontend/src/pages/Register.vue
@@ -122,9 +122,6 @@ export default {
     getValidationState({ dirty, validated, valid = null }) {
       return dirty || validated ? valid : null
     },
-    commitStorePublisherId(val) {
-      this.$store.commit('publisherId', val)
-    },
     async onSubmit() {
       this.$apollo
         .mutate({
@@ -142,16 +139,7 @@ export default {
           this.showPageMessage = true
         })
         .catch((error) => {
-          let errorMessage
-          switch (error.message) {
-            case 'GraphQL error: User already exists.':
-              errorMessage = this.$t('error.user-already-exists')
-              break
-            default:
-              errorMessage = this.$t('error.unknown-error') + error.message
-              break
-          }
-          this.toastError(errorMessage)
+          this.toastError(this.$t('error.unknown-error') + error.message)
         })
     },
   },
diff --git a/frontend/src/pages/ResetPassword.vue b/frontend/src/pages/ResetPassword.vue
index d9bf1f891..ec7ae6811 100644
--- a/frontend/src/pages/ResetPassword.vue
+++ b/frontend/src/pages/ResetPassword.vue
@@ -88,7 +88,11 @@ export default {
             ? this.$t('message.checkEmail')
             : this.$t('message.reset')
           this.messageButtonText = this.$t('login')
-          this.messageButtonLinktTo = '/login'
+          if (this.$route.params.code) {
+            this.messageButtonLinktTo = `/login/${this.$route.params.code}`
+          } else {
+            this.messageButtonLinktTo = '/login'
+          }
         })
         .catch((error) => {
           let errorMessage
diff --git a/frontend/src/pages/Send.spec.js b/frontend/src/pages/Send.spec.js
index 47a30ff65..0738d9720 100644
--- a/frontend/src/pages/Send.spec.js
+++ b/frontend/src/pages/Send.spec.js
@@ -25,9 +25,11 @@ describe('Send', () => {
   const mocks = {
     $t: jest.fn((t) => t),
     $n: jest.fn((n) => String(n)),
+    $d: jest.fn((d) => d),
     $store: {
       state: {
         email: 'sender@example.org',
+        firstName: 'Testy',
       },
     },
     $apollo: {
@@ -160,11 +162,15 @@ describe('Send', () => {
     })
 
     describe('transaction form link', () => {
+      const now = new Date().toISOString()
       beforeEach(async () => {
         apolloMutationMock.mockResolvedValue({
           data: {
             createTransactionLink: {
               link: 'http://localhost/redeem/0123456789',
+              amount: '56.78',
+              memo: 'Make the best of the link!',
+              validUntil: now,
             },
           },
         })
@@ -228,18 +234,64 @@ describe('Send', () => {
             navigator.clipboard = navigatorClipboard
           })
 
-          describe('copy with success', () => {
+          describe('copy link with success', () => {
             beforeEach(async () => {
               navigatorClipboardMock.mockResolvedValue()
-              await wrapper.findAll('button').at(0).trigger('click')
+              await wrapper.findAll('button').at(1).trigger('click')
             })
 
+            it('should call clipboard.writeText', () => {
+              expect(navigator.clipboard.writeText).toHaveBeenCalledWith(
+                'http://localhost/redeem/0123456789',
+              )
+            })
             it('toasts success message', () => {
               expect(toastSuccessSpy).toBeCalledWith('gdd_per_link.link-copied')
             })
           })
 
-          describe('copy with error', () => {
+          describe('copy link with error', () => {
+            beforeEach(async () => {
+              navigatorClipboardMock.mockRejectedValue()
+              await wrapper.findAll('button').at(1).trigger('click')
+            })
+
+            it('toasts error message', () => {
+              expect(toastErrorSpy).toBeCalledWith('gdd_per_link.not-copied')
+            })
+          })
+        })
+
+        describe('copy link and text with success', () => {
+          const navigatorClipboard = navigator.clipboard
+          beforeAll(() => {
+            delete navigator.clipboard
+            navigator.clipboard = { writeText: navigatorClipboardMock }
+          })
+          afterAll(() => {
+            navigator.clipboard = navigatorClipboard
+          })
+
+          describe('copy link and text with success', () => {
+            beforeEach(async () => {
+              navigatorClipboardMock.mockResolvedValue()
+              await wrapper.findAll('button').at(0).trigger('click')
+            })
+
+            it('should call clipboard.writeText', () => {
+              expect(navigator.clipboard.writeText).toHaveBeenCalledWith(
+                'http://localhost/redeem/0123456789\n' +
+                  'Testy transaction-link.send_you 56.78 Gradido.\n' +
+                  '"Make the best of the link!"\n' +
+                  'gdd_per_link.credit-your-gradido gdd_per_link.validUntilDate',
+              )
+            })
+            it('toasts success message', () => {
+              expect(toastSuccessSpy).toBeCalledWith('gdd_per_link.link-and-text-copied')
+            })
+          })
+
+          describe('copy link and text with error', () => {
             beforeEach(async () => {
               navigatorClipboardMock.mockRejectedValue()
               await wrapper.findAll('button').at(0).trigger('click')
@@ -253,7 +305,7 @@ describe('Send', () => {
 
         describe('close button click', () => {
           beforeEach(async () => {
-            await wrapper.findAll('button').at(2).trigger('click')
+            await wrapper.findAll('button').at(3).trigger('click')
           })
 
           it('Shows the TransactionForm', () => {
diff --git a/frontend/src/pages/Send.vue b/frontend/src/pages/Send.vue
index cd5f8f572..74e2b0270 100644
--- a/frontend/src/pages/Send.vue
+++ b/frontend/src/pages/Send.vue
@@ -41,7 +41,13 @@
           ></transaction-result-send-error>
         </template>
         <template #transactionResultLink>
-          <transaction-result-link :link="link" @on-reset="onReset"></transaction-result-link>
+          <transaction-result-link
+            :link="link"
+            :amount="amount"
+            :memo="memo"
+            :validUntil="validUntil"
+            @on-reset="onReset"
+          ></transaction-result-link>
         </template>
       </gdd-send>
       <hr />
@@ -144,7 +150,15 @@ export default {
             })
             .then((result) => {
               this.$emit('set-tunneled-email', null)
-              this.link = result.data.createTransactionLink.link
+              const {
+                data: {
+                  createTransactionLink: { link, amount, memo, validUntil },
+                },
+              } = result
+              this.link = link
+              this.amount = amount
+              this.memo = memo
+              this.validUntil = validUntil
               this.transactionData = { ...EMPTY_TRANSACTION_DATA }
               this.currentTransactionStep = TRANSACTION_STEPS.transactionResultLink
               this.updateTransactions({})
diff --git a/frontend/src/pages/TransactionLink.spec.js b/frontend/src/pages/TransactionLink.spec.js
index abc86f0ef..b1bbd8950 100644
--- a/frontend/src/pages/TransactionLink.spec.js
+++ b/frontend/src/pages/TransactionLink.spec.js
@@ -24,6 +24,7 @@ const transactionLinkValidExpireDate = () => {
 apolloQueryMock.mockResolvedValue({
   data: {
     queryTransactionLink: {
+      __typename: 'TransactionLink',
       id: 92,
       amount: '22',
       memo: 'Abrakadabra drei, vier, fünf, sechs, hier steht jetzt ein Memotext! Hex hex ',
@@ -82,6 +83,7 @@ describe('TransactionLink', () => {
         variables: {
           code: 'some-code',
         },
+        fetchPolicy: 'no-cache',
       })
     })
 
@@ -90,6 +92,7 @@ describe('TransactionLink', () => {
         apolloQueryMock.mockResolvedValue({
           data: {
             queryTransactionLink: {
+              __typename: 'TransactionLink',
               id: 92,
               amount: '22',
               memo: 'Abrakadabra drei, vier, fünf, sechs, hier steht jetzt ein Memotext! Hex hex ',
@@ -120,6 +123,7 @@ describe('TransactionLink', () => {
         apolloQueryMock.mockResolvedValue({
           data: {
             queryTransactionLink: {
+              __typename: 'TransactionLink',
               id: 92,
               amount: '22',
               memo: 'Abrakadabra drei, vier, fünf, sechs, hier steht jetzt ein Memotext! Hex hex ',
@@ -150,6 +154,7 @@ describe('TransactionLink', () => {
         apolloQueryMock.mockResolvedValue({
           data: {
             queryTransactionLink: {
+              __typename: 'TransactionLink',
               id: 92,
               amount: '22',
               memo: 'Abrakadabra drei, vier, fünf, sechs, hier steht jetzt ein Memotext! Hex hex ',
@@ -177,9 +182,11 @@ describe('TransactionLink', () => {
 
     describe('no token in store', () => {
       beforeEach(() => {
+        mocks.$store.state.token = null
         apolloQueryMock.mockResolvedValue({
           data: {
             queryTransactionLink: {
+              __typename: 'TransactionLink',
               id: 92,
               amount: '22',
               memo: 'Abrakadabra drei, vier, fünf, sechs, hier steht jetzt ein Memotext! Hex hex ',
@@ -213,6 +220,7 @@ describe('TransactionLink', () => {
         apolloQueryMock.mockResolvedValue({
           data: {
             queryTransactionLink: {
+              __typename: 'TransactionLink',
               id: 92,
               amount: '22',
               memo: 'Abrakadabra drei, vier, fünf, sechs, hier steht jetzt ein Memotext! Hex hex ',
@@ -248,6 +256,7 @@ describe('TransactionLink', () => {
         apolloQueryMock.mockResolvedValue({
           data: {
             queryTransactionLink: {
+              __typename: 'TransactionLink',
               id: 92,
               amount: '22',
               memo: 'Abrakadabra drei, vier, fünf, sechs, hier steht jetzt ein Memotext! Hex hex ',
@@ -298,7 +307,7 @@ describe('TransactionLink', () => {
         })
 
         it('toasts a success message', () => {
-          expect(mocks.$t).toBeCalledWith('gdd_per_link.redeemed', { n: '22' })
+          expect(mocks.$t).toBeCalledWith('gdd_per_link.redeem')
           expect(toastSuccessSpy).toBeCalledWith('gdd_per_link.redeemed; ')
         })
 
diff --git a/frontend/src/pages/TransactionLink.vue b/frontend/src/pages/TransactionLink.vue
index 5fc20326e..57236b55c 100644
--- a/frontend/src/pages/TransactionLink.vue
+++ b/frontend/src/pages/TransactionLink.vue
@@ -1,18 +1,21 @@
 <template>
   <div class="show-transaction-link-informations">
-    <div class="text-center"><b-img :src="img" fluid alt="logo"></b-img></div>
     <b-container class="mt-4">
       <transaction-link-item :type="itemType">
         <template #LOGGED_OUT>
-          <redeem-logged-out v-bind="linkData" />
+          <redeem-logged-out :linkData="linkData" :isContributionLink="isContributionLink" />
         </template>
 
         <template #SELF_CREATOR>
-          <redeem-self-creator v-bind="linkData" />
+          <redeem-self-creator :linkData="linkData" />
         </template>
 
         <template #VALID>
-          <redeem-valid v-bind="linkData" @redeem-link="redeemLink" />
+          <redeem-valid
+            :linkData="linkData"
+            :isContributionLink="isContributionLink"
+            @redeem-link="redeemLink"
+          />
         </template>
 
         <template #TEXT>
@@ -44,6 +47,7 @@ export default {
     return {
       img: '/img/brand/green.png',
       linkData: {
+        __typename: 'TransactionLink',
         amount: '123.45',
         memo: 'memo',
         user: {
@@ -57,6 +61,7 @@ export default {
     setTransactionLinkInformation() {
       this.$apollo
         .query({
+          fetchPolicy: 'no-cache',
           query: queryTransactionLink,
           variables: {
             code: this.$route.params.code,
@@ -64,39 +69,47 @@ export default {
         })
         .then((result) => {
           this.linkData = result.data.queryTransactionLink
+          if (this.linkData.__typename === 'ContributionLink' && this.$store.state.token) {
+            this.mutationLink(this.linkData.amount)
+          }
         })
         .catch((err) => {
           this.toastError(err.message)
         })
     },
+    mutationLink(amount) {
+      this.$apollo
+        .mutate({
+          mutation: redeemTransactionLink,
+          variables: {
+            code: this.$route.params.code,
+          },
+        })
+        .then(() => {
+          this.toastSuccess(
+            this.$t('gdd_per_link.redeemed', {
+              n: amount,
+            }),
+          )
+          this.$router.push('/overview')
+        })
+        .catch((err) => {
+          this.toastError(err.message)
+          this.$router.push('/overview')
+        })
+    },
     redeemLink(amount) {
-      this.$bvModal.msgBoxConfirm(this.$t('gdd_per_link.redeem-text')).then(async (value) => {
-        if (value)
-          await this.$apollo
-            .mutate({
-              mutation: redeemTransactionLink,
-              variables: {
-                code: this.$route.params.code,
-              },
-            })
-            .then(() => {
-              this.toastSuccess(
-                this.$t('gdd_per_link.redeemed', {
-                  n: amount,
-                }),
-              )
-              this.$router.push('/overview')
-            })
-            .catch((err) => {
-              this.toastError(err.message)
-              this.$router.push('/overview')
-            })
+      this.$bvModal.msgBoxConfirm(this.$t('gdd_per_link.redeem-text')).then((value) => {
+        if (value) this.mutationLink(amount)
       })
     },
   },
   computed: {
+    isContributionLink() {
+      return this.$route.params.code.search(/^CL-/) === 0
+    },
     itemType() {
-      // link wurde gelöscht: am, von
+      // link is deleted: at, from
       if (this.linkData.deletedAt) {
         // eslint-disable-next-line vue/no-side-effects-in-computed-properties
         this.redeemedBoxText = this.$t('gdd_per_link.link-deleted', {
@@ -124,16 +137,12 @@ export default {
 
       if (this.$store.state.token) {
         // logged in, nicht berechtigt einzulösen, eigener link
-        if (this.$store.state.email === this.linkData.user.email) {
+        if (this.linkData.user && this.$store.state.email === this.linkData.user.email) {
           return `SELF_CREATOR`
         }
 
         // logged in und berechtigt einzulösen
-        if (
-          this.$store.state.email !== this.linkData.user.email &&
-          !this.linkData.redeemedAt &&
-          !this.linkData.deletedAt
-        ) {
+        if (!this.linkData.redeemedAt && !this.linkData.deletedAt) {
           return `VALID`
         }
       }
diff --git a/frontend/src/plugins/apolloProvider.js b/frontend/src/plugins/apolloProvider.js
index 73452e5ba..4a0ff9914 100644
--- a/frontend/src/plugins/apolloProvider.js
+++ b/frontend/src/plugins/apolloProvider.js
@@ -29,7 +29,11 @@ const authLink = new ApolloLink((operation, forward) => {
 
 const apolloClient = new ApolloClient({
   link: authLink.concat(httpLink),
-  cache: new InMemoryCache(),
+  cache: new InMemoryCache({
+    possibleTypes: {
+      QueryLinkResult: ['TransactionLink', 'ContributionLink'],
+    },
+  }),
 })
 
 export const apolloProvider = new VueApollo({
diff --git a/frontend/src/plugins/dashboard-plugin.js b/frontend/src/plugins/dashboard-plugin.js
index 4825377c7..fe617169f 100755
--- a/frontend/src/plugins/dashboard-plugin.js
+++ b/frontend/src/plugins/dashboard-plugin.js
@@ -18,6 +18,8 @@ import 'vue-loading-overlay/dist/vue-loading.css'
 
 import VueApollo from 'vue-apollo'
 
+import VueTimers from 'vue-timers'
+
 export default {
   install(Vue) {
     Vue.use(GlobalComponents)
@@ -29,5 +31,6 @@ export default {
     Vue.use(FlatPickr)
     Vue.use(Loading)
     Vue.use(VueApollo)
+    Vue.use(VueTimers)
   },
 }
diff --git a/frontend/src/routes/router.test.js b/frontend/src/routes/router.test.js
index a1083a499..c843f85bb 100644
--- a/frontend/src/routes/router.test.js
+++ b/frontend/src/routes/router.test.js
@@ -75,6 +75,17 @@ describe('router', () => {
         })
       })
 
+      describe('community', () => {
+        it('requires authorization', () => {
+          expect(routes.find((r) => r.path === '/community').meta.requiresAuth).toBeTruthy()
+        })
+
+        it('loads the "Community" page', async () => {
+          const component = await routes.find((r) => r.path === '/community').component()
+          expect(component.default.name).toBe('Community')
+        })
+      })
+
       describe('profile', () => {
         it('requires authorization', () => {
           expect(routes.find((r) => r.path === '/profile').meta.requiresAuth).toBeTruthy()
diff --git a/frontend/src/store/store.js b/frontend/src/store/store.js
index 129337e7f..8fdbc519e 100644
--- a/frontend/src/store/store.js
+++ b/frontend/src/store/store.js
@@ -3,6 +3,7 @@ import Vuex from 'vuex'
 import createPersistedState from 'vuex-persistedstate'
 import { localeChanged } from 'vee-validate'
 import i18n from '@/i18n.js'
+import jwtDecode from 'jwt-decode'
 
 Vue.use(Vuex)
 
@@ -26,6 +27,11 @@ export const mutations = {
   },
   token: (state, token) => {
     state.token = token
+    if (token) {
+      state.tokenTime = jwtDecode(token).exp
+    } else {
+      state.tokenTime = null
+    }
   },
   newsletterState: (state, newsletterState) => {
     state.newsletterState = newsletterState
@@ -41,6 +47,9 @@ export const mutations = {
   hasElopage: (state, hasElopage) => {
     state.hasElopage = hasElopage
   },
+  creation: (state, creation) => {
+    state.creation = creation
+  },
 }
 
 export const actions = {
@@ -54,6 +63,7 @@ export const actions = {
     commit('hasElopage', data.hasElopage)
     commit('publisherId', data.publisherId)
     commit('isAdmin', data.isAdmin)
+    commit('creation', data.creation)
   },
   logout: ({ commit, state }) => {
     commit('token', null)
@@ -65,6 +75,7 @@ export const actions = {
     commit('hasElopage', false)
     commit('publisherId', null)
     commit('isAdmin', false)
+    commit('creation', null)
     localStorage.clear()
   },
 }
@@ -85,10 +96,12 @@ try {
       lastName: '',
       // username: '',
       token: null,
+      tokenTime: null,
       isAdmin: false,
       newsletterState: null,
       hasElopage: false,
       publisherId: null,
+      creation: null,
     },
     getters: {},
     // Syncronous mutation of the state
diff --git a/frontend/src/store/store.test.js b/frontend/src/store/store.test.js
index e8d680f94..651a3ccc5 100644
--- a/frontend/src/store/store.test.js
+++ b/frontend/src/store/store.test.js
@@ -3,6 +3,7 @@ import Vuex from 'vuex'
 import Vue from 'vue'
 import i18n from '@/i18n.js'
 import { localeChanged } from 'vee-validate'
+import jwtDecode from 'jwt-decode'
 
 jest.mock('vuex')
 jest.mock('@/i18n.js')
@@ -11,6 +12,11 @@ jest.mock('vee-validate', () => {
     localeChanged: jest.fn(),
   }
 })
+jest.mock('jwt-decode', () => {
+  return jest.fn(() => {
+    return { exp: '1234' }
+  })
+})
 
 i18n.locale = 'blubb'
 
@@ -24,6 +30,7 @@ const {
   publisherId,
   isAdmin,
   hasElopage,
+  creation,
 } = mutations
 const { login, logout } = actions
 
@@ -59,6 +66,25 @@ describe('Vuex store', () => {
         token(state, '1234')
         expect(state.token).toEqual('1234')
       })
+
+      describe('token has a value', () => {
+        it('sets the state of tokenTime', () => {
+          const state = { token: null, tokenTime: null }
+          token(state, 'token')
+          expect(jwtDecode).toBeCalledWith('token')
+          expect(state.tokenTime).toEqual('1234')
+        })
+      })
+
+      describe('token has null value', () => {
+        it('sets the state of tokenTime to null', () => {
+          jest.clearAllMocks()
+          const state = { token: null, tokenTime: '123' }
+          token(state, null)
+          expect(jwtDecode).not.toBeCalled()
+          expect(state.tokenTime).toEqual(null)
+        })
+      })
     })
 
     describe('firstName', () => {
@@ -114,6 +140,14 @@ describe('Vuex store', () => {
         expect(state.hasElopage).toBeTruthy()
       })
     })
+
+    describe('creation', () => {
+      it('sets the state of creation', () => {
+        const state = { creation: null }
+        creation(state, true)
+        expect(state.creation).toEqual(true)
+      })
+    })
   })
 
   describe('actions', () => {
@@ -131,11 +165,12 @@ describe('Vuex store', () => {
         hasElopage: false,
         publisherId: 1234,
         isAdmin: true,
+        creation: ['1000', '1000', '1000'],
       }
 
       it('calls nine commits', () => {
         login({ commit, state }, commitedData)
-        expect(commit).toHaveBeenCalledTimes(8)
+        expect(commit).toHaveBeenCalledTimes(9)
       })
 
       it('commits email', () => {
@@ -177,6 +212,11 @@ describe('Vuex store', () => {
         login({ commit, state }, commitedData)
         expect(commit).toHaveBeenNthCalledWith(8, 'isAdmin', true)
       })
+
+      it('commits creation', () => {
+        login({ commit, state }, commitedData)
+        expect(commit).toHaveBeenNthCalledWith(9, 'creation', ['1000', '1000', '1000'])
+      })
     })
 
     describe('logout', () => {
@@ -185,7 +225,7 @@ describe('Vuex store', () => {
 
       it('calls nine commits', () => {
         logout({ commit, state })
-        expect(commit).toHaveBeenCalledTimes(8)
+        expect(commit).toHaveBeenCalledTimes(9)
       })
 
       it('commits token', () => {
@@ -228,6 +268,11 @@ describe('Vuex store', () => {
         expect(commit).toHaveBeenNthCalledWith(8, 'isAdmin', false)
       })
 
+      it('commits creation', () => {
+        logout({ commit, state })
+        expect(commit).toHaveBeenNthCalledWith(9, 'creation', null)
+      })
+
       // how to get this working?
       it.skip('calls localStorage.clear()', () => {
         const clearStorageMock = jest.fn()
diff --git a/frontend/test/testSetup.js b/frontend/test/testSetup.js
index 614621a09..32cf335a8 100644
--- a/frontend/test/testSetup.js
+++ b/frontend/test/testSetup.js
@@ -8,6 +8,7 @@ import * as rules from 'vee-validate/dist/rules'
 import { messages } from 'vee-validate/dist/locale/en.json'
 
 import RegeneratorRuntime from 'regenerator-runtime'
+import VueTimers from 'vue-timers'
 
 import VueMoment from 'vue-moment'
 
@@ -46,6 +47,7 @@ global.localVue.use(Vuex)
 global.localVue.use(IconsPlugin)
 global.localVue.use(RegeneratorRuntime)
 global.localVue.use(VueMoment)
+global.localVue.use(VueTimers)
 global.localVue.component('validation-provider', ValidationProvider)
 global.localVue.component('validation-observer', ValidationObserver)
 // global.localVue.directive('click-outside', clickOutside)
diff --git a/frontend/yarn.lock b/frontend/yarn.lock
index f7dc7c964..829b63dcf 100644
--- a/frontend/yarn.lock
+++ b/frontend/yarn.lock
@@ -4615,20 +4615,10 @@ caniuse-api@^3.0.0:
     lodash.memoize "^4.1.2"
     lodash.uniq "^4.5.0"
 
-caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001109:
-  version "1.0.30001251"
-  resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001251.tgz"
-  integrity sha512-HOe1r+9VkU4TFmnU70z+r7OLmtR+/chB1rdcJUeQlAinjEeb0cKL20tlAtOagNZhbrtLnCvV19B4FmF1rgzl6A==
-
-caniuse-lite@^1.0.30001181, caniuse-lite@^1.0.30001280:
-  version "1.0.30001285"
-  resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001285.tgz#fe1e52229187e11d6670590790d669b9e03315b7"
-  integrity sha512-KAOkuUtcQ901MtmvxfKD+ODHH9YVDYnBt+TGYSz2KIfnq22CiArbUxXPN9067gNbgMlnNYRSwho8OPXZPALB9Q==
-
-caniuse-lite@^1.0.30001286:
-  version "1.0.30001303"
-  resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001303.tgz#9b168e4f43ccfc372b86f4bc5a551d9b909c95c9"
-  integrity sha512-/Mqc1oESndUNszJP0kx0UaQU9kEv9nNtJ7Kn8AdA0mNnH8eR1cj0kG+NbNuC1Wq/b21eA8prhKRA3bbkjONegQ==
+caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001181, caniuse-lite@^1.0.30001280, caniuse-lite@^1.0.30001286:
+  version "1.0.30001354"
+  resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001354.tgz"
+  integrity sha512-mImKeCkyGDAHNywYFA4bqnLAzTUvVkqPvhY4DV47X+Gl2c5Z8c3KNETnXp14GQt11LvxE8AwjzGxJ+rsikiOzg==
 
 capture-exit@^2.0.0:
   version "2.0.0"
@@ -9831,6 +9821,11 @@ jsprim@^1.2.2:
     json-schema "0.2.3"
     verror "1.10.0"
 
+jwt-decode@^3.1.2:
+  version "3.1.2"
+  resolved "https://registry.yarnpkg.com/jwt-decode/-/jwt-decode-3.1.2.tgz#3fb319f3675a2df0c2895c8f5e9fa4b67b04ed59"
+  integrity sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==
+
 killable@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892"
@@ -14482,6 +14477,11 @@ vue-template-es2015-compiler@^1.6.0, vue-template-es2015-compiler@^1.9.0:
   resolved "https://registry.yarnpkg.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz#1ee3bc9a16ecbf5118be334bb15f9c46f82f5825"
   integrity sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==
 
+vue-timers@^2.0.4:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/vue-timers/-/vue-timers-2.0.4.tgz#7e1c443abf2109db5eeab6e62b0f5a47e94cf70b"
+  integrity sha512-QOEVdO4V4o9WjFG6C0Kn9tfdTeeECjqvEQozcQlfL1Tn8v0qx4uUPhTYoc1+s6qoJnSbu8f68x8+nm1ZEir0kw==
+
 vue2-transitions@^0.2.3:
   version "0.2.3"
   resolved "https://registry.yarnpkg.com/vue2-transitions/-/vue2-transitions-0.2.3.tgz#69c9d75b1db05f231b80980c03459d68490ba27d"
diff --git a/package.json b/package.json
index 3d5bc51b7..2bba1b52c 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "gradido",
-  "version": "1.9.0",
+  "version": "1.11.0",
   "description": "Gradido",
   "main": "index.js",
   "repository": "git@github.com:gradido/gradido.git",
